jenkins-bot has submitted this change and it was merged.
Change subject: Allow multiple "{{PLURAL}}" with i18n.twntranslate method
......................................................................
Allow multiple "{{PLURAL}}" with i18n.twntranslate method
avoid duplicate code by extracting parts from pywikibot.translate()
and i18n.twntranslate() to "internal" method _extract_plural()
enable tuple or list as parameters and check whether the items
count is equal to the number of plural items found by re.findall()
Some test stuff added.
Change-Id: I6420b22835ec8db9c70806f46bf2efda65944c34
---
M pywikibot/i18n.py
M tests/i18n/test.py
M tests/i18n_tests.py
3 files changed, 132 insertions(+), 61 deletions(-)
Approvals:
Merlijn van Deen: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/i18n.py b/pywikibot/i18n.py
index 8e93f89..40fed49 100644
--- a/pywikibot/i18n.py
+++ b/pywikibot/i18n.py
@@ -225,6 +225,45 @@
pass
+def _extract_plural(code, message, parameters):
+ """Check for the plural variants in message and replace them depending on
+ parameter settings.
+ @param message: the message to be replaced
+ @type message: unicode string
+ @param parameters: plural parameters passed from other methods
+ @type parameters: int, basestring, tuple, list, dict
+
+ """
+ plural_items = re.findall(PLURAL_PATTERN, message)
+ if plural_items: # we found PLURAL patterns, process it
+ if len(plural_items) > 1 and isinstance(parameters, (tuple, list)) and
\
+ len(plural_items) != len(parameters):
+ raise ValueError("Length of parameter does not match PLURAL "
+ "occurences.")
+ i = 0
+ for selector, variants in plural_items:
+ if type(parameters) == dict:
+ num = int(parameters[selector])
+ elif isinstance(parameters, basestring):
+ num = int(parameters)
+ elif isinstance(parameters, (tuple, list)):
+ num = int(parameters[i])
+ i += 1
+ else:
+ num = parameters
+ # TODO: check against plural_rules[code]['nplurals']
+ try:
+ index = plural_rules[code]['plural'](num)
+ except KeyError:
+ index = plural_rules['_default']['plural'](num)
+ except TypeError:
+ # we got an int, not a function
+ index = plural_rules[code]['plural']
+ repl = variants.split('|')[index]
+ message = re.sub(PLURAL_PATTERN, repl, message, count=1)
+ return message
+
+
def translate(code, xdict, parameters=None, fallback=True):
"""Return the most appropriate translation from a translation dict.
@@ -253,10 +292,6 @@
For PLURAL support have a look at the twntranslate method
"""
- param = None
- if type(parameters) == dict:
- param = parameters
-
family = pywikibot.config.family
# If a site is given instead of a code, use its language
if hasattr(code, 'code'):
@@ -291,31 +326,11 @@
return trans
# else we check for PLURAL variants
- while re.search(PLURAL_PATTERN, trans):
+ trans = _extract_plural(code, trans, parameters)
+ if parameters:
try:
- selector, variants = re.search(PLURAL_PATTERN, trans).groups()
- except AttributeError:
- pass
- else: # we found PLURAL patterns, process it
- if type(parameters) == dict:
- num = param[selector]
- elif isinstance(parameters, basestring):
- num = int(parameters)
- else:
- num = parameters
- # TODO: check against plural_rules[lang]['nplurals']
- try:
- index = plural_rules[code]['plural'](num)
- except KeyError:
- index = plural_rules['_default']['plural'](num)
- except TypeError:
- # we got an int, not a function
- index = plural_rules[code]['plural']
- trans = re.sub(PLURAL_PATTERN, variants.split('|')[index], trans,
count=1)
- if param:
- try:
- return trans % param
- except KeyError:
+ return trans % parameters
+ except (KeyError, TypeError):
# parameter is for PLURAL variants only, don't change the string
pass
return trans
@@ -388,7 +403,7 @@
contains a plural tag inside which looks like
{{PLURAL:<number>|<variant1>|<variant2>[|<variantn>]}}
it takes that variant calculated by the plural_rules depending on the
number
- value.
+ value. Multiple plurals are allowed.
Examples:
If we had a test dictionary in test.py like
@@ -429,45 +444,22 @@
import table.
"""
- param = None
- if type(parameters) == dict:
- param = parameters
# If a site is given instead of a code, use its language
if hasattr(code, 'code'):
code = code.code
# we send the code via list and get the alternate code back
code = [code]
- trans = twtranslate(code, twtitle, None)
- try:
- selector, variants = re.search(PLURAL_PATTERN, trans).groups()
- # No PLURAL tag found: nothing to replace
- except AttributeError:
- pass
- else:
- if type(parameters) == dict:
- num = param[selector]
- elif isinstance(parameters, basestring):
- num = int(parameters)
- else:
- num = parameters
- # get the alternate language code modified by twtranslate
- lang = code.pop()
- # we only need the lang or _default, not a _altlang code
- # maybe we should implement this to i18n.translate()
- # TODO: check against plural_rules[lang]['nplurals']
+ trans = twtranslate(code, twtitle)
+ # get the alternate language code modified by twtranslate
+ lang = code.pop()
+ # check for PLURAL variants
+ trans = _extract_plural(lang, trans, parameters)
+ # we always have a dict for replacement of translatewiki messages
+ if parameters and type(parameters) == dict:
try:
- index = plural_rules[lang]['plural'](num)
+ return trans % parameters
except KeyError:
- index = plural_rules['_default']['plural'](num)
- except TypeError:
- # we got an int not a function
- index = plural_rules[lang]['plural']
- repl = variants.split('|')[index]
- trans = re.sub(PLURAL_PATTERN, repl, trans)
- if param:
- try:
- return trans % param
- except KeyError:
+ # parameter is for PLURAL variants only, don't change the string
pass
return trans
diff --git a/tests/i18n/test.py b/tests/i18n/test.py
index 9e030ca..048b063 100644
--- a/tests/i18n/test.py
+++ b/tests/i18n/test.py
@@ -2,6 +2,7 @@
msg = {
'de': {
'test-plural': u'Bot: Ändere %(num)d {{PLURAL:num|Seite|Seiten}}.',
+ 'test-multiple-plurals': u'Bot: %(action)s %(line)s
{{PLURAL:line|Zeile|Zeilen}} von {{PLURAL:%(page)d|einer|mehreren}}
{{PLURAL:page|Seite|Seiten}}.',
},
'en': {
'test-localized': u'test-localized EN',
diff --git a/tests/i18n_tests.py b/tests/i18n_tests.py
index e996fbb..6df9a46 100644
--- a/tests/i18n_tests.py
+++ b/tests/i18n_tests.py
@@ -154,6 +154,84 @@
i18n.twntranslate('fr', 'test-plural', 1) % {'descr': 'seulement'},
u'Robot: Changer seulement une page.')
+ def testMultiple(self):
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals', 1)
+ % {'action': u'Ändere', 'line': u'eine'},
+ u'Bot: Ändere eine Zeile von einer Seite.')
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals', 2)
+ % {'action': u'Ändere', 'line': u'zwei'},
+ u'Bot: Ändere zwei Zeilen von mehreren Seiten.')
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals', 3)
+ % {'action': u'Ändere', 'line': u'drei'},
+ u'Bot: Ändere drei Zeilen von mehreren Seiten.')
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals', (1, 2, 2))
+ % {'action': u'Ändere', 'line': u'eine'},
+ u'Bot: Ändere eine Zeile von mehreren Seiten.')
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals', [3, 1, 1])
+ % {'action': u'Ändere', 'line': u'drei'},
+ u'Bot: Ändere drei Zeilen von einer Seite.')
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals', ["3", 1, 1])
+ % {'action': u'Ändere', 'line': u'drei'},
+ u'Bot: Ändere drei Zeilen von einer Seite.')
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals', "321")
+ % {'action': u'Ändere', 'line': u'dreihunderteinundzwanzig'},
+ u'Bot: Ändere dreihunderteinundzwanzig Zeilen von mehreren
Seiten.')
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals',
+ {'action': u'Ändere', 'line': 1, 'page': 1}),
+ u'Bot: Ändere 1 Zeile von einer Seite.')
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals',
+ {'action': u'Ändere', 'line': 1, 'page': 2}),
+ u'Bot: Ändere 1 Zeile von mehreren Seiten.')
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals',
+ {'action': u'Ändere', 'line': "11", 'page': 2}),
+ u'Bot: Ändere 11 Zeilen von mehreren Seiten.')
+
+ def testMultipleWrongParameterLength(self):
+ """ Test wrong parameter lenght"""
+ with self.assertRaisesRegexp(ValueError, "Length of parameter does not
match PLURAL occurences"):
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals', (1, 2))
+ % {'action': u'Ändere', 'line': u'drei'},
+ u'Bot: Ändere drei Zeilen von mehreren Seiten.')
+
+ with self.assertRaisesRegexp(ValueError, "Length of parameter does not
match PLURAL occurences"):
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals', ["321"])
+ % {'action': u'Ändere', 'line': u'dreihunderteinundzwanzig'},
+ u'Bot: Ändere dreihunderteinundzwanzig Zeilen von mehreren
Seiten.')
+
+ def testMultipleNonNumbers(self):
+ """ Numbers or string numbers are required for tuple or list items """
+ with self.assertRaisesRegexp(ValueError, "invalid literal for int\(\)
with base 10: 'drei'"):
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals', ["drei", "1",
1])
+ % {'action': u'Ändere', 'line': u'drei'},
+ u'Bot: Ändere drei Zeilen von einer Seite.')
+ with self.assertRaisesRegexp(ValueError, "invalid literal for int\(\)
with base 10: 'elf'"):
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals',
+ {'action': u'Ändere', 'line': "elf", 'page':
2}),
+ u'Bot: Ändere elf Zeilen von mehreren Seiten.')
+
+ def testAllParametersExist(self):
+ with self.assertRaisesRegexp(KeyError, "u'line'"):
+ # all parameters must be inside twntranslate
+ self.assertEqual(
+ i18n.twntranslate('de', 'test-multiple-plurals',
+ {'line': 1, 'page': 1})
+ % {'action': u'Ändere'},
+ u'Bot: Ändere 1 Zeile von einer Seite.')
+
if __name__ == '__main__':
try:
--
To view, visit https://gerrit.wikimedia.org/r/119338
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I6420b22835ec8db9c70806f46bf2efda65944c34
Gerrit-PatchSet: 8
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: Xqt <[email protected]>
Gerrit-Reviewer: Ladsgroup <[email protected]>
Gerrit-Reviewer: Merlijn van Deen <[email protected]>
Gerrit-Reviewer: Pyfisch <[email protected]>
Gerrit-Reviewer: Ricordisamoa <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
Pywikibot-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/pywikibot-commits