How to use multiple .mo files at the same time to translate gettext?

In short, can I use a lot of .mo files in python for the same language at the same time?

In my python application, I need to use gettext for I18N. This application uses a view of the connected system. This means that you can download the plugin and put it in the appropriate directory, and it works like any other python package. The main application stores the .mo file that it uses, for example ./locale/en/LC_MESSAGES/main.mo . And plugin nr 1 has its own .mo file called plugin1.mo in the same directory.

I would use this to load main.mo I18N messages:

 gettext.install('main', './locale', unicode=False) 

How can I install others so that all plugins are translated as they should be?

The solutions I was thinking about:

Should I gettext.install() in every package namespace? But this will override the previously described _() and ruin future translations of the main application.

Is there a way to merge two .mo files into one (when a new plug-in is installed)?

At runtime, can I merge them into a single GNUTranslation object? Or override the default method _() , which is added to the global namespace? Then, how would I go with this option? Instead of _('Hello World') I would use _('plugin1', 'Hello World in plug-in 1')

Note. An application does not need to know about all the plug-ins that need to be installed, so it cannot already have all the messages translated into its main.mo file.

+4
source share
2 answers

You must use different domains for each plugin. A domain can be a package name to prevent conflicts.

I don’t understand why you need to translate something outside the plugin using the plugin domain, but if you really need to, you must change the domain every time.

Each plugin can provide it with its own "undescore", easily bound to the plugin domain:

 from my.plugin import MessageFactory as _my_plugin 

Please note that underlining is only a convention, so extraction tools may find i18n messages in the program. Plugin messages should be underlined in their respective packages (you put them in separate packages, right?). In all other places, you can call these factories by some other name and leave an underscore for the main domain of translation of the program.

I'm less sure about .mo files, but you can compile all your .po files into a single .mo file. However, if the plugins are written by independent inconsistent authors, there may be message conflicts.

UPDATE:

If the plugins are in the same package with the main application, then it makes no sense to use separate imperial domains for them (this is not your case). If the plugins are in separate packages, then for these packages you must run them yourself. In both cases, you have no problem with the variable _. If for some reason the main application wants to translate plugins into your code, use a different name for _, as in the answer. Of course, extraction tools will not identify anything other than underscores.

In other words, plugins must take care of their translations themselves. The main application can use the translation function associated with the plugins as part of the plugin API. Extracting or manually adding lines to po / mo files is also not related to the main application: its plug-in developer is provided with a translation.

+1
source

gettext.install() installs immutable and only _ in built-in functions ( __builtin__ module or builtins in py3) - app-global. Thus, there is no flexibility.
Note. Python name resolution order: locals> module-globals> builtins.

In any case, gettext.translation() (a class-based API) or even gettext.GNUTranslations() (for example, for custom .mo path schemes) will be used explicitly to simultaneously use multiple translations separately or in a mixed style.

Some options:

  • Via t = gettext.translation(...); _ = t.ugettext t = gettext.translation(...); _ = t.ugettext you can simply put individual translations as _ in each module namespace - most likely a more automated way in the real world. Perhaps the main translation can still be the built-in (via main_t.install() ).

  • When all mixed translations / all translations are approved or whatever you want, you can link multiple translations globally via t.install(); t.add_fallback(t_plugin1); t.add_fallback(t_plugin1);...; t.install(); t.add_fallback(t_plugin1); t.add_fallback(t_plugin1);...; - and keep the global approach in reverse.

  • gettext tags other than _ can be used, and can be sent via the xgettext -k other_keyword . But I do not like the long and unique names of the modules.
    (However, I personally prefer the I keyword as a whole over _ , and I also include an operator scheme like I % "some text" instead of _("some text") or I("some text") . Through I = t; t.__call__ = t.__mod__ = t.ugettext effective, plus a small pygettext patch.This template is more text-friendly, looks more readable and Pythonic for me, and avoids the critical / ugly collision of _ names in Python using the analog final- result-result-anaphor (see sys.displayhook ) when using gettext 'ed modules in Python interactive hints. _ also "reserved" as my preferred (local) for a filler for unused values ​​in expressions like _, _, x, y, z, _ = some_tuple .
    In the end, gettext is a pretty simple module and mechanism, and everything is easy to configure in Python.)

+2
source

Source: https://habr.com/ru/post/1391139/


All Articles