Translation (i18n)¶
REvoDesign supports multiple languages via Qt Linguist (.ts/.qm files).
The translation system is managed by LanguageSwitch in the
REvoDesign.application.i18n package.
How It Works¶
Translation sources¶
REvoDesign has three sources of translatable strings:
-
.uiwidget strings — Labels, tooltips, and menu section titles defined inREvoDesign.ui,value_dialog.ui, andlaunching.ui. These are extracted bypylupdate5and stored in.tsfiles with<location>tags. -
Python-source strings — Dynamic menu items (config-edit links, font settings, runtime tools) and dialog messages that use
_translate()in builder functions. These are hand-maintained in the.tsfiles —pylupdate5cannot reliably extract them from Python source (it does not follow aliases or resolve variables). -
YAML dialog strings —
title,banner, andreasonfields inshortcuts/registry/*.yamlare translated at display time byValueDialogvia_translate("ValueDialog", ...).reasonstrings are kept as English source on theAskedValuedataclass so that open dialogs can retranslate after a language switch.
Translator lifecycle¶
install_translator_early() (in language_settings.py) reads the saved
language from main.yaml directly and installs the translator on the
QApplication before the launching/splash page is shown, so the splash
appears in the correct language from the first paint.
When LanguageSwitch is later created during make_window(), its
constructor receives and owns that same translator directly, preventing
duplicate translator instances.
Language Files¶
Translation files live in src/REvoDesign/UI/language/:
UI/language/
├── language.json # Registry: maps language codes to display names and actions
├── eng-chs.ts # English → Chinese (Simplified) — Qt Linguist source
├── eng-chs.qm # English → Chinese (Simplified) — compiled binary
├── eng-cht.ts # English → Chinese (Traditional)
└── eng-cht.qm # English → Chinese (Traditional)
.tsfiles are XML-based Qt Linguist source files. Edit these in Qt Linguist or by hand to add or update translations..qmfiles are compiled binary translations loaded at runtime.language.jsonis the registry that maps language codes to human-readable names and PyMOL menu action IDs.
language.json format¶
Each entry maps a language code to a display name and menu action:
[
{"code": "eng-eng", "name": "English", "action": "actionEnglish"},
{"code": "eng-chs", "name": "简体中文", "action": "actionChinese"},
{"code": "eng-cht", "name": "繁體中文", "action": "actionChineseTraditional"},
{"code": "eng-fr", "name": "français", "action": "actionFrench"}
]
Not all entries require .qm files — eng-eng (English) has no translation
binary, and some registered languages may lack completed translations.
LanguageSwitch¶
LanguageSwitch (in application/i18n/language_settings.py) manages the
translator lifecycle:
- Constructor ownership — Receives the translator returned by
install_translator_early()or creates one when the saved language did not require early installation. switch_language(language)— Removes the previous translator from the application, loads the new.qmfile, installs it, callsui.retranslateUi()to refresh all static widget text, then iteratesopen_windowsand callsretranslateUi()on each window that supports it (e.g.ValueDialog). Dynamic menu items created at startup are not re-created, but theiraction_textstrings are translated at binding time via lazy builder functions (seeapplication/menu.py)._retranslate_language_actions()— Updates the dynamic language-switch menu items to show the correct language name.
Translation contexts¶
.ts context |
Source | Strings |
|---|---|---|
REvoDesignPyMOL_UI |
REvoDesign.ui + hand-maintained |
Main window, menu items |
ValueDialog |
value_dialog.ui + hand-maintained |
Dialog column headers, buttons, YAML title/banner/reason |
LaunchingPage |
launching.ui + hand-maintained |
Splash page + 10 bootstrap status messages |
ValueDialog retranslation pattern¶
ValueDialog defers translation to display time so that open dialogs
retranslate correctly after a language switch:
-
Title and banner — YAML strings are passed as raw English source from
shortcuts/utils.py.ValueDialog.__init__stores the source (_title_source_text,_banner_source_text) and translates via_tr("ValueDialog", source)only for display.retranslateUire-translates from the stored source. -
Action buttons — Each button stores its English source strings as Qt dynamic properties (
source_text,source_tooltip) in_add_field_to_table._retranslate_rowreads these properties instead of maintaining a separate objectName→source mapping, and handles both direct-QPushButtoncell widgets (Browse, Pick Color) and container-embedded buttons (JsonInput, multi-choice).
Adding a New Language¶
-
Create the
.tsfile — Use Qt Linguist orpylupdate5:pylupdate5 src/REvoDesign/UI/REvoDesign.ui src/REvoDesign/UI/value_dialog.ui src/REvoDesign/UI/launching.ui -ts src/REvoDesign/UI/language/eng-xxx.ts -
Add the new language to
language.json— Register it with a uniquecode,name, and matchingactionID:{ "code": "eng-xxx", "name": "English → New Language", "action": "actionSwitch_to_New_Language" } -
Translate — Open the
.tsfile in Qt Linguist, fill in translations for each UI string. -
Build — Compile
.ts→.qm:make translate -
Test — Restart PyMOL and switch to the new language via the menu.
Runtime Behavior¶
- The active language is stored in the config (
main.yaml) underlanguage. - On plugin startup,
install_translator_early()reads this config and loads the corresponding.qmfile before the splash dialog is shown. - When
LanguageSwitchis later initialized, it reuses the early-installed translator. - The language can be switched at runtime via Menu > Language > ....
retranslateUi()refreshes all static UI text and any openValueDialoginstances. There is no restart warning — all visible strings update immediately.- Dynamic text (e.g., mutant scores) is language-agnostic.
- Package Manager currently has no translations.
Updating Translations After UI Changes¶
When .ui files are modified:
-
Regenerate the UI typing contract:
python dev/tools/generate_ui_typing.py -
Run
make translate— this runspylupdate5on all three.uifiles to update the.tsfiles with new/changed widget strings, stripstype="obsolete"andtype="unfinished"from hand-maintained entries so they are not dropped, then compiles.ts→.qmvialrelease.
make translate
The script (tools/translate.sh) scans REvoDesign.ui, value_dialog.ui,
and launching.ui for widget strings. Dynamic-menu and dialog strings in
Python source are hand-maintained — add or update their <message> entries
directly in the .ts files.
The script uses portable sed -i.bak + rm -f (compatible with both
BSD/macOS and GNU/Linux) and iterates over .ts files via glob rather
than ls output.
Adding a new Python-source string¶
When you add a _translate() call in Python source (e.g., a new menu item
in menu.py, a dialog in language_settings.py, or a YAML reason field):
-
Add a
<message>entry by hand to botheng-chs.tsandeng-cht.tsinside the appropriate context (REvoDesignPyMOL_UI,ValueDialog, orLaunchingPage):<message> <source>Your English string</source> <translation>你的中文翻译</translation> </message> -
Omit the
<location>tag —pylupdate5will mark the entrytype="obsolete", but thesedstep intranslate.shstrips that attribute so the translation survives into the compiled.qm. -
Rebuild:
make translate
API Reference¶
For the LanguageSwitch, LanguageNameRegistry, and LanguageItem API,
see Application API.