diff --git a/AUTHORS b/AUTHORS index 4632c66a62e83..aef3caa812f25 100644 --- a/AUTHORS +++ b/AUTHORS @@ -766,6 +766,7 @@ answer newbie questions, and generally made Django that much better: Rob Hudson Rob Nguyen Robin Munn + Rodrigo Gadea Rodrigo Pinheiro Marques de Araújo Romain Garrigues Ronny Haryanto diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 830ba25408b41..006d04ce29390 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -151,6 +151,11 @@ def gettext_noop(s): USE_I18N = True LOCALE_PATHS = [] +# If you set this to True, Django will issue a warning when merging a message +# file for translations with different plural forms than the main ones of the +# locale. +PLURAL_FORMS_CONSISTENCY = False + # Settings for language cookie LANGUAGE_COOKIE_NAME = 'django_language' LANGUAGE_COOKIE_AGE = None diff --git a/django/contrib/admin/locale/en/LC_MESSAGES/djangojs.po b/django/contrib/admin/locale/en/LC_MESSAGES/djangojs.po index 2b335c932556d..f5e1edcc53770 100644 --- a/django/contrib/admin/locale/en/LC_MESSAGES/djangojs.po +++ b/django/contrib/admin/locale/en/LC_MESSAGES/djangojs.po @@ -12,6 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #: contrib/admin/static/admin/js/SelectFilter2.js:47 #, javascript-format diff --git a/django/contrib/admin/locale/kn/LC_MESSAGES/django.mo b/django/contrib/admin/locale/kn/LC_MESSAGES/django.mo index 3740da20869e1..51248ece22333 100644 Binary files a/django/contrib/admin/locale/kn/LC_MESSAGES/django.mo and b/django/contrib/admin/locale/kn/LC_MESSAGES/django.mo differ diff --git a/django/contrib/admin/locale/kn/LC_MESSAGES/django.po b/django/contrib/admin/locale/kn/LC_MESSAGES/django.po index 3ae96cfa6791b..0e16ea62a5eac 100644 --- a/django/contrib/admin/locale/kn/LC_MESSAGES/django.po +++ b/django/contrib/admin/locale/kn/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" #, python-format msgid "Successfully deleted %(count)d %(items)s." @@ -221,11 +221,13 @@ msgstr "ದತ್ತಸಂಚಯದ ದೋಷ" msgid "%(count)s %(name)s was changed successfully." msgid_plural "%(count)s %(name)s were changed successfully." msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(total_count)s selected" msgid_plural "All %(total_count)s selected" msgstr[0] "" +msgstr[1] "" #, python-format msgid "0 of %(cnt)s selected" @@ -511,6 +513,7 @@ msgstr "" msgid "%(counter)s result" msgid_plural "%(counter)s results" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(full_result_count)s total" diff --git a/django/contrib/admin/locale/kn/LC_MESSAGES/djangojs.mo b/django/contrib/admin/locale/kn/LC_MESSAGES/djangojs.mo index 988728ce948e9..ab3a19dab2af1 100644 Binary files a/django/contrib/admin/locale/kn/LC_MESSAGES/djangojs.mo and b/django/contrib/admin/locale/kn/LC_MESSAGES/djangojs.mo differ diff --git a/django/contrib/admin/locale/kn/LC_MESSAGES/djangojs.po b/django/contrib/admin/locale/kn/LC_MESSAGES/djangojs.po index 90363b7a2cf94..71e3e880eb439 100644 --- a/django/contrib/admin/locale/kn/LC_MESSAGES/djangojs.po +++ b/django/contrib/admin/locale/kn/LC_MESSAGES/djangojs.po @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" #, javascript-format msgid "Available %s" @@ -68,6 +68,7 @@ msgstr "" msgid "%(sel)s of %(cnt)s selected" msgid_plural "%(sel)s of %(cnt)s selected" msgstr[0] "" +msgstr[1] "" msgid "" "You have unsaved changes on individual editable fields. If you run an " @@ -92,11 +93,13 @@ msgstr "" msgid "Note: You are %s hour ahead of server time." msgid_plural "Note: You are %s hours ahead of server time." msgstr[0] "" +msgstr[1] "" #, javascript-format msgid "Note: You are %s hour behind server time." msgid_plural "Note: You are %s hours behind server time." msgstr[0] "" +msgstr[1] "" msgid "Now" msgstr "ಈಗ" diff --git a/django/contrib/admindocs/locale/en/LC_MESSAGES/django.po b/django/contrib/admindocs/locale/en/LC_MESSAGES/django.po index ebbbd3abd9470..75ec91bd425a4 100644 --- a/django/contrib/admindocs/locale/en/LC_MESSAGES/django.po +++ b/django/contrib/admindocs/locale/en/LC_MESSAGES/django.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: Django\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-09-08 17:27+0200\n" +"POT-Creation-Date: 2020-01-05 22:32-0500\n" "PO-Revision-Date: 2010-05-13 15:35+0200\n" "Last-Translator: Django team\n" "Language-Team: English \n" @@ -12,288 +12,201 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: contrib/admindocs/apps.py:7 msgid "Administrative Documentation" msgstr "" -#: contrib/admindocs/templates/admin_doc/bookmarklets.html:6 -#: contrib/admindocs/templates/admin_doc/index.html:6 -#: contrib/admindocs/templates/admin_doc/missing_docutils.html:6 -#: contrib/admindocs/templates/admin_doc/model_detail.html:14 -#: contrib/admindocs/templates/admin_doc/model_index.html:8 -#: contrib/admindocs/templates/admin_doc/template_detail.html:6 -#: contrib/admindocs/templates/admin_doc/template_filter_index.html:7 -#: contrib/admindocs/templates/admin_doc/template_tag_index.html:7 -#: contrib/admindocs/templates/admin_doc/view_detail.html:6 -#: contrib/admindocs/templates/admin_doc/view_index.html:7 msgid "Home" msgstr "" -#: contrib/admindocs/templates/admin_doc/bookmarklets.html:7 -#: contrib/admindocs/templates/admin_doc/index.html:7 -#: contrib/admindocs/templates/admin_doc/index.html:10 -#: contrib/admindocs/templates/admin_doc/index.html:14 -#: contrib/admindocs/templates/admin_doc/missing_docutils.html:7 -#: contrib/admindocs/templates/admin_doc/missing_docutils.html:14 -#: contrib/admindocs/templates/admin_doc/model_detail.html:15 -#: contrib/admindocs/templates/admin_doc/model_index.html:9 -#: contrib/admindocs/templates/admin_doc/template_detail.html:7 -#: contrib/admindocs/templates/admin_doc/template_filter_index.html:8 -#: contrib/admindocs/templates/admin_doc/template_tag_index.html:8 -#: contrib/admindocs/templates/admin_doc/view_detail.html:7 -#: contrib/admindocs/templates/admin_doc/view_index.html:8 msgid "Documentation" msgstr "" -#: contrib/admindocs/templates/admin_doc/bookmarklets.html:8 -#: contrib/admindocs/templates/admin_doc/index.html:29 msgid "Bookmarklets" msgstr "" -#: contrib/admindocs/templates/admin_doc/bookmarklets.html:11 msgid "Documentation bookmarklets" msgstr "" -#: contrib/admindocs/templates/admin_doc/bookmarklets.html:15 msgid "" "To install bookmarklets, drag the link to your bookmarks toolbar, or right-" "click the link and add it to your bookmarks. Now you can select the " "bookmarklet from any page in the site." msgstr "" -#: contrib/admindocs/templates/admin_doc/bookmarklets.html:22 msgid "Documentation for this page" msgstr "" -#: contrib/admindocs/templates/admin_doc/bookmarklets.html:23 msgid "" "Jumps you from any page to the documentation for the view that generates " "that page." msgstr "" -#: contrib/admindocs/templates/admin_doc/index.html:17 -#: contrib/admindocs/templates/admin_doc/template_tag_index.html:9 msgid "Tags" msgstr "" -#: contrib/admindocs/templates/admin_doc/index.html:18 msgid "List of all the template tags and their functions." msgstr "" -#: contrib/admindocs/templates/admin_doc/index.html:20 -#: contrib/admindocs/templates/admin_doc/template_filter_index.html:9 msgid "Filters" msgstr "" -#: contrib/admindocs/templates/admin_doc/index.html:21 msgid "" "Filters are actions which can be applied to variables in a template to alter " "the output." msgstr "" -#: contrib/admindocs/templates/admin_doc/index.html:23 -#: contrib/admindocs/templates/admin_doc/model_detail.html:16 -#: contrib/admindocs/templates/admin_doc/model_index.html:10 -#: contrib/admindocs/templates/admin_doc/model_index.html:14 msgid "Models" msgstr "" -#: contrib/admindocs/templates/admin_doc/index.html:24 msgid "" "Models are descriptions of all the objects in the system and their " "associated fields. Each model has a list of fields which can be accessed as " "template variables" msgstr "" -#: contrib/admindocs/templates/admin_doc/index.html:26 -#: contrib/admindocs/templates/admin_doc/view_detail.html:8 -#: contrib/admindocs/templates/admin_doc/view_index.html:9 -#: contrib/admindocs/templates/admin_doc/view_index.html:12 msgid "Views" msgstr "" -#: contrib/admindocs/templates/admin_doc/index.html:27 msgid "" "Each page on the public site is generated by a view. The view defines which " "template is used to generate the page and which objects are available to " "that template." msgstr "" -#: contrib/admindocs/templates/admin_doc/index.html:30 msgid "Tools for your browser to quickly access admin functionality." msgstr "" -#: contrib/admindocs/templates/admin_doc/missing_docutils.html:10 msgid "Please install docutils" msgstr "" -#: contrib/admindocs/templates/admin_doc/missing_docutils.html:17 #, python-format msgid "" "The admin documentation system requires Python's docutils library." msgstr "" -#: contrib/admindocs/templates/admin_doc/missing_docutils.html:19 #, python-format msgid "" "Please ask your administrators to install docutils." msgstr "" -#: contrib/admindocs/templates/admin_doc/model_detail.html:21 #, python-format msgid "Model: %(name)s" msgstr "" -#: contrib/admindocs/templates/admin_doc/model_detail.html:30 msgid "Fields" msgstr "" -#: contrib/admindocs/templates/admin_doc/model_detail.html:35 msgid "Field" msgstr "" -#: contrib/admindocs/templates/admin_doc/model_detail.html:36 msgid "Type" msgstr "" -#: contrib/admindocs/templates/admin_doc/model_detail.html:37 -#: contrib/admindocs/templates/admin_doc/model_detail.html:60 msgid "Description" msgstr "" -#: contrib/admindocs/templates/admin_doc/model_detail.html:53 msgid "Methods with arguments" msgstr "" -#: contrib/admindocs/templates/admin_doc/model_detail.html:58 msgid "Method" msgstr "" -#: contrib/admindocs/templates/admin_doc/model_detail.html:59 msgid "Arguments" msgstr "" -#: contrib/admindocs/templates/admin_doc/model_detail.html:76 msgid "Back to Model documentation" msgstr "" -#: contrib/admindocs/templates/admin_doc/model_index.html:18 msgid "Model documentation" msgstr "" -#: contrib/admindocs/templates/admin_doc/model_index.html:43 msgid "Model groups" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_detail.html:8 msgid "Templates" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_detail.html:13 #, python-format msgid "Template: %(name)s" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_detail.html:16 #, python-format msgid "Template: %(name)s" msgstr "" #. Translators: Search is not a verb here, it qualifies path (a search path) -#: contrib/admindocs/templates/admin_doc/template_detail.html:19 #, python-format msgid "Search path for template %(name)s:" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_detail.html:22 msgid "(does not exist)" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_detail.html:26 msgid "Back to Documentation" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_filter_index.html:12 msgid "Template filters" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_filter_index.html:16 msgid "Template filter documentation" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_filter_index.html:22 -#: contrib/admindocs/templates/admin_doc/template_filter_index.html:43 msgid "Built-in filters" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_filter_index.html:23 #, python-format msgid "" "To use these filters, put %(code)s in your template before " "using the filter." msgstr "" -#: contrib/admindocs/templates/admin_doc/template_tag_index.html:12 msgid "Template tags" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_tag_index.html:16 msgid "Template tag documentation" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_tag_index.html:22 -#: contrib/admindocs/templates/admin_doc/template_tag_index.html:43 msgid "Built-in tags" msgstr "" -#: contrib/admindocs/templates/admin_doc/template_tag_index.html:23 #, python-format msgid "" "To use these tags, put %(code)s in your template before using " "the tag." msgstr "" -#: contrib/admindocs/templates/admin_doc/view_detail.html:12 #, python-format msgid "View: %(name)s" msgstr "" -#: contrib/admindocs/templates/admin_doc/view_detail.html:23 msgid "Context:" msgstr "" -#: contrib/admindocs/templates/admin_doc/view_detail.html:28 msgid "Templates:" msgstr "" -#: contrib/admindocs/templates/admin_doc/view_detail.html:32 msgid "Back to View documentation" msgstr "" -#: contrib/admindocs/templates/admin_doc/view_index.html:16 msgid "View documentation" msgstr "" -#: contrib/admindocs/templates/admin_doc/view_index.html:22 msgid "Jump to namespace" msgstr "" -#: contrib/admindocs/templates/admin_doc/view_index.html:27 msgid "Empty namespace" msgstr "" -#: contrib/admindocs/templates/admin_doc/view_index.html:40 #, python-format msgid "Views by namespace %(name)s" msgstr "" -#: contrib/admindocs/templates/admin_doc/view_index.html:42 msgid "Views by empty namespace" msgstr "" -#: contrib/admindocs/templates/admin_doc/view_index.html:49 #, python-format msgid "" "\n" @@ -301,59 +214,42 @@ msgid "" "code>.\n" msgstr "" -#: contrib/admindocs/views.py:71 contrib/admindocs/views.py:72 -#: contrib/admindocs/views.py:74 msgid "tag:" msgstr "" -#: contrib/admindocs/views.py:102 contrib/admindocs/views.py:103 -#: contrib/admindocs/views.py:105 msgid "filter:" msgstr "" -#: contrib/admindocs/views.py:161 contrib/admindocs/views.py:162 -#: contrib/admindocs/views.py:164 msgid "view:" msgstr "" -#: contrib/admindocs/views.py:191 #, python-format msgid "App %(app_label)r not found" msgstr "" -#: contrib/admindocs/views.py:195 #, python-format msgid "Model %(model_name)r not found in app %(app_label)r" msgstr "" -#: contrib/admindocs/views.py:200 contrib/admindocs/views.py:201 -#: contrib/admindocs/views.py:216 contrib/admindocs/views.py:239 -#: contrib/admindocs/views.py:244 contrib/admindocs/views.py:259 -#: contrib/admindocs/views.py:300 contrib/admindocs/views.py:305 msgid "model:" msgstr "" -#: contrib/admindocs/views.py:212 #, python-format msgid "the related `%(app_label)s.%(data_type)s` object" msgstr "" -#: contrib/admindocs/views.py:232 contrib/admindocs/views.py:292 #, python-format msgid "related `%(app_label)s.%(object_name)s` objects" msgstr "" -#: contrib/admindocs/views.py:239 contrib/admindocs/views.py:300 #, python-format msgid "all %s" msgstr "" -#: contrib/admindocs/views.py:244 contrib/admindocs/views.py:305 #, python-format msgid "number of %s" msgstr "" -#: contrib/admindocs/views.py:398 #, python-format msgid "%s does not appear to be a urlpattern object" msgstr "" diff --git a/django/contrib/admindocs/locale/kn/LC_MESSAGES/django.mo b/django/contrib/admindocs/locale/kn/LC_MESSAGES/django.mo index 1c112d5364747..6864131dc714d 100644 Binary files a/django/contrib/admindocs/locale/kn/LC_MESSAGES/django.mo and b/django/contrib/admindocs/locale/kn/LC_MESSAGES/django.mo differ diff --git a/django/contrib/admindocs/locale/kn/LC_MESSAGES/django.po b/django/contrib/admindocs/locale/kn/LC_MESSAGES/django.po index e1a900df0d40f..7d6743620c107 100644 --- a/django/contrib/admindocs/locale/kn/LC_MESSAGES/django.po +++ b/django/contrib/admindocs/locale/kn/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Administrative Documentation" msgstr "" diff --git a/django/contrib/auth/locale/kn/LC_MESSAGES/django.mo b/django/contrib/auth/locale/kn/LC_MESSAGES/django.mo index be5a6deede908..005a31be43f76 100644 Binary files a/django/contrib/auth/locale/kn/LC_MESSAGES/django.mo and b/django/contrib/auth/locale/kn/LC_MESSAGES/django.mo differ diff --git a/django/contrib/auth/locale/kn/LC_MESSAGES/django.po b/django/contrib/auth/locale/kn/LC_MESSAGES/django.po index f1b7174d08994..e1784d2a3c73a 100644 --- a/django/contrib/auth/locale/kn/LC_MESSAGES/django.po +++ b/django/contrib/auth/locale/kn/LC_MESSAGES/django.po @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Personal info" msgstr "ವೈಯುಕ್ತಿಕ ಮಾಹಿತಿ" @@ -221,11 +221,13 @@ msgid_plural "" "This password is too short. It must contain at least %(min_length)d " "characters." msgstr[0] "" +msgstr[1] "" #, python-format msgid "Your password must contain at least %(min_length)d character." msgid_plural "Your password must contain at least %(min_length)d characters." msgstr[0] "" +msgstr[1] "" #, python-format msgid "The password is too similar to the %(verbose_name)s." diff --git a/django/contrib/contenttypes/locale/en/LC_MESSAGES/django.po b/django/contrib/contenttypes/locale/en/LC_MESSAGES/django.po index cee02371410a4..bf55304e4d55f 100644 --- a/django/contrib/contenttypes/locale/en/LC_MESSAGES/django.po +++ b/django/contrib/contenttypes/locale/en/LC_MESSAGES/django.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: Django\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-09-08 17:27+0200\n" +"POT-Creation-Date: 2019-12-31 17:33-0500\n" "PO-Revision-Date: 2010-05-13 15:35+0200\n" "Last-Translator: Django team\n" "Language-Team: English \n" @@ -12,6 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #: contrib/contenttypes/apps.py:16 msgid "Content Types" diff --git a/django/contrib/contenttypes/locale/ka/LC_MESSAGES/django.mo b/django/contrib/contenttypes/locale/ka/LC_MESSAGES/django.mo index 55454596ee3e5..760e3f8d5c188 100644 Binary files a/django/contrib/contenttypes/locale/ka/LC_MESSAGES/django.mo and b/django/contrib/contenttypes/locale/ka/LC_MESSAGES/django.mo differ diff --git a/django/contrib/contenttypes/locale/ka/LC_MESSAGES/django.po b/django/contrib/contenttypes/locale/ka/LC_MESSAGES/django.po index 6c5c82121ebee..e2f139688cd9f 100644 --- a/django/contrib/contenttypes/locale/ka/LC_MESSAGES/django.po +++ b/django/contrib/contenttypes/locale/ka/LC_MESSAGES/django.po @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ka\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" msgid "Content Types" msgstr "კონტენტის ტიპები" diff --git a/django/contrib/contenttypes/locale/kn/LC_MESSAGES/django.mo b/django/contrib/contenttypes/locale/kn/LC_MESSAGES/django.mo index 00951f1cb484e..8295af4955470 100644 Binary files a/django/contrib/contenttypes/locale/kn/LC_MESSAGES/django.mo and b/django/contrib/contenttypes/locale/kn/LC_MESSAGES/django.mo differ diff --git a/django/contrib/contenttypes/locale/kn/LC_MESSAGES/django.po b/django/contrib/contenttypes/locale/kn/LC_MESSAGES/django.po index 10e5ae6adcfe7..d4bde118f9145 100644 --- a/django/contrib/contenttypes/locale/kn/LC_MESSAGES/django.po +++ b/django/contrib/contenttypes/locale/kn/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Content Types" msgstr "" diff --git a/django/contrib/flatpages/locale/en/LC_MESSAGES/django.po b/django/contrib/flatpages/locale/en/LC_MESSAGES/django.po index 8fe158ead1536..2bfdf8bd726bb 100644 --- a/django/contrib/flatpages/locale/en/LC_MESSAGES/django.po +++ b/django/contrib/flatpages/locale/en/LC_MESSAGES/django.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: Django\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-09-08 17:27+0200\n" +"POT-Creation-Date: 2019-12-31 17:33-0500\n" "PO-Revision-Date: 2010-05-13 15:35+0200\n" "Last-Translator: Django team\n" "Language-Team: English \n" @@ -12,6 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #: contrib/flatpages/admin.py:12 msgid "Advanced options" diff --git a/django/contrib/flatpages/locale/fa/LC_MESSAGES/django.mo b/django/contrib/flatpages/locale/fa/LC_MESSAGES/django.mo index 091b0afc48bba..73040091050c6 100644 Binary files a/django/contrib/flatpages/locale/fa/LC_MESSAGES/django.mo and b/django/contrib/flatpages/locale/fa/LC_MESSAGES/django.mo differ diff --git a/django/contrib/flatpages/locale/fa/LC_MESSAGES/django.po b/django/contrib/flatpages/locale/fa/LC_MESSAGES/django.po index 0412ace95b8a4..c3c56c7bc8e03 100644 --- a/django/contrib/flatpages/locale/fa/LC_MESSAGES/django.po +++ b/django/contrib/flatpages/locale/fa/LC_MESSAGES/django.po @@ -18,7 +18,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fa\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Advanced options" msgstr "گزینه‌های پیشرفته" diff --git a/django/contrib/flatpages/locale/ka/LC_MESSAGES/django.mo b/django/contrib/flatpages/locale/ka/LC_MESSAGES/django.mo index 9b20adf6c18ac..76f49ae9ed7bb 100644 Binary files a/django/contrib/flatpages/locale/ka/LC_MESSAGES/django.mo and b/django/contrib/flatpages/locale/ka/LC_MESSAGES/django.mo differ diff --git a/django/contrib/flatpages/locale/ka/LC_MESSAGES/django.po b/django/contrib/flatpages/locale/ka/LC_MESSAGES/django.po index 12dcb14058b43..3bf4bcc1403fa 100644 --- a/django/contrib/flatpages/locale/ka/LC_MESSAGES/django.po +++ b/django/contrib/flatpages/locale/ka/LC_MESSAGES/django.po @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ka\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" msgid "Advanced options" msgstr "დამატებითი პარამეტრები" diff --git a/django/contrib/flatpages/locale/kn/LC_MESSAGES/django.mo b/django/contrib/flatpages/locale/kn/LC_MESSAGES/django.mo index ed64a6b861787..a06136827ed6e 100644 Binary files a/django/contrib/flatpages/locale/kn/LC_MESSAGES/django.mo and b/django/contrib/flatpages/locale/kn/LC_MESSAGES/django.mo differ diff --git a/django/contrib/flatpages/locale/kn/LC_MESSAGES/django.po b/django/contrib/flatpages/locale/kn/LC_MESSAGES/django.po index 9d86fb9fefa58..83198cc083818 100644 --- a/django/contrib/flatpages/locale/kn/LC_MESSAGES/django.po +++ b/django/contrib/flatpages/locale/kn/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Advanced options" msgstr "" diff --git a/django/contrib/gis/locale/en/LC_MESSAGES/django.po b/django/contrib/gis/locale/en/LC_MESSAGES/django.po index aed3a2f9ddb15..9859184a8c27b 100644 --- a/django/contrib/gis/locale/en/LC_MESSAGES/django.po +++ b/django/contrib/gis/locale/en/LC_MESSAGES/django.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: Django\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-09-08 17:27+0200\n" +"POT-Creation-Date: 2019-12-31 17:33-0500\n" "PO-Revision-Date: 2010-05-13 15:35+0200\n" "Last-Translator: Django team\n" "Language-Team: English \n" @@ -12,6 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #: contrib/gis/apps.py:8 msgid "GIS" diff --git a/django/contrib/gis/locale/ka/LC_MESSAGES/django.mo b/django/contrib/gis/locale/ka/LC_MESSAGES/django.mo index b684ee95ae592..9ea3da3bb570b 100644 Binary files a/django/contrib/gis/locale/ka/LC_MESSAGES/django.mo and b/django/contrib/gis/locale/ka/LC_MESSAGES/django.mo differ diff --git a/django/contrib/gis/locale/ka/LC_MESSAGES/django.po b/django/contrib/gis/locale/ka/LC_MESSAGES/django.po index 52f95b8b277c5..31bb23c8d5b5c 100644 --- a/django/contrib/gis/locale/ka/LC_MESSAGES/django.po +++ b/django/contrib/gis/locale/ka/LC_MESSAGES/django.po @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ka\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" msgid "GIS" msgstr "" diff --git a/django/contrib/gis/locale/kk/LC_MESSAGES/django.mo b/django/contrib/gis/locale/kk/LC_MESSAGES/django.mo index c7503014981e9..426ba82bd94b5 100644 Binary files a/django/contrib/gis/locale/kk/LC_MESSAGES/django.mo and b/django/contrib/gis/locale/kk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/gis/locale/kk/LC_MESSAGES/django.po b/django/contrib/gis/locale/kk/LC_MESSAGES/django.po index cd5e947cfdf53..2666802e787ba 100644 --- a/django/contrib/gis/locale/kk/LC_MESSAGES/django.po +++ b/django/contrib/gis/locale/kk/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kk\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" msgid "GIS" msgstr "" diff --git a/django/contrib/gis/locale/kn/LC_MESSAGES/django.mo b/django/contrib/gis/locale/kn/LC_MESSAGES/django.mo index be4f674140bee..a381f5b9b7153 100644 Binary files a/django/contrib/gis/locale/kn/LC_MESSAGES/django.mo and b/django/contrib/gis/locale/kn/LC_MESSAGES/django.mo differ diff --git a/django/contrib/gis/locale/kn/LC_MESSAGES/django.po b/django/contrib/gis/locale/kn/LC_MESSAGES/django.po index b2b29a8f0f385..0ec1b161b4770 100644 --- a/django/contrib/gis/locale/kn/LC_MESSAGES/django.po +++ b/django/contrib/gis/locale/kn/LC_MESSAGES/django.po @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "GIS" msgstr "" diff --git a/django/contrib/gis/locale/sk/LC_MESSAGES/django.mo b/django/contrib/gis/locale/sk/LC_MESSAGES/django.mo index 7b3b58569b1e8..8d2bf2fd08418 100644 Binary files a/django/contrib/gis/locale/sk/LC_MESSAGES/django.mo and b/django/contrib/gis/locale/sk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/gis/locale/sk/LC_MESSAGES/django.po b/django/contrib/gis/locale/sk/LC_MESSAGES/django.po index 9ad9a85c8d34a..731d3262bf28a 100644 --- a/django/contrib/gis/locale/sk/LC_MESSAGES/django.po +++ b/django/contrib/gis/locale/sk/LC_MESSAGES/django.po @@ -17,7 +17,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sk\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n " +">= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" msgid "GIS" msgstr "GIS" diff --git a/django/contrib/gis/locale/uk/LC_MESSAGES/django.mo b/django/contrib/gis/locale/uk/LC_MESSAGES/django.mo index 2437a6326bee3..56964d54a35dc 100644 Binary files a/django/contrib/gis/locale/uk/LC_MESSAGES/django.mo and b/django/contrib/gis/locale/uk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/gis/locale/uk/LC_MESSAGES/django.po b/django/contrib/gis/locale/uk/LC_MESSAGES/django.po index 1d6a3c05fd87f..8c1919eb23f7c 100644 --- a/django/contrib/gis/locale/uk/LC_MESSAGES/django.po +++ b/django/contrib/gis/locale/uk/LC_MESSAGES/django.po @@ -21,8 +21,10 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != " +"11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % " +"100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || " +"(n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" msgid "GIS" msgstr "ГІС" diff --git a/django/contrib/humanize/locale/kn/LC_MESSAGES/django.mo b/django/contrib/humanize/locale/kn/LC_MESSAGES/django.mo index b75cf46d95c92..9359e87e5a5c1 100644 Binary files a/django/contrib/humanize/locale/kn/LC_MESSAGES/django.mo and b/django/contrib/humanize/locale/kn/LC_MESSAGES/django.mo differ diff --git a/django/contrib/humanize/locale/kn/LC_MESSAGES/django.po b/django/contrib/humanize/locale/kn/LC_MESSAGES/django.po index b38dd8cc7609c..bdae525203cfc 100644 --- a/django/contrib/humanize/locale/kn/LC_MESSAGES/django.po +++ b/django/contrib/humanize/locale/kn/LC_MESSAGES/django.po @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Humanize" msgstr "" @@ -35,111 +35,133 @@ msgstr "" msgid "%(value).1f million" msgid_plural "%(value).1f million" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s million" msgid_plural "%(value)s million" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value).1f billion" msgid_plural "%(value).1f billion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s billion" msgid_plural "%(value)s billion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value).1f trillion" msgid_plural "%(value).1f trillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s trillion" msgid_plural "%(value)s trillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value).1f quadrillion" msgid_plural "%(value).1f quadrillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s quadrillion" msgid_plural "%(value)s quadrillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value).1f quintillion" msgid_plural "%(value).1f quintillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s quintillion" msgid_plural "%(value)s quintillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value).1f sextillion" msgid_plural "%(value).1f sextillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s sextillion" msgid_plural "%(value)s sextillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value).1f septillion" msgid_plural "%(value).1f septillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s septillion" msgid_plural "%(value)s septillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value).1f octillion" msgid_plural "%(value).1f octillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s octillion" msgid_plural "%(value)s octillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value).1f nonillion" msgid_plural "%(value).1f nonillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s nonillion" msgid_plural "%(value)s nonillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value).1f decillion" msgid_plural "%(value).1f decillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s decillion" msgid_plural "%(value)s decillion" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value).1f googol" msgid_plural "%(value).1f googol" msgstr[0] "" +msgstr[1] "" #, python-format msgid "%(value)s googol" msgid_plural "%(value)s googol" msgstr[0] "" +msgstr[1] "" msgid "one" msgstr "" @@ -191,6 +213,7 @@ msgstr "" msgid "a second ago" msgid_plural "%(count)s seconds ago" msgstr[0] "" +msgstr[1] "" #. Translators: please keep a non-breaking space (U+00A0) #. between count and time unit. @@ -198,6 +221,7 @@ msgstr[0] "" msgid "a minute ago" msgid_plural "%(count)s minutes ago" msgstr[0] "" +msgstr[1] "" #. Translators: please keep a non-breaking space (U+00A0) #. between count and time unit. @@ -205,6 +229,7 @@ msgstr[0] "" msgid "an hour ago" msgid_plural "%(count)s hours ago" msgstr[0] "" +msgstr[1] "" #, python-format msgctxt "naturaltime" @@ -217,6 +242,7 @@ msgstr "" msgid "a second from now" msgid_plural "%(count)s seconds from now" msgstr[0] "" +msgstr[1] "" #. Translators: please keep a non-breaking space (U+00A0) #. between count and time unit. @@ -224,6 +250,7 @@ msgstr[0] "" msgid "a minute from now" msgid_plural "%(count)s minutes from now" msgstr[0] "" +msgstr[1] "" #. Translators: please keep a non-breaking space (U+00A0) #. between count and time unit. @@ -231,3 +258,4 @@ msgstr[0] "" msgid "an hour from now" msgid_plural "%(count)s hours from now" msgstr[0] "" +msgstr[1] "" diff --git a/django/contrib/postgres/locale/en/LC_MESSAGES/django.mo b/django/contrib/postgres/locale/en/LC_MESSAGES/django.mo index 08a7b68596a8a..d7c1287a9422a 100644 Binary files a/django/contrib/postgres/locale/en/LC_MESSAGES/django.mo and b/django/contrib/postgres/locale/en/LC_MESSAGES/django.mo differ diff --git a/django/contrib/postgres/locale/en_GB/LC_MESSAGES/django.mo b/django/contrib/postgres/locale/en_GB/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..71cbdf3e9d8d5 Binary files /dev/null and b/django/contrib/postgres/locale/en_GB/LC_MESSAGES/django.mo differ diff --git a/django/contrib/postgres/locale/km/LC_MESSAGES/django.mo b/django/contrib/postgres/locale/km/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..314bedb17d5ca Binary files /dev/null and b/django/contrib/postgres/locale/km/LC_MESSAGES/django.mo differ diff --git a/django/contrib/postgres/locale/ml/LC_MESSAGES/django.mo b/django/contrib/postgres/locale/ml/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..71cbdf3e9d8d5 Binary files /dev/null and b/django/contrib/postgres/locale/ml/LC_MESSAGES/django.mo differ diff --git a/django/contrib/redirects/locale/en/LC_MESSAGES/django.po b/django/contrib/redirects/locale/en/LC_MESSAGES/django.po index 5da48fb866892..996110b550527 100644 --- a/django/contrib/redirects/locale/en/LC_MESSAGES/django.po +++ b/django/contrib/redirects/locale/en/LC_MESSAGES/django.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: Django\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-09-08 17:27+0200\n" +"POT-Creation-Date: 2019-12-31 17:33-0500\n" "PO-Revision-Date: 2010-05-13 15:35+0200\n" "Last-Translator: Django team\n" "Language-Team: English \n" @@ -12,6 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #: contrib/redirects/apps.py:7 msgid "Redirects" diff --git a/django/contrib/redirects/locale/fa/LC_MESSAGES/django.mo b/django/contrib/redirects/locale/fa/LC_MESSAGES/django.mo index 2969ccc727130..98acfd82a78b5 100644 Binary files a/django/contrib/redirects/locale/fa/LC_MESSAGES/django.mo and b/django/contrib/redirects/locale/fa/LC_MESSAGES/django.mo differ diff --git a/django/contrib/redirects/locale/fa/LC_MESSAGES/django.po b/django/contrib/redirects/locale/fa/LC_MESSAGES/django.po index 10625cca863f1..c87ab16b7930a 100644 --- a/django/contrib/redirects/locale/fa/LC_MESSAGES/django.po +++ b/django/contrib/redirects/locale/fa/LC_MESSAGES/django.po @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fa\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Redirects" msgstr "باز-ارسال‌ها" diff --git a/django/contrib/redirects/locale/he/LC_MESSAGES/django.mo b/django/contrib/redirects/locale/he/LC_MESSAGES/django.mo index effbc33efc4c9..5cf696117fdd6 100644 Binary files a/django/contrib/redirects/locale/he/LC_MESSAGES/django.mo and b/django/contrib/redirects/locale/he/LC_MESSAGES/django.mo differ diff --git a/django/contrib/redirects/locale/he/LC_MESSAGES/django.po b/django/contrib/redirects/locale/he/LC_MESSAGES/django.po index 4d32ce1e8d9bb..6b5e0fba288a3 100644 --- a/django/contrib/redirects/locale/he/LC_MESSAGES/django.po +++ b/django/contrib/redirects/locale/he/LC_MESSAGES/django.po @@ -15,7 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: he\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % " +"1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n" msgid "Redirects" msgstr "הפניות" diff --git a/django/contrib/redirects/locale/ka/LC_MESSAGES/django.mo b/django/contrib/redirects/locale/ka/LC_MESSAGES/django.mo index 475955eefe145..f9b02abd4afa2 100644 Binary files a/django/contrib/redirects/locale/ka/LC_MESSAGES/django.mo and b/django/contrib/redirects/locale/ka/LC_MESSAGES/django.mo differ diff --git a/django/contrib/redirects/locale/ka/LC_MESSAGES/django.po b/django/contrib/redirects/locale/ka/LC_MESSAGES/django.po index a168d070f0e47..bf76c7a2c05a9 100644 --- a/django/contrib/redirects/locale/ka/LC_MESSAGES/django.po +++ b/django/contrib/redirects/locale/ka/LC_MESSAGES/django.po @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ka\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" msgid "Redirects" msgstr "გადამისამართებები" diff --git a/django/contrib/redirects/locale/kk/LC_MESSAGES/django.mo b/django/contrib/redirects/locale/kk/LC_MESSAGES/django.mo index fb9d36f3abb89..dbe7765429bd4 100644 Binary files a/django/contrib/redirects/locale/kk/LC_MESSAGES/django.mo and b/django/contrib/redirects/locale/kk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/redirects/locale/kk/LC_MESSAGES/django.po b/django/contrib/redirects/locale/kk/LC_MESSAGES/django.po index 91d2a9c4aea16..8c6af97d57060 100644 --- a/django/contrib/redirects/locale/kk/LC_MESSAGES/django.po +++ b/django/contrib/redirects/locale/kk/LC_MESSAGES/django.po @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kk\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" msgid "Redirects" msgstr "Қайта бағыттаулар" diff --git a/django/contrib/redirects/locale/kn/LC_MESSAGES/django.mo b/django/contrib/redirects/locale/kn/LC_MESSAGES/django.mo index a497d71c4134e..da36d536174a2 100644 Binary files a/django/contrib/redirects/locale/kn/LC_MESSAGES/django.mo and b/django/contrib/redirects/locale/kn/LC_MESSAGES/django.mo differ diff --git a/django/contrib/redirects/locale/kn/LC_MESSAGES/django.po b/django/contrib/redirects/locale/kn/LC_MESSAGES/django.po index 214edc4e54f8d..40609952cd1d4 100644 --- a/django/contrib/redirects/locale/kn/LC_MESSAGES/django.po +++ b/django/contrib/redirects/locale/kn/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Redirects" msgstr "" diff --git a/django/contrib/redirects/locale/lt/LC_MESSAGES/django.mo b/django/contrib/redirects/locale/lt/LC_MESSAGES/django.mo index 294ce4c532e3d..d2a24806dd1df 100644 Binary files a/django/contrib/redirects/locale/lt/LC_MESSAGES/django.mo and b/django/contrib/redirects/locale/lt/LC_MESSAGES/django.mo differ diff --git a/django/contrib/redirects/locale/lt/LC_MESSAGES/django.po b/django/contrib/redirects/locale/lt/LC_MESSAGES/django.po index 2d79101c35d7a..811c24887839e 100644 --- a/django/contrib/redirects/locale/lt/LC_MESSAGES/django.po +++ b/django/contrib/redirects/locale/lt/LC_MESSAGES/django.po @@ -16,8 +16,9 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: lt\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n" -"%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < " +"11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? " +"1 : n % 1 != 0 ? 2: 3);\n" msgid "Redirects" msgstr "Nukreipimai" diff --git a/django/contrib/redirects/locale/sk/LC_MESSAGES/django.mo b/django/contrib/redirects/locale/sk/LC_MESSAGES/django.mo index 92ad19f45af40..a562e68080a4d 100644 Binary files a/django/contrib/redirects/locale/sk/LC_MESSAGES/django.mo and b/django/contrib/redirects/locale/sk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/redirects/locale/sk/LC_MESSAGES/django.po b/django/contrib/redirects/locale/sk/LC_MESSAGES/django.po index 0517b05e6107c..f657303dc1f97 100644 --- a/django/contrib/redirects/locale/sk/LC_MESSAGES/django.po +++ b/django/contrib/redirects/locale/sk/LC_MESSAGES/django.po @@ -16,7 +16,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sk\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n " +">= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" msgid "Redirects" msgstr "Presmerovania" diff --git a/django/contrib/redirects/locale/uk/LC_MESSAGES/django.mo b/django/contrib/redirects/locale/uk/LC_MESSAGES/django.mo index ca77d244d8eed..dffe8adf857ec 100644 Binary files a/django/contrib/redirects/locale/uk/LC_MESSAGES/django.mo and b/django/contrib/redirects/locale/uk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/redirects/locale/uk/LC_MESSAGES/django.po b/django/contrib/redirects/locale/uk/LC_MESSAGES/django.po index 8851897584862..bbb1653db8547 100644 --- a/django/contrib/redirects/locale/uk/LC_MESSAGES/django.po +++ b/django/contrib/redirects/locale/uk/LC_MESSAGES/django.po @@ -18,8 +18,10 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != " +"11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % " +"100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || " +"(n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" msgid "Redirects" msgstr "Перенаправлення" diff --git a/django/contrib/sessions/locale/en/LC_MESSAGES/django.po b/django/contrib/sessions/locale/en/LC_MESSAGES/django.po index 2ce18723404f0..3e2771486a2da 100644 --- a/django/contrib/sessions/locale/en/LC_MESSAGES/django.po +++ b/django/contrib/sessions/locale/en/LC_MESSAGES/django.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: Django\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-01-17 11:07+0100\n" +"POT-Creation-Date: 2020-01-05 23:23-0500\n" "PO-Revision-Date: 2010-05-13 15:35+0200\n" "Last-Translator: Django team\n" "Language-Team: English \n" @@ -12,27 +12,22 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: contrib/sessions/apps.py:8 msgid "Sessions" msgstr "" -#: contrib/sessions/models.py:44 msgid "session key" msgstr "" -#: contrib/sessions/models.py:46 msgid "session data" msgstr "" -#: contrib/sessions/models.py:47 msgid "expire date" msgstr "" -#: contrib/sessions/models.py:52 msgid "session" msgstr "" -#: contrib/sessions/models.py:53 msgid "sessions" msgstr "" diff --git a/django/contrib/sessions/locale/fa/LC_MESSAGES/django.mo b/django/contrib/sessions/locale/fa/LC_MESSAGES/django.mo index c2fb6622b418c..7313c7240a655 100644 Binary files a/django/contrib/sessions/locale/fa/LC_MESSAGES/django.mo and b/django/contrib/sessions/locale/fa/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sessions/locale/fa/LC_MESSAGES/django.po b/django/contrib/sessions/locale/fa/LC_MESSAGES/django.po index 5e53fab5c6229..276d2de3c64de 100644 --- a/django/contrib/sessions/locale/fa/LC_MESSAGES/django.po +++ b/django/contrib/sessions/locale/fa/LC_MESSAGES/django.po @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fa\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Sessions" msgstr "نشست‌ها" diff --git a/django/contrib/sessions/locale/he/LC_MESSAGES/django.mo b/django/contrib/sessions/locale/he/LC_MESSAGES/django.mo index 1cce90494d9b2..002850414f8e7 100644 Binary files a/django/contrib/sessions/locale/he/LC_MESSAGES/django.mo and b/django/contrib/sessions/locale/he/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sessions/locale/he/LC_MESSAGES/django.po b/django/contrib/sessions/locale/he/LC_MESSAGES/django.po index 85206d42b6c95..e8bd93468bee8 100644 --- a/django/contrib/sessions/locale/he/LC_MESSAGES/django.po +++ b/django/contrib/sessions/locale/he/LC_MESSAGES/django.po @@ -15,7 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: he\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % " +"1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n" msgid "Sessions" msgstr "התחברויות" diff --git a/django/contrib/sessions/locale/ka/LC_MESSAGES/django.mo b/django/contrib/sessions/locale/ka/LC_MESSAGES/django.mo index be4e5d87e082f..3fa111db93303 100644 Binary files a/django/contrib/sessions/locale/ka/LC_MESSAGES/django.mo and b/django/contrib/sessions/locale/ka/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sessions/locale/ka/LC_MESSAGES/django.po b/django/contrib/sessions/locale/ka/LC_MESSAGES/django.po index b42fbf1b368d7..bcdcb5f802f30 100644 --- a/django/contrib/sessions/locale/ka/LC_MESSAGES/django.po +++ b/django/contrib/sessions/locale/ka/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ka\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" msgid "Sessions" msgstr "" diff --git a/django/contrib/sessions/locale/kk/LC_MESSAGES/django.mo b/django/contrib/sessions/locale/kk/LC_MESSAGES/django.mo index f3b0c1b2389c3..3b8262aa03063 100644 Binary files a/django/contrib/sessions/locale/kk/LC_MESSAGES/django.mo and b/django/contrib/sessions/locale/kk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sessions/locale/kk/LC_MESSAGES/django.po b/django/contrib/sessions/locale/kk/LC_MESSAGES/django.po index 9fd740b9b0f9b..5777dc2621d9d 100644 --- a/django/contrib/sessions/locale/kk/LC_MESSAGES/django.po +++ b/django/contrib/sessions/locale/kk/LC_MESSAGES/django.po @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kk\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" msgid "Sessions" msgstr "Сессиялар" diff --git a/django/contrib/sessions/locale/kn/LC_MESSAGES/django.mo b/django/contrib/sessions/locale/kn/LC_MESSAGES/django.mo index 1240807f06b7d..f818c57f1fa12 100644 Binary files a/django/contrib/sessions/locale/kn/LC_MESSAGES/django.mo and b/django/contrib/sessions/locale/kn/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sessions/locale/kn/LC_MESSAGES/django.po b/django/contrib/sessions/locale/kn/LC_MESSAGES/django.po index cf9e7bf4aa69b..7f369494c17a3 100644 --- a/django/contrib/sessions/locale/kn/LC_MESSAGES/django.po +++ b/django/contrib/sessions/locale/kn/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Sessions" msgstr "" diff --git a/django/contrib/sessions/locale/lt/LC_MESSAGES/django.mo b/django/contrib/sessions/locale/lt/LC_MESSAGES/django.mo index bfd37fbd0e5a6..f365ad36b2312 100644 Binary files a/django/contrib/sessions/locale/lt/LC_MESSAGES/django.mo and b/django/contrib/sessions/locale/lt/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sessions/locale/lt/LC_MESSAGES/django.po b/django/contrib/sessions/locale/lt/LC_MESSAGES/django.po index 5307182d5621e..0051e3000a24a 100644 --- a/django/contrib/sessions/locale/lt/LC_MESSAGES/django.po +++ b/django/contrib/sessions/locale/lt/LC_MESSAGES/django.po @@ -16,8 +16,9 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: lt\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n" -"%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < " +"11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? " +"1 : n % 1 != 0 ? 2: 3);\n" msgid "Sessions" msgstr "Sesijos" diff --git a/django/contrib/sessions/locale/sk/LC_MESSAGES/django.mo b/django/contrib/sessions/locale/sk/LC_MESSAGES/django.mo index 675f761319080..681667a41400b 100644 Binary files a/django/contrib/sessions/locale/sk/LC_MESSAGES/django.mo and b/django/contrib/sessions/locale/sk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sessions/locale/sk/LC_MESSAGES/django.po b/django/contrib/sessions/locale/sk/LC_MESSAGES/django.po index 84c591aad37db..ca01c84e68c75 100644 --- a/django/contrib/sessions/locale/sk/LC_MESSAGES/django.po +++ b/django/contrib/sessions/locale/sk/LC_MESSAGES/django.po @@ -15,7 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sk\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n " +">= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" msgid "Sessions" msgstr "Relácie" diff --git a/django/contrib/sessions/locale/uk/LC_MESSAGES/django.mo b/django/contrib/sessions/locale/uk/LC_MESSAGES/django.mo index a2def308b9fd1..839c316b0ec12 100644 Binary files a/django/contrib/sessions/locale/uk/LC_MESSAGES/django.mo and b/django/contrib/sessions/locale/uk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sessions/locale/uk/LC_MESSAGES/django.po b/django/contrib/sessions/locale/uk/LC_MESSAGES/django.po index 6a5aef7b40c45..befabf0653993 100644 --- a/django/contrib/sessions/locale/uk/LC_MESSAGES/django.po +++ b/django/contrib/sessions/locale/uk/LC_MESSAGES/django.po @@ -16,8 +16,10 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != " +"11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % " +"100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || " +"(n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" msgid "Sessions" msgstr "Сесії" diff --git a/django/contrib/sites/locale/en/LC_MESSAGES/django.po b/django/contrib/sites/locale/en/LC_MESSAGES/django.po index 3b1884c4af547..c4d19ce06ff2d 100644 --- a/django/contrib/sites/locale/en/LC_MESSAGES/django.po +++ b/django/contrib/sites/locale/en/LC_MESSAGES/django.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: Django\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-01-17 11:07+0100\n" +"POT-Creation-Date: 2020-01-06 01:01-0500\n" "PO-Revision-Date: 2010-05-13 15:35+0200\n" "Last-Translator: Django team\n" "Language-Team: English \n" @@ -12,27 +12,22 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: contrib/sites/apps.py:11 msgid "Sites" msgstr "" -#: contrib/sites/models.py:30 msgid "The domain name cannot contain any spaces or tabs." msgstr "" -#: contrib/sites/models.py:81 msgid "domain name" msgstr "" -#: contrib/sites/models.py:83 msgid "display name" msgstr "" -#: contrib/sites/models.py:88 msgid "site" msgstr "" -#: contrib/sites/models.py:89 msgid "sites" msgstr "" diff --git a/django/contrib/sites/locale/fa/LC_MESSAGES/django.mo b/django/contrib/sites/locale/fa/LC_MESSAGES/django.mo index 7bc004f3b11eb..bddae167b59e4 100644 Binary files a/django/contrib/sites/locale/fa/LC_MESSAGES/django.mo and b/django/contrib/sites/locale/fa/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sites/locale/fa/LC_MESSAGES/django.po b/django/contrib/sites/locale/fa/LC_MESSAGES/django.po index 4aab2231eec52..ba91492439ed2 100644 --- a/django/contrib/sites/locale/fa/LC_MESSAGES/django.po +++ b/django/contrib/sites/locale/fa/LC_MESSAGES/django.po @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fa\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Sites" msgstr "وب‌گاه‌ها" diff --git a/django/contrib/sites/locale/he/LC_MESSAGES/django.mo b/django/contrib/sites/locale/he/LC_MESSAGES/django.mo index 3cdf5dc68c031..8d5cb380d75ed 100644 Binary files a/django/contrib/sites/locale/he/LC_MESSAGES/django.mo and b/django/contrib/sites/locale/he/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sites/locale/he/LC_MESSAGES/django.po b/django/contrib/sites/locale/he/LC_MESSAGES/django.po index 6bc277defc9a5..62de695f3dc9e 100644 --- a/django/contrib/sites/locale/he/LC_MESSAGES/django.po +++ b/django/contrib/sites/locale/he/LC_MESSAGES/django.po @@ -15,7 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: he\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % " +"1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n" msgid "Sites" msgstr "אתרים" diff --git a/django/contrib/sites/locale/ka/LC_MESSAGES/django.mo b/django/contrib/sites/locale/ka/LC_MESSAGES/django.mo index c7eb889d0737c..a08a7a8cf4a89 100644 Binary files a/django/contrib/sites/locale/ka/LC_MESSAGES/django.mo and b/django/contrib/sites/locale/ka/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sites/locale/ka/LC_MESSAGES/django.po b/django/contrib/sites/locale/ka/LC_MESSAGES/django.po index 4a2ac8673a841..5d05019a821e9 100644 --- a/django/contrib/sites/locale/ka/LC_MESSAGES/django.po +++ b/django/contrib/sites/locale/ka/LC_MESSAGES/django.po @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ka\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" msgid "Sites" msgstr "საიტები" diff --git a/django/contrib/sites/locale/kk/LC_MESSAGES/django.mo b/django/contrib/sites/locale/kk/LC_MESSAGES/django.mo index edfaf6dfd1d97..433c0828298d1 100644 Binary files a/django/contrib/sites/locale/kk/LC_MESSAGES/django.mo and b/django/contrib/sites/locale/kk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sites/locale/kk/LC_MESSAGES/django.po b/django/contrib/sites/locale/kk/LC_MESSAGES/django.po index b986095fbc04b..23c0f0024abea 100644 --- a/django/contrib/sites/locale/kk/LC_MESSAGES/django.po +++ b/django/contrib/sites/locale/kk/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kk\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" msgid "Sites" msgstr "Сайттар" diff --git a/django/contrib/sites/locale/kn/LC_MESSAGES/django.mo b/django/contrib/sites/locale/kn/LC_MESSAGES/django.mo index 234ed90f9d04b..9607c2d4b72e7 100644 Binary files a/django/contrib/sites/locale/kn/LC_MESSAGES/django.mo and b/django/contrib/sites/locale/kn/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sites/locale/kn/LC_MESSAGES/django.po b/django/contrib/sites/locale/kn/LC_MESSAGES/django.po index 1f9b3b984f905..2d81d8f5a042e 100644 --- a/django/contrib/sites/locale/kn/LC_MESSAGES/django.po +++ b/django/contrib/sites/locale/kn/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Sites" msgstr "" diff --git a/django/contrib/sites/locale/lt/LC_MESSAGES/django.mo b/django/contrib/sites/locale/lt/LC_MESSAGES/django.mo index 8cdaf71ebfd0f..9d42bf0f865b9 100644 Binary files a/django/contrib/sites/locale/lt/LC_MESSAGES/django.mo and b/django/contrib/sites/locale/lt/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sites/locale/lt/LC_MESSAGES/django.po b/django/contrib/sites/locale/lt/LC_MESSAGES/django.po index f919c3b19c946..afcb5ac6a9b7b 100644 --- a/django/contrib/sites/locale/lt/LC_MESSAGES/django.po +++ b/django/contrib/sites/locale/lt/LC_MESSAGES/django.po @@ -18,8 +18,9 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: lt\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n" -"%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < " +"11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? " +"1 : n % 1 != 0 ? 2: 3);\n" msgid "Sites" msgstr "Tinklalapiai" diff --git a/django/contrib/sites/locale/sk/LC_MESSAGES/django.mo b/django/contrib/sites/locale/sk/LC_MESSAGES/django.mo index fbcf69a0d4814..2706b4717b455 100644 Binary files a/django/contrib/sites/locale/sk/LC_MESSAGES/django.mo and b/django/contrib/sites/locale/sk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sites/locale/sk/LC_MESSAGES/django.po b/django/contrib/sites/locale/sk/LC_MESSAGES/django.po index 9b3f3182fbda5..0f48ec98a1534 100644 --- a/django/contrib/sites/locale/sk/LC_MESSAGES/django.po +++ b/django/contrib/sites/locale/sk/LC_MESSAGES/django.po @@ -16,7 +16,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sk\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n " +">= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" msgid "Sites" msgstr "Sídla" diff --git a/django/contrib/sites/locale/uk/LC_MESSAGES/django.mo b/django/contrib/sites/locale/uk/LC_MESSAGES/django.mo index 8ffb1b948f77e..7ae4795b761de 100644 Binary files a/django/contrib/sites/locale/uk/LC_MESSAGES/django.mo and b/django/contrib/sites/locale/uk/LC_MESSAGES/django.mo differ diff --git a/django/contrib/sites/locale/uk/LC_MESSAGES/django.po b/django/contrib/sites/locale/uk/LC_MESSAGES/django.po index 232940a7a5aa4..f98454c9d4cbb 100644 --- a/django/contrib/sites/locale/uk/LC_MESSAGES/django.po +++ b/django/contrib/sites/locale/uk/LC_MESSAGES/django.po @@ -17,8 +17,10 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != " +"11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % " +"100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || " +"(n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" msgid "Sites" msgstr "Сайти" diff --git a/django/core/checks/translation.py b/django/core/checks/translation.py index 8457a6b89d862..2790a4c253364 100644 --- a/django/core/checks/translation.py +++ b/django/core/checks/translation.py @@ -1,8 +1,13 @@ +import re +import warnings + from django.conf import settings -from django.utils.translation import get_supported_language_variant -from django.utils.translation.trans_real import language_code_re +from django.utils.translation.trans_real import ( + activate, deactivate, get_language, get_supported_language_variant, + language_code_re, reset_translations_cache, +) -from . import Error, Tags, register +from . import Error, Tags, Warning, register E001 = Error( 'You have provided an invalid value for the LANGUAGE_CODE setting: {!r}.', @@ -25,6 +30,11 @@ id='translation.E004', ) +W005 = Warning( + 'Inconsistent plural forms across catalogs for language {!r}.', + id='translation.W005', +) + @register(Tags.translation) def check_setting_language_code(app_configs, **kwargs): @@ -60,5 +70,36 @@ def check_language_settings_consistent(app_configs, **kwargs): get_supported_language_variant(settings.LANGUAGE_CODE) except LookupError: return [E004] - else: - return [] + return [] + + +@register(Tags.translation) +def check_plural_forms_consistency(app_configs, **kwargs): + """ + Warns if plural forms are not consistent for languages in the LANGUAGES setting. + """ + if settings.USE_I18N and settings.PLURAL_FORMS_CONSISTENCY: + with warnings.catch_warnings(record=True) as ws: + warnings.simplefilter("always") + saved_locale = get_language() + try: + warns = [] + deactivate() + reset_translations_cache() + if settings.LANGUAGES: + for lang, _ in settings.LANGUAGES: + activate(lang) + else: + activate(settings.LANGUAGE_CODE) + if len(ws) > 0: + for warn in ws: + m = re.search(r'(?<=Locale: )(.*)(?=\n)', str(warn.message)) + if m: + tag = m.group(0) + warns.append(Warning(W005.msg.format(tag), id=W005.id)) + return warns + finally: + reset_translations_cache() + if saved_locale: + activate(saved_locale) + return [] diff --git a/django/core/management/commands/makemessages.py b/django/core/management/commands/makemessages.py index 1b6bacc02e66b..a52c7afc0e2c9 100644 --- a/django/core/management/commands/makemessages.py +++ b/django/core/management/commands/makemessages.py @@ -19,6 +19,7 @@ from django.utils.regex_helper import _lazy_re_compile from django.utils.text import get_text_list from django.utils.translation import templatize +from django.utils.translation.plural_forms import PluralForms plural_forms_re = _lazy_re_compile(r'^(?P"Plural-Forms.+?\\n")\s*$', re.MULTILINE | re.DOTALL) STATUS_OK = 0 @@ -205,12 +206,14 @@ class Command(BaseCommand): translatable_file_class = TranslatableFile build_file_class = BuildFile + plural_forms_class = PluralForms requires_system_checks = False msgmerge_options = ['-q', '--previous'] msguniq_options = ['--to-code=utf-8'] msgattrib_options = ['--no-obsolete'] + msgcat_options = ['--use-first', '--to-code=UTF-8'] xgettext_options = ['--from-code=UTF-8', '--add-comments=Translators'] def add_arguments(self, parser): @@ -279,6 +282,21 @@ def add_arguments(self, parser): '--keep-pot', action='store_true', help="Keep .pot file after making messages. Useful when debugging.", ) + parser.add_argument( + '--collect-bundled', '-cb', + choices=('default-path', 'all-bundled'), nargs='?', + const='default-path', + help="Collects Django's bundled message files into LOCALE_ROOT." + ) + parser.add_argument( + '--update-plural-forms', '-upf', action='store', nargs='?', + const='interactive', + help=( + "Checks or aligns all project or application message files' " + "plural forms for the locale(s) with the main plural forms " + "in a domain (see --domain)." + ) + ) def handle(self, *args, **options): locale = options['locale'] @@ -288,6 +306,8 @@ def handle(self, *args, **options): process_all = options['all'] extensions = options['extensions'] self.symlinks = options['symlinks'] + self.collect_bundled = options['collect_bundled'] + self.update_pfs = options['update_plural_forms'] ignore_patterns = options['ignore_patterns'] if options['use_default_ignore_patterns']: @@ -299,11 +319,13 @@ def handle(self, *args, **options): self.msgmerge_options = self.msgmerge_options[:] + ['--no-wrap'] self.msguniq_options = self.msguniq_options[:] + ['--no-wrap'] self.msgattrib_options = self.msgattrib_options[:] + ['--no-wrap'] + self.msgcat_options = self.msgcat_options[:] + ['--no-wrap'] self.xgettext_options = self.xgettext_options[:] + ['--no-wrap'] if options['no_location']: self.msgmerge_options = self.msgmerge_options[:] + ['--no-location'] self.msguniq_options = self.msguniq_options[:] + ['--no-location'] self.msgattrib_options = self.msgattrib_options[:] + ['--no-location'] + self.msgcat_options = self.msgcat_options[:] + ['--no-location'] self.xgettext_options = self.xgettext_options[:] + ['--no-location'] if options['add_location']: if self.gettext_version < (0, 19): @@ -315,6 +337,7 @@ def handle(self, *args, **options): self.msgmerge_options = self.msgmerge_options[:] + [arg_add_location] self.msguniq_options = self.msguniq_options[:] + [arg_add_location] self.msgattrib_options = self.msgattrib_options[:] + [arg_add_location] + self.msgcat_options = self.msgcat_options[:] + [arg_add_location] self.xgettext_options = self.xgettext_options[:] + [arg_add_location] self.no_obsolete = options['no_obsolete'] @@ -335,6 +358,20 @@ def handle(self, *args, **options): % (os.path.basename(sys.argv[0]), sys.argv[1]) ) + if (self.collect_bundled) and self.settings_available and not hasattr(settings, 'LOCALE_ROOT'): + raise CommandError( + "currently makemessages only supports collecting bundled message files " + "with the LOCALE_ROOT setting defined." + ) + + if self.update_pfs and self.update_pfs not in ['interactive', 'copy']: + update_pfs_regex = r'(\d,)*\d' + if not re.fullmatch(update_pfs_regex, self.update_pfs): + raise CommandError( + "currently the --update-plural-forms option only supports " + "'interactive', 'copy' or comma-separated digits as a parameter." + ) + if self.verbosity > 1: self.stdout.write( 'examining files with the extensions: %s\n' @@ -346,6 +383,7 @@ def handle(self, *args, **options): self.default_locale_path = None if os.path.isdir(os.path.join('conf', 'locale')): self.locale_paths = [os.path.abspath(os.path.join('conf', 'locale'))] + self.locale_paths.extend(self.contrib_apps_locale_dirs) self.default_locale_path = self.locale_paths[0] self.invoked_for_django = True else: @@ -355,16 +393,14 @@ def handle(self, *args, **options): if os.path.isdir('locale'): self.locale_paths.append(os.path.abspath('locale')) if self.locale_paths: - self.default_locale_path = self.locale_paths[0] + if self.settings_available and hasattr(settings, 'LOCALE_ROOT'): + self.default_locale_path = settings.LOCALE_ROOT + else: + self.default_locale_path = self.locale_paths[0] os.makedirs(self.default_locale_path, exist_ok=True) # Build locale list - looks_like_locale = re.compile(r'[a-z]{2}') - locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % self.default_locale_path)) - all_locales = [ - lang_code for lang_code in map(os.path.basename, locale_dirs) - if looks_like_locale.match(lang_code) - ] + all_locales = self.locale_list_from_path(self.default_locale_path) # Account for excluded locales if process_all: @@ -376,17 +412,46 @@ def handle(self, *args, **options): if locales: check_programs('msguniq', 'msgmerge', 'msgattrib') + if self.collect_bundled: + check_programs('msgcat') + + if self.update_pfs: + check_programs('msgfmt') + check_programs('xgettext') try: potfiles = self.build_potfiles() + if self.collect_bundled: + main_po_ph = os.path.join( + self.django_dir, 'conf', 'locale', '%s', 'LC_MESSAGES', 'django.po' + ) + locales_with_catalogs = [ + lang_code for lang_code in + self.locale_list_from_path(self.django_conf_locale_dir) + if os.path.exists(main_po_ph % lang_code) + ] + locales_to_collect = ( + set(locales_with_catalogs + self.locale_list_from_path(settings.LOCALE_ROOT)) + if self.collect_bundled == 'all-bundled' else locales + ) + for locale in locales_to_collect: + if self.verbosity > 0: + self.stdout.write( + "collecting bundled messages for locale %s\n" % locale + ) + self.collect_bundled_messages(locale) + # Build po files for each selected locale for locale in locales: if self.verbosity > 0: self.stdout.write("processing locale %s\n" % locale) - for potfile in potfiles: - self.write_po_file(potfile, locale) + if self.update_pfs: + self.update_plural_forms(locale) + else: + for potfile in potfiles: + self.write_po_file(potfile, locale) finally: if not self.keep_pot: self.remove_potfiles() @@ -415,11 +480,56 @@ def settings_available(self): return False return True + @cached_property + def django_dir(self): + return os.path.normpath(os.path.join(os.path.dirname(django.__file__))) + + @cached_property + def django_conf_locale_dir(self): + return os.path.join(self.django_dir, 'conf', 'locale') + + @cached_property + def contrib_apps_locale_dirs(self): + return glob.glob(self.django_dir + '/contrib/*/locale') + + def locale_list_from_path(self, path): + looks_like_locale = re.compile(r'[a-z]{2}') + locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % path)) + return [ + lang_code for lang_code in map(os.path.basename, locale_dirs) + if looks_like_locale.match(lang_code) + ] + + def get_main_po(self, locale, domain): + """ + Returns a string with the path to main po for the locale and domain if + exists. If it doesn't exists for a language variant, return the main + language main po. + """ + if self.settings_available and hasattr(settings, 'LOCALE_ROOT'): + main_po_dir = os.path.join(settings.LOCALE_ROOT, '%s', 'LC_MESSAGES') + else: + main_po_dir = os.path.join( + self.django_dir, 'conf', 'locale', '%s', 'LC_MESSAGES' + ) + main_po_ph = os.path.join(main_po_dir, '%s.po') + if os.path.exists(main_po_ph % (locale, domain)): + return main_po_ph % (locale, domain) + else: + if "_" in locale: + # Use the main language instead of the variant + lang_locale = locale.split("_")[0] + if os.path.exists(main_po_ph % (lang_locale, domain)): + return main_po_ph % (lang_locale, domain) + return None + def build_potfiles(self): """ Build pot files and apply msguniq to them. """ file_list = self.find_files(".") + if self.collect_bundled: + file_list.extend(self.find_files(self.django_dir)) self.remove_potfiles() self.process_files(file_list) potfiles = [] @@ -475,6 +585,10 @@ def find_files(self, root): else: locale_dir = None for path in self.locale_paths: + if self.collect_bundled: + if self.django_dir < os.path.abspath(path): + locale_dir = settings.LOCALE_ROOT + break if os.path.abspath(dirpath).startswith(os.path.dirname(path)): locale_dir = path break @@ -630,21 +744,98 @@ def write_po_file(self, potfile, locale): elif self.verbosity > 0: self.stdout.write(errors) - def copy_plural_forms(self, msgs, locale): + def collect_bundled_messages(self, locale): + """ + Extract all the literals and collects all the translation strings in + message files bundled with Django, for a `locale` and creates or + updates the corresponding message file in LOCALE_ROOT. + + Use msgcat GNU gettext utility. + """ + django_main_po = [ + os.path.join(self.django_dir, 'conf', 'locale', locale, + 'LC_MESSAGES', '%s.po') + ] + django_contrib_pos = [ + os.path.join(dirname, locale, 'LC_MESSAGES', '%s.po') + for dirname in self.contrib_apps_locale_dirs + ] + + django_pos = [ + po % self.domain for po in django_main_po + django_contrib_pos + if os.path.exists(po % self.domain) + ] + if len(django_pos) > 0: + args = ['msgcat'] + self.msgcat_options + django_pos + msgs, errors, status = popen_wrapper(args) + if errors: + if status != STATUS_OK: + raise CommandError( + "errors happened while running msgcat\n%s" % errors) + elif self.verbosity > 0: + self.stdout.write(errors) + msgs = normalize_eols(msgs) + if not msgs: + # msgcat will not output the header if there is only a null + # msgid in the file, keep the header for the plural forms + with open(django_pos[0], encoding='utf-8') as fp: + msgs = fp.read() + else: + # No catalogs were bundled for the locale (adding a new locale) + potfile = os.path.join(settings.LOCALE_ROOT, '%s.pot' % self.domain) + with open(potfile, encoding='utf-8') as fp: + msgs = fp.read() + + translators_re = r'(?<=# Translators:\n)(.*?)(?=msgid)' + m = re.search(translators_re, msgs, flags=re.DOTALL) + if m: + new_translators_strs = [ + "# Contributors to this catalog are listed in:", + ] + new_translators_strs += [ + "# " + django_po for django_po in django_pos + ] + new_translators_strs = '\n'.join(new_translators_strs) + '\n' + i, j = m.span() + msgs = msgs[:i] + new_translators_strs + msgs[j:] + + basedir = os.path.join(settings.LOCALE_ROOT, locale, 'LC_MESSAGES') + os.makedirs(basedir, exist_ok=True) + pofile = os.path.join(basedir, '%s.po' % self.domain) + + if os.path.exists(pofile): + tempfile = NamedTemporaryFile(mode='w+b') + tempfile.file.write(bytes(msgs, encoding='utf-8')) + tempfile.file.flush() + args = ['msgcat'] + self.msgcat_options + [pofile, tempfile.name] + msgs, errors, status = popen_wrapper(args) + if errors: + if status != STATUS_OK: + raise CommandError( + "errors happened while running msgcat\n%s" % errors) + elif self.verbosity > 0: + self.stdout.write(errors) + msgs = normalize_eols(msgs) + tempfile.close() + + with open(pofile, 'w', encoding='utf-8') as fp: + fp.write(msgs) + + def copy_plural_forms(self, msgs, locale, update=False): """ - Copy plural forms header contents from a Django catalog of locale to + Copy plural forms header contents from a main catalog of a locale to the msgs string, inserting it at the right place. msgs should be the - contents of a newly created .po file. + contents of a newly created .po file or the contents of an already + created .po if update is True. """ - django_dir = os.path.normpath(os.path.join(os.path.dirname(django.__file__))) if self.domain == 'djangojs': domains = ('djangojs', 'django') else: domains = ('django',) for domain in domains: - django_po = os.path.join(django_dir, 'conf', 'locale', locale, 'LC_MESSAGES', '%s.po' % domain) - if os.path.exists(django_po): - with open(django_po, encoding='utf-8') as fp: + main_po = self.get_main_po(locale, domain) or self.get_main_po(locale, 'django') + if main_po: + with open(main_po, encoding='utf-8') as fp: m = plural_forms_re.search(fp.read()) if m: plural_form_line = m.group('value') @@ -652,11 +843,249 @@ def copy_plural_forms(self, msgs, locale): self.stdout.write("copying plural forms: %s\n" % plural_form_line) lines = [] found = False - for line in msgs.splitlines(): - if not found and (not line or plural_forms_re.search(line)): - line = plural_form_line - found = True - lines.append(line) - msgs = '\n'.join(lines) - break + if not update: + for line in msgs.splitlines(): + if not found and (not line or plural_forms_re.search(line)): + line = plural_form_line + '\n' + found = True + lines.append(line) + msgs = '\n'.join(lines) + break + else: + o = plural_forms_re.search(msgs) + if o: + plural_form_to_update = o.group('value') + msgs = msgs.replace( + plural_form_to_update, plural_form_line) + return msgs + + def update_plural_forms(self, locale): + """ + Examines the user's .po files of a locale for a divergence in the + plural forms with the main forms. If one is found (mismatch) and no + action or form map is given in the argument, prompts the user to map + the main form to the user's form and outputs a compliant .po file. + """ + # For the 'djangojs' domain, fallback to 'django' if not exists + main_po = (self.get_main_po(locale, self.domain) or + self.get_main_po(locale, 'django')) + if not main_po: + raise CommandError( + "unable to find the main .po file for '%s' (or fallback), if " + "you're using settings.LOCALE_ROOT, make sure you have already " + "run `makemessages --collect-base-catalogs --locale=%s`." % + (locale, locale) + ) + + self.check_po_header_validity(main_po) + with open(main_po, encoding='utf-8') as fp: + m = plural_forms_re.search(fp.read()) + if m: + try: + main_plural_forms = self.plural_forms_class(m.group('value')) + except ValueError: + raise CommandError( + 'plural forms in %s seems incomplete or unset - unable to parse.' % main_po + ) + + locale_paths_to_check = set(self.locale_paths) + if self.settings_available and hasattr(settings, 'LOCALE_ROOT'): + locale_paths_to_check = locale_paths_to_check - set([settings.LOCALE_ROOT]) + for locale_path in locale_paths_to_check: + user_po = os.path.join(locale_path, locale, 'LC_MESSAGES', + '%s.po' % self.domain) + if os.path.exists(user_po): + self.check_po_header_validity(user_po) + with open(user_po, encoding='utf-8') as fp: + o = plural_forms_re.search(fp.read()) + if o: + try: + user_plural_forms = self.plural_forms_class(o.group('value')) + except ValueError: + raise CommandError( + 'plural forms in %s seems incomplete or unset - unable to parse.' % user_po + ) + + if user_plural_forms == main_plural_forms: + if self.verbosity > 0: + self.stdout.write( + "Plural forms in %s for %s are compliant " + "with the main forms." % (locale_path, locale) + ) + else: + if self.verbosity > 0: + self.stdout.write( + ":: Aligning plural forms in %s for %s " + "with the main form ::" % (locale_path, locale) + ) + if self.update_pfs == 'interactive': + form_map = [] + overwrite = None # will be set by user input + else: + form_map = [int(d) for d in self.update_pfs.split(",")] + overwrite = 'y' + if main_plural_forms.nplurals < user_plural_forms.nplurals: + if self.verbosity > 0: + self.stdout.write( + "WARNING: Main form plurals are less than " + "user's, trimming will occur." + ) + m_forms = main_plural_forms.forms + u_forms = user_plural_forms.forms + if not form_map: + if self.verbosity > 0: + self.stdout.write("Main Plural Forms:") + for f_number in m_forms: + self.stdout.write( + "%s: %s" % (f_number, m_forms[f_number])) + self.stdout.write("User Plural Forms:") + for f_number in u_forms: + self.stdout.write( + "%s: %s" % (f_number, u_forms[f_number])) + for form_number in m_forms: + input_message = "Main form %s: %s maps to [%s] in User form: " % ( + form_number, m_forms[form_number], + ("|").join(map(str, range(len(u_forms)))) + ) + user_input = int(self.get_user_input(input_message)) + while user_input not in u_forms: + self.stdout.write("Form not available in User catalog.") + user_input = int(self.get_user_input(input_message)) + form_map.append(user_input) + msgs = self.remap_plural_forms(user_po, form_map) + msgs = self.copy_plural_forms('\n'.join(msgs), locale, update=True) + overwrite_msg = "Overwrite user's catalog? [y/n]: " + if not overwrite: + overwrite = self.get_user_input(overwrite_msg) + while overwrite not in ['y', 'yes', 'n', 'no']: + self.stdout.write("Please answer 'y'/'yes' or 'n'/'no'.") + overwrite = self.get_user_input(overwrite_msg) + filename = user_po if overwrite in ['y', 'yes'] else user_po + '.new' + with open(filename, 'w', encoding="utf-8") as fp: + msgs = normalize_eols(msgs) + fp.write(msgs) + if self.verbosity > 0: + self.stdout.write( + "Remapped plural forms have been written to %s." % filename + ) + else: + copy_pf, overwrite = ('y', 'y') if self.update_pfs == 'copy' else (None, None) + copy_pf_msg = ( + "Catalog in %s does not contain plural forms while the main catalog " + "has, copy plural forms from the main one? (no remapping will be " + "done) [y/n]:" % user_po + + ) + if not copy_pf: + copy_pf = self.get_user_input(copy_pf_msg) + while copy_pf not in ['y', 'yes', 'n', 'no']: + self.stdout.write("Please answer 'y'/'yes' or 'n'/'no'.") + copy_pf = self.get_user_input(copy_pf_msg) + overwrite_msg = "Overwrite user's catalog? [y/n]: " + if not overwrite: + overwrite = self.get_user_input(overwrite_msg) + while overwrite not in ['y', 'yes', 'n', 'no']: + self.stdout.write("Please answer 'y'/'yes' or 'n'/'no'.") + overwrite = self.get_user_input(overwrite_msg) + filename = user_po if overwrite in ['y', 'yes'] else user_po + '.new' + with open(user_po, encoding='utf-8') as fp: + msgs = fp.read() + msgs = self.copy_plural_forms(msgs, locale) + msgs = normalize_eols(msgs) + with open(filename, 'w', encoding='utf-8') as fp: + fp.write(msgs) + if self.verbosity > 0: + self.stdout.write( + "Plural forms have been written to %s." % filename + ) + + def remap_plural_forms(self, pofile, form_map): + """ + Performs the remapping of the .po file with the given form map. + """ + with open(pofile, encoding='utf-8') as fp: + msgs = fp.read() + msgs = msgs.splitlines() + groups, groups_msgs, groups_forms, groups_new_msgs = [], [], [], [] + group_start, group_end = None, None + # Find the groups of pluralized msgs in msgs + for i, line in enumerate(msgs): + if line.startswith("msgstr[0]"): + group_start = i + elif line == "" and group_start: + group_end = i + if i == len(msgs) - 1 and group_start: + # Last empty line is stripped by splitlines() + group_end = i + 1 + if group_start and group_end: + groups.append([group_start, group_end]) + group_start, group_end = None, None + # Collect all msgs in groups + for group in groups: + groups_msgs.append(msgs[group[0]:group[1]]) + # Process the msgs in groups + for group_index, group_msgs in enumerate(groups_msgs): + group_forms = {} + for k, msg in enumerate(group_msgs): + m = re.search(r'(?<=msgstr\[)\d(?=\])', msg) + if m: + group_number = int(m.group(0)) + group_forms[group_number] = [msg] + else: + group_forms[group_number].append(msg) + groups_forms.append(group_forms) + + new_msgs = [] + for main_form, user_form in enumerate(form_map): + try: + msgs_to_append = groups_forms[group_index][user_form] + msgs_to_append[0] = "msgstr[%d]" % main_form + msgs_to_append[0][9:] + except KeyError: + raise CommandError( + "The provided form map is not compatible with the main " + "and user plural forms." + ) + new_msgs.extend(msgs_to_append) + groups_new_msgs.append(new_msgs) + # It's needed to go again through msgs because replacing msgs may + # change groups locations and the index + i, group_number = 0, 0 + group_start, group_end = None, None + while i < len(msgs): + line = msgs[i] + if line.startswith("msgstr[0]"): + group_start = i + elif line == "" and group_start: + group_end = i + if i == len(msgs) - 1 and group_start: + group_end = i + 1 + if group_start and group_end: + del msgs[group_start:group_end] + msgs[group_start:group_start] = groups_new_msgs[group_number] + i += len(groups_new_msgs[group_number]) - (group_end - group_start) - 1 + group_number += 1 + group_start, group_end = None, None + i += 1 + return msgs + + def get_user_input(self, message): + """ + Wraps input() to make it testable. + """ + return(input(message)) + + def check_po_header_validity(self, pofile): + """ + Check the validity the header (including plural forms) of a .po file + using msgfmt. + """ + args = ['msgfmt', '--check-header', pofile] + msgs, errors, status = popen_wrapper(args) + if errors: + if status != STATUS_OK: + raise CommandError( + "errors happened while checking po validity\n%s" % errors) + elif self.verbosity > 0: + self.stdout.write(errors) + return True diff --git a/django/utils/translation/plural_forms.py b/django/utils/translation/plural_forms.py new file mode 100644 index 0000000000000..5115fa54d8c7c --- /dev/null +++ b/django/utils/translation/plural_forms.py @@ -0,0 +1,64 @@ +import re + + +class PluralForms: + """ + Represent Plural Forms, constructed from an already msgfmt-validated string. + """ + PLACEHOLDER_STRING = '"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n"' + + def __init__(self, raw_plural_form): + self.full_string = raw_plural_form + self.forms = {} + self.nplurals = None + if self.full_string != self.PLACEHOLDER_STRING: + pf = re.sub(r'"\n"|"|\\n', "", raw_plural_form.strip(), re.MULTILINE) + m = re.search(r'(?<=nplurals=)\d', pf) + o = re.search(r'(?<=plural=)(.*?)(?=;|$)', pf) + if m and o: + self.nplurals = int(m.group(0)) + self.forms_string = o.group(0) + else: + # In some cases, msgfmt may consider valid forms without nplurals + # or plurals (bug) + raise ValueError( + "Unable to find 'nplurals' and/or 'plural' in the init string " + "(%s)." % raw_plural_form + ) + forms = re.split(r'\s?:\s?', self.forms_string) + forms = [self.trim_enclosing_parentheses(f) for f in forms] + if len(forms) == 1 and self.nplurals == 1: + self.forms[0] = forms[0] + elif len(forms) == 1 and self.nplurals == 2: + self.forms[0] = "SINGULAR" + self.forms[1] = forms[0] + else: + for form in forms: + p = re.split(r'\s?\?\s?', form) + if len(p) == 1: + self.forms[int(p[0])] = "OTHER" + else: + self.forms[int(p[1])] = p[0] + + def __eq__(self, other): + if other and self.nplurals == other.nplurals and self.forms == other.forms: + return True + else: + return False + + def trim_enclosing_parentheses(self, form_string): + """ + Trim all-forms enclosing parenthensis (if any). + """ + counter = 0 + for char in form_string: + if char == '(': + counter += 1 + elif char == ')': + counter -= 1 + if counter < 0: + return form_string[:counter] + elif counter > 0: + return form_string[counter:] + else: + return form_string diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index d8526753605b4..f95ae73136465 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -18,6 +18,7 @@ from django.utils.safestring import SafeData, mark_safe from . import to_language, to_locale +from .plural_forms import PluralForms # Translations are cached in a dictionary for every language. # The active translations are stored by threadid to make them thread local. @@ -99,8 +100,15 @@ def __init__(self, language, domain=None, localedirs=None): self._add_local_translations() if self.__language == settings.LANGUAGE_CODE and self.domain == 'django' and self._catalog is None: - # default lang should have at least one translation file available. - raise OSError('No translation files found for default language %s.' % settings.LANGUAGE_CODE) + if not hasattr(settings, 'LOCALE_ROOT'): + # default lang should have at least one translation file available if not using LOCALE_ROOT. + raise OSError('No translation files found for default language %s.' % settings.LANGUAGE_CODE) + else: + msg = ('LOCALE_ROOT has been set and no translation files found for default language %s. ' + 'Make sure that the bundled message files have been collected with ' + '`makemessages --collect-bundled` and/or they have been compiled with ' + '`compilemessages`.' % settings.LANGUAGE_CODE) + warnings.warn(msg, RuntimeWarning) self._add_fallback(localedirs) if self._catalog is None: # No catalogs found for this language, set an empty catalog. @@ -111,23 +119,28 @@ def __repr__(self): def _new_gnu_trans(self, localedir, use_null_fallback=True): """ - Return a mergeable gettext.GNUTranslations instance. + Return an annotated mergeable gettext.GNUTranslations instance. A convenience wrapper. By default gettext uses 'fallback=False'. Using param `use_null_fallback` to avoid confusion with any other - references to 'fallback'. + references to 'fallback'. Also annotates the localedir in the object. """ - return gettext_module.translation( + annotated_gnu_trans = gettext_module.translation( domain=self.domain, localedir=localedir, languages=[self.__locale], fallback=use_null_fallback, ) + annotated_gnu_trans.localedir = localedir + return annotated_gnu_trans def _init_translation_catalog(self): """Create a base catalog using global django translations.""" - settingsfile = sys.modules[settings.__module__].__file__ - localedir = os.path.join(os.path.dirname(settingsfile), 'locale') + if not hasattr(settings, 'LOCALE_ROOT'): + settingsfile = sys.modules[settings.__module__].__file__ + localedir = os.path.join(os.path.dirname(settingsfile), 'locale') + else: + localedir = settings.LOCALE_ROOT translation = self._new_gnu_trans(localedir) self.merge(translation) @@ -142,9 +155,13 @@ def _add_installed_apps_translations(self): "gettext calls at import time.") for app_config in app_configs: localedir = os.path.join(app_config.path, 'locale') - if os.path.exists(localedir): - translation = self._new_gnu_trans(localedir) - self.merge(translation) + if (hasattr(settings, 'LOCALE_ROOT') and + os.path.join('django', 'contrib') in os.path.dirname(localedir)): + continue + else: + if os.path.exists(localedir): + translation = self._new_gnu_trans(localedir) + self.merge(translation) def _add_local_translations(self): """Merge translations defined in LOCALE_PATHS.""" @@ -177,7 +194,32 @@ def merge(self, other): self._info = other._info.copy() self._catalog = other._catalog.copy() else: + if settings.PLURAL_FORMS_CONSISTENCY: + if 'plural-forms' in self.info(): + current_plural_forms = PluralForms(self.info()['plural-forms']) + if 'plural-forms' not in other.info(): + other._info['MISSING PLURAL FORMS'] = "MISSING PLURAL FORMS" + other_plural_forms = None + else: + other_plural_forms = PluralForms(other.info()['plural-forms']) + if current_plural_forms != other_plural_forms: + from pprint import pformat + msg = ( + "\nPosible inconsistencies and undesired behavior detected " + "due to different plural forms in message file.\n" + "Locale: %s\n" + "Unconsistent message file localedir: %s\n" + "Unconsistent message file info: \n%s\n" + "MAIN PLURAL FORM: \n%s\n" + "See https://docs.djangoproject.com/en/dev/topics/i18n/translation/#plural-forms" + % (self.__language, + other.localedir, + pformat(other.info(), indent=4), + pformat(self.info()['plural-forms'], indent=4), ) + ) + warnings.warn(msg, RuntimeWarning) self._catalog.update(other._catalog) + if other._fallback: self.add_fallback(other._fallback) @@ -200,6 +242,15 @@ def translation(language): return _translations[language] +def reset_translations_cache(): + """ + Clears the translations cache dict. + """ + global _translations + if _translations: + _translations.clear() + + def activate(language): """ Fetch the translation object for a given language and install it as the diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index a080b5bdf51c6..8215bcf762763 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -457,6 +457,8 @@ configured: :setting:`OPTIONS ` must be a string but got: ``{value}`` (``{type}``). +.. _translation-checks: + Translation ----------- @@ -472,6 +474,12 @@ The following checks are performed on your translation configuration: :setting:`LANGUAGE_CODE` setting that is not in the :setting:`LANGUAGES` setting. +The following checks are performed on your translations catalogs for the +languages in the :setting:`LANGUAGES` setting: + +* **translation.W005**: Inconsistent plural forms across catalogs for + language ```` (unmerged catalogs). + URLs ---- diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index cbb4a2d8eda44..30e2cac6195af 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -629,7 +629,8 @@ the :ref:`i18n documentation ` for details. This command doesn't require configured settings. However, when settings aren't configured, the command can't ignore the :setting:`MEDIA_ROOT` and -:setting:`STATIC_ROOT` directories or include :setting:`LOCALE_PATHS`. +:setting:`STATIC_ROOT` directories, include :setting:`LOCALE_PATHS` or collect +to :setting:`LOCALE_ROOT`. .. django-admin-option:: --all, -a @@ -727,6 +728,75 @@ Prevents deleting the temporary ``.pot`` files generated before creating the ``.po`` file. This is useful for debugging errors which may prevent the final language files from being created. +.. django-admin-option:: --collect-bundled [{default-path, all-bundled}] -cb + +Pulls out all strings marked for translation in Django for a domain (defaults +to 'django'), collects all catalogs (message files) bundled for the locale(s) +and merges them into the corresponding main po file(s) in +:setting:`LOCALE_ROOT` (required setting). + +Defaults to the locales defined in the default locale path that the command +considers (``default-path``), use ``all-bundled`` for collecting all locales +bundled with Django. + +Specific locale(s) to collect can be set with the ``--locale`` option (or +ignored with ``--exclude``). If the specified locale does not exists, an +untranslated message file will be created for it. + +Example usage:: + + django-admin makemessages --collect-bundled --locale=en --locale=pt + django-admin makemessages --collect-bundled all-bundled --exclude=fr + django-admin makemessages --collect-bundled --domain djangojs + django-admin makemessages -cb -l xx_yy -d djangojs + +.. django-admin-option:: --update-plural-forms [{interactive, copy, form_map}] -cpf + +Checks or aligns all project or application message files' plural forms for the +locale(s) (detected or specified) in a domain (defaults to ``django``) with the +main plural forms (see :ref:`plural-forms`). + +If a divergence is found and the option is set to ``interactive`` (default), +the user will be prompted to map the main plural forms to the ones found in +the message file. With the form map provided, the message file will be +reorganized accordingly and the plural forms will be updated. + +In the case of an increase in the number of plurals, it will fill +those with the previously chosen forms so you avoid having translation results +in the fallback language or the original string - this will produce the same +results as before though you may want to update those later for a +better expression of the language if it corresponds. + +In a decrease of the forms, it will reorganize and trim the exceeding ones. + +When only the equation differs, only reorganization will occur. + +If no plural forms is found in the message file, the user will be prompted to +copy them from the main po file. No remapping will be done, it is assumed that +is already aligned. If it is not the case, use a plural form with the number of +plurals matching the message file's and then re-run the command to perform form +mapping. + +Specific locale(s) to consider can be set with the ``--locale`` option (or +ignored with ``--exclude``). + +Automation can be done only for a specific locale by using the values ``copy`` +for only copying the plural forms or the ``form_map`` in comma-separated digits +- i.e. ``0,1,1,1`` - for perform form mapping. + +Example usage:: + + django-admin makemessages --update-plural-forms + django-admin makemessages --update-plural-forms copy --locale=en + django-admin makemessages -upf 0,1,1,1 -l he -d djangojs + +.. note:: + + Be aware that while this tool can handle most of the regular cases, + it may be an unlikely situation where a linear mapping is not adequate. + It is recommended not to overwrite and check the results if the form + map is not "obvious". + .. seealso:: See :ref:`customizing-makemessages` for instructions on how to customize diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 51bbba35f0fd8..e7c96803301c2 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -1954,6 +1954,57 @@ Example:: Django will look within each of these paths for the ``/LC_MESSAGES`` directories containing the actual translation files. +.. setting:: LOCALE_ROOT + +``LOCALE_ROOT`` +---------------- + +.. versionadded:: 3.1 + +Default: ``None`` + +Absolute filesystem path to the directory that will hold the main po files of +translations. + +Example:: + + LOCALE_ROOT = BASEDIR / 'locale' + +Django will use the files contained in ``/LC_MESSAGES`` under this +directory as the main Django po file of a translation for a domain. + +.. note:: + + Using this setting requires compiled message file(s) for your locale(s), you may use + :option:`django-admin makemessages --collect-bundled` + for collecting the bundled ones with Django (for both ``django`` and ``djangojs`` domains) + and then + :djadmin:`django-admin compilemessages ` to provide them. + +.. note:: + + This setting will make Django not take into account the bundled message files, + is up to the user to run + :option:`django-admin makemessages --collect-bundled` + after an upgrade to collect any new messages. + +.. setting:: PLURAL_FORMS_CONSISTENCY + +``PLURAL_FORMS_CONSISTENCY`` +---------------------------- + +.. versionadded:: 3.1 + +Default: ``False`` + +When ``True``, Django will issue a warning when merging any message file for +translations that contains different plural forms than the main Django po file, +both at +:ref:`system check level ` (``translation.W005``) +and run-time. + +See also :ref:`plural-forms`. + .. setting:: LOGGING ``LOGGING`` @@ -3578,8 +3629,10 @@ Globalization (``i18n``/``l10n``) * :setting:`LANGUAGES` * :setting:`LANGUAGES_BIDI` * :setting:`LOCALE_PATHS` +* :setting:`LOCALE_ROOT` * :setting:`MONTH_DAY_FORMAT` * :setting:`NUMBER_GROUPING` +* :setting:`PLURAL_FORMS_CONSISTENCY` * :setting:`SHORT_DATE_FORMAT` * :setting:`SHORT_DATETIME_FORMAT` * :setting:`THOUSAND_SEPARATOR` diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt index 29e5e223140b6..8eee2631b8ab3 100644 --- a/docs/releases/3.1.txt +++ b/docs/releases/3.1.txt @@ -27,6 +27,41 @@ officially support the latest release of each series. What's new in Django 3.1 ======================== +Plural forms consistency and customization +------------------------------------------ + +Django does not support multiple plural forms in message files. As all +translation files are merged, only the plural forms in the main Django po +file is considered. + +This led to inconsistencies and undesired results in users' translations +mostly when Django updated the plural forms of a locale and the users +did not re-organize their message files to be in line with the new plural +forms (:ref:`more details `). + +To avoid this undesired result, the :setting:`PLURAL_FORMS_CONSISTENCY` +setting has been introduced. + +When enabled (disabled by default), Django will issue a warning when merging +any message file that contains different plural forms than the main Django po +file, both at a +:ref:`system check level ` (``translation.W005``) +and run-time. + +As fixing this issue can be automated in most scenarios, the tool used for +ensuring plural forms consistency in all Django bundled message files is +provided in the +:option:`django-admin makemessages --update-plural-forms`. +option. + +Also, customization of the plural forms was not possible previously without +modifying Django source files. + +The :setting:`LOCALE_ROOT` setting and the +:option:`django-admin makemessages --collect-bundled` +option has been introduced for enabling the feature. + + Minor features -------------- diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist index 6a36a117073f9..9fa8993587fcc 100644 --- a/docs/spelling_wordlist +++ b/docs/spelling_wordlist @@ -728,6 +728,7 @@ unlocalize unlocalized unmaintained unmanaged +unmerged unordered unparseable unparsed diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt index 241dcea660b5f..fcf4e89fd9f7e 100644 --- a/docs/topics/i18n/translation.txt +++ b/docs/topics/i18n/translation.txt @@ -198,10 +198,10 @@ plural translation string and the number of objects. This function is useful when you need your Django application to be localizable to languages where the number and complexity of `plural forms -`_ is -greater than the two forms used in English ('object' for the singular and -'objects' for all the cases where ``count`` is different from one, irrespective -of its value.) +`_ +(and :ref:`see below `) greater than the two forms used in English +('object' for the singular and 'objects' for all the cases where ``count`` is +different from one, irrespective of its value.) For example:: @@ -279,14 +279,52 @@ In a case like this, consider something like the following:: a format specification for argument 'name', as in 'msgstr[0]', doesn't exist in 'msgid' -.. note:: Plural form and po files +.. _plural-forms: - Django does not support custom plural equations in po files. As all - translation catalogs are merged, only the plural form for the main Django po - file (in ``django/conf/locale//LC_MESSAGES/django.po``) is - considered. Plural forms in all other po files are ignored. Therefore, you - should not use different plural equations in your project or application po - files. +Plural Forms +~~~~~~~~~~~~ + +Django does not support multiple plural forms in message files. As all +translation files are merged, only the plural form in the main Django po +file (located by default in ``django/conf/locale//LC_MESSAGES/django.po``, +customized with the :setting:`LOCALE_ROOT` setting) is considered. + +To prevent inconsistencies and undesired results in translations, Django +provides the :setting:`PLURAL_FORMS_CONSISTENCY` setting (disabled by default). + +If enabled, Django will issue a warning when merging any message file that +contains different plural forms than the main Django po file, both at a +:ref:`system check level ` (``translation.W005``) and +run-time. + +This issue may arise mostly in two situations: + +* when the main plural forms for a language is updated in Django and your po + files were created with a previous one, or + +* when including third-party translations with different plural forms. + +If you had created your message file with a previous version of Django, the +standard may have changed or a bug has been fixed in the release. + +For aligning with the new version of the standard (or addressing the bug), +you may use +:option:`django-admin makemessages --update-plural-forms` +to update your message files so they are aligned with the main plural forms +and avoid unexpected behavior. + +Customization of the plural forms for a language is done via the +:setting:`LOCALE_ROOT` setting. + +Once the setting is defined, Django will use the files under this directory as +the main Django po files for translations. + +You may use :option:`django-admin makemessages --collect-bundled` +for collecting the bundled ones with Django and then customize them. + +.. versionchanged:: 3.1 + + Handling plural forms as described above was added. .. _contextual-markers: diff --git a/tests/.coveragerc b/tests/.coveragerc index e519f06259498..9e204434b6b28 100644 --- a/tests/.coveragerc +++ b/tests/.coveragerc @@ -9,6 +9,5 @@ ignore_errors = True omit = */django/conf/locale/* */tests/* - [html] directory = coverage_html diff --git a/tests/check_framework/locale_dir/cs/LC_MESSAGES/django.mo b/tests/check_framework/locale_dir/cs/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..11f853d6f6f46 Binary files /dev/null and b/tests/check_framework/locale_dir/cs/LC_MESSAGES/django.mo differ diff --git a/tests/check_framework/locale_dir/cs/LC_MESSAGES/django.po b/tests/check_framework/locale_dir/cs/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..e4eb778b3a851 --- /dev/null +++ b/tests/check_framework/locale_dir/cs/LC_MESSAGES/django.po @@ -0,0 +1,17 @@ +# This file is distributed under the same license as the Django package. +# +msgid "" +msgstr "" +"Project-Id-Version: Django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-12-13 09:47+0200\n" +"PO-Revision-Date: 2010-05-13 15:35+0200\n" +"Last-Translator: Django team\n" +"Language-Team: English \n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Hello" +msgstr "" diff --git a/tests/check_framework/locale_dir/fr/LC_MESSAGES/django.mo b/tests/check_framework/locale_dir/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..fe513c297214d Binary files /dev/null and b/tests/check_framework/locale_dir/fr/LC_MESSAGES/django.mo differ diff --git a/tests/check_framework/locale_dir/fr/LC_MESSAGES/django.po b/tests/check_framework/locale_dir/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..c9169b7982a33 --- /dev/null +++ b/tests/check_framework/locale_dir/fr/LC_MESSAGES/django.po @@ -0,0 +1,14 @@ +# This file is distributed under the same license as the Django package. +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-29 09:09+0000\n" +"Last-Translator: Claude Paroz \n" +"Language-Team: French (http://www.transifex.com/django/django/language/fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" diff --git a/tests/check_framework/test_translation.py b/tests/check_framework/test_translation.py index 8747a52cda075..5a93e47242f26 100644 --- a/tests/check_framework/test_translation.py +++ b/tests/check_framework/test_translation.py @@ -1,10 +1,15 @@ -from django.core.checks import Error +import os + +from django.core.checks import Error, Warning from django.core.checks.translation import ( - check_language_settings_consistent, check_setting_language_code, - check_setting_languages, check_setting_languages_bidi, + check_language_settings_consistent, check_plural_forms_consistency, + check_setting_language_code, check_setting_languages, + check_setting_languages_bidi, ) from django.test import SimpleTestCase, override_settings +here = os.path.dirname(os.path.abspath(__file__)) + class TranslationCheckTests(SimpleTestCase): @@ -108,3 +113,42 @@ def test_valid_variant_consistent_language_settings(self): for tag in tests: with self.subTest(tag), self.settings(LANGUAGE_CODE=tag): self.assertEqual(check_language_settings_consistent(None), []) + + def test_inconsistent_plural_forms_in_languages(self): + languages = [('cs', 'Czech'), ('fr', 'French'), ('sk', 'Slovak')] + msg = 'Inconsistent plural forms across catalogs for language {!r}.' + with self.settings( + PLURAL_FORMS_CONSISTENCY=True, + LANGUAGE_CODE='cs', + LANGUAGES=languages, + LOCALE_PATHS=[os.path.join(here, 'locale_dir'), ]): + expected_warnings = [ + Warning(msg.format(lang), id='translation.W005') for lang in ['cs', 'fr'] + ] + received_warnings = check_plural_forms_consistency(None) + for warn in received_warnings: + self.assertIn(warn, expected_warnings) + expected_warnings.remove(warn) + received_warnings.remove(warn) + self.assertEqual(expected_warnings, received_warnings, []) + + def test_inconsistent_plural_forms_in_language_code(self): + msg = 'Inconsistent plural forms across catalogs for language {!r}.' + with self.settings( + PLURAL_FORMS_CONSISTENCY=True, + LANGUAGE_CODE='cs', + LANGUAGES=None, + LOCALE_PATHS=[os.path.join(here, 'locale_dir'), ]): + expected_warnings = [Warning(msg.format('cs'), id='translation.W005'), ] + received_warnings = check_plural_forms_consistency(None) + self.assertEqual(expected_warnings, received_warnings) + + def test_inconsistent_plural_forms_in_languages_disabled_setting(self): + languages = [('cs', 'Czech'), ('fr', 'French'), ('sk', 'Slovak')] + with self.settings( + PLURAL_FORMS_CONSISTENCY=False, + LANGUAGE_CODE='cs', + LANGUAGES=languages, + LOCALE_PATHS=[os.path.join(here, 'locale_dir'), ]): + received_warnings = check_plural_forms_consistency(None) + self.assertEqual(received_warnings, []) diff --git a/tests/i18n/commands/app_with_locale/locale/cs/LC_MESSAGES/django.mo b/tests/i18n/commands/app_with_locale/locale/cs/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..74ff78f9b66a7 Binary files /dev/null and b/tests/i18n/commands/app_with_locale/locale/cs/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/app_with_locale/locale/cs/LC_MESSAGES/django.po b/tests/i18n/commands/app_with_locale/locale/cs/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..1fbb8888dcbea --- /dev/null +++ b/tests/i18n/commands/app_with_locale/locale/cs/LC_MESSAGES/django.po @@ -0,0 +1,30 @@ +# This file is distributed under the same license as the Django package. +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Czech (http://www.transifex.com/django/django/language/cs/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: cs\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + + +#, python-format +msgid "" +"Ensure that there are no more than %(max)s digit before the decimal point." +msgid_plural "" +"Ensure that there are no more than %(max)s digits before the decimal point." +msgstr[0] "" +"Ujistěte se, že hodnota neobsahuje více než %(max)s místo před desetinnou " +"čárkou (tečkou)." +msgstr[1] "" +"Ujistěte se, že hodnota neobsahuje více než %(max)s místa před desetinnou " +"čárkou (tečkou)." + +#, python-format +msgid "Ensure that there are no more than %(max)s digit in total." +msgid_plural "Ensure that there are no more than %(max)s digits in total." +msgstr[0] "Ujistěte se, že pole neobsahuje celkem více než %(max)s číslici." +msgstr[1] "Ujistěte se, že pole neobsahuje celkem více než %(max)s číslice." diff --git a/tests/i18n/commands/app_with_locale/locale/en/LC_MESSAGES/django.po b/tests/i18n/commands/app_with_locale/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..61b22e32ee774 --- /dev/null +++ b/tests/i18n/commands/app_with_locale/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,18 @@ +# This file is distributed under the same license as the Django package. +# +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: English (http://www.transifex.com/django/django/language/" +"en/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" + +msgid "Oh, what a string!!" +msgstr "" diff --git a/tests/i18n/commands/app_with_locale/locale/es_XX/LC_MESSAGES/django.po b/tests/i18n/commands/app_with_locale/locale/es_XX/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..2240292d657ac --- /dev/null +++ b/tests/i18n/commands/app_with_locale/locale/es_XX/LC_MESSAGES/django.po @@ -0,0 +1,16 @@ +# This file is distributed under the same license as the Django package. +# +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Spanish (http://www.transifex.com/django/django/language/" +"es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" + diff --git a/tests/i18n/commands/app_with_locale/locale/lt/LC_MESSAGES/django.mo b/tests/i18n/commands/app_with_locale/locale/lt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..cb6a8f611f33a Binary files /dev/null and b/tests/i18n/commands/app_with_locale/locale/lt/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/app_with_locale/locale/lt/LC_MESSAGES/django.po b/tests/i18n/commands/app_with_locale/locale/lt/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..dcd8fa024ddba --- /dev/null +++ b/tests/i18n/commands/app_with_locale/locale/lt/LC_MESSAGES/django.po @@ -0,0 +1,28 @@ +# This file is distributed under the same license as the Django package. +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Lithuanian (http://www.transifex.com/django/django/language/" +"lt/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: lt\n" +"Plural-Forms: nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < " +"11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? " +"1 : n % 1 != 0 ? 2: 3);\n" + +msgid "Password change" +msgstr "Slaptažodžio keitimas" + +#, python-format +msgid "%(counter)s result" +msgid_plural "%(counter)s results" +msgstr[0] "%(counter)s rezultatas" +msgstr[1] "%(counter)s rezultatai" +msgstr[2] "%(counter)s rezultatai" +msgstr[3] "%(counter)s rezultatai" diff --git a/tests/i18n/commands/app_with_locale/locale/mk/LC_MESSAGES/django.mo b/tests/i18n/commands/app_with_locale/locale/mk/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..ec20271eeef74 Binary files /dev/null and b/tests/i18n/commands/app_with_locale/locale/mk/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/app_with_locale/locale/mk/LC_MESSAGES/django.po b/tests/i18n/commands/app_with_locale/locale/mk/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..a9cc6b45ce940 --- /dev/null +++ b/tests/i18n/commands/app_with_locale/locale/mk/LC_MESSAGES/django.po @@ -0,0 +1,22 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# dekomote , 2015 +# Jannis Leidel , 2011 +# Vasil Vangelovski , 2016-2017 +# Vasil Vangelovski , 2013-2015 +# Vasil Vangelovski , 2011-2013 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Macedonian (http://www.transifex.com/django/django/language/" +"mk/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: mk\n" +"Plural-Forms: nplurals=; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;\n" \ No newline at end of file diff --git a/tests/i18n/commands/app_with_locale/locale/ru/LC_MESSAGES/django.mo b/tests/i18n/commands/app_with_locale/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..7e5dd9943b160 Binary files /dev/null and b/tests/i18n/commands/app_with_locale/locale/ru/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/app_with_locale/locale/ru/LC_MESSAGES/django.po b/tests/i18n/commands/app_with_locale/locale/ru/LC_MESSAGES/django.po index ae23e448a37c4..2eb59503cb9dc 100644 --- a/tests/i18n/commands/app_with_locale/locale/ru/LC_MESSAGES/django.po +++ b/tests/i18n/commands/app_with_locale/locale/ru/LC_MESSAGES/django.po @@ -16,8 +16,9 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" # msgid "Lenin" diff --git a/tests/i18n/commands/app_with_locale/locale/sk/LC_MESSAGES/django.mo b/tests/i18n/commands/app_with_locale/locale/sk/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..a5decce96e6e4 Binary files /dev/null and b/tests/i18n/commands/app_with_locale/locale/sk/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/app_with_locale/locale/sk/LC_MESSAGES/django.po b/tests/i18n/commands/app_with_locale/locale/sk/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..06e31e5b286dc --- /dev/null +++ b/tests/i18n/commands/app_with_locale/locale/sk/LC_MESSAGES/django.po @@ -0,0 +1,30 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# Jannis Leidel , 2011 +# Juraj Bubniak , 2012-2013 +# Marian Andre , 2013,2015,2017-2018 +# Martin Kosír, 2011 +# Martin Tóth , 2017 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Slovak (http://www.transifex.com/django/django/language/sk/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sk\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n " +">= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" + +#, python-format +msgid "Please submit %d or fewer forms." +msgid_plural "Please submit %d or fewer forms." +msgstr[0] "Prosím odošlite %d alebo menej formulárov. -0-" +msgstr[1] "Prosím odošlite %d alebo menej formulárov. -1-" +msgstr[2] "Prosím odošlite %d alebo menej formulárov. -2-" +msgstr[3] "Prosím odošlite %d alebo menej formulárov. -3-" \ No newline at end of file diff --git a/tests/i18n/commands/app_with_locale/locale/sk_XX/LC_MESSAGES/django.po b/tests/i18n/commands/app_with_locale/locale/sk_XX/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..0801df56f7c3c --- /dev/null +++ b/tests/i18n/commands/app_with_locale/locale/sk_XX/LC_MESSAGES/django.po @@ -0,0 +1,19 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-01-03 05:13+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" diff --git a/tests/i18n/commands/app_with_locale/locale/sl/LC_MESSAGES/django.mo b/tests/i18n/commands/app_with_locale/locale/sl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..6ad4e390ec752 Binary files /dev/null and b/tests/i18n/commands/app_with_locale/locale/sl/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/app_with_locale/locale/sl/LC_MESSAGES/django.po b/tests/i18n/commands/app_with_locale/locale/sl/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..40c6d50ea1a7e --- /dev/null +++ b/tests/i18n/commands/app_with_locale/locale/sl/LC_MESSAGES/django.po @@ -0,0 +1,31 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# iElectric , 2011-2012 +# Jannis Leidel , 2011 +# Jure Cuhalev , 2012-2013 +# Marko Zabreznik , 2016 +# Primož Verdnik , 2017 +# zejn , 2013,2016-2017 +# zejn , 2011-2013 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Slovenian (http://www.transifex.com/django/django/language/" +"sl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sl\n" +"Plural-Forms: plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" +"%100==4 ? 2 : 3);\n" + +msgid "Afrikaans" +msgstr "Afrikanščina" + +msgid "Arabic" +msgstr "Arabščina" diff --git a/tests/i18n/commands/app_with_locale/locale/tt/LC_MESSAGES/django.mo b/tests/i18n/commands/app_with_locale/locale/tt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..57a9e19a5b76b Binary files /dev/null and b/tests/i18n/commands/app_with_locale/locale/tt/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/app_with_locale/locale/tt/LC_MESSAGES/django.po b/tests/i18n/commands/app_with_locale/locale/tt/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..a9a297b0ff032 --- /dev/null +++ b/tests/i18n/commands/app_with_locale/locale/tt/LC_MESSAGES/django.po @@ -0,0 +1,23 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# Azat Khasanshin , 2011 +# v_ildar , 2014 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Tatar (http://www.transifex.com/django/django/language/tt/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: tt\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "" diff --git a/tests/i18n/commands/app_with_locale/locale/xxx/LC_MESSAGES/djangojs.po b/tests/i18n/commands/app_with_locale/locale/xxx/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000000000..1da4fead7f63a --- /dev/null +++ b/tests/i18n/commands/app_with_locale/locale/xxx/LC_MESSAGES/djangojs.po @@ -0,0 +1,14 @@ +# This file is distributed under the same license as the Django package. +# +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Language-Team: XXX\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: xxx\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" diff --git a/tests/i18n/commands/django_dir/conf/global_settings.py b/tests/i18n/commands/django_dir/conf/global_settings.py new file mode 100644 index 0000000000000..5170baf296828 --- /dev/null +++ b/tests/i18n/commands/django_dir/conf/global_settings.py @@ -0,0 +1,15 @@ +""" +Mocked file based on default settings to trigger xgettext extraction +""" + + +# This is defined here as a do-nothing function because we can't import +# django.utils.translation -- that module depends on the settings. +def gettext_noop(s): + return s + + +# Languages we provide translations for, out of the box. +LANGUAGES = [ + ('lv', gettext_noop('Love')), +] diff --git a/tests/i18n/commands/django_dir/conf/locale/cs/LC_MESSAGES/django.mo b/tests/i18n/commands/django_dir/conf/locale/cs/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..47cddf1774457 Binary files /dev/null and b/tests/i18n/commands/django_dir/conf/locale/cs/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/django_dir/conf/locale/cs/LC_MESSAGES/django.po b/tests/i18n/commands/django_dir/conf/locale/cs/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..ca569c59dbdba --- /dev/null +++ b/tests/i18n/commands/django_dir/conf/locale/cs/LC_MESSAGES/django.po @@ -0,0 +1,18 @@ +# This file is distributed under the same license as the Django package. +# Translators: +# Translator #1 +# Translator #2 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Czech (http://www.transifex.com/django/django/language/cs/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: cs\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n " +"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" + +msgid "A string" +msgstr "translated to cs" diff --git a/tests/i18n/commands/django_dir/conf/locale/es/LC_MESSAGES/django.mo b/tests/i18n/commands/django_dir/conf/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..4bf35741a0c66 Binary files /dev/null and b/tests/i18n/commands/django_dir/conf/locale/es/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/django_dir/conf/locale/es/LC_MESSAGES/django.po b/tests/i18n/commands/django_dir/conf/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..e5340004c4768 --- /dev/null +++ b/tests/i18n/commands/django_dir/conf/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,19 @@ +# This file is distributed under the same license as the Django package. +# +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Spanish (http://www.transifex.com/django/django/language/" +"es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Afrikaans" +msgstr "Africano" diff --git a/tests/i18n/commands/django_dir/conf/locale/lt/LC_MESSAGES/django.mo b/tests/i18n/commands/django_dir/conf/locale/lt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..1b839200b9295 Binary files /dev/null and b/tests/i18n/commands/django_dir/conf/locale/lt/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/django_dir/conf/locale/lt/LC_MESSAGES/django.po b/tests/i18n/commands/django_dir/conf/locale/lt/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..0fd6966870df7 --- /dev/null +++ b/tests/i18n/commands/django_dir/conf/locale/lt/LC_MESSAGES/django.po @@ -0,0 +1,18 @@ +# This file is distributed under the same license as the Django package. +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Lithuanian (http://www.transifex.com/django/django/language/" +"lt/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: lt\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "A string" +msgstr "translated to lt" diff --git a/tests/i18n/commands/django_dir/conf/locale/mk/LC_MESSAGES/django.mo b/tests/i18n/commands/django_dir/conf/locale/mk/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..6adfcce106c3d Binary files /dev/null and b/tests/i18n/commands/django_dir/conf/locale/mk/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/django_dir/conf/locale/mk/LC_MESSAGES/django.po b/tests/i18n/commands/django_dir/conf/locale/mk/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..92b9b383894b3 --- /dev/null +++ b/tests/i18n/commands/django_dir/conf/locale/mk/LC_MESSAGES/django.po @@ -0,0 +1,25 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# dekomote , 2015 +# Jannis Leidel , 2011 +# Vasil Vangelovski , 2016-2017 +# Vasil Vangelovski , 2013-2015 +# Vasil Vangelovski , 2011-2013 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Macedonian (http://www.transifex.com/django/django/language/" +"mk/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: mk\n" +"Plural-Forms: nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;\n" + +msgid "A string" +msgstr "translated to mk" diff --git a/tests/i18n/commands/django_dir/conf/locale/ru/LC_MESSAGES/django.mo b/tests/i18n/commands/django_dir/conf/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..7007a3d4e50dd Binary files /dev/null and b/tests/i18n/commands/django_dir/conf/locale/ru/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/django_dir/conf/locale/ru/LC_MESSAGES/django.po b/tests/i18n/commands/django_dir/conf/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..6a96e2aa1339e --- /dev/null +++ b/tests/i18n/commands/django_dir/conf/locale/ru/LC_MESSAGES/django.po @@ -0,0 +1,21 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-03-30 12:51+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" diff --git a/tests/i18n/commands/django_dir/conf/locale/sl/LC_MESSAGES/django.mo b/tests/i18n/commands/django_dir/conf/locale/sl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..63b975834c407 Binary files /dev/null and b/tests/i18n/commands/django_dir/conf/locale/sl/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/django_dir/conf/locale/sl/LC_MESSAGES/django.po b/tests/i18n/commands/django_dir/conf/locale/sl/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..5f9593a3665f5 --- /dev/null +++ b/tests/i18n/commands/django_dir/conf/locale/sl/LC_MESSAGES/django.po @@ -0,0 +1,25 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# iElectric , 2011-2012 +# Jannis Leidel , 2011 +# Jure Cuhalev , 2012-2013 +# Marko Zabreznik , 2016 +# Primož Verdnik , 2017 +# zejn , 2013,2016-2017 +# zejn , 2011-2013 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Slovenian (http://www.transifex.com/django/django/language/" +"sl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sl\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" +"%100==4 ? 2 : 3);\n" diff --git a/tests/i18n/commands/django_dir/conf/locale/tt/LC_MESSAGES/django.mo b/tests/i18n/commands/django_dir/conf/locale/tt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..ae0373e2e176c Binary files /dev/null and b/tests/i18n/commands/django_dir/conf/locale/tt/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/django_dir/conf/locale/tt/LC_MESSAGES/django.po b/tests/i18n/commands/django_dir/conf/locale/tt/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..dad8137eab350 --- /dev/null +++ b/tests/i18n/commands/django_dir/conf/locale/tt/LC_MESSAGES/django.po @@ -0,0 +1,18 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# Azat Khasanshin , 2011 +# v_ildar , 2014 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Tatar (http://www.transifex.com/django/django/language/tt/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: tt\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" diff --git a/tests/i18n/commands/django_dir/contrib/admin/locale/es/LC_MESSAGES/django.mo b/tests/i18n/commands/django_dir/contrib/admin/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..d1239e3d8259b Binary files /dev/null and b/tests/i18n/commands/django_dir/contrib/admin/locale/es/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/django_dir/contrib/admin/locale/es/LC_MESSAGES/django.po b/tests/i18n/commands/django_dir/contrib/admin/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..458f91cbeb284 --- /dev/null +++ b/tests/i18n/commands/django_dir/contrib/admin/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,19 @@ +# This file is distributed under the same license as the Django package. +# +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Spanish (http://www.transifex.com/django/django/language/" +"es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Arabic" +msgstr "Árabe" diff --git a/tests/i18n/commands/locale/en/LC_MESSAGES/django.po b/tests/i18n/commands/locale/en/LC_MESSAGES/django.po index ddb831b24b187..e6724f1f9b276 100644 --- a/tests/i18n/commands/locale/en/LC_MESSAGES/django.po +++ b/tests/i18n/commands/locale/en/LC_MESSAGES/django.po @@ -16,6 +16,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #. Translators: This comment should be extracted #: __init__.py:4 diff --git a/tests/i18n/commands/locale/fr/LC_MESSAGES/django.mo b/tests/i18n/commands/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..93a58ad34a2f0 Binary files /dev/null and b/tests/i18n/commands/locale/fr/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/locale/hr/LC_MESSAGES/django.mo b/tests/i18n/commands/locale/hr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..b8d616fa2c745 Binary files /dev/null and b/tests/i18n/commands/locale/hr/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/locale/ko/LC_MESSAGES/django.mo b/tests/i18n/commands/locale/ko/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..cca2e5dfe95a3 Binary files /dev/null and b/tests/i18n/commands/locale/ko/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/locale/ru/LC_MESSAGES/django.mo b/tests/i18n/commands/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..7e5dd9943b160 Binary files /dev/null and b/tests/i18n/commands/locale/ru/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/commands/locale/ru/LC_MESSAGES/django.po b/tests/i18n/commands/locale/ru/LC_MESSAGES/django.po index ae23e448a37c4..2eb59503cb9dc 100644 --- a/tests/i18n/commands/locale/ru/LC_MESSAGES/django.po +++ b/tests/i18n/commands/locale/ru/LC_MESSAGES/django.po @@ -16,8 +16,9 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" # msgid "Lenin" diff --git a/tests/i18n/commands/locale_root/es/LC_MESSAGES/django.po b/tests/i18n/commands/locale_root/es/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..350a2782b7972 --- /dev/null +++ b/tests/i18n/commands/locale_root/es/LC_MESSAGES/django.po @@ -0,0 +1,19 @@ +# This file is distributed under the same license as the Django package. +# +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Spanish (http://www.transifex.com/django/django/language/" +"es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Asturian" +msgstr "Asturiano" diff --git a/tests/i18n/commands/locale_root/mk/LC_MESSAGES/django.po b/tests/i18n/commands/locale_root/mk/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..2b3104ff31d5b --- /dev/null +++ b/tests/i18n/commands/locale_root/mk/LC_MESSAGES/django.po @@ -0,0 +1,16 @@ +# This file is distributed under the same license as the Django package. +# +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Macedonian (http://www.transifex.com/django/django/language/" +"mk/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: mk\n" +"Plural-Forms: nplurals=3; plural=(? 0 : 1;\n" diff --git a/tests/i18n/commands/locale_root/sk/LC_MESSAGES/django.po b/tests/i18n/commands/locale_root/sk/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..93a6f5af5e461 --- /dev/null +++ b/tests/i18n/commands/locale_root/sk/LC_MESSAGES/django.po @@ -0,0 +1,21 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# Jannis Leidel , 2011 +# Juraj Bubniak , 2012-2013 +# Marian Andre , 2013,2015,2017-2018 +# Martin Kosír, 2011 +# Martin Tóth , 2017 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Slovak (http://www.transifex.com/django/django/language/sk/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sk\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" diff --git a/tests/i18n/commands/locale_root/sl/LC_MESSAGES/django.po b/tests/i18n/commands/locale_root/sl/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..696f0c9bd85eb --- /dev/null +++ b/tests/i18n/commands/locale_root/sl/LC_MESSAGES/django.po @@ -0,0 +1,30 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# iElectric , 2011-2012 +# Jannis Leidel , 2011 +# Jure Cuhalev , 2012-2013 +# Marko Zabreznik , 2016 +# Primož Verdnik , 2017 +# zejn , 2013,2016-2017 +# zejn , 2011-2013 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Slovenian (http://www.transifex.com/django/django/language/" +"sl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sl\n" +"Plural-Forms: nplurals=4;\n" + +msgid "Afrikaans" +msgstr "Afrikanščina" + +msgid "Arabic" +msgstr "Arabščina" diff --git a/tests/i18n/contenttypes/locale/en/LC_MESSAGES/django.po b/tests/i18n/contenttypes/locale/en/LC_MESSAGES/django.po index 2529ce6dfbcd7..dbdb6034d3e48 100644 --- a/tests/i18n/contenttypes/locale/en/LC_MESSAGES/django.po +++ b/tests/i18n/contenttypes/locale/en/LC_MESSAGES/django.po @@ -16,6 +16,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #: models.py:6 msgid "Anything" @@ -23,4 +24,4 @@ msgstr "" #: models.py:15 msgid "Company" -msgstr "Company" \ No newline at end of file +msgstr "Company" diff --git a/tests/i18n/locale_root/cs/LC_MESSAGES/django.mo b/tests/i18n/locale_root/cs/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..a640f358ca149 Binary files /dev/null and b/tests/i18n/locale_root/cs/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/locale_root/cs/LC_MESSAGES/django.po b/tests/i18n/locale_root/cs/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..0f0662ddfcf56 --- /dev/null +++ b/tests/i18n/locale_root/cs/LC_MESSAGES/django.po @@ -0,0 +1,23 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# Jannis Leidel , 2011 +# Jan Papež , 2012 +# Jirka Vejrazka , 2011 +# Tomáš Ehrlich , 2015 +# Vláďa Macek , 2012-2014 +# Vláďa Macek , 2015-2019 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-18 11:37+0000\n" +"Last-Translator: Vláďa Macek \n" +"Language-Team: Czech (http://www.transifex.com/django/django/language/cs/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: cs\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n " +"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" diff --git a/tests/i18n/locale_root/es/LC_MESSAGES/django.mo b/tests/i18n/locale_root/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..2814f78ad5fc8 Binary files /dev/null and b/tests/i18n/locale_root/es/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/locale_root/es/LC_MESSAGES/django.po b/tests/i18n/locale_root/es/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..ba01a93d316ae --- /dev/null +++ b/tests/i18n/locale_root/es/LC_MESSAGES/django.po @@ -0,0 +1,19 @@ +# This file is distributed under the same license as the Django package. +# +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Spanish (http://www.transifex.com/django/django/language/" +"es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Do you like icecream?" +msgstr "¿Os gusta el helado?" diff --git a/tests/i18n/other/locale/cs/LC_MESSAGES/django.mo b/tests/i18n/other/locale/cs/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..891619034f175 Binary files /dev/null and b/tests/i18n/other/locale/cs/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/other/locale/cs/LC_MESSAGES/django.po b/tests/i18n/other/locale/cs/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..f9e9b3d180ee8 --- /dev/null +++ b/tests/i18n/other/locale/cs/LC_MESSAGES/django.po @@ -0,0 +1,26 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# Jannis Leidel , 2011 +# Jan Papež , 2012 +# Jirka Vejrazka , 2011 +# Tomáš Ehrlich , 2015 +# Vláďa Macek , 2012-2014 +# Vláďa Macek , 2015-2019 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-18 11:37+0000\n" +"Last-Translator: Vláďa Macek \n" +"Language-Team: Czech (http://www.transifex.com/django/django/language/cs/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: cs\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n " +">= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" + +msgid "Afrikaans" +msgstr "afrikánsky" diff --git a/tests/i18n/other/locale/lt/LC_MESSAGES/django.mo b/tests/i18n/other/locale/lt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..f5f04b613df8d Binary files /dev/null and b/tests/i18n/other/locale/lt/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/other/locale/lt/LC_MESSAGES/django.po b/tests/i18n/other/locale/lt/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..e74e3c86dd5ad --- /dev/null +++ b/tests/i18n/other/locale/lt/LC_MESSAGES/django.po @@ -0,0 +1,18 @@ +# This file is distributed under the same license as the Django package. +# +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Lithuanian (http://www.transifex.com/django/django/language/" +"lt/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: lt\n" + +msgid "Afrikaans" +msgstr "Afrikiečių" diff --git a/tests/i18n/other/locale/sk/LC_MESSAGES/django.mo b/tests/i18n/other/locale/sk/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000..62edf93facd63 Binary files /dev/null and b/tests/i18n/other/locale/sk/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/other/locale/sk/LC_MESSAGES/django.po b/tests/i18n/other/locale/sk/LC_MESSAGES/django.po new file mode 100644 index 0000000000000..eb96dd0588650 --- /dev/null +++ b/tests/i18n/other/locale/sk/LC_MESSAGES/django.po @@ -0,0 +1,25 @@ +# This file is distributed under the same license as the Django package. +# +# Translators: +# Jannis Leidel , 2011 +# Juraj Bubniak , 2012-2013 +# Marian Andre , 2013,2015,2017-2018 +# Martin Kosír, 2011 +# Martin Tóth , 2017 +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-27 22:40+0200\n" +"PO-Revision-Date: 2019-11-05 00:38+0000\n" +"Last-Translator: Ramiro Morales\n" +"Language-Team: Slovak (http://www.transifex.com/django/django/language/sk/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sk\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n " +">= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" + +msgid "a test string" +msgstr "translated into sk" \ No newline at end of file diff --git a/tests/i18n/patterns/locale/en/LC_MESSAGES/django.po b/tests/i18n/patterns/locale/en/LC_MESSAGES/django.po index 9a14a80ceb8f9..0bbf0e4e8526d 100644 --- a/tests/i18n/patterns/locale/en/LC_MESSAGES/django.po +++ b/tests/i18n/patterns/locale/en/LC_MESSAGES/django.po @@ -15,6 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #: urls/default.py:11 msgid "^translated/$" diff --git a/tests/i18n/sampleproject/locale/fr/LC_MESSAGES/django.mo b/tests/i18n/sampleproject/locale/fr/LC_MESSAGES/django.mo index ebc475caa20d4..a57181b098fbb 100644 Binary files a/tests/i18n/sampleproject/locale/fr/LC_MESSAGES/django.mo and b/tests/i18n/sampleproject/locale/fr/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/sampleproject/locale/fr/LC_MESSAGES/django.po b/tests/i18n/sampleproject/locale/fr/LC_MESSAGES/django.po index 734f139b5c77c..fca21f824731a 100644 --- a/tests/i18n/sampleproject/locale/fr/LC_MESSAGES/django.po +++ b/tests/i18n/sampleproject/locale/fr/LC_MESSAGES/django.po @@ -3,6 +3,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" #: templates/percents.html:3 #, python-format diff --git a/tests/i18n/territorial_fallback/locale/de/LC_MESSAGES/django.mo b/tests/i18n/territorial_fallback/locale/de/LC_MESSAGES/django.mo index 454fef0c7a779..dec34a957e27d 100644 Binary files a/tests/i18n/territorial_fallback/locale/de/LC_MESSAGES/django.mo and b/tests/i18n/territorial_fallback/locale/de/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/territorial_fallback/locale/de/LC_MESSAGES/django.po b/tests/i18n/territorial_fallback/locale/de/LC_MESSAGES/django.po index 72013ab5798f9..55c796ac50ff0 100644 --- a/tests/i18n/territorial_fallback/locale/de/LC_MESSAGES/django.po +++ b/tests/i18n/territorial_fallback/locale/de/LC_MESSAGES/django.po @@ -16,6 +16,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #. Translators: This comment should be extracted #: __init__.py:1 diff --git a/tests/i18n/territorial_fallback/locale/de_DE/LC_MESSAGES/django.mo b/tests/i18n/territorial_fallback/locale/de_DE/LC_MESSAGES/django.mo index 4d014cb1bf6dc..b0b70e0a3eee8 100644 Binary files a/tests/i18n/territorial_fallback/locale/de_DE/LC_MESSAGES/django.mo and b/tests/i18n/territorial_fallback/locale/de_DE/LC_MESSAGES/django.mo differ diff --git a/tests/i18n/territorial_fallback/locale/de_DE/LC_MESSAGES/django.po b/tests/i18n/territorial_fallback/locale/de_DE/LC_MESSAGES/django.po index e28fcd3405174..6df9f4e94ee5a 100644 --- a/tests/i18n/territorial_fallback/locale/de_DE/LC_MESSAGES/django.po +++ b/tests/i18n/territorial_fallback/locale/de_DE/LC_MESSAGES/django.po @@ -16,6 +16,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #. Translators: This comment should be extracted #: __init__.py:1 diff --git a/tests/i18n/test_extraction.py b/tests/i18n/test_extraction.py index 709a6133f58a5..808c91813f0e4 100644 --- a/tests/i18n/test_extraction.py +++ b/tests/i18n/test_extraction.py @@ -515,6 +515,7 @@ def test_symlink(self): class CopyPluralFormsExtractorTests(ExtractorTests): PO_FILE_ES = 'locale/es/LC_MESSAGES/django.po' + PO_FILE_RU = 'locale/ru/LC_MESSAGES/django.po' def test_copy_plural_forms(self): management.call_command('makemessages', locale=[LOCALE], verbosity=0) @@ -547,6 +548,289 @@ def test_translate_and_plural_blocktranslate_collision(self): self.assertMsgIdPlural('Plural for a `translate` and `blocktranslate` collision case', po_contents) +class CollectBundledTests(ExtractorTests): + + PO_FILE = 'locale_root/%s/LC_MESSAGES/django.po' + BUNDLED_LOCALES = ['cs', 'es', 'lt', 'mk', 'ru', 'sl', 'tt'] + + def test_single_locale(self): + with override_settings(LOCALE_ROOT=os.path.join(self.test_dir, 'locale_root')): + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + out = StringIO() + management.call_command( + 'makemessages', locale=['es'], collect_bundled='default-path', + stdout=out, verbosity=1 + ) + with open(self.PO_FILE % 'es', encoding='utf-8') as fp: + po_contents = fp.read() + should_contain = """ + msgid "Afrikaans" + msgstr "Africano" + msgid "Arabic" + msgstr "Árabe" + msgid "Asturian" + msgstr "Asturiano" + """ + for line in should_contain.splitlines(): + self.assertIn(line.strip(), po_contents) + + def test_translators_string(self): + with override_settings(LOCALE_ROOT=os.path.join(self.test_dir, 'locale_root')): + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + management.call_command( + 'makemessages', locale=['cs'], collect_bundled='default-path', + verbosity=0 + ) + with open(self.PO_FILE % 'cs', encoding='utf-8') as fp: + po_contents = fp.read() + should_contain = "Contributors to this catalog are listed in" + self.assertIn(should_contain, po_contents) + + def test_all_bundled(self): + with override_settings(LOCALE_ROOT=os.path.join(self.test_dir, 'locale_root')): + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + management.call_command('makemessages', collect_bundled='all-bundled', verbosity=0) + for locale in self.BUNDLED_LOCALES: + self.assertTrue(os.path.exists(self.PO_FILE % locale)) + + def test_new_locale(self): + with override_settings(LOCALE_ROOT=os.path.join(self.test_dir, 'locale_root')): + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + management.call_command( + 'makemessages', locale=['xxx'], collect_bundled='default-path', + verbosity=0 + ) + should_contain = """ + "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + msgid "Love" + """ + with open(self.PO_FILE % 'xxx', encoding='utf-8') as fp: + po_contents = fp.read() + for line in should_contain.splitlines(): + self.assertIn(line.strip(), po_contents) + + def test_no_locale_root_setting(self): + msg = ("currently makemessages only supports collecting bundled message files " + "with the LOCALE_ROOT setting defined.") + with self.assertRaisesMessage(CommandError, msg): + management.call_command('makemessages', collect_bundled='default-path', verbosity=0) + + +class UpdatePluralFormsTests(ExtractorTests): + + PO_FILE_NEW = 'app_with_locale/locale/%s/LC_MESSAGES/django.po.new' + PO_FILE = 'app_with_locale/locale/%s/LC_MESSAGES/django.po' + + def test_remapping_interactive(self): + """ + Test the correct functioning of form remapping by --update-plural-forms. + """ + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + with mock.patch('django.core.management.commands.makemessages.Command.get_user_input', + side_effect=['0', '1', '1', '9', '1', 'm', 'n']): + out = StringIO() + management.call_command( + 'makemessages', locale=['cs'], update_plural_forms='interactive', + stdout=out, verbosity=1 + ) + with open(self.PO_FILE_NEW % 'cs', encoding='utf-8') as fp: + po_contents = fp.read() + should_contain = """ + "Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n " + "<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" + + #, python-format + msgid "" + "Ensure that there are no more than %(max)s digit before the decimal point." + msgid_plural "" + "Ensure that there are no more than %(max)s digits before the decimal point." + msgstr[0] "" + "Ujistěte se, že hodnota neobsahuje více než %(max)s místo před desetinnou " + "čárkou (tečkou)." + msgstr[1] "" + "Ujistěte se, že hodnota neobsahuje více než %(max)s místa před desetinnou " + "čárkou (tečkou)." + msgstr[2] "" + "Ujistěte se, že hodnota neobsahuje více než %(max)s místa před desetinnou " + "čárkou (tečkou)." + msgstr[3] "" + "Ujistěte se, že hodnota neobsahuje více než %(max)s místa před desetinnou " + "čárkou (tečkou)." + + #, python-format + msgid "Ensure that there are no more than %(max)s digit in total." + msgid_plural "Ensure that there are no more than %(max)s digits in total." + msgstr[0] "Ujistěte se, že pole neobsahuje celkem více než %(max)s číslici." + msgstr[1] "Ujistěte se, že pole neobsahuje celkem více než %(max)s číslice." + msgstr[2] "Ujistěte se, že pole neobsahuje celkem více než %(max)s číslice." + msgstr[3] "Ujistěte se, že pole neobsahuje celkem více než %(max)s číslice." + """ + for line in should_contain.splitlines(): + self.assertIn(line.strip(), po_contents) + + def test_trimming(self): + """ + Test the correct functioning of trimming in --update-plural-forms ('trimming' is when the + main form has less plural forms than the user's forms. + """ + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + with mock.patch('django.core.management.commands.makemessages.Command.get_user_input', + side_effect=['0', '1', 'n']): + out = StringIO() + management.call_command( + 'makemessages', locale=['lt'], update_plural_forms='interactive', + stdout=out, verbosity=1 + ) + with open(self.PO_FILE_NEW % 'lt', encoding='utf-8') as fp: + po_contents = fp.read() + should_contain = """ + "Plural-Forms: nplurals=2; plural=(n != 1);\n" + msgid "Password change" + msgstr "Slaptažodžio keitimas" + #, python-format + msgid "%(counter)s result" + msgid_plural "%(counter)s results" + msgstr[0] "%(counter)s rezultatas" + msgstr[1] "%(counter)s rezultatai" + """ + + should_not_contain = """msgstr[2] "%(counter)s rezultatai" + msgstr[3] "%(counter)s rezultatai""" + + for line in should_contain.splitlines(): + self.assertIn(line.strip(), po_contents) + + for line in should_not_contain.splitlines(): + self.assertNotIn(line.strip(), po_contents) + + def test_automation_remapping(self): + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + management.call_command('makemessages', locale=['tt'], update_plural_forms='0,0', verbosity=0) + with open(self.PO_FILE % 'tt', encoding='utf-8') as fp: + po_contents = fp.read() + should_contain = """ + "Plural-Forms: nplurals=2; plural=(n != 1);\n" + #, python-format + msgid "%d day" + msgid_plural "%d days" + msgstr[0] "" + msgstr[1] "" + """ + + for line in should_contain.splitlines(): + self.assertIn(line.strip(), po_contents) + + def test_automation_bad_form_map(self): + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + msg = ("currently the --update-plural-forms option only supports " + "'interactive', 'copy' or comma-separated digits as a parameter.") + with self.assertRaisesMessage(CommandError, msg): + management.call_command('makemessages', locale=['tt'], update_plural_forms='0,b', verbosity=0) + + def test_copy_interactive(self): + with mock.patch('django.core.management.commands.makemessages.Command.get_user_input', + side_effect=['u', 'y', 'm', 'n']): + out = StringIO() + management.call_command( + 'makemessages', locale=['es_XX'], update_plural_forms='interactive', + stdout=out, verbosity=1 + ) + with open(self.PO_FILE_NEW % 'es_XX', encoding='utf-8') as fp: + po_contents = fp.read() + should_contain = "Plural-Forms: nplurals=2; plural=(n != 1);\\n" + self.assertIn(should_contain, po_contents) + + def test_automation_copy(self): + management.call_command('makemessages', locale=['en'], update_plural_forms='copy', verbosity=0) + with open(self.PO_FILE % 'en', encoding='utf-8') as fp: + po_contents = fp.read() + should_contain = "Plural-Forms: nplurals=2; plural=(n != 1);\\n" + self.assertIn(should_contain, po_contents) + + def test_locale_root(self): + with override_settings(LOCALE_ROOT=os.path.join(self.test_dir, 'locale_root')): + management.call_command('makemessages', locale=['sk'], update_plural_forms='2,3', verbosity=0) + with open(self.PO_FILE % 'sk', encoding='utf-8') as fp: + po_contents = fp.read() + should_contain = """ + "Plural-Forms: nplurals=2; plural=(n != 1);\n" + msgid "Please submit %d or fewer forms." + msgid_plural "Please submit %d or fewer forms." + msgstr[0] "Prosím odošlite %d alebo menej formulárov. -2-" + msgstr[1] "Prosím odošlite %d alebo menej formulárov. -3-" + """ + + should_not_contain = """msgstr[2] "Prosím odošlite %d alebo menej formulárov. -2-" + msgstr[3] "Prosím odošlite %d alebo menej formulárov. -3-" """ + + for line in should_contain.splitlines(): + self.assertIn(line.strip(), po_contents) + + for line in should_not_contain.splitlines(): + self.assertNotIn(line.strip(), po_contents) + + def test_msgfmt_check_main_form(self): + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + with override_settings(LOCALE_ROOT=os.path.join(self.test_dir, 'locale_root')): + msg = "invalid plural" + with self.assertRaisesMessage(CommandError, msg): + management.call_command( + 'makemessages', locale=['mk'], update_plural_forms='interactive', verbosity=0 + ) + + def test_msgfmt_check_user_form(self): + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + msg = "invalid nplurals value" + with self.assertRaisesMessage(CommandError, msg): + management.call_command('makemessages', locale=['mk'], update_plural_forms='interactive', verbosity=0) + + def test_plural_forms_check_main_form(self): + """ + In some cases, msgfmt --check deems the plural forms as valid if + they not contain either 'nplurals' or 'plural' (bug in msgfmt). + """ + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + with override_settings(LOCALE_ROOT=os.path.join(self.test_dir, 'locale_root')): + msg = "unable to parse" + with self.assertRaisesMessage(CommandError, msg): + management.call_command( + 'makemessages', locale=['sl'], update_plural_forms='interactive', verbosity=0 + ) + + def test_plural_forms_check_user_form(self): + with mock.patch('django.core.management.commands.makemessages.Command.django_dir', + os.path.join(self.test_dir, 'django_dir')): + msg = "unable to parse" + with self.assertRaisesMessage(CommandError, msg): + management.call_command('makemessages', locale=['sl'], update_plural_forms='interactive', verbosity=0) + + def test_incompatible_form_map(self): + with override_settings(LOCALE_ROOT=os.path.join(self.test_dir, 'locale_root')): + msg = "The provided form map is not compatible" + with self.assertRaisesMessage(CommandError, msg): + management.call_command('makemessages', locale=['sk'], update_plural_forms='4,5', verbosity=0) + + def test_no_main_po(self): + with override_settings(LOCALE_ROOT=os.path.join(self.test_dir, 'locale_root')): + msg = "unable to find the main .po file" + with self.assertRaisesMessage(CommandError, msg): + management.call_command( + 'makemessages', locale=['xxx'], domain='djangojs', update_plural_forms='4,5', + verbosity=0 + ) + + class NoWrapExtractorTests(ExtractorTests): def test_no_wrap_enabled(self): diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index ac813b3439f50..4ab275d0bf765 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -1,6 +1,7 @@ import datetime import decimal import gettext as gettext_module +import glob import os import pickle import re @@ -12,6 +13,7 @@ from asgiref.local import Local +import django from django import forms from django.apps import AppConfig from django.conf import settings @@ -1780,6 +1782,98 @@ def test_failure_finding_default_mo_files(self): with self.assertRaises(OSError): activate('en') + def test_failure_finding_mo_files_with_locale_root(self): + """ + Only a warning is raised if no .mo files are found when + setting.LOCALE_ROOT is set. + """ + with override_settings(LOCALE_ROOT=os.path.join(here, 'locale_root/')): + trans_real._translations = {} + msg = ( + 'LOCALE_ROOT has been set and no translation files found for ' + 'default language' + ) + with self.assertWarnsMessage(RuntimeWarning, msg): + activate('en') + + +class LocaleRootTests(SimpleTestCase): + """ + Test the functioning of the LOCALE_ROOT setting. + """ + @override_settings( + USE_I18N=True, + LANGUAGE_CODE='es', + LOCALE_ROOT=os.path.join(here, 'locale_root/') + ) + def test_correct_functioning(self): + self.assertEqual(gettext("Do you like icecream?"), "¿Os gusta el helado?") + self.assertEqual(gettext("password"), "password") + + +class CatalogMergingTests(SimpleTestCase): + """ + Test the functioning of catalog merging in translations + """ + + @override_settings( + PLURAL_FORMS_CONSISTENCY=True + ) + def test_django_bundled_catalogs_consistency(self): + app_configs = [] + django_dir = os.path.normpath(os.path.join(os.path.dirname(django.__file__))) + contrib_apps_dirs = glob.glob(django_dir + '/contrib/*') + for contrib_app_dir in contrib_apps_dirs: + app_configs.append( + AppConfig(contrib_app_dir, AppModuleStub(__path__=[contrib_app_dir])) + ) + with mock.patch('django.apps.apps.get_app_configs', return_value=app_configs): + for lang in LANG_INFO: + activate(lang) + # If it gets up to here, no warning have been issued and all catalogs + # have been merged correctly (any warning will make this test fail). + + @override_settings( + PLURAL_FORMS_CONSISTENCY=True, + LOCALE_PATHS=extended_locale_paths + ) + def test_catalog_with_plural_forms_merged(self): + activate('sk') + self.assertEqual(gettext("a test string"), "translated into sk") + + @override_settings( + PLURAL_FORMS_CONSISTENCY=True, + LANGUAGE_CODE='es', + LOCALE_ROOT=os.path.join(here, 'locale_root/'), + LOCALE_PATHS=extended_locale_paths + ) + def test_catalog_with_different_plural_forms(self): + msg = 'Posible inconsistencies and undesired behavior detected' + with self.assertWarnsMessage(RuntimeWarning, msg): + activate('cs') + + @override_settings( + PLURAL_FORMS_CONSISTENCY=True, + LANGUAGE_CODE='es', + LOCALE_PATHS=extended_locale_paths + ) + def test_catalog_without_plural_forms(self): + msg = 'Posible inconsistencies and undesired behavior detected' + with self.assertWarnsMessage(RuntimeWarning, msg): + activate('lt') + + @override_settings( + PLURAL_FORMS_CONSISTENCY=False, + LANGUAGE_CODE='es', + LOCALE_PATHS=extended_locale_paths + ) + def test_inconsistent_catalog_merging(self): + trans_real.reset_translations_cache() + activate('cs') + activate('lt') + # If it gets up to here, no warning have been issued and all catalogs + # have been merged correctly (any warning will make this test fail). + class NonDjangoLanguageTests(SimpleTestCase): """ diff --git a/tests/urlpatterns_reverse/translations/locale/fr/LC_MESSAGES/django.mo b/tests/urlpatterns_reverse/translations/locale/fr/LC_MESSAGES/django.mo index e755e5baeade0..73bd6f9e54429 100644 Binary files a/tests/urlpatterns_reverse/translations/locale/fr/LC_MESSAGES/django.mo and b/tests/urlpatterns_reverse/translations/locale/fr/LC_MESSAGES/django.mo differ diff --git a/tests/urlpatterns_reverse/translations/locale/fr/LC_MESSAGES/django.po b/tests/urlpatterns_reverse/translations/locale/fr/LC_MESSAGES/django.po index de1b96611ce05..efb396f901849 100644 --- a/tests/urlpatterns_reverse/translations/locale/fr/LC_MESSAGES/django.po +++ b/tests/urlpatterns_reverse/translations/locale/fr/LC_MESSAGES/django.po @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" msgid "^foo/$" msgstr "^foo-fr/$" diff --git a/tests/view_tests/locale/nl/LC_MESSAGES/django.mo b/tests/view_tests/locale/nl/LC_MESSAGES/django.mo index ef12f2ade80a2..4e8770621b18c 100644 Binary files a/tests/view_tests/locale/nl/LC_MESSAGES/django.mo and b/tests/view_tests/locale/nl/LC_MESSAGES/django.mo differ diff --git a/tests/view_tests/locale/nl/LC_MESSAGES/django.po b/tests/view_tests/locale/nl/LC_MESSAGES/django.po index 4e5f7e2fb598b..7db917a079dc2 100644 --- a/tests/view_tests/locale/nl/LC_MESSAGES/django.po +++ b/tests/view_tests/locale/nl/LC_MESSAGES/django.po @@ -15,6 +15,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #: urls.py:78 msgid "^translated/$"