mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Add support for format method to translation objects
For now translation classes have old style % formatting way only. But 'format' is convenience, preferred in Python3 string formatting method. Fixes: https://pagure.io/freeipa/issue/7586 Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
This commit is contained in:
committed by
Christian Heimes
parent
8c3ff0308c
commit
f4716b6991
@@ -67,6 +67,17 @@ u'Hello, Joe.'
|
|||||||
>>> unicode(my_plugin.my_string) % dict(name='Joe') # Long form
|
>>> unicode(my_plugin.my_string) % dict(name='Joe') # Long form
|
||||||
u'Hello, Joe.'
|
u'Hello, Joe.'
|
||||||
|
|
||||||
|
Translation can also be performed via the `Gettext.format()` convenience
|
||||||
|
method. For example, these two are equivalent:
|
||||||
|
|
||||||
|
>>> my_plugin.my_string = _('Hello, {name}.')
|
||||||
|
>>> my_plugin.my_string.format(name='Joe')
|
||||||
|
u'Hello, Joe.'
|
||||||
|
|
||||||
|
>>> my_plugin.my_string = _('Hello, {0}.')
|
||||||
|
>>> my_plugin.my_string.format('Joe')
|
||||||
|
u'Hello, Joe.'
|
||||||
|
|
||||||
Similar to ``_()``, the ``ngettext()`` function above is actually an
|
Similar to ``_()``, the ``ngettext()`` function above is actually an
|
||||||
`NGettextFactory` instance, which when called returns an `NGettext` instance.
|
`NGettextFactory` instance, which when called returns an `NGettext` instance.
|
||||||
An `NGettext` instance stores the singular and plural messages, and the gettext
|
An `NGettext` instance stores the singular and plural messages, and the gettext
|
||||||
@@ -88,6 +99,15 @@ u'1 goose'
|
|||||||
>>> my_plugin.my_plural(1) % dict(count=1) # Long form
|
>>> my_plugin.my_plural(1) % dict(count=1) # Long form
|
||||||
u'1 goose'
|
u'1 goose'
|
||||||
|
|
||||||
|
Translation can also be performed via the `NGettext.format()` convenience
|
||||||
|
method. For example:
|
||||||
|
|
||||||
|
>>> my_plugin.my_plural = ngettext('{count} goose', '{count} geese', 0)
|
||||||
|
>>> my_plugin.my_plural.format(count=1)
|
||||||
|
u'1 goose'
|
||||||
|
>>> my_plugin.my_plural.format(count=2)
|
||||||
|
u'2 geese'
|
||||||
|
|
||||||
Lastly, 3rd-party plugins can create factories bound to a different gettext
|
Lastly, 3rd-party plugins can create factories bound to a different gettext
|
||||||
domain. The default domain is ``'ipa'``, which is also the domain of the
|
domain. The default domain is ``'ipa'``, which is also the domain of the
|
||||||
standard ``ipalib._()`` and ``ipalib.ngettext()`` factories. But 3rd-party
|
standard ``ipalib._()`` and ``ipalib.ngettext()`` factories. But 3rd-party
|
||||||
@@ -230,6 +250,19 @@ class Gettext(LazyText):
|
|||||||
>>> unicode(msg) % dict(name='Joe') # Long form
|
>>> unicode(msg) % dict(name='Joe') # Long form
|
||||||
u'Hello, Joe.'
|
u'Hello, Joe.'
|
||||||
|
|
||||||
|
`Gettext.format()` is a convenience method for Python string formatting.
|
||||||
|
It will translate your message using `Gettext.__unicode__()` and then
|
||||||
|
perform the string substitution on the translated message. For example,
|
||||||
|
these two are equivalent:
|
||||||
|
|
||||||
|
>>> msg = Gettext('Hello, {name}.')
|
||||||
|
>>> msg.format(name='Joe')
|
||||||
|
u'Hello, Joe.'
|
||||||
|
|
||||||
|
>>> msg = Gettext('Hello, {0}.')
|
||||||
|
>>> msg.format('Joe')
|
||||||
|
u'Hello, Joe.'
|
||||||
|
|
||||||
See `GettextFactory` for additional details. If you need to pick between
|
See `GettextFactory` for additional details. If you need to pick between
|
||||||
singular and plural form, use `NGettext` instances via the
|
singular and plural form, use `NGettext` instances via the
|
||||||
`NGettextFactory`.
|
`NGettextFactory`.
|
||||||
@@ -268,6 +301,9 @@ class Gettext(LazyText):
|
|||||||
def __mod__(self, kw):
|
def __mod__(self, kw):
|
||||||
return unicode(self) % kw #pylint: disable=no-member
|
return unicode(self) % kw #pylint: disable=no-member
|
||||||
|
|
||||||
|
def format(self, *args, **kwargs):
|
||||||
|
return unicode(self).format(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@six.python_2_unicode_compatible
|
@six.python_2_unicode_compatible
|
||||||
class FixMe(Gettext):
|
class FixMe(Gettext):
|
||||||
@@ -385,6 +421,33 @@ class NGettext(LazyText):
|
|||||||
>>> msg2(0) % dict(num=0)
|
>>> msg2(0) % dict(num=0)
|
||||||
u'0 geese'
|
u'0 geese'
|
||||||
|
|
||||||
|
`NGettext.format()` is a convenience method for Python string formatting.
|
||||||
|
It can only be used if your substitution ``dict`` contains the count in a
|
||||||
|
``'count'`` item. For example:
|
||||||
|
|
||||||
|
>>> msg = NGettext('{count} goose', '{count} geese')
|
||||||
|
>>> msg.format(count=0)
|
||||||
|
u'0 geese'
|
||||||
|
>>> msg.format(count=1)
|
||||||
|
u'1 goose'
|
||||||
|
>>> msg.format(count=2)
|
||||||
|
u'2 geese'
|
||||||
|
|
||||||
|
A ``KeyError`` is raised if your substitution ``dict`` doesn't have a
|
||||||
|
``'count'`` item. For example:
|
||||||
|
|
||||||
|
>>> msg2 = NGettext('{num} goose', '{num} geese')
|
||||||
|
>>> msg2.format(num=0)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
KeyError: 'count'
|
||||||
|
|
||||||
|
However, in this case you can still use the longer, explicit form for
|
||||||
|
string substitution:
|
||||||
|
|
||||||
|
>>> msg2(0).format(num=0)
|
||||||
|
u'0 geese'
|
||||||
|
|
||||||
See `NGettextFactory` for additional details.
|
See `NGettextFactory` for additional details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -404,6 +467,10 @@ class NGettext(LazyText):
|
|||||||
count = kw['count']
|
count = kw['count']
|
||||||
return self(count) % kw
|
return self(count) % kw
|
||||||
|
|
||||||
|
def format(self, *args, **kwargs):
|
||||||
|
count = kwargs['count']
|
||||||
|
return self(count).format(*args, **kwargs)
|
||||||
|
|
||||||
def __call__(self, count):
|
def __call__(self, count):
|
||||||
if self.key in context.__dict__:
|
if self.key in context.__dict__:
|
||||||
t = context.__dict__[self.key]
|
t = context.__dict__[self.key]
|
||||||
@@ -442,6 +509,9 @@ class ConcatenatedLazyText(object):
|
|||||||
def __mod__(self, kw):
|
def __mod__(self, kw):
|
||||||
return unicode(self) % kw
|
return unicode(self) % kw
|
||||||
|
|
||||||
|
def format(self, *args, **kwargs):
|
||||||
|
return unicode(self).format(*args, **kwargs)
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
if isinstance(other, ConcatenatedLazyText):
|
if isinstance(other, ConcatenatedLazyText):
|
||||||
return ConcatenatedLazyText(*self.components + other.components)
|
return ConcatenatedLazyText(*self.components + other.components)
|
||||||
|
|||||||
@@ -201,6 +201,12 @@ class test_Gettext(object):
|
|||||||
inst = self.klass('hello %(adj)s nurse', 'foo', 'bar')
|
inst = self.klass('hello %(adj)s nurse', 'foo', 'bar')
|
||||||
assert inst % dict(adj='tall', stuff='junk') == 'hello tall nurse'
|
assert inst % dict(adj='tall', stuff='junk') == 'hello tall nurse'
|
||||||
|
|
||||||
|
def test_format(self):
|
||||||
|
inst = self.klass('{0} {adj} nurse', 'foo', 'bar')
|
||||||
|
posargs = ('hello', 'bye')
|
||||||
|
knownargs = {'adj': 'caring', 'stuff': 'junk'}
|
||||||
|
assert inst.format(*posargs, **knownargs) == 'hello caring nurse'
|
||||||
|
|
||||||
def test_eq(self):
|
def test_eq(self):
|
||||||
inst1 = self.klass('what up?', 'foo', 'bar')
|
inst1 = self.klass('what up?', 'foo', 'bar')
|
||||||
inst2 = self.klass('what up?', 'foo', 'bar')
|
inst2 = self.klass('what up?', 'foo', 'bar')
|
||||||
@@ -264,6 +270,21 @@ class test_NGettext(object):
|
|||||||
assert inst % dict(count=1, dish='stew') == '1 goose makes a stew'
|
assert inst % dict(count=1, dish='stew') == '1 goose makes a stew'
|
||||||
assert inst % dict(count=2, dish='pie') == '2 geese make a pie'
|
assert inst % dict(count=2, dish='pie') == '2 geese make a pie'
|
||||||
|
|
||||||
|
def test_format(self):
|
||||||
|
singular = '{count} goose makes a {0} {dish}'
|
||||||
|
plural = '{count} geese make a {0} {dish}'
|
||||||
|
inst = self.klass(singular, plural, 'foo', 'bar')
|
||||||
|
posargs = ('tasty', 'disgusting')
|
||||||
|
knownargs0 = {'count': 0, 'dish': 'frown', 'stuff': 'junk'}
|
||||||
|
knownargs1 = {'count': 1, 'dish': 'stew', 'stuff': 'junk'}
|
||||||
|
knownargs2 = {'count': 2, 'dish': 'pie', 'stuff': 'junk'}
|
||||||
|
expected_str0 = '0 geese make a tasty frown'
|
||||||
|
expected_str1 = '1 goose makes a tasty stew'
|
||||||
|
expected_str2 = '2 geese make a tasty pie'
|
||||||
|
assert inst.format(*posargs, **knownargs0) == expected_str0
|
||||||
|
assert inst.format(*posargs, **knownargs1) == expected_str1
|
||||||
|
assert inst.format(*posargs, **knownargs2) == expected_str2
|
||||||
|
|
||||||
def test_eq(self):
|
def test_eq(self):
|
||||||
inst1 = self.klass(singular, plural, 'foo', 'bar')
|
inst1 = self.klass(singular, plural, 'foo', 'bar')
|
||||||
inst2 = self.klass(singular, plural, 'foo', 'bar')
|
inst2 = self.klass(singular, plural, 'foo', 'bar')
|
||||||
@@ -387,6 +408,12 @@ class test_ConcatenatedText(object):
|
|||||||
inst = self.klass('[', text.Gettext('%(color)s', 'foo', 'bar'), ']')
|
inst = self.klass('[', text.Gettext('%(color)s', 'foo', 'bar'), ']')
|
||||||
assert inst % dict(color='red', stuff='junk') == '[red]'
|
assert inst % dict(color='red', stuff='junk') == '[red]'
|
||||||
|
|
||||||
|
def test_format(self):
|
||||||
|
inst = self.klass('{0}', text.Gettext('{color}', 'foo', 'bar'), ']')
|
||||||
|
posargs = ('[', '(')
|
||||||
|
knownargs = {'color': 'red', 'stuff': 'junk'}
|
||||||
|
assert inst.format(*posargs, **knownargs) == '[red]'
|
||||||
|
|
||||||
def test_add(self):
|
def test_add(self):
|
||||||
inst = (text.Gettext('pale ', 'foo', 'bar') +
|
inst = (text.Gettext('pale ', 'foo', 'bar') +
|
||||||
text.Gettext('blue', 'foo', 'bar'))
|
text.Gettext('blue', 'foo', 'bar'))
|
||||||
|
|||||||
Reference in New Issue
Block a user