Translate the Windows installer through Inno .isl files - #15222
Conversation
- .isl is the exchange format both ways now; the PO round-trip and polib go. - Crowdin gets two sources: custom.isl for Kolibri's own installer strings, messages.isl for Inno's stock set — the latter only reaches the languages Inno does not translate. - [Languages] and [LangOptions] are generated from definitions.py before iscc runs, so a language chains its own file only once Crowdin delivers one and no English copies need committing. - Inno's official translations resolve through compiler: at compile time; only the unofficial ones are fetched, and neither kind is committed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018QZSjPGfRnaQoBtcnt3kcS
- messages.isl skips the languages Inno translates, a list generated by generate_mapping.py from definitions.py and asserted in the config tests. - Ignore the in-context pseudo-language where downloads land under platforms/; only Kolibri itself and the plugins use it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018QZSjPGfRnaQoBtcnt3kcS
Build Artifacts
Smoke test screenshot |
🟡 Waiting for changesLast updated: 2026-08-26 19:32 UTC |
rtibblesbot
left a comment
There was a problem hiding this comment.
PR #15222 — messages.isl round-trips; CI passing.
@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly
How was this generated?
Ran a phased review pipeline over the pull request diff:
- Classified the diff to select review passes (core, frontend, backend) and whether manual QA was required
- Core review pass checked correctness, design, architecture, testing, completeness, and DRY/SRP/Rule-of-Three principles
- Specialized frontend/backend review passes applied framework-specific lenses where those files changed
- For UI changes: manual QA and an accessibility audit against a live dev server, when available
- Checked CI status and linked issue acceptance criteria
- Synthesized one review from those passes and chose the verdict from the findings, CI status, and QA evidence
|
|
||
| def write_languages(languages_path, locale_dir): | ||
| lines = [f"; Generated by {Path(__file__).name} — do not edit."] | ||
| for locale_code, definition in LANG_DEFINITIONS.items(): |
There was a problem hiding this comment.
blocking: emits ar first, where the replaced block had en. Inno falls back to index 0 (DetermineDefaultLanguage) before the language dialog, so unmatched Windows locales get an Arabic RTL installer. Emit en first, with a test.
| chain.append(inno_messages_file(definition["inno_file"])) | ||
|
|
||
| if definition.get("translate_messages"): | ||
| chain.append(translation_file(locale_code, "messages.isl", locale_dir)) |
There was a problem hiding this comment.
suggestion: es-419/pt-mz chain Crowdin over Inno's translation; Crowdin exports untranslated strings as source text by default, swapping Spanish for English.
| # definitions.py and asserted in test_i18n_desktop_crowdin.py; a code the project | ||
| # does not have as a target language fails the whole entry, which rules out `ach` | ||
| # (the in-context pseudo-language). | ||
| {"source": "/platforms/desktop-app/installer/translations/locale/en/custom.isl", "type": "ini", "dest": "/desktop_installer.isl", "update_option": "update_as_unapproved", "translation": "/platforms/desktop-app/installer/translations/locale/%locale%/custom.isl", "languages_mapping": &installer_language_mapping {"locale": {"ach": "ach-ug", "ar": "ar", "bg": "bg-bg", "bn": "bn-bd", "de": "de", "el": "el", "en": "en", "es-ES": "es-es", "fa": "fa", "fr": "fr-fr", "fv": "ff-cm", "gu-IN": "gu-in", "ha": "ha", "hi": "hi-in", "ht": "ht", "id": "id", "it": "it", "ka": "ka", "km": "km", "ko": "ko", "la": "es-419", "mr": "mr", "my": "my", "ny": "ny", "pa-IN": "pa", "pt-BR": "pt-br", "pt-mz": "pt-mz", "sw-TZ": "sw-tz", "te": "te", "uk": "uk", "ur-PK": "ur-pk", "vi": "vi", "yo": "yo", "zh-CN": "zh-hans"}}}, {"source": "/platforms/desktop-app/installer/translations/locale/en/messages.isl", "type": "ini", "dest": "/desktop_installer_messages.isl", "update_option": "update_as_unapproved", "translation": "/platforms/desktop-app/installer/translations/locale/%locale%/messages.isl", "excluded_target_languages": ["ar", "bg", "bn", "de", "el", "es-ES", "fa", "fr", "hi", "id", "it", "ka", "ko", "mr", "pt-BR", "uk", "ur-PK", "vi", "zh-CN"], "languages_mapping": *installer_language_mapping}, |
There was a problem hiding this comment.
suggestion: new dest files start empty; pre-translate from TM, archive the .po.
|
|
||
| def fetch(path, tag): | ||
| url = SOURCE_URL.format(tag=tag, path=path) | ||
| with urllib.request.urlopen(url) as response: |
There was a problem hiding this comment.
suggestion: signed builds now fetch unchecksummed text; commit inno/.
| # crowdin.yml has to be told separately, and a stale list either bills translators | ||
| # for 281 strings Inno already covers or leaves a language without any. | ||
| e = _entry("/installer/translations/locale/en/messages.isl") | ||
| assert sorted(e["excluded_target_languages"]) == get_installer_excluded_languages() |
There was a problem hiding this comment.
suggestion: a language missing from LANG_DEFINITIONS silently escapes excluded_target_languages.
| return "compiler:" + inno_file.replace("/", "\\") | ||
|
|
||
|
|
||
| def messages_files(locale_code, definition, locale_dir): |
There was a problem hiding this comment.
praise: clean chain abstraction.
Summary
References
Follows: #15079. Original issue: #15073.
Reviewer guidance
Download and run the Windows Installer. The language list should carry all 33 languages; e.g. Ukrainian shows Inno's Ukrainian wizard text with Kolibri's custom messages still in English.
AI usage
Used Claude Code to convert the installer translation pipeline to .isl, generate the [Languages] block from definitions.py, and update the Crowdin config. Verified with the desktop-app and Crowdin config test suites, prek, local review rounds, and a live upload to a Crowdin test branch.