Create a JavaScript equivalent of ruby’s Nn_() gettext method
The Situation
Ideally we would be able to use something like Nn__()
in JavaScript to automatically store singular & plural translations under the same msgid
in gitlab.pot
and return them both in an array for later use in the n__()
function.
The ruby-gettext
gem already has the concept of the Nn_()
method for doing so.
The idea is that we can translate it at the time of the call to Nn__()
but doing so actually returns both translations:
const strings = Nn__('singular', 'plural'); // -> ['singular', 'plural']
const translated = n__(...strings, count);
Current Workarounds
For now we have a few different options for dealing with this shortcoming:
-
Only translate singular/plural pairs when we have access to the
count
and other variables:// everywhere we want to use the translation const translated = n__('1 item here named %{name}', '%{count} items here named %{name}', count); sprintf(translated, { count, name });
-
This approach has the disadvantage of causing us to repeat ourselves if we want to use the same translation in multiple places. We won’t be able to easily move the translated strings into reusable variables.
-
Some advantages of this approach are that it is quite compact and it keeps the strings together under the same
msgid
in thegitlab.pot
file.
-
-
❌ Manually translate the singular/plural pair twice and use a different staticcount
for each:// one time const singular = n__('1 item here named %{name}', '%{count} items here named %{name}', 1); const plural = n__('1 item here named %{name}', '%{count} items here named %{name}', 2); // elsewhere sprintf(n__(singular, plural, count), { count, name });
-
❌ Do not do this – this is an anti-pattern which bypasses the benefits of pluralize-able translation strings! -
This has the obvious immediate disadvantage of having to repeat the two strings twice, once to get the
singular
version and again to get theplural
version. This is also bad for languages which might have several pluralization forms (Russian, for example) as we’re only allowing for two and we’re hard-coding the count variable just to get the translated string, then using a different count where the string actually gets used. -
This approach maintains the advantage of keeping the two strings together under the same
msgid
in thegitlab.pot
file.
-
-
❌ Translate the strings separately:// one time const singular = __('1 item here named %{name}'); const plural = __('%{count} items here named %{name}'); // elsewhere sprintf(n__(singular, plural, count), { count, name });
-
❌ Do not do this – this is an anti-pattern which bypasses the benefits of pluralize-able translation strings! -
The main disadvantage here is that the strings are now disconnected in the
gitlab.pot
file. We can namespace them to keep them close, but they’ll always be under differentmsgid
s. The problem with this is that we lose the ability to have more pluralization options. Languages, such as Russian, have more than 2 options and when the strings are separated like this, gettext is unable to make use of those other pluralization options. -
The advantage of this approach over the first approach is that we won’t need to reiterate the actual strings everywhere we want to use them. The advantage over the second approach is that we won’t have to repeat the two strings in order to get the
singular
andplural
strings into reusable variables.
-
-
Create a function specific to the translation:
// one time const translator = (count) => n__('1 item here named %{name}', '%{count} items here named %{name}', count); // elsewhere sprintf(translator(count), { count, name });
-
A slight disadvantage here is that moving such a function into a
constants.js
file feels improper, non-semantic. That can be easily forgiven or we could adjust the name of the file to be something more semantic, likesupport.js
. -
A key advantage here is that we’re not repeating ourselves nor are we separating the strings in the
gitlab.pot
file.
-