User:Eduralph/Sandbox/Gramps 6.0 Wiki Manual - Addon Development - Internationalization
← Previous · Index · Next →
Contents
Overview
Gramps is a highly globalized application, and addons should be fully translatable to support users worldwide. This guide covers how to prepare your addon for internationalization (i18n), manage translation strings using gettext, and package translations with your addon.
See the addon development overview for where this fits into the broader addon lifecycle.
Working example
To make strings in your addon translatable, you need to mark them using the standard translation functions, extract them into a template (.pot), and provide translations (.po).
Registration
In your *.gpr.py file, the strings you provide for name, description, etc., should use _() so they can be extracted by Gramps' build tools.
You do not need to import _ in the .gpr.py file — Gramps' plugin registration loader pre-defines it to use your locale translations. Just mark strings with _("TEXT") and supply a translation in your .po file.
# exampleaddon.gpr.py
register(
KIND,
id="ExampleAddon",
name=_("Example Addon"),
description=_("A sample addon to demonstrate internationalization."),
version="1.0.0",
gramps_target_version="6.0",
status=STABLE,
fname="exampleaddon.py",
)
Implementation
Inside your Python implementation, you must set up your addon's translation domain or use the core Gramps translation tools if contributing to the main repository.
# exampleaddon.py
import os
from gramps.gen.plug import Gramplet
# Typical setup for an external addon to manage its own translation domain
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.get_addon_translator(__file__).gettext
class ExampleAddon(Gramplet):
def init(self):
# A simple translated string
message = _("Welcome to the Example Addon!")
self.set_text(message)
def show_items(self, count):
# Using ngettext for proper pluralization
ngettext = glocale.get_addon_translator(__file__).ngettext
msg = ngettext(
"Found %d item.",
"Found %d items.",
count
) % count
print(msg)
Translating UI Files (Glade)
Gramps' addon translation tools only automatically extract and manage Python strings. If your addon uses a Glade (.ui / .glade) file for its interface, those strings will not be picked up by the standard addon translation workflow. The recommended pattern is to mark the Glade strings as translatable (so they show up for translators), then override the label at runtime from Python so they get translated through your addon's gettext domain.
Give the relevant widget a meaningful
idin the.gladefile (not the autogeneratedlabel3-style id), so your Python code can look it up:<object class="GtkLabel" id="place_name_label"> <property name="label" translatable="yes">place|Name:</property> </object>
The
place|prefix is a translator context hint (see String Marking Rules) — it tells the translator which sense of "Name" you mean, and is stripped before display.In the corresponding dialog's
__init__, override the label with the runtime-translated string:PLACE_NAME = _("place|Name:") # inside __init__: self.get_widget("place_name_label").set_label(PLACE_NAME)The exact setter depends on the widget —
GtkLabelusesset_text,GtkButtonusesset_label, etc.Re-run
make.py … initso the new string lands intemplate.pot, then translate and test.
String Marking Rules
| Function | Meaning / Usage |
|---|---|
_("...")
|
Standard string translation. Marks a string for extraction and translates it at runtime. |
N_("...")
|
Marks a string for extraction but does not translate it at runtime. Useful for defining lists of strings that will be translated later when displayed. |
ngettext("Singular", "Plural", n)
|
Translates a string while applying the correct pluralization rules for the target language based on the integer n.
|
| String") | ). The translator sees the hint in the .po file and renders only the post-pipe portion. The same _ handles it — no special function call is needed. The two-arg form _("String", "Context") works equivalently and dispatches to pgettext under the hood.
|
Canonical context example: the English word "Title" can mean the title of a book or the nobility title of a person. In many languages these need different translations. Mark them as:
_("book|Title")
_("person|Title")
Translators see the hint, drop the prefix| part, and translate the two senses independently. This is the form used throughout addons-source today; don't reach for pgettext or sgettext directly — go through _.
Note on obsolete functions: In older versions of Gramps (pre-Gramps 4), you may have seen lgettext, ugettext, lngettext, and friends. The l* variants returned strings encoded according to the current locale (bytes, not text), and the u* variants existed only to force Unicode output under Python 2. With Python 3, all strings are Unicode by default, so both families became redundant. Use _ (i.e. gettext) and ngettext — they always return translated strings as Python str. sgettext and pgettext also exist as internal helpers, but addon code should go through _.
Weblate (Gramps 6.0+)
Gramps 6.0 Weblate Workflow: Starting with Gramps 6.0 (and only 6.0), addon translations can be done collaboratively on the Gramps Weblate platform. The
Third-party Addonscomponent contains aggregated translations for every addon. If your addon is hosted in the official repository, you do not need to manually manage.pofiles.
Managing Translations Manually with make.py
If you are managing translations manually (or for older Gramps versions), the Gramps addons-source repository provides a make.py script to manage the entire lifecycle of your translations. This script relies on the standard gettext tools.
Assuming you are in the addons-source directory and your addon is named ExampleAddon, here is the workflow:
1. Extracting Strings (Template Generation)
To extract all marked strings from your Python files and generate the template.pot file:
python3 make.py gramps60 init ExampleAddon
This command parses your addon, creates necessary subdirectories (like po/), and writes the base .pot template.
2. Adding a New Language
To initialize a translation file for a specific locale (e.g., French fr):
python3 make.py gramps60 init ExampleAddon fr
This creates a new, empty po/fr-local.po file based on your template. A translator can now open this .po file in a tool like Poedit to provide translations.
3. Updating Translations
If you modify your Python code and add new strings, you must update your templates and existing language files:
python3 make.py gramps60 update ExampleAddon fr
This synchronizes the existing .po file with the latest template.pot without destroying existing translations.
4. Compiling Translations
When testing locally or preparing to package, compile the human-readable .po files into binary .mo files (which are placed in locale/<locale>/LC_MESSAGES/<addon>.mo):
python3 make.py gramps60 compile ExampleAddon
Note: To compile all projects in your local repository at once, use compile all instead of ExampleAddon.
Before committing a hand-edited .po, run a quick syntax sanity check:
msgfmt -c po/fr-local.po
This catches malformed headers, missing/mismatched format placeholders, and broken plural forms without going through the full make.py pipeline.
5. Building for Release
When your addon is ready, the build command will package everything, including the compiled translations, into a .tgz archive:
python3 make.py gramps60 build ExampleAddon
Implementation notes
- Do not use f-strings or
.format()inside the translation wrapper: Translation tools likexgettextcannot extract dynamically generated strings. You must use old-style%formatting or translate the static template string first before calling.format().- Bad:
_(f"User {name}") - Good:
_("User %s") % name
- Bad:
- Context is key: If a word can mean multiple things (e.g., "Date" as a fruit vs. "Date" as a calendar day), consider adding translation context comments so translators know how to interpret it.
- Extraction: Addons distributed in the
gramps-addonsrepository have their translation strings automatically extracted into a.potfile by the Gramps translation infrastructure.
See also
- Addon Development overview
- Coding for translation — the core-side counterpart to this page; covers conventions for marking strings in Gramps itself.
- Translating Gramps — general guidelines for translators (
.poheaders, plural forms, context, mnemonics). - Python
gettextdocumentation — primary reference forgettext,ngettext, and theGNUTranslationsclass that backs them.
|
This article's content is incomplete or a placeholder stub. |