GNU Gettext
Is GNU's implementation of the Gettext system and also the most common translation format for libre-software. It has support for plurals, contexts, and contains a vast ecosystem of tools designed for it.
The only caveat is that Gettext does not handle how fractional values can affect plural-forms.
Gettext usually comes in two containers:
- A human-readable
.pofile for translators - A binary
.mofile for the program.
Lens provide support for both of these in the form of Gettext::POBackend and Gettext::MOBackend respectively.
Note
Lens does not currently offer any method to export .po to .mo. So an external tool would have to be used.
Using Gettext
As with all backends, the first step is to initialize it with the locale directory.
gettext_backend = Gettext::MOBackend.new("locales")
Locale files are searched with the ** glob, so feel free to nest in as many levels as you'd like.
Tip
There are no API/behavior differences between the po and mo varieties. Anything that is shown to apply to one would also apply to the other.
Now you'll just need to call the #create method:
catalogue_hash = gettext_backend.create()
Which returns a mapping of the language code, as defined via the Language header — or the file name when it isn't defined, to a Catalogue object.
Now, we can begin translating!
catalogue = catalogue_hash["en_US"]
The most basic syntax for translating strings is the #gettext method. If a translation is not found, then the original ID would be returned.
catalogue.gettext("A message") # => "Translated message"
catalogue.gettext("I don't exist") # => "I don't exist"
Pluralization
Plurals are handled through the #ngettext method. The given number is passed to the C expression from the Plural-Forms header, to compute which plural-form to use.
catalogue.ngettext("I have %d apple", "I have %d apples", 0) # => "Translated I have %d apple"
catalogue.ngettext("I have %d apple", "I have %d apples", 1) # => "Translated I have %d apples"
Context
A translation can be constrained by a specific context, and can be accessed through the #pgettext method. This is useful to avoid ambiguities with commonly seen strings.
catalogue.pgettext("CopyPasteMenu", "copy") # => "Translated copy"
catalogue.pgettext("CopyPasteMenu", "I don't exist") # => "I don't exist"
Context w/ pluralization
A context-constrained translation can also have plurals, which are accessed through the #npgettext method
catalogue.npgettext("CopyPasteMenu", "Export %d file", "Export %d files", 0) # => "Translated message with plural-form 1"
catalogue.npgettext("CopyPasteMenu", "Export %d file", "Export %d files", 1) # => "Translated message with plural-form 0"