diff options
author | Jason Madden <jamadden@gmail.com> | 2015-06-04 17:24:26 -0500 |
---|---|---|
committer | Jason Madden <jamadden@gmail.com> | 2015-06-04 17:24:26 -0500 |
commit | e016951ed2c8f925b576052bdb20c8cccc91e3bd (patch) | |
tree | 47d9adabdfefff7b4427054ee1eb9a8f0bb6cbac | |
parent | 82281eb7ee9a2e71af6011053670648fdf31e938 (diff) | |
download | zope-i18n-e016951ed2c8f925b576052bdb20c8cccc91e3bd.tar.gz |
Add support for PyPy3 and Python3.2
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | CHANGES.rst | 5 | ||||
-rw-r--r-- | setup.py | 1 | ||||
-rw-r--r-- | src/zope/i18n/__init__.py | 25 | ||||
-rw-r--r-- | src/zope/i18n/_compat.py | 32 | ||||
-rw-r--r-- | src/zope/i18n/format.py | 44 | ||||
-rw-r--r-- | src/zope/i18n/interfaces/__init__.py | 41 | ||||
-rw-r--r-- | src/zope/i18n/interfaces/locales.py | 500 | ||||
-rw-r--r-- | src/zope/i18n/locales/__init__.py | 75 | ||||
-rw-r--r-- | src/zope/i18n/locales/fallbackcollator.txt | 17 | ||||
-rw-r--r-- | src/zope/i18n/locales/xmlfactory.py | 231 | ||||
-rw-r--r-- | src/zope/i18n/testmessagecatalog.py | 9 | ||||
-rw-r--r-- | src/zope/i18n/testmessagecatalog.txt | 8 | ||||
-rw-r--r-- | src/zope/i18n/tests/test_formats.py | 40 | ||||
-rw-r--r-- | src/zope/i18n/tests/test_translationdomain.py | 38 | ||||
-rw-r--r-- | src/zope/i18n/tests/test_zcml.py | 21 | ||||
-rw-r--r-- | src/zope/i18n/translationdomain.py | 9 | ||||
-rw-r--r-- | src/zope/i18n/zcml.py | 12 | ||||
-rw-r--r-- | tox.ini | 2 |
19 files changed, 585 insertions, 527 deletions
diff --git a/.travis.yml b/.travis.yml index e1ccd66..8cf9441 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,11 @@ sudo: false env: - TOXENV=py26 - TOXENV=py27 + - TOXENV=py32 - TOXENV=py33 - TOXENV=py34 - TOXENV=pypy + - TOXENV=pypy3 install: - travis_retry pip install tox diff --git a/CHANGES.rst b/CHANGES.rst index a8e7cc1..6b185ae 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,11 @@ CHANGES ======= +4.0.1 (unreleased) +-------------------- + +- Added support for Python 3.2 and PyPy3. + 4.0.0 (2014-12-20) -------------------- @@ -64,6 +64,7 @@ setup( 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: Implementation :: CPython', diff --git a/src/zope/i18n/__init__.py b/src/zope/i18n/__init__.py index ca4974e..6cb8443 100644 --- a/src/zope/i18n/__init__.py +++ b/src/zope/i18n/__init__.py @@ -24,6 +24,8 @@ from zope.i18n.interfaces import INegotiator from zope.i18n.interfaces import ITranslationDomain from zope.i18n.interfaces import IFallbackTranslationDomainFactory +from ._compat import _u + PY3 = sys.version_info[0] == 3 if PY3: unicode = str @@ -69,14 +71,14 @@ def translate(msgid, domain=None, mapping=None, context=None, Normally, the translation system will use a domain utility: - >>> component.provideUtility(TestDomain(eek=u'ook'), name='my.domain') - >>> translate(u'eek', 'my.domain') + >>> component.provideUtility(TestDomain(eek=_u("ook")), name='my.domain') + >>> translate(_u("eek"), 'my.domain') u'ook' Normally, if no domain is given, or if there is no domain utility for the given domain, then the text isn't translated: - >>> translate(u'eek') + >>> translate(_u("eek")) u'eek' Moreover the text will be converted to unicode: @@ -87,8 +89,8 @@ def translate(msgid, domain=None, mapping=None, context=None, A fallback domain factory can be provided. This is normally used for testing: - >>> def fallback(domain=u''): - ... return TestDomain(eek=u'test-from-' + domain) + >>> def fallback(domain=_u("")): + ... return TestDomain(eek=_u("test-from-") + domain) >>> interface.directlyProvides( ... fallback, ... zope.i18n.interfaces.IFallbackTranslationDomainFactory, @@ -96,10 +98,10 @@ def translate(msgid, domain=None, mapping=None, context=None, >>> component.provideUtility(fallback) - >>> translate(u'eek') + >>> translate(_u("eek")) u'test-from-' - >>> translate(u'eek', 'your.domain') + >>> translate(_u("eek"), 'your.domain') u'test-from-your.domain' """ @@ -139,23 +141,24 @@ def interpolate(text, mapping=None): In the text we can use substitution slots like $varname or ${varname}: - >>> interpolate(u"This is $name version ${version}.", mapping) + >>> from zope.i18n._compat import _u + >>> interpolate(_u("This is $name version ${version}."), mapping) u'This is Zope version 3.' Interpolation variables can be used more than once in the text: - >>> interpolate(u"This is $name version ${version}. ${name} $version!", + >>> interpolate(_u("This is $name version ${version}. ${name} $version!"), ... mapping) u'This is Zope version 3. Zope 3!' In case if the variable wasn't found in the mapping or '$$' form was used no substitution will happens: - >>> interpolate(u"This is $name $version. $unknown $$name $${version}.", + >>> interpolate(_u("This is $name $version. $unknown $$name $${version}."), ... mapping) u'This is Zope 3. $unknown $$name $${version}.' - >>> interpolate(u"This is ${name}") + >>> interpolate(_u("This is ${name}")) u'This is ${name}' """ diff --git a/src/zope/i18n/_compat.py b/src/zope/i18n/_compat.py new file mode 100644 index 0000000..09b3f74 --- /dev/null +++ b/src/zope/i18n/_compat.py @@ -0,0 +1,32 @@ +############################################################################## +# +# Copyright (c) 2015 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE +# +############################################################################## +import sys + +if sys.version_info[0] < 3: #pragma NO COVER Python2 + + PY2 = True + PY3 = False + + def _u(s, encoding='unicode_escape'): + return unicode(s, encoding) + +else: #pragma NO COVER Python3 + + PY2 = False + PY3 = True + + def _u(s, encoding=None): + if encoding is None: + return s + return str(s, encoding) diff --git a/src/zope/i18n/format.py b/src/zope/i18n/format.py index 51d64f1..7095ece 100644 --- a/src/zope/i18n/format.py +++ b/src/zope/i18n/format.py @@ -26,6 +26,8 @@ import pytz.reference from zope.i18n.interfaces import IDateTimeFormat, INumberFormat from zope.interface import implementer +from ._compat import _u + PY3 = sys.version_info[0] == 3 if PY3: unicode = str @@ -199,7 +201,7 @@ class DateTimeFormat(object): else: bin_pattern = self._bin_pattern - text = u'' + text = _u("") info = buildDateTimeInfo(obj, self.calendar, bin_pattern) for elem in bin_pattern: text += info.get(elem, elem) @@ -222,18 +224,18 @@ class NumberFormat(object): def __init__(self, pattern=None, symbols={}): # setup default symbols self.symbols = { - u'decimal': u'.', - u'group': u',', - u'list': u';', - u'percentSign': u'%', - u'nativeZeroDigit': u'0', - u'patternDigit': u'#', - u'plusSign': u'+', - u'minusSign': u'-', - u'exponential': u'E', - u'perMille': u'\xe2\x88\x9e', - u'infinity': u'\xef\xbf\xbd', - u'nan': '' } + _u("decimal"): _u("."), + _u("group"): _u(","), + _u("list"): _u(";"), + _u("percentSign"): _u("%"), + _u("nativeZeroDigit"): _u("0"), + _u("patternDigit"): _u("#"), + _u("plusSign"): _u("+"), + _u("minusSign"): _u("-"), + _u("exponential"): _u("E"), + _u("perMille"): _u("\xe2\x88\x9e"), + _u("infinity"): _u("\xef\xbf\xbd"), + _u("nan"): '' } self.symbols.update(symbols) self._pattern = pattern self._bin_pattern = None @@ -373,7 +375,7 @@ class NumberFormat(object): # The exponential might have a mandatory sign; remove it from the # bin_pattern and remember the setting exp_bin_pattern = bin_pattern[EXPONENTIAL] - plus_sign = u'' + plus_sign = _u("") if exp_bin_pattern.startswith('+'): plus_sign = self.symbols['plusSign'] exp_bin_pattern = exp_bin_pattern[1:] @@ -656,7 +658,7 @@ def buildDateTimeInfo(dt, calendar, pattern): ('S', dt.microsecond), ('w', int(dt.strftime('%W'))), ('W', week_in_month)): for entry in _findFormattingCharacterInPattern(field, pattern): - info[entry] = (u'%%.%ii' %entry[1]) %value + info[entry] = (_u("%%.%ii") %entry[1]) %value # am/pm marker (Text) for entry in _findFormattingCharacterInPattern('a', pattern): @@ -670,9 +672,9 @@ def buildDateTimeInfo(dt, calendar, pattern): # time zone (Text) for entry in _findFormattingCharacterInPattern('z', pattern): if entry[1] == 1: - info[entry] = u"%s%i%.2i" %(tz_sign, tz_hours, tz_mins) + info[entry] = _u("%s%i%.2i") %(tz_sign, tz_hours, tz_mins) elif entry[1] == 2: - info[entry] = u"%s%.2i:%.2i" %(tz_sign, tz_hours, tz_mins) + info[entry] = _u("%s%.2i:%.2i") %(tz_sign, tz_hours, tz_mins) elif entry[1] == 3: info[entry] = tz_name else: @@ -681,9 +683,9 @@ def buildDateTimeInfo(dt, calendar, pattern): # month in year (Text and Number) for entry in _findFormattingCharacterInPattern('M', pattern): if entry[1] == 1: - info[entry] = u'%i' %dt.month + info[entry] = _u("%i") %dt.month elif entry[1] == 2: - info[entry] = u'%.2i' %dt.month + info[entry] = _u("%.2i") %dt.month elif entry[1] == 3: info[entry] = calendar.months[dt.month][1] else: @@ -692,9 +694,9 @@ def buildDateTimeInfo(dt, calendar, pattern): # day in week (Text and Number) for entry in _findFormattingCharacterInPattern('E', pattern): if entry[1] == 1: - info[entry] = u'%i' %weekday + info[entry] = _u("%i") %weekday elif entry[1] == 2: - info[entry] = u'%.2i' %weekday + info[entry] = _u("%.2i") %weekday elif entry[1] == 3: info[entry] = calendar.days[dt.weekday() + 1][1] else: diff --git a/src/zope/i18n/interfaces/__init__.py b/src/zope/i18n/interfaces/__init__.py index 99944c2..9cee5c6 100644 --- a/src/zope/i18n/interfaces/__init__.py +++ b/src/zope/i18n/interfaces/__init__.py @@ -16,6 +16,7 @@ from zope.interface import Interface, Attribute from zope.schema import TextLine, Dict, Choice, Field +from .._compat import _u class II18nAware(Interface): """Internationalization aware content object.""" @@ -68,13 +69,13 @@ class IMessageCatalog(Interface): """ language = TextLine( - title=u"Language", - description=u"The language the catalog translates to.", + title=_u("Language"), + description=_u("The language the catalog translates to."), required=True) domain = TextLine( - title=u"Domain", - description=u"The domain the catalog is registered for.", + title=_u("Domain"), + description=_u("The domain the catalog is registered for."), required=True) def getIdentifier(): @@ -128,8 +129,8 @@ class ITranslationDomain(Interface): """ domain = TextLine( - title=u"Domain Name", - description=u"The name of the domain this object represents.", + title=_u("Domain Name"), + description=_u("The name of the domain this object represents."), required=True) def translate(msgid, mapping=None, context=None, target_language=None, @@ -154,8 +155,8 @@ class IFallbackTranslationDomainFactory(Interface): debugging i18n. """ - def __call__(domain_id=u''): - """Return a fallback translation domain for the given domain id. + def __call__(domain_id=_u("")): + """Return a fallback translation domain for the given domain id. """ class ITranslator(Interface): @@ -302,7 +303,7 @@ class IFormat(Interface): class INumberFormat(IFormat): - u"""Specific number formatting interface. Here are the formatting + """Specific number formatting interface. Here are the formatting rules (I modified the rules from ICU a bit, since I think they did not agree well with the real world XML formatting strings): @@ -356,22 +357,22 @@ class INumberFormat(IFormat): """ type = Field( - title=u'Type', - description=(u'The type into which a string is parsed. If ``None``, ' - u'then ``int`` will be used for whole numbers and ' - u'``float`` for decimals.'), + title=_u("Type"), + description=(_u("The type into which a string is parsed. If ``None``, " + "then ``int`` will be used for whole numbers and " + "``float`` for decimals.")), default=None, required=False) symbols = Dict( - title=u"Number Symbols", + title=_u("Number Symbols"), key_type=Choice( - title=u"Dictionary Class", - values=(u'decimal', u'group', u'list', u'percentSign', - u'nativeZeroDigit', u'patternDigit', u'plusSign', - u'minusSign', u'exponential', u'perMille', - u'infinity', u'nan')), - value_type=TextLine(title=u"Symbol")) + title=_u("Dictionary Class"), + values=(_u("decimal"), _u("group"), _u("list"), _u("percentSign"), + _u("nativeZeroDigit"), _u("patternDigit"), _u("plusSign"), + _u("minusSign"), _u("exponential"), _u("perMille"), + _u("infinity"), _u("nan"))), + value_type=TextLine(title=_u("Symbol"))) class IDateTimeFormat(IFormat): diff --git a/src/zope/i18n/interfaces/locales.py b/src/zope/i18n/interfaces/locales.py index e054d08..25d64de 100644 --- a/src/zope/i18n/interfaces/locales.py +++ b/src/zope/i18n/interfaces/locales.py @@ -18,6 +18,7 @@ from zope.interface import Interface, Attribute from zope.schema import \ Field, Text, TextLine, Int, Bool, Tuple, List, Dict, Date from zope.schema import Container, Choice +from .._compat import _u class ILocaleProvider(Interface): """This interface is our connection to the Zope 3 service. From it @@ -64,37 +65,37 @@ class ILocaleIdentity(Interface): """ language = TextLine( - title = u"Language Type", - description = u"The language for which a locale is applicable.", + title = _u("Language Type"), + description = _u("The language for which a locale is applicable."), constraint = re.compile(r'[a-z]{2}').match, required = True, readonly = True) script = TextLine( - title = u"Script Type", - description = u"""The script for which the language/locale is - applicable.""", + title = _u("Script Type"), + description = _u("""The script for which the language/locale is + applicable."""), constraint = re.compile(r'[a-z]*').match) territory = TextLine( - title = u"Territory Type", - description = u"The territory for which a locale is applicable.", + title = _u("Territory Type"), + description = _u("The territory for which a locale is applicable."), constraint = re.compile(r'[A-Z]{2}').match, required = True, readonly = True) variant = TextLine( - title = u"Variant Type", - description = u"The variant for which a locale is applicable.", + title = _u("Variant Type"), + description = _u("The variant for which a locale is applicable."), constraint = re.compile(r'[a-zA-Z]*').match, required = True, readonly = True) version = Field( - title = u"Locale Version", - description = u"The value of this field is an ILocaleVersion object.", + title = _u("Locale Version"), + description = _u("The value of this field is an ILocaleVersion object."), readonly = True) - + def __repr__(self): """Defines the representation of the id, which should be a compact string that references the language, country and variant.""" @@ -105,23 +106,23 @@ class ILocaleVersion(Interface): The locale version is part of the ILocaleIdentity object. """ - + number = TextLine( - title = u"Version Number", - description = u"The version number of the locale.", + title = _u("Version Number"), + description = _u("The version number of the locale."), constraint = re.compile(r'^([0-9].)*[0-9]$').match, required = True, readonly = True) generationDate = Date( - title = u"Generation Date", - description = u"Specifies the creation date of the locale.", + title = _u("Generation Date"), + description = _u("Specifies the creation date of the locale."), constraint = lambda date: date < datetime.now(), readonly = True) notes = Text( - title = u"Notes", - description = u"Some release notes for the version of this locale.", + title = _u("Notes"), + description = _u("Some release notes for the version of this locale."), readonly = True) @@ -132,36 +133,36 @@ class ILocaleDisplayNames(Interface): language, script and territory names. But also keys and types used throughout the locale object are localized here. """ - + languages = Dict( - title = u"Language type to translated name", - key_type = TextLine(title=u"Language Type"), - value_type = TextLine(title=u"Language Name")) + title = _u("Language type to translated name"), + key_type = TextLine(title=_u("Language Type")), + value_type = TextLine(title=_u("Language Name"))) scripts = Dict( - title = u"Script type to script name", - key_type = TextLine(title=u"Script Type"), - value_type = TextLine(title=u"Script Name")) + title = _u("Script type to script name"), + key_type = TextLine(title=_u("Script Type")), + value_type = TextLine(title=_u("Script Name"))) territories = Dict( - title = u"Territory type to translated territory name", - key_type = TextLine(title=u"Territory Type"), - value_type = TextLine(title=u"Territory Name")) + title = _u("Territory type to translated territory name"), + key_type = TextLine(title=_u("Territory Type")), + value_type = TextLine(title=_u("Territory Name"))) variants = Dict( - title = u"Variant type to name", - key_type = TextLine(title=u"Variant Type"), - value_type = TextLine(title=u"Variant Name")) + title = _u("Variant type to name"), + key_type = TextLine(title=_u("Variant Type")), + value_type = TextLine(title=_u("Variant Name"))) keys = Dict( - title = u"Key type to name", - key_type = TextLine(title=u"Key Type"), - value_type = TextLine(title=u"Key Name")) + title = _u("Key type to name"), + key_type = TextLine(title=_u("Key Type")), + value_type = TextLine(title=_u("Key Name"))) types = Dict( - title = u"Type type and key to localized name", - key_type = Tuple(title=u"Type Type and Key"), - value_type = TextLine(title=u"Type Name")) + title = _u("Type type and key to localized name"), + key_type = Tuple(title=_u("Type Type and Key")), + value_type = TextLine(title=_u("Type Name"))) class ILocaleTimeZone(Interface): @@ -174,26 +175,26 @@ class ILocaleTimeZone(Interface): """ type = TextLine( - title = u"Time Zone Type", - description = u"Standard name of the timezone for unique referencing.", + title = _u("Time Zone Type"), + description = _u("Standard name of the timezone for unique referencing."), required = True, readonly = True) cities = List( - title = u"Cities", - description = u"Cities in Timezone", - value_type = TextLine(title=u"City Name"), + title = _u("Cities"), + description = _u("Cities in Timezone"), + value_type = TextLine(title=_u("City Name")), required = True, readonly = True) names = Dict( - title = u"Time Zone Names", - description = u"Various names of the timezone.", + title = _u("Time Zone Names"), + description = _u("Various names of the timezone."), key_type = Choice( - title = u"Time Zone Name Type", - values = (u'generic', u'standard', u'daylight')), - value_type = Tuple(title=u"Time Zone Name and Abbreviation", + title = _u("Time Zone Name Type"), + values = (_u("generic"), _u("standard"), _u("daylight"))), + value_type = Tuple(title=_u("Time Zone Name and Abbreviation"), min_length=2, max_length=2), required = True, readonly = True) @@ -203,44 +204,44 @@ class ILocaleFormat(Interface): """Specifies a format for a particular type of data.""" type = TextLine( - title=u"Format Type", - description=u"The name of the format", + title=_u("Format Type"), + description=_u("The name of the format"), required = False, readonly = True) displayName = TextLine( - title = u"Display Name", - description = u"Name of the calendar, for example 'gregorian'.", + title = _u("Display Name"), + description = _u("Name of the calendar, for example 'gregorian'."), required = False, readonly = True) pattern = TextLine( - title = u"Format Pattern", - description = u"The pattern that is used to format the object.", + title = _u("Format Pattern"), + description = _u("The pattern that is used to format the object."), required = True, readonly = True) class ILocaleFormatLength(Interface): """The format length describes a class of formats.""" - + type = Choice( - title = u"Format Length Type", - description = u"Name of the format length", - values = (u'full', u'long', u'medium', u'short') + title = _u("Format Length Type"), + description = _u("Name of the format length"), + values = (_u("full"), _u("long"), _u("medium"), _u("short")) ) default = TextLine( - title=u"Default Format", - description=u"The name of the defaulkt format.") + title=_u("Default Format"), + description=_u("The name of the defaulkt format.")) formats = Dict( - title = u"Formats", - description = u"Maps format types to format objects", - key_type = TextLine(title = u"Format Type"), + title = _u("Formats"), + description = _u("Maps format types to format objects"), + key_type = TextLine(title = _u("Format Type")), value_type = Field( - title = u"Format Object", - description = u"Values are ILocaleFormat objects."), + title = _u("Format Object"), + description = _u("Values are ILocaleFormat objects.")), required = True, readonly = True) @@ -249,24 +250,24 @@ class ILocaleMonthContext(Interface): """Specifices a usage context for month names""" type = TextLine( - title=u'Month context type', - description=u"Name of the month context, format or stand-alone.") + title=_u("Month context type"), + description=_u("Name of the month context, format or stand-alone.")) defaultWidth = TextLine( - title=u'Default month name width', - default=u'wide') + title=_u("Default month name width"), + default=_u("wide")) months = Dict( - title=u'Month Names', - description=u'A mapping of month name widths to a mapping of' - u'corresponding month names.', + title=_u("Month Names"), + description=_u("A mapping of month name widths to a mapping of" + "corresponding month names."), key_type=Choice( - title=u'Width type', - values=(u'wide', u'abbreviated', u'narrow')), + title=_u("Width type"), + values=(_u("wide"), _u("abbreviated"), _u("narrow"))), value_type=Dict( - title=u'Month name', - key_type=Int(title=u'Type', min=1, max=12), - value_type=TextLine(title=u'Month Name')) + title=_u("Month name"), + key_type=Int(title=_u("Type"), min=1, max=12), + value_type=TextLine(title=_u("Month Name"))) ) @@ -274,27 +275,27 @@ class ILocaleDayContext(Interface): """Specifices a usage context for days names""" type = TextLine( - title=u'Day context type', - description=u"Name of the day context, format or stand-alone.") + title=_u("Day context type"), + description=_u("Name of the day context, format or stand-alone.")) defaultWidth = TextLine( - title=u'Default day name width', - default=u'wide') + title=_u("Default day name width"), + default=_u("wide")) days = Dict( - title=u'Day Names', - description=u'A mapping of day name widths to a mapping of' - u'corresponding day names.', + title=_u("Day Names"), + description=_u("A mapping of day name widths to a mapping of" + "corresponding day names."), key_type=Choice( - title=u'Width type', - values=(u'wide', u'abbreviated', u'narrow')), + title=_u("Width type"), + values=(_u("wide"), _u("abbreviated"), _u("narrow"))), value_type=Dict( - title=u'Day name', + title=_u("Day name"), key_type=Choice( - title=u"Type", - values=(u'sun', u'mon', u'tue', u'wed', - u'thu', u'fri', u'sat')), - value_type=TextLine(title=u'Day Name')) + title=_u("Type"), + values=(_u("sun"), _u("mon"), _u("tue"), _u("wed"), + _u("thu"), _u("fri"), _u("sat"))), + value_type=TextLine(title=_u("Day Name"))) ) @@ -303,57 +304,57 @@ class ILocaleCalendar(Interface): which made it attractive to be added.""" type = TextLine( - title=u"Calendar Type", - description=u"Name of the calendar, for example 'gregorian'.") + title=_u("Calendar Type"), + description=_u("Name of the calendar, for example 'gregorian'.")) defaultMonthContext = TextLine( - title=u'Default month context', - default=u'format') - + title=_u("Default month context"), + default=_u("format")) + monthContexts = Dict( - title=u'Month Contexts', - description=u'A mapping of month context types to ' - u'ILocaleMonthContext objects', - key_type=Choice(title=u'Type', - values=(u'format', u'stand-alone')), - value_type=Field(title=u'ILocaleMonthContext object')) + title=_u("Month Contexts"), + description=_u("A mapping of month context types to " + "ILocaleMonthContext objects"), + key_type=Choice(title=_u("Type"), + values=(_u("format"), _u("stand-alone"))), + value_type=Field(title=_u("ILocaleMonthContext object"))) # BBB: leftover from CLDR 1.0 months = Dict( - title = u"Month Names", - description = u"A mapping of all month names and abbreviations", - key_type = Int(title=u"Type", min=1, max=12), - value_type = Tuple(title=u"Month Name and Abbreviation", + title = _u("Month Names"), + description = _u("A mapping of all month names and abbreviations"), + key_type = Int(title=_u("Type"), min=1, max=12), + value_type = Tuple(title=_u("Month Name and Abbreviation"), min_length=2, max_length=2)) defaultDayContext = TextLine( - title=u'Default day context', - default=u'format') - + title=_u("Default day context"), + default=_u("format")) + dayContexts = Dict( - title=u'Day Contexts', - description=u'A mapping of day context types to ' - u'ILocaleDayContext objects', - key_type=Choice(title=u'Type', - values=(u'format', u'stand-alone')), - value_type=Field(title=u'ILocaleDayContext object')) + title=_u("Day Contexts"), + description=_u("A mapping of day context types to " + "ILocaleDayContext objects"), + key_type=Choice(title=_u("Type"), + values=(_u("format"), _u("stand-alone"))), + value_type=Field(title=_u("ILocaleDayContext object"))) # BBB: leftover from CLDR 1.0 days = Dict( - title=u"Weekdays Names", - description = u"A mapping of all month names and abbreviations", - key_type = Choice(title=u"Type", - values=(u'sun', u'mon', u'tue', u'wed', - u'thu', u'fri', u'sat')), - value_type = Tuple(title=u"Weekdays Name and Abbreviation", + title=_u("Weekdays Names"), + description = _u("A mapping of all month names and abbreviations"), + key_type = Choice(title=_u("Type"), + values=(_u("sun"), _u("mon"), _u("tue"), _u("wed"), + _u("thu"), _u("fri"), _u("sat"))), + value_type = Tuple(title=_u("Weekdays Name and Abbreviation"), min_length=2, max_length=2)) week = Dict( - title=u"Week Information", - description = u"Contains various week information", + title=_u("Week Information"), + description = _u("Contains various week information"), key_type = Choice( - title=u"Type", - description=u""" + title=_u("Type"), + description=_u(""" Varies Week information: - 'minDays' is just an integer between 1 and 7. @@ -362,52 +363,52 @@ class ILocaleCalendar(Interface): - The 'weekendStart' and 'weekendEnd' are tuples of the form (weekDayNumber, datetime.time) - """, - values=(u'minDays', u'firstDay', - u'weekendStart', u'weekendEnd'))) + """), + values=(_u("minDays"), _u("firstDay"), + _u("weekendStart"), _u("weekendEnd")))) - am = TextLine(title=u"AM String") + am = TextLine(title=_u("AM String")) - pm = TextLine(title=u"PM String") + pm = TextLine(title=_u("PM String")) eras = Dict( - title = u"Era Names", - key_type = Int(title=u"Type", min=0), - value_type = Tuple(title=u"Era Name and Abbreviation", + title = _u("Era Names"), + key_type = Int(title=_u("Type"), min=0), + value_type = Tuple(title=_u("Era Name and Abbreviation"), min_length=2, max_length=2)) - defaultDateFormat = TextLine(title=u"Default Date Format Type") + defaultDateFormat = TextLine(title=_u("Default Date Format Type")) dateFormats = Dict( - title=u"Date Formats", - description = u"Contains various Date Formats.", + title=_u("Date Formats"), + description = _u("Contains various Date Formats."), key_type = Choice( - title=u"Type", - description = u"Name of the format length", - values = (u'full', u'long', u'medium', u'short')), - value_type = Field(title=u"ILocaleFormatLength object")) + title=_u("Type"), + description = _u("Name of the format length"), + values = (_u("full"), _u("long"), _u("medium"), _u("short"))), + value_type = Field(title=_u("ILocaleFormatLength object"))) - defaultTimeFormat = TextLine(title=u"Default Time Format Type") + defaultTimeFormat = TextLine(title=_u("Default Time Format Type")) timeFormats = Dict( - title=u"Time Formats", - description = u"Contains various Time Formats.", + title=_u("Time Formats"), + description = _u("Contains various Time Formats."), key_type = Choice( - title=u"Type", - description = u"Name of the format length", - values = (u'full', u'long', u'medium', u'short')), - value_type = Field(title=u"ILocaleFormatLength object")) + title=_u("Type"), + description = _u("Name of the format length"), + values = (_u("full"), _u("long"), _u("medium"), _u("short"))), + value_type = Field(title=_u("ILocaleFormatLength object"))) - defaultDateTimeFormat = TextLine(title=u"Default Date-Time Format Type") + defaultDateTimeFormat = TextLine(title=_u("Default Date-Time Format Type")) dateTimeFormats = Dict( - title=u"Date-Time Formats", - description = u"Contains various Date-Time Formats.", + title=_u("Date-Time Formats"), + description = _u("Contains various Date-Time Formats."), key_type = Choice( - title=u"Type", - description = u"Name of the format length", - values = (u'full', u'long', u'medium', u'short')), - value_type = Field(title=u"ILocaleFormatLength object")) + title=_u("Type"), + description = _u("Name of the format length"), + values = (_u("full"), _u("long"), _u("medium"), _u("short"))), + value_type = Field(title=_u("ILocaleFormatLength object"))) def getMonthNames(): """Return a list of month names.""" @@ -437,37 +438,37 @@ class ILocaleCalendar(Interface): """Determines whether a the argument lies in a weekend.""" def getFirstDayName(): - """Return the the type of the first day in the week.""" + """Return the the type of the first day in the week.""" class ILocaleDates(Interface): """This object contains various data about dates, times and time zones.""" localizedPatternChars = TextLine( - title = u"Localized Pattern Characters", - description = u"Localized pattern characters used in dates and times") + title = _u("Localized Pattern Characters"), + description = _u("Localized pattern characters used in dates and times")) calendars = Dict( - title = u"Calendar type to ILocaleCalendar", + title = _u("Calendar type to ILocaleCalendar"), key_type = Choice( - title=u"Calendar Type", - values=(u'gregorian', - u'arabic', - u'chinese', - u'civil-arabic', - u'hebrew', - u'japanese', - u'thai-buddhist')), - value_type=Field(title=u"Calendar", - description=u"This is a ILocaleCalendar object.")) + title=_u("Calendar Type"), + values=(_u("gregorian"), + _u("arabic"), + _u("chinese"), + _u("civil-arabic"), + _u("hebrew"), + _u("japanese"), + _u("thai-buddhist"))), + value_type=Field(title=_u("Calendar"), + description=_u("This is a ILocaleCalendar object."))) timezones = Dict( - title=u"Time zone type to ILocaleTimezone", - key_type=TextLine(title=u"Time Zone type"), - value_type=Field(title=u"Time Zone", - description=u"This is a ILocaleTimeZone object.")) + title=_u("Time zone type to ILocaleTimezone"), + key_type=TextLine(title=_u("Time Zone type")), + value_type=Field(title=_u("Time Zone"), + description=_u("This is a ILocaleTimeZone object."))) - def getFormatter(category, length=None, name=None, calendar=u'gregorian'): + def getFormatter(category, length=None, name=None, calendar=_u("gregorian")): """Get a date/time formatter. `category` must be one of 'date', 'dateTime', 'time'. @@ -481,81 +482,81 @@ class ILocaleDates(Interface): class ILocaleCurrency(Interface): """Defines a particular currency.""" - type = TextLine(title=u'Type') + type = TextLine(title=_u("Type")) - symbol = TextLine(title=u'Symbol') + symbol = TextLine(title=_u("Symbol")) - displayName = TextLine(title=u'Official Name') + displayName = TextLine(title=_u("Official Name")) - symbolChoice = Bool(title=u'Symbol Choice') + symbolChoice = Bool(title=_u("Symbol Choice")) class ILocaleNumbers(Interface): """This object contains various data about numbers and currencies.""" symbols = Dict( - title = u"Number Symbols", + title = _u("Number Symbols"), key_type = Choice( - title = u"Format Name", - values = (u'decimal', u'group', u'list', u'percentSign', - u'nativeZeroDigit', u'patternDigit', u'plusSign', - u'minusSign', u'exponential', u'perMille', - u'infinity', u'nan')), - value_type=TextLine(title=u"Symbol")) + title = _u("Format Name"), + values = (_u("decimal"), _u("group"), _u("list"), _u("percentSign"), + _u("nativeZeroDigit"), _u("patternDigit"), _u("plusSign"), + _u("minusSign"), _u("exponential"), _u("perMille"), + _u("infinity"), _u("nan"))), + value_type=TextLine(title=_u("Symbol"))) - defaultDecimalFormat = TextLine(title=u"Default Decimal Format Type") + defaultDecimalFormat = TextLine(title=_u("Default Decimal Format Type")) decimalFormats = Dict( - title=u"Decimal Formats", - description = u"Contains various Decimal Formats.", + title=_u("Decimal Formats"), + description = _u("Contains various Decimal Formats."), key_type = Choice( - title=u"Type", - description = u"Name of the format length", - values = (u'full', u'long', u'medium', u'short')), - value_type = Field(title=u"ILocaleFormatLength object")) + title=_u("Type"), + description = _u("Name of the format length"), + values = (_u("full"), _u("long"), _u("medium"), _u("short"))), + value_type = Field(title=_u("ILocaleFormatLength object"))) - defaultScientificFormat = TextLine(title=u"Default Scientific Format Type") + defaultScientificFormat = TextLine(title=_u("Default Scientific Format Type")) scientificFormats = Dict( - title=u"Scientific Formats", - description = u"Contains various Scientific Formats.", + title=_u("Scientific Formats"), + description = _u("Contains various Scientific Formats."), key_type = Choice( - title=u"Type", - description = u"Name of the format length", - values = (u'full', u'long', u'medium', u'short')), - value_type = Field(title=u"ILocaleFormatLength object")) + title=_u("Type"), + description = _u("Name of the format length"), + values = (_u("full"), _u("long"), _u("medium"), _u("short"))), + value_type = Field(title=_u("ILocaleFormatLength object"))) - defaultPercentFormat = TextLine(title=u"Default Percent Format Type") + defaultPercentFormat = TextLine(title=_u("Default Percent Format Type")) percentFormats = Dict( - title=u"Percent Formats", - description = u"Contains various Percent Formats.", + title=_u("Percent Formats"), + description = _u("Contains various Percent Formats."), key_type = Choice( - title=u"Type", - description = u"Name of the format length", - values = (u'full', u'long', u'medium', u'short')), - value_type = Field(title=u"ILocaleFormatLength object")) + title=_u("Type"), + description = _u("Name of the format length"), + values = (_u("full"), _u("long"), _u("medium"), _u("short"))), + value_type = Field(title=_u("ILocaleFormatLength object"))) - defaultCurrencyFormat = TextLine(title=u"Default Currency Format Type") + defaultCurrencyFormat = TextLine(title=_u("Default Currency Format Type")) currencyFormats = Dict( - title=u"Currency Formats", - description = u"Contains various Currency Formats.", + title=_u("Currency Formats"), + description = _u("Contains various Currency Formats."), key_type = Choice( - title=u"Type", - description = u"Name of the format length", - values = (u'full', u'long', u'medium', u'short')), - value_type = Field(title=u"ILocaleFormatLength object")) + title=_u("Type"), + description = _u("Name of the format length"), + values = (_u("full"), _u("long"), _u("medium"), _u("short"))), + value_type = Field(title=_u("ILocaleFormatLength object"))) currencies = Dict( - title=u"Currencies", - description = u"Contains various Currency data.", + title=_u("Currencies"), + description = _u("Contains various Currency data."), key_type = TextLine( - title=u"Type", - description = u"Name of the format length"), - value_type = Field(title=u"ILocaleCurrency object")) + title=_u("Type"), + description = _u("Name of the format length")), + value_type = Field(title=_u("ILocaleCurrency object"))) - def getFormatter(category, length=None, name=u''): + def getFormatter(category, length=None, name=_u("")): """Get the NumberFormat based on the category, length and name of the format. @@ -575,23 +576,23 @@ class ILocaleNumbers(Interface): def getDefaultCurrency(): """Get the default currency.""" -_orientations = [u"left-to-right", u"right-to-left", - u"top-to-bottom", u"bottom-to-top"] +_orientations = [_u("left-to-right"), _u("right-to-left"), + _u("top-to-bottom"), _u("bottom-to-top")] class ILocaleOrientation(Interface): """Information about the orientation of text.""" characters = Choice( - title = u"Orientation of characters", + title = _u("Orientation of characters"), values = _orientations, - default = u"left-to-right" + default = _u("left-to-right") ) lines = Choice( - title = u"Orientation of characters", + title = _u("Orientation of characters"), values = _orientations, - default = u"top-to-bottom" + default = _u("top-to-bottom") ) - + class ILocale(Interface): """This class contains all important information about the locale. @@ -605,38 +606,39 @@ class ILocale(Interface): """ id = Field( - title = u"Locale identity", - description = u"ILocaleIdentity object identifying the locale.", + title = _u("Locale identity"), + description = _u("ILocaleIdentity object identifying the locale."), required = True, readonly = True) displayNames = Field( - title = u"Display Names", - description = u"""ILocaleDisplayNames object that contains localized - names.""") + title = _u("Display Names"), + description = _u("""ILocaleDisplayNames object that contains localized + names.""")) dates = Field( - title = u"Dates", - description = u"ILocaleDates object that contains date/time data.") + title = _u("Dates"), + description = _u("ILocaleDates object that contains date/time data.")) numbers = Field( - title = u"Numbers", - description = u"ILocaleNumbers object that contains number data.") + title = _u("Numbers"), + description = _u("ILocaleNumbers object that contains number data.")) orientation = Field( - title = u"Orientation", - description = u"ILocaleOrientation with text orientation info.") + title = _u("Orientation"), + description = _u("ILocaleOrientation with text orientation info.")) delimiters = Dict( - title=u"Delimiters", - description = u"Contains various Currency data.", + title=_u("Delimiters"), + description = _u("Contains various Currency data."), key_type = Choice( - title=u"Delimiter Type", - description = u"Delimiter name.", - values=(u'quotationStart', u'quotationEnd', - u'alternateQuotationStart', - u'alternateQuotationEnd')), - value_type = Field(title=u"Delimiter symbol")) + title=_u("Delimiter Type"), + description = _u("Delimiter name."), + values=(_u("quotationStart"), + _u("quotationEnd"), + _u("alternateQuotationStart"), + _u("alternateQuotationEnd"))), + value_type = Field(title=_u("Delimiter symbol"))) def getLocaleID(): """Return a locale id as specified in the LDML specification""" @@ -647,15 +649,15 @@ class ILocaleInheritance(Interface): Locale-related objects implementing this interface are able to ask for its inherited self. For example, 'en_US.dates.monthNames' can call on itself - 'getInheritedSelf()' and get the value for 'en.dates.monthNames'. + 'getInheritedSelf()' and get the value for 'en.dates.monthNames'. """ __parent__ = Attribute("The parent in the location hierarchy") __name__ = TextLine( - title = u"The name within the parent", - description=u"""The parent can be traversed with this name to get - the object.""") + title = _u("The name within the parent"), + description=_u("""The parent can be traversed with this name to get + the object.""")) def getInheritedSelf(): """Return itself but in the next higher up Locale.""" @@ -712,5 +714,3 @@ class ICollator(Interface): The return value is negative if text1 < text2, 0 is they are equal, and positive if text1 > text2. """ - - diff --git a/src/zope/i18n/locales/__init__.py b/src/zope/i18n/locales/__init__.py index da83db3..f36edd9 100644 --- a/src/zope/i18n/locales/__init__.py +++ b/src/zope/i18n/locales/__init__.py @@ -32,6 +32,7 @@ from zope.i18n.format import NumberFormat, DateTimeFormat from zope.i18n.locales.inheritance import \ AttributeInheritance, InheritingDictionary, NoParentException from zope.i18n.locales.provider import LocaleProvider, LoadLocaleError +from .._compat import _u # Setup the locale directory from zope import i18n @@ -223,8 +224,8 @@ class LocaleFormat(object): def __init__(self, type=None): """Initialize the object.""" self.type = type - self.displayName = u'' - self.pattern = u'' + self.displayName = _u("") + self.pattern = _u("") @implementer(ILocaleFormatLength) @@ -245,7 +246,7 @@ class LocaleMonthContext(AttributeInheritance): def __init__(self, type=None): """Initialize the object.""" self.type = type - self.default = u'wide' + self.default = _u("wide") @implementer(ILocaleDayContext) @@ -254,7 +255,7 @@ class LocaleDayContext(AttributeInheritance): def __init__(self, type=None): """Initialize the object.""" self.type = type - self.default = u'wide' + self.default = _u("wide") @implementer(ILocaleCalendar) @@ -279,44 +280,44 @@ class LocaleCalendar(AttributeInheritance): >>> locale.calendar = LocaleCalendar('gregorian') >>> root.calendar.months = InheritingDictionary( - ... {1: (u'January', u'Jan'), 2: (u'February', u'Feb')}) + ... {1: (_u("January"), _u("Jan")), 2: (_u("February"), _u("Feb"))}) >>> locale.calendar.months = InheritingDictionary( - ... {2: (u'Februar', u'Feb'), 3: (u'Maerz', u'Mrz')}) + ... {2: (_u("Februar"), _u("Feb")), 3: (_u("Maerz"), _u("Mrz"))}) >>> locale.calendar.getMonthNames()[:4] [u'January', u'Februar', u'Maerz', None] - >>> locale.calendar.getMonthTypeFromName(u'January') + >>> locale.calendar.getMonthTypeFromName(_u("January")) 1 - >>> locale.calendar.getMonthTypeFromName(u'Februar') + >>> locale.calendar.getMonthTypeFromName(_u("Februar")) 2 >>> locale.calendar.getMonthAbbreviations()[:4] [u'Jan', u'Feb', u'Mrz', None] - >>> locale.calendar.getMonthTypeFromAbbreviation(u'Jan') + >>> locale.calendar.getMonthTypeFromAbbreviation(_u("Jan")) 1 - >>> locale.calendar.getMonthTypeFromAbbreviation(u'Mrz') + >>> locale.calendar.getMonthTypeFromAbbreviation(_u("Mrz")) 3 >>> root.calendar.days = InheritingDictionary( - ... {1: (u'Monday', u'Mon'), 2: (u'Tuesday', u'Tue')}) + ... {1: (_u("Monday"), _u("Mon")), 2: (_u("Tuesday"), _u("Tue"))}) >>> locale.calendar.days = InheritingDictionary( - ... {2: (u'Dienstag', u'Die'), 3: (u'Mittwoch', u'Mit')}) + ... {2: (_u("Dienstag"), _u("Die")), 3: (_u("Mittwoch"), _u("Mit"))}) >>> locale.calendar.getDayNames()[:4] [u'Monday', u'Dienstag', u'Mittwoch', None] - >>> locale.calendar.getDayTypeFromName(u'Monday') + >>> locale.calendar.getDayTypeFromName(_u("Monday")) 1 - >>> locale.calendar.getDayTypeFromName(u'Dienstag') + >>> locale.calendar.getDayTypeFromName(_u("Dienstag")) 2 >>> locale.calendar.getDayAbbreviations()[:4] [u'Mon', u'Die', u'Mit', None] - >>> locale.calendar.getDayTypeFromAbbreviation(u'Mon') + >>> locale.calendar.getDayTypeFromAbbreviation(_u("Mon")) 1 - >>> locale.calendar.getDayTypeFromAbbreviation(u'Die') + >>> locale.calendar.getDayTypeFromAbbreviation(_u("Die")) 2 Let's test the direct attribute access as well. - >>> root.am = u'AM' - >>> root.pm = u'PM' - >>> locale.pm = u'nachm.' + >>> root.am = _u("AM") + >>> root.pm = _u("PM") + >>> locale.pm = _u("nachm.") >>> locale.pm u'nachm.' >>> locale.am @@ -403,12 +404,12 @@ class LocaleDates(AttributeInheritance): >>> fulllength = LocaleFormatLength() >>> format = LocaleFormat() - >>> format.pattern = u'EEEE, d. MMMM yyyy' + >>> format.pattern = _u("EEEE, d. MMMM yyyy") >>> fulllength.formats = {None: format} >>> mediumlength = LocaleFormatLength() >>> format = LocaleFormat() - >>> format.pattern = u'dd.MM.yyyy' + >>> format.pattern = _u("dd.MM.yyyy") >>> mediumlength.formats = {None: format} >>> cal.dateFormats = {'full': fulllength, 'medium': mediumlength} @@ -426,12 +427,12 @@ class LocaleDates(AttributeInheritance): >>> fulllength = LocaleFormatLength() >>> format = LocaleFormat() - >>> format.pattern = u"H:mm' Uhr 'z" + >>> format.pattern = _u("H:mm' Uhr 'z") >>> fulllength.formats = {None: format} >>> mediumlength = LocaleFormatLength() >>> format = LocaleFormat() - >>> format.pattern = u'HH:mm:ss' + >>> format.pattern = _u("HH:mm:ss") >>> mediumlength.formats = {None: format} >>> cal.timeFormats = {'full': fulllength, 'medium': mediumlength} @@ -450,7 +451,7 @@ class LocaleDates(AttributeInheritance): >>> length = LocaleFormatLength() >>> format = LocaleFormat() - >>> format.pattern = u'{1} {0}' + >>> format.pattern = _u("{1} {0}") >>> length.formats = {None: format} >>> cal.dateTimeFormats = {None: length} @@ -479,15 +480,15 @@ class LocaleDates(AttributeInheritance): """ def getFormatter(self, category, length=None, name=None, - calendar=u'gregorian'): + calendar=_u("gregorian")): """See zope.i18n.interfaces.locales.ILocaleDates""" - if category not in (u'date', u'time', u'dateTime'): + if category not in (_u("date"), _u("time"), _u("dateTime")): raise ValueError('Invalid category: %s' % category) - if calendar not in (u'gregorian', u'arabic', u'chinese', - u'civil-arabic', u'hebrew', u'japanese', - u'thai-buddhist'): + if calendar not in (_u("gregorian"), _u("arabic"), _u("chinese"), + _u("civil-arabic"), _u("hebrew"), _u("japanese"), + _u("thai-buddhist")): raise ValueError('Invalid calendar: %s' % calendar) - if length not in (u'short', u'medium', u'long', u'full', None): + if length not in (_u("short"), _u("medium"), _u("long"), _u("full"), None): raise ValueError('Invalid format length: %s' % length) cal = self.calendars[calendar] @@ -555,7 +556,7 @@ class LocaleNumbers(AttributeInheritance): >>> length = LocaleFormatLength() >>> format = LocaleFormat() - >>> format.pattern = u'#,##0.###;-#,##0.###' + >>> format.pattern = _u("#,##0.###;-#,##0.###") >>> length.formats = {None: format} >>> numbers.decimalFormats = {None: length} >>> formatter = numbers.getFormatter('decimal') @@ -570,11 +571,11 @@ class LocaleNumbers(AttributeInheritance): >>> longlength = LocaleFormatLength('long') >>> format = LocaleFormat() - >>> format.pattern = u'0.000###E+00' + >>> format.pattern = _u("0.000###E+00") >>> longlength.formats = {None: format} >>> mediumlength = LocaleFormatLength('long') >>> format = LocaleFormat() - >>> format.pattern = u'0.00##E+00' + >>> format.pattern = _u("0.00##E+00") >>> mediumlength.formats = {None: format} >>> numbers.scientificFormats = {'long': longlength, ... 'medium': mediumlength} @@ -591,9 +592,9 @@ class LocaleNumbers(AttributeInheritance): >>> longlength = LocaleFormatLength('long') >>> fooformat = LocaleFormat() - >>> fooformat.pattern = u'0.##0%' + >>> fooformat.pattern = _u("0.##0%") >>> barformat = LocaleFormat() - >>> barformat.pattern = u'0%' + >>> barformat.pattern = _u("0%") >>> longlength.formats = {None: fooformat, 'bar': barformat} >>> numbers.percentFormats = {'long': longlength} >>> numbers.defaultPercentFormat = 'long' @@ -615,8 +616,8 @@ class LocaleNumbers(AttributeInheritance): def getFormatter(self, category, length=None, name=None): """See zope.i18n.interfaces.locales.ILocaleNumbers""" - assert category in (u'decimal', u'percent', u'scientific', u'currency') - assert length in (u'short', u'medium', u'long', u'full', None) + assert category in (_u("decimal"), _u("percent"), _u("scientific"), _u("currency")) + assert length in (_u("short"), _u("medium"), _u("long"), _u("full"), None) formats = getattr(self, category+'Formats') if length is None: diff --git a/src/zope/i18n/locales/fallbackcollator.txt b/src/zope/i18n/locales/fallbackcollator.txt index 9457be2..727d6b1 100644 --- a/src/zope/i18n/locales/fallbackcollator.txt +++ b/src/zope/i18n/locales/fallbackcollator.txt @@ -10,7 +10,7 @@ true for English. :) Text collation is a fairly involved process. Systems that need this, will likely use something like ICU -(http://www-306.ibm.com/software/globalization/icu, +(http://www-306.ibm.com/software/globalization/icu, http://pyicu.osafoundation.org/). We don't want to introduce a dependency on ICU and this time, so we are providing a fallback collator that: @@ -31,7 +31,8 @@ application code should certainly *not* count on this. Now, we can pass the collator's key method to sort functions to sort strings in a slightly friendly way: - >>> sorted([u'Sam', u'sally', u'Abe', u'alice', u'Terry', u'tim'], + >>> from zope.i18n._compat import _u + >>> sorted([_u("Sam"), _u("sally"), _u("Abe"), _u("alice"), _u("Terry"), _u("tim")], ... key=collator.key) [u'Abe', u'alice', u'sally', u'Sam', u'Terry', u'tim'] @@ -41,23 +42,23 @@ then returns a tuple with the result of lower-casing the normalized string and the normalized string. We can see this by calling the key method, which converts unicode strings to collation keys: - >>> collator.key(u'Sam') + >>> collator.key(_u("Sam")) (u'sam', u'Sam') - >>> collator.key(u'\xc6\xf8a\u030a') + >>> collator.key(_u("\xc6\xf8a\u030a")) (u'\xe6\xf8\xe5', u'\xc6\xf8\xe5') There is also a cmp function for comparing strings: - >>> collator.cmp(u'Terry', u'sally') + >>> collator.cmp(_u("Terry"), _u("sally")) 1 - >>> collator.cmp(u'sally', u'Terry') + >>> collator.cmp(_u("sally"), _u("Terry")) -1 - >>> collator.cmp(u'terry', u'Terry') + >>> collator.cmp(_u("terry"), _u("Terry")) 1 - >>> collator.cmp(u'terry', u'terry') + >>> collator.cmp(_u("terry"), _u("terry")) 0 diff --git a/src/zope/i18n/locales/xmlfactory.py b/src/zope/i18n/locales/xmlfactory.py index 1276d7b..5d4fb3b 100644 --- a/src/zope/i18n/locales/xmlfactory.py +++ b/src/zope/i18n/locales/xmlfactory.py @@ -22,6 +22,9 @@ from zope.i18n.locales import LocaleFormat, LocaleFormatLength, dayMapping from zope.i18n.locales import LocaleOrientation, LocaleDayContext from zope.i18n.locales import LocaleMonthContext, calendarAliases from zope.i18n.locales.inheritance import InheritingDictionary +from .._compat import _u + +_BLANK = _u('') class LocaleFactory(object): """This class creates a Locale object from an ICU XML file.""" @@ -34,7 +37,7 @@ class LocaleFactory(object): self._data = parseXML(path).documentElement def _getText(self, nodelist): - rc = u'' + rc = _BLANK for node in nodelist: if node.nodeType == node.TEXT_NODE: rc = rc + node.data @@ -49,13 +52,13 @@ class LocaleFactory(object): >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <identity> ... <version number="1.0">Some notes</version> ... <generation date="2003-12-19" /> - ... <language type="de" /> - ... <territory type="DE" /> - ... </identity>''' + ... <language type="de" /> + ... <territory type="DE" /> + ... </identity>''') >>> dom = parseString(xml) >>> version = factory._extractVersion(dom.documentElement) @@ -79,7 +82,7 @@ class LocaleFactory(object): generationDate = date(int(year), int(month), int(day)) return LocaleVersion(number, generationDate, notes) - + def _extractIdentity(self): """Extract the Locale's identity object based on info from the DOM @@ -88,16 +91,16 @@ class LocaleFactory(object): Example:: >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <ldml> ... <identity> ... <version number="1.0"/> ... <generation date="2003-12-19" /> - ... <language type="en" /> - ... <territory type="US" /> - ... <variant type="POSIX" /> + ... <language type="en" /> + ... <territory type="US" /> + ... <variant type="POSIX" /> ... </identity> - ... </ldml>''' + ... </ldml>''') >>> factory = LocaleFactory(None) >>> factory._data = parseString(xml).documentElement @@ -130,7 +133,7 @@ class LocaleFactory(object): id.version = self._extractVersion(identity) return id - + def _extractTypes(self, names_node): """Extract all types from the names_node. @@ -139,7 +142,7 @@ class LocaleFactory(object): >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <displayNames> ... <types> ... <type type="Fallback" key="calendar"></type> @@ -149,7 +152,7 @@ class LocaleFactory(object): ... <type type="stroke" key="collation">STROKE</type> ... <type type="traditional" key="collation">TRADITIONAL</type> ... </types> - ... </displayNames>''' + ... </displayNames>''') >>> dom = parseString(xml) >>> types = factory._extractTypes(dom.documentElement) @@ -161,15 +164,15 @@ class LocaleFactory(object): [(u'chinese', u'calendar'), (u'gregorian', u'calendar')] >>> keys[4:] [(u'stroke', u'collation'), (u'traditional', u'collation')] - >>> types[(u'chinese', u'calendar')] + >>> types[(_u('chinese'), _u('calendar'))] u'CHINESE' - >>> types[(u'stroke', u'collation')] + >>> types[(_u('stroke'), _u('collation'))] u'STROKE' """ - # 'types' node has not to exist + # 'types' node has not to exist types_nodes = names_node.getElementsByTagName('types') if types_nodes == []: - return + return # Retrieve all types types = InheritingDictionary() for type_node in types_nodes[0].getElementsByTagName('type'): @@ -185,7 +188,7 @@ class LocaleFactory(object): Example:: >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <ldml> ... <localeDisplayNames> ... <languages> @@ -214,7 +217,7 @@ class LocaleFactory(object): ... <type type="stroke" key="collation">STROKE</type> ... </types> ... </localeDisplayNames> - ... </ldml>''' + ... </ldml>''') >>> factory = LocaleFactory(None) >>> factory._data = parseString(xml).documentElement @@ -224,42 +227,42 @@ class LocaleFactory(object): >>> keys.sort() >>> keys [u'Fallback', u'aa', u'ab'] - >>> names.languages[u'aa'] + >>> names.languages[_u("aa")] u'aa' >>> keys = names.scripts.keys() >>> keys.sort() >>> keys [u'Arab', u'Armn'] - >>> names.scripts[u'Arab'] + >>> names.scripts[_u("Arab")] u'Arab' >>> keys = names.territories.keys() >>> keys.sort() >>> keys [u'AD', u'AE'] - >>> names.territories[u'AD'] + >>> names.territories[_u("AD")] u'AD' >>> keys = names.variants.keys() >>> keys.sort() >>> keys [u'Fallback', u'POSIX'] - >>> names.variants[u'Fallback'] + >>> names.variants[_u("Fallback")] u'' >>> keys = names.keys.keys() >>> keys.sort() >>> keys [u'calendar', u'collation'] - >>> names.keys[u'calendar'] + >>> names.keys[_u("calendar")] u'CALENDAR' - >>> names.types[(u'stroke', u'collation')] + >>> names.types[(_u("stroke"), _u("collation"))] u'STROKE' """ displayNames = LocaleDisplayNames() - # Neither the 'localeDisplayNames' or 'scripts' node has to exist + # Neither the 'localeDisplayNames' or 'scripts' node has to exist names_nodes = self._data.getElementsByTagName('localeDisplayNames') if names_nodes == []: return displayNames @@ -295,7 +298,7 @@ class LocaleFactory(object): >>> calendar = CalendarStub() >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <months> ... <default type="format" /> ... <monthContext type="format"> @@ -329,27 +332,27 @@ class LocaleFactory(object): ... <month type="12">Dez</month> ... </monthWidth> ... </monthContext> - ... </months>''' + ... </months>''') >>> dom = parseString(xml) >>> factory._extractMonths(dom.documentElement, calendar) The contexts and widths were introduced in CLDR 1.1, the way of getting month names is like this:: - + >>> calendar.defaultMonthContext u'format' - - >>> ctx = calendar.monthContexts[u'format'] + + >>> ctx = calendar.monthContexts[_u("format")] >>> ctx.defaultWidth u'wide' - - >>> names = [ctx.months[u'wide'][type] for type in range(1,13)] + + >>> names = [ctx.months[_u("wide")][type] for type in range(1,13)] >>> names[:7] [u'Januar', u'Februar', u'Maerz', u'April', u'Mai', u'Juni', u'Juli'] >>> names[7:] [u'August', u'September', u'Oktober', u'November', u'Dezember'] - - >>> abbrs = [ctx.months[u'abbreviated'][type] for type in range(1,13)] + + >>> abbrs = [ctx.months[_u("abbreviated")][type] for type in range(1,13)] >>> abbrs[:6] [u'Jan', u'Feb', u'Mrz', u'Apr', u'Mai', u'Jun'] >>> abbrs[6:] @@ -370,21 +373,21 @@ class LocaleFactory(object): [u'Jan', u'Feb', u'Mrz', u'Apr', u'Mai', u'Jun'] >>> abbrs[6:] [u'Jul', u'Aug', u'Sep', u'Okt', u'Nov', u'Dez'] - - + + """ - + defaultMonthContext_node = months_node.getElementsByTagName('default') if defaultMonthContext_node: calendar.defaultMonthContext = defaultMonthContext_node[0].getAttribute('type') - + monthContext_nodes = months_node.getElementsByTagName('monthContext') if not monthContext_nodes: return calendar.monthContexts = InheritingDictionary() names_node = abbrs_node = None # BBB - + for node in monthContext_nodes: context_type = node.getAttribute('type') mctx = LocaleMonthContext(context_type) @@ -400,20 +403,20 @@ class LocaleFactory(object): width_type = width_node.getAttribute('type') width = InheritingDictionary() widths[width_type] = width - + for month_node in width_node.getElementsByTagName('month'): mtype = int(month_node.getAttribute('type')) width[mtype] = self._getText(month_node.childNodes) - + if context_type == 'format': if width_type == 'abbreviated': abbrs_node = width_node elif width_type == 'wide': names_node = width_node - + if not (names_node and abbrs_node): return - + # Get all month names names = {} for name_node in names_node.getElementsByTagName('month'): @@ -444,7 +447,7 @@ class LocaleFactory(object): >>> calendar = CalendarStub() >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <days> ... <default type="format" /> ... <dayContext type="format"> @@ -468,30 +471,30 @@ class LocaleFactory(object): ... <day type="sat">Sa</day> ... </dayWidth> ... </dayContext> - ... </days>''' + ... </days>''') >>> dom = parseString(xml) >>> factory._extractDays(dom.documentElement, calendar) Day contexts and widths were introduced in CLDR 1.1, here's how to use them:: - + >>> calendar.defaultDayContext u'format' - - >>> ctx = calendar.dayContexts[u'format'] + + >>> ctx = calendar.dayContexts[_u("format")] >>> ctx.defaultWidth u'wide' - - >>> names = [ctx.days[u'wide'][type] for type in range(1,8)] + + >>> names = [ctx.days[_u("wide")][type] for type in range(1,8)] >>> names[:4] [u'Montag', u'Dienstag', u'Mittwoch', u'Donnerstag'] >>> names[4:] [u'Freitag', u'Samstag', u'Sonntag'] - >>> abbrs = [ctx.days[u'abbreviated'][type] for type in range(1,8)] + >>> abbrs = [ctx.days[_u("abbreviated")][type] for type in range(1,8)] >>> abbrs [u'Mo', u'Di', u'Mi', u'Do', u'Fr', u'Sa', u'So'] - + And here's the old CLDR 1.0 way of getting day names and abbreviations:: @@ -511,14 +514,14 @@ class LocaleFactory(object): defaultDayContext_node = days_node.getElementsByTagName('default') if defaultDayContext_node: calendar.defaultDayContext = defaultDayContext_node[0].getAttribute('type') - + dayContext_nodes = days_node.getElementsByTagName('dayContext') if not dayContext_nodes: return calendar.dayContexts = InheritingDictionary() names_node = abbrs_node = None # BBB - + for node in dayContext_nodes: context_type = node.getAttribute('type') dctx = LocaleDayContext(context_type) @@ -534,11 +537,11 @@ class LocaleFactory(object): width_type = width_node.getAttribute('type') width = InheritingDictionary() widths[width_type] = width - + for day_node in width_node.getElementsByTagName('day'): dtype = dayMapping[day_node.getAttribute('type')] width[dtype] = self._getText(day_node.childNodes) - + if context_type == 'format': if width_type == 'abbreviated': abbrs_node = width_node @@ -577,7 +580,7 @@ class LocaleFactory(object): >>> calendar = CalendarStub() >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <calendar type="gregorian"> ... <week> ... <minDays count="1"/> @@ -585,7 +588,7 @@ class LocaleFactory(object): ... <weekendStart day="fri" time="18:00"/> ... <weekendEnd day="sun" time="18:00"/> ... </week> - ... </calendar>''' + ... </calendar>''') >>> dom = parseString(xml) >>> factory._extractWeek(dom.documentElement, calendar) @@ -637,7 +640,7 @@ class LocaleFactory(object): >>> calendar = CalendarStub() >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <calendar type="gregorian"> ... <eras> ... <eraAbbr> @@ -648,7 +651,7 @@ class LocaleFactory(object): ... <era type="0">Before Christ</era> ... </eraName> ... </eras> - ... </calendar>''' + ... </calendar>''') >>> dom = parseString(xml) >>> factory._extractEras(dom.documentElement, calendar) @@ -695,7 +698,7 @@ class LocaleFactory(object): >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <dateFormats> ... <default type="medium"/> ... <dateFormatLength type="full"> @@ -713,20 +716,20 @@ class LocaleFactory(object): ... <pattern>MMM dd, yyyy</pattern> ... </dateFormat> ... </dateFormatLength> - ... </dateFormats>''' + ... </dateFormats>''') >>> dom = parseString(xml) >>> default, lengths = factory._extractFormats( ... dom.documentElement, 'dateFormatLength', 'dateFormat') >>> default u'medium' - >>> lengths[u'full'].formats[None].pattern + >>> lengths[_u("full")].formats[None].pattern u'EEEE, MMMM d, yyyy' - >>> lengths[u'medium'].default + >>> lengths[_u("medium")].default u'DateFormatsKey2' - >>> lengths[u'medium'].formats['DateFormatsKey3'].pattern + >>> lengths[_u("medium")].formats['DateFormatsKey3'].pattern u'MMM dd, yyyy' - >>> lengths[u'medium'].formats['DateFormatsKey2'].displayName + >>> lengths[_u("medium")].formats['DateFormatsKey2'].displayName u'Standard Date' """ formats_default = None @@ -738,14 +741,14 @@ class LocaleFactory(object): for length_node in formats_node.getElementsByTagName(lengthNodeName): type = length_node.getAttribute('type') or None length = LocaleFormatLength(type) - + default_nodes = length_node.getElementsByTagName('default') if default_nodes: length.default = default_nodes[0].getAttribute('type') if length_node.getElementsByTagName(formatNodeName): length.formats = InheritingDictionary() - + for format_node in length_node.getElementsByTagName(formatNodeName): format = LocaleFormat() format.type = format_node.getAttribute('type') or None @@ -768,7 +771,7 @@ class LocaleFactory(object): >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <dates> ... <calendars> ... <calendar type="gregorian"> @@ -829,7 +832,7 @@ class LocaleFactory(object): ... </eras> ... </calendar> ... </calendars> - ... </dates>''' + ... </dates>''') >>> dom = parseString(xml) >>> calendars = factory._extractCalendars(dom.documentElement) @@ -837,12 +840,12 @@ class LocaleFactory(object): >>> keys.sort() >>> keys [u'buddhist', u'gregorian', 'thai-buddhist'] - + Note that "thai-buddhist" are added as an alias to "buddhist". - + >>> calendars['buddhist'] is calendars['thai-buddhist'] True - + """ cals_nodes = dates_node.getElementsByTagName('calendars') # no calendar node @@ -909,7 +912,7 @@ class LocaleFactory(object): >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <dates> ... <timeZoneNames> ... <zone type="America/Los_Angeles" > @@ -934,7 +937,7 @@ class LocaleFactory(object): ... <exemplarCity>York</exemplarCity> ... </zone> ... </timeZoneNames> - ... </dates>''' + ... </dates>''') >>> dom = parseString(xml) >>> zones = factory._extractTimeZones(dom.documentElement) @@ -942,11 +945,11 @@ class LocaleFactory(object): >>> keys.sort() >>> keys [u'America/Los_Angeles', u'Europe/London'] - >>> zones[u'Europe/London'].names[u'generic'] + >>> zones[_u("Europe/London")].names[_u("generic")] (u'British Time', None) - >>> zones[u'Europe/London'].cities + >>> zones[_u("Europe/London")].cities [u'York'] - >>> zones[u'America/Los_Angeles'].names[u'generic'] + >>> zones[_u("America/Los_Angeles")].names[_u("generic")] (u'Pacific Time', u'PT') """ tz_names = dates_node.getElementsByTagName('timeZoneNames') @@ -961,7 +964,7 @@ class LocaleFactory(object): # get the short and long name node long = node.getElementsByTagName('long') short = node.getElementsByTagName('short') - for type in (u'generic', u'standard', u'daylight'): + for type in (_u("generic"), _u("standard"), _u("daylight")): # get long name long_desc = None if long: @@ -1009,7 +1012,7 @@ class LocaleFactory(object): >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <numbers> ... <symbols> ... <decimal>.</decimal> @@ -1025,7 +1028,7 @@ class LocaleFactory(object): ... <infinity>oo</infinity> ... <nan>NaN</nan> ... </symbols> - ... </numbers>''' + ... </numbers>''') >>> dom = parseString(xml) >>> symbols = factory._extractSymbols(dom.documentElement) @@ -1046,10 +1049,10 @@ class LocaleFactory(object): return symbols = InheritingDictionary() - for name in (u'decimal', u'group', u'list', u'percentSign', - u'nativeZeroDigit', u'patternDigit', u'plusSign', - u'minusSign', u'exponential', u'perMille', - u'infinity', u'nan'): + for name in (_u("decimal"), _u("group"), _u("list"), _u("percentSign"), + _u("nativeZeroDigit"), _u("patternDigit"), _u("plusSign"), + _u("minusSign"), _u("exponential"), _u("perMille"), + _u("infinity"), _u("nan")): nodes = symbols_nodes[0].getElementsByTagName(name) if nodes: symbols[name] = self._getText(nodes[0].childNodes) @@ -1075,7 +1078,7 @@ class LocaleFactory(object): >>> numbers = Numbers() >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <numbers> ... <decimalFormats> ... <decimalFormatLength type="long"> @@ -1111,28 +1114,28 @@ class LocaleFactory(object): ... </currencyFormat> ... </currencyFormatLength> ... </currencyFormats> - ... </numbers>''' + ... </numbers>''') >>> dom = parseString(xml) >>> factory._extractNumberFormats(dom.documentElement, numbers) - >>> numbers.decimalFormats[u'long'].formats[None].pattern + >>> numbers.decimalFormats[_u("long")].formats[None].pattern u'#,##0.###' >>> numbers.defaultScientificFormat u'long' - >>> numbers.scientificFormats[u'long'].formats[None].pattern + >>> numbers.scientificFormats[_u("long")].formats[None].pattern u'0.000###E+00' - >>> numbers.scientificFormats[u'medium'].formats[None].pattern + >>> numbers.scientificFormats[_u("medium")].formats[None].pattern u'0.00##E+00' - >>> numbers.percentFormats[u'long'].formats[None].pattern + >>> numbers.percentFormats[_u("long")].formats[None].pattern u'#,##0%' - >>> numbers.percentFormats.get(u'medium', None) is None + >>> numbers.percentFormats.get(_u("medium"), None) is None True - >>> numbers.currencyFormats[u'long'].formats[None].pattern + >>> numbers.currencyFormats[_u("long")].formats[None].pattern u'$ #,##0.00;($ #,##0.00)' - >>> numbers.currencyFormats.get(u'medium', None) is None + >>> numbers.currencyFormats.get(_u("medium"), None) is None True """ @@ -1158,7 +1161,7 @@ class LocaleFactory(object): >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <numbers> ... <currencies> ... <currency type="USD"> @@ -1178,7 +1181,7 @@ class LocaleFactory(object): ... <symbol>$</symbol> ... </currency> ... </currencies> - ... </numbers>''' + ... </numbers>''') >>> dom = parseString(xml) >>> currencies = factory._extractCurrencies(dom.documentElement) @@ -1207,7 +1210,7 @@ class LocaleFactory(object): if nodes: currency.symbol = self._getText(nodes[0].childNodes) currency.symbolChoice = \ - nodes[0].getAttribute('choice') == u'true' + nodes[0].getAttribute('choice') == _u("true") nodes = curr_node.getElementsByTagName('displayName') if nodes: @@ -1226,14 +1229,14 @@ class LocaleFactory(object): numbers = LocaleNumbers() symbols = self._extractSymbols(numbers_nodes[0]) - if symbols is not None: + if symbols is not None: numbers.symbols = symbols self._extractNumberFormats(numbers_nodes[0], numbers) currencies = self._extractCurrencies(numbers_nodes[0]) if currencies is not None: numbers.currencies = currencies return numbers - + def _extractDelimiters(self): """Extract all delimiter entries from the DOM tree. @@ -1242,7 +1245,7 @@ class LocaleFactory(object): >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <ldml> ... <delimiters> ... <quotationStart>``</quotationStart> @@ -1250,18 +1253,18 @@ class LocaleFactory(object): ... <alternateQuotationStart>`</alternateQuotationStart> ... <alternateQuotationEnd>'</alternateQuotationEnd> ... </delimiters> - ... </ldml>''' + ... </ldml>''') >>> dom = parseString(xml) >>> factory._data = parseString(xml).documentElement >>> delimiters = factory._extractDelimiters() - >>> delimiters[u'quotationStart'] + >>> delimiters[_u("quotationStart")] u'``' - >>> delimiters[u'quotationEnd'] + >>> delimiters[_u("quotationEnd")] u"''" - >>> delimiters[u'alternateQuotationStart'] + >>> delimiters[_u("alternateQuotationStart")] u'`' - >>> delimiters[u'alternateQuotationEnd'] + >>> delimiters[_u("alternateQuotationEnd")] u"'" Escape: "'" @@ -1272,8 +1275,8 @@ class LocaleFactory(object): return delimiters = InheritingDictionary() - for name in (u'quotationStart', u'quotationEnd', - u'alternateQuotationStart', u'alternateQuotationEnd'): + for name in (_u('quotationStart'), _u("quotationEnd"), + _u("alternateQuotationStart"), _u("alternateQuotationEnd")): nodes = delimiters_nodes[0].getElementsByTagName(name) if nodes: delimiters[name] = self._getText(nodes[0].childNodes) @@ -1286,12 +1289,12 @@ class LocaleFactory(object): >>> factory = LocaleFactory(None) >>> from xml.dom.minidom import parseString - >>> xml = u''' + >>> xml = _u(''' ... <ldml> ... <layout> ... <orientation lines="bottom-to-top" characters="right-to-left" /> ... </layout> - ... </ldml>''' + ... </ldml>''') >>> dom = parseString(xml) >>> factory._data = parseString(xml).documentElement >>> orientation = factory._extractOrientation() @@ -1304,7 +1307,7 @@ class LocaleFactory(object): if not orientation_nodes: return orientation = LocaleOrientation() - for name in (u'characters', u'lines'): + for name in (_u("characters"), _u("lines")): value = orientation_nodes[0].getAttribute(name) if value: setattr(orientation, name, value) @@ -1317,7 +1320,7 @@ class LocaleFactory(object): names = self._extractDisplayNames() if names is not None: - locale.displayNames = names + locale.displayNames = names dates = self._extractDates() if dates is not None: @@ -1334,7 +1337,7 @@ class LocaleFactory(object): orientation = self._extractOrientation() if orientation is not None: locale.orientation = orientation - + # Unmapped: # # - <characters> diff --git a/src/zope/i18n/testmessagecatalog.py b/src/zope/i18n/testmessagecatalog.py index f6104e5..4bebda2 100644 --- a/src/zope/i18n/testmessagecatalog.py +++ b/src/zope/i18n/testmessagecatalog.py @@ -17,6 +17,7 @@ from zope import interface import zope.i18n.interfaces from zope.i18n.translationdomain import TranslationDomain +from ._compat import _u @interface.implementer(zope.i18n.interfaces.IGlobalMessageCatalog) class TestMessageCatalog: @@ -29,11 +30,11 @@ class TestMessageCatalog: def queryMessage(self, msgid, default=None): default = getattr(msgid, 'default', default) if default != None and default != msgid: - msg = u"%s (%s)" % (msgid, default) + msg = _u("%s (%s)") % (msgid, default) else: msg = msgid - - return u'[[%s][%s]]' % (self.domain, msg) + + return _u("[[%s][%s]]") % (self.domain, msg) getMessage = queryMessage @@ -44,7 +45,7 @@ class TestMessageCatalog: pass @interface.implementer(zope.i18n.interfaces.ITranslationDomain) -def TestMessageFallbackDomain(domain_id=u''): +def TestMessageFallbackDomain(domain_id=_u("")): domain = TranslationDomain(domain_id) domain.addCatalog(TestMessageCatalog(domain_id)) return domain diff --git a/src/zope/i18n/testmessagecatalog.txt b/src/zope/i18n/testmessagecatalog.txt index bd04ad8..dc1d9d0 100644 --- a/src/zope/i18n/testmessagecatalog.txt +++ b/src/zope/i18n/testmessagecatalog.txt @@ -51,16 +51,16 @@ that has the test catalog as it's only catalog: >>> zope.i18n.interfaces.IFallbackTranslationDomainFactory.providedBy( ... factory) True - + >>> domain = factory('foo.bar') - >>> domain.translate(u'eek') + >>> domain.translate('eek') u'eek' - >>> domain.translate(u'eek', target_language='test') + >>> domain.translate('eek', target_language='test') u'[[foo.bar][eek]]' Note that if a default is padded in, it will be included in test output: - >>> domain.translate(u'eek', target_language='test', default=u'Eek') + >>> domain.translate('eek', target_language='test', default='Eek') u'[[foo.bar][eek (Eek)]]' diff --git a/src/zope/i18n/tests/test_formats.py b/src/zope/i18n/tests/test_formats.py index 74baeef..aa7910c 100644 --- a/src/zope/i18n/tests/test_formats.py +++ b/src/zope/i18n/tests/test_formats.py @@ -29,12 +29,14 @@ from zope.i18n.interfaces import INumberFormat from zope.i18n.format import NumberFormat, NumberParseError from zope.i18n.format import parseNumberPattern +from .._compat import _u + class LocaleStub(object): pass class LocaleCalendarStub(object): - type = u'gregorian' + type = _u("gregorian") months = { 1: ('Januar', 'Jan'), 2: ('Februar', 'Feb'), 3: ('Maerz', 'Mrz'), 4: ('April', 'Apr'), @@ -222,9 +224,9 @@ class TestBuildDateTimeParseInfo(TestCase): self.assertEqual(self.info(('M', 2)), '([0-9]{2})') def testMonthNames(self): - names = [u'Januar', u'Februar', u'Maerz', u'April', - u'Mai', u'Juni', u'Juli', u'August', u'September', u'Oktober', - u'November', u'Dezember'] + names = [_u("Januar"), _u("Februar"), _u("Maerz"), _u("April"), + _u("Mai"), _u("Juni"), _u("Juli"), _u("August"), _u("September"), _u("Oktober"), + _u("November"), _u("Dezember")] self.assertEqual(self.info(('M', 4)), '('+'|'.join(names)+')') def testMonthAbbr(self): @@ -548,54 +550,54 @@ class TestDateTimeFormat(TestCase): def testFormatDayInYear(self): self.assertEqual( self.format.format(datetime.date(2003, 1, 3), 'D'), - u'3') + _u("3")) self.assertEqual( self.format.format(datetime.date(2003, 1, 3), 'DD'), - u'03') + _u("03")) self.assertEqual( self.format.format(datetime.date(2003, 1, 3), 'DDD'), - u'003') + _u("003")) self.assertEqual( self.format.format(datetime.date(2003, 12, 31), 'D'), - u'365') + _u("365")) self.assertEqual( self.format.format(datetime.date(2003, 12, 31), 'DD'), - u'365') + _u("365")) self.assertEqual( self.format.format(datetime.date(2003, 12, 31), 'DDD'), - u'365') + _u("365")) self.assertEqual( self.format.format(datetime.date(2004, 12, 31), 'DDD'), - u'366') + _u("366")) def testFormatDayOfWeekInMOnth(self): self.assertEqual( self.format.format(datetime.date(2003, 1, 3), 'F'), - u'1') + _u("1")) self.assertEqual( self.format.format(datetime.date(2003, 1, 10), 'F'), - u'2') + _u("2")) self.assertEqual( self.format.format(datetime.date(2003, 1, 17), 'F'), - u'3') + _u("3")) self.assertEqual( self.format.format(datetime.date(2003, 1, 24), 'F'), - u'4') + _u("4")) self.assertEqual( self.format.format(datetime.date(2003, 1, 31), 'F'), - u'5') + _u("5")) self.assertEqual( self.format.format(datetime.date(2003, 1, 6), 'F'), - u'1') + _u("1")) def testFormatUnusualFormats(self): self.assertEqual( self.format.format(datetime.date(2003, 1, 3), 'DDD-yyyy'), - u'003-2003') + _u("003-2003")) self.assertEqual( self.format.format(datetime.date(2003, 1, 10), "F. EEEE 'im' MMMM, yyyy"), - u'2. Freitag im Januar, 2003') + _u("2. Freitag im Januar, 2003")) diff --git a/src/zope/i18n/tests/test_translationdomain.py b/src/zope/i18n/tests/test_translationdomain.py index 85e87af..baf6aa7 100644 --- a/src/zope/i18n/tests/test_translationdomain.py +++ b/src/zope/i18n/tests/test_translationdomain.py @@ -20,6 +20,7 @@ from zope.i18n.tests.test_itranslationdomain import \ TestITranslationDomain, Environment from zope.i18nmessageid import MessageFactory from zope.i18n.interfaces import ITranslationDomain +from .._compat import _u import zope.component def testdir(): @@ -72,19 +73,19 @@ class TestGlobalTranslationDomain(unittest.TestCase, TestITranslationDomain): def testEmptyStringTranslate(self): translate = self._domain.translate - self.assertEqual(translate(u'', target_language='en'), u'') - self.assertEqual(translate(u'', target_language='foo'), u'') + self.assertEqual(translate(_u(""), target_language='en'), _u("")) + self.assertEqual(translate(_u(""), target_language='foo'), _u("")) def testStringTranslate(self): self.assertEqual( - self._domain.translate(u'short_greeting', target_language='en'), - u'Hello!') + self._domain.translate(_u("short_greeting"), target_language='en'), + _u("Hello!")) def testMessageIDTranslate(self): factory = MessageFactory('default') translate = self._domain.translate - msgid = factory(u'short_greeting', 'default') - self.assertEqual(translate(msgid, target_language='en'), u'Hello!') + msgid = factory(_u("short_greeting"), 'default') + self.assertEqual(translate(msgid, target_language='en'), _u("Hello!")) # MessageID attributes override arguments msgid = factory('43-not-there', 'this ${that} the other', mapping={'that': 'THAT'}) @@ -95,13 +96,13 @@ class TestGlobalTranslationDomain(unittest.TestCase, TestITranslationDomain): def testMessageIDRecursiveTranslate(self): factory = MessageFactory('default') translate = self._domain.translate - msgid_sub1 = factory(u'44-not-there', '${blue}', + msgid_sub1 = factory(_u("44-not-there"), '${blue}', mapping = {'blue': 'BLUE'}) - msgid_sub2 = factory(u'45-not-there', '${yellow}', + msgid_sub2 = factory(_u("45-not-there"), '${yellow}', mapping = {'yellow': 'YELLOW'}) mapping = {'color1': msgid_sub1, 'color2': msgid_sub2} - msgid = factory(u'46-not-there', 'Color: ${color1}/${color2}', + msgid = factory(_u("46-not-there"), 'Color: ${color1}/${color2}', mapping=mapping) self.assertEqual( translate(msgid, target_language='en', default="default"), @@ -110,9 +111,9 @@ class TestGlobalTranslationDomain(unittest.TestCase, TestITranslationDomain): self.assertEqual(msgid.mapping, {'color1': msgid_sub1, 'color2': msgid_sub2}) # A circular reference should not lead to crashes - msgid1 = factory(u'47-not-there', 'Message 1 and $msg2', + msgid1 = factory(_u("47-not-there"), 'Message 1 and $msg2', mapping = {}) - msgid2 = factory(u'48-not-there', 'Message 2 and $msg1', + msgid2 = factory(_u("48-not-there"), 'Message 2 and $msg1', mapping = {}) msgid1.mapping['msg2'] = msgid2 msgid2.mapping['msg1'] = msgid1 @@ -121,16 +122,16 @@ class TestGlobalTranslationDomain(unittest.TestCase, TestITranslationDomain): # Recusrive translations also work if the original message id wasn't a # message id but a unicode with a directly passed mapping self.assertEqual("Color: BLUE/YELLOW", - translate(u'Color: ${color1}/${color2}', mapping=mapping, + translate(_u("Color: ${color1}/${color2}"), mapping=mapping, target_language='en')) # If we have mapping with a message id from a different domain, make sure # we use that domain, not ours. If the message domain is not registered yet, # we should return a defualt translation. alt_factory = MessageFactory('alt') - msgid_sub = alt_factory(u'special', default=u'oohhh') + msgid_sub = alt_factory(_u("special"), default=_u("oohhh")) mapping = {'message': msgid_sub} - msgid = factory(u'46-not-there', 'Message: ${message}', + msgid = factory(_u("46-not-there"), 'Message: ${message}', mapping=mapping) # test we get a default with no domain registerd self.assertEqual( @@ -161,9 +162,9 @@ class TestGlobalTranslationDomain(unittest.TestCase, TestITranslationDomain): zope.component.provideUtility(domain, ITranslationDomain, 'alt') factory = MessageFactory('alt') - msgid = factory(u'special', 'default') + msgid = factory(_u("special"), 'default') self.assertEqual( - self._domain.translate(msgid, target_language='en'), u'Wow') + self._domain.translate(msgid, target_language='en'), _u("Wow")) def testSimpleFallbackTranslation(self): translate = self._domain.translate @@ -171,11 +172,11 @@ class TestGlobalTranslationDomain(unittest.TestCase, TestITranslationDomain): # Test that a translation in an unsupported language returns a # translation in the fallback language (by default, English) eq(translate('short_greeting', target_language='es'), - u'Hello!') + _u("Hello!")) # Same test, but use the context argument instead of target_language context = Environment() eq(translate('short_greeting', context=context), - u'Hello!') + _u("Hello!")) def testInterpolationWithoutTranslation(self): translate = self._domain.translate @@ -193,4 +194,3 @@ def test_suite(): if __name__ == '__main__': unittest.main(defaultTest='test_suite') - diff --git a/src/zope/i18n/tests/test_zcml.py b/src/zope/i18n/tests/test_zcml.py index 147456d..9693fe6 100644 --- a/src/zope/i18n/tests/test_zcml.py +++ b/src/zope/i18n/tests/test_zcml.py @@ -27,6 +27,7 @@ from zope.component.testing import PlacelessSetup import zope.i18n.tests from zope.i18n.interfaces import ITranslationDomain from zope.i18n import config +from .._compat import _u PY3 = sys.version_info[0] == 3 if PY3: @@ -110,14 +111,14 @@ class DirectivesTest(PlacelessSetup, unittest.TestCase): self.assertEqual(util._catalogs.get('en'), [unicode(path1), unicode(path2)]) - msg = util.translate(u'Additional message', target_language='en') - self.assertEqual(msg, u'Additional message translated') + msg = util.translate(_u("Additional message"), target_language='en') + self.assertEqual(msg, _u("Additional message translated")) - msg = util.translate(u'New Domain', target_language='en') - self.assertEqual(msg, u'New Domain translated') + msg = util.translate(_u("New Domain"), target_language='en') + self.assertEqual(msg, _u("New Domain translated")) - msg = util.translate(u'New Language', target_language='en') - self.assertEqual(msg, u'New Language translated') + msg = util.translate(_u("New Language"), target_language='en') + self.assertEqual(msg, _u("New Language translated")) def testRegisterAndCompileTranslations(self): from zope.configuration import xmlconfig @@ -148,12 +149,12 @@ class DirectivesTest(PlacelessSetup, unittest.TestCase): self.assertEqual(util._catalogs, {'test': ['test'], 'en': [unicode(path)]}) - msg = util.translate(u"I'm a newer file", target_language='en') - self.assertEqual(msg, u"I'm a newer file translated") + msg = util.translate(_u("I'm a newer file"), target_language='en') + self.assertEqual(msg, _u("I'm a newer file translated")) util = getUtility(ITranslationDomain, 'zope-i18n2') - msg = util.translate(u"I'm a new file", target_language='en') - self.assertEqual(msg, u"I'm a new file translated") + msg = util.translate(_u("I'm a new file"), target_language='en') + self.assertEqual(msg, _u("I'm a new file translated")) # Reset the mtime of the mo file os.utime(path, (path_atime, path_mtime)) diff --git a/src/zope/i18n/translationdomain.py b/src/zope/i18n/translationdomain.py index 6629c9e..415f1ba 100644 --- a/src/zope/i18n/translationdomain.py +++ b/src/zope/i18n/translationdomain.py @@ -20,6 +20,7 @@ from zope.i18nmessageid import Message from zope.i18n import translate, interpolate from zope.i18n.simpletranslationdomain import SimpleTranslationDomain from zope.i18n.interfaces import ITranslationDomain, INegotiator +from ._compat import _u # The configuration should specify a list of fallback languages for the # site. If a particular catalog for a negotiated language is not available, @@ -35,6 +36,8 @@ PY3 = sys.version_info[0] == 3 if PY3: unicode = str +_EMPTY = _u("") + class TranslationDomain(SimpleTranslationDomain): def __init__(self, domain, fallbacks=None): @@ -69,8 +72,8 @@ class TranslationDomain(SimpleTranslationDomain): """See zope.i18n.interfaces.ITranslationDomain""" # if the msgid is empty, let's save a lot of calculations and return # an empty string. - if msgid == u'': - return u'' + if msgid == _EMPTY: + return _EMPTY if target_language is None and context is not None: langs = self._catalogs.keys() @@ -129,7 +132,7 @@ class TranslationDomain(SimpleTranslationDomain): # this is a slight optimization for the case when there is a # single catalog. More importantly, it is extremely helpful # when testing and the test language is used, because it - # allows the test language to get the default. + # allows the test language to get the default. text = self._data[catalog_names[0]].queryMessage( msgid, default) else: diff --git a/src/zope/i18n/zcml.py b/src/zope/i18n/zcml.py index 4ab9af1..959a58e 100644 --- a/src/zope/i18n/zcml.py +++ b/src/zope/i18n/zcml.py @@ -33,7 +33,7 @@ from zope.i18n.gettextmessagecatalog import GettextMessageCatalog from zope.i18n.testmessagecatalog import TestMessageCatalog from zope.i18n.translationdomain import TranslationDomain from zope.i18n.interfaces import ITranslationDomain - +from ._compat import _u logger = logging.getLogger("zope.i18n") @@ -42,15 +42,15 @@ class IRegisterTranslationsDirective(Interface): """Register translations with the global site manager.""" directory = Path( - title=u"Directory", - description=u"Directory containing the translations", + title=_u("Directory"), + description=_u("Directory containing the translations"), required=True ) domain = TextLine( - title=u"Domain", - description=u"Translation domain to register. If not specified, " - "all domains found in the directory are registered", + title=_u("Domain"), + description=_u("Translation domain to register. If not specified, " + "all domains found in the directory are registered"), required=False ) @@ -1,5 +1,5 @@ [tox] -envlist = py26,py27,py33,py34,pypy,coverage,docs +envlist = py26,py27,py32,py33,py34,pypy,pypy3,coverage,docs [testenv] commands = |