-
Notifications
You must be signed in to change notification settings - Fork 14
Add multi-language support to Windows installer #183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add multi-language support to Windows installer #183
Conversation
12267e8 to
c22e54e
Compare
e7164e5 to
224a5ef
Compare
This commit refactors the Windows installer to support multiple languages and improves the build system's organization. User-facing strings are now externalized from `kolibri.iss` into `.isl` language files, enabling a language selection dialog on startup. All installer-related files (the script, translations, and dependencies) have been consolidated into the `installer/` directory. Major changes: - Added new translation management scripts (`create_new_language.py`, `update_from_inno_default.py`) to streamline localization. - Introduced `new-language` and `update-translations` Makefile targets to automate the translation workflow. - Updated the `Makefile` and PyInstaller spec to use the new `installer/` directory structure.
224a5ef to
8cda0e6
Compare
This commit introduces a translation workflow for the Windows installer using `.po` files. This replaces the previous method of directly editing `.isl` files, making the localization process more accessible and manageable for translators. - PO/ISL Conversion: Added `isl_to_po.py` and `po_to_isl.py` scripts to convert between Inno Setup's `.isl` format and the standard `.po` format. - Makefile Integration: - Created a `translations-export` target to generate `.po` files from existing `.isl` files for translators, using the `isl_to_po.py` script. - Added a `translations-compile` target to convert all `.po` files back into `.isl` format, using the `po_to_isl.py` script. - The `build-installer-windows` process now automatically runs `translations-compile`, ensuring the latest translations are always included in the build. - Initial German PO File: Added `German.po` to demonstrate the new workflow. - Improved Scaffolding: The `create_new_language.py` script has been updated to better handle the creation of new language files, ensuring custom messages are correctly scaffolded for translation.
c22cad8 to
462d25d
Compare
rtibbles
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this has most of the right pieces in place! Just a couple of clarifications that came to mind - and I'm not entirely sure we need all of the code here with the right workflow in place.
| @@ -0,0 +1,173 @@ | |||
| """ | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this script. The workflow we would most likely use is to take the English isl file, convert it to a po file then upload it to Crowdin (the translation platform that we use).
We would then download the translated po files for each language, and convert those to isl files for each language. I think your two conversion scripts should handle all that is needed in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
take the English isl file, convert it to a po file then upload it to Crowdin
If we don't use create_new_language.py, then the translator would have to re-translate even the standard strings that InnoSetup already provides (for languages like spanish).
Instead if we use create_new_language.py, then only the custom strings would need to be translated.
Do I miss something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Crowdin lets you upload existing translations for a source as well - so if we have the original inno translations, we can convert them to a po file for upload.
My basic thought is that I'd like us to specify which languages we want to support, and then conditionally upload already existing translations for those languages for which translations already exist. It is also possible that I'm just misreading the workflow you're intending.
| @@ -0,0 +1,305 @@ | |||
| ; Master English messages for Kolibri Installer | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be easier to use the locale code as the filename en.isl rather than the language name? Especially as we have the language name encoded in here anyway!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, create_new_language.py uses the language name (e.g. Spanish) to find the packaged translation in C:\Program Files (x86)\Inno Setup 6\Languages.
We could modify the create_new_language.py script to take a locale code as input, and then use an internal dictionary to look up the Inno Setup Filename it needs to find.
Something like that
LOCALE_TO_INNO_NAME = {
"de": "German",
"es": "Spanish",
"fr": "French",
"it": "Italian",
# ...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that works for me - we end up doing this kind of mapping quite a lot for translations, because every translation system uses something different. We use the locale (e.g. es_ES) canonically, because it is the most specific, whereas just saying "Spanish" is very ambiguous - is that Spanish from Spain, Spanish from Argentina, Spanish from Latin America?
So, essentially for each locale code that we want to support, we would also make a note of which Inno Setup language name we would pull translations from.
|
|
||
| [LangOptions] | ||
| languagename=English | ||
| languageid=$0409 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where do we find out these values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They can be found here: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c
I was thinking of adding this to the readme, when this PR is complete
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be great - I suppose we could even add this information to the locale lookup object that we're defining above:
LOCALE_INFO = {
"de": {
"inno_setup_name": "German",
"ms_languageid": "0x0007",
},
# ...
}
If we wanted to get really fancy, we could fetch the page and parse the HTML table - but that seems very unneccessary!
| [LangOptions] | ||
| languagename=English | ||
| languageid=$0409 | ||
| languagecodepage=0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does languagecodepage mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It specifies the Windows ANSI code page that the language file text is encoded in. It tells Inno Setup how to correctly read and display the localized strings if the file isn’t in Unicode (UTF-8).
However how that the files are UTF-8, its not needed.
We can either remove it when creating a new language or maybe we can leave it as is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we can be sure to encode in UTF-8 that seems like the best solution!
| @@ -0,0 +1,147 @@ | |||
| """ | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the main distinction to keep in mind is that we treat English as the "source", and all other languages as the "translations".
So, the workflow is, we upload every message we need in English in a po file - but then for some languages we will essentially have 'pre-filled' translations based on what InnoSetup already provides (either from its built in translations or community supported translations).
Summary
This PR restores multi-language support to the Windows installer, addressing a regression from our legacy version. It implements a modern, industry-standard translation workflow using .po files.
All user-facing strings have been externalized from kolibri.iss into language files. Additionally, all installer related files (the main script, translations, and dependencies) have been moved into a new
installer/directory for better organization.Changes
kolibri.issinto separate.isllanguage files, enabling a language selection dialog on startup.isl_to_po.pyandpo_to_isl.pyto convert between Inno Setup's.islformat and the universal.poformat.build-installer-windowscommand now automatically compiles all.pofiles into the required.islformat, ensuring the installer is always built with the latest translations.translations-export,translations-compile, andnew-languageto streamline the entire localization lifecycle.References
Fixes #181
Translation Workflow
Prerequisites
make dependencies).make pyinstallerto build the application.pip install polib.1. Adding a New Language (Developer Task)
This is performed once to scaffold the necessary files for a new language.
Create the Language File:
Use the
new-languageMakefile target to create a new.islfile. You need to provide the language name in English (e.g., 'Spanish', 'French'). This name will be used for the filename.This command runs the
create_new_language.pyscript, which createsinstaller/translations/Spanish.isl. The file will be pre-filled with standard Inno Setup translations if available, otherwise it will be a copy of the English template with empty values for translation.Enable the Language in the Installer Script:
Open
installer/kolibri.issand add a new entry in the[Languages]section. TheNameis a short language code, and theMessagesFilepoints to the file you just created.Commit the New Language File:
Add the newly created
Spanish.islfile and the changes tokolibri.issto Git and commit them. This establishes the new language in the codebase.2. Exporting Strings for Translation (Developer Task)
Now, you need to generate a
.pofile, which is the format that will be used in Crowdin.Run the Export Script:
Use the
translations-exporttarget. You must provide both theLANG(the filename basis, e.g., "Spanish") and theLANG_CODE(the standard locale code, e.g., "es_ES").This runs the
isl_to_po.pyscript, which reads the English source text fromEnglish.island creates a newinstaller/translations/Spanish.pofile. Themsgidfields will contain the English strings, and themsgstrfields will be empty, ready for translation.Upload the
.poFile to Crowdin:Warning
Don't know about this part
3. Translating the Content (Translator Task)
Warning
Don't know about this part either
4. Integrating Completed Translations (Developer Task)
Once translations are complete or have been updated in Crowdin, they need to be brought back into the repository.
Download the Translated
.poFile from Crowdin:Update the Local
.poFile and commit changes:installer/translations/Spanish.pofile with the newly translated version.Spanish.pofile.5. Building the Installer with the New Language (Developer Task)
This is the final step where the translated
.pofiles are automatically compiled and included in the installer.Build the Installer:
Simply run the standard build command for the Windows installer.
Automatic Compilation:
The
build-installer-windowstarget automatically runs thetranslations-compiledependency first. This process:.pofiles in theinstaller/translations/directory (including theSpanish.poyou just updated).po_to_isl.pyscript for each one..islfile (e.g.,Spanish.isl) with the latest translations from the.pofile.Test the Final Installer:
dist-installer/directory and run the setup.exe.