Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localization example #293

Merged
merged 3 commits into from
Apr 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion xmlschema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
__license__ = "MIT"
__status__ = "Production/Stable"


__all__ = [
'limits', 'XMLSchemaException', 'XMLResourceError', 'XMLSchemaNamespaceError',
'etree_tostring', 'normalize_url', 'normalize_locations', 'fetch_resource',
Expand Down
19 changes: 19 additions & 0 deletions xmlschema/locale/__init__.py
Original file line number Diff line number Diff line change
@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to use locale/__init__.py for this, but instead of providing extra arguments to schema class it could be better to provide an helper function like this:

import gettext
from pathlib import Path

translation = None


def install_translation(localedir=None, languages=None, class_=None, fallback=False):
    global translation

    if localedir is None:
       localedir = pathlib.Path(__file__).parent..joinpath('../locale').resolve()

    translation = gettext.translation(
        domain= 'xmlschema',
        localedir=localedir,
        class_=class_,
        fallback=fallback,
    )
    translation.install()

importing install_translation into package __init__.py the function can be used to activate xmlschema provided translations after package import:

import xmlschema
xmlschema.install_translation()
schema = xmlschema.XMLSchema(...)

or to install other custom translations for the xmlschema domain providing optional arguments:

import xmlschema
xmlschema.install_translation(localedir='../mylocale', languages=['fur'])
schema = xmlschema.XMLSchema(...)

Binary file added xmlschema/locale/ru/LC_MESSAGES/xmlschema.mo
Binary file not shown.
94 changes: 94 additions & 0 deletions xmlschema/locale/ru/LC_MESSAGES/xmlschema.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# SOME DESCRIPTIVE TITLE.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add copyright info on this part.
If it's not a problem also add author info.

Copy link
Contributor Author

@serwizz serwizz Apr 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, it was autogenerated by xgettext utility

# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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} не булево значение"
94 changes: 94 additions & 0 deletions xmlschema/locale/xmlschema.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# SOME DESCRIPTIVE TITLE.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A script or an utilily function for regenerate this POT file could be useful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe need adding Localization section in README with helpful utilities. In fact they may be not easy to use.

# generate *.pot file with all strings, that must be translated
xgettext xmlschema/validators/simple_types.py xmlschema/validators/exceptions.py -o xmlschema/locale/xmlschema.pot
# update locale *.po file from *.pot
msgmerge xmlschema/locale/ru/LC_MESSAGES/xmlschema.po xmlschema/locale/xmlschema.pot -o xmlschema/locale/ru/LC_MESSAGES/xmlschema.po
# generate *.mo file from locale *.po
msgfmt xmlschema/locale/ru/LC_MESSAGES/xmlschema.po -o xmlschema/locale/ru/LC_MESSAGES/xmlschema.mo

# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 ""
9 changes: 5 additions & 4 deletions xmlschema/validators/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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." % (
Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion xmlschema/validators/global_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 _


#
Expand Down Expand Up @@ -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'

Expand Down
Loading