packaging/windows: i18n the installer (auto-driven from po/<lang>.po) - #899
Merged
Merged
Conversation
This was referenced Jun 7, 2026
Closed
got3nks
force-pushed
the
feat/installer-i18n
branch
from
June 7, 2026 11:10
94eec4e to
214f7cb
Compare
The Windows installer was English-only by default -- the original afd508c commit only registered `!insertmacro MUI_LANGUAGE "English"` and inlined every section name / description / MessageBox / DetailPrint as a hardcoded English literal. Translating it required two changes: register the additional MUI_LANGUAGE entries (which pulls in NSIS's bundled translations for the Welcome / License / Components / Directory / Install / Finish pages plus all standard buttons and error dialogs "for free"), and extract the aMule-specific strings to LangString tables so they can be localized. Register MUI_LANGUAGE for all 37 catalogs in po/ that map to a NSIS bundled language file. English is registered first so it acts as the runtime fallback for any LangString entry a given language is missing. NSIS auto-detects the user's system locale at install / uninstall time and routes to the matching registered language; no picker is shown. Extract the aMule-specific user-facing strings into 16 LangString declarations (5 section names, 5 component descriptions, 6 runtime messages). Section first-args remain English literals because NSIS evaluates them at compile time -- the runtime locale is applied via SectionSetText in .onInit / un.onInit, which also keeps the magic "Uninstall" entry-point name and the `un.*` dispatch-prefix rules intact for the uninstaller block. MessageBox / DetailPrint / MUI_*_ DESCRIPTION_TEXT call sites use the LangString refs directly. Initial commit ships only the ${LANG_ENGLISH} bodies. Translators contribute additional per-${LANG_*} blocks via follow-up PRs (one block per language). A future change can autogenerate the per-language blocks from the aMule po/ catalogs so translators stay on the existing gettext workflow; that bridging script is deferred to a follow-up since it requires a small extraction stub in the source tree to make the installer strings visible to xgettext and a po-to-nsh script in packaging/windows/. Refs amule-project#897.
Follow-up to the previous commit, which registered only the 37 languages aMule has a po/ catalog for. The MUI built-in pages come from NSIS's bundled .nlf files for free for every registered language -- so capping at the po/ subset under-served users whose Windows is in a language NSIS supports but aMule's runtime app catalog doesn't. Register every language NSIS 3.x ships a Contrib/Language file for (67 entries). Users whose system language is in this broader set now get the MUI Welcome / License / Components / Directory / Install / Finish pages plus standard buttons and error dialogs in their language even if aMule has no app-level translation for it. The aMule-specific strings (the LangString block below the language registrations) continue to fall back to English for any language not represented in po/ -- NSIS's "first registered language wins for missing LangString entries" rule applies, and English remains first in the list.
Missed in the prior commit's pass over NSIS 3.x's Contrib/Language files set. The bundle ships Malagasy.nsh; the rest of the list (Armenian through Welsh) is already covered.
Adds packaging/windows/installer_strings.c -- a stub file that lists each translatable string from installer.nsi inside a _() invocation so the existing xgettext sweep over POTFILES.in picks them up into po/amule.pot. The file uses a local `#define _(s) (s)` so it parses as valid C in editors with C language servers; it is not built into any artifact. This gives translators a single workflow: they keep editing po/<lang>.po the way they do today, and the installer-specific strings now appear in their .po next to the app strings. The per-language LangString blocks for the installer are generated from the resulting msgstr entries by the bridge script added in the next commit. Add packaging/windows/installer_strings.c to po/POTFILES.in and regenerate po/amule.pot from the existing Makevars (--keyword=_ --keyword=wxTRANSLATE --keyword=wxPLURAL:1,2 --from-code=UTF-8) so the new strings are visible immediately. The bulk of the .pot diff is line-ref shifts in unchanged entries (source files moved since the last regeneration in f936bc5); the new content sits at the end and is straightforward to spot. Refs amule-project#897.
got3nks
force-pushed
the
feat/installer-i18n
branch
from
June 7, 2026 11:33
214f7cb to
60fb06e
Compare
Closes the loop from amule-project#897: translators contribute Windows installer strings the same way they contribute app strings -- by editing po/<lang>.po -- and the per-language LangString blocks for the installer are generated from those .po files at installer build time by packaging/windows/po-to-nsh.py. The bridge script: - maps each gettext locale aMule carries a po/ catalog for to the matching NSIS Contrib/Language file (Italian, French, German, ... -- table at the top of po-to-nsh.py); - parses each po/<locale>.po and matches msgstr entries against the English msgids declared as the installer string keys (the KEYS list mirrors installer_strings.c and the hand-written ${LANG_ENGLISH} block in installer.nsi); - translates standard C escapes in the msgstr (\r, \n, ", \\) into their NSIS string-literal equivalents ($\r, $\n, $\", $\\) and passes NSIS runtime variables ($INSTDIR, $0, $APPDATA) through verbatim; - emits a `LangString MYSTR_KEY ${LANG_NSISNAME} "..."` line per (key, language) pair into installer_strings_generated.nsh. Wiring: - installer.nsi `!include /NONFATAL "installer_strings_generated.nsh"` after the hand-written English LangString block. /NONFATAL means developers invoking makensis directly without going through build.sh still get a working installer (custom strings stay English for non-English languages via NSIS's first-registered-fallback). - packaging/windows/build.sh `installer` subcommand runs python3 po-to-nsh.py po/ installer_strings_generated.nsh before makensis. python3 is available in every shipping build environment (MSYS2 includes it; Linux + macOS runners ship it). - .gitignore excludes installer_strings_generated.nsh: it's a build artifact, regenerated on every installer build from the .po files. - packaging/windows/README.md grows an "Installer translations" subsection covering the auto-detect / fallback behaviour, the translator workflow (edit po/<lang>.po as normal), and the three files to update in lockstep when adding or renaming a string. Refs amule-project#897.
NSIS 3.x (as installed via Chocolatey on the CI windows-installer runner) ships 67 .nlf files under Contrib/Language files/. The initial registration list included three names that aren't in that set, so makensis aborts on the MUI_LANGUAGEEX include: Malagasy (Malagasy.nlf not in NSIS 3.x) Uyghur (Uyghur.nlf not in NSIS 3.x) Yiddish (Yiddish.nlf not in NSIS 3.x) Drop all three. Confirmed by installing NSIS via choco on a local Windows host and diffing the bundled language set against the installer's registration list. The remaining 67 entries match the NSIS bundle exactly.
xgettext defaults the comment-line copyright to the literal 'YEAR' placeholder when --package-version doesn't drive it; the prior amule.pot had it substituted to 2026. Restore that.
The windows-installer matrix on the GH Actions runner failed at `packaging/windows/build.sh installer` with 'python3: command not found'. MSYS2's `python` package ships the interpreter as `python` -- there's no `python3` symlink in the base install -- and the workflow's msys2/setup-msys2 step wasn't installing the package at all. Fix both ends: - packaging/windows/build.sh: try `python3` then `python`, pick the first that resolves; fail with a helpful pacman/apt hint if neither is available. - .github/workflows/packaging.yml: add `python` to the MSYS2 install list for the windows-installer job so the runner has it. The defensive build.sh change also covers anyone invoking the installer build outside CI (e.g. a developer on a dev Linux/macOS box where the interpreter may only be called `python`).
got3nks
force-pushed
the
feat/installer-i18n
branch
from
June 7, 2026 12:04
60fb06e to
b48d6e7
Compare
got3nks
marked this pull request as ready for review
June 7, 2026 12:31
got3nks
added a commit
to got3nks/amule
that referenced
this pull request
Jun 7, 2026
Picks up the entries left untranslated or marked fuzzy after the preceding pot/po regen pass: * po/it.po -- 14 untranslated installer-string entries (extracted from packaging/windows/installer_strings.c via amule-project#899) and 4 fuzzy entries: - 'Uninstall' had been msgmerge-mapped to the existing 'Installa' translation (wrong direction); fixed to 'Disinstalla'. - 'aMule application files (required).' had been msgmerge-mapped to the existing 'Integrazione di aMule non riuscita' translation (unrelated); fixed to the literal 'File dell'applicazione aMule (obbligatori).'. - 'Start aMule when I log in' kept the substantively correct existing translation, just unfuzzied. - The web-server-startup message updated to reference the -DBUILD_WEBSERVER=YES CMake flag we use today. * docs/man/po/manpages-it.po -- 9 untranslated entries (the new --configure-autostart / --force-zlib / -t/--category / -o-and-p optional-arg / GD-support / aMule-online-sign FILES entries from the amule-project#900 audit fixes) and 5 fuzzy entries on synopsis lines and the 'all link found' grammar fix. Refs amule-org/amule-org.github.io#4.
mrjimenez
pushed a commit
that referenced
this pull request
Jun 7, 2026
Pre-release pot/po refresh ahead of 3.0.0. Driven by scripts/update-po.sh which runs xgettext over POTFILES.in to regenerate po/amule.pot and then msgmerge into every po/*.po. The substantive change picked up by this sweep is the 16 Windows- installer translatable strings extracted into amule.pot via the packaging/windows/installer_strings.c stub added in #899 (the LangString MYSTR_* set used by packaging/windows/installer.nsi via the po-to-nsh.py bridge). Each catalog gains those 16 entries with empty msgstr; translators see them in the next .po edit session and the installer build's bridge script flips them from English fallback to the translated text as soon as a non-empty msgstr is present. The bulk of the diff outside that is cosmetic: gettext-tools 0.27 rewraps some long strings differently than whatever version last ran an update on the committed catalogs, and the #: source-location refs shift by a few lines as source files have moved on since the last sweep. No msgid content was lost; no existing translation was discarded -- fuzzy markers grow only on entries whose source string genuinely changed (e.g. man-page strings touched by the audit fixes in #900). Refs amule-org/amule-org.github.io#4 (pre-3.0.0 housekeeping).
mrjimenez
pushed a commit
that referenced
this pull request
Jun 7, 2026
Picks up the entries left untranslated or marked fuzzy after the preceding pot/po regen pass: * po/it.po -- 14 untranslated installer-string entries (extracted from packaging/windows/installer_strings.c via #899) and 4 fuzzy entries: - 'Uninstall' had been msgmerge-mapped to the existing 'Installa' translation (wrong direction); fixed to 'Disinstalla'. - 'aMule application files (required).' had been msgmerge-mapped to the existing 'Integrazione di aMule non riuscita' translation (unrelated); fixed to the literal 'File dell'applicazione aMule (obbligatori).'. - 'Start aMule when I log in' kept the substantively correct existing translation, just unfuzzied. - The web-server-startup message updated to reference the -DBUILD_WEBSERVER=YES CMake flag we use today. * docs/man/po/manpages-it.po -- 9 untranslated entries (the new --configure-autostart / --force-zlib / -t/--category / -o-and-p optional-arg / GD-support / aMule-online-sign FILES entries from the #900 audit fixes) and 5 fuzzy entries on synopsis lines and the 'all link found' grammar fix. Refs amule-org/amule-org.github.io#4.
got3nks
added a commit
to got3nks/amule
that referenced
this pull request
Jun 7, 2026
…ule-project#912) Extends existing categories (preferring extensions over new lines): - Performance/Upload: amule-project#898 SlotAllocation default raised. - Networking & Discovery: wire-parser hardening list extended with amule-project#879/amule-project#882/amule-project#890/amule-project#886; new amuleweb security hardening bullet consolidating ngosang's amule-project#869-amule-project#874 triage (all landed in amule-project#875); amulegui list extended with amule-project#857; shared-folder watcher extended with amule-project#858. - Packaging: Windows installer i18n line extended with amule-project#899. - Internals & Refactoring: new docs-polish + code-quality bullets covering amule-project#851/amule-project#855/amule-project#862/amule-project#888/amule-project#900/amule-project#866/amule-project#867/amule-project#895 and amule-project#909/amule-project#910/amule-project#912. - Translations: new pre-release final-wave bullet covering amule-project#847/amule-project#856/ amule-project#891/amule-project#908/amule-project#860/amule-project#904/amule-project#859/amule-project#863/amule-project#861/amule-project#880/amule-project#911/amule-project#901/amule-project#902/amule-project#889/amule-project#868/amule-project#853. - Bug Fixes & Stability: amule-project#850/amule-project#854/amule-project#878/amule-project#906. - CI: ccache wiring (amule-project#892, amule-project#903) + CodeQL binutils-dev (amule-project#907). Contributors footer gains mifritscher and nguyenhoangminhhieu2004-gif (both first-time contributors). PR index extended through amule-project#912.
mrjimenez
pushed a commit
that referenced
this pull request
Jun 8, 2026
Extends existing categories (preferring extensions over new lines): - Performance/Upload: #898 SlotAllocation default raised. - Networking & Discovery: wire-parser hardening list extended with #879/#882/#890/#886; new amuleweb security hardening bullet consolidating ngosang's #869-#874 triage (all landed in #875); amulegui list extended with #857; shared-folder watcher extended with #858. - Packaging: Windows installer i18n line extended with #899. - Internals & Refactoring: new docs-polish + code-quality bullets covering #851/#855/#862/#888/#900/#866/#867/#895 and #909/#910/#912. - Translations: new pre-release final-wave bullet covering #847/#856/ #891/#908/#860/#904/#859/#863/#861/#880/#911/#901/#902/#889/#868/#853. - Bug Fixes & Stability: #850/#854/#878/#906. - CI: ccache wiring (#892, #903) + CodeQL binutils-dev (#907). Contributors footer gains mifritscher and nguyenhoangminhhieu2004-gif (both first-time contributors). PR index extended through #912.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #897.
Wires the Windows installer for full i18n in three commits:
1.
installer.nsi— register all NSIS-bundled languages + extract custom strings!insertmacro MUI_LANGUAGE "..."for every language NSIS 3.x'sContrib/Language files/ships (67 entries). The Welcome / License / Components / Directory / Install / Finish pages + standard buttons + error dialogs come translated for free.LangString MYSTR_*blocks. English bodies inlined as the baseline.SectionSetTextin.onInit/un.onInit(Section first-arg is compile-time; the runtime locale is applied via this NSIS API; preserves the magic"Uninstall"entry-point andun.*dispatch rules).2.
installer_strings.c+POTFILES.in— make strings visible to xgettextpackaging/windows/installer_strings.clists each translatable string inside_("..."). Uses a local#define _(s) (s)so editors parse it cleanly; the file is never compiled.po/POTFILES.inso the existing xgettext sweep picks them up.po/amule.potregenerated — installer strings now appear next to the app strings in everypo/<lang>.poafter the nextmsgmergepass.3.
po-to-nsh.py— generate per-language LangString blocks from.popo/<locale>.po, matches msgstr entries against the English msgids of the installer string keys, translates standard C escapes (\r,\n,",\) into NSIS string-literal escapes ($\r,$\n,$\",$\\), passes NSIS runtime variables ($INSTDIR,$0,$APPDATA) through verbatim.packaging/windows/installer_strings_generated.nsh— gitignored, regenerated on every installer build.installer.nsipulls it in via!include /NONFATALafter the hand-written English block./NONFATALso developers can still invokemakensisdirectly without going throughbuild.sh.build.sh installerrunspython3 po-to-nsh.py po/ installer_strings_generated.nshbeforemakensis.packaging/windows/README.mdgrows an Installer translations subsection covering the auto-detect / fallback behaviour, the translator workflow, and the three files to update in lockstep when adding a new string.Translator workflow
Same as for app strings: edit
po/<lang>.po. The installer strings appear in the .po marked#: packaging/windows/installer_strings.c:NN. Translate them, commit. The next installer build picks them up automatically.Test plan
windows-installermatrix (x64 + arm64) compiles installer.nsi against the runner's NSIS distribution and validates that everyMUI_LANGUAGEname maps to a real.nlffile. (Initial run flaggedMalagasy.nlfmissing from the Chocolatey-installed NSIS; dropped from the list; the remaining 67 names resolved. A re-run on the head of this branch is what gates this checkbox.)