add gettext support
authorEmmanuel Garette <egarette@cadoles.com>
Sat, 13 Apr 2013 21:09:05 +0000 (23:09 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Sat, 13 Apr 2013 21:09:05 +0000 (23:09 +0200)
tiramisu/config.py
tiramisu/i18n.py [new file with mode: 0644]
tiramisu/option.py
tiramisu/value.py

index 811f931..93cfe34 100644 (file)
@@ -26,6 +26,7 @@ from tiramisu.error import (PropertiesOptionError, NotFoundError,
 from tiramisu.option import OptionDescription, Option, SymLinkOption
 from tiramisu.setting import groups, Setting, apply_requires
 from tiramisu.value import Values
+from tiramisu.i18n import _
 
 
 class SubConfig(object):
@@ -85,7 +86,7 @@ class SubConfig(object):
         "validation for the setattr and the getattr"
         if not isinstance(opt_or_descr, Option) and \
                 not isinstance(opt_or_descr, OptionDescription):
-            raise TypeError('Unexpected object: {0}'.format(repr(opt_or_descr)))
+            raise TypeError(_('Unexpected object: {0}').format(repr(opt_or_descr)))
         properties = set(self.cfgimpl_get_settings().get_properties(opt_or_descr))
         #remove this properties, those properties are validate in value/setting
         properties = properties - set(['mandatory', 'frozen'])
@@ -96,9 +97,9 @@ class SubConfig(object):
         properties = properties - set(self.cfgimpl_get_settings().get_permissive(opt_or_descr))
         properties = list(properties)
         if properties != []:
-            raise PropertiesOptionError("trying to access"
+            raise PropertiesOptionError(_("trying to access"
                                         " to an option named: {0} with properties"
-                                        " {1}".format(name, str(properties)),
+                                        " {1}").format(name, str(properties)),
                                         properties)
 
     def __getattr__(self, name):
@@ -131,10 +132,10 @@ class SubConfig(object):
         if isinstance(opt_or_descr, OptionDescription):
             children = self.cfgimpl_get_description()._children
             if opt_or_descr not in children[1]:
-                raise AttributeError("{0} with name {1} object has "
-                                     "no attribute {2}".format(self.__class__,
-                                                               opt_or_descr._name,
-                                                               name))
+                raise AttributeError(_("{0} with name {1} object has "
+                                     "no attribute {2}").format(self.__class__,
+                                                                opt_or_descr._name,
+                                                                name))
             return SubConfig(opt_or_descr, self._cfgimpl_context)
         # special attributes
         if name.startswith('_cfgimpl_'):
@@ -153,16 +154,16 @@ class SubConfig(object):
         apply_requires(child, self)
         #needed to ?
         if child not in self._cfgimpl_descr._children[1]:
-            raise AttributeError('unknown option %s' % (name))
+            raise AttributeError(_('unknown option {}').format(name))
 
         if setting.has_property('everything_frozen'):
-            raise TypeError("cannot set a value to the option {} if the whole "
-                            "config has been frozen".format(name))
+            raise TypeError(_("cannot set a value to the option {} if the whole "
+                            "config has been frozen").format(name))
 
         if setting.has_property('frozen') and setting.has_property('frozen',
                                                                    child, is_apply_req=False):
-            raise TypeError('cannot change the value to %s for '
-                            'option %s this option is frozen' % (str(value), name))
+            raise TypeError(_('cannot change the value to {} for '
+                            'option {} this option is frozen').format(str(value), name))
         self.cfgimpl_get_values()[child] = value
 
     def cfgimpl_get_home_by_path(self, path, force_permissive=False, force_properties=None):
@@ -226,7 +227,7 @@ class SubConfig(object):
         """
         if group_type is not None:
             if not isinstance(group_type, groups.GroupType):
-                raise TypeError("Unknown group_type: {0}".format(group_type))
+                raise TypeError(_("Unknown group_type: {0}").format(group_type))
         for child in self._cfgimpl_descr._children[1]:
             if isinstance(child, OptionDescription):
                 try:
@@ -320,7 +321,7 @@ class SubConfig(object):
         if _currpath is None:
             _currpath = []
         if withoption is None and withvalue is not None:
-            raise ValueError("make_dict can't filtering with value without option")
+            raise ValueError(_("make_dict can't filtering with value without option"))
         if withoption is not None:
             mypath = self.getpath()
             for path in self.cfgimpl_get_context()._find(bytype=Option,
@@ -339,8 +340,8 @@ class SubConfig(object):
                     else:
                         tmypath = mypath + '.'
                         if not path.startswith(tmypath):
-                            raise Exception('unexpected path {}, '
-                                            'should start with {}'.format(path, mypath))
+                            raise Exception(_('unexpected path {}, '
+                                            'should start with {}').format(path, mypath))
                         path = path[len(tmypath):]
                 self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten)
         #withoption can be set to None below !
@@ -428,11 +429,11 @@ class Config(SubConfig):
                 homeconfig.setoption(name, child, value)
             elif len(candidates) > 1:
                 raise AmbigousOptionError(
-                    'more than one option that ends with %s' % (key, ))
+                    _('more than one option that ends with {}').format(key))
             else:
                 raise NoMatchingOptionFound(
-                    'there is no option that matches %s'
-                    ' or the option is hidden or disabled' % (key, ))
+                    _('there is no option that matches {}'
+                      ' or the option is hidden or disabled').format(key))
 
     def getpath(self):
         return None
@@ -483,7 +484,7 @@ class Config(SubConfig):
         #                return False
         #    return False
         if type_ not in ('option', 'path', 'value'):
-            raise ValueError('unknown type_ type {} for _find'.format(type_))
+            raise ValueError(_('unknown type_ type {} for _find').format(type_))
         find_results = []
         opts, paths = self.cfgimpl_get_description()._cache_paths
         for index in range(0, len(paths)):
@@ -517,7 +518,7 @@ class Config(SubConfig):
             else:
                 find_results.append(retval)
         if find_results == []:
-            raise NotFoundError("no option found in config with these criteria")
+            raise NotFoundError(_("no option found in config with these criteria"))
         else:
             return find_results
 
diff --git a/tiramisu/i18n.py b/tiramisu/i18n.py
new file mode 100644 (file)
index 0000000..a8825b0
--- /dev/null
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import gettext
+gettext.translation('tiramisu', fallback=True)
+_ = gettext.gettext
index 7a49b98..8f0f0cc 100644 (file)
@@ -28,6 +28,7 @@ from IPy import IP
 from tiramisu.error import (ConfigError, NotFoundError, ConflictConfigError,
                             RequiresError, ValidateError)
 from tiramisu.setting import groups, multitypes
+from tiramisu.i18n import _
 
 name_regexp = re.compile(r'^\d+')
 
@@ -36,7 +37,7 @@ def valid_name(name):
     try:
         name = str(name)
     except:
-        raise ValueError("not a valid string name")
+        raise ValueError(_('not a valid string name'))
     if re.match(name_regexp, name) is None:
         return True
     else:
@@ -67,7 +68,7 @@ class BaseInformation(object):
         elif default is not None:
             return default
         else:
-            raise ValueError("Information's item not found: {0}".format(key))
+            raise ValueError(_("Information's item not found: {0}").format(key))
 
 
 class Option(BaseInformation):
@@ -103,7 +104,7 @@ class Option(BaseInformation):
         :param validator_args: the validator's parameters
         """
         if not valid_name(name):
-            raise NameError("invalid name: {0} for option".format(name))
+            raise NameError(_("invalid name: {0} for option").format(name))
         self._name = name
         self._informations = {}
         self.set_information('doc', doc)
@@ -113,24 +114,24 @@ class Option(BaseInformation):
         self._consistency = None
         if validator is not None:
             if type(validator) != FunctionType:
-                raise TypeError("validator must be a function")
+                raise TypeError(_("validator must be a function"))
             if validator_args is None:
                 validator_args = {}
             self._validator = (validator, validator_args)
         else:
             self._validator = None
         if not self._multi and default_multi is not None:
-            raise ConfigError("a default_multi is set whereas multi is False"
-                              " in option: {0}".format(name))
+            raise ConfigError(_("a default_multi is set whereas multi is False"
+                              " in option: {0}").format(name))
         if default_multi is not None and not self._validate(default_multi):
-            raise ConfigError("invalid default_multi value {0} "
-                              "for option {1}".format(str(default_multi), name))
+            raise ConfigError(_("invalid default_multi value {0} "
+                              "for option {1}").format(str(default_multi), name))
         if callback is not None and (default is not None or default_multi is not None):
-            raise ConfigError("defaut values not allowed if option: {0} "
-                              "is calculated".format(name))
+            raise ConfigError(_("defaut values not allowed if option: {0} "
+                              "is calculated").format(name))
         if callback is None and callback_params is not None:
-            raise ConfigError("params defined for a callback function but "
-                              "no callback defined yet for option {0}".format(name))
+            raise ConfigError(_("params defined for a callback function but "
+                              "no callback defined yet for option {0}").format(name))
         if callback is not None:
             self._callback = (callback, callback_params)
         else:
@@ -143,21 +144,21 @@ class Option(BaseInformation):
             #                        "for option {1} : not list type"
             #                        "".format(str(default), name))
             if not self.validate(default):
-                raise ValidateError("invalid default value {0} "
+                raise ValidateError(_("invalid default value {0} "
                                     "for option {1}"
-                                    "".format(str(default), name))
+                                    "").format(str(default), name))
             self._multitype = multitypes.default
             self._default_multi = default_multi
         else:
             if default is not None and not self.validate(default):
-                raise ValidateError("invalid default value {0} "
-                                    "for option {1}".format(str(default), name))
+                raise ValidateError(_("invalid default value {0} "
+                                    "for option {1}").format(str(default), name))
         self._default = default
         if properties is None:
             properties = ()
         if not isinstance(properties, tuple):
-            raise ConfigError('invalid properties type {0} for {1},'
-                              ' must be a tuple'.format(type(properties), self._name))
+            raise ConfigError(_('invalid properties type {0} for {1},'
+                              ' must be a tuple').format(type(properties), self._name))
         self._properties = properties  # 'hidden', 'disabled'...
 
     def validate(self, value, context=None, validate=True):
@@ -183,9 +184,9 @@ class Option(BaseInformation):
                     return cons.valid_consistency(self, value, context, None)
         else:
             if not isinstance(value, list):
-                raise ValidateError("invalid value {0} "
+                raise ValidateError(_("invalid value {0} "
                                     "for option {1} which must be a list"
-                                    "".format(value, self._name))
+                                    "").format(value, self._name))
             for index in range(0, len(value)):
                 val = value[index]
                 # None allows the reset of the value
@@ -268,11 +269,11 @@ class ChoiceOption(Option):
                  callback_params=None, open_values=False, validator=None,
                  validator_args=None, properties=()):
         if not isinstance(values, tuple):
-            raise ConfigError('values must be a tuple for {0}'.format(name))
+            raise ConfigError(_('values must be a tuple for {0}').format(name))
         self._values = values
         if open_values not in (True, False):
-            raise ConfigError('Open_values must be a boolean for '
-                              '{0}'.format(name))
+            raise ConfigError(_('open_values must be a boolean for '
+                              '{0}').format(name))
         self._open_values = open_values
         super(ChoiceOption, self).__init__(name, doc, default=default,
                                            default_multi=default_multi,
@@ -394,7 +395,7 @@ class NetmaskOption(Option):
                  properties=None, opt_ip=None):
         if opt_ip is not None and not isinstance(opt_ip, IPOption) and \
                 not isinstance(opt_ip, NetworkOption):
-            raise ValueError('opt_ip must be a IPOption not {}'.format(type(opt_ip)))
+            raise ValueError(_('opt_ip must be a IPOption not {}').format(type(opt_ip)))
         super(NetmaskOption, self).__init__(name, doc, default=default,
                                             default_multi=default_multi,
                                             callback=callback,
@@ -411,7 +412,7 @@ class NetmaskOption(Option):
         elif isinstance(opt_ip, NetworkOption):
             self._consistency = ('cons_network_netmask', (self, opt_ip))
         else:
-            raise ValueError('unknown type for opt_ip')
+            raise ValueError(_('unknown type for opt_ip'))
 
     def _validate(self, value):
         try:
@@ -465,7 +466,7 @@ class OptionDescription(BaseInformation):
         ``OptionDescription`` instances for nested namespaces).
         """
         if not valid_name(name):
-            raise NameError("invalid name: {0} for option descr".format(name))
+            raise NameError(_("invalid name: {0} for option descr").format(name))
         self._name = name
         self._informations = {}
         self.set_information('doc', doc)
@@ -476,8 +477,8 @@ class OptionDescription(BaseInformation):
         old = None
         for child in valid_child:
             if child == old:
-                raise ConflictConfigError('duplicate option name: '
-                                          '{0}'.format(child))
+                raise ConflictConfigError(_('duplicate option name: '
+                                          '{0}').format(child))
             old = child
         self._children = (tuple(child_names), tuple(children))
         validate_requires_arg(requires, self._name)
@@ -485,8 +486,8 @@ class OptionDescription(BaseInformation):
         self._cache_paths = None
         self._consistencies = None
         if not isinstance(properties, tuple):
-            raise ConfigError('invalid properties type {0} for {1},'
-                              ' must be a tuple'.format(type(properties), self._name))
+            raise ConfigError(_('invalid properties type {0} for {1},'
+                              ' must be a tuple').format(type(properties), self._name))
         self._properties = properties  # 'hidden', 'disabled'...
         # the group_type is useful for filtering OptionDescriptions in a config
         self._group_type = groups.default
@@ -498,8 +499,8 @@ class OptionDescription(BaseInformation):
         try:
             return self._children[1][self._children[0].index(name)]
         except ValueError:
-            raise AttributeError('unknown Option {} in OptionDescription {}'
-                                 ''.format(name, self._name))
+            raise AttributeError(_('unknown Option {} in OptionDescription {}'
+                                 '').format(name, self._name))
 
     def getkey(self, config):
         return tuple([child.getkey(getattr(config, child._name))
@@ -550,7 +551,7 @@ class OptionDescription(BaseInformation):
                     func, opts = option._consistency
                     for opt in opts:
                         if opt in _consistencies:
-                            raise ValueError('opt {} already in consistency'.format(opt._name))
+                            raise ValueError(_('opt {} already in consistency').format(opt._name))
                         _consistencies[opt] = (func, opts)
             else:
                 _currpath.append(attr)
@@ -563,8 +564,8 @@ class OptionDescription(BaseInformation):
             old = None
             for child in valid_child:
                 if child == old:
-                    raise ConflictConfigError('duplicate option: '
-                                              '{0}'.format(child))
+                    raise ConflictConfigError(_('duplicate option: '
+                                              '{0}').format(child))
                 old = child
             self._cache_paths = (tuple(cache_option), tuple(cache_path))
             self._consistencies = _consistencies
@@ -573,13 +574,13 @@ class OptionDescription(BaseInformation):
         try:
             return self._cache_paths[0][self._cache_paths[1].index(path)]
         except ValueError:
-            raise NotFoundError('no option for path {}'.format(path))
+            raise NotFoundError(_('no option for path {}').format(path))
 
     def get_path_by_opt(self, opt):
         try:
             return self._cache_paths[1][self._cache_paths[0].index(opt)]
         except ValueError:
-            raise NotFoundError('no option {} found'.format(opt))
+            raise NotFoundError(_('no option {} found').format(opt))
 
     # ____________________________________________________________
     def set_group_type(self, group_type):
@@ -589,8 +590,8 @@ class OptionDescription(BaseInformation):
                               that lives in `setting.groups`
         """
         if self._group_type != groups.default:
-            ConfigError('cannot change group_type if already set '
-                        '(old {}, new {})'.format(self._group_type, group_type))
+            ConfigError(_('cannot change group_type if already set '
+                        '(old {}, new {})').format(self._group_type, group_type))
         if isinstance(group_type, groups.GroupType):
             self._group_type = group_type
             if isinstance(group_type, groups.MasterGroupType):
@@ -601,12 +602,12 @@ class OptionDescription(BaseInformation):
                 master = None
                 for child in self._children[1]:
                     if isinstance(child, OptionDescription):
-                        raise ConfigError("master group {} shall not have "
-                                          "a subgroup".format(self._name))
+                        raise ConfigError(_("master group {} shall not have "
+                                          "a subgroup").format(self._name))
                     if not child.is_multi():
-                        raise ConfigError("not allowed option {0} in group {1}"
+                        raise ConfigError(_("not allowed option {0} in group {1}"
                                           ": this option is not a multi"
-                                          "".format(child._name, self._name))
+                                          "").format(child._name, self._name))
                     if child._name == self._name:
                         identical_master_child_name = True
                         child._multitype = multitypes.master
@@ -614,18 +615,18 @@ class OptionDescription(BaseInformation):
                     else:
                         slaves.append(child)
                 if master is None:
-                    raise ConfigError('master group with wrong master name for {}'
-                                      ''.format(self._name))
+                    raise ConfigError(_('master group with wrong master name for {}'
+                                      '').format(self._name))
                 master._master_slaves = tuple(slaves)
                 for child in self._children[1]:
                     if child != master:
                         child._master_slaves = master
                         child._multitype = multitypes.slave
                 if not identical_master_child_name:
-                    raise ConfigError("the master group: {} has not any "
-                                      "master child".format(self._name))
+                    raise ConfigError(_("the master group: {} has not any "
+                                      "master child").format(self._name))
         else:
-            raise ConfigError('not allowed group_type : {0}'.format(group_type))
+            raise ConfigError(_('not allowed group_type : {0}').format(group_type))
 
     def get_group_type(self):
         return self._group_type
@@ -644,8 +645,8 @@ def validate_requires_arg(requires, name):
         config_action = {}
         for req in requires:
             if not type(req) == tuple:
-                raise RequiresError("malformed requirements type for option:"
-                                    " {0}, must be a tuple".format(name))
+                raise RequiresError(_("malformed requirements type for option:"
+                                    " {0}, must be a tuple").format(name))
             if len(req) == 3:
                 action = req[2]
                 inverse = False
@@ -653,11 +654,11 @@ def validate_requires_arg(requires, name):
                 action = req[2]
                 inverse = req[3]
             else:
-                raise RequiresError("malformed requirements for option: {0}"
-                                    " invalid len".format(name))
+                raise RequiresError(_("malformed requirements for option: {0}"
+                                    " invalid len").format(name))
             if action in config_action:
                 if inverse != config_action[action]:
-                    raise RequiresError("inconsistency in action types for option: {0}"
-                                        " action: {1}".format(name, action))
+                    raise RequiresError(_("inconsistency in action types for option: {0}"
+                                        " action: {1}").format(name, action))
             else:
                 config_action[action] = inverse
index 528185a..a9ef389 100644 (file)
@@ -21,6 +21,7 @@ from tiramisu.error import MandatoryError, MultiTypeError, \
     ConfigError, ValidateError
 from tiramisu.setting import owners, multitypes
 from tiramisu.autolib import carry_out_calculation
+from tiramisu.i18n import _
 
 
 class Values(object):
@@ -49,8 +50,8 @@ class Values(object):
                     mastervalue = getattr(self.context, masterpath)
                     masterlen = len(mastervalue)
                     if len(value) > masterlen:
-                        raise MultiTypeError("invalid len for the slave: {0}"
-                                             " which has {1} as master".format(
+                        raise MultiTypeError(_("invalid len for the slave: {0}"
+                                             " which has {1} as master").format(
                                                  opt._name, masterpath))
                     if len(value) < masterlen:
                         for num in range(0, masterlen - len(value)):
@@ -85,18 +86,18 @@ class Values(object):
                              setting.has_property('mandatory'))
         if setting.has_property('mandatory', opt, False) and set_mandatory:
             if self._is_empty(opt, value) and opt.is_empty_by_default():
-                raise MandatoryError("option: {0} is mandatory "
-                                     "and shall have a value".format(opt._name))
+                raise MandatoryError(_("option: {0} is mandatory "
+                                     "and shall have a value").format(opt._name))
             #empty value
             if opt.is_multi():
                 for val in value:
                     if val == '':
-                        raise MandatoryError("option: {0} is mandatory "
-                                             "and shall have not empty value".format(opt._name))
+                        raise MandatoryError(_("option: {0} is mandatory "
+                                             "and shall have not empty value").format(opt._name))
             else:
                 if value == '':
-                    raise MandatoryError("option: {0} is mandatory "
-                                         "and shall have not empty value".format(opt._name))
+                    raise MandatoryError(_("option: {0} is mandatory "
+                                         "and shall have not empty value").format(opt._name))
 
     def fill_multi(self, opt, result):
         """fills a multi option with default and calculated values
@@ -144,23 +145,23 @@ class Values(object):
                 value = self.fill_multi(opt, value)
         self._test_mandatory(opt, value, force_properties)
         if validate and not opt.validate(value, self.context, setting.has_property('validator')):
-            raise ValidateError('invalid calculated value returned'
-                                ' for option {0}: {1}'.format(opt._name, value))
+            raise ValidateError(_('invalid calculated value returned'
+                                ' for option {0}: {1}').format(opt._name, value))
         return value
 
     def __setitem__(self, opt, value):
         if not opt.validate(value, self.context,
                             self.context.cfgimpl_get_settings().has_property('validator')):
-            raise ValidateError('invalid value {}'
-                                ' for option {}'.format(value, opt._name))
+            raise ValidateError(_('invalid value {}'
+                                ' for option {}').format(value, opt._name))
         if opt.is_multi():
             if opt.get_multitype() == multitypes.master:
                 masterlen = len(value)
                 for slave in opt.master_slaves:
                     value_slave = self._get_value(slave)
                     if len(value_slave) > masterlen:
-                        raise MultiTypeError("invalid len for the slave: {0}"
-                                             " which has {1} as master".format(
+                        raise MultiTypeError(_("invalid len for the slave: {0}"
+                                             " which has {1} as master").format(
                                                  slave._name, opt._name))
                     elif len(value_slave) < masterlen:
                         for num in range(0, masterlen - len(value_slave)):
@@ -168,8 +169,8 @@ class Values(object):
 
             elif opt.get_multitype() == multitypes.slave:
                 if len(self._get_value(opt.master_slaves)) != len(value):
-                    raise MultiTypeError("invalid len for the slave: {0}"
-                                         " which has {1} as master".format(
+                    raise MultiTypeError(_("invalid len for the slave: {0}"
+                                         " which has {1} as master").format(
                                              opt._name, opt.master_slaves._name))
             if not isinstance(value, Multi):
                 value = Multi(value, self.context, opt)
@@ -177,8 +178,8 @@ class Values(object):
 
     def setitem(self, opt, value):
         if type(value) == list:
-            raise MultiTypeError("the type of the value {0} which is multi shall "
-                                 "be Multi and not list".format(str(value)))
+            raise MultiTypeError(_("the type of the value {0} which is multi shall "
+                                 "be Multi and not list").format(str(value)))
         self._test_mandatory(opt, value)
         self.values[opt] = (self.context.cfgimpl_get_settings().getowner(), value)
 
@@ -190,9 +191,9 @@ class Values(object):
 
     def setowner(self, opt, owner):
         if opt not in self.values:
-            raise ConfigError('no value for {} cannot change owner to {}'.format(opt))
+            raise ConfigError(_('no value for {1} cannot change owner to {2}').format(opt))
         if not isinstance(owner, owners.Owner):
-            raise TypeError("invalid generic owner {0}".format(str(owner)))
+            raise TypeError(_("invalid generic owner {0}").format(str(owner)))
         self.values[opt] = (owner, self.values[opt][1])
 
     def is_default_owner(self, opt):
@@ -233,8 +234,8 @@ class Multi(list):
         """
         if not force:
             if self.opt.get_multitype() == multitypes.slave:
-                raise MultiTypeError("cannot append a value on a multi option {0}"
-                                     " which is a slave".format(self.opt._name))
+                raise MultiTypeError(_("cannot append a value on a multi option {0}"
+                                     " which is a slave").format(self.opt._name))
             elif self.opt.get_multitype() == multitypes.master:
                 for slave in self.opt.get_master_slaves():
                     self.context.cfgimpl_get_values()[slave].append(slave.getdefault_multi(), force=True)
@@ -244,9 +245,9 @@ class Multi(list):
 
     def _validate(self, value):
         if value is not None and not self.opt._validate(value):
-            raise ConfigError("invalid value {0} "
-                              "for option {1}".format(str(value),
-                                                      self.opt._name))
+            raise ConfigError(_("invalid value {0} "
+                              "for option {1}").format(str(value),
+                                                       self.opt._name))
 
     def pop(self, key, force=False):
         """the list value can be updated (poped)
@@ -257,8 +258,8 @@ class Multi(list):
         """
         if not force:
             if self.opt.multitype == multitypes.slave:
-                raise MultiTypeError("cannot append a value on a multi option {0}"
-                                     " which is a slave".format(self.opt._name))
+                raise MultiTypeError(_("cannot append a value on a multi option {0}"
+                                     " which is a slave").format(self.opt._name))
             elif self.opt.multitype == multitypes.master:
                 for slave in self.opt.get_master_slaves():
                     self.context.cfgimpl_get_values()[slave].pop(key, force=True)