elixir-gettext / gettext

Internationalization and localization support for Elixir.
https://hexdocs.pm/gettext
469 stars 86 forks source link

Gettext.PluralFormError for plural form "1" in "ja" locale #351

Closed woylie closed 1 year ago

woylie commented 1 year ago

I'm a bit confused about plural forms. According to the GNU Gettext documentation, the appropriate header for languages that don't distinguish between singular and plural is Plural-Forms: nplurals=1; plural=0;. So I added this to my priv/gettext/ja/LC_MESSAGES/default.po file:

msgid ""
msgstr ""
"Language: ja\n"
"Plural-Forms: nplurals=1; plural=0;\n"

Now when I run mix gettext.extract --merge, it adds this to the .po file for strings passed to ngettext/3:

msgid "There is a thing."
msgid_plural "There are %{count} things."
msgstr[0] ""

After I add a translation:

msgid "There is a thing."
msgid_plural "There are %{count} things."
msgstr[0] "ことがある"

I'm getting this error:

** (Gettext.PluralFormError) plural form 1 is required for locale "ja" but is missing for message compiled from priv/gettext/ja/LC_MESSAGES/default.po:1407
    (my_app 0.1.0) lib/my_app_web/gettext.ex:1: MyAppWeb.Gettext.ja_default_lngettext/5
    (gettext 0.22.0) lib/gettext.ex:931: Gettext.dpngettext/7
    (my_app 0.1.0) lib/my_app_web/live/thing_live/show.ex:219: anonymous fn/2 in MyWeb.ThingLive.Show.notification/1

Am I doing something wrong?

gettext 0.22.0

whatyouhide commented 1 year ago

@woylie thanks for the report! Doesn't look like you're doing anything wrong, no. ja already has plural=0 in the built-in Gettext locales, so this should work.

@maennchen do you have time to take a look at this? My cycles are busy for a few days 🙃

maennchen commented 1 year ago

@whatyouhide I should have some time to have a look on monday 👍

whatyouhide commented 1 year ago

@maennchen fantastic, thank you! 💟

maennchen commented 1 year ago

@woylie I'm unable to reproduce that myself.

Are you sure that:

If all are good, it would be very helpful if you could either:

woylie commented 1 year ago

I just set up a pristine Phoenix 1.7-rc.2 application with Gettext 0.22.0.

I noticed two other issues.

** (FunctionClauseError) no function clause matching in Expo.PO.Composer.dump_kw_and_strings/3

    The following arguments were given to Expo.PO.Composer.dump_kw_and_strings/3:

        # 1
        "msgstr"

        # 2
        []

        # 3
        []

    Attempted function clauses (showing 1 out of 1):

        defp dump_kw_and_strings(keyword, [first | rest], line_prefix)

    (expo 0.3.0) lib/expo/po/composer.ex:88: Expo.PO.Composer.dump_kw_and_strings/3
    (expo 0.3.0) lib/expo/po/composer.ex:36: Expo.PO.Composer.dump_message/1
    (elixir 1.14.2) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
    (expo 0.3.0) lib/expo/po/composer.ex:21: Expo.PO.Composer.dump_messages/1
    (gettext 0.22.0) lib/gettext/extractor.ex:240: Gettext.Extractor.merge_or_unchanged/3
    (gettext 0.22.0) lib/gettext/extractor.ex:267: Gettext.Extractor.tag_files/2
    (elixir 1.14.2) lib/enum.ex:1662: anonymous fn/3 in Enum.map/2
    (stdlib 4.1.1) maps.erl:411: :maps.fold_1/3

I fixed both by updating the plural form headers as suggested and by deleting errors.pot.

What remains is the Gettext.PluralFormError, which you can see by starting the server and opening http://localhost:4000. The error disappears after downgrading Gettext to 0.21.0. Here's the demo.

maennchen commented 1 year ago

@woylie Oh, that also shouldn’t happen. Thanks for the demo ❤️

maennchen commented 1 year ago

FYI: I had a few things standing in the way of adressing this issue in the last few days. I'll have a look until the end of the week.

maennchen commented 1 year ago

I identified the issue, one character missing :laughing:

diff --git a/lib/gettext/compiler.ex b/lib/gettext/compiler.ex
index d68e901..c0b1107 100644
--- a/lib/gettext/compiler.ex
+++ b/lib/gettext/compiler.ex
@@ -504,7 +504,7 @@ defmodule Gettext.Compiler do
     %{locale: locale, domain: domain, path: path} = po_file
     %Messages{messages: messages, file: file} = messages_struct = PO.parse_file!(path)

-    plural_forms_fun = :"{locale}_#{domain}_plural"
+    plural_forms_fun = :"#{locale}_#{domain}_plural"

     plural_forms = compile_plural_forms(locale, messages_struct, plural_mod, plural_forms_fun)
     nplurals = nplurals(locale, messages_struct, plural_mod)

I'll write a test and open a PR.

maennchen commented 1 year ago

Moved to https://github.com/elixir-gettext/gettext/issues/355#issuecomment-1433456264