diff --git a/xmlschema/__init__.py b/xmlschema/__init__.py index b82e3533..4b04a0d6 100644 --- a/xmlschema/__init__.py +++ b/xmlschema/__init__.py @@ -37,7 +37,6 @@ __license__ = "MIT" __status__ = "Production/Stable" - __all__ = [ 'limits', 'XMLSchemaException', 'XMLResourceError', 'XMLSchemaNamespaceError', 'etree_tostring', 'normalize_url', 'normalize_locations', 'fetch_resource', diff --git a/xmlschema/locale/__init__.py b/xmlschema/locale/__init__.py new file mode 100644 index 00000000..473a47ca --- /dev/null +++ b/xmlschema/locale/__init__.py @@ -0,0 +1,19 @@ +import gettext +from pathlib import PurePath + +translator = gettext.NullTranslations() + + +def register_translator(folder: PurePath): + global translator + translator = gettext.translation( + 'xmlschema', + folder + ) + + +def get_translation(message): + return translator.gettext(message) + + +_ = get_translation diff --git a/xmlschema/locale/ru/LC_MESSAGES/xmlschema.mo b/xmlschema/locale/ru/LC_MESSAGES/xmlschema.mo new file mode 100644 index 00000000..99979339 Binary files /dev/null and b/xmlschema/locale/ru/LC_MESSAGES/xmlschema.mo differ diff --git a/xmlschema/locale/ru/LC_MESSAGES/xmlschema.po b/xmlschema/locale/ru/LC_MESSAGES/xmlschema.po new file mode 100644 index 00000000..e2cb2a00 --- /dev/null +++ b/xmlschema/locale/ru/LC_MESSAGES/xmlschema.po @@ -0,0 +1,94 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-04-05 17:41+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: xmlschema/validators/exceptions.py:343 +#, python-format +msgid "Unexpected child with tag %r at position %d." +msgstr "Неожиданный дочерний тэг %r в позиции %d." + +#: xmlschema/validators/exceptions.py:370 +#, python-format +msgid " Tag (%s) expected." +msgstr " Ожидается тэг (%s)" + +#: xmlschema/validators/exceptions.py:372 +#, python-format +msgid " Tag %s expected." +msgstr " Ожидается тэг %s" + +#: xmlschema/validators/exceptions.py:374 +#, python-format +msgid " Tag %r expected." +msgstr " Ожидается тэг (%r)" + +#: xmlschema/validators/global_maps.py:405 +msgid "invalid" +msgstr "невалидный" + +#: xmlschema/validators/helpers.py:43 +#, python-format +msgid "wrong value %r for attribute %r" +msgstr "неверное значение %r для атрибута %r" + +#: xmlschema/validators/helpers.py:58 +msgid "value is not a valid xs:decimal" +msgstr "значение неверно для типа xs:decimal" + +#: xmlschema/validators/helpers.py:64 +msgid "value is not an xs:QName" +msgstr "значение не xs:QName" + +#: xmlschema/validators/helpers.py:70 xmlschema/validators/helpers.py:76 +#: xmlschema/validators/helpers.py:82 xmlschema/validators/helpers.py:88 +#: xmlschema/validators/helpers.py:94 xmlschema/validators/helpers.py:100 +#: xmlschema/validators/helpers.py:106 xmlschema/validators/helpers.py:112 +msgid "value must be {:s}" +msgstr "значение должно быть {:s}" + +#: xmlschema/validators/helpers.py:118 +msgid "value must be negative" +msgstr "значение должно быть отрицательным" + +#: xmlschema/validators/helpers.py:124 +msgid "value must be positive" +msgstr "значение должно быть положительным" + +#: xmlschema/validators/helpers.py:130 +msgid "value must be non positive" +msgstr "значение не должно быть положительным" + +#: xmlschema/validators/helpers.py:136 +msgid "value must be non negative" +msgstr "значение не должно быть отрицательным" + +#: xmlschema/validators/helpers.py:143 +msgid "not an hexadecimal number" +msgstr "не шестнадцатеричное число" + +#: xmlschema/validators/helpers.py:156 +msgid "not a base64 encoding" +msgstr "не закодировано в base64" + +#: xmlschema/validators/helpers.py:161 +msgid "no value is allowed for xs:error type" +msgstr "значение недоступно для типа xs:error" + +#: xmlschema/validators/helpers.py:173 +msgid "{!r} is not a boolean value" +msgstr "{!r} не булево значение" diff --git a/xmlschema/locale/xmlschema.pot b/xmlschema/locale/xmlschema.pot new file mode 100644 index 00000000..56fee9b0 --- /dev/null +++ b/xmlschema/locale/xmlschema.pot @@ -0,0 +1,94 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-04-05 17:41+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: xmlschema/validators/exceptions.py:343 +#, python-format +msgid "Unexpected child with tag %r at position %d." +msgstr "" + +#: xmlschema/validators/exceptions.py:370 +#, python-format +msgid " Tag (%s) expected." +msgstr "" + +#: xmlschema/validators/exceptions.py:372 +#, python-format +msgid " Tag %s expected." +msgstr "" + +#: xmlschema/validators/exceptions.py:374 +#, python-format +msgid " Tag %r expected." +msgstr "" + +#: xmlschema/validators/global_maps.py:405 +msgid "invalid" +msgstr "" + +#: xmlschema/validators/helpers.py:43 +#, python-format +msgid "wrong value %r for attribute %r" +msgstr "" + +#: xmlschema/validators/helpers.py:58 +msgid "value is not a valid xs:decimal" +msgstr "" + +#: xmlschema/validators/helpers.py:64 +msgid "value is not an xs:QName" +msgstr "" + +#: xmlschema/validators/helpers.py:70 xmlschema/validators/helpers.py:76 +#: xmlschema/validators/helpers.py:82 xmlschema/validators/helpers.py:88 +#: xmlschema/validators/helpers.py:94 xmlschema/validators/helpers.py:100 +#: xmlschema/validators/helpers.py:106 xmlschema/validators/helpers.py:112 +msgid "value must be {:s}" +msgstr "" + +#: xmlschema/validators/helpers.py:118 +msgid "value must be negative" +msgstr "" + +#: xmlschema/validators/helpers.py:124 +msgid "value must be positive" +msgstr "" + +#: xmlschema/validators/helpers.py:130 +msgid "value must be non positive" +msgstr "" + +#: xmlschema/validators/helpers.py:136 +msgid "value must be non negative" +msgstr "" + +#: xmlschema/validators/helpers.py:143 +msgid "not an hexadecimal number" +msgstr "" + +#: xmlschema/validators/helpers.py:156 +msgid "not a base64 encoding" +msgstr "" + +#: xmlschema/validators/helpers.py:161 +msgid "no value is allowed for xs:error type" +msgstr "" + +#: xmlschema/validators/helpers.py:173 +msgid "{!r} is not a boolean value" +msgstr "" diff --git a/xmlschema/validators/exceptions.py b/xmlschema/validators/exceptions.py index b7cda275..bb53bee7 100644 --- a/xmlschema/validators/exceptions.py +++ b/xmlschema/validators/exceptions.py @@ -12,6 +12,7 @@ from ..etree import etree_tostring from ..aliases import ElementType, NamespacesType, SchemaElementType, ModelParticleType from ..helpers import get_prefixed_qname, etree_getpath, is_etree_element +from ..locale import _ if TYPE_CHECKING: from ..resources import XMLResource @@ -340,7 +341,7 @@ def __init__(self, validator: 'XsdValidator', reason = "The content of element %r is not complete." % tag else: child_tag = get_prefixed_qname(elem[index].tag, validator.namespaces, use_empty=False) - reason = "Unexpected child with tag %r at position %d." % (child_tag, index + 1) + reason = _("Unexpected child with tag %r at position %d.") % (child_tag, index + 1) if occurs and particle.is_missing(occurs): reason += " The particle %r occurs %d times but the minimum is %d." % ( @@ -367,11 +368,11 @@ def __init__(self, validator: 'XsdValidator', if not expected_tags: pass elif len(expected_tags) > 1: - reason += " Tag (%s) expected." % ' | '.join(repr(tag) for tag in expected_tags) + reason += _(" Tag (%s) expected.") % ' | '.join(repr(tag) for tag in expected_tags) elif expected_tags[0].startswith('from '): - reason += " Tag %s expected." % expected_tags[0] + reason += _(" Tag %s expected.") % expected_tags[0] else: - reason += " Tag %r expected." % expected_tags[0] + reason += _(" Tag %r expected.") % expected_tags[0] super(XMLSchemaChildrenValidationError, self).\ __init__(validator, elem, reason, source, namespaces) diff --git a/xmlschema/validators/global_maps.py b/xmlschema/validators/global_maps.py index cf30367a..63c30d23 100644 --- a/xmlschema/validators/global_maps.py +++ b/xmlschema/validators/global_maps.py @@ -31,6 +31,7 @@ from .builtins import xsd_builtin_types_factory from . import XsdAttribute, XsdSimpleType, XsdComplexType, XsdElement, XsdAttributeGroup, \ XsdGroup, XsdNotation, XsdIdentity, XsdAssert, XsdUnion, XsdAtomicRestriction +from ..locale import _ # @@ -402,7 +403,7 @@ def validity(self) -> str: if all(schema.validity == 'valid' for schema in self.iter_schemas()): return 'valid' elif any(schema.validity == 'invalid' for schema in self.iter_schemas()): - return 'invalid' + return _('invalid') else: return 'notKnown' diff --git a/xmlschema/validators/helpers.py b/xmlschema/validators/helpers.py index a9903f92..dcab595c 100644 --- a/xmlschema/validators/helpers.py +++ b/xmlschema/validators/helpers.py @@ -15,6 +15,7 @@ from ..exceptions import XMLSchemaValueError from .exceptions import XMLSchemaValidationError +from ..locale import _ XSD_FINAL_ATTRIBUTE_VALUES = {'restriction', 'extension', 'list', 'union'} @@ -40,7 +41,7 @@ def get_xsd_derivation_attribute(elem: Element, attribute: str, if len(items) == 1 and items[0] == '#all': return ' '.join(values) elif not all(s in values for s in items): - raise ValueError("wrong value %r for attribute %r" % (value, attribute)) + raise ValueError(_("wrong value %r for attribute %r") % (value, attribute)) return value @@ -55,92 +56,92 @@ def decimal_validator(value: Union[Decimal, int, float, str]) -> None: raise ValueError() except (ValueError, TypeError): raise XMLSchemaValidationError(decimal_validator, value, - "value is not a valid xs:decimal") from None + _("value is not a valid xs:decimal")) from None def qname_validator(value: str) -> None: if datatypes.QName.pattern.match(value) is None: raise XMLSchemaValidationError(qname_validator, value, - "value is not an xs:QName") + _("value is not an xs:QName")) def byte_validator(value: int) -> None: if not (-2**7 <= value < 2 ** 7): raise XMLSchemaValidationError(int_validator, value, - "value must be -128 <= x < 128") + _("value must be {:s}").format("-128 <= x < 128")) def short_validator(value: int) -> None: if not (-2**15 <= value < 2 ** 15): raise XMLSchemaValidationError(short_validator, value, - "value must be -2^15 <= x < 2^15") + _("value must be {:s}").format("-2^15 <= x < 2^15")) def int_validator(value: int) -> None: if not (-2**31 <= value < 2 ** 31): raise XMLSchemaValidationError(int_validator, value, - "value must be -2^31 <= x < 2^31") + _("value must be {:s}").format("-2^31 <= x < 2^31")) def long_validator(value: int) -> None: if not (-2**63 <= value < 2 ** 63): raise XMLSchemaValidationError(long_validator, value, - "value must be -2^63 <= x < 2^63") + _("value must be {:s}").format("-2^63 <= x < 2^63")) def unsigned_byte_validator(value: int) -> None: if not (0 <= value < 2 ** 8): raise XMLSchemaValidationError(unsigned_byte_validator, value, - "value must be 0 <= x < 256") + _("value must be {:s}").format("0 <= x < 256")) def unsigned_short_validator(value: int) -> None: if not (0 <= value < 2 ** 16): raise XMLSchemaValidationError(unsigned_short_validator, value, - "value must be 0 <= x < 2^16") + _("value must be {:s}").format("0 <= x < 2^16")) def unsigned_int_validator(value: int) -> None: if not (0 <= value < 2 ** 32): raise XMLSchemaValidationError(unsigned_int_validator, value, - "value must be 0 <= x < 2^32") + _("value must be {:s}").format("0 <= x < 2^32")) def unsigned_long_validator(value: int) -> None: if not (0 <= value < 2 ** 64): raise XMLSchemaValidationError(unsigned_long_validator, value, - "value must be 0 <= x < 2^64") + _("value must be {:s}").format("0 <= x < 2^64")) def negative_int_validator(value: int) -> None: if value >= 0: raise XMLSchemaValidationError(negative_int_validator, value, - "value must be negative") + _("value must be negative")) def positive_int_validator(value: int) -> None: if value <= 0: raise XMLSchemaValidationError(positive_int_validator, value, - "value must be positive") + _("value must be positive")) def non_positive_int_validator(value: int) -> None: if value > 0: raise XMLSchemaValidationError(non_positive_int_validator, value, - "value must be non positive") + _("value must be non positive")) def non_negative_int_validator(value: int) -> None: if value < 0: raise XMLSchemaValidationError(non_negative_int_validator, value, - "value must be non negative") + _("value must be non negative")) def hex_binary_validator(value: Union[str, datatypes.HexBinary]) -> None: if not isinstance(value, datatypes.HexBinary) and \ datatypes.HexBinary.pattern.match(value) is None: raise XMLSchemaValidationError(hex_binary_validator, value, - "not an hexadecimal number") + _("not an hexadecimal number")) def base64_binary_validator(value: Union[str, datatypes.Base64Binary]) -> None: @@ -153,12 +154,12 @@ def base64_binary_validator(value: Union[str, datatypes.Base64Binary]) -> None: match = datatypes.Base64Binary.pattern.match(value) if match is None or match.group(0) != value: raise XMLSchemaValidationError(base64_binary_validator, value, - "not a base64 encoding") + _("not a base64 encoding")) def error_type_validator(value: object) -> None: raise XMLSchemaValidationError(error_type_validator, value, - "no value is allowed for xs:error type") + _("no value is allowed for xs:error type")) # @@ -170,7 +171,7 @@ def boolean_to_python(value: str) -> bool: elif value in {'false', '0'}: return False else: - raise XMLSchemaValueError('{!r} is not a boolean value'.format(value)) + raise XMLSchemaValueError(_('{!r} is not a boolean value').format(value)) def python_to_boolean(value: object) -> str: diff --git a/xmlschema/validators/schemas.py b/xmlschema/validators/schemas.py index 8e699f5b..9262e8fc 100644 --- a/xmlschema/validators/schemas.py +++ b/xmlschema/validators/schemas.py @@ -15,6 +15,8 @@ the standard. """ import sys +from pathlib import Path, PurePath + if sys.version_info < (3, 7): from typing import GenericMeta as ABCMeta else: @@ -321,11 +323,19 @@ def __init__(self, source: Union[SchemaSourceType, List[SchemaSourceType]], build: bool = True, use_meta: bool = True, use_fallback: bool = True, - loglevel: Optional[Union[str, int]] = None) -> None: + loglevel: Optional[Union[str, int]] = None, use_translation=False, + translation_folder: PurePath = None) -> None: super(XMLSchemaBase, self).__init__(validation) self.lock = threading.Lock() # Lock for build operations + if use_translation: + from xmlschema.locale import register_translator + if not translation_folder: + translation_folder = Path.joinpath(Path(__file__).parent.resolve(), '../locale') + + register_translator(translation_folder) + if loglevel is not None: if isinstance(loglevel, str): level = loglevel.strip().upper() diff --git a/xmlschema/validators/simple_types.py b/xmlschema/validators/simple_types.py index 6165324f..35e9b51c 100644 --- a/xmlschema/validators/simple_types.py +++ b/xmlschema/validators/simple_types.py @@ -606,6 +606,7 @@ def iter_decode(self, obj: Union[str, bytes], validation: str = 'lax', **kwargs: try: result = self.to_python(obj) except (ValueError, DecimalException) as err: + # todo: maybe need to translate python error messages? yield XMLSchemaDecodeError(self, obj, self.to_python, reason=str(err)) yield None return