Manage translations¶
Requirements¶
python -m pip install PyQt6 # pylupdate6, the string extractor
sudo apt install qttools5-dev-tools # lrelease and Qt Linguist
pylupdate5 is not an option. It silently skips a translate() call that
black wrapped onto several lines, or whose text is written as adjacent string
literals. That was 65 of the plugin’s 455 strings when measured. pylupdate6
parses the Python itself. Qt’s own lupdate cannot read Python at all.
Which call to use¶
A tab mixin uses
translate("<MixinClass>", "…"), neverself.tr(). In a mixin,self.trisQObject.trwith the instance’s context,GeoServerMainDialog.pylupdateextracts the string under the mixin’s own class, so every lookup missed. Each mixin file aliasestranslate = QCoreApplication.translateand repeats its context at the call site, becausepylupdateonly understands a literal context. A wrapper function is not extracted at all (measured, not assumed).GeoServerMainDialog,ResourceFormDialogand the settings page are realQObjectsubclasses and keepself.tr(). A toolbelt module translates under its own literal context (ConnectionProbe,QgisExport), listed in the known contexts oftest_i18n.py.A string that the code compares, rather than only shows, must come from one place. The row-actions column label is
self.actions_column_label()on the dialog, so the comparison in_setup_tablecannot drift from the header once a locale is installed.tests/qgis/test_i18n.pyfails in four cases.A mixin goes back to
self.tr().A
translate()call names another file’s context.A new
tab_*.pyappears without being covered.The code has a string that the
.tsfile lacks.
Workflow¶
Update the
.tsfiles. Every.tsingeoserver_manager/resources/i18n/is updated in one go, and existing translations are kept:python scripts/update_translations.pyRun it after you change any user-visible string:
tests/qgis/test_i18n.pyfails when the code has a string thatgeoserver_manager_en.tslacks. To add a locale, copygeoserver_manager_en.tstogeoserver_manager_<locale>.ts, set itslanguageattribute, and run the script.Translate, in Qt Linguist or directly in the
.tsfile:linguist geoserver_manager/resources/i18n/*.tsCompile. CI does this when it packages, and the
.qmfiles are ignored by git:lrelease geoserver_manager/resources/i18n/*.ts
Counts: Qt’s plural forms, never “(s)”¶
A message that says how many of something there are goes through Qt’s
plural forms. The count is the last argument of the call, and the text says
%n where the number goes:
translate("WorkspaceTabMixin", "%n workspace(s)", None, n)
self.tr("%n item(s) could not be listed: {names}.", None, n)
pylupdate6 marks such a message numerus="yes", and each locale fills in
its own forms (English and French have two). Never build the plural from a
noun and “(s)” or + "s": that is right in no language. For the deletes, a
tab hands _delete_many its own sentences through _one_or_many, with the
plural one counted this way.
The English .ts needs the English forms too. With no translation, Qt
only puts the number in. So “%n layer(s)” would reach an English user as
“3 layer(s)”. tests/qgis/test_i18n.py fails when a plural is left
unfinished in any shipped locale.
At startup the plugin loads resources/i18n/geoserver_manager_<locale>.qm for
QGIS’s locale (plugin_main.py).