Jump to: navigation, search

Coding for translation using weblate

8,723 bytes added, 19:49, 29 June 2021
no edit summary
An entry must also be made in the <code>_LOCALE_NAMES</code> dictionary in the [] file.
= Tips for writing a translatable Python module =
== Use complete sentences ==
Don't build up a sentence from phrases. Because a sentence is ordered in a particular way in your language does not mean that it is ordered the same way in another. Providing the entire sentence as a single unit allows the translator to make a meaningful translation. Do not concatenate phrases or terms as they will then show up as separate phrases or terms to be translated and the complete sentence may then show up incorrectly, especially in right-to-left languages (Arabic, Hebrew, <abbr title="et cetera - Latin phrase meaning 'and so on'">etc.</abbr>).
== Use named %s/%d values ==
Python provides a powerful mechanism that allows the reordering of %s values in a string. A translator may need to rearrange the structure of a sentence, and it may not match the order you chose. For example:
print "%s was born in %s" % ('Joe','Toronto')
In some languages it may make more sense to say:
print "%s is the city in which %s was born" % ('Toronto', 'Joe')
The problem is that this requires a change to the order of the arguments. Python provides a solution for this. By using named operators and dictionaries, we can say:
print "%(male_name)s was born in %(city)s" % {
'city' : 'Toronto', 'male_name' : 'Joe'}
In this case, the order of the %s formatters is not important, since the values will be looked up in the dictionary at run time to resolve the value. The translator can reorder the %s formatters, or even remove them without causing any problems.
Note that Python also allows a variation which some people find easier to read:
print "%(male_name)s was born in %(city)s" % dict(
city = 'Toronto', male_name = 'Joe')
Some languages are using right-to-left text direction. It is important to use named arguments when there is more than one %s/%d value into a translation string.
== Provide separate strings for masculine and feminine ==
Many languages have the concept of gender, while others don't. A sentence may need to be phrased differently depending on whether the subject is male or female. By using the named %s values along with a bit of code, this problem can be solved.
if person.getGender() == Person.male:
print _("%(male_name)s was born in %(city)s\n") % {
'male_name' : name, 'city' : city }
print _("%(female_name)s was born in %(city)s\n") % {
'female_name' : name, 'city' : city }
This allows languages with gender differences to map nicely into your sentence.
== Provide support for plural forms ==
Plurals are handled differently in various languages. Whilst English or German have a singular and a plural form, other languages like Turkish don't distinguish between plural or singular and there are languages which use different plurals for different numbers, <abbr title="exempli gratia - Latin phrase meaning 'for example'">e.g.</abbr>, Polish.
Gramps provides a [[Translating_Gramps#Plural_forms|plural forms]] support, useful for locales with multiples plurals according to a number (''often slavic based languages'') or for Asian family languages (''singular = plural'').
Note, some locales need singular form with [ zero] and plural form might be also used in this case.
We need to call module :
from gen.ggettext import ngettext
and code like this :
ngettext("singular %d", "plural %d", n) %n
msg = ngettext('Import Complete: %d second',
'Import Complete: %d seconds', t ) % t
== Provide a context support ==
A translator needs context for a good translation. Keep in mind you can help him/her, by using context on translation string.
We need to call module :
from gen.ggettext import sgettext as _
from gen.ggettext import sngettext as _
(if you use ngettext) # not implemented
Translation string will use context, but this will be hidden on user interface.
Translator will see the translation string and a help string without loading program.
Program will only display the string in English or with another locale.
== Object classes ==
Gramps often displays names of primary objects (''Person, Family, Event, <abbr title="et cetera - Latin phrase meaning 'and so on'">etc.</abbr> ...''), for being consistent on displayed strings (also in english!), there is a ''trans_objclass(objclass_str)'' function on TransUtils module.
So, when we need to display the primary object name in lower case into a sentence, we can use this function.
from gen.ggettext import sgettext as _
from TransUtils import trans_objclass
_("the object|See %s details") % trans_objclass(objclass)
_("the object|Make %s active") % trans_objclass('Person')
will display:
See ''the person'' details # or See ''the family, the event, <abbr title="et cetera - Latin phrase meaning 'and so on'">etc.</abbr> ...'' details
Make ''the person'' active
== Genitive form ==
Genitive (and some other) forms need to modify the name itself into some locales, like Finnish or Swedish.
Instead of "free form" text that talks about
<abbr title="exempli gratia - Latin phrase meaning 'for example'">e.g.</abbr>,
son '''of %s'''
better would be for example some tabulated format like this:
son: %s
daughter: %s
which doesn't require genitive.
== Punctuation ==
Use of commas, semicolons and spacing can be different than into english.
Remember, simple is better, maybe try to limit punctuation marks.
=== definition ===
$ python3
>>> import string
>>> print(string.punctuation)
!"#$%&'()*+,-./:;<=>[email protected][\]^_`{|}~
=== locale case ===
In French, a space is required before or after some punctuation marks and symbols, like
<pre> : ; « » ! ? % $ # .</pre>
* GtkBuilder (editors, configuration dialogs) can provide a default colon after the string without spacing,
so need some extra-testing and customization for some translators. <abbr title="exempli gratia - Latin phrase meaning 'for example'">e.g.</abbr>, in french
#: ../gramps/gen/plug/report/ ../gramps/gui/
msgid "Date format"
msgstr "Format des dates "</pre>
# comté (Canada)
#: ../gramps/gui/
#: ../gramps/gui/editors/displaytabs/
#: ../gramps/plugins/view/
msgid "State/County"
msgstr "Province/Comté "</pre>
# L'espace final est pour précéder le « : » codé en dur.
#: ../gramps/gui/
msgid "Status bar"
msgstr "Barre d'état "
== Deferred key on lists ==
In most coding situations, strings are translated where they are coded. Occasionally however, you need to mark strings for translation, but defer actual translation until later. A classic example is:
animals = ['mollusk',
'python', ]
for a in animals:
Here, you want to mark the strings in the animals list as being translatable, but you don’t actually want to translate them until they are printed.
Here is one way you can handle this situation:
def _(message): return message
animals = [_('mollusk'),
_('python'), ]
del _
for a in animals:
This works because the dummy definition of _() simply returns the string unchanged. And this dummy definition will temporarily override any definition of _() in the built-in namespace (until the del command). Take care, though if you have a previous definition of _() in the local namespace.
Note that the second use of _() will not identify “a” as being translatable to the gettext program, because the parameter is not a string literal.
Another way to handle this is with the following example:
def _T_(message): return message
animals = [_T_('mollusk'),
_T_('python'), ]
for a in animals:
In this case, you are marking translatable strings with the function _T_(), which won’t conflict with any definition of _().
See [ deferred translations]
Current custom key on gramps code is '''_T_'''. Set as xgettext flag on [ shell script] and [ python interface], generating the translation strings template.

Navigation menu