Add plural to language
This commit is contained in:
1 parent
ccd026c9c6
commit
01e715bb05
9 files changed
+120
No files matched your search
@@ -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'
|
||||
|
||||
@@ -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"',
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -10,6 +10,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_en">
|
||||
<field name="code">en</field>
|
||||
<field name="name">English</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%m/%d/%Y</field>
|
||||
<field name="am">AM</field>
|
||||
<field name="pm">PM</field>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,6 +11,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_bg">
|
||||
<field name="code">bg</field>
|
||||
<field name="name">Bulgarian</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -32,6 +34,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_ca">
|
||||
<field name="code">ca</field>
|
||||
<field name="name">Català</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%d/%m/%Y</field>
|
||||
<field name="am">a. m.</field>
|
||||
<field name="pm">p. m.</field>
|
||||
@@ -53,6 +57,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_cs">
|
||||
<field name="code">cs</field>
|
||||
<field name="name">Czech</field>
|
||||
<field name="nplurals" eval="3"/>
|
||||
<field name="plural">0 if n == 1 else 1 if n >= 2 and n <= 4 else 2</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -74,6 +80,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_de">
|
||||
<field name="code">de</field>
|
||||
<field name="name">German</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -98,6 +106,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_es">
|
||||
<field name="code">es</field>
|
||||
<field name="name">Spanish</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%d/%m/%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -119,6 +129,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_es_419">
|
||||
<field name="code">es_419</field>
|
||||
<field name="name">Spanish (Latin American)</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%d/%m/%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -140,6 +152,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_et">
|
||||
<field name="code">et</field>
|
||||
<field name="name">Estonian</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="grouping">[3, 3]</field>
|
||||
<field name="decimal_point">,</field>
|
||||
@@ -159,6 +173,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_fa">
|
||||
<field name="code">fa</field>
|
||||
<field name="name">Persian</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n > 1</field>
|
||||
<field name="direction">rtl</field>
|
||||
<field name="date">%Y/%m/%d</field>
|
||||
<field name="am"></field>
|
||||
@@ -181,6 +197,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_fi">
|
||||
<field name="code">fi</field>
|
||||
<field name="name">Finnish</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="grouping">[3, 3, 0]</field>
|
||||
<field name="decimal_point">,</field>
|
||||
@@ -200,6 +218,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_fr">
|
||||
<field name="code">fr</field>
|
||||
<field name="name">French</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n > 1</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -221,6 +241,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_hu">
|
||||
<field name="code">hu</field>
|
||||
<field name="name">Hungarian</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%Y-%m-%d</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -242,6 +264,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_id">
|
||||
<field name="code">id</field>
|
||||
<field name="name">Indonesian</field>
|
||||
<field name="nplurals" eval="1"/>
|
||||
<field name="plural">0</field>
|
||||
<field name="date">%d/%m/%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -263,6 +287,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_it">
|
||||
<field name="code">it</field>
|
||||
<field name="name">Italian</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%d/%m/%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -284,6 +310,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_lo">
|
||||
<field name="code">lo</field>
|
||||
<field name="name">Lao</field>
|
||||
<field name="nplurals" eval="1"/>
|
||||
<field name="plural">0</field>
|
||||
<field name="date">%d/%m/%Y</field>
|
||||
<field name="am">AM</field>
|
||||
<field name="pm">PM</field>
|
||||
@@ -305,6 +333,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_lt">
|
||||
<field name="code">lt</field>
|
||||
<field name="name">Lithuanian</field>
|
||||
<field name="nplurals" eval="3"/>
|
||||
<field name="plural">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</field>
|
||||
<field name="date">%Y-%m-%d</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -326,6 +356,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_nl">
|
||||
<field name="code">nl</field>
|
||||
<field name="name">Dutch</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%d-%m-%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -347,6 +379,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_pl">
|
||||
<field name="code">pl</field>
|
||||
<field name="name">Polish</field>
|
||||
<field name="nplurals" eval="3"/>
|
||||
<field name="plural">0 if n == 1 else 1 if n % 10 >= 2 and n % 10 <= 4 and (n % 100 < 10 or n % 100 >= 20) else 2</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -368,6 +402,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_pt">
|
||||
<field name="code">pt</field>
|
||||
<field name="name">Portuguese</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n != 1</field>
|
||||
<field name="date">%d-%m-%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -389,6 +425,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_ro">
|
||||
<field name="code">ro</field>
|
||||
<field name="name">Romanian</field>
|
||||
<field name="nplurals" eval="3"/>
|
||||
<field name="plural">0 if n == 1 else 1 if n == 0 or (n % 100 > 0 and n % 100 < 20) else 2</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -410,6 +448,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_ru">
|
||||
<field name="code">ru</field>
|
||||
<field name="name">Russian</field>
|
||||
<field name="nplurals" eval="3"/>
|
||||
<field name="plural">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</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -431,6 +471,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_sl">
|
||||
<field name="code">sl</field>
|
||||
<field name="name">Slovenian</field>
|
||||
<field name="nplurals" eval="4"/>
|
||||
<field name="plural">0 if n % 100 == 1 else 1 if n % 100 == 2 else 2 if n % 100 == 3 or n % 100 == 4 else 3</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="am"></field>
|
||||
<field name="pm"></field>
|
||||
@@ -452,6 +494,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_tr">
|
||||
<field name="code">tr</field>
|
||||
<field name="name">Turkish</field>
|
||||
<field name="nplurals" eval="2"/>
|
||||
<field name="plural">n > 1</field>
|
||||
<field name="date">%d-%m-%Y</field>
|
||||
<field name="grouping">[3, 3, 0]</field>
|
||||
<field name="decimal_point">,</field>
|
||||
@@ -471,6 +515,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_uk">
|
||||
<field name="code">uk</field>
|
||||
<field name="name">Ukrainian</field>
|
||||
<field name="nplurals" eval="3"/>
|
||||
<field name="plural">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</field>
|
||||
<field name="date">%d.%m.%Y</field>
|
||||
<field name="grouping">[3, 3]</field>
|
||||
<field name="decimal_point">,</field>
|
||||
@@ -490,6 +536,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.lang" id="lang_zh_CN">
|
||||
<field name="code">zh_CN</field>
|
||||
<field name="name">Chinese Simplified</field>
|
||||
<field name="nplurals" eval="1"/>
|
||||
<field name="plural">0</field>
|
||||
<field name="date">%Y-%m-%d</field>
|
||||
<field name="am">上午</field>
|
||||
<field name="pm">下午</field>
|
||||
|
||||
@@ -307,6 +307,9 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.message" id="msg_language_invalid_date">
|
||||
<field name="text">Invalid date format "%(format)s" for language "%(language)s".</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_language_plural_invalid">
|
||||
<field name="text">Invalid plural "%(plural)s" for language "%(language)s" with exception "%(exception)s" and n %(n)r.</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_language_default_translatable">
|
||||
<field name="text">The default language "%(language)s" must be translatable.</field>
|
||||
</record>
|
||||
|
||||
@@ -14,6 +14,12 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="translatable"/>
|
||||
<label name="parent"/>
|
||||
<field name="parent"/>
|
||||
|
||||
<label name="nplurals"/>
|
||||
<field name="nplurals"/>
|
||||
<label name="plural"/>
|
||||
<field name="plural" colspan="4"/>
|
||||
|
||||
<separator string="Date Formatting" colspan="6" id="date"/>
|
||||
<label name="date"/>
|
||||
<field name="date"/>
|
||||
|
||||
@@ -335,6 +335,17 @@ class IrTestCase(ModuleTestCase):
|
||||
lang.format_number_symbol(value, unit, digits, grouping),
|
||||
result)
|
||||
|
||||
@with_transaction()
|
||||
def test_lang_plural(self):
|
||||
"Test Lang plural"
|
||||
pool = Pool()
|
||||
Lang = pool.get('ir.lang')
|
||||
|
||||
languages = Lang.search([])
|
||||
for i in range(100):
|
||||
for language in languages:
|
||||
language.get_plural(i)
|
||||
|
||||
@with_transaction()
|
||||
def test_model_data_get_id(self):
|
||||
"Test ModelData.get_id"
|
||||
|
||||
Reference in new issue
Block a user