* Add multi-language i18n support (English, Chinese, Japanese, Korean)
- Add i18n.py module for translation management via QTranslator
- Add Simplified Chinese (zh_CN), Japanese (ja_JP), and Korean (ko_KR) translations
- Integrate translation files into Qt resource system (KCC.qrc / KCC_rc.py)
- Add language switcher button in the top button bar of main window
- Language setting persists via QSettings
- Dynamic text updates work correctly after language switch
- Support %1, %2, %3 placeholders via tr_arg() helper function
- KCCGUI and KCCGUI_MetaEditor now inherit QObject for tr() support
* Complete Japanese/Korean/Chinese translations + fix language switch issues
- Fill 61 missing Japanese translations (tooltips, 3-state checkboxes, etc.)
- Fill 61 missing Korean translations (tooltips, 3-state checkboxes, etc.)
- Fill 6 missing Chinese translations
- Fix language menu: use QActionGroup for exclusive (single-select) checkmarks
- Fix jobList initial tips: refresh translations on language switch by
updating label text directly (preserves message order and user-added entries)
- Add PROJECT_I18N_README.md developer documentation
* Replace emoji language icon with PNG globe icon
Fixes PR review feedback from axu2: the emoji character doesn't render on Windows 7 (no emoji font support). Replaced with a PNG globe icon from Wikimedia Commons (CC license), loaded via Qt resource system for consistent cross-platform rendering.
* Fix RuntimeError when switching language: re-fetch labels from jobList
Previously, QLabel references were saved directly, but the underlying
C++ objects could be deleted by Qt, causing RuntimeError on access.
Now we save only source strings and re-fetch labels from jobList
items when updating, with try/except as a safety net.
* Use text label for language button instead of PNG icon
Replace the globe PNG icon with a plain text button (' 文 A ')
so its color automatically follows the system light/dark theme,
per review feedback. Removes icons/language.png and its QRC entry.
* Finalize i18n: retranslate jobList messages and translate CLI output
- Add source= to 16 GUI addMessage calls so already-shown messages retranslate on language switch
- Translate comic2ebook.py conversion/CLI messages via QCoreApplication.translate('KCCGUI', ...)
- Clear 29 unfinished WorkerThread translations (context unified to KCCGUI)
- Guard apply_language when QApplication is not yet created
- Trim dead imports and redundant code
* Avoid duplicated source strings: translate inside addMessage
Replace the self.tr/translate + source= pattern (same string written twice) with
QT_TRANSLATE_NOOP('KCCGUI', ...) at call sites; addMessage now translates internally
and stores the source text for retranslation on language switch.
- Drop the source parameter from addMessage; simplify signal to 3 args
- Include comic2ebook.py in lupdate (20 CLI/conversion messages)
* Add translation maintenance workflow
Add gen_translation_files.sh/.bat, TRANSLATION.md, and a README pointer; remove the superseded PROJECT_I18N_README.md.
* chmod +x
4.7 KiB
Translating KCC
KCC ships its UI and CLI strings in English by default, with optional translations loaded at runtime. This file documents how to keep those translations up to date when strings are added or changed.
Why translation files need maintenance
Translatable strings are wrapped in self.tr(...) or
QT_TRANSLATE_NOOP('KCCGUI', ...) in the source. The English text lives in
the code, but the actual translations live in translations/*.ts. If a new
string is added to the code and the .ts files are not regenerated, the new
string has no translation and silently falls back to English.
The .ts files are the human-editable source of truth. The .qm files are
the compiled, runtime-format translations. Both are committed to the
repository.
Prerequisites
- Python 3 with PySide6 installed in the active environment, which provides
the
pyside6-lupdate,pyside6-lrelease, andpyside6-rcctools. - Run all commands from the repository root.
Updating translations after adding a string
The whole flow is wrapped in one script:
./gen_translation_files.sh # macOS / Linux
gen_translation_files.bat # Windows
It runs three steps in order:
pyside6-lupdatescans the source files and updates everytranslations/*.tsin place.pyside6-lreleasecompiles each.tsinto its.qmruntime file.pyside6-rccre-bundles the.qmfiles intoKCC_rc.py, because the.qmfiles are loaded from the Qt resource system, not from disk.
After running the script, open the .ts files and fill in the newly added
<translation> entries. lupdate extracts strings but does not translate
them.
Manual equivalent
If you prefer to run the steps yourself, the script is equivalent to:
for ts in translations/*.ts; do
pyside6-lupdate \
kindlecomicconverter/KCC_gui.py \
kindlecomicconverter/comic2ebook.py \
gui/KCC.ui \
gui/MetaEditor.ui \
-ts "$ts"
done
for ts in translations/*.ts; do
pyside6-lrelease "$ts" -qm "${ts%.ts}.qm"
done
pyside6-rcc gui/KCC.qrc > kindlecomicconverter/KCC_rc.py
The source file list is significant. comic2ebook.py contains the CLI-side
messages; omitting it drops 20 strings (250 -> 230 extracted). The .ui
files contribute the mainWindow and editorDialog contexts.
pyside6-project is intentionally not used. Its lupdate scans the whole
project, which would pick up both gui/KCC.ui and the generated
kindlecomicconverter/KCC_ui.py and extract the mainWindow context twice.
Generated files and what to commit
| File | Generated by | Commit? |
|---|---|---|
translations/*.ts |
edited by hand (updated by lupdate) |
yes |
translations/*.qm |
pyside6-lrelease |
yes |
kindlecomicconverter/KCC_rc.py |
pyside6-rcc |
yes |
The .qm files are also embedded into KCC_rc.py via gui/KCC.qrc; both
the standalone .qm and the resource module are kept in sync by the script.
Adding a new language
- Generate the new source file:
pyside6-lupdate \ kindlecomicconverter/KCC_gui.py \ kindlecomicconverter/comic2ebook.py \ gui/KCC.ui \ gui/MetaEditor.ui \ -ts translations/kcc_xx_XX.ts - Fill in the
<translation>entries. - Register the language in
kindlecomicconverter/i18n.pyin theLANGUAGESdict. - Add the
.qmtogui/KCC.qrcunder the/i18nprefix:<file alias="kcc_xx_XX.qm">../translations/kcc_xx_XX.qm</file> - Run
gen_translation_filesto compile and re-bundle the new language.
Verifying the result
- Run the script twice: the second run should produce no further changes
(
git diffstays empty), confirming the flow is idempotent. - Launch KCC and switch languages via the language button; verify the UI, the metadata editor, and the conversion progress messages all switch.
Common problems
pyside6-lupdate: command not found— PySide6 is not installed or the virtual environment is not active. Install withpip install pyside6.- Hundreds of
<location>lines changed after runninglupdate— the-tstarget was written outsidetranslations/. Location paths are relative to the.tsfile, so always update the files in place. dropping duplicate messageswarnings fromlrelease— a.tsfile has the same(context, source)entry twice. Regenerate it withlupdate.- Some strings stay English after switching languages — the
.qmwas not re-bundled intoKCC_rc.py. Rungen_translation_files(step 3). type="vanished"entries accumulate — this is normal:lupdatemarks entries whose source string is no longer found instead of deleting them.lreleaseskips them, so they do not affect the runtime translations.