Pier Angelo Vendrame pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits: ae09131d by Pier Angelo Vendrame at 2024-06-06T16:54:48+02:00 Bug 40955: Translate the Windows installer.
Define the user facing strings with LangString in languages.nsh.
- - - - - 4634a7b2 by Pier Angelo Vendrame at 2024-06-06T16:56:52+02:00 Bug 40955: Translate the Windows installer.
Add a script to add the translated strings to languages.nsh.
Currently, our localization platform (Weblate) does not support NSIS files. Therefore, we use another standard format, and, before creating the installer, we inject the translated strings to an NSIS script.
- - - - - 5ac07d83 by Pier Angelo Vendrame at 2024-06-06T16:56:53+02:00 Bug 40955: Translate the Windows installer.
Update the browser build script to apply the Windows installer localization.
- - - - -
11 changed files:
- projects/browser/build - projects/browser/config - + projects/browser/windows-installer/add-strings.py - projects/browser/windows-installer/browser-install.nsi - projects/browser/windows-installer/browser-portable.nsi - projects/browser/windows-installer/common.nsh - projects/browser/windows-installer/defines.nsh.in - + projects/browser/windows-installer/extract-strings.py - − projects/browser/windows-installer/language-map.sh - projects/browser/windows-installer/languages.nsh - rbm.conf
Changes:
===================================== projects/browser/build ===================================== @@ -296,17 +296,17 @@ done tar -C /var/tmp/dist -xf $rootdir/[% c('input_files_by_name/nsis') %] export PATH="/var/tmp/dist/nsis/bin:$PATH"
- mv $rootdir/windows-installer $distdir/windows-installer - mv $rootdir/defines.nsh $distdir/windows-installer/ + mv defines.nsh windows-installer/ [% IF !c('var/testbuild') -%] - source $distdir/windows-installer/language-map.sh supported_locales="[% tmpl(c('var/locales').join(' ')) %]" - for code in $supported_locales; do - if [[ -n ${nsis_languages[$code]} ]]; then - echo '!insertmacro MUI_LANGUAGE "'${nsis_languages[$code]}'"' >> $distdir/windows-installer/languages.nsh - fi - done + tar -xf "[% c('input_files_by_name/translation-base-browser') %]" + python3 windows-installer/add-strings.py --enable-languages translation-base-browser $supported_locales >> windows-installer/languages.nsh + [% IF c("var/mullvad-browser") -%] + tar -xf "[% c('input_files_by_name/translation-mullvad-browser') %]" + python3 windows-installer/add-strings.py translation-mullvad-browser $supported_locales >> windows-installer/languages.nsh + [% END -%] [% END -%] + mv windows-installer $distdir/windows-installer
[% IF c('var/mullvad-browser') -%] pushd $distdir/windows-installer
===================================== projects/browser/config ===================================== @@ -134,6 +134,14 @@ input_files: enable: '[% c("var/windows") %]' - filename: pe_checksum_fix.py enable: '[% c("var/windows") %]' + - project: translation + name: translation-base-browser + pkg_type: base-browser + enable: '[% c("var/windows") && !c("var/testbuild") %]' + - project: translation + name: translation-mullvad-browser + pkg_type: mullvad-browser + enable: '[% c("var/mullvad-browser") && c("var/windows") && !c("var/testbuild") %]' # To generate a new keystore, see how-to-generate-keystore.txt - filename: android-qa.keystore enable: '[% c("var/android") %]'
===================================== projects/browser/windows-installer/add-strings.py ===================================== @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +import argparse +import configparser +from pathlib import Path +import sys + + +def nsis_escape(string): + return string.replace("$", "$$").replace('"', r"$"") + + +parser = argparse.ArgumentParser() +parser.add_argument( + "--enable-languages", + action="store_true", + help="Enable the passed languages on NSIS (needs to be done only once)", +) +parser.add_argument( + "directory", + type=Path, + help="Directory where the installer strings have been extracted", +) +parser.add_argument("langs", nargs="+") +args = parser.parse_args() + +# This does not contain en-US, as en-US strings should already be in +# languages.nsh. +languages = { + "ar": "Arabic", + "ca": "Catalan", + "cs": "Czech", + "da": "Danish", + "de": "German", + "el": "Greek", + "es-ES": "Spanish", + "fa": "Farsi", + "fi": "Finnish", + "fr": "French", + "ga-IE": "ScotsGaelic", + "he": "Hebrew", + "hu": "Hungarian", + "id": "Indonesian", + "is": "Icelandic", + "it": "Italian", + "ja": "Japanese", + "ka": "Georgian", + "ko": "Korean", + "lt": "Lithuanian", + "mk": "Macedonian", + "ms": "Malay", + # Burmese not available on NSIS + # "my": "Burmese", + "nb-NO": "Norwegian", + "nl": "Dutch", + "pl": "Polish", + "pt-BR": "PortugueseBR", + "ro": "Romanian", + "ru": "Russian", + "sq": "Albanian", + "sv-SE": "Swedish", + "th": "Thai", + "tr": "Turkish", + "uk": "Ukrainian", + "vi": "Vietnamese", + "zh-CN": "SimpChinese", + "zh-TW": "TradChinese", + # Nightly-only at the moment + "be": "Belarusian", + "bg": "Bulgarian", + "pt-PT": "Portuguese", +} + +replacements = { + "min_windows_version": { + "program": "${PROJECT_NAME}", + "version": "7", + }, + "welcome_title": ("${DISPLAY_NAME}",), + "mb_intro": ("${PROJECT_NAME}",), + "standalone_description": ("${PROJECT_NAME}",), +} + + +def read_strings(code): + strings = configparser.ConfigParser(interpolation=None) + strings.read(args.directory / code / "windows-installer/strings.ini") + if "strings" not in strings: + return {} + strings = strings["strings"] + for key, value in strings.items(): + strings[key] = nsis_escape(value.replace("\n", "").replace("\r", "")) + return strings + + +strings_en = read_strings("en-US") +if not strings_en: + print("Strings not found for en-US.", file=sys.stderr) + sys.exit(1) + +for code in args.langs: + if code not in languages: + print(f"Unknown or unsupported language {code}.", file=sys.stderr) + continue + lang = languages[code] + if args.enable_languages: + print(f'!insertmacro MUI_LANGUAGE "{lang}"') + + strings = read_strings(code) + for key, string in strings_en.items(): + tr = strings.get(key) + # Use an explicit if in case the string is found but it is empty. + if tr: + string = tr + if key in replacements: + string = string % replacements[key] + print(f'LangString {key} ${{LANG_{lang}}} "{string}"') + print()
===================================== projects/browser/windows-installer/browser-install.nsi ===================================== @@ -89,7 +89,7 @@ Function SetupType Pop $0 !insertmacro MUI_INTERNAL_FULLWINDOW_LOADWIZARDIMAGE "" $0 $PLUGINSDIR${WELCOME_IMAGE} $1
- ${NSD_CreateLabel} 120u 10u 195u 28u "Welcome to the ${DISPLAY_NAME} Installer" + ${NSD_CreateLabel} 120u 10u 195u 28u "$(welcome_title)" Pop $0 SetCtlColors $0 "${MUI_TEXTCOLOR}" "${MUI_BGCOLOR}" CreateFont $2 "$(^Font)" "12" "700" @@ -99,18 +99,18 @@ Function SetupType Pop $0 SetCtlColors $0 "${MUI_TEXTCOLOR}" "${MUI_BGCOLOR}"
- ${NSD_CreateLabel} 120u 105u 195u 12u "Installation Type" + ${NSD_CreateLabel} 120u 105u 195u 12u "$(installation_type)" Pop $0 SetCtlColors $0 "" ${MUI_BGCOLOR}
${If} $existingInstall == "" - ${NSD_CreateRadioButton} 120u 117u 160u 12u "Standard" + ${NSD_CreateRadioButton} 120u 117u 160u 12u "$(standard)" Pop $typeRadioStandard ${Else} - ${NSD_CreateRadioButton} 120u 117u 160u 12u "Update current installation" + ${NSD_CreateRadioButton} 120u 117u 160u 12u "$(update_current)" Pop $typeRadioStandard ${EndIf} - ${NSD_CreateRadioButton} 120u 129u 160u 12u "Advanced" + ${NSD_CreateRadioButton} 120u 129u 160u 12u "$(advanced)" Pop $typeRadioAdvanced
SetCtlColors $typeRadioStandard "" ${MUI_BGCOLOR} @@ -149,7 +149,7 @@ Function SetupTypeUpdate ${If} $existingInstall == "" SendMessage $typeNextButton ${WM_SETTEXT} 0 "STR:$(^InstallBtn)" ${Else} - SendMessage $typeNextButton ${WM_SETTEXT} 0 "STR:&Update" + SendMessage $typeNextButton ${WM_SETTEXT} 0 "STR:$(update_button)" ${EndIf} ${EndIf} FunctionEnd @@ -170,18 +170,18 @@ Function AdvancedSetup Return ${EndIf}
- !insertmacro MUI_HEADER_TEXT "Advanced setup" "" + !insertmacro MUI_HEADER_TEXT "$(advanced_setup)" "" nsDialogs::Create 1018 Pop $0 ${If} $0 == error Abort ${EndIf}
- ${NSD_CreateCheckbox} 0 18% 100% 6% "Create a desktop shortcut" + ${NSD_CreateCheckbox} 0 18% 100% 6% "$(desktop_shortcut)" Pop $advancedCheckboxDesktop - ${NSD_CreateCheckbox} 0 30% 100% 6% "Standalone installation" + ${NSD_CreateCheckbox} 0 30% 100% 6% "$(standalone_installation)" Pop $advancedCheckboxStandalone - ${NSD_CreateLabel} 4% 37% 95% 50% "Choose the standalone installation if you want to install Mullvad Browser in its own dedicated folder, without adding it to the Start menu and to the list of applications." + ${NSD_CreateLabel} 4% 37% 95% 50% "$(standalone_description)" Pop $0 ${NSD_OnClick} $advancedCheckboxStandalone AdvancedSetupCheckboxClick ${NSD_OnClick} $advancedCheckboxDesktop AdvancedSetupCheckboxClick
===================================== projects/browser/windows-installer/browser-portable.nsi ===================================== @@ -10,7 +10,7 @@ ; Misuse the option to show the readme to create the shortcuts. ; Less ugly than MUI_PAGE_COMPONENTS. !define MUI_FINISHPAGE_SHOWREADME - !define MUI_FINISHPAGE_SHOWREADME_TEXT "&Add Start Menu && Desktop shortcuts" + !define MUI_FINISHPAGE_SHOWREADME_TEXT "$(add_shortcuts)" !define MUI_FINISHPAGE_SHOWREADME_FUNCTION "CreateShortcuts"
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckIfTargetDirectoryExists
===================================== projects/browser/windows-installer/common.nsh ===================================== @@ -62,7 +62,7 @@ ; Helper functions Function CheckRequirements ${IfNot} ${AtLeastWin7} - MessageBox MB_USERICON|MB_OK "${PROJECT_NAME} requires at least Windows 7" + MessageBox MB_USERICON|MB_OK "$(min_windows_version)" SetErrorLevel 1 Quit ${EndIf} @@ -70,7 +70,7 @@ FunctionEnd
Function CheckIfTargetDirectoryExists ${If} ${FileExists} "$INSTDIR*.*" - MessageBox MB_YESNO "The destination directory already exists. Do you want to continue anyway?" IDYES +2 + MessageBox MB_YESNO "$(destination_exists)" IDYES +2 Abort ${EndIf} FunctionEnd
===================================== projects/browser/windows-installer/defines.nsh.in ===================================== @@ -35,8 +35,7 @@ !define URL_UPDATE "https://github.com/mullvad/mullvad-browser/releases/%5B% c('var/torbrowser_version') %]" !define URL_HELP "https://mullvad.net/help/tag/browser/"
- ; TODO: This will likely be localized in the future. - !define INTRO_TEXT "Mullvad Browser is a privacy-focused web browser designed to minimize tracking and fingerprinting." + !define INTRO_TEXT "$(mb_intro)" [% ELSE -%] ; Not defined for Tor Browser !define APP_DIR "TorProject" @@ -48,5 +47,6 @@ !define URL_UPDATE "https://blog.torproject.org/new%5B% IF c('var/alpha') %]-alpha[% END %]-release-tor-browser-[% c('var/torbrowser_version') FILTER remove('.') %]" !define URL_HELP "https://tb-manual.torproject.org/"
+ ; TODO: Localize if we actually start using it. !define INTRO_TEXT "Tor Browser. Protect yourself against tracking, surveillance, and censorship." [% END -%]
===================================== projects/browser/windows-installer/extract-strings.py ===================================== @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +import re + + +with open("languages.nsh") as f: + strings = re.findall( + r'LangString (\S+) ${LANG_ENGLISH} "(.+)"$', f.read(), re.I | re.M + ) +print("[strings]") +for key, value in strings: + print(f"{key}={value}")
===================================== projects/browser/windows-installer/language-map.sh deleted ===================================== @@ -1,49 +0,0 @@ -#!/bin/bash - -# Usually NSIS uses English name with capital first letter. -# You can check the exact language names on NSIS's archive or here: -# https://sourceforge.net/p/nsis/code/HEAD/tree/NSIS/trunk/Contrib/Language%20... - -declare -A nsis_languages -nsis_languages[ar]="Arabic" -nsis_languages[ca]="Catalan" -nsis_languages[cs]="Czech" -nsis_languages[da]="Danish" -nsis_languages[de]="German" -nsis_languages[el]="Greek" -nsis_languages[es-ES]="Spanish" -nsis_languages[fa]="Farsi" -nsis_languages[fi]="Finnish" -nsis_languages[fr]="French" -nsis_languages[ga-IE]="ScotsGaelic" -nsis_languages[he]="Hebrew" -nsis_languages[hu]="Hungarian" -nsis_languages[id]="Indonesian" -nsis_languages[is]="Icelandic" -nsis_languages[it]="Italian" -nsis_languages[ja]="Japanese" -nsis_languages[ka]="Georgian" -nsis_languages[ko]="Korean" -nsis_languages[lt]="Lithuanian" -nsis_languages[mk]="Macedonian" -nsis_languages[ms]="Malay" -# nsis_languages[my]="Burmese" # Not available on NSIS -nsis_languages[nb-NO]="Norwegian" -nsis_languages[nl]="Dutch" -nsis_languages[pl]="Polish" -nsis_languages[pt-BR]="PortugueseBR" -nsis_languages[ro]="Romanian" -nsis_languages[ru]="Russian" -nsis_languages[sq]="Albanian" -nsis_languages[sv-SE]="Swedish" -nsis_languages[th]="Thai" -nsis_languages[tr]="Turkish" -nsis_languages[uk]="Ukrainian" -nsis_languages[vi]="Vietnamese" -nsis_languages[zh-CN]="SimpChinese" -nsis_languages[zh-TW]="TradChinese" - -# Currently nightly only -nsis_languages[be]="Belarusian" -nsis_languages[bg]="Bulgarian" -nsis_languages[pt-PT]="Portuguese"
===================================== projects/browser/windows-installer/languages.nsh ===================================== @@ -1,4 +1,29 @@ ;-------------------------------- ; Additional languages !insertmacro MUI_LANGUAGE "English" ; Always available - ; The rest of the languages will be added here during the build. + + ; Base Browser strings + LangString add_shortcuts ${LANG_ENGLISH} "&Add Start menu and desktop icons" + ; Use %(program)s instead of ${PROJECT_NAME} and %(version)s instead of 7 + ; when sending the string from localization. + LangString min_windows_version ${LANG_ENGLISH} "${PROJECT_NAME} requires Windows 7 or later." + LangString destination_exists ${LANG_ENGLISH} "The destination folder already exists. Do you want to continue anyway?" + + ; Mullvad Browser strings + ; Use %s instead of ${DISPLAY_NAME} for localization. + LangString welcome_title ${LANG_ENGLISH} "Welcome to the ${DISPLAY_NAME} installer" + ; Use %s instead of ${PROJECT_NAME} for localization + LangString mb_intro ${LANG_ENGLISH} "${PROJECT_NAME} is a privacy-focused web browser designed to minimize tracking and fingerprinting." + LangString installation_type ${LANG_ENGLISH} "Installation type" + LangString standard ${LANG_ENGLISH} "Standard" + LangString update_current ${LANG_ENGLISH} "Update current installation" + LangString advanced ${LANG_ENGLISH} "Advanced" + LangString update_button ${LANG_ENGLISH} "&Update" + LangString advanced_setup ${LANG_ENGLISH} "Advanced Installation" + LangString desktop_shortcut ${LANG_ENGLISH} "Add desktop icon" + LangString standalone_installation ${LANG_ENGLISH} "Standalone installation" + ; Use %s instead of ${PROJECT_NAME} for localization + LangString standalone_description ${LANG_ENGLISH} "Choose the standalone installation if you want to install ${PROJECT_NAME} in its own dedicated folder, without adding it to the Start menu and to the list of applications." + + ; The rest of the languages and translated strings will be added here by + ; add-strings.py.
===================================== rbm.conf ===================================== @@ -110,7 +110,7 @@ var: exe_name: firefox locale_ja: ja # When adding new languages, add the equivalent NSIS name to - # projects/browser/windows-installer/language-map.sh. + # projects/browser/windows-installer/add-strings.py. locales: - ar - ca
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/compare/3...