i18nPlugin icon indicating copy to clipboard operation
i18nPlugin copied to clipboard

Support for PHP's gettext()

Open lurkie opened this issue 4 years ago • 8 comments

I was drawn to this plugin to assist me in our project where we use PHP gettext() and its related *gettext() functions for translations using .po and .mo files. It seems that this plugin does not support gettext. Am I correct? If so, please consider this a feature request. If not, how should I configure this plugin for PHP gettext?

lurkie avatar Oct 22 '20 07:10 lurkie

Hi! I would implement this feature, if you give me some more details about how this should work. Could you please give some examples of .po and .mo files? What's the folder structure? How do translation keys look like? I'm not familiar with PHP, so I need help here.

Evgeniy

nyavro avatar Oct 22 '20 08:10 nyavro

Hi Evgeniy,

Fortunately, PHP is something I am familiar with :slightly_smiling_face:. I created a small demo, you can see it at my fork (fork will probably be deleted some time in the future). This commit shows a demo of gettext, and includes a few sample .mo and .po files.

The folder structure is as following. The LC_MESSAGES directory is a requirement of gettext. Here I used 'messages' as the domain.

some_resource_dir/
   |- de_DE
   |     \- LC_MESSAGES
   |         |- messages.mo
   |         \- messages.po
   |- en_US
   |     \- LC_MESSAGES
   |         |- messages.mo
   |         \- messages.po
   ...

A .po file (portable object) is a plain text file containing pairs of msgid as the key, and msgstr as the translation for singular texts. Plural texts have a msgid_plural-tag combined with multiple msgstr[n]. The msgid can be any text string in my experience. We're using the complete string as a source, but this is not a best practice (as described in this article). Using key strings which resembles the meaning is better. The .po file needs to be compiled into a binary .mo file (machine object). This can be done using the tool msgfmt. You might need to compile my example files it again as the .mo files are not intended to be portable. More info about gettext can be found at GNU's documentation.

Please note that the gettext() function has an alias: _(). In our usecase, we have __() and ___() as well, which are wrapper functions for gettext + sprintf and ngettext + sprintf combined. Using alias functions is a practice I encountered before, e.g. Magento has a __() function (although Magento does not use gettext). For this, a configurable list of functions to analyze for i18n would be great.

I hope this helps you understand how gettext works. Please let me know if you need more information.

Lurkie

lurkie avatar Oct 22 '20 13:10 lurkie

Awesome! I've grabbed your commit as pull request to nyavro:master: https://github.com/nyavro/i18nPlugin/pull/64, if you don't mind. Thanks for demo, now I got the problem. Let's see what could be done here.

nyavro avatar Oct 22 '20 17:10 nyavro

Do I get it right that for plural translations used another function, ngettext. So, ngettext also may have several aliases? And one more question: is there 1-2-5 notation for plurals? I see in examples only 1 and 2. I mean in i18next you only need to specify plurals for 1,2 and 5 items, so it picks correct translation for any number. Is it the same principle here?

nyavro avatar Oct 22 '20 18:10 nyavro

One more question. Here is how path to messages configured: 'translations/$lang/LC_MESSAGES/messages.po'. So the translation file itself is under LC_MESSAGES folder, and lang folder is LC_MESSAGES parent. Is it possible to configure the path this way: 'translations/LC_MESSAGES/$lang/messages.po' or '$lang/translations/LC_MESSAGES/messages.po'? If yes, then we need one more configuration setting.

nyavro avatar Oct 23 '20 04:10 nyavro

Have you tried this plugin? https://plugins.jetbrains.com/plugin/7123-gnu-gettext-files-support--po-

nyavro avatar Oct 23 '20 10:10 nyavro

I'm not too familiar with all the nitty-gritty details of plurals, but gettext does support plurals quite well. For example, Arabic has 6 plural forms (according to the docs), and can be configured in the .po file using 'Plural-Forms'. As long as you can specify the plural form using this kind of expressions, you should be good to go. The docs have examples for a lot of languages.

Plural-Forms: nplurals=6; \
    plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 \
    : n%100>=11 ? 4 : 5;

The *ngettext() functions have two text parameters, which should both exists in the .po (and .mo) file in the msgid and msgid_plural tags respectively. Please note that gettext as implemented in PHP has several functions to override the domain or category for a single call, the PHP manual has more info on it.

On the path layout: the structure is pretty rigid. You can select a base directory, the remaining part is fixed. Meaning: you need to work with this format: $base_dir/$language/LC_MESSAGES/$domain.po. I am not aware of any other order of path segments.

I actually have the GNU GetText files support -plugin installed, but unfortunately it only provides syntax highlighting for .po files. Which is still pretty nice to have though. The change with my example has been pushed to my fork, as I wasn't sure you want it in your repo. I have no problem if you include it.

lurkie avatar Oct 23 '20 14:10 lurkie

You made and merged a branch, awesome. Just to let you know, django(python) use same gettext/po tools.

Christophe31 avatar Jan 13 '23 13:01 Christophe31