From 01e715bb05320e6aaae8d2fa843fb7ec13062c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 16 Oct 2024 22:46:26 +0200 Subject: [PATCH] Add plural to language --- trytond/CHANGELOG | 1 + trytond/setup.py | 1 + trytond/trytond/ir/exceptions.py | 2 ++ trytond/trytond/ir/ir.xml | 2 ++ trytond/trytond/ir/lang.py | 46 +++++++++++++++++++++++++ trytond/trytond/ir/lang.xml | 48 +++++++++++++++++++++++++++ trytond/trytond/ir/message.xml | 3 ++ trytond/trytond/ir/view/lang_form.xml | 6 ++++ trytond/trytond/tests/test_ir.py | 11 ++++++ 9 files changed, 120 insertions(+) diff --git a/trytond/CHANGELOG b/trytond/CHANGELOG index 425ac608e1..7c88fe20d0 100644 --- a/trytond/CHANGELOG +++ b/trytond/CHANGELOG @@ -1,3 +1,4 @@ +* Add plural to language * Set Decimal precision of default context from TRYTOND_DECIMAL_PREC * Replace usage of docstring of Model by __string__ attribute * Rename ir.model.field 'field_description' into 'string' diff --git a/trytond/setup.py b/trytond/setup.py index 57b92daaca..fca4261601 100755 --- a/trytond/setup.py +++ b/trytond/setup.py @@ -141,6 +141,7 @@ setup(name=name, 'python-dateutil', 'polib', 'python-sql >= 1.5', + 'simpleeval', 'werkzeug >= 0.12', 'passlib >= 1.7.0', 'pytz;python_version<"3.9"', diff --git a/trytond/trytond/ir/exceptions.py b/trytond/trytond/ir/exceptions.py index 9c847335b1..e73fe5bf92 100644 --- a/trytond/trytond/ir/exceptions.py +++ b/trytond/trytond/ir/exceptions.py @@ -4,6 +4,7 @@ from .lang import DateError as LanguageDateError from .lang import DeleteDefaultError as LanguageDeleteDefaultError from .lang import GroupingError as LanguageGroupingError +from .lang import PluralError as LanguagePluralError from .lang import TranslatableError as LanguageTranslatableError from .module import DeactivateDependencyError from .sequence import AffixError as SequenceAffixError @@ -16,6 +17,7 @@ __all__ = [ LanguageDateError, LanguageDeleteDefaultError, LanguageGroupingError, + LanguagePluralError, LanguageTranslatableError, SequenceAffixError, SequenceMissingError, diff --git a/trytond/trytond/ir/ir.xml b/trytond/trytond/ir/ir.xml index 9d42e4b137..4eefc3c9fe 100644 --- a/trytond/trytond/ir/ir.xml +++ b/trytond/trytond/ir/ir.xml @@ -10,6 +10,8 @@ this repository contains the full copyright notices and license terms. --> en English + + n != 1 %m/%d/%Y AM PM diff --git a/trytond/trytond/ir/lang.py b/trytond/trytond/ir/lang.py index 5998feb845..74604fdcb4 100644 --- a/trytond/trytond/ir/lang.py +++ b/trytond/trytond/ir/lang.py @@ -7,6 +7,7 @@ from decimal import Decimal from itertools import takewhile from locale import CHAR_MAX +from simpleeval import simple_eval from sql import Table from trytond.cache import Cache @@ -31,6 +32,10 @@ class DateError(UserError): pass +class PluralError(UserError): + pass + + class TranslatableError(UserError): pass @@ -75,6 +80,16 @@ class Lang(DeactivableMixin, ModelSQL, ModelView): ('rtl', 'Right-to-left'), ], 'Direction', required=True) + nplurals = fields.Integer( + "Number of plurals", required=True, + domain=[ + ('nplurals', '>=', 1), + ('nplurals', '<', 5), + ]) + plural = fields.Char( + "Plural", required=True, + help="Python expression that returns the plural form for 'n'.") + # date date = fields.Char("Date", required=True, strip=False) @@ -171,6 +186,14 @@ class Lang(DeactivableMixin, ModelSQL, ModelView): def default_direction(): return 'ltr' + @classmethod + def default_nplurals(cls): + return 2 + + @classmethod + def default_plural(cls): + return 'n != 1' + @staticmethod def default_date(): return '%m/%d/%Y' @@ -268,6 +291,7 @@ class Lang(DeactivableMixin, ModelSQL, ModelView): cls.check_grouping(languages, field_names) cls.check_date(languages, field_names) cls.check_translatable(languages) + cls.check_plural(languages, field_names) @classmethod def check_grouping(cls, langs, fields_names=None): @@ -339,6 +363,28 @@ class Lang(DeactivableMixin, ModelSQL, ModelView): gettext('ir.msg_language_default_translatable', language=lang.rec_name)) + @classmethod + def check_plural(cls, languages, field_names=None): + if field_names and 'plural' not in field_names: + return + for language in languages: + language.get_plural(1) + + def get_plural(self, n): + try: + plural = simple_eval(self.plural, names={'n': n}) + if not (0 <= plural < self.nplurals): + raise ValueError( + f"result is not between 0 and {self.nplurals}") + return int(plural) + except Exception as exception: + raise PluralError( + gettext('ir.msg_language_plural_invalid', + language=self.rec_name, + plural=self.plural, + n=n, + exception=exception)) from exception + @classmethod def check_xml_record(cls, langs, values): pass diff --git a/trytond/trytond/ir/lang.xml b/trytond/trytond/ir/lang.xml index 20a44ada60..57296244a7 100644 --- a/trytond/trytond/ir/lang.xml +++ b/trytond/trytond/ir/lang.xml @@ -11,6 +11,8 @@ this repository contains the full copyright notices and license terms. --> bg Bulgarian + + n != 1 %d.%m.%Y @@ -32,6 +34,8 @@ this repository contains the full copyright notices and license terms. --> ca Català + + n != 1 %d/%m/%Y a. m. p. m. @@ -53,6 +57,8 @@ this repository contains the full copyright notices and license terms. --> cs Czech + + 0 if n == 1 else 1 if n >= 2 and n <= 4 else 2 %d.%m.%Y @@ -74,6 +80,8 @@ this repository contains the full copyright notices and license terms. --> de German + + n != 1 %d.%m.%Y @@ -98,6 +106,8 @@ this repository contains the full copyright notices and license terms. --> es Spanish + + n != 1 %d/%m/%Y @@ -119,6 +129,8 @@ this repository contains the full copyright notices and license terms. --> es_419 Spanish (Latin American) + + n != 1 %d/%m/%Y @@ -140,6 +152,8 @@ this repository contains the full copyright notices and license terms. --> et Estonian + + n != 1 %d.%m.%Y [3, 3] , @@ -159,6 +173,8 @@ this repository contains the full copyright notices and license terms. --> fa Persian + + n > 1 rtl %Y/%m/%d @@ -181,6 +197,8 @@ this repository contains the full copyright notices and license terms. --> fi Finnish + + n != 1 %d.%m.%Y [3, 3, 0] , @@ -200,6 +218,8 @@ this repository contains the full copyright notices and license terms. --> fr French + + n > 1 %d.%m.%Y @@ -221,6 +241,8 @@ this repository contains the full copyright notices and license terms. --> hu Hungarian + + n != 1 %Y-%m-%d @@ -242,6 +264,8 @@ this repository contains the full copyright notices and license terms. --> id Indonesian + + 0 %d/%m/%Y @@ -263,6 +287,8 @@ this repository contains the full copyright notices and license terms. --> it Italian + + n != 1 %d/%m/%Y @@ -284,6 +310,8 @@ this repository contains the full copyright notices and license terms. --> lo Lao + + 0 %d/%m/%Y AM PM @@ -305,6 +333,8 @@ this repository contains the full copyright notices and license terms. --> lt Lithuanian + + 0 if n % 10 == 1 and n % 100 != 11 else 1 if n % 10 >= 2 and (n % 100 < 10 or n % 100 >= 20) else 2 %Y-%m-%d @@ -326,6 +356,8 @@ this repository contains the full copyright notices and license terms. --> nl Dutch + + n != 1 %d-%m-%Y @@ -347,6 +379,8 @@ this repository contains the full copyright notices and license terms. --> pl Polish + + 0 if n == 1 else 1 if n % 10 >= 2 and n % 10 <= 4 and (n % 100 < 10 or n % 100 >= 20) else 2 %d.%m.%Y @@ -368,6 +402,8 @@ this repository contains the full copyright notices and license terms. --> pt Portuguese + + n != 1 %d-%m-%Y @@ -389,6 +425,8 @@ this repository contains the full copyright notices and license terms. --> ro Romanian + + 0 if n == 1 else 1 if n == 0 or (n % 100 > 0 and n % 100 < 20) else 2 %d.%m.%Y @@ -410,6 +448,8 @@ this repository contains the full copyright notices and license terms. --> ru Russian + + 0 if n % 10 == 1 and n % 100 != 11 else 1 if n % 10 >= 2 and n % 10 <= 4 and (n % 100 < 10 or n % 100 >= 20) else 2 %d.%m.%Y @@ -431,6 +471,8 @@ this repository contains the full copyright notices and license terms. --> sl Slovenian + + 0 if n % 100 == 1 else 1 if n % 100 == 2 else 2 if n % 100 == 3 or n % 100 == 4 else 3 %d.%m.%Y @@ -452,6 +494,8 @@ this repository contains the full copyright notices and license terms. --> tr Turkish + + n > 1 %d-%m-%Y [3, 3, 0] , @@ -471,6 +515,8 @@ this repository contains the full copyright notices and license terms. --> uk Ukrainian + + 0 if n % 10 == 1 and n % 100 != 11 else 1 if n % 10 >= 2 and n % 10 <= 4 and (n % 100 < 10 or n % 100 >= 20) else 2 %d.%m.%Y [3, 3] , @@ -490,6 +536,8 @@ this repository contains the full copyright notices and license terms. --> zh_CN Chinese Simplified + + 0 %Y-%m-%d 上午 下午 diff --git a/trytond/trytond/ir/message.xml b/trytond/trytond/ir/message.xml index 02a8d5427a..80a1059968 100644 --- a/trytond/trytond/ir/message.xml +++ b/trytond/trytond/ir/message.xml @@ -307,6 +307,9 @@ this repository contains the full copyright notices and license terms. --> Invalid date format "%(format)s" for language "%(language)s". + + Invalid plural "%(plural)s" for language "%(language)s" with exception "%(exception)s" and n %(n)r. + The default language "%(language)s" must be translatable. diff --git a/trytond/trytond/ir/view/lang_form.xml b/trytond/trytond/ir/view/lang_form.xml index b08ec2ac8d..b84e6df2d0 100644 --- a/trytond/trytond/ir/view/lang_form.xml +++ b/trytond/trytond/ir/view/lang_form.xml @@ -14,6 +14,12 @@ this repository contains the full copyright notices and license terms. -->