From e5472b7d476142f57fb61d2c31c814dbf34bdd06 Mon Sep 17 00:00:00 2001 From: Dimitrios Mylonas Date: Wed, 15 Oct 2025 15:55:08 +0300 Subject: [PATCH 1/4] feat(installer): Add multi-language support and refactor build process 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. --- .github/workflows/build_windows.yml | 11 +- .gitignore | 4 + Makefile | 47 ++- kolibri.iss => installer/kolibri.iss | 56 +++- installer/translations/English.isl | 305 ++++++++++++++++++ installer/translations/German.isl | 302 +++++++++++++++++ installer/translations/create_new_language.py | 147 +++++++++ .../translations/update_from_inno_default.py | 147 +++++++++ kolibri.spec | 2 +- 9 files changed, 988 insertions(+), 33 deletions(-) rename kolibri.iss => installer/kolibri.iss (88%) create mode 100644 installer/translations/English.isl create mode 100644 installer/translations/German.isl create mode 100644 installer/translations/create_new_language.py create mode 100644 installer/translations/update_from_inno_default.py diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index ddf31c3..15a7e89 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -109,12 +109,12 @@ jobs: id: get-exe-filename shell: pwsh run: | - $baseName = (Get-ChildItem -Path dist-installer -Filter *.exe).BaseName + $baseName = (Get-ChildItem -Path installer/dist-installer -Filter *.exe).BaseName $unsignedName = "$baseName-unsigned.exe" # The final name depends on whether this is a release build $finalName = if ('${{ inputs.release }}' -eq 'true') { "$baseName.exe" } else { $unsignedName } # Rename the built file to have the "-unsigned" suffix - Rename-Item -Path "dist-installer\$baseName.exe" -NewName $unsignedName + Rename-Item -Path "installer/dist-installer\$baseName.exe" -NewName $unsignedName echo "unsigned-exe-file-name=$unsignedName" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append echo "final-exe-file-name=$finalName" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append @@ -128,7 +128,7 @@ jobs: endpoint: 'https://wus2.codesigning.azure.net/' trusted-signing-account-name: 'LE-Trusted-Signing-Acct' certificate-profile-name: 'LE-Windows-Certificates' - files-folder: dist-installer + files-folder: installer/dist-installer files-folder-filter: ${{ steps.get-exe-filename.outputs.unsigned-exe-file-name }} file-digest: SHA256 timestamp-rfc3161: 'http://timestamp.acs.microsoft.com' @@ -138,11 +138,10 @@ jobs: if: ${{ inputs.release }} shell: pwsh run: | - # Only for a release, rename the file from "-unsigned.exe" to its final name after signing. - Rename-Item -Path "dist-installer\${{ steps.get-exe-filename.outputs.unsigned-exe-file-name }}" -NewName "${{ steps.get-exe-filename.outputs.final-exe-file-name }}" + Rename-Item -Path "installer/dist-installer\${{ steps.get-exe-filename.outputs.unsigned-exe-file-name }}" -NewName "${{ steps.get-exe-filename.outputs.final-exe-file-name }}" - name: Upload installer artifact uses: actions/upload-artifact@v5 with: name: ${{ steps.get-exe-filename.outputs.final-exe-file-name }} - path: dist-installer/${{ steps.get-exe-filename.outputs.final-exe-file-name }} + path: installer/dist-installer/${{ steps.get-exe-filename.outputs.final-exe-file-name }} diff --git a/.gitignore b/.gitignore index bb0af52..2be7ccd 100644 --- a/.gitignore +++ b/.gitignore @@ -136,3 +136,7 @@ whl package kolibrisrc hooks/kolibri_plugins_entrypoints_hook.py +installer/MicrosoftEdgeWebView2RuntimeInstallerX64.exe +installer/nssm.exe +update_report.txt +installer/dist-installer/ diff --git a/Makefile b/Makefile index 1c21318..35b83d2 100644 --- a/Makefile +++ b/Makefile @@ -90,13 +90,13 @@ build-dmg: needs-version .PHONY: webview2 # Download WebView2 runtime installer webview2: - @if [ ! -f MicrosoftEdgeWebView2RuntimeInstallerX64.exe ]; then \ + @if [ ! -f installer/MicrosoftEdgeWebView2RuntimeInstallerX64.exe ]; then \ echo "Downloading WebView2 full installer..."; \ ( \ - trap 'echo "Interrupted. Cleaning up..."; rm -f MicrosoftEdgeWebView2RuntimeInstallerX64.exe; exit 1' INT TERM; \ - wget https://go.microsoft.com/fwlink/?linkid=2124701 -O MicrosoftEdgeWebView2RuntimeInstallerX64.exe || { \ + trap 'echo "Interrupted. Cleaning up..."; rm -f installer/MicrosoftEdgeWebView2RuntimeInstallerX64.exe; exit 1' INT TERM; \ + wget https://go.microsoft.com/fwlink/?linkid=2124701 -O installer/MicrosoftEdgeWebView2RuntimeInstallerX64.exe || { \ echo "\Download failed. Cleaning up..."; \ - rm -f MicrosoftEdgeWebView2RuntimeInstallerX64.exe; \ + rm -f installer/MicrosoftEdgeWebView2RuntimeInstallerX64.exe; \ exit 1; \ } \ ); \ @@ -107,23 +107,23 @@ webview2: .PHONY: nssm # Download NSSM for Windows service management nssm: - @if [ ! -f nssm.exe ]; then \ + @if [ ! -f installer/nssm.exe ]; then \ echo "Downloading NSSM..."; \ ( \ - trap 'echo "Interrupted. Cleaning up..."; rm -f nssm.zip; rm -rf nssm; exit 1' INT TERM; \ - mkdir -p nssm && \ - wget https://nssm.cc/release/nssm-$(NSSM_VERSION).zip -O nssm.zip || { \ + trap 'echo "Interrupted. Cleaning up..."; rm -f installer/nssm.zip; rm -rf installer/nssm; exit 1' INT TERM; \ + mkdir -p installer/nssm && \ + wget https://nssm.cc/release/nssm-$(NSSM_VERSION).zip -O installer/nssm.zip || { \ echo "Download failed. Cleaning up..."; \ - rm -f nssm.zip; rm -rf nssm; \ + rm -f installer/nssm.zip; rm -rf installer/nssm; \ exit 1; \ }; \ - unzip -n nssm.zip -d nssm || { \ + unzip -n installer/nssm.zip -d installer/nssm || { \ echo "Unzip failed. Cleaning up..."; \ - rm -f nssm.zip; rm -rf nssm; \ + rm -f installer/nssm.zip; rm -rf installer/nssm; \ exit 1; \ }; \ - cp nssm/nssm-$(NSSM_VERSION)/win64/nssm.exe . && \ - rm -rf nssm nssm.zip \ + cp installer/nssm/nssm-$(NSSM_VERSION)/win64/nssm.exe installer/ && \ + rm -rf installer/nssm installer/nssm.zip \ ); \ else \ echo "NSSM already present."; \ @@ -135,11 +135,30 @@ build-installer-windows: needs-version nssm webview2 ifeq ($(OS),Windows_NT) # Assumes Inno Setup is installed in the default location. # MSYS_NO_PATHCONV=1 prevents Git Bash/MINGW from converting the /D flag into a file path. - MSYS_NO_PATHCONV=1 "C:\Program Files (x86)\Inno Setup 6\iscc.exe" /DAppVersion=$(KOLIBRI_VERSION) kolibri.iss + MSYS_NO_PATHCONV=1 "C:\Program Files (x86)\Inno Setup 6\iscc.exe" /DAppVersion=$(KOLIBRI_VERSION) installer/kolibri.iss else @echo "Windows installer can only be built on Windows." endif +INNO_DEFAULT_ISL ?= C:/Program Files (x86)/Inno Setup 6/Default.isl +INNO_LANGUAGES_DIR ?= C:/Program Files (x86)/Inno Setup 6/Languages + +.PHONY: new-language +new-language: + $(MAKE) guard-LANG + @echo "Creating new language scaffolding for '$(LANG)'..." + $(PYTHON_EXEC) installer/translations/create_new_language.py \ + --name "$(LANG)" \ + --inno-languages-dir "$(INNO_LANGUAGES_DIR)" + +.PHONY: update-translations +update-translations: + @echo "Updating master language file from '$(INNO_DEFAULT_ISL)'..." + $(PYTHON_EXEC) installer/translations/update_from_inno_default.py \ + --new-default "$(INNO_DEFAULT_ISL)" \ + --project-master "installer/translations/English.isl" + @echo "Update complete. Please review update_report.txt and commit the changes to English.isl." + compile-mo: find src/kolibri_app/locales -name LC_MESSAGES -exec msgfmt {}/wxapp.po -o {}/wxapp.mo \; diff --git a/kolibri.iss b/installer/kolibri.iss similarity index 88% rename from kolibri.iss rename to installer/kolibri.iss index 94f120a..e3b0189 100644 --- a/kolibri.iss +++ b/installer/kolibri.iss @@ -7,7 +7,7 @@ #ifndef AppVersion #error "The AppVersion definition must be passed to the compiler via the command line, e.g., /DAppVersion=x.y.z" #endif -#define SourceDir "dist\" + AppName + "-" + AppVersion +#define SourceDir "..\dist\" + AppName + "-" + AppVersion #define KolibriDataDir "{commonappdata}\kolibri" #define NssmExePath "{app}\nssm\nssm.exe" #define TaskkillExePath "{sys}\taskkill.exe" @@ -38,6 +38,39 @@ ArchitecturesInstallIn64BitMode=x64compatible UninstallDisplayIcon={app}\{#AppExeName} SetupLogging=yes CloseApplicationsFilter={#AppExeName} +ShowLanguageDialog=yes + +[Languages] +Name: "en"; MessagesFile: "translations\English.isl" +; Name: "af_ZA"; MessagesFile: "translations\Afrikaans.isl" +; Name: "ar"; MessagesFile: "translations\Arabic.isl" +; Name: "bg"; MessagesFile: "translations\Bulgarian.isl" +; Name: "bn"; MessagesFile: "translations\Bengali.isl" +; Name: "my"; MessagesFile: "translations\Burmese.isl" +; Name: "ny"; MessagesFile: "translations\Chewa.isl" +; Name: "zh_CN"; MessagesFile: "translations\Chinese_Simplified.isl" +Name: "de"; MessagesFile: "translations\German.isl" +; Name: "fa"; MessagesFile: "translations\Persian.isl" +; Name: "fr"; MessagesFile: "translations\French.isl" +; Name: "fv"; MessagesFile: "translations\Fulfulde_Mbororoore.isl" +; Name: "ka"; MessagesFile: "translations\Georgian.isl" +; Name: "gu_IN"; MessagesFile: "translations\Gujarati.isl" +; Name: "hi"; MessagesFile: "translations\Hindi.isl" +; Name: "it"; MessagesFile: "translations\Italian.isl" +; Name: "km"; MessagesFile: "translations\Khmer.isl" +; Name: "ko"; MessagesFile: "translations\Korean.isl" +; Name: "la"; MessagesFile: "translations\Spanish_Latin_America.isl" +; Name: "mr"; MessagesFile: "translations\Marathi.isl" +; Name: "ne_NP"; MessagesFile: "translations\Nepali.isl" +; Name: "pt_BR"; MessagesFile: "translations\Portuguese_Brazilian.isl" +; Name: "es_ES"; MessagesFile: "translations\Spanish.isl" +; Name: "sw_TZ"; MessagesFile: "translations\Swahili_Tanzania.isl" +; Name: "tl"; MessagesFile: "translations\Tagalog.isl" +; Name: "te"; MessagesFile: "translations\Telugu.isl" +; Name: "tr"; MessagesFile: "translations\Turkish.isl" +; Name: "ur_PK"; MessagesFile: "translations\Urdu_(Pakistan).isl" +; Name: "vi"; MessagesFile: "translations\Vietnamese.isl" +; Name: "yo"; MessagesFile: "translations\Yoruba.isl" [Registry] ; This registry key is used to detect the installed version for upgrades/repairs. @@ -47,7 +80,7 @@ Root: HKLM; Subkey: "Software\Kolibri"; ValueType: dword; ValueName: "ShowTrayIc Root: HKLM; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueName: "KolibriTray"; Flags: uninsdeletevalue [Tasks] -Name: "installservice"; Description: "Run Kolibri automatically when the computer starts"; GroupDescription: "Installation Type:"; +Name: "installservice"; Description: "{cm:InstallServiceTask}"; GroupDescription: "{cm:InstallationType}"; Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; [Dirs] @@ -210,14 +243,14 @@ begin begin Log('ERROR: User data migration failed. Robocopy exit code: ' + IntToStr(ResultCode)); // Even if robocopy runs but fails, we should inform the user. - MsgBox('Kolibri was unable to automatically move your user data to the new location. Please move the contents of "' + SourcePath + '" to "' + DestPath + '" manually.', mbError, MB_OK); + MsgBox(FmtMessage(CustomMessage('MigrationFailed'), [SourcePath, DestPath]), mbError, MB_OK); end end else begin // This block runs if robocopy.exe itself could not be found or executed. Log('ERROR: Failed to execute robocopy.exe. Ensure it is in the system PATH. Error code: ' + IntToStr(ResultCode)); - MsgBox('Kolibri was unable to automatically move your user data to the new location. Please move the contents of "' + SourcePath + '" to "' + DestPath + '" manually.', mbError, MB_OK); + MsgBox(FmtMessage(CustomMessage('MigrationFailed'), [SourcePath, DestPath]), mbError, MB_OK); end; end; @@ -234,14 +267,14 @@ begin // if the process fails to launch Log(Format('ERROR: Failed to launch process for "%s". System Error: %s', [Description, SysErrorMessage(ResultCode)])); if not WizardSilent() then - MsgBox(Format('A critical error occurred while trying to run a setup command: %s.'#13#10'The installation cannot continue.', [Description]), mbError, MB_OK); + MsgBox(FmtMessage(CustomMessage('CriticalError'), [Description]), mbError, MB_OK); Abort; end; if ResultCode <> 0 then begin Log(Format('ERROR: Command "%s" failed with a non-zero exit code: %d.', [Description, ResultCode])); if not WizardSilent() then - MsgBox(Format('A command required for setup failed to execute correctly: %s.'#13#10'Error Code: %d'#13#10'The installation cannot continue.', [Description, ResultCode]), mbError, MB_OK); + MsgBox(FmtMessage(CustomMessage('CommandError'), [Description, IntToStr(ResultCode)]), mbError, MB_OK); Abort; end else @@ -305,7 +338,7 @@ begin Log(Format(' -> Installer Version String: "%s"', [InstallerVersionString])); Log(Format(' -> Installed Version String: "%s"', [InstalledVersionString])); if not WizardSilent() then - MsgBox('Could not compare versions due to an invalid version format. Please uninstall the previous version manually and try again.', mbError, MB_OK); + MsgBox(CustomMessage('VersionParseError'), mbError, MB_OK); Result := False; Exit; end; @@ -319,7 +352,7 @@ begin begin Log(Format('Downgrade detected. Installed version %s is newer than installer version %s. Aborting.', [InstalledVersionString, InstallerVersionString])); if not WizardSilent() then - MsgBox(Format('A newer version of {#AppName} (%s) is already installed.' + #13#10#13#10 + 'This installer contains version %s, which is older than the installed version.' + #13#10 + 'The setup will now exit.', [InstalledVersionString, InstallerVersionString]), mbInformation, MB_OK); + MsgBox(FmtMessage(CustomMessage('NewerVersionInstalled'), [InstalledVersionString, InstallerVersionString]), mbInformation, MB_OK); Result := False; end else if VersionDiff = 0 then @@ -327,7 +360,7 @@ begin Log('Same version detected. Proposing a repair/reinstall.'); if not WizardSilent() then begin - if MsgBox('This version of {#AppName} is already installed.' + #13#10#13#10 + 'Do you want to repair the installation by reinstalling it?', mbConfirmation, MB_YESNO) <> IDYES then + if MsgBox(FmtMessage(CustomMessage('SameVersionInstalled'), ['{#AppName}']), mbConfirmation, MB_YESNO) <> IDYES then Result := False; end; end @@ -336,7 +369,7 @@ begin Log('Older version detected. Proposing an upgrade.'); if not WizardSilent() then begin - if MsgBox(Format('An older version of {#AppName} (%s) was detected.' + #13#10#13#10 + 'Do you want to upgrade to version {#AppVersion}?', [InstalledVersionString]), mbConfirmation, MB_YESNO) <> IDYES then + if MsgBox(FmtMessage(CustomMessage('OlderVersionInstalled'), [InstalledVersionString]), mbConfirmation, MB_YESNO) <> IDYES then Result := False; end; end; @@ -527,8 +560,7 @@ begin // Default to NOT deleting user data unless the user explicitly agrees. g_DeleteUserData := False; - if MsgBox('Do you want to completely remove all Kolibri user data?' + #13#10 + - 'This includes all downloaded content, user accounts, and progress, and cannot be undone.', + if MsgBox(CustomMessage('ConfirmUninstallData'), mbConfirmation, MB_YESNO) = IDYES then begin g_DeleteUserData := True; diff --git a/installer/translations/English.isl b/installer/translations/English.isl new file mode 100644 index 0000000..f63e087 --- /dev/null +++ b/installer/translations/English.isl @@ -0,0 +1,305 @@ +; Master English messages for Kolibri Installer +; Last updated: 2025-10-15T09:48:28Z + +[LangOptions] +languagename=English +languageid=$0409 +languagecodepage=0 + +[Messages] +SetupAppTitle=Setup +SetupWindowTitle=Setup - %1 +UninstallAppTitle=Uninstall +UninstallAppFullTitle=%1 Uninstall +InformationTitle=Information +ConfirmTitle=Confirm +ErrorTitle=Error +SetupLdrStartupMessage=This will install %1. Do you wish to continue? +LdrCannotCreateTemp=Unable to create a temporary file. Setup aborted +LdrCannotExecTemp=Unable to execute file in the temporary directory. Setup aborted +HelpTextNote= +LastErrorMessage=%1.%n%nError %2: %3 +SetupFileMissing=The file %1 is missing from the installation directory. Please correct the problem or obtain a new copy of the program. +SetupFileCorrupt=The setup files are corrupted. Please obtain a new copy of the program. +SetupFileCorruptOrWrongVer=The setup files are corrupted, or are incompatible with this version of Setup. Please correct the problem or obtain a new copy of the program. +InvalidParameter=An invalid parameter was passed on the command line:%n%n%1 +SetupAlreadyRunning=Setup is already running. +WindowsVersionNotSupported=This program does not support the version of Windows your computer is running. +WindowsServicePackRequired=This program requires %1 Service Pack %2 or later. +NotOnThisPlatform=This program will not run on %1. +OnlyOnThisPlatform=This program must be run on %1. +OnlyOnTheseArchitectures=This program can only be installed on versions of Windows designed for the following processor architectures:%n%n%1 +WinVersionTooLowError=This program requires %1 version %2 or later. +WinVersionTooHighError=This program cannot be installed on %1 version %2 or later. +AdminPrivilegesRequired=You must be logged in as an administrator when installing this program. +PowerUserPrivilegesRequired=You must be logged in as an administrator or as a member of the Power Users group when installing this program. +SetupAppRunningError=Setup has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit. +UninstallAppRunningError=Uninstall has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit. +PrivilegesRequiredOverrideTitle=Select Setup Install Mode +PrivilegesRequiredOverrideInstruction=Select install mode +PrivilegesRequiredOverrideText1=%1 can be installed for all users (requires administrative privileges), or for you only. +PrivilegesRequiredOverrideText2=%1 can be installed for you only, or for all users (requires administrative privileges). +PrivilegesRequiredOverrideAllUsers=Install for &all users +PrivilegesRequiredOverrideAllUsersRecommended=Install for &all users (recommended) +PrivilegesRequiredOverrideCurrentUser=Install for &me only +PrivilegesRequiredOverrideCurrentUserRecommended=Install for &me only (recommended) +ErrorCreatingDir=Setup was unable to create the directory "%1" +ErrorTooManyFilesInDir=Unable to create a file in the directory "%1" because it contains too many files +ExitSetupTitle=Exit Setup +ExitSetupMessage=Setup is not complete. If you exit now, the program will not be installed.%n%nYou may run Setup again at another time to complete the installation.%n%nExit Setup? +AboutSetupMenuItem=&About Setup... +AboutSetupTitle=About Setup +AboutSetupMessage=%1 version %2%n%3%n%n%1 home page:%n%4 +AboutSetupNote= +TranslatorNote= +ButtonBack=< &Back +ButtonNext=&Next > +ButtonInstall=&Install +ButtonOK=OK +ButtonCancel=Cancel +ButtonYes=&Yes +ButtonYesToAll=Yes to &All +ButtonNo=&No +ButtonNoToAll=N&o to All +ButtonFinish=&Finish +ButtonBrowse=&Browse... +ButtonWizardBrowse=B&rowse... +ButtonNewFolder=&Make New Folder +SelectLanguageTitle=Select Setup Language +SelectLanguageLabel=Select the language to use during the installation. +ClickNext=Click Next to continue, or Cancel to exit Setup. +BeveledLabel= +BrowseDialogTitle=Browse For Folder +BrowseDialogLabel=Select a folder in the list below, then click OK. +NewFolderName=New Folder +WelcomeLabel1=Welcome to the [name] Setup Wizard +WelcomeLabel2=This will install [name/ver] on your computer.%n%nIt is recommended that you close all other applications before continuing. +WizardPassword=Password +PasswordLabel1=This installation is password protected. +PasswordLabel3=Please provide the password, then click Next to continue. Passwords are case-sensitive. +PasswordEditLabel=&Password: +IncorrectPassword=The password you entered is not correct. Please try again. +WizardLicense=License Agreement +LicenseLabel=Please read the following important information before continuing. +LicenseLabel3=Please read the following License Agreement. You must accept the terms of this agreement before continuing with the installation. +LicenseAccepted=I &accept the agreement +LicenseNotAccepted=I &do not accept the agreement +WizardInfoBefore=Information +InfoBeforeLabel=Please read the following important information before continuing. +InfoBeforeClickLabel=When you are ready to continue with Setup, click Next. +WizardInfoAfter=Information +InfoAfterLabel=Please read the following important information before continuing. +InfoAfterClickLabel=When you are ready to continue with Setup, click Next. +WizardUserInfo=User Information +UserInfoDesc=Please enter your information. +UserInfoName=&User Name: +UserInfoOrg=&Organization: +UserInfoSerial=&Serial Number: +UserInfoNameRequired=You must enter a name. +WizardSelectDir=Select Destination Location +SelectDirDesc=Where should [name] be installed? +SelectDirLabel3=Setup will install [name] into the following folder. +SelectDirBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse. +DiskSpaceGBLabel=At least [gb] GB of free disk space is required. +DiskSpaceMBLabel=At least [mb] MB of free disk space is required. +CannotInstallToNetworkDrive=Setup cannot install to a network drive. +CannotInstallToUNCPath=Setup cannot install to a UNC path. +InvalidPath=You must enter a full path with drive letter; for example:%n%nC:\APP%n%nor a UNC path in the form:%n%n\\server\share +InvalidDrive=The drive or UNC share you selected does not exist or is not accessible. Please select another. +DiskSpaceWarningTitle=Not Enough Disk Space +DiskSpaceWarning=Setup requires at least %1 KB of free space to install, but the selected drive only has %2 KB available.%n%nDo you want to continue anyway? +DirNameTooLong=The folder name or path is too long. +InvalidDirName=The folder name is not valid. +BadDirName32=Folder names cannot include any of the following characters:%n%n%1 +DirExistsTitle=Folder Exists +DirExists=The folder:%n%n%1%n%nalready exists. Would you like to install to that folder anyway? +DirDoesntExistTitle=Folder Does Not Exist +DirDoesntExist=The folder:%n%n%1%n%ndoes not exist. Would you like the folder to be created? +WizardSelectComponents=Select Components +SelectComponentsDesc=Which components should be installed? +SelectComponentsLabel2=Select the components you want to install; clear the components you do not want to install. Click Next when you are ready to continue. +FullInstallation=Full installation +CompactInstallation=Compact installation +CustomInstallation=Custom installation +NoUninstallWarningTitle=Components Exist +NoUninstallWarning=Setup has detected that the following components are already installed on your computer:%n%n%1%n%nDeselecting these components will not uninstall them.%n%nWould you like to continue anyway? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Current selection requires at least [gb] GB of disk space. +ComponentsDiskSpaceMBLabel=Current selection requires at least [mb] MB of disk space. +WizardSelectTasks=Select Additional Tasks +SelectTasksDesc=Which additional tasks should be performed? +SelectTasksLabel2=Select the additional tasks you would like Setup to perform while installing [name], then click Next. +WizardSelectProgramGroup=Select Start Menu Folder +SelectStartMenuFolderDesc=Where should Setup place the program's shortcuts? +SelectStartMenuFolderLabel3=Setup will create the program's shortcuts in the following Start Menu folder. +SelectStartMenuFolderBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse. +MustEnterGroupName=You must enter a folder name. +GroupNameTooLong=The folder name or path is too long. +InvalidGroupName=The folder name is not valid. +BadGroupName=The folder name cannot include any of the following characters:%n%n%1 +NoProgramGroupCheck2=&Don't create a Start Menu folder +WizardReady=Ready to Install +ReadyLabel1=Setup is now ready to begin installing [name] on your computer. +ReadyLabel2a=Click Install to continue with the installation, or click Back if you want to review or change any settings. +ReadyLabel2b=Click Install to continue with the installation. +ReadyMemoUserInfo=User information: +ReadyMemoDir=Destination location: +ReadyMemoType=Setup type: +ReadyMemoComponents=Selected components: +ReadyMemoGroup=Start Menu folder: +ReadyMemoTasks=Additional tasks: +DownloadingLabel2=Downloading files... +ButtonStopDownload=&Stop download +StopDownload=Are you sure you want to stop the download? +ErrorDownloadAborted=Download aborted +ErrorDownloadFailed=Download failed: %1 %2 +ErrorDownloadSizeFailed=Getting size failed: %1 %2 +ErrorProgress=Invalid progress: %1 of %2 +ErrorFileSize=Invalid file size: expected %1, found %2 +ExtractingLabel=Extracting files... +ButtonStopExtraction=&Stop extraction +StopExtraction=Are you sure you want to stop the extraction? +ErrorExtractionAborted=Extraction aborted +ErrorExtractionFailed=Extraction failed: %1 +ArchiveIncorrectPassword=The password is incorrect +ArchiveIsCorrupted=The archive is corrupted +ArchiveUnsupportedFormat=The archive format is unsupported +WizardPreparing=Preparing to Install +PreparingDesc=Setup is preparing to install [name] on your computer. +PreviousInstallNotCompleted=The installation/removal of a previous program was not completed. You will need to restart your computer to complete that installation.%n%nAfter restarting your computer, run Setup again to complete the installation of [name]. +CannotContinue=Setup cannot continue. Please click Cancel to exit. +ApplicationsFound=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications. +ApplicationsFound2=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications. After the installation has completed, Setup will attempt to restart the applications. +CloseApplications=&Automatically close the applications +DontCloseApplications=&Do not close the applications +ErrorCloseApplications=Setup was unable to automatically close all applications. It is recommended that you close all applications using files that need to be updated by Setup before continuing. +PrepareToInstallNeedsRestart=Setup must restart your computer. After restarting your computer, run Setup again to complete the installation of [name].%n%nWould you like to restart now? +WizardInstalling=Installing +InstallingLabel=Please wait while Setup installs [name] on your computer. +FinishedHeadingLabel=Completing the [name] Setup Wizard +FinishedLabelNoIcons=Setup has finished installing [name] on your computer. +FinishedLabel=Setup has finished installing [name] on your computer. The application may be launched by selecting the installed shortcuts. +ClickFinish=Click Finish to exit Setup. +FinishedRestartLabel=To complete the installation of [name], Setup must restart your computer. Would you like to restart now? +FinishedRestartMessage=To complete the installation of [name], Setup must restart your computer.%n%nWould you like to restart now? +ShowReadmeCheck=Yes, I would like to view the README file +YesRadio=&Yes, restart the computer now +NoRadio=&No, I will restart the computer later +RunEntryExec=Run %1 +RunEntryShellExec=View %1 +ChangeDiskTitle=Setup Needs the Next Disk +SelectDiskLabel2=Please insert Disk %1 and click OK.%n%nIf the files on this disk can be found in a folder other than the one displayed below, enter the correct path or click Browse. +PathLabel=&Path: +FileNotInDir2=The file "%1" could not be located in "%2". Please insert the correct disk or select another folder. +SelectDirectoryLabel=Please specify the location of the next disk. +SetupAborted=Setup was not completed.%n%nPlease correct the problem and run Setup again. +AbortRetryIgnoreSelectAction=Select action +AbortRetryIgnoreRetry=&Try again +AbortRetryIgnoreIgnore=&Ignore the error and continue +AbortRetryIgnoreCancel=Cancel installation +RetryCancelSelectAction=Select action +RetryCancelRetry=&Try again +RetryCancelCancel=Cancel +StatusClosingApplications=Closing applications... +StatusCreateDirs=Creating directories... +StatusExtractFiles=Extracting files... +StatusDownloadFiles=Downloading files... +StatusCreateIcons=Creating shortcuts... +StatusCreateIniEntries=Creating INI entries... +StatusCreateRegistryEntries=Creating registry entries... +StatusRegisterFiles=Registering files... +StatusSavingUninstall=Saving uninstall information... +StatusRunProgram=Finishing installation... +StatusRestartingApplications=Restarting applications... +StatusRollback=Rolling back changes... +ErrorInternal2=Internal error: %1 +ErrorFunctionFailedNoCode=%1 failed +ErrorFunctionFailed=%1 failed; code %2 +ErrorFunctionFailedWithMessage=%1 failed; code %2.%n%3 +ErrorExecutingProgram=Unable to execute file:%n%1 +ErrorRegOpenKey=Error opening registry key:%n%1\%2 +ErrorRegCreateKey=Error creating registry key:%n%1\%2 +ErrorRegWriteKey=Error writing to registry key:%n%1\%2 +ErrorIniEntry=Error creating INI entry in file "%1". +FileAbortRetryIgnoreSkipNotRecommended=&Skip this file (not recommended) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignore the error and continue (not recommended) +SourceIsCorrupted=The source file is corrupted +SourceDoesntExist=The source file "%1" does not exist +SourceVerificationFailed=Verification of the source file failed: %1 +VerificationSignatureDoesntExist=The signature file "%1" does not exist +VerificationSignatureInvalid=The signature file "%1" is invalid +VerificationKeyNotFound=The signature file "%1" uses an unknown key +VerificationFileNameIncorrect=The name of the file is incorrect +VerificationFileTagIncorrect=The tag of the file is incorrect +VerificationFileSizeIncorrect=The size of the file is incorrect +VerificationFileHashIncorrect=The hash of the file is incorrect +ExistingFileReadOnly2=The existing file could not be replaced because it is marked read-only. +ExistingFileReadOnlyRetry=&Remove the read-only attribute and try again +ExistingFileReadOnlyKeepExisting=&Keep the existing file +ErrorReadingExistingDest=An error occurred while trying to read the existing file: +FileExistsSelectAction=Select action +FileExists2=The file already exists. +FileExistsOverwriteExisting=&Overwrite the existing file +FileExistsKeepExisting=&Keep the existing file +FileExistsOverwriteOrKeepAll=&Do this for the next conflicts +ExistingFileNewerSelectAction=Select action +ExistingFileNewer2=The existing file is newer than the one Setup is trying to install. +ExistingFileNewerOverwriteExisting=&Overwrite the existing file +ExistingFileNewerKeepExisting=&Keep the existing file (recommended) +ExistingFileNewerOverwriteOrKeepAll=&Do this for the next conflicts +ErrorChangingAttr=An error occurred while trying to change the attributes of the existing file: +ErrorCreatingTemp=An error occurred while trying to create a file in the destination directory: +ErrorReadingSource=An error occurred while trying to read the source file: +ErrorCopying=An error occurred while trying to copy a file: +ErrorDownloading=An error occurred while trying to download a file: +ErrorExtracting=An error occurred while trying to extract an archive: +ErrorReplacingExistingFile=An error occurred while trying to replace the existing file: +ErrorRestartReplace=RestartReplace failed: +ErrorRenamingTemp=An error occurred while trying to rename a file in the destination directory: +ErrorRegisterServer=Unable to register the DLL/OCX: %1 +ErrorRegSvr32Failed=RegSvr32 failed with exit code %1 +ErrorRegisterTypeLib=Unable to register the type library: %1 +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=All users +UninstallDisplayNameMarkCurrentUser=Current user +ErrorOpeningReadme=An error occurred while trying to open the README file. +ErrorRestartingComputer=Setup was unable to restart the computer. Please do this manually. +UninstallNotFound=File "%1" does not exist. Cannot uninstall. +UninstallOpenError=File "%1" could not be opened. Cannot uninstall +UninstallUnsupportedVer=The uninstall log file "%1" is in a format not recognized by this version of the uninstaller. Cannot uninstall +UninstallUnknownEntry=An unknown entry (%1) was encountered in the uninstall log +ConfirmUninstall=Are you sure you want to completely remove %1 and all of its components? +UninstallOnlyOnWin64=This installation can only be uninstalled on 64-bit Windows. +OnlyAdminCanUninstall=This installation can only be uninstalled by a user with administrative privileges. +UninstallStatusLabel=Please wait while %1 is removed from your computer. +UninstalledAll=%1 was successfully removed from your computer. +UninstalledMost=%1 uninstall complete.%n%nSome elements could not be removed. These can be removed manually. +UninstalledAndNeedsRestart=To complete the uninstallation of %1, your computer must be restarted.%n%nWould you like to restart now? +UninstallDataCorrupted="%1" file is corrupted. Cannot uninstall +ConfirmDeleteSharedFileTitle=Remove Shared File? +ConfirmDeleteSharedFile2=The system indicates that the following shared file is no longer in use by any programs. Would you like for Uninstall to remove this shared file?%n%nIf any programs are still using this file and it is removed, those programs may not function properly. If you are unsure, choose No. Leaving the file on your system will not cause any harm. +SharedFileNameLabel=File name: +SharedFileLocationLabel=Location: +WizardUninstalling=Uninstall Status +StatusUninstalling=Uninstalling %1... +ShutdownBlockReasonInstallingApp=Installing %1. +ShutdownBlockReasonUninstallingApp=Uninstalling %1. + +[CustomMessages] +installservicetask=Run Kolibri automatically when the computer starts +newerversioninstalled=A newer version of {#AppName} (%1) is already installed. This installer contains version %2, which is older. The setup will now exit. +sameversioninstalled=This version of %1 is already installed. Do you want to repair the installation by reinstalling it? +olderversioninstalled=An older version of {#AppName} (%1) was detected. Do you want to upgrade to version {#AppVersion}? +confirmuninstalldata=Do you want to completely remove all Kolibri user data? This includes all downloaded content, user accounts, and progress, and cannot be undone. +criticalerror=A critical error occurred while trying to run a setup command: %1. The installation cannot continue. +commanderror=A command required for setup failed to execute correctly: %1. Error Code: %2. The installation cannot continue. +versionparseerror=Could not compare versions due to an invalid version format. Please uninstall the previous version manually and try again. +migrationfailed=The installer failed to migrate user data from the old location (%1) to the new location (%2). Your data has not been moved. Please contact support for assistance. +createdesktopicon=Create a &desktop icon +additionalicons=Additional icons: +launchprogram=Launch %1 +installationtype=Installation Type: diff --git a/installer/translations/German.isl b/installer/translations/German.isl new file mode 100644 index 0000000..0cab27f --- /dev/null +++ b/installer/translations/German.isl @@ -0,0 +1,302 @@ +[LangOptions] +LanguageName=Deutsch +LanguageID=$0407 +LanguageCodePage=1252 + +[Messages] +SetupAppTitle=Setup +SetupWindowTitle=Setup - %1 +UninstallAppTitle=Entfernen +UninstallAppFullTitle=%1 entfernen +InformationTitle=Information +ConfirmTitle=Bestätigen +ErrorTitle=Fehler +SetupLdrStartupMessage=%1 wird jetzt installiert. Möchten Sie fortfahren? +LdrCannotCreateTemp=Es konnte keine temporäre Datei erstellt werden. Das Setup wurde abgebrochen +LdrCannotExecTemp=Die Datei konnte nicht im temporären Ordner ausgeführt werden. Das Setup wurde abgebrochen +HelpTextNote= +LastErrorMessage=%1.%n%nFehler %2: %3 +SetupFileMissing=Die Datei %1 fehlt im Installationsordner. Bitte beheben Sie das Problem oder besorgen Sie sich eine neue Kopie des Programms. +SetupFileCorrupt=Die Setup-Dateien sind beschädigt. Besorgen Sie sich bitte eine neue Kopie des Programms. +SetupFileCorruptOrWrongVer=Die Setup-Dateien sind beschädigt oder inkompatibel zu dieser Version des Setups. Bitte beheben Sie das Problem oder besorgen Sie sich eine neue Kopie des Programms. +InvalidParameter=Ein ungültiger Parameter wurde auf der Kommandozeile übergeben:%n%n%1 +SetupAlreadyRunning=Setup läuft bereits. +WindowsVersionNotSupported=Dieses Programm unterstützt die auf Ihrem Computer installierte Windows-Version nicht. +WindowsServicePackRequired=Dieses Programm benötigt %1 Service Pack %2 oder höher. +NotOnThisPlatform=Dieses Programm kann nicht unter %1 ausgeführt werden. +OnlyOnThisPlatform=Dieses Programm muss unter %1 ausgeführt werden. +OnlyOnTheseArchitectures=Dieses Programm kann nur auf Windows-Versionen installiert werden, die folgende Prozessor-Architekturen unterstützen:%n%n%1 +WinVersionTooLowError=Dieses Programm benötigt %1 Version %2 oder höher. +WinVersionTooHighError=Dieses Programm kann nicht unter %1 Version %2 oder höher installiert werden. +AdminPrivilegesRequired=Sie müssen als Administrator angemeldet sein, um dieses Programm installieren zu können. +PowerUserPrivilegesRequired=Sie müssen als Administrator oder als Mitglied der Hauptbenutzer-Gruppe angemeldet sein, um dieses Programm installieren zu können. +SetupAppRunningError=Das Setup hat entdeckt, dass %1 zurzeit ausgeführt wird.%n%nBitte schließen Sie jetzt alle laufenden Instanzen und klicken Sie auf "OK", um fortzufahren, oder auf "Abbrechen", um zu beenden. +UninstallAppRunningError=Die Deinstallation hat entdeckt, dass %1 zurzeit ausgeführt wird.%n%nBitte schließen Sie jetzt alle laufenden Instanzen und klicken Sie auf "OK", um fortzufahren, oder auf "Abbrechen", um zu beenden. +PrivilegesRequiredOverrideTitle=Installationsmodus auswählen +PrivilegesRequiredOverrideInstruction=Bitte wählen Sie den Installationsmodus +PrivilegesRequiredOverrideText1=%1 kann für alle Benutzer (erfordert Administrationsrechte) oder nur für Sie installiert werden. +PrivilegesRequiredOverrideText2=%1 kann nur für Sie oder für alle Benutzer (erfordert Administrationsrechte) installiert werden. +PrivilegesRequiredOverrideAllUsers=Installation für &alle Benutzer +PrivilegesRequiredOverrideAllUsersRecommended=Installation für &alle Benutzer (empfohlen) +PrivilegesRequiredOverrideCurrentUser=Installation nur für &Sie +PrivilegesRequiredOverrideCurrentUserRecommended=Installation nur für &Sie (empfohlen) +ErrorCreatingDir=Das Setup konnte den Ordner "%1" nicht erstellen. +ErrorTooManyFilesInDir=Das Setup konnte eine Datei im Ordner "%1" nicht erstellen, weil er zu viele Dateien enthält. +ExitSetupTitle=Setup verlassen +ExitSetupMessage=Das Setup ist noch nicht abgeschlossen. Wenn Sie jetzt beenden, wird das Programm nicht installiert.%n%nSie können das Setup zu einem späteren Zeitpunkt nochmals ausführen, um die Installation zu vervollständigen.%n%nSetup verlassen? +AboutSetupMenuItem=&Über das Setup ... +AboutSetupTitle=Über das Setup +AboutSetupMessage=%1 Version %2%n%3%n%n%1 Webseite:%n%4 +AboutSetupNote= +TranslatorNote=German translation maintained by Jens Brand (jens.brand@wolf-software.de) +ButtonBack=< &Zurück +ButtonNext=&Weiter > +ButtonInstall=&Installieren +ButtonOK=OK +ButtonCancel=Abbrechen +ButtonYes=&Ja +ButtonYesToAll=J&a für Alle +ButtonNo=&Nein +ButtonNoToAll=N&ein für Alle +ButtonFinish=&Fertigstellen +ButtonBrowse=&Durchsuchen ... +ButtonWizardBrowse=Du&rchsuchen ... +ButtonNewFolder=&Neuen Ordner erstellen +SelectLanguageTitle=Setup-Sprache auswählen +SelectLanguageLabel=Wählen Sie die Sprache aus, die während der Installation benutzt werden soll: +ClickNext="Weiter" zum Fortfahren, "Abbrechen" zum Verlassen. +BeveledLabel= +BrowseDialogTitle=Ordner suchen +BrowseDialogLabel=Wählen Sie einen Ordner aus und klicken Sie danach auf "OK". +NewFolderName=Neuer Ordner +WelcomeLabel1=Willkommen zum [name] Setup-Assistenten +WelcomeLabel2=Dieser Assistent wird jetzt [name/ver] auf Ihrem Computer installieren.%n%nSie sollten alle anderen Anwendungen beenden, bevor Sie mit dem Setup fortfahren. +WizardPassword=Passwort +PasswordLabel1=Diese Installation wird durch ein Passwort geschützt. +PasswordLabel3=Bitte geben Sie das Passwort ein und klicken Sie danach auf "Weiter". Achten Sie auf korrekte Groß-/Kleinschreibung. +PasswordEditLabel=&Passwort: +IncorrectPassword=Das eingegebene Passwort ist nicht korrekt. Bitte versuchen Sie es noch einmal. +WizardLicense=Lizenzvereinbarung +LicenseLabel=Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren. +LicenseLabel3=Lesen Sie bitte die folgenden Lizenzvereinbarungen. Benutzen Sie bei Bedarf die Bildlaufleiste oder drücken Sie die "Bild Ab"-Taste. +LicenseAccepted=Ich &akzeptiere die Vereinbarung +LicenseNotAccepted=Ich &lehne die Vereinbarung ab +WizardInfoBefore=Information +InfoBeforeLabel=Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren. +InfoBeforeClickLabel=Klicken Sie auf "Weiter", sobald Sie bereit sind, mit dem Setup fortzufahren. +WizardInfoAfter=Information +InfoAfterLabel=Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren. +InfoAfterClickLabel=Klicken Sie auf "Weiter", sobald Sie bereit sind, mit dem Setup fortzufahren. +WizardUserInfo=Benutzerinformationen +UserInfoDesc=Bitte tragen Sie Ihre Daten ein. +UserInfoName=&Name: +UserInfoOrg=&Organisation: +UserInfoSerial=&Seriennummer: +UserInfoNameRequired=Sie müssen einen Namen eintragen. +WizardSelectDir=Ziel-Ordner wählen +SelectDirDesc=Wohin soll [name] installiert werden? +SelectDirLabel3=Das Setup wird [name] in den folgenden Ordner installieren. +SelectDirBrowseLabel=Klicken Sie auf "Weiter", um fortzufahren. Klicken Sie auf "Durchsuchen", falls Sie einen anderen Ordner auswählen möchten. +DiskSpaceGBLabel=Mindestens [gb] GB freier Speicherplatz ist erforderlich. +DiskSpaceMBLabel=Mindestens [mb] MB freier Speicherplatz ist erforderlich. +CannotInstallToNetworkDrive=Das Setup kann nicht in einen Netzwerk-Pfad installieren. +CannotInstallToUNCPath=Das Setup kann nicht in einen UNC-Pfad installieren. Wenn Sie auf ein Netzlaufwerk installieren möchten, müssen Sie dem Netzwerkpfad einen Laufwerksbuchstaben zuordnen. +InvalidPath=Sie müssen einen vollständigen Pfad mit einem Laufwerksbuchstaben angeben, z. B.:%n%nC:\Beispiel%n%noder einen UNC-Pfad in der Form:%n%n\\Server\Freigabe +InvalidDrive=Das angegebene Laufwerk bzw. der UNC-Pfad existiert nicht oder es kann nicht darauf zugegriffen werden. Wählen Sie bitte einen anderen Ordner. +DiskSpaceWarningTitle=Nicht genug freier Speicherplatz +DiskSpaceWarning=Das Setup benötigt mindestens %1 KB freien Speicherplatz zum Installieren, aber auf dem ausgewählten Laufwerk sind nur %2 KB verfügbar.%n%nMöchten Sie trotzdem fortfahren? +DirNameTooLong=Der Ordnername/Pfad ist zu lang. +InvalidDirName=Der Ordnername ist nicht gültig. +BadDirName32=Ordnernamen dürfen keine der folgenden Zeichen enthalten:%n%n%1 +DirExistsTitle=Ordner existiert bereits +DirExists=Der Ordner:%n%n%1%n%n existiert bereits. Möchten Sie trotzdem in diesen Ordner installieren? +DirDoesntExistTitle=Ordner ist nicht vorhanden +DirDoesntExist=Der Ordner:%n%n%1%n%nist nicht vorhanden. Soll der Ordner erstellt werden? +WizardSelectComponents=Komponenten auswählen +SelectComponentsDesc=Welche Komponenten sollen installiert werden? +SelectComponentsLabel2=Wählen Sie die Komponenten aus, die Sie installieren möchten. Klicken Sie auf "Weiter", wenn Sie bereit sind, fortzufahren. +FullInstallation=Vollständige Installation +CompactInstallation=Kompakte Installation +CustomInstallation=Benutzerdefinierte Installation +NoUninstallWarningTitle=Komponenten vorhanden +NoUninstallWarning=Das Setup hat festgestellt, dass die folgenden Komponenten bereits auf Ihrem Computer installiert sind:%n%n%1%n%nDiese nicht mehr ausgewählten Komponenten werden nicht vom Computer entfernt.%n%nMöchten Sie trotzdem fortfahren? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Die aktuelle Auswahl erfordert mindestens [gb] GB Speicherplatz. +ComponentsDiskSpaceMBLabel=Die aktuelle Auswahl erfordert mindestens [mb] MB Speicherplatz. +WizardSelectTasks=Zusätzliche Aufgaben auswählen +SelectTasksDesc=Welche zusätzlichen Aufgaben sollen ausgeführt werden? +SelectTasksLabel2=Wählen Sie die zusätzlichen Aufgaben aus, die das Setup während der Installation von [name] ausführen soll, und klicken Sie danach auf "Weiter". +WizardSelectProgramGroup=Startmenü-Ordner auswählen +SelectStartMenuFolderDesc=Wo soll das Setup die Programm-Verknüpfungen erstellen? +SelectStartMenuFolderLabel3=Das Setup wird die Programm-Verknüpfungen im folgenden Startmenü-Ordner erstellen. +SelectStartMenuFolderBrowseLabel=Klicken Sie auf "Weiter", um fortzufahren. Klicken Sie auf "Durchsuchen", falls Sie einen anderen Ordner auswählen möchten. +MustEnterGroupName=Sie müssen einen Ordnernamen eingeben. +GroupNameTooLong=Der Ordnername/Pfad ist zu lang. +InvalidGroupName=Der Ordnername ist nicht gültig. +BadGroupName=Der Ordnername darf keine der folgenden Zeichen enthalten:%n%n%1 +NoProgramGroupCheck2=&Keinen Ordner im Startmenü erstellen +WizardReady=Bereit zur Installation. +ReadyLabel1=Das Setup ist jetzt bereit, [name] auf Ihrem Computer zu installieren. +ReadyLabel2a=Klicken Sie auf "Installieren", um mit der Installation zu beginnen, oder auf "Zurück", um Ihre Einstellungen zu überprüfen oder zu ändern. +ReadyLabel2b=Klicken Sie auf "Installieren", um mit der Installation zu beginnen. +ReadyMemoUserInfo=Benutzerinformationen: +ReadyMemoDir=Ziel-Ordner: +ReadyMemoType=Setup-Typ: +ReadyMemoComponents=Ausgewählte Komponenten: +ReadyMemoGroup=Startmenü-Ordner: +ReadyMemoTasks=Zusätzliche Aufgaben: +DownloadingLabel2=Lade Dateien herunter... +ButtonStopDownload=Download &abbrechen +StopDownload=Sind Sie sicher, dass Sie den Download abbrechen wollen? +ErrorDownloadAborted=Download abgebrochen +ErrorDownloadFailed=Download fehlgeschlagen: %1 %2 +ErrorDownloadSizeFailed=Fehler beim Ermitteln der Größe: %1 %2 +ErrorProgress=Ungültiger Fortschritt: %1 von %2 +ErrorFileSize=Ungültige Dateigröße: erwartet %1, gefunden %2 +ExtractingLabel=Entpacke Dateien... +ButtonStopExtraction=Entpacken &abbrechen +StopExtraction=Sind Sie sicher, dass Sie das Entpacken abbrechen wollen? +ErrorExtractionAborted=Entpacken abgebrochen +ErrorExtractionFailed=Entpacken fehlgeschlagen: %1 +ArchiveIncorrectPassword=Ungültiges Passwort +ArchiveIsCorrupted=Das Archiv ist defekt +ArchiveUnsupportedFormat=Das Archivformat wird nicht unterstützt +WizardPreparing=Vorbereitung der Installation +PreparingDesc=Das Setup bereitet die Installation von [name] auf diesem Computer vor. +PreviousInstallNotCompleted=Eine vorherige Installation/Deinstallation eines Programms wurde nicht abgeschlossen. Der Computer muss neu gestartet werden, um die Installation/Deinstallation zu beenden.%n%nStarten Sie das Setup nach dem Neustart Ihres Computers erneut, um die Installation von [name] durchzuführen. +CannotContinue=Das Setup kann nicht fortfahren. Bitte klicken Sie auf "Abbrechen" zum Verlassen. +ApplicationsFound=Die folgenden Anwendungen benutzen Dateien, die aktualisiert werden müssen. Es wird empfohlen, Setup zu erlauben, diese Anwendungen zu schließen. +ApplicationsFound2=Die folgenden Anwendungen benutzen Dateien, die aktualisiert werden müssen. Es wird empfohlen, Setup zu erlauben, diese Anwendungen zu schließen. Nachdem die Installation fertiggestellt wurde, versucht Setup, diese Anwendungen wieder zu starten. +CloseApplications=&Schließe die Anwendungen automatisch +DontCloseApplications=Schließe die A&nwendungen nicht +ErrorCloseApplications=Das Setup konnte nicht alle Anwendungen automatisch schließen. Es wird empfohlen, alle Anwendungen zu schließen, die Dateien benutzen, die vom Setup vor einer Fortsetzung aktualisiert werden müssen. +PrepareToInstallNeedsRestart=Das Setup muss Ihren Computer neu starten. Führen Sie nach dem Neustart Setup erneut aus, um die Installation von [name] abzuschließen.%n%nWollen Sie jetzt neu starten? +WizardInstalling=Installiere ... +InstallingLabel=Warten Sie bitte, während [name] auf Ihrem Computer installiert wird. +FinishedHeadingLabel=Beenden des [name] Setup-Assistenten +FinishedLabelNoIcons=Das Setup hat die Installation von [name] auf Ihrem Computer abgeschlossen. +FinishedLabel=Das Setup hat die Installation von [name] auf Ihrem Computer abgeschlossen. Die Anwendung kann über die installierten Programm-Verknüpfungen gestartet werden. +ClickFinish=Klicken Sie auf "Fertigstellen", um das Setup zu beenden. +FinishedRestartLabel=Um die Installation von [name] abzuschließen, muss das Setup Ihren Computer neu starten. Möchten Sie jetzt neu starten? +FinishedRestartMessage=Um die Installation von [name] abzuschließen, muss das Setup Ihren Computer neu starten.%n%nMöchten Sie jetzt neu starten? +ShowReadmeCheck=Ja, ich möchte die LIESMICH-Datei sehen +YesRadio=&Ja, Computer jetzt neu starten +NoRadio=&Nein, ich werde den Computer später neu starten +RunEntryExec=%1 starten +RunEntryShellExec=%1 anzeigen +ChangeDiskTitle=Nächsten Datenträger einlegen +SelectDiskLabel2=Legen Sie bitte Datenträger %1 ein und klicken Sie auf "OK".%n%nWenn sich die Dateien von diesem Datenträger in einem anderen als dem angezeigten Ordner befinden, dann geben Sie bitte den korrekten Pfad ein oder klicken auf "Durchsuchen". +PathLabel=&Pfad: +FileNotInDir2=Die Datei "%1" befindet sich nicht in "%2". Bitte Ordner ändern oder richtigen Datenträger einlegen. +SelectDirectoryLabel=Geben Sie bitte an, wo der nächste Datenträger eingelegt wird. +SetupAborted=Das Setup konnte nicht abgeschlossen werden.%n%nBeheben Sie bitte das Problem und starten Sie das Setup erneut. +AbortRetryIgnoreSelectAction=Bitte auswählen +AbortRetryIgnoreRetry=&Nochmals versuchen +AbortRetryIgnoreIgnore=&Den Fehler ignorieren und fortfahren +AbortRetryIgnoreCancel=Installation abbrechen +RetryCancelSelectAction=Bitte auswählen +RetryCancelRetry=&Wiederholen +RetryCancelCancel=&Abbrechen +StatusClosingApplications=Anwendungen werden geschlossen ... +StatusCreateDirs=Ordner werden erstellt ... +StatusExtractFiles=Dateien werden entpackt ... +StatusDownloadFiles=Dateien werden herunter geladen... +StatusCreateIcons=Verknüpfungen werden erstellt ... +StatusCreateIniEntries=INI-Einträge werden erstellt ... +StatusCreateRegistryEntries=Registry-Einträge werden erstellt ... +StatusRegisterFiles=Dateien werden registriert ... +StatusSavingUninstall=Deinstallationsinformationen werden gespeichert ... +StatusRunProgram=Installation wird beendet ... +StatusRestartingApplications=Neustart der Anwendungen ... +StatusRollback=Änderungen werden rückgängig gemacht ... +ErrorInternal2=Interner Fehler: %1 +ErrorFunctionFailedNoCode=%1 schlug fehl +ErrorFunctionFailed=%1 schlug fehl; Code %2 +ErrorFunctionFailedWithMessage=%1 schlug fehl; Code %2.%n%3 +ErrorExecutingProgram=Datei kann nicht ausgeführt werden:%n%1 +ErrorRegOpenKey=Registry-Schlüssel konnte nicht geöffnet werden:%n%1\%2 +ErrorRegCreateKey=Registry-Schlüssel konnte nicht erstellt werden:%n%1\%2 +ErrorRegWriteKey=Fehler beim Schreiben des Registry-Schlüssels:%n%1\%2 +ErrorIniEntry=Fehler beim Erstellen eines INI-Eintrages in der Datei "%1". +FileAbortRetryIgnoreSkipNotRecommended=Diese Datei &überspringen (nicht empfohlen) +FileAbortRetryIgnoreIgnoreNotRecommended=Den Fehler &ignorieren und fortfahren (nicht empfohlen) +SourceIsCorrupted=Die Quelldatei ist beschädigt +SourceDoesntExist=Die Quelldatei "%1" existiert nicht +SourceVerificationFailed=Überprüfung der Quelldatei fehlgeschlagen: %1 +VerificationSignatureDoesntExist=Die Signaturdatei "%1" existiert nicht +VerificationSignatureInvalid=Die Signaturdatei "%1" ist ungültig +VerificationKeyNotFound=Die Signaturdatei "%1" verwendet einen unbekannten Schlüssel +VerificationFileNameIncorrect=Der Name der Datei ist ungültig +VerificationFileTagIncorrect=Der Tag der Datei ist ungültig +VerificationFileSizeIncorrect=Die Größe der Datei ist ungültig +VerificationFileHashIncorrect=Der Hashwert der Datei ist ungültig +ExistingFileReadOnly2=Die vorhandene Datei kann nicht ersetzt werden, da sie schreibgeschützt ist. +ExistingFileReadOnlyRetry=&Den Schreibschutz entfernen und noch einmal versuchen +ExistingFileReadOnlyKeepExisting=Die &vorhandene Datei behalten +ErrorReadingExistingDest=Lesefehler in Datei: +FileExistsSelectAction=Aktion auswählen +FileExists2=Die Datei ist bereits vorhanden. +FileExistsOverwriteExisting=Vorhandene Datei &überschreiben +FileExistsKeepExisting=Vorhandene Datei &behalten +FileExistsOverwriteOrKeepAll=&Dies auch für die nächsten Konflikte ausführen +ExistingFileNewerSelectAction=Aktion auswählen +ExistingFileNewer2=Die vorhandene Datei ist neuer als die Datei, die installiert werden soll. +ExistingFileNewerOverwriteExisting=Vorhandene Datei &überschreiben +ExistingFileNewerKeepExisting=Vorhandene Datei &behalten (empfohlen) +ExistingFileNewerOverwriteOrKeepAll=&Dies auch für die nächsten Konflikte ausführen +ErrorChangingAttr=Fehler beim Ändern der Datei-Attribute: +ErrorCreatingTemp=Fehler beim Erstellen einer Datei im Ziel-Ordner: +ErrorReadingSource=Fehler beim Lesen der Quelldatei: +ErrorCopying=Fehler beim Kopieren einer Datei: +ErrorDownloading=Beim Download der Datei ist ein Fehler aufgetreten: +ErrorExtracting=Beim Entpacken eines Archivs ist ein Fehler aufgetreten: +ErrorReplacingExistingFile=Fehler beim Ersetzen einer vorhandenen Datei: +ErrorRestartReplace="Ersetzen nach Neustart" fehlgeschlagen: +ErrorRenamingTemp=Fehler beim Umbenennen einer Datei im Ziel-Ordner: +ErrorRegisterServer=DLL/OCX konnte nicht registriert werden: %1 +ErrorRegSvr32Failed=RegSvr32-Aufruf scheiterte mit Exit-Code %1 +ErrorRegisterTypeLib=Typen-Bibliothek konnte nicht registriert werden: %1 +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32 Bit +UninstallDisplayNameMark64Bit=64 Bit +UninstallDisplayNameMarkAllUsers=Alle Benutzer +UninstallDisplayNameMarkCurrentUser=Aktueller Benutzer +ErrorOpeningReadme=Fehler beim Öffnen der LIESMICH-Datei. +ErrorRestartingComputer=Das Setup konnte den Computer nicht neu starten. Bitte führen Sie den Neustart manuell durch. +UninstallNotFound=Die Datei "%1" existiert nicht. Entfernen der Anwendung fehlgeschlagen. +UninstallOpenError=Die Datei "%1" konnte nicht geöffnet werden. Entfernen der Anwendung fehlgeschlagen. +UninstallUnsupportedVer=Das Format der Deinstallationsdatei "%1" konnte nicht erkannt werden. Entfernen der Anwendung fehlgeschlagen. +UninstallUnknownEntry=In der Deinstallationsdatei wurde ein unbekannter Eintrag (%1) gefunden. +ConfirmUninstall=Sind Sie sicher, dass Sie %1 und alle zugehörigen Komponenten entfernen möchten? +UninstallOnlyOnWin64=Diese Installation kann nur unter 64-Bit-Windows-Versionen entfernt werden. +OnlyAdminCanUninstall=Diese Installation kann nur von einem Benutzer mit Administrator-Rechten entfernt werden. +UninstallStatusLabel=Warten Sie bitte, während %1 von Ihrem Computer entfernt wird. +UninstalledAll=%1 wurde erfolgreich von Ihrem Computer entfernt. +UninstalledMost=Entfernen von %1 beendet.%n%nEinige Komponenten konnten nicht entfernt werden. Diese können von Ihnen manuell gelöscht werden. +UninstalledAndNeedsRestart=Um die Deinstallation von %1 abzuschließen, muss Ihr Computer neu gestartet werden.%n%nMöchten Sie jetzt neu starten? +UninstallDataCorrupted="%1"-Datei ist beschädigt. Entfernen der Anwendung fehlgeschlagen. +ConfirmDeleteSharedFileTitle=Gemeinsame Datei entfernen? +ConfirmDeleteSharedFile2=Das System zeigt an, dass die folgende gemeinsame Datei von keinem anderen Programm mehr benutzt wird. Möchten Sie diese Datei entfernen lassen?%nSollte es doch noch Programme geben, die diese Datei benutzen und sie wird entfernt, funktionieren diese Programme vielleicht nicht mehr richtig. Wenn Sie unsicher sind, wählen Sie "Nein", um die Datei im System zu belassen. Es schadet Ihrem System nicht, wenn Sie die Datei behalten. +SharedFileNameLabel=Dateiname: +SharedFileLocationLabel=Ordner: +WizardUninstalling=Entfernen (Status) +StatusUninstalling=Entferne %1 ... +ShutdownBlockReasonInstallingApp=Installation von %1. +ShutdownBlockReasonUninstallingApp=Deinstallation von %1. + +[CustomMessages] +installservicetask=Run Kolibri automatically when the computer starts +newerversioninstalled=A newer version of {#AppName} (%1) is already installed. This installer contains version %2, which is older. The setup will now exit. +sameversioninstalled=This version of %1 is already installed. Do you want to repair the installation by reinstalling it? +olderversioninstalled=An older version of {#AppName} (%1) was detected. Do you want to upgrade to version {#AppVersion}? +confirmuninstalldata=Do you want to completely remove all Kolibri user data? This includes all downloaded content, user accounts, and progress, and cannot be undone. +criticalerror=A critical error occurred while trying to run a setup command: %1. The installation cannot continue. +commanderror=A command required for setup failed to execute correctly: %1. Error Code: %2. The installation cannot continue. +versionparseerror=Could not compare versions due to an invalid version format. Please uninstall the previous version manually and try again. +migrationfailed=The installer failed to migrate user data from the old location (%1) to the new location (%2). Your data has not been moved. Please contact support for assistance. +createdesktopicon=Create a &desktop icon +additionalicons=Additional icons: +launchprogram=Launch %1 +installationtype=Installation Type: diff --git a/installer/translations/create_new_language.py b/installer/translations/create_new_language.py new file mode 100644 index 0000000..aa913da --- /dev/null +++ b/installer/translations/create_new_language.py @@ -0,0 +1,147 @@ +""" +Create New Inno Setup Language File (`.isl`). + +This script automates the creation of a new language file for the Kolibri +Windows installer. It's reusing existing translations from the standard +Inno Setup language packs, when they are available. + +Workflow: +1. Takes a language name (e.g., "French") as an argument. +2. Checks for a corresponding standard language file (e.g., "French.isl") + in the specified Inno Setup installation directory. +3. If a standard file is found, it merges the pre-translated `[Messages]` + section from that file with the project-specific `[CustomMessages]` + from the local `English.isl` template. +4. If no standard file is found, it falls back to creating a direct copy of + the `English.isl` template. +5. The final output is a new `.isl` file in the `translations` directory, + ready to be translated and enabled in `kolibri.iss`. +""" +import argparse +import configparser +import shutil +from pathlib import Path + +SOURCE_TEMPLATE = "English.isl" +TRANSLATIONS_DIR = Path(__file__).parent.resolve() + + +def _merge_with_standard_isl(standard_path: Path, master_path: Path, dest_path: Path): + """ + Merges a standard Inno Setup language file with the project's master template. + """ + print(f"Found standard Inno Setup file: {standard_path}") + print("Merging standard messages with project's custom messages...") + try: + # Load the standard Inno file (pre-translated [Messages]) + final_config = configparser.ConfigParser( + allow_no_value=True, interpolation=None, strict=False + ) + final_config.optionxform = str + final_config.read(standard_path, encoding="utf-8-sig") + + # Load our English template to get the custom messages + master_config = configparser.ConfigParser( + allow_no_value=True, interpolation=None, strict=False + ) + master_config.optionxform = str + master_config.read(master_path, encoding="utf-8-sig") + + # Add the [CustomMessages] section if it exists in the master + if "CustomMessages" in master_config: + final_config["CustomMessages"] = master_config["CustomMessages"] + else: + print("Warning: No [CustomMessages] section found in the English template.") + final_config.add_section("CustomMessages") # Add an empty section + + # Write the merged result to the new file + with open(dest_path, "w", encoding="utf-8") as f: + final_config.write(f, space_around_delimiters=False) + + return "merged" + except (configparser.Error, UnicodeDecodeError) as e: + print(f"Config/encoding error: {e}") + return "error" + except (OSError,) as e: + print(f"Filesystem error: {e}") + return "error" + + +def _copy_from_english_template(source_path: Path, dest_path: Path): + """ + Creates a new language file by copying the English template. + """ + print("Falling back to creating from the English template.") + try: + shutil.copy(source_path, dest_path) + return "copied" + except (shutil.SameFileError, FileNotFoundError, PermissionError, OSError) as e: + print(f"Copy error: {e}") + return "error" + + +def create_new_language_file(language_name: str, inno_languages_dir: str): + dest_filename = f"{language_name}.isl" + dest_path = TRANSLATIONS_DIR / dest_filename + source_path = TRANSLATIONS_DIR / SOURCE_TEMPLATE + + print(f"Attempting to create new language file: {dest_path}") + + if dest_path.exists(): + print(f"Error: A file for '{language_name}' already exists at {dest_path}") + print("Aborting to prevent data loss.") + return + + if not source_path.exists(): + print(f"Error: Master template '{SOURCE_TEMPLATE}' not found.") + return + + standard_isl_path = None + if inno_languages_dir: + standard_isl_path = Path(inno_languages_dir) / dest_filename + + mode = "error" + if standard_isl_path and standard_isl_path.exists(): + # Case 1: Standard Inno Setup file exists. MERGE IT. + mode = _merge_with_standard_isl(standard_isl_path, source_path, dest_path) + else: + # Case 2: No standard file found. FALL BACK to copying. + if inno_languages_dir: + print(f"Info: Standard Inno Setup file not found for '{language_name}'.") + else: + print("Info: Inno Setup languages directory not provided.") + mode = _copy_from_english_template(source_path, dest_path) + + if mode != "error": + print_success_message(dest_path, mode) + + +def print_success_message(path, mode): + print(f"\nSuccess! New language file created: {path}") + print("\n--- Next Steps ---") + print( + r"1. Add the new language to the [Languages] section in 'installer\kolibri.iss'." + ) + print( + r' Example for Spanish, Name: "es"; MessagesFile: "translations\Spanish.isl"' + ) + if mode == "copied": + print("2. Configure the [LangOptions] section in the new .isl file") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Scaffold a new Inno Setup language file from the English template." + ) + parser.add_argument( + "--name", + required=True, + help="The name of the new language (e.g., 'French', 'Spanish'). This will be used for the filename.", + ) + parser.add_argument( + "--inno-languages-dir", + help="Optional: Path to the 'Languages' directory of your Inno Setup installation.", + ) + args = parser.parse_args() + + create_new_language_file(args.name, args.inno_languages_dir) diff --git a/installer/translations/update_from_inno_default.py b/installer/translations/update_from_inno_default.py new file mode 100644 index 0000000..bc21248 --- /dev/null +++ b/installer/translations/update_from_inno_default.py @@ -0,0 +1,147 @@ +""" +Update Master Language File from Inno Setup Defaults. + +This script is designed to synchronize the project's master +language file (`English.isl`) with an updated `Default.isl` +from a new version of the Inno Setup compiler. + +Workflow: +1. Compares the `[Messages]` section of the new `Default.isl` with the + project's current `English.isl`. +2. Identifies and calculates the differences: strings that have been added, + removed, or modified between the two versions. +3. Merges these changes into the project's `English.isl`, + updating the base translations while preserving the project-specific + `[CustomMessages]` and `[LangOptions]` sections. +4. Generates a `update_report.txt` file that lists all changes. + This report serves as a guide for translators to update the + other language files accordingly. +""" +import argparse +import configparser +import os +from datetime import datetime +from datetime import timezone + + +def _load_config(file_path): + """Loads an ISL file into a ConfigParser object.""" + config = configparser.ConfigParser( + allow_no_value=True, interpolation=None, strict=False + ) + config.optionxform = str # Preserve case + config.read(file_path, encoding="utf-8-sig") + return config + + +def _compare_messages(new_messages, master_messages): + """Compares two dictionaries of messages and returns the differences.""" + added = {k: v for k, v in new_messages.items() if k not in master_messages} + removed = {k: v for k, v in master_messages.items() if k not in new_messages} + modified = { + k: {"old": master_messages[k], "new": v} + for k, v in new_messages.items() + if k in master_messages and master_messages[k] != v + } + return added, removed, modified + + +def _generate_report(report_path, added, removed, modified): + """Writes the comparison results to a text file.""" + with open(report_path, "w", encoding="utf-8") as f: + f.write( + f"Inno Setup String Update Report - {datetime.now(timezone.utc).isoformat(timespec='seconds').replace('+00:00','Z')}\n\n" + ) + f.write("=" * 50 + "\n\n") + + if not any([added, removed, modified]): + f.write( + "No changes detected between the new Default.isl and the project master.\n" + ) + return + + if added: + f.write("--- ADDED STRINGS ---\n") + for key, value in added.items(): + f.write(f"{key}={value}\n") + f.write("\n") + + if removed: + f.write("--- REMOVED STRINGS ---\n") + for key, value in removed.items(): + f.write(f"{key}={value}\n") + f.write("\n") + + if modified: + f.write("--- MODIFIED STRINGS ---\n") + for key, values in modified.items(): + f.write(f"{key}\n") + f.write(f" - OLD: {values['old']}\n") + f.write(f" + NEW: {values['new']}\n") + f.write("\n") + print(f"Update report generated: {report_path}") + + +def update_master_from_default(new_default_path, project_master_path): + """ + Compares a new Inno Setup Default.isl with the project's master English.isl, + merges changes, and generates a report. + """ + if not os.path.exists(new_default_path): + print(f"Error: New default file not found at {new_default_path}") + return + + if not os.path.exists(project_master_path): + print(f"Error: Project master file not found at {project_master_path}") + return + + # 1. Load configuration files + new_config = _load_config(new_default_path) + master_config = _load_config(project_master_path) + + # 2. Perform comparison + new_messages = dict(new_config["Messages"]) + master_messages = dict(master_config["Messages"]) + added, removed, modified = _compare_messages(new_messages, master_messages) + + # 3. Merge the configurations + final_config = configparser.ConfigParser( + allow_no_value=True, interpolation=None, strict=False + ) + final_config.optionxform = str # Preserve case + final_config.read_dict(new_config) + if "CustomMessages" in master_config: + final_config["CustomMessages"] = master_config["CustomMessages"] + if "LangOptions" in master_config: + final_config["LangOptions"] = master_config["LangOptions"] + + # 4. Write the updated master file + with open(project_master_path, "w", encoding="utf-8") as f: + f.write("; Master English messages for Kolibri Installer\n") + f.write( + f"; Last updated: {datetime.now(timezone.utc).isoformat(timespec='seconds').replace('+00:00','Z')}\n\n" + ) + final_config.write(f, space_around_delimiters=False) + print(f"Successfully updated master file: {project_master_path}") + + # 5. Generate the update report + _generate_report("update_report.txt", added, removed, modified) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Update the project's master Inno Setup language file from a new Default.isl." + ) + parser.add_argument( + "--new-default", + required=True, + help="Path to the Default.isl from the new Inno Setup installation.", + ) + parser.add_argument( + "--project-master", + required=True, + help="Path to the project's master English.isl file to be updated.", + ) + args = parser.parse_args() + + update_master_from_default(args.new_default, args.project_master) diff --git a/kolibri.spec b/kolibri.spec index e0d9142..f93184c 100644 --- a/kolibri.spec +++ b/kolibri.spec @@ -70,7 +70,7 @@ datas_list = [ if sys.platform == "win32": datas_list.extend([ ('src/kolibri_app/icons', 'kolibri_app/icons'), - ('nssm.exe', 'nssm') + (os.path.join('installer', 'nssm.exe'), 'nssm') ]) binaries_list = [] From e0ed8f3e682afeab6e00762d18677eb44a8203bd Mon Sep 17 00:00:00 2001 From: Dimitrios Mylonas Date: Sun, 26 Oct 2025 19:20:50 +0200 Subject: [PATCH 2/4] feat(installer): Implement PO file workflow for translations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- Makefile | 35 +- build_requires.txt | 1 + installer/translations/German.isl | 24 +- installer/translations/German.po | 1471 +++++++++++++++++ installer/translations/create_new_language.py | 56 +- installer/translations/isl_to_po.py | 92 ++ installer/translations/po_to_isl.py | 61 + 7 files changed, 1712 insertions(+), 28 deletions(-) create mode 100644 installer/translations/German.po create mode 100644 installer/translations/isl_to_po.py create mode 100644 installer/translations/po_to_isl.py diff --git a/Makefile b/Makefile index 35b83d2..31e06f9 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ nssm: # Windows Installer Build .PHONY: build-installer-windows -build-installer-windows: needs-version nssm webview2 +build-installer-windows: translations-compile needs-version nssm webview2 ifeq ($(OS),Windows_NT) # Assumes Inno Setup is installed in the default location. # MSYS_NO_PATHCONV=1 prevents Git Bash/MINGW from converting the /D flag into a file path. @@ -151,6 +151,39 @@ new-language: --name "$(LANG)" \ --inno-languages-dir "$(INNO_LANGUAGES_DIR)" +TRANSLATIONS_DIR := installer/translations +ISL_TO_PO_SCRIPT := $(TRANSLATIONS_DIR)/isl_to_po.py +PO_TO_ISL_SCRIPT := $(TRANSLATIONS_DIR)/po_to_isl.py + +# Usage example: make translations-export LANG=German LANG_CODE=de_DE +# Exports a single .isl file to a .po file for translators. +.PHONY: translations-export +translations-export: + $(MAKE) guard-LANG + $(MAKE) guard-LANG_CODE + @echo "Exporting '$(LANG).isl' to a .po file for translators..." + $(PYTHON_EXEC) $(ISL_TO_PO_SCRIPT) \ + -t $(TRANSLATIONS_DIR)/English.isl \ + -i $(TRANSLATIONS_DIR)/$(LANG).isl \ + -o $(TRANSLATIONS_DIR)/$(LANG).po \ + -l "$(LANG_CODE)" + +# Compiles all .po files in the translations dir into their final .isl format. +# Runs automatically before the windows installer is built. +.PHONY: translations-compile +translations-compile: + @echo "Compiling .po files to .isl format for Inno Setup..." + @for po_file in $(TRANSLATIONS_DIR)/*.po; do \ + if [ -f "$$po_file" ]; then \ + lang_name=$$(basename "$$po_file" .po); \ + echo " -> Processing $${lang_name}.po -> $${lang_name}.isl"; \ + $(PYTHON_EXEC) $(PO_TO_ISL_SCRIPT) \ + -t $(TRANSLATIONS_DIR)/English.isl \ + -i "$$po_file" \ + -o "$(TRANSLATIONS_DIR)/$${lang_name}.isl"; \ + fi \ + done + .PHONY: update-translations update-translations: @echo "Updating master language file from '$(INNO_DEFAULT_ISL)'..." diff --git a/build_requires.txt b/build_requires.txt index 3a756d7..5bff430 100644 --- a/build_requires.txt +++ b/build_requires.txt @@ -3,3 +3,4 @@ pkginfo PyInstaller==6.16.0 dmgbuild==1.6.5; sys_platform == 'darwin' attrdict==2.0.1 # required to install wxpython +polib==1.2.0 # required for handling .po translation files diff --git a/installer/translations/German.isl b/installer/translations/German.isl index 0cab27f..12c5158 100644 --- a/installer/translations/German.isl +++ b/installer/translations/German.isl @@ -1,7 +1,7 @@ -[LangOptions] -LanguageName=Deutsch -LanguageID=$0407 -LanguageCodePage=1252 +[LangOptions] +languagename=German +languageid=$0407 +languagecodepage=0 [Messages] SetupAppTitle=Setup @@ -48,12 +48,12 @@ AboutSetupMenuItem=&Über das Setup ... AboutSetupTitle=Über das Setup AboutSetupMessage=%1 Version %2%n%3%n%n%1 Webseite:%n%4 AboutSetupNote= -TranslatorNote=German translation maintained by Jens Brand (jens.brand@wolf-software.de) +TranslatorNote= ButtonBack=< &Zurück ButtonNext=&Weiter > ButtonInstall=&Installieren ButtonOK=OK -ButtonCancel=Abbrechen +ButtonCancel=&Abbrechen ButtonYes=&Ja ButtonYesToAll=J&a für Alle ButtonNo=&Nein @@ -146,7 +146,7 @@ ReadyMemoType=Setup-Typ: ReadyMemoComponents=Ausgewählte Komponenten: ReadyMemoGroup=Startmenü-Ordner: ReadyMemoTasks=Zusätzliche Aufgaben: -DownloadingLabel2=Lade Dateien herunter... +DownloadingLabel2=Dateien werden herunter geladen... ButtonStopDownload=Download &abbrechen StopDownload=Sind Sie sicher, dass Sie den Download abbrechen wollen? ErrorDownloadAborted=Download abgebrochen @@ -154,7 +154,7 @@ ErrorDownloadFailed=Download fehlgeschlagen: %1 %2 ErrorDownloadSizeFailed=Fehler beim Ermitteln der Größe: %1 %2 ErrorProgress=Ungültiger Fortschritt: %1 von %2 ErrorFileSize=Ungültige Dateigröße: erwartet %1, gefunden %2 -ExtractingLabel=Entpacke Dateien... +ExtractingLabel=Dateien werden entpackt ... ButtonStopExtraction=Entpacken &abbrechen StopExtraction=Sind Sie sicher, dass Sie das Entpacken abbrechen wollen? ErrorExtractionAborted=Entpacken abgebrochen @@ -191,11 +191,11 @@ PathLabel=&Pfad: FileNotInDir2=Die Datei "%1" befindet sich nicht in "%2". Bitte Ordner ändern oder richtigen Datenträger einlegen. SelectDirectoryLabel=Geben Sie bitte an, wo der nächste Datenträger eingelegt wird. SetupAborted=Das Setup konnte nicht abgeschlossen werden.%n%nBeheben Sie bitte das Problem und starten Sie das Setup erneut. -AbortRetryIgnoreSelectAction=Bitte auswählen -AbortRetryIgnoreRetry=&Nochmals versuchen +AbortRetryIgnoreSelectAction=Aktion auswählen +AbortRetryIgnoreRetry=&Wiederholen AbortRetryIgnoreIgnore=&Den Fehler ignorieren und fortfahren AbortRetryIgnoreCancel=Installation abbrechen -RetryCancelSelectAction=Bitte auswählen +RetryCancelSelectAction=Aktion auswählen RetryCancelRetry=&Wiederholen RetryCancelCancel=&Abbrechen StatusClosingApplications=Anwendungen werden geschlossen ... @@ -233,7 +233,7 @@ VerificationFileSizeIncorrect=Die Größe der Datei ist ungültig VerificationFileHashIncorrect=Der Hashwert der Datei ist ungültig ExistingFileReadOnly2=Die vorhandene Datei kann nicht ersetzt werden, da sie schreibgeschützt ist. ExistingFileReadOnlyRetry=&Den Schreibschutz entfernen und noch einmal versuchen -ExistingFileReadOnlyKeepExisting=Die &vorhandene Datei behalten +ExistingFileReadOnlyKeepExisting=Vorhandene Datei &behalten ErrorReadingExistingDest=Lesefehler in Datei: FileExistsSelectAction=Aktion auswählen FileExists2=Die Datei ist bereits vorhanden. diff --git a/installer/translations/German.po b/installer/translations/German.po new file mode 100644 index 0000000..3dbbe8b --- /dev/null +++ b/installer/translations/German.po @@ -0,0 +1,1471 @@ +# +msgid "" +msgstr "" +"Project-Id-Version: kolibri-windows-installer\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-10-25T16:10:15.833345+03:00\n" +"PO-Revision-Date: 2025-10-25T16:10:15.833345+03:00\n" +"Last-Translator: FULL NAME \n" +"Language-Team: \n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. [LangOptions]languagename +msgid "English" +msgstr "German" + +#. [LangOptions]languageid +msgid "$0409" +msgstr "$0407" + +#. [LangOptions]languagecodepage +msgid "0" +msgstr "0" + +#. [Messages]SetupAppTitle +msgid "Setup" +msgstr "Setup" + +#. [Messages]SetupWindowTitle +msgid "Setup - %1" +msgstr "Setup - %1" + +#. [Messages]UninstallAppTitle +msgid "Uninstall" +msgstr "Entfernen" + +#. [Messages]UninstallAppFullTitle +msgid "%1 Uninstall" +msgstr "%1 entfernen" + +#. [Messages]InformationTitle +msgid "Information" +msgstr "Information" + +#. [Messages]ConfirmTitle +msgid "Confirm" +msgstr "Bestätigen" + +#. [Messages]ErrorTitle +msgid "Error" +msgstr "Fehler" + +#. [Messages]SetupLdrStartupMessage +msgid "This will install %1. Do you wish to continue?" +msgstr "%1 wird jetzt installiert. Möchten Sie fortfahren?" + +#. [Messages]LdrCannotCreateTemp +msgid "Unable to create a temporary file. Setup aborted" +msgstr "" +"Es konnte keine temporäre Datei erstellt werden. Das Setup wurde abgebrochen" + +#. [Messages]LdrCannotExecTemp +msgid "Unable to execute file in the temporary directory. Setup aborted" +msgstr "" +"Die Datei konnte nicht im temporären Ordner ausgeführt werden. Das Setup " +"wurde abgebrochen" + +#. [Messages]HelpTextNote +msgid "" +msgstr "" + +#. [Messages]LastErrorMessage +msgid "%1.%n%nError %2: %3" +msgstr "%1.%n%nFehler %2: %3" + +#. [Messages]SetupFileMissing +msgid "" +"The file %1 is missing from the installation directory. Please correct the " +"problem or obtain a new copy of the program." +msgstr "" +"Die Datei %1 fehlt im Installationsordner. Bitte beheben Sie das Problem " +"oder besorgen Sie sich eine neue Kopie des Programms." + +#. [Messages]SetupFileCorrupt +msgid "" +"The setup files are corrupted. Please obtain a new copy of the program." +msgstr "" +"Die Setup-Dateien sind beschädigt. Besorgen Sie sich bitte eine neue Kopie " +"des Programms." + +#. [Messages]SetupFileCorruptOrWrongVer +msgid "" +"The setup files are corrupted, or are incompatible with this version of " +"Setup. Please correct the problem or obtain a new copy of the program." +msgstr "" +"Die Setup-Dateien sind beschädigt oder inkompatibel zu dieser Version des " +"Setups. Bitte beheben Sie das Problem oder besorgen Sie sich eine neue Kopie" +" des Programms." + +#. [Messages]InvalidParameter +msgid "An invalid parameter was passed on the command line:%n%n%1" +msgstr "Ein ungültiger Parameter wurde auf der Kommandozeile übergeben:%n%n%1" + +#. [Messages]SetupAlreadyRunning +msgid "Setup is already running." +msgstr "Setup läuft bereits." + +#. [Messages]WindowsVersionNotSupported +msgid "" +"This program does not support the version of Windows your computer is " +"running." +msgstr "" +"Dieses Programm unterstützt die auf Ihrem Computer installierte Windows-" +"Version nicht." + +#. [Messages]WindowsServicePackRequired +msgid "This program requires %1 Service Pack %2 or later." +msgstr "Dieses Programm benötigt %1 Service Pack %2 oder höher." + +#. [Messages]NotOnThisPlatform +msgid "This program will not run on %1." +msgstr "Dieses Programm kann nicht unter %1 ausgeführt werden." + +#. [Messages]OnlyOnThisPlatform +msgid "This program must be run on %1." +msgstr "Dieses Programm muss unter %1 ausgeführt werden." + +#. [Messages]OnlyOnTheseArchitectures +msgid "" +"This program can only be installed on versions of Windows designed for the " +"following processor architectures:%n%n%1" +msgstr "" +"Dieses Programm kann nur auf Windows-Versionen installiert werden, die " +"folgende Prozessor-Architekturen unterstützen:%n%n%1" + +#. [Messages]WinVersionTooLowError +msgid "This program requires %1 version %2 or later." +msgstr "Dieses Programm benötigt %1 Version %2 oder höher." + +#. [Messages]WinVersionTooHighError +msgid "This program cannot be installed on %1 version %2 or later." +msgstr "" +"Dieses Programm kann nicht unter %1 Version %2 oder höher installiert " +"werden." + +#. [Messages]AdminPrivilegesRequired +msgid "" +"You must be logged in as an administrator when installing this program." +msgstr "" +"Sie müssen als Administrator angemeldet sein, um dieses Programm " +"installieren zu können." + +#. [Messages]PowerUserPrivilegesRequired +msgid "" +"You must be logged in as an administrator or as a member of the Power Users " +"group when installing this program." +msgstr "" +"Sie müssen als Administrator oder als Mitglied der Hauptbenutzer-Gruppe " +"angemeldet sein, um dieses Programm installieren zu können." + +#. [Messages]SetupAppRunningError +msgid "" +"Setup has detected that %1 is currently running.%n%nPlease close all " +"instances of it now, then click OK to continue, or Cancel to exit." +msgstr "" +"Das Setup hat entdeckt, dass %1 zurzeit ausgeführt wird.%n%nBitte schließen " +"Sie jetzt alle laufenden Instanzen und klicken Sie auf \"OK\", um " +"fortzufahren, oder auf \"Abbrechen\", um zu beenden." + +#. [Messages]UninstallAppRunningError +msgid "" +"Uninstall has detected that %1 is currently running.%n%nPlease close all " +"instances of it now, then click OK to continue, or Cancel to exit." +msgstr "" +"Die Deinstallation hat entdeckt, dass %1 zurzeit ausgeführt wird.%n%nBitte " +"schließen Sie jetzt alle laufenden Instanzen und klicken Sie auf \"OK\", um " +"fortzufahren, oder auf \"Abbrechen\", um zu beenden." + +#. [Messages]PrivilegesRequiredOverrideTitle +msgid "Select Setup Install Mode" +msgstr "Installationsmodus auswählen" + +#. [Messages]PrivilegesRequiredOverrideInstruction +msgid "Select install mode" +msgstr "Bitte wählen Sie den Installationsmodus" + +#. [Messages]PrivilegesRequiredOverrideText1 +msgid "" +"%1 can be installed for all users (requires administrative privileges), or " +"for you only." +msgstr "" +"%1 kann für alle Benutzer (erfordert Administrationsrechte) oder nur für Sie" +" installiert werden." + +#. [Messages]PrivilegesRequiredOverrideText2 +msgid "" +"%1 can be installed for you only, or for all users (requires administrative " +"privileges)." +msgstr "" +"%1 kann nur für Sie oder für alle Benutzer (erfordert Administrationsrechte)" +" installiert werden." + +#. [Messages]PrivilegesRequiredOverrideAllUsers +msgid "Install for &all users" +msgstr "Installation für &alle Benutzer" + +#. [Messages]PrivilegesRequiredOverrideAllUsersRecommended +msgid "Install for &all users (recommended)" +msgstr "Installation für &alle Benutzer (empfohlen)" + +#. [Messages]PrivilegesRequiredOverrideCurrentUser +msgid "Install for &me only" +msgstr "Installation nur für &Sie" + +#. [Messages]PrivilegesRequiredOverrideCurrentUserRecommended +msgid "Install for &me only (recommended)" +msgstr "Installation nur für &Sie (empfohlen)" + +#. [Messages]ErrorCreatingDir +msgid "Setup was unable to create the directory \"%1\"" +msgstr "Das Setup konnte den Ordner \"%1\" nicht erstellen." + +#. [Messages]ErrorTooManyFilesInDir +msgid "" +"Unable to create a file in the directory \"%1\" because it contains too many" +" files" +msgstr "" +"Das Setup konnte eine Datei im Ordner \"%1\" nicht erstellen, weil er zu " +"viele Dateien enthält." + +#. [Messages]ExitSetupTitle +msgid "Exit Setup" +msgstr "Setup verlassen" + +#. [Messages]ExitSetupMessage +msgid "" +"Setup is not complete. If you exit now, the program will not be " +"installed.%n%nYou may run Setup again at another time to complete the " +"installation.%n%nExit Setup?" +msgstr "" +"Das Setup ist noch nicht abgeschlossen. Wenn Sie jetzt beenden, wird das " +"Programm nicht installiert.%n%nSie können das Setup zu einem späteren " +"Zeitpunkt nochmals ausführen, um die Installation zu " +"vervollständigen.%n%nSetup verlassen?" + +#. [Messages]AboutSetupMenuItem +msgid "&About Setup..." +msgstr "&Über das Setup ..." + +#. [Messages]AboutSetupTitle +msgid "About Setup" +msgstr "Über das Setup" + +#. [Messages]AboutSetupMessage +msgid "%1 version %2%n%3%n%n%1 home page:%n%4" +msgstr "%1 Version %2%n%3%n%n%1 Webseite:%n%4" + +#. [Messages]AboutSetupNote +msgid "" +msgstr "" + +#. [Messages]TranslatorNote +msgid "" +msgstr "" +"German translation maintained by Jens Brand (jens.brand@wolf-software.de)" + +#. [Messages]ButtonBack +msgid "< &Back" +msgstr "< &Zurück" + +#. [Messages]ButtonNext +msgid "&Next >" +msgstr "&Weiter >" + +#. [Messages]ButtonInstall +msgid "&Install" +msgstr "&Installieren" + +#. [Messages]ButtonOK +msgid "OK" +msgstr "OK" + +#. [Messages]ButtonCancel +msgid "Cancel" +msgstr "Abbrechen" + +#. [Messages]ButtonYes +msgid "&Yes" +msgstr "&Ja" + +#. [Messages]ButtonYesToAll +msgid "Yes to &All" +msgstr "J&a für Alle" + +#. [Messages]ButtonNo +msgid "&No" +msgstr "&Nein" + +#. [Messages]ButtonNoToAll +msgid "N&o to All" +msgstr "N&ein für Alle" + +#. [Messages]ButtonFinish +msgid "&Finish" +msgstr "&Fertigstellen" + +#. [Messages]ButtonBrowse +msgid "&Browse..." +msgstr "&Durchsuchen ..." + +#. [Messages]ButtonWizardBrowse +msgid "B&rowse..." +msgstr "Du&rchsuchen ..." + +#. [Messages]ButtonNewFolder +msgid "&Make New Folder" +msgstr "&Neuen Ordner erstellen" + +#. [Messages]SelectLanguageTitle +msgid "Select Setup Language" +msgstr "Setup-Sprache auswählen" + +#. [Messages]SelectLanguageLabel +msgid "Select the language to use during the installation." +msgstr "" +"Wählen Sie die Sprache aus, die während der Installation benutzt werden " +"soll:" + +#. [Messages]ClickNext +msgid "Click Next to continue, or Cancel to exit Setup." +msgstr "\"Weiter\" zum Fortfahren, \"Abbrechen\" zum Verlassen." + +#. [Messages]BeveledLabel +msgid "" +msgstr "" + +#. [Messages]BrowseDialogTitle +msgid "Browse For Folder" +msgstr "Ordner suchen" + +#. [Messages]BrowseDialogLabel +msgid "Select a folder in the list below, then click OK." +msgstr "Wählen Sie einen Ordner aus und klicken Sie danach auf \"OK\"." + +#. [Messages]NewFolderName +msgid "New Folder" +msgstr "Neuer Ordner" + +#. [Messages]WelcomeLabel1 +msgid "Welcome to the [name] Setup Wizard" +msgstr "Willkommen zum [name] Setup-Assistenten" + +#. [Messages]WelcomeLabel2 +msgid "" +"This will install [name/ver] on your computer.%n%nIt is recommended that you" +" close all other applications before continuing." +msgstr "" +"Dieser Assistent wird jetzt [name/ver] auf Ihrem Computer " +"installieren.%n%nSie sollten alle anderen Anwendungen beenden, bevor Sie mit" +" dem Setup fortfahren." + +#. [Messages]WizardPassword +msgid "Password" +msgstr "Passwort" + +#. [Messages]PasswordLabel1 +msgid "This installation is password protected." +msgstr "Diese Installation wird durch ein Passwort geschützt." + +#. [Messages]PasswordLabel3 +msgid "" +"Please provide the password, then click Next to continue. Passwords are " +"case-sensitive." +msgstr "" +"Bitte geben Sie das Passwort ein und klicken Sie danach auf \"Weiter\". " +"Achten Sie auf korrekte Groß-/Kleinschreibung." + +#. [Messages]PasswordEditLabel +msgid "&Password:" +msgstr "&Passwort:" + +#. [Messages]IncorrectPassword +msgid "The password you entered is not correct. Please try again." +msgstr "" +"Das eingegebene Passwort ist nicht korrekt. Bitte versuchen Sie es noch " +"einmal." + +#. [Messages]WizardLicense +msgid "License Agreement" +msgstr "Lizenzvereinbarung" + +#. [Messages]LicenseLabel +msgid "Please read the following important information before continuing." +msgstr "" +"Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren." + +#. [Messages]LicenseLabel3 +msgid "" +"Please read the following License Agreement. You must accept the terms of " +"this agreement before continuing with the installation." +msgstr "" +"Lesen Sie bitte die folgenden Lizenzvereinbarungen. Benutzen Sie bei Bedarf " +"die Bildlaufleiste oder drücken Sie die \"Bild Ab\"-Taste." + +#. [Messages]LicenseAccepted +msgid "I &accept the agreement" +msgstr "Ich &akzeptiere die Vereinbarung" + +#. [Messages]LicenseNotAccepted +msgid "I &do not accept the agreement" +msgstr "Ich &lehne die Vereinbarung ab" + +#. [Messages]WizardInfoBefore +msgid "Information" +msgstr "Information" + +#. [Messages]InfoBeforeLabel +msgid "Please read the following important information before continuing." +msgstr "" +"Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren." + +#. [Messages]InfoBeforeClickLabel +msgid "When you are ready to continue with Setup, click Next." +msgstr "" +"Klicken Sie auf \"Weiter\", sobald Sie bereit sind, mit dem Setup " +"fortzufahren." + +#. [Messages]WizardInfoAfter +msgid "Information" +msgstr "Information" + +#. [Messages]InfoAfterLabel +msgid "Please read the following important information before continuing." +msgstr "" +"Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren." + +#. [Messages]InfoAfterClickLabel +msgid "When you are ready to continue with Setup, click Next." +msgstr "" +"Klicken Sie auf \"Weiter\", sobald Sie bereit sind, mit dem Setup " +"fortzufahren." + +#. [Messages]WizardUserInfo +msgid "User Information" +msgstr "Benutzerinformationen" + +#. [Messages]UserInfoDesc +msgid "Please enter your information." +msgstr "Bitte tragen Sie Ihre Daten ein." + +#. [Messages]UserInfoName +msgid "&User Name:" +msgstr "&Name:" + +#. [Messages]UserInfoOrg +msgid "&Organization:" +msgstr "&Organisation:" + +#. [Messages]UserInfoSerial +msgid "&Serial Number:" +msgstr "&Seriennummer:" + +#. [Messages]UserInfoNameRequired +msgid "You must enter a name." +msgstr "Sie müssen einen Namen eintragen." + +#. [Messages]WizardSelectDir +msgid "Select Destination Location" +msgstr "Ziel-Ordner wählen" + +#. [Messages]SelectDirDesc +msgid "Where should [name] be installed?" +msgstr "Wohin soll [name] installiert werden?" + +#. [Messages]SelectDirLabel3 +msgid "Setup will install [name] into the following folder." +msgstr "Das Setup wird [name] in den folgenden Ordner installieren." + +#. [Messages]SelectDirBrowseLabel +msgid "" +"To continue, click Next. If you would like to select a different folder, " +"click Browse." +msgstr "" +"Klicken Sie auf \"Weiter\", um fortzufahren. Klicken Sie auf " +"\"Durchsuchen\", falls Sie einen anderen Ordner auswählen möchten." + +#. [Messages]DiskSpaceGBLabel +msgid "At least [gb] GB of free disk space is required." +msgstr "Mindestens [gb] GB freier Speicherplatz ist erforderlich." + +#. [Messages]DiskSpaceMBLabel +msgid "At least [mb] MB of free disk space is required." +msgstr "Mindestens [mb] MB freier Speicherplatz ist erforderlich." + +#. [Messages]CannotInstallToNetworkDrive +msgid "Setup cannot install to a network drive." +msgstr "Das Setup kann nicht in einen Netzwerk-Pfad installieren." + +#. [Messages]CannotInstallToUNCPath +msgid "Setup cannot install to a UNC path." +msgstr "" +"Das Setup kann nicht in einen UNC-Pfad installieren. Wenn Sie auf ein " +"Netzlaufwerk installieren möchten, müssen Sie dem Netzwerkpfad einen " +"Laufwerksbuchstaben zuordnen." + +#. [Messages]InvalidPath +msgid "" +"You must enter a full path with drive letter; for example:%n%nC:\\APP%n%nor " +"a UNC path in the form:%n%n\\\\server\\share" +msgstr "" +"Sie müssen einen vollständigen Pfad mit einem Laufwerksbuchstaben angeben, " +"z. B.:%n%nC:\\Beispiel%n%noder einen UNC-Pfad in der " +"Form:%n%n\\\\Server\\Freigabe" + +#. [Messages]InvalidDrive +msgid "" +"The drive or UNC share you selected does not exist or is not accessible. " +"Please select another." +msgstr "" +"Das angegebene Laufwerk bzw. der UNC-Pfad existiert nicht oder es kann nicht" +" darauf zugegriffen werden. Wählen Sie bitte einen anderen Ordner." + +#. [Messages]DiskSpaceWarningTitle +msgid "Not Enough Disk Space" +msgstr "Nicht genug freier Speicherplatz" + +#. [Messages]DiskSpaceWarning +msgid "" +"Setup requires at least %1 KB of free space to install, but the selected " +"drive only has %2 KB available.%n%nDo you want to continue anyway?" +msgstr "" +"Das Setup benötigt mindestens %1 KB freien Speicherplatz zum Installieren, " +"aber auf dem ausgewählten Laufwerk sind nur %2 KB verfügbar.%n%nMöchten Sie " +"trotzdem fortfahren?" + +#. [Messages]DirNameTooLong +msgid "The folder name or path is too long." +msgstr "Der Ordnername/Pfad ist zu lang." + +#. [Messages]InvalidDirName +msgid "The folder name is not valid." +msgstr "Der Ordnername ist nicht gültig." + +#. [Messages]BadDirName32 +msgid "Folder names cannot include any of the following characters:%n%n%1" +msgstr "Ordnernamen dürfen keine der folgenden Zeichen enthalten:%n%n%1" + +#. [Messages]DirExistsTitle +msgid "Folder Exists" +msgstr "Ordner existiert bereits" + +#. [Messages]DirExists +msgid "" +"The folder:%n%n%1%n%nalready exists. Would you like to install to that " +"folder anyway?" +msgstr "" +"Der Ordner:%n%n%1%n%n existiert bereits. Möchten Sie trotzdem in diesen " +"Ordner installieren?" + +#. [Messages]DirDoesntExistTitle +msgid "Folder Does Not Exist" +msgstr "Ordner ist nicht vorhanden" + +#. [Messages]DirDoesntExist +msgid "" +"The folder:%n%n%1%n%ndoes not exist. Would you like the folder to be " +"created?" +msgstr "" +"Der Ordner:%n%n%1%n%nist nicht vorhanden. Soll der Ordner erstellt werden?" + +#. [Messages]WizardSelectComponents +msgid "Select Components" +msgstr "Komponenten auswählen" + +#. [Messages]SelectComponentsDesc +msgid "Which components should be installed?" +msgstr "Welche Komponenten sollen installiert werden?" + +#. [Messages]SelectComponentsLabel2 +msgid "" +"Select the components you want to install; clear the components you do not " +"want to install. Click Next when you are ready to continue." +msgstr "" +"Wählen Sie die Komponenten aus, die Sie installieren möchten. Klicken Sie " +"auf \"Weiter\", wenn Sie bereit sind, fortzufahren." + +#. [Messages]FullInstallation +msgid "Full installation" +msgstr "Vollständige Installation" + +#. [Messages]CompactInstallation +msgid "Compact installation" +msgstr "Kompakte Installation" + +#. [Messages]CustomInstallation +msgid "Custom installation" +msgstr "Benutzerdefinierte Installation" + +#. [Messages]NoUninstallWarningTitle +msgid "Components Exist" +msgstr "Komponenten vorhanden" + +#. [Messages]NoUninstallWarning +msgid "" +"Setup has detected that the following components are already installed on " +"your computer:%n%n%1%n%nDeselecting these components will not uninstall " +"them.%n%nWould you like to continue anyway?" +msgstr "" +"Das Setup hat festgestellt, dass die folgenden Komponenten bereits auf Ihrem" +" Computer installiert sind:%n%n%1%n%nDiese nicht mehr ausgewählten " +"Komponenten werden nicht vom Computer entfernt.%n%nMöchten Sie trotzdem " +"fortfahren?" + +#. [Messages]ComponentSize1 +msgid "%1 KB" +msgstr "%1 KB" + +#. [Messages]ComponentSize2 +msgid "%1 MB" +msgstr "%1 MB" + +#. [Messages]ComponentsDiskSpaceGBLabel +msgid "Current selection requires at least [gb] GB of disk space." +msgstr "Die aktuelle Auswahl erfordert mindestens [gb] GB Speicherplatz." + +#. [Messages]ComponentsDiskSpaceMBLabel +msgid "Current selection requires at least [mb] MB of disk space." +msgstr "Die aktuelle Auswahl erfordert mindestens [mb] MB Speicherplatz." + +#. [Messages]WizardSelectTasks +msgid "Select Additional Tasks" +msgstr "Zusätzliche Aufgaben auswählen" + +#. [Messages]SelectTasksDesc +msgid "Which additional tasks should be performed?" +msgstr "Welche zusätzlichen Aufgaben sollen ausgeführt werden?" + +#. [Messages]SelectTasksLabel2 +msgid "" +"Select the additional tasks you would like Setup to perform while installing" +" [name], then click Next." +msgstr "" +"Wählen Sie die zusätzlichen Aufgaben aus, die das Setup während der " +"Installation von [name] ausführen soll, und klicken Sie danach auf " +"\"Weiter\"." + +#. [Messages]WizardSelectProgramGroup +msgid "Select Start Menu Folder" +msgstr "Startmenü-Ordner auswählen" + +#. [Messages]SelectStartMenuFolderDesc +msgid "Where should Setup place the program's shortcuts?" +msgstr "Wo soll das Setup die Programm-Verknüpfungen erstellen?" + +#. [Messages]SelectStartMenuFolderLabel3 +msgid "" +"Setup will create the program's shortcuts in the following Start Menu " +"folder." +msgstr "" +"Das Setup wird die Programm-Verknüpfungen im folgenden Startmenü-Ordner " +"erstellen." + +#. [Messages]SelectStartMenuFolderBrowseLabel +msgid "" +"To continue, click Next. If you would like to select a different folder, " +"click Browse." +msgstr "" +"Klicken Sie auf \"Weiter\", um fortzufahren. Klicken Sie auf " +"\"Durchsuchen\", falls Sie einen anderen Ordner auswählen möchten." + +#. [Messages]MustEnterGroupName +msgid "You must enter a folder name." +msgstr "Sie müssen einen Ordnernamen eingeben." + +#. [Messages]GroupNameTooLong +msgid "The folder name or path is too long." +msgstr "Der Ordnername/Pfad ist zu lang." + +#. [Messages]InvalidGroupName +msgid "The folder name is not valid." +msgstr "Der Ordnername ist nicht gültig." + +#. [Messages]BadGroupName +msgid "The folder name cannot include any of the following characters:%n%n%1" +msgstr "Der Ordnername darf keine der folgenden Zeichen enthalten:%n%n%1" + +#. [Messages]NoProgramGroupCheck2 +msgid "&Don't create a Start Menu folder" +msgstr "&Keinen Ordner im Startmenü erstellen" + +#. [Messages]WizardReady +msgid "Ready to Install" +msgstr "Bereit zur Installation." + +#. [Messages]ReadyLabel1 +msgid "Setup is now ready to begin installing [name] on your computer." +msgstr "" +"Das Setup ist jetzt bereit, [name] auf Ihrem Computer zu installieren." + +#. [Messages]ReadyLabel2a +msgid "" +"Click Install to continue with the installation, or click Back if you want " +"to review or change any settings." +msgstr "" +"Klicken Sie auf \"Installieren\", um mit der Installation zu beginnen, oder " +"auf \"Zurück\", um Ihre Einstellungen zu überprüfen oder zu ändern." + +#. [Messages]ReadyLabel2b +msgid "Click Install to continue with the installation." +msgstr "Klicken Sie auf \"Installieren\", um mit der Installation zu beginnen." + +#. [Messages]ReadyMemoUserInfo +msgid "User information:" +msgstr "Benutzerinformationen:" + +#. [Messages]ReadyMemoDir +msgid "Destination location:" +msgstr "Ziel-Ordner:" + +#. [Messages]ReadyMemoType +msgid "Setup type:" +msgstr "Setup-Typ:" + +#. [Messages]ReadyMemoComponents +msgid "Selected components:" +msgstr "Ausgewählte Komponenten:" + +#. [Messages]ReadyMemoGroup +msgid "Start Menu folder:" +msgstr "Startmenü-Ordner:" + +#. [Messages]ReadyMemoTasks +msgid "Additional tasks:" +msgstr "Zusätzliche Aufgaben:" + +#. [Messages]DownloadingLabel2 +msgid "Downloading files..." +msgstr "Lade Dateien herunter..." + +#. [Messages]ButtonStopDownload +msgid "&Stop download" +msgstr "Download &abbrechen" + +#. [Messages]StopDownload +msgid "Are you sure you want to stop the download?" +msgstr "Sind Sie sicher, dass Sie den Download abbrechen wollen?" + +#. [Messages]ErrorDownloadAborted +msgid "Download aborted" +msgstr "Download abgebrochen" + +#. [Messages]ErrorDownloadFailed +msgid "Download failed: %1 %2" +msgstr "Download fehlgeschlagen: %1 %2" + +#. [Messages]ErrorDownloadSizeFailed +msgid "Getting size failed: %1 %2" +msgstr "Fehler beim Ermitteln der Größe: %1 %2" + +#. [Messages]ErrorProgress +msgid "Invalid progress: %1 of %2" +msgstr "Ungültiger Fortschritt: %1 von %2" + +#. [Messages]ErrorFileSize +msgid "Invalid file size: expected %1, found %2" +msgstr "Ungültige Dateigröße: erwartet %1, gefunden %2" + +#. [Messages]ExtractingLabel +msgid "Extracting files..." +msgstr "Entpacke Dateien..." + +#. [Messages]ButtonStopExtraction +msgid "&Stop extraction" +msgstr "Entpacken &abbrechen" + +#. [Messages]StopExtraction +msgid "Are you sure you want to stop the extraction?" +msgstr "Sind Sie sicher, dass Sie das Entpacken abbrechen wollen?" + +#. [Messages]ErrorExtractionAborted +msgid "Extraction aborted" +msgstr "Entpacken abgebrochen" + +#. [Messages]ErrorExtractionFailed +msgid "Extraction failed: %1" +msgstr "Entpacken fehlgeschlagen: %1" + +#. [Messages]ArchiveIncorrectPassword +msgid "The password is incorrect" +msgstr "Ungültiges Passwort" + +#. [Messages]ArchiveIsCorrupted +msgid "The archive is corrupted" +msgstr "Das Archiv ist defekt" + +#. [Messages]ArchiveUnsupportedFormat +msgid "The archive format is unsupported" +msgstr "Das Archivformat wird nicht unterstützt" + +#. [Messages]WizardPreparing +msgid "Preparing to Install" +msgstr "Vorbereitung der Installation" + +#. [Messages]PreparingDesc +msgid "Setup is preparing to install [name] on your computer." +msgstr "" +"Das Setup bereitet die Installation von [name] auf diesem Computer vor." + +#. [Messages]PreviousInstallNotCompleted +msgid "" +"The installation/removal of a previous program was not completed. You will " +"need to restart your computer to complete that installation.%n%nAfter " +"restarting your computer, run Setup again to complete the installation of " +"[name]." +msgstr "" +"Eine vorherige Installation/Deinstallation eines Programms wurde nicht " +"abgeschlossen. Der Computer muss neu gestartet werden, um die " +"Installation/Deinstallation zu beenden.%n%nStarten Sie das Setup nach dem " +"Neustart Ihres Computers erneut, um die Installation von [name] " +"durchzuführen." + +#. [Messages]CannotContinue +msgid "Setup cannot continue. Please click Cancel to exit." +msgstr "" +"Das Setup kann nicht fortfahren. Bitte klicken Sie auf \"Abbrechen\" zum " +"Verlassen." + +#. [Messages]ApplicationsFound +msgid "" +"The following applications are using files that need to be updated by Setup." +" It is recommended that you allow Setup to automatically close these " +"applications." +msgstr "" +"Die folgenden Anwendungen benutzen Dateien, die aktualisiert werden müssen. " +"Es wird empfohlen, Setup zu erlauben, diese Anwendungen zu schließen." + +#. [Messages]ApplicationsFound2 +msgid "" +"The following applications are using files that need to be updated by Setup." +" It is recommended that you allow Setup to automatically close these " +"applications. After the installation has completed, Setup will attempt to " +"restart the applications." +msgstr "" +"Die folgenden Anwendungen benutzen Dateien, die aktualisiert werden müssen. " +"Es wird empfohlen, Setup zu erlauben, diese Anwendungen zu schließen. " +"Nachdem die Installation fertiggestellt wurde, versucht Setup, diese " +"Anwendungen wieder zu starten." + +#. [Messages]CloseApplications +msgid "&Automatically close the applications" +msgstr "&Schließe die Anwendungen automatisch" + +#. [Messages]DontCloseApplications +msgid "&Do not close the applications" +msgstr "Schließe die A&nwendungen nicht" + +#. [Messages]ErrorCloseApplications +msgid "" +"Setup was unable to automatically close all applications. It is recommended " +"that you close all applications using files that need to be updated by Setup" +" before continuing." +msgstr "" +"Das Setup konnte nicht alle Anwendungen automatisch schließen. Es wird " +"empfohlen, alle Anwendungen zu schließen, die Dateien benutzen, die vom " +"Setup vor einer Fortsetzung aktualisiert werden müssen." + +#. [Messages]PrepareToInstallNeedsRestart +msgid "" +"Setup must restart your computer. After restarting your computer, run Setup " +"again to complete the installation of [name].%n%nWould you like to restart " +"now?" +msgstr "" +"Das Setup muss Ihren Computer neu starten. Führen Sie nach dem Neustart " +"Setup erneut aus, um die Installation von [name] abzuschließen.%n%nWollen " +"Sie jetzt neu starten?" + +#. [Messages]WizardInstalling +msgid "Installing" +msgstr "Installiere ..." + +#. [Messages]InstallingLabel +msgid "Please wait while Setup installs [name] on your computer." +msgstr "Warten Sie bitte, während [name] auf Ihrem Computer installiert wird." + +#. [Messages]FinishedHeadingLabel +msgid "Completing the [name] Setup Wizard" +msgstr "Beenden des [name] Setup-Assistenten" + +#. [Messages]FinishedLabelNoIcons +msgid "Setup has finished installing [name] on your computer." +msgstr "" +"Das Setup hat die Installation von [name] auf Ihrem Computer abgeschlossen." + +#. [Messages]FinishedLabel +msgid "" +"Setup has finished installing [name] on your computer. The application may " +"be launched by selecting the installed shortcuts." +msgstr "" +"Das Setup hat die Installation von [name] auf Ihrem Computer abgeschlossen. " +"Die Anwendung kann über die installierten Programm-Verknüpfungen gestartet " +"werden." + +#. [Messages]ClickFinish +msgid "Click Finish to exit Setup." +msgstr "Klicken Sie auf \"Fertigstellen\", um das Setup zu beenden." + +#. [Messages]FinishedRestartLabel +msgid "" +"To complete the installation of [name], Setup must restart your computer. " +"Would you like to restart now?" +msgstr "" +"Um die Installation von [name] abzuschließen, muss das Setup Ihren Computer " +"neu starten. Möchten Sie jetzt neu starten?" + +#. [Messages]FinishedRestartMessage +msgid "" +"To complete the installation of [name], Setup must restart your " +"computer.%n%nWould you like to restart now?" +msgstr "" +"Um die Installation von [name] abzuschließen, muss das Setup Ihren Computer " +"neu starten.%n%nMöchten Sie jetzt neu starten?" + +#. [Messages]ShowReadmeCheck +msgid "Yes, I would like to view the README file" +msgstr "Ja, ich möchte die LIESMICH-Datei sehen" + +#. [Messages]YesRadio +msgid "&Yes, restart the computer now" +msgstr "&Ja, Computer jetzt neu starten" + +#. [Messages]NoRadio +msgid "&No, I will restart the computer later" +msgstr "&Nein, ich werde den Computer später neu starten" + +#. [Messages]RunEntryExec +msgid "Run %1" +msgstr "%1 starten" + +#. [Messages]RunEntryShellExec +msgid "View %1" +msgstr "%1 anzeigen" + +#. [Messages]ChangeDiskTitle +msgid "Setup Needs the Next Disk" +msgstr "Nächsten Datenträger einlegen" + +#. [Messages]SelectDiskLabel2 +msgid "" +"Please insert Disk %1 and click OK.%n%nIf the files on this disk can be " +"found in a folder other than the one displayed below, enter the correct path" +" or click Browse." +msgstr "" +"Legen Sie bitte Datenträger %1 ein und klicken Sie auf \"OK\".%n%nWenn sich " +"die Dateien von diesem Datenträger in einem anderen als dem angezeigten " +"Ordner befinden, dann geben Sie bitte den korrekten Pfad ein oder klicken " +"auf \"Durchsuchen\"." + +#. [Messages]PathLabel +msgid "&Path:" +msgstr "&Pfad:" + +#. [Messages]FileNotInDir2 +msgid "" +"The file \"%1\" could not be located in \"%2\". Please insert the correct " +"disk or select another folder." +msgstr "" +"Die Datei \"%1\" befindet sich nicht in \"%2\". Bitte Ordner ändern oder " +"richtigen Datenträger einlegen." + +#. [Messages]SelectDirectoryLabel +msgid "Please specify the location of the next disk." +msgstr "Geben Sie bitte an, wo der nächste Datenträger eingelegt wird." + +#. [Messages]SetupAborted +msgid "" +"Setup was not completed.%n%nPlease correct the problem and run Setup again." +msgstr "" +"Das Setup konnte nicht abgeschlossen werden.%n%nBeheben Sie bitte das " +"Problem und starten Sie das Setup erneut." + +#. [Messages]AbortRetryIgnoreSelectAction +msgid "Select action" +msgstr "Bitte auswählen" + +#. [Messages]AbortRetryIgnoreRetry +msgid "&Try again" +msgstr "&Nochmals versuchen" + +#. [Messages]AbortRetryIgnoreIgnore +msgid "&Ignore the error and continue" +msgstr "&Den Fehler ignorieren und fortfahren" + +#. [Messages]AbortRetryIgnoreCancel +msgid "Cancel installation" +msgstr "Installation abbrechen" + +#. [Messages]RetryCancelSelectAction +msgid "Select action" +msgstr "Bitte auswählen" + +#. [Messages]RetryCancelRetry +msgid "&Try again" +msgstr "&Wiederholen" + +#. [Messages]RetryCancelCancel +msgid "Cancel" +msgstr "&Abbrechen" + +#. [Messages]StatusClosingApplications +msgid "Closing applications..." +msgstr "Anwendungen werden geschlossen ..." + +#. [Messages]StatusCreateDirs +msgid "Creating directories..." +msgstr "Ordner werden erstellt ..." + +#. [Messages]StatusExtractFiles +msgid "Extracting files..." +msgstr "Dateien werden entpackt ..." + +#. [Messages]StatusDownloadFiles +msgid "Downloading files..." +msgstr "Dateien werden herunter geladen..." + +#. [Messages]StatusCreateIcons +msgid "Creating shortcuts..." +msgstr "Verknüpfungen werden erstellt ..." + +#. [Messages]StatusCreateIniEntries +msgid "Creating INI entries..." +msgstr "INI-Einträge werden erstellt ..." + +#. [Messages]StatusCreateRegistryEntries +msgid "Creating registry entries..." +msgstr "Registry-Einträge werden erstellt ..." + +#. [Messages]StatusRegisterFiles +msgid "Registering files..." +msgstr "Dateien werden registriert ..." + +#. [Messages]StatusSavingUninstall +msgid "Saving uninstall information..." +msgstr "Deinstallationsinformationen werden gespeichert ..." + +#. [Messages]StatusRunProgram +msgid "Finishing installation..." +msgstr "Installation wird beendet ..." + +#. [Messages]StatusRestartingApplications +msgid "Restarting applications..." +msgstr "Neustart der Anwendungen ..." + +#. [Messages]StatusRollback +msgid "Rolling back changes..." +msgstr "Änderungen werden rückgängig gemacht ..." + +#. [Messages]ErrorInternal2 +msgid "Internal error: %1" +msgstr "Interner Fehler: %1" + +#. [Messages]ErrorFunctionFailedNoCode +msgid "%1 failed" +msgstr "%1 schlug fehl" + +#. [Messages]ErrorFunctionFailed +msgid "%1 failed; code %2" +msgstr "%1 schlug fehl; Code %2" + +#. [Messages]ErrorFunctionFailedWithMessage +msgid "%1 failed; code %2.%n%3" +msgstr "%1 schlug fehl; Code %2.%n%3" + +#. [Messages]ErrorExecutingProgram +msgid "Unable to execute file:%n%1" +msgstr "Datei kann nicht ausgeführt werden:%n%1" + +#. [Messages]ErrorRegOpenKey +msgid "Error opening registry key:%n%1\\%2" +msgstr "Registry-Schlüssel konnte nicht geöffnet werden:%n%1\\%2" + +#. [Messages]ErrorRegCreateKey +msgid "Error creating registry key:%n%1\\%2" +msgstr "Registry-Schlüssel konnte nicht erstellt werden:%n%1\\%2" + +#. [Messages]ErrorRegWriteKey +msgid "Error writing to registry key:%n%1\\%2" +msgstr "Fehler beim Schreiben des Registry-Schlüssels:%n%1\\%2" + +#. [Messages]ErrorIniEntry +msgid "Error creating INI entry in file \"%1\"." +msgstr "Fehler beim Erstellen eines INI-Eintrages in der Datei \"%1\"." + +#. [Messages]FileAbortRetryIgnoreSkipNotRecommended +msgid "&Skip this file (not recommended)" +msgstr "Diese Datei &überspringen (nicht empfohlen)" + +#. [Messages]FileAbortRetryIgnoreIgnoreNotRecommended +msgid "&Ignore the error and continue (not recommended)" +msgstr "Den Fehler &ignorieren und fortfahren (nicht empfohlen)" + +#. [Messages]SourceIsCorrupted +msgid "The source file is corrupted" +msgstr "Die Quelldatei ist beschädigt" + +#. [Messages]SourceDoesntExist +msgid "The source file \"%1\" does not exist" +msgstr "Die Quelldatei \"%1\" existiert nicht" + +#. [Messages]SourceVerificationFailed +msgid "Verification of the source file failed: %1" +msgstr "Überprüfung der Quelldatei fehlgeschlagen: %1" + +#. [Messages]VerificationSignatureDoesntExist +msgid "The signature file \"%1\" does not exist" +msgstr "Die Signaturdatei \"%1\" existiert nicht" + +#. [Messages]VerificationSignatureInvalid +msgid "The signature file \"%1\" is invalid" +msgstr "Die Signaturdatei \"%1\" ist ungültig" + +#. [Messages]VerificationKeyNotFound +msgid "The signature file \"%1\" uses an unknown key" +msgstr "Die Signaturdatei \"%1\" verwendet einen unbekannten Schlüssel" + +#. [Messages]VerificationFileNameIncorrect +msgid "The name of the file is incorrect" +msgstr "Der Name der Datei ist ungültig" + +#. [Messages]VerificationFileTagIncorrect +msgid "The tag of the file is incorrect" +msgstr "Der Tag der Datei ist ungültig" + +#. [Messages]VerificationFileSizeIncorrect +msgid "The size of the file is incorrect" +msgstr "Die Größe der Datei ist ungültig" + +#. [Messages]VerificationFileHashIncorrect +msgid "The hash of the file is incorrect" +msgstr "Der Hashwert der Datei ist ungültig" + +#. [Messages]ExistingFileReadOnly2 +msgid "" +"The existing file could not be replaced because it is marked read-only." +msgstr "" +"Die vorhandene Datei kann nicht ersetzt werden, da sie schreibgeschützt ist." + +#. [Messages]ExistingFileReadOnlyRetry +msgid "&Remove the read-only attribute and try again" +msgstr "&Den Schreibschutz entfernen und noch einmal versuchen" + +#. [Messages]ExistingFileReadOnlyKeepExisting +msgid "&Keep the existing file" +msgstr "Die &vorhandene Datei behalten" + +#. [Messages]ErrorReadingExistingDest +msgid "An error occurred while trying to read the existing file:" +msgstr "Lesefehler in Datei:" + +#. [Messages]FileExistsSelectAction +msgid "Select action" +msgstr "Aktion auswählen" + +#. [Messages]FileExists2 +msgid "The file already exists." +msgstr "Die Datei ist bereits vorhanden." + +#. [Messages]FileExistsOverwriteExisting +msgid "&Overwrite the existing file" +msgstr "Vorhandene Datei &überschreiben" + +#. [Messages]FileExistsKeepExisting +msgid "&Keep the existing file" +msgstr "Vorhandene Datei &behalten" + +#. [Messages]FileExistsOverwriteOrKeepAll +msgid "&Do this for the next conflicts" +msgstr "&Dies auch für die nächsten Konflikte ausführen" + +#. [Messages]ExistingFileNewerSelectAction +msgid "Select action" +msgstr "Aktion auswählen" + +#. [Messages]ExistingFileNewer2 +msgid "The existing file is newer than the one Setup is trying to install." +msgstr "" +"Die vorhandene Datei ist neuer als die Datei, die installiert werden soll." + +#. [Messages]ExistingFileNewerOverwriteExisting +msgid "&Overwrite the existing file" +msgstr "Vorhandene Datei &überschreiben" + +#. [Messages]ExistingFileNewerKeepExisting +msgid "&Keep the existing file (recommended)" +msgstr "Vorhandene Datei &behalten (empfohlen)" + +#. [Messages]ExistingFileNewerOverwriteOrKeepAll +msgid "&Do this for the next conflicts" +msgstr "&Dies auch für die nächsten Konflikte ausführen" + +#. [Messages]ErrorChangingAttr +msgid "" +"An error occurred while trying to change the attributes of the existing " +"file:" +msgstr "Fehler beim Ändern der Datei-Attribute:" + +#. [Messages]ErrorCreatingTemp +msgid "" +"An error occurred while trying to create a file in the destination " +"directory:" +msgstr "Fehler beim Erstellen einer Datei im Ziel-Ordner:" + +#. [Messages]ErrorReadingSource +msgid "An error occurred while trying to read the source file:" +msgstr "Fehler beim Lesen der Quelldatei:" + +#. [Messages]ErrorCopying +msgid "An error occurred while trying to copy a file:" +msgstr "Fehler beim Kopieren einer Datei:" + +#. [Messages]ErrorDownloading +msgid "An error occurred while trying to download a file:" +msgstr "Beim Download der Datei ist ein Fehler aufgetreten:" + +#. [Messages]ErrorExtracting +msgid "An error occurred while trying to extract an archive:" +msgstr "Beim Entpacken eines Archivs ist ein Fehler aufgetreten:" + +#. [Messages]ErrorReplacingExistingFile +msgid "An error occurred while trying to replace the existing file:" +msgstr "Fehler beim Ersetzen einer vorhandenen Datei:" + +#. [Messages]ErrorRestartReplace +msgid "RestartReplace failed:" +msgstr "\"Ersetzen nach Neustart\" fehlgeschlagen:" + +#. [Messages]ErrorRenamingTemp +msgid "" +"An error occurred while trying to rename a file in the destination " +"directory:" +msgstr "Fehler beim Umbenennen einer Datei im Ziel-Ordner:" + +#. [Messages]ErrorRegisterServer +msgid "Unable to register the DLL/OCX: %1" +msgstr "DLL/OCX konnte nicht registriert werden: %1" + +#. [Messages]ErrorRegSvr32Failed +msgid "RegSvr32 failed with exit code %1" +msgstr "RegSvr32-Aufruf scheiterte mit Exit-Code %1" + +#. [Messages]ErrorRegisterTypeLib +msgid "Unable to register the type library: %1" +msgstr "Typen-Bibliothek konnte nicht registriert werden: %1" + +#. [Messages]UninstallDisplayNameMark +msgid "%1 (%2)" +msgstr "%1 (%2)" + +#. [Messages]UninstallDisplayNameMarks +msgid "%1 (%2, %3)" +msgstr "%1 (%2, %3)" + +#. [Messages]UninstallDisplayNameMark32Bit +msgid "32-bit" +msgstr "32 Bit" + +#. [Messages]UninstallDisplayNameMark64Bit +msgid "64-bit" +msgstr "64 Bit" + +#. [Messages]UninstallDisplayNameMarkAllUsers +msgid "All users" +msgstr "Alle Benutzer" + +#. [Messages]UninstallDisplayNameMarkCurrentUser +msgid "Current user" +msgstr "Aktueller Benutzer" + +#. [Messages]ErrorOpeningReadme +msgid "An error occurred while trying to open the README file." +msgstr "Fehler beim Öffnen der LIESMICH-Datei." + +#. [Messages]ErrorRestartingComputer +msgid "Setup was unable to restart the computer. Please do this manually." +msgstr "" +"Das Setup konnte den Computer nicht neu starten. Bitte führen Sie den " +"Neustart manuell durch." + +#. [Messages]UninstallNotFound +msgid "File \"%1\" does not exist. Cannot uninstall." +msgstr "Die Datei \"%1\" existiert nicht. Entfernen der Anwendung fehlgeschlagen." + +#. [Messages]UninstallOpenError +msgid "File \"%1\" could not be opened. Cannot uninstall" +msgstr "" +"Die Datei \"%1\" konnte nicht geöffnet werden. Entfernen der Anwendung " +"fehlgeschlagen." + +#. [Messages]UninstallUnsupportedVer +msgid "" +"The uninstall log file \"%1\" is in a format not recognized by this version " +"of the uninstaller. Cannot uninstall" +msgstr "" +"Das Format der Deinstallationsdatei \"%1\" konnte nicht erkannt werden. " +"Entfernen der Anwendung fehlgeschlagen." + +#. [Messages]UninstallUnknownEntry +msgid "An unknown entry (%1) was encountered in the uninstall log" +msgstr "" +"In der Deinstallationsdatei wurde ein unbekannter Eintrag (%1) gefunden." + +#. [Messages]ConfirmUninstall +msgid "" +"Are you sure you want to completely remove %1 and all of its components?" +msgstr "" +"Sind Sie sicher, dass Sie %1 und alle zugehörigen Komponenten entfernen " +"möchten?" + +#. [Messages]UninstallOnlyOnWin64 +msgid "This installation can only be uninstalled on 64-bit Windows." +msgstr "" +"Diese Installation kann nur unter 64-Bit-Windows-Versionen entfernt werden." + +#. [Messages]OnlyAdminCanUninstall +msgid "" +"This installation can only be uninstalled by a user with administrative " +"privileges." +msgstr "" +"Diese Installation kann nur von einem Benutzer mit Administrator-Rechten " +"entfernt werden." + +#. [Messages]UninstallStatusLabel +msgid "Please wait while %1 is removed from your computer." +msgstr "Warten Sie bitte, während %1 von Ihrem Computer entfernt wird." + +#. [Messages]UninstalledAll +msgid "%1 was successfully removed from your computer." +msgstr "%1 wurde erfolgreich von Ihrem Computer entfernt." + +#. [Messages]UninstalledMost +msgid "" +"%1 uninstall complete.%n%nSome elements could not be removed. These can be " +"removed manually." +msgstr "" +"Entfernen von %1 beendet.%n%nEinige Komponenten konnten nicht entfernt " +"werden. Diese können von Ihnen manuell gelöscht werden." + +#. [Messages]UninstalledAndNeedsRestart +msgid "" +"To complete the uninstallation of %1, your computer must be " +"restarted.%n%nWould you like to restart now?" +msgstr "" +"Um die Deinstallation von %1 abzuschließen, muss Ihr Computer neu gestartet " +"werden.%n%nMöchten Sie jetzt neu starten?" + +#. [Messages]UninstallDataCorrupted +msgid "\"%1\" file is corrupted. Cannot uninstall" +msgstr "\"%1\"-Datei ist beschädigt. Entfernen der Anwendung fehlgeschlagen." + +#. [Messages]ConfirmDeleteSharedFileTitle +msgid "Remove Shared File?" +msgstr "Gemeinsame Datei entfernen?" + +#. [Messages]ConfirmDeleteSharedFile2 +msgid "" +"The system indicates that the following shared file is no longer in use by " +"any programs. Would you like for Uninstall to remove this shared file?%n%nIf" +" any programs are still using this file and it is removed, those programs " +"may not function properly. If you are unsure, choose No. Leaving the file on" +" your system will not cause any harm." +msgstr "" +"Das System zeigt an, dass die folgende gemeinsame Datei von keinem anderen " +"Programm mehr benutzt wird. Möchten Sie diese Datei entfernen " +"lassen?%nSollte es doch noch Programme geben, die diese Datei benutzen und " +"sie wird entfernt, funktionieren diese Programme vielleicht nicht mehr " +"richtig. Wenn Sie unsicher sind, wählen Sie \"Nein\", um die Datei im System" +" zu belassen. Es schadet Ihrem System nicht, wenn Sie die Datei behalten." + +#. [Messages]SharedFileNameLabel +msgid "File name:" +msgstr "Dateiname:" + +#. [Messages]SharedFileLocationLabel +msgid "Location:" +msgstr "Ordner:" + +#. [Messages]WizardUninstalling +msgid "Uninstall Status" +msgstr "Entfernen (Status)" + +#. [Messages]StatusUninstalling +msgid "Uninstalling %1..." +msgstr "Entferne %1 ..." + +#. [Messages]ShutdownBlockReasonInstallingApp +msgid "Installing %1." +msgstr "Installation von %1." + +#. [Messages]ShutdownBlockReasonUninstallingApp +msgid "Uninstalling %1." +msgstr "Deinstallation von %1." + +#. [CustomMessages]installservicetask +msgid "Run Kolibri automatically when the computer starts" +msgstr "" + +#. [CustomMessages]newerversioninstalled +msgid "" +"A newer version of {#AppName} (%1) is already installed. This installer " +"contains version %2, which is older. The setup will now exit." +msgstr "" + +#. [CustomMessages]sameversioninstalled +msgid "" +"This version of %1 is already installed. Do you want to repair the " +"installation by reinstalling it?" +msgstr "" + +#. [CustomMessages]olderversioninstalled +msgid "" +"An older version of {#AppName} (%1) was detected. Do you want to upgrade to " +"version {#AppVersion}?" +msgstr "" + +#. [CustomMessages]confirmuninstalldata +msgid "" +"Do you want to completely remove all Kolibri user data? This includes all " +"downloaded content, user accounts, and progress, and cannot be undone." +msgstr "" + +#. [CustomMessages]criticalerror +msgid "" +"A critical error occurred while trying to run a setup command: %1. The " +"installation cannot continue." +msgstr "" + +#. [CustomMessages]commanderror +msgid "" +"A command required for setup failed to execute correctly: %1. Error Code: " +"%2. The installation cannot continue." +msgstr "" + +#. [CustomMessages]versionparseerror +msgid "" +"Could not compare versions due to an invalid version format. Please " +"uninstall the previous version manually and try again." +msgstr "" + +#. [CustomMessages]migrationfailed +msgid "" +"The installer failed to migrate user data from the old location (%1) to the " +"new location (%2). Your data has not been moved. Please contact support for " +"assistance." +msgstr "" + +#. [CustomMessages]createdesktopicon +msgid "Create a &desktop icon" +msgstr "" + +#. [CustomMessages]additionalicons +msgid "Additional icons:" +msgstr "" + +#. [CustomMessages]launchprogram +msgid "Launch %1" +msgstr "" + +#. [CustomMessages]installationtype +msgid "Installation Type:" +msgstr "" diff --git a/installer/translations/create_new_language.py b/installer/translations/create_new_language.py index aa913da..119c539 100644 --- a/installer/translations/create_new_language.py +++ b/installer/translations/create_new_language.py @@ -19,7 +19,6 @@ """ import argparse import configparser -import shutil from pathlib import Path SOURCE_TEMPLATE = "English.isl" @@ -49,13 +48,18 @@ def _merge_with_standard_isl(standard_path: Path, master_path: Path, dest_path: # Add the [CustomMessages] section if it exists in the master if "CustomMessages" in master_config: - final_config["CustomMessages"] = master_config["CustomMessages"] + # First, ensure the [CustomMessages] section exists. If not, add it. + if not final_config.has_section("CustomMessages"): + final_config.add_section("CustomMessages") + + for key, _ in master_config.items("CustomMessages"): + final_config.set("CustomMessages", key, "") else: print("Warning: No [CustomMessages] section found in the English template.") final_config.add_section("CustomMessages") # Add an empty section # Write the merged result to the new file - with open(dest_path, "w", encoding="utf-8") as f: + with open(dest_path, "w", encoding="utf-8-sig") as f: final_config.write(f, space_around_delimiters=False) return "merged" @@ -67,17 +71,39 @@ def _merge_with_standard_isl(standard_path: Path, master_path: Path, dest_path: return "error" -def _copy_from_english_template(source_path: Path, dest_path: Path): +def _create_from_english_template(source_path: Path, dest_path: Path): """ - Creates a new language file by copying the English template. + Creates a new language file from the English template, but with empty values + for all translatable strings. """ - print("Falling back to creating from the English template.") - try: - shutil.copy(source_path, dest_path) - return "copied" - except (shutil.SameFileError, FileNotFoundError, PermissionError, OSError) as e: - print(f"Copy error: {e}") - return "error" + print("Falling back to creating a blank template from English.isl.") + # Load the English template + template_config = configparser.ConfigParser( + allow_no_value=True, interpolation=None, strict=False + ) + template_config.optionxform = str + template_config.read(source_path, encoding="utf-8-sig") + + # Create a new config for the new language + new_lang_config = configparser.ConfigParser( + allow_no_value=True, interpolation=None, strict=False + ) + new_lang_config.optionxform = str + + # Iterate through the template sections + for section in template_config.sections(): + new_lang_config.add_section(section) + if section == "LangOptions": + for key, value in template_config.items(section): + new_lang_config.set(section, key, value) + else: + for key, _ in template_config.items(section): + new_lang_config.set(section, key, "") + + with open(dest_path, "w", encoding="utf-8-sig") as f: + new_lang_config.write(f, space_around_delimiters=False) + + return "created" def create_new_language_file(language_name: str, inno_languages_dir: str): @@ -105,12 +131,12 @@ def create_new_language_file(language_name: str, inno_languages_dir: str): # Case 1: Standard Inno Setup file exists. MERGE IT. mode = _merge_with_standard_isl(standard_isl_path, source_path, dest_path) else: - # Case 2: No standard file found. FALL BACK to copying. + # Case 2: No standard file found. FALL BACK to creating a blank template. if inno_languages_dir: print(f"Info: Standard Inno Setup file not found for '{language_name}'.") else: print("Info: Inno Setup languages directory not provided.") - mode = _copy_from_english_template(source_path, dest_path) + mode = _create_from_english_template(source_path, dest_path) if mode != "error": print_success_message(dest_path, mode) @@ -125,7 +151,7 @@ def print_success_message(path, mode): print( r' Example for Spanish, Name: "es"; MessagesFile: "translations\Spanish.isl"' ) - if mode == "copied": + if mode == "created": print("2. Configure the [LangOptions] section in the new .isl file") diff --git a/installer/translations/isl_to_po.py b/installer/translations/isl_to_po.py new file mode 100644 index 0000000..9e2454f --- /dev/null +++ b/installer/translations/isl_to_po.py @@ -0,0 +1,92 @@ +import argparse +import configparser +from datetime import datetime + +import polib + + +def convert_isl_to_po( + template_isl_path, translated_isl_path, output_po_path, language_code="" +): + """ + Converts an ISL file to a PO file, using another ISL as a template. + - template_isl_path (e.g., English.isl): Used for msgid. + - translated_isl_path (e.g., German.isl): Used for msgstr. + """ + encoding = "utf-8-sig" + + # Read the English template for msgids + template_config = configparser.ConfigParser(interpolation=None) + template_config.optionxform = str + template_config.read(template_isl_path, encoding=encoding) + + # Read the translated file for msgstrs + translated_config = configparser.ConfigParser(interpolation=None) + translated_config.optionxform = str + translated_config.read(translated_isl_path, encoding=encoding) + + # Create a new PO file object + po = polib.POFile() + + # Add Metadata to the PO file + now_iso = datetime.now().astimezone().isoformat() + po.metadata = { + "Project-Id-Version": "kolibri-windows-installer", + "Report-Msgid-Bugs-To": " ", + "POT-Creation-Date": now_iso, + "PO-Revision-Date": now_iso, + "Last-Translator": "FULL NAME ", + "Language-Team": " ", + "Language": language_code, + "MIME-Version": "1.0", + "Content-Type": "text/plain; charset=utf-8", + "Content-Transfer-Encoding": "8bit", + } + + # Process all sections in the template + for section in template_config.sections(): + if section not in translated_config: + continue + + for key in template_config[section]: + if not key: + continue + + msgid = template_config[section][key] + msgstr = translated_config.get(section, key, fallback="") + + entry = polib.POEntry( + msgid=msgid, msgstr=msgstr, comment=f"[{section}]{key}" + ) + po.append(entry) + + print(f"Successfully created PO file: {output_po_path}") + po.save(output_po_path) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Convert ISL files to PO format.") + parser.add_argument( + "-t", + "--template", + required=True, + help="Path to the template ISL file (e.g., English.isl).", + ) + parser.add_argument( + "-i", + "--input", + required=True, + help="Path to the translated ISL file (e.g., German.isl).", + ) + parser.add_argument( + "-o", + "--output", + required=True, + help="Path for the output PO file (e.g., German.po).", + ) + parser.add_argument( + "-l", "--lang", required=True, help="Language code (e.g., 'de_DE', 'bg_BG')." + ) + args = parser.parse_args() + + convert_isl_to_po(args.template, args.input, args.output, args.lang) diff --git a/installer/translations/po_to_isl.py b/installer/translations/po_to_isl.py new file mode 100644 index 0000000..dde40d3 --- /dev/null +++ b/installer/translations/po_to_isl.py @@ -0,0 +1,61 @@ +import argparse +import configparser + +import polib + + +def convert_po_to_isl(template_isl_path, translated_po_path, output_isl_path): + encoding = "utf-8-sig" + + # 1. Load the translated .po file + po = polib.pofile(translated_po_path, encoding="utf-8") + + # 2. Create a lookup map from msgid (English) to msgstr (Translated) + translation_map = { + entry.msgid: entry.msgstr for entry in po if entry.msgstr and entry.msgid + } + + # 3. Load the template .isl file to get the structure and keys + template_config = configparser.ConfigParser(interpolation=None) + template_config.optionxform = str + template_config.read(template_isl_path, encoding=encoding) + + # 4. Iterate through the template and replace values with translations + for section in template_config.sections(): + for key in template_config[section]: + english_string = template_config[section][key] + + translated_string = translation_map.get(english_string) + + # If a translation exists, update the value in our config object + if translated_string: + template_config.set(section, key, translated_string) + + print(f"Successfully created ISL file: {output_isl_path}") + with open(output_isl_path, "w", encoding="utf-8-sig") as f: + template_config.write(f, space_around_delimiters=False) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Convert PO files back to ISL format.") + parser.add_argument( + "-t", + "--template", + required=True, + help="Path to the template ISL file (e.g., English.isl).", + ) + parser.add_argument( + "-i", + "--input", + required=True, + help="Path to the translated PO file (e.g., German.po).", + ) + parser.add_argument( + "-o", + "--output", + required=True, + help="Path for the output ISL file (e.g., German.isl).", + ) + args = parser.parse_args() + + convert_po_to_isl(args.template, args.input, args.output) From a1039f6c7cdf28e2f16046e14e99912cebcc88db Mon Sep 17 00:00:00 2001 From: Dimitrios Mylonas Date: Thu, 27 Nov 2025 11:39:45 +0200 Subject: [PATCH 3/4] refactor(installer): standardize on locale codes and automate translation config Changes: - Renamed translation files and directories to use ISO codes (e.g., `es_ES` instead of `Spanish`), removing ambiguity. - Added `definitions.py` as a single source of truth for Microsoft Language IDs and Inno Setup names, removing the need to manually configure `[LangOptions]`. - Workflow Refactor: - Removed `create_new_language.py`, its logic is now integrated into `isl_to_po.py` via the `new-language` target. - Updated `po_to_isl.py` to automatically add the correct Language ID during compilation. - Updated `Makefile` and `kolibri.iss` to support the new `translations/locale//` directory structure. --- .gitignore | 1 + Makefile | 81 ++- installer/kolibri.iss | 33 +- installer/translations/German.isl | 302 --------- installer/translations/create_new_language.py | 173 ----- installer/translations/definitions.py | 16 + .../translations/{English.isl => en.isl} | 9 +- installer/translations/isl_to_po.py | 138 ++-- .../{German.po => locale/de_DE/messages.po} | 609 +++++++++--------- installer/translations/po_to_isl.py | 73 +-- 10 files changed, 498 insertions(+), 937 deletions(-) delete mode 100644 installer/translations/German.isl delete mode 100644 installer/translations/create_new_language.py create mode 100644 installer/translations/definitions.py rename installer/translations/{English.isl => en.isl} (99%) rename installer/translations/{German.po => locale/de_DE/messages.po} (74%) diff --git a/.gitignore b/.gitignore index 2be7ccd..756a0e7 100644 --- a/.gitignore +++ b/.gitignore @@ -140,3 +140,4 @@ installer/MicrosoftEdgeWebView2RuntimeInstallerX64.exe installer/nssm.exe update_report.txt installer/dist-installer/ +installer/translations/locale/*/*.isl diff --git a/Makefile b/Makefile index 31e06f9..dab99de 100644 --- a/Makefile +++ b/Makefile @@ -143,44 +143,59 @@ endif INNO_DEFAULT_ISL ?= C:/Program Files (x86)/Inno Setup 6/Default.isl INNO_LANGUAGES_DIR ?= C:/Program Files (x86)/Inno Setup 6/Languages +TRANSLATIONS_DIR := installer/translations +LOCALE_DIR := $(TRANSLATIONS_DIR)/locale +TEMPLATE_ISL := $(TRANSLATIONS_DIR)/en.isl +SCRIPT_ISL_TO_PO := $(TRANSLATIONS_DIR)/isl_to_po.py +SCRIPT_PO_TO_ISL := $(TRANSLATIONS_DIR)/po_to_isl.py + +# New Language Target +# Usage: make new-language LANG=es_ES .PHONY: new-language new-language: $(MAKE) guard-LANG - @echo "Creating new language scaffolding for '$(LANG)'..." - $(PYTHON_EXEC) installer/translations/create_new_language.py \ - --name "$(LANG)" \ - --inno-languages-dir "$(INNO_LANGUAGES_DIR)" + @echo "Scaffolding new PO file for locale '$(LANG)'..." + $(PYTHON_EXEC) $(SCRIPT_ISL_TO_PO) \ + --template $(TEMPLATE_ISL) \ + --output $(LOCALE_DIR)/$(LANG)/messages.po \ + --lang "$(LANG)" \ + --inno-dir "$(INNO_LANGUAGES_DIR)" \ + --no-overwrite -TRANSLATIONS_DIR := installer/translations -ISL_TO_PO_SCRIPT := $(TRANSLATIONS_DIR)/isl_to_po.py -PO_TO_ISL_SCRIPT := $(TRANSLATIONS_DIR)/po_to_isl.py +# Export Source Target (en) +.PHONY: translations-export-source +translations-export-source: + @echo "Exporting master en.isl to locale/en/messages.po (Source)..." + $(PYTHON_EXEC) $(SCRIPT_ISL_TO_PO) \ + --template $(TEMPLATE_ISL) \ + --output $(LOCALE_DIR)/en/messages.po \ + --lang "en" -# Usage example: make translations-export LANG=German LANG_CODE=de_DE -# Exports a single .isl file to a .po file for translators. -.PHONY: translations-export -translations-export: - $(MAKE) guard-LANG - $(MAKE) guard-LANG_CODE - @echo "Exporting '$(LANG).isl' to a .po file for translators..." - $(PYTHON_EXEC) $(ISL_TO_PO_SCRIPT) \ - -t $(TRANSLATIONS_DIR)/English.isl \ - -i $(TRANSLATIONS_DIR)/$(LANG).isl \ - -o $(TRANSLATIONS_DIR)/$(LANG).po \ - -l "$(LANG_CODE)" - -# Compiles all .po files in the translations dir into their final .isl format. -# Runs automatically before the windows installer is built. +# Compile Target (PO -> ISL) .PHONY: translations-compile translations-compile: - @echo "Compiling .po files to .isl format for Inno Setup..." - @for po_file in $(TRANSLATIONS_DIR)/*.po; do \ - if [ -f "$$po_file" ]; then \ - lang_name=$$(basename "$$po_file" .po); \ - echo " -> Processing $${lang_name}.po -> $${lang_name}.isl"; \ - $(PYTHON_EXEC) $(PO_TO_ISL_SCRIPT) \ - -t $(TRANSLATIONS_DIR)/English.isl \ - -i "$$po_file" \ - -o "$(TRANSLATIONS_DIR)/$${lang_name}.isl"; \ + @echo "Compiling PO files to ISL format..." + @# Loop through directories in translations/locale/ + @for lang_dir in $(LOCALE_DIR)/*; do \ + if [ -d "$$lang_dir" ]; then \ + lang_code=$$(basename "$$lang_dir"); \ + \ + # Skip 'en' because we use the master en.isl template directly \ + if [ "$$lang_code" = "en" ]; then \ + continue; \ + fi; \ + \ + po_file="$$lang_dir/messages.po"; \ + isl_file="$$lang_dir/$${lang_code}.isl"; \ + \ + if [ -f "$$po_file" ]; then \ + echo " -> Processing $$lang_code ..."; \ + $(PYTHON_EXEC) $(SCRIPT_PO_TO_ISL) \ + -t $(TEMPLATE_ISL) \ + -i "$$po_file" \ + -o "$$isl_file" \ + -l "$$lang_code"; \ + fi \ fi \ done @@ -189,8 +204,8 @@ update-translations: @echo "Updating master language file from '$(INNO_DEFAULT_ISL)'..." $(PYTHON_EXEC) installer/translations/update_from_inno_default.py \ --new-default "$(INNO_DEFAULT_ISL)" \ - --project-master "installer/translations/English.isl" - @echo "Update complete. Please review update_report.txt and commit the changes to English.isl." + --project-master "$(TEMPLATE_ISL)" + @echo "Update complete. Please review update_report.txt and commit the changes to en.isl." compile-mo: find src/kolibri_app/locales -name LC_MESSAGES -exec msgfmt {}/wxapp.po -o {}/wxapp.mo \; diff --git a/installer/kolibri.iss b/installer/kolibri.iss index e3b0189..a9602c7 100644 --- a/installer/kolibri.iss +++ b/installer/kolibri.iss @@ -41,36 +41,9 @@ CloseApplicationsFilter={#AppExeName} ShowLanguageDialog=yes [Languages] -Name: "en"; MessagesFile: "translations\English.isl" -; Name: "af_ZA"; MessagesFile: "translations\Afrikaans.isl" -; Name: "ar"; MessagesFile: "translations\Arabic.isl" -; Name: "bg"; MessagesFile: "translations\Bulgarian.isl" -; Name: "bn"; MessagesFile: "translations\Bengali.isl" -; Name: "my"; MessagesFile: "translations\Burmese.isl" -; Name: "ny"; MessagesFile: "translations\Chewa.isl" -; Name: "zh_CN"; MessagesFile: "translations\Chinese_Simplified.isl" -Name: "de"; MessagesFile: "translations\German.isl" -; Name: "fa"; MessagesFile: "translations\Persian.isl" -; Name: "fr"; MessagesFile: "translations\French.isl" -; Name: "fv"; MessagesFile: "translations\Fulfulde_Mbororoore.isl" -; Name: "ka"; MessagesFile: "translations\Georgian.isl" -; Name: "gu_IN"; MessagesFile: "translations\Gujarati.isl" -; Name: "hi"; MessagesFile: "translations\Hindi.isl" -; Name: "it"; MessagesFile: "translations\Italian.isl" -; Name: "km"; MessagesFile: "translations\Khmer.isl" -; Name: "ko"; MessagesFile: "translations\Korean.isl" -; Name: "la"; MessagesFile: "translations\Spanish_Latin_America.isl" -; Name: "mr"; MessagesFile: "translations\Marathi.isl" -; Name: "ne_NP"; MessagesFile: "translations\Nepali.isl" -; Name: "pt_BR"; MessagesFile: "translations\Portuguese_Brazilian.isl" -; Name: "es_ES"; MessagesFile: "translations\Spanish.isl" -; Name: "sw_TZ"; MessagesFile: "translations\Swahili_Tanzania.isl" -; Name: "tl"; MessagesFile: "translations\Tagalog.isl" -; Name: "te"; MessagesFile: "translations\Telugu.isl" -; Name: "tr"; MessagesFile: "translations\Turkish.isl" -; Name: "ur_PK"; MessagesFile: "translations\Urdu_(Pakistan).isl" -; Name: "vi"; MessagesFile: "translations\Vietnamese.isl" -; Name: "yo"; MessagesFile: "translations\Yoruba.isl" +Name: "en"; MessagesFile: "translations\en.isl" +; Name: "fr_FR"; MessagesFile: "translations\locale\fr_FR\fr_FR.isl" +Name: "de_DE"; MessagesFile: "translations\locale\de_DE\de_DE.isl" [Registry] ; This registry key is used to detect the installed version for upgrades/repairs. diff --git a/installer/translations/German.isl b/installer/translations/German.isl deleted file mode 100644 index 12c5158..0000000 --- a/installer/translations/German.isl +++ /dev/null @@ -1,302 +0,0 @@ -[LangOptions] -languagename=German -languageid=$0407 -languagecodepage=0 - -[Messages] -SetupAppTitle=Setup -SetupWindowTitle=Setup - %1 -UninstallAppTitle=Entfernen -UninstallAppFullTitle=%1 entfernen -InformationTitle=Information -ConfirmTitle=Bestätigen -ErrorTitle=Fehler -SetupLdrStartupMessage=%1 wird jetzt installiert. Möchten Sie fortfahren? -LdrCannotCreateTemp=Es konnte keine temporäre Datei erstellt werden. Das Setup wurde abgebrochen -LdrCannotExecTemp=Die Datei konnte nicht im temporären Ordner ausgeführt werden. Das Setup wurde abgebrochen -HelpTextNote= -LastErrorMessage=%1.%n%nFehler %2: %3 -SetupFileMissing=Die Datei %1 fehlt im Installationsordner. Bitte beheben Sie das Problem oder besorgen Sie sich eine neue Kopie des Programms. -SetupFileCorrupt=Die Setup-Dateien sind beschädigt. Besorgen Sie sich bitte eine neue Kopie des Programms. -SetupFileCorruptOrWrongVer=Die Setup-Dateien sind beschädigt oder inkompatibel zu dieser Version des Setups. Bitte beheben Sie das Problem oder besorgen Sie sich eine neue Kopie des Programms. -InvalidParameter=Ein ungültiger Parameter wurde auf der Kommandozeile übergeben:%n%n%1 -SetupAlreadyRunning=Setup läuft bereits. -WindowsVersionNotSupported=Dieses Programm unterstützt die auf Ihrem Computer installierte Windows-Version nicht. -WindowsServicePackRequired=Dieses Programm benötigt %1 Service Pack %2 oder höher. -NotOnThisPlatform=Dieses Programm kann nicht unter %1 ausgeführt werden. -OnlyOnThisPlatform=Dieses Programm muss unter %1 ausgeführt werden. -OnlyOnTheseArchitectures=Dieses Programm kann nur auf Windows-Versionen installiert werden, die folgende Prozessor-Architekturen unterstützen:%n%n%1 -WinVersionTooLowError=Dieses Programm benötigt %1 Version %2 oder höher. -WinVersionTooHighError=Dieses Programm kann nicht unter %1 Version %2 oder höher installiert werden. -AdminPrivilegesRequired=Sie müssen als Administrator angemeldet sein, um dieses Programm installieren zu können. -PowerUserPrivilegesRequired=Sie müssen als Administrator oder als Mitglied der Hauptbenutzer-Gruppe angemeldet sein, um dieses Programm installieren zu können. -SetupAppRunningError=Das Setup hat entdeckt, dass %1 zurzeit ausgeführt wird.%n%nBitte schließen Sie jetzt alle laufenden Instanzen und klicken Sie auf "OK", um fortzufahren, oder auf "Abbrechen", um zu beenden. -UninstallAppRunningError=Die Deinstallation hat entdeckt, dass %1 zurzeit ausgeführt wird.%n%nBitte schließen Sie jetzt alle laufenden Instanzen und klicken Sie auf "OK", um fortzufahren, oder auf "Abbrechen", um zu beenden. -PrivilegesRequiredOverrideTitle=Installationsmodus auswählen -PrivilegesRequiredOverrideInstruction=Bitte wählen Sie den Installationsmodus -PrivilegesRequiredOverrideText1=%1 kann für alle Benutzer (erfordert Administrationsrechte) oder nur für Sie installiert werden. -PrivilegesRequiredOverrideText2=%1 kann nur für Sie oder für alle Benutzer (erfordert Administrationsrechte) installiert werden. -PrivilegesRequiredOverrideAllUsers=Installation für &alle Benutzer -PrivilegesRequiredOverrideAllUsersRecommended=Installation für &alle Benutzer (empfohlen) -PrivilegesRequiredOverrideCurrentUser=Installation nur für &Sie -PrivilegesRequiredOverrideCurrentUserRecommended=Installation nur für &Sie (empfohlen) -ErrorCreatingDir=Das Setup konnte den Ordner "%1" nicht erstellen. -ErrorTooManyFilesInDir=Das Setup konnte eine Datei im Ordner "%1" nicht erstellen, weil er zu viele Dateien enthält. -ExitSetupTitle=Setup verlassen -ExitSetupMessage=Das Setup ist noch nicht abgeschlossen. Wenn Sie jetzt beenden, wird das Programm nicht installiert.%n%nSie können das Setup zu einem späteren Zeitpunkt nochmals ausführen, um die Installation zu vervollständigen.%n%nSetup verlassen? -AboutSetupMenuItem=&Über das Setup ... -AboutSetupTitle=Über das Setup -AboutSetupMessage=%1 Version %2%n%3%n%n%1 Webseite:%n%4 -AboutSetupNote= -TranslatorNote= -ButtonBack=< &Zurück -ButtonNext=&Weiter > -ButtonInstall=&Installieren -ButtonOK=OK -ButtonCancel=&Abbrechen -ButtonYes=&Ja -ButtonYesToAll=J&a für Alle -ButtonNo=&Nein -ButtonNoToAll=N&ein für Alle -ButtonFinish=&Fertigstellen -ButtonBrowse=&Durchsuchen ... -ButtonWizardBrowse=Du&rchsuchen ... -ButtonNewFolder=&Neuen Ordner erstellen -SelectLanguageTitle=Setup-Sprache auswählen -SelectLanguageLabel=Wählen Sie die Sprache aus, die während der Installation benutzt werden soll: -ClickNext="Weiter" zum Fortfahren, "Abbrechen" zum Verlassen. -BeveledLabel= -BrowseDialogTitle=Ordner suchen -BrowseDialogLabel=Wählen Sie einen Ordner aus und klicken Sie danach auf "OK". -NewFolderName=Neuer Ordner -WelcomeLabel1=Willkommen zum [name] Setup-Assistenten -WelcomeLabel2=Dieser Assistent wird jetzt [name/ver] auf Ihrem Computer installieren.%n%nSie sollten alle anderen Anwendungen beenden, bevor Sie mit dem Setup fortfahren. -WizardPassword=Passwort -PasswordLabel1=Diese Installation wird durch ein Passwort geschützt. -PasswordLabel3=Bitte geben Sie das Passwort ein und klicken Sie danach auf "Weiter". Achten Sie auf korrekte Groß-/Kleinschreibung. -PasswordEditLabel=&Passwort: -IncorrectPassword=Das eingegebene Passwort ist nicht korrekt. Bitte versuchen Sie es noch einmal. -WizardLicense=Lizenzvereinbarung -LicenseLabel=Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren. -LicenseLabel3=Lesen Sie bitte die folgenden Lizenzvereinbarungen. Benutzen Sie bei Bedarf die Bildlaufleiste oder drücken Sie die "Bild Ab"-Taste. -LicenseAccepted=Ich &akzeptiere die Vereinbarung -LicenseNotAccepted=Ich &lehne die Vereinbarung ab -WizardInfoBefore=Information -InfoBeforeLabel=Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren. -InfoBeforeClickLabel=Klicken Sie auf "Weiter", sobald Sie bereit sind, mit dem Setup fortzufahren. -WizardInfoAfter=Information -InfoAfterLabel=Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren. -InfoAfterClickLabel=Klicken Sie auf "Weiter", sobald Sie bereit sind, mit dem Setup fortzufahren. -WizardUserInfo=Benutzerinformationen -UserInfoDesc=Bitte tragen Sie Ihre Daten ein. -UserInfoName=&Name: -UserInfoOrg=&Organisation: -UserInfoSerial=&Seriennummer: -UserInfoNameRequired=Sie müssen einen Namen eintragen. -WizardSelectDir=Ziel-Ordner wählen -SelectDirDesc=Wohin soll [name] installiert werden? -SelectDirLabel3=Das Setup wird [name] in den folgenden Ordner installieren. -SelectDirBrowseLabel=Klicken Sie auf "Weiter", um fortzufahren. Klicken Sie auf "Durchsuchen", falls Sie einen anderen Ordner auswählen möchten. -DiskSpaceGBLabel=Mindestens [gb] GB freier Speicherplatz ist erforderlich. -DiskSpaceMBLabel=Mindestens [mb] MB freier Speicherplatz ist erforderlich. -CannotInstallToNetworkDrive=Das Setup kann nicht in einen Netzwerk-Pfad installieren. -CannotInstallToUNCPath=Das Setup kann nicht in einen UNC-Pfad installieren. Wenn Sie auf ein Netzlaufwerk installieren möchten, müssen Sie dem Netzwerkpfad einen Laufwerksbuchstaben zuordnen. -InvalidPath=Sie müssen einen vollständigen Pfad mit einem Laufwerksbuchstaben angeben, z. B.:%n%nC:\Beispiel%n%noder einen UNC-Pfad in der Form:%n%n\\Server\Freigabe -InvalidDrive=Das angegebene Laufwerk bzw. der UNC-Pfad existiert nicht oder es kann nicht darauf zugegriffen werden. Wählen Sie bitte einen anderen Ordner. -DiskSpaceWarningTitle=Nicht genug freier Speicherplatz -DiskSpaceWarning=Das Setup benötigt mindestens %1 KB freien Speicherplatz zum Installieren, aber auf dem ausgewählten Laufwerk sind nur %2 KB verfügbar.%n%nMöchten Sie trotzdem fortfahren? -DirNameTooLong=Der Ordnername/Pfad ist zu lang. -InvalidDirName=Der Ordnername ist nicht gültig. -BadDirName32=Ordnernamen dürfen keine der folgenden Zeichen enthalten:%n%n%1 -DirExistsTitle=Ordner existiert bereits -DirExists=Der Ordner:%n%n%1%n%n existiert bereits. Möchten Sie trotzdem in diesen Ordner installieren? -DirDoesntExistTitle=Ordner ist nicht vorhanden -DirDoesntExist=Der Ordner:%n%n%1%n%nist nicht vorhanden. Soll der Ordner erstellt werden? -WizardSelectComponents=Komponenten auswählen -SelectComponentsDesc=Welche Komponenten sollen installiert werden? -SelectComponentsLabel2=Wählen Sie die Komponenten aus, die Sie installieren möchten. Klicken Sie auf "Weiter", wenn Sie bereit sind, fortzufahren. -FullInstallation=Vollständige Installation -CompactInstallation=Kompakte Installation -CustomInstallation=Benutzerdefinierte Installation -NoUninstallWarningTitle=Komponenten vorhanden -NoUninstallWarning=Das Setup hat festgestellt, dass die folgenden Komponenten bereits auf Ihrem Computer installiert sind:%n%n%1%n%nDiese nicht mehr ausgewählten Komponenten werden nicht vom Computer entfernt.%n%nMöchten Sie trotzdem fortfahren? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceGBLabel=Die aktuelle Auswahl erfordert mindestens [gb] GB Speicherplatz. -ComponentsDiskSpaceMBLabel=Die aktuelle Auswahl erfordert mindestens [mb] MB Speicherplatz. -WizardSelectTasks=Zusätzliche Aufgaben auswählen -SelectTasksDesc=Welche zusätzlichen Aufgaben sollen ausgeführt werden? -SelectTasksLabel2=Wählen Sie die zusätzlichen Aufgaben aus, die das Setup während der Installation von [name] ausführen soll, und klicken Sie danach auf "Weiter". -WizardSelectProgramGroup=Startmenü-Ordner auswählen -SelectStartMenuFolderDesc=Wo soll das Setup die Programm-Verknüpfungen erstellen? -SelectStartMenuFolderLabel3=Das Setup wird die Programm-Verknüpfungen im folgenden Startmenü-Ordner erstellen. -SelectStartMenuFolderBrowseLabel=Klicken Sie auf "Weiter", um fortzufahren. Klicken Sie auf "Durchsuchen", falls Sie einen anderen Ordner auswählen möchten. -MustEnterGroupName=Sie müssen einen Ordnernamen eingeben. -GroupNameTooLong=Der Ordnername/Pfad ist zu lang. -InvalidGroupName=Der Ordnername ist nicht gültig. -BadGroupName=Der Ordnername darf keine der folgenden Zeichen enthalten:%n%n%1 -NoProgramGroupCheck2=&Keinen Ordner im Startmenü erstellen -WizardReady=Bereit zur Installation. -ReadyLabel1=Das Setup ist jetzt bereit, [name] auf Ihrem Computer zu installieren. -ReadyLabel2a=Klicken Sie auf "Installieren", um mit der Installation zu beginnen, oder auf "Zurück", um Ihre Einstellungen zu überprüfen oder zu ändern. -ReadyLabel2b=Klicken Sie auf "Installieren", um mit der Installation zu beginnen. -ReadyMemoUserInfo=Benutzerinformationen: -ReadyMemoDir=Ziel-Ordner: -ReadyMemoType=Setup-Typ: -ReadyMemoComponents=Ausgewählte Komponenten: -ReadyMemoGroup=Startmenü-Ordner: -ReadyMemoTasks=Zusätzliche Aufgaben: -DownloadingLabel2=Dateien werden herunter geladen... -ButtonStopDownload=Download &abbrechen -StopDownload=Sind Sie sicher, dass Sie den Download abbrechen wollen? -ErrorDownloadAborted=Download abgebrochen -ErrorDownloadFailed=Download fehlgeschlagen: %1 %2 -ErrorDownloadSizeFailed=Fehler beim Ermitteln der Größe: %1 %2 -ErrorProgress=Ungültiger Fortschritt: %1 von %2 -ErrorFileSize=Ungültige Dateigröße: erwartet %1, gefunden %2 -ExtractingLabel=Dateien werden entpackt ... -ButtonStopExtraction=Entpacken &abbrechen -StopExtraction=Sind Sie sicher, dass Sie das Entpacken abbrechen wollen? -ErrorExtractionAborted=Entpacken abgebrochen -ErrorExtractionFailed=Entpacken fehlgeschlagen: %1 -ArchiveIncorrectPassword=Ungültiges Passwort -ArchiveIsCorrupted=Das Archiv ist defekt -ArchiveUnsupportedFormat=Das Archivformat wird nicht unterstützt -WizardPreparing=Vorbereitung der Installation -PreparingDesc=Das Setup bereitet die Installation von [name] auf diesem Computer vor. -PreviousInstallNotCompleted=Eine vorherige Installation/Deinstallation eines Programms wurde nicht abgeschlossen. Der Computer muss neu gestartet werden, um die Installation/Deinstallation zu beenden.%n%nStarten Sie das Setup nach dem Neustart Ihres Computers erneut, um die Installation von [name] durchzuführen. -CannotContinue=Das Setup kann nicht fortfahren. Bitte klicken Sie auf "Abbrechen" zum Verlassen. -ApplicationsFound=Die folgenden Anwendungen benutzen Dateien, die aktualisiert werden müssen. Es wird empfohlen, Setup zu erlauben, diese Anwendungen zu schließen. -ApplicationsFound2=Die folgenden Anwendungen benutzen Dateien, die aktualisiert werden müssen. Es wird empfohlen, Setup zu erlauben, diese Anwendungen zu schließen. Nachdem die Installation fertiggestellt wurde, versucht Setup, diese Anwendungen wieder zu starten. -CloseApplications=&Schließe die Anwendungen automatisch -DontCloseApplications=Schließe die A&nwendungen nicht -ErrorCloseApplications=Das Setup konnte nicht alle Anwendungen automatisch schließen. Es wird empfohlen, alle Anwendungen zu schließen, die Dateien benutzen, die vom Setup vor einer Fortsetzung aktualisiert werden müssen. -PrepareToInstallNeedsRestart=Das Setup muss Ihren Computer neu starten. Führen Sie nach dem Neustart Setup erneut aus, um die Installation von [name] abzuschließen.%n%nWollen Sie jetzt neu starten? -WizardInstalling=Installiere ... -InstallingLabel=Warten Sie bitte, während [name] auf Ihrem Computer installiert wird. -FinishedHeadingLabel=Beenden des [name] Setup-Assistenten -FinishedLabelNoIcons=Das Setup hat die Installation von [name] auf Ihrem Computer abgeschlossen. -FinishedLabel=Das Setup hat die Installation von [name] auf Ihrem Computer abgeschlossen. Die Anwendung kann über die installierten Programm-Verknüpfungen gestartet werden. -ClickFinish=Klicken Sie auf "Fertigstellen", um das Setup zu beenden. -FinishedRestartLabel=Um die Installation von [name] abzuschließen, muss das Setup Ihren Computer neu starten. Möchten Sie jetzt neu starten? -FinishedRestartMessage=Um die Installation von [name] abzuschließen, muss das Setup Ihren Computer neu starten.%n%nMöchten Sie jetzt neu starten? -ShowReadmeCheck=Ja, ich möchte die LIESMICH-Datei sehen -YesRadio=&Ja, Computer jetzt neu starten -NoRadio=&Nein, ich werde den Computer später neu starten -RunEntryExec=%1 starten -RunEntryShellExec=%1 anzeigen -ChangeDiskTitle=Nächsten Datenträger einlegen -SelectDiskLabel2=Legen Sie bitte Datenträger %1 ein und klicken Sie auf "OK".%n%nWenn sich die Dateien von diesem Datenträger in einem anderen als dem angezeigten Ordner befinden, dann geben Sie bitte den korrekten Pfad ein oder klicken auf "Durchsuchen". -PathLabel=&Pfad: -FileNotInDir2=Die Datei "%1" befindet sich nicht in "%2". Bitte Ordner ändern oder richtigen Datenträger einlegen. -SelectDirectoryLabel=Geben Sie bitte an, wo der nächste Datenträger eingelegt wird. -SetupAborted=Das Setup konnte nicht abgeschlossen werden.%n%nBeheben Sie bitte das Problem und starten Sie das Setup erneut. -AbortRetryIgnoreSelectAction=Aktion auswählen -AbortRetryIgnoreRetry=&Wiederholen -AbortRetryIgnoreIgnore=&Den Fehler ignorieren und fortfahren -AbortRetryIgnoreCancel=Installation abbrechen -RetryCancelSelectAction=Aktion auswählen -RetryCancelRetry=&Wiederholen -RetryCancelCancel=&Abbrechen -StatusClosingApplications=Anwendungen werden geschlossen ... -StatusCreateDirs=Ordner werden erstellt ... -StatusExtractFiles=Dateien werden entpackt ... -StatusDownloadFiles=Dateien werden herunter geladen... -StatusCreateIcons=Verknüpfungen werden erstellt ... -StatusCreateIniEntries=INI-Einträge werden erstellt ... -StatusCreateRegistryEntries=Registry-Einträge werden erstellt ... -StatusRegisterFiles=Dateien werden registriert ... -StatusSavingUninstall=Deinstallationsinformationen werden gespeichert ... -StatusRunProgram=Installation wird beendet ... -StatusRestartingApplications=Neustart der Anwendungen ... -StatusRollback=Änderungen werden rückgängig gemacht ... -ErrorInternal2=Interner Fehler: %1 -ErrorFunctionFailedNoCode=%1 schlug fehl -ErrorFunctionFailed=%1 schlug fehl; Code %2 -ErrorFunctionFailedWithMessage=%1 schlug fehl; Code %2.%n%3 -ErrorExecutingProgram=Datei kann nicht ausgeführt werden:%n%1 -ErrorRegOpenKey=Registry-Schlüssel konnte nicht geöffnet werden:%n%1\%2 -ErrorRegCreateKey=Registry-Schlüssel konnte nicht erstellt werden:%n%1\%2 -ErrorRegWriteKey=Fehler beim Schreiben des Registry-Schlüssels:%n%1\%2 -ErrorIniEntry=Fehler beim Erstellen eines INI-Eintrages in der Datei "%1". -FileAbortRetryIgnoreSkipNotRecommended=Diese Datei &überspringen (nicht empfohlen) -FileAbortRetryIgnoreIgnoreNotRecommended=Den Fehler &ignorieren und fortfahren (nicht empfohlen) -SourceIsCorrupted=Die Quelldatei ist beschädigt -SourceDoesntExist=Die Quelldatei "%1" existiert nicht -SourceVerificationFailed=Überprüfung der Quelldatei fehlgeschlagen: %1 -VerificationSignatureDoesntExist=Die Signaturdatei "%1" existiert nicht -VerificationSignatureInvalid=Die Signaturdatei "%1" ist ungültig -VerificationKeyNotFound=Die Signaturdatei "%1" verwendet einen unbekannten Schlüssel -VerificationFileNameIncorrect=Der Name der Datei ist ungültig -VerificationFileTagIncorrect=Der Tag der Datei ist ungültig -VerificationFileSizeIncorrect=Die Größe der Datei ist ungültig -VerificationFileHashIncorrect=Der Hashwert der Datei ist ungültig -ExistingFileReadOnly2=Die vorhandene Datei kann nicht ersetzt werden, da sie schreibgeschützt ist. -ExistingFileReadOnlyRetry=&Den Schreibschutz entfernen und noch einmal versuchen -ExistingFileReadOnlyKeepExisting=Vorhandene Datei &behalten -ErrorReadingExistingDest=Lesefehler in Datei: -FileExistsSelectAction=Aktion auswählen -FileExists2=Die Datei ist bereits vorhanden. -FileExistsOverwriteExisting=Vorhandene Datei &überschreiben -FileExistsKeepExisting=Vorhandene Datei &behalten -FileExistsOverwriteOrKeepAll=&Dies auch für die nächsten Konflikte ausführen -ExistingFileNewerSelectAction=Aktion auswählen -ExistingFileNewer2=Die vorhandene Datei ist neuer als die Datei, die installiert werden soll. -ExistingFileNewerOverwriteExisting=Vorhandene Datei &überschreiben -ExistingFileNewerKeepExisting=Vorhandene Datei &behalten (empfohlen) -ExistingFileNewerOverwriteOrKeepAll=&Dies auch für die nächsten Konflikte ausführen -ErrorChangingAttr=Fehler beim Ändern der Datei-Attribute: -ErrorCreatingTemp=Fehler beim Erstellen einer Datei im Ziel-Ordner: -ErrorReadingSource=Fehler beim Lesen der Quelldatei: -ErrorCopying=Fehler beim Kopieren einer Datei: -ErrorDownloading=Beim Download der Datei ist ein Fehler aufgetreten: -ErrorExtracting=Beim Entpacken eines Archivs ist ein Fehler aufgetreten: -ErrorReplacingExistingFile=Fehler beim Ersetzen einer vorhandenen Datei: -ErrorRestartReplace="Ersetzen nach Neustart" fehlgeschlagen: -ErrorRenamingTemp=Fehler beim Umbenennen einer Datei im Ziel-Ordner: -ErrorRegisterServer=DLL/OCX konnte nicht registriert werden: %1 -ErrorRegSvr32Failed=RegSvr32-Aufruf scheiterte mit Exit-Code %1 -ErrorRegisterTypeLib=Typen-Bibliothek konnte nicht registriert werden: %1 -UninstallDisplayNameMark=%1 (%2) -UninstallDisplayNameMarks=%1 (%2, %3) -UninstallDisplayNameMark32Bit=32 Bit -UninstallDisplayNameMark64Bit=64 Bit -UninstallDisplayNameMarkAllUsers=Alle Benutzer -UninstallDisplayNameMarkCurrentUser=Aktueller Benutzer -ErrorOpeningReadme=Fehler beim Öffnen der LIESMICH-Datei. -ErrorRestartingComputer=Das Setup konnte den Computer nicht neu starten. Bitte führen Sie den Neustart manuell durch. -UninstallNotFound=Die Datei "%1" existiert nicht. Entfernen der Anwendung fehlgeschlagen. -UninstallOpenError=Die Datei "%1" konnte nicht geöffnet werden. Entfernen der Anwendung fehlgeschlagen. -UninstallUnsupportedVer=Das Format der Deinstallationsdatei "%1" konnte nicht erkannt werden. Entfernen der Anwendung fehlgeschlagen. -UninstallUnknownEntry=In der Deinstallationsdatei wurde ein unbekannter Eintrag (%1) gefunden. -ConfirmUninstall=Sind Sie sicher, dass Sie %1 und alle zugehörigen Komponenten entfernen möchten? -UninstallOnlyOnWin64=Diese Installation kann nur unter 64-Bit-Windows-Versionen entfernt werden. -OnlyAdminCanUninstall=Diese Installation kann nur von einem Benutzer mit Administrator-Rechten entfernt werden. -UninstallStatusLabel=Warten Sie bitte, während %1 von Ihrem Computer entfernt wird. -UninstalledAll=%1 wurde erfolgreich von Ihrem Computer entfernt. -UninstalledMost=Entfernen von %1 beendet.%n%nEinige Komponenten konnten nicht entfernt werden. Diese können von Ihnen manuell gelöscht werden. -UninstalledAndNeedsRestart=Um die Deinstallation von %1 abzuschließen, muss Ihr Computer neu gestartet werden.%n%nMöchten Sie jetzt neu starten? -UninstallDataCorrupted="%1"-Datei ist beschädigt. Entfernen der Anwendung fehlgeschlagen. -ConfirmDeleteSharedFileTitle=Gemeinsame Datei entfernen? -ConfirmDeleteSharedFile2=Das System zeigt an, dass die folgende gemeinsame Datei von keinem anderen Programm mehr benutzt wird. Möchten Sie diese Datei entfernen lassen?%nSollte es doch noch Programme geben, die diese Datei benutzen und sie wird entfernt, funktionieren diese Programme vielleicht nicht mehr richtig. Wenn Sie unsicher sind, wählen Sie "Nein", um die Datei im System zu belassen. Es schadet Ihrem System nicht, wenn Sie die Datei behalten. -SharedFileNameLabel=Dateiname: -SharedFileLocationLabel=Ordner: -WizardUninstalling=Entfernen (Status) -StatusUninstalling=Entferne %1 ... -ShutdownBlockReasonInstallingApp=Installation von %1. -ShutdownBlockReasonUninstallingApp=Deinstallation von %1. - -[CustomMessages] -installservicetask=Run Kolibri automatically when the computer starts -newerversioninstalled=A newer version of {#AppName} (%1) is already installed. This installer contains version %2, which is older. The setup will now exit. -sameversioninstalled=This version of %1 is already installed. Do you want to repair the installation by reinstalling it? -olderversioninstalled=An older version of {#AppName} (%1) was detected. Do you want to upgrade to version {#AppVersion}? -confirmuninstalldata=Do you want to completely remove all Kolibri user data? This includes all downloaded content, user accounts, and progress, and cannot be undone. -criticalerror=A critical error occurred while trying to run a setup command: %1. The installation cannot continue. -commanderror=A command required for setup failed to execute correctly: %1. Error Code: %2. The installation cannot continue. -versionparseerror=Could not compare versions due to an invalid version format. Please uninstall the previous version manually and try again. -migrationfailed=The installer failed to migrate user data from the old location (%1) to the new location (%2). Your data has not been moved. Please contact support for assistance. -createdesktopicon=Create a &desktop icon -additionalicons=Additional icons: -launchprogram=Launch %1 -installationtype=Installation Type: diff --git a/installer/translations/create_new_language.py b/installer/translations/create_new_language.py deleted file mode 100644 index 119c539..0000000 --- a/installer/translations/create_new_language.py +++ /dev/null @@ -1,173 +0,0 @@ -""" -Create New Inno Setup Language File (`.isl`). - -This script automates the creation of a new language file for the Kolibri -Windows installer. It's reusing existing translations from the standard -Inno Setup language packs, when they are available. - -Workflow: -1. Takes a language name (e.g., "French") as an argument. -2. Checks for a corresponding standard language file (e.g., "French.isl") - in the specified Inno Setup installation directory. -3. If a standard file is found, it merges the pre-translated `[Messages]` - section from that file with the project-specific `[CustomMessages]` - from the local `English.isl` template. -4. If no standard file is found, it falls back to creating a direct copy of - the `English.isl` template. -5. The final output is a new `.isl` file in the `translations` directory, - ready to be translated and enabled in `kolibri.iss`. -""" -import argparse -import configparser -from pathlib import Path - -SOURCE_TEMPLATE = "English.isl" -TRANSLATIONS_DIR = Path(__file__).parent.resolve() - - -def _merge_with_standard_isl(standard_path: Path, master_path: Path, dest_path: Path): - """ - Merges a standard Inno Setup language file with the project's master template. - """ - print(f"Found standard Inno Setup file: {standard_path}") - print("Merging standard messages with project's custom messages...") - try: - # Load the standard Inno file (pre-translated [Messages]) - final_config = configparser.ConfigParser( - allow_no_value=True, interpolation=None, strict=False - ) - final_config.optionxform = str - final_config.read(standard_path, encoding="utf-8-sig") - - # Load our English template to get the custom messages - master_config = configparser.ConfigParser( - allow_no_value=True, interpolation=None, strict=False - ) - master_config.optionxform = str - master_config.read(master_path, encoding="utf-8-sig") - - # Add the [CustomMessages] section if it exists in the master - if "CustomMessages" in master_config: - # First, ensure the [CustomMessages] section exists. If not, add it. - if not final_config.has_section("CustomMessages"): - final_config.add_section("CustomMessages") - - for key, _ in master_config.items("CustomMessages"): - final_config.set("CustomMessages", key, "") - else: - print("Warning: No [CustomMessages] section found in the English template.") - final_config.add_section("CustomMessages") # Add an empty section - - # Write the merged result to the new file - with open(dest_path, "w", encoding="utf-8-sig") as f: - final_config.write(f, space_around_delimiters=False) - - return "merged" - except (configparser.Error, UnicodeDecodeError) as e: - print(f"Config/encoding error: {e}") - return "error" - except (OSError,) as e: - print(f"Filesystem error: {e}") - return "error" - - -def _create_from_english_template(source_path: Path, dest_path: Path): - """ - Creates a new language file from the English template, but with empty values - for all translatable strings. - """ - print("Falling back to creating a blank template from English.isl.") - # Load the English template - template_config = configparser.ConfigParser( - allow_no_value=True, interpolation=None, strict=False - ) - template_config.optionxform = str - template_config.read(source_path, encoding="utf-8-sig") - - # Create a new config for the new language - new_lang_config = configparser.ConfigParser( - allow_no_value=True, interpolation=None, strict=False - ) - new_lang_config.optionxform = str - - # Iterate through the template sections - for section in template_config.sections(): - new_lang_config.add_section(section) - if section == "LangOptions": - for key, value in template_config.items(section): - new_lang_config.set(section, key, value) - else: - for key, _ in template_config.items(section): - new_lang_config.set(section, key, "") - - with open(dest_path, "w", encoding="utf-8-sig") as f: - new_lang_config.write(f, space_around_delimiters=False) - - return "created" - - -def create_new_language_file(language_name: str, inno_languages_dir: str): - dest_filename = f"{language_name}.isl" - dest_path = TRANSLATIONS_DIR / dest_filename - source_path = TRANSLATIONS_DIR / SOURCE_TEMPLATE - - print(f"Attempting to create new language file: {dest_path}") - - if dest_path.exists(): - print(f"Error: A file for '{language_name}' already exists at {dest_path}") - print("Aborting to prevent data loss.") - return - - if not source_path.exists(): - print(f"Error: Master template '{SOURCE_TEMPLATE}' not found.") - return - - standard_isl_path = None - if inno_languages_dir: - standard_isl_path = Path(inno_languages_dir) / dest_filename - - mode = "error" - if standard_isl_path and standard_isl_path.exists(): - # Case 1: Standard Inno Setup file exists. MERGE IT. - mode = _merge_with_standard_isl(standard_isl_path, source_path, dest_path) - else: - # Case 2: No standard file found. FALL BACK to creating a blank template. - if inno_languages_dir: - print(f"Info: Standard Inno Setup file not found for '{language_name}'.") - else: - print("Info: Inno Setup languages directory not provided.") - mode = _create_from_english_template(source_path, dest_path) - - if mode != "error": - print_success_message(dest_path, mode) - - -def print_success_message(path, mode): - print(f"\nSuccess! New language file created: {path}") - print("\n--- Next Steps ---") - print( - r"1. Add the new language to the [Languages] section in 'installer\kolibri.iss'." - ) - print( - r' Example for Spanish, Name: "es"; MessagesFile: "translations\Spanish.isl"' - ) - if mode == "created": - print("2. Configure the [LangOptions] section in the new .isl file") - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Scaffold a new Inno Setup language file from the English template." - ) - parser.add_argument( - "--name", - required=True, - help="The name of the new language (e.g., 'French', 'Spanish'). This will be used for the filename.", - ) - parser.add_argument( - "--inno-languages-dir", - help="Optional: Path to the 'Languages' directory of your Inno Setup installation.", - ) - args = parser.parse_args() - - create_new_language_file(args.name, args.inno_languages_dir) diff --git a/installer/translations/definitions.py b/installer/translations/definitions.py new file mode 100644 index 0000000..2166380 --- /dev/null +++ b/installer/translations/definitions.py @@ -0,0 +1,16 @@ +# Map functionality: +# Key: The ISO locale code (used for filenames, e.g., 'es_ES.isl', 'es_ES.po') +# inno_name: The filename of the standard Inno Setup translation (e.g., 'Spanish.isl') +# or just use the name you want to display in the installer's language selection. +# id: The Microsoft Language ID required by Windows, can be found here: +# MS IDs: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c + +LANG_DEFINITIONS = { + "en": {"inno_name": "English", "id": "$0409"}, # Exists in Inno Languages + "es_ES": {"inno_name": "Spanish", "id": "$040A"}, # Exists in Inno Languages + "de_DE": {"inno_name": "German", "id": "$0407"}, # Exists in Inno Languages + "ar_SA": {"inno_name": "Arabic", "id": "$0401"}, # Exists in Inno Languages + "fr_FR": {"inno_name": "French", "id": "$040C"}, # Exists in Inno Languages + "ko_KR": {"inno_name": "Korean", "id": "$0412"}, # Exists in Inno Languages + "yo_NG": {"inno_name": "Yoruba", "id": "$0438"}, # Does NOT exist in Inno Languages +} diff --git a/installer/translations/English.isl b/installer/translations/en.isl similarity index 99% rename from installer/translations/English.isl rename to installer/translations/en.isl index f63e087..dfcd100 100644 --- a/installer/translations/English.isl +++ b/installer/translations/en.isl @@ -1,10 +1,7 @@ -; Master English messages for Kolibri Installer -; Last updated: 2025-10-15T09:48:28Z - -[LangOptions] -languagename=English -languageid=$0409 +[LangOptions] languagecodepage=0 +LanguageName=English +LanguageID=$0409 [Messages] SetupAppTitle=Setup diff --git a/installer/translations/isl_to_po.py b/installer/translations/isl_to_po.py index 9e2454f..ce119ae 100644 --- a/installer/translations/isl_to_po.py +++ b/installer/translations/isl_to_po.py @@ -1,51 +1,87 @@ import argparse import configparser +import os +import sys from datetime import datetime +from pathlib import Path import polib +from definitions import LANG_DEFINITIONS -def convert_isl_to_po( - template_isl_path, translated_isl_path, output_po_path, language_code="" -): +def resolve_input_file(locale_code, inno_dir, direct_input): """ - Converts an ISL file to a PO file, using another ISL as a template. - - template_isl_path (e.g., English.isl): Used for msgid. - - translated_isl_path (e.g., German.isl): Used for msgstr. + Determines the path to the translation file (e.g., es_ES.isl). + Returns None if generating the source (en) or if file not found. """ + # Case 1: Direct file path provided + if direct_input: + return direct_input + + # Case 2: Auto-lookup based on directory and definitions + if inno_dir and locale_code in LANG_DEFINITIONS: + inno_name = LANG_DEFINITIONS[locale_code]["inno_name"] + candidate = Path(inno_dir) / f"{inno_name}.isl" + if candidate.exists(): + print(f" -> Found standard Inno Setup translations: {candidate}") + return str(candidate) + else: + print( + f" -> Warning: Standard file '{inno_name}.isl' not found in {inno_dir}." + ) + + return None + + +def main( + template_path, + output_path, + locale_code, + input_path=None, + inno_dir=None, + no_overwrite=False, +): encoding = "utf-8-sig" - # Read the English template for msgids + if no_overwrite and os.path.exists(output_path): + print(f"Error: The file '{output_path}' already exists.") + print("Aborting to prevent overwriting existing translations.") + sys.exit(1) + + # Resolve the secondary file (Translations) + translated_file_path = resolve_input_file(locale_code, inno_dir, input_path) + + # Read English Template (Keys) template_config = configparser.ConfigParser(interpolation=None) template_config.optionxform = str - template_config.read(template_isl_path, encoding=encoding) + template_config.read(template_path, encoding=encoding) - # Read the translated file for msgstrs + # Read Translated File (Values) - if it exists translated_config = configparser.ConfigParser(interpolation=None) translated_config.optionxform = str - translated_config.read(translated_isl_path, encoding=encoding) - # Create a new PO file object - po = polib.POFile() + has_translation = False + if translated_file_path and os.path.exists(translated_file_path): + translated_config.read(translated_file_path, encoding=encoding) + has_translation = True - # Add Metadata to the PO file + # Create PO Object + po = polib.POFile() now_iso = datetime.now().astimezone().isoformat() po.metadata = { "Project-Id-Version": "kolibri-windows-installer", - "Report-Msgid-Bugs-To": " ", "POT-Creation-Date": now_iso, "PO-Revision-Date": now_iso, - "Last-Translator": "FULL NAME ", - "Language-Team": " ", - "Language": language_code, - "MIME-Version": "1.0", + "Language": locale_code, "Content-Type": "text/plain; charset=utf-8", - "Content-Transfer-Encoding": "8bit", } - # Process all sections in the template + # Merge Logic + print(f" -> Generating PO file for '{locale_code}'...") + for section in template_config.sections(): - if section not in translated_config: + # Filter out technical sections + if section in ["LangOptions", "Setup"]: continue for key in template_config[section]: @@ -53,40 +89,54 @@ def convert_isl_to_po( continue msgid = template_config[section][key] - msgstr = translated_config.get(section, key, fallback="") + msgstr = "" + + # Only fill msgstr if we are NOT in English AND we have a translation file + if locale_code != "en" and has_translation: + if translated_config.has_section(section): + msgstr = translated_config.get(section, key, fallback="") entry = polib.POEntry( - msgid=msgid, msgstr=msgstr, comment=f"[{section}]{key}" + msgid=msgid, msgstr=msgstr, msgctxt=f"[{section}]{key}" ) po.append(entry) - print(f"Successfully created PO file: {output_po_path}") - po.save(output_po_path) + output_dir = os.path.dirname(output_path) + if output_dir and not os.path.exists(output_dir): + os.makedirs(output_dir) + + po.save(output_path) + print(f" -> Success! Created: {output_path}") if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Convert ISL files to PO format.") - parser.add_argument( - "-t", - "--template", - required=True, - help="Path to the template ISL file (e.g., English.isl).", + parser = argparse.ArgumentParser( + description="Generate PO files from Inno Setup ISL files." ) - parser.add_argument( - "-i", - "--input", - required=True, - help="Path to the translated ISL file (e.g., German.isl).", - ) - parser.add_argument( - "-o", - "--output", - required=True, - help="Path for the output PO file (e.g., German.po).", + + # Required + parser.add_argument("-t", "--template", required=True, help="Path to en.isl") + parser.add_argument("-o", "--output", required=True, help="Path to output .po file") + parser.add_argument("-l", "--lang", required=True, help="Locale code (e.g. es_ES)") + + # Optional (Choose one or the other or neither) + group = parser.add_mutually_exclusive_group() + group.add_argument("-i", "--input", help="Direct path to a translated ISL file") + group.add_argument( + "--inno-dir", help="Directory of Inno Setup Languages to auto-lookup files" ) + parser.add_argument( - "-l", "--lang", required=True, help="Language code (e.g., 'de_DE', 'bg_BG')." + "--no-overwrite", action="store_true", help="Prevent overwriting existing files" ) + args = parser.parse_args() - convert_isl_to_po(args.template, args.input, args.output, args.lang) + main( + args.template, + args.output, + args.lang, + args.input, + args.inno_dir, + args.no_overwrite, + ) diff --git a/installer/translations/German.po b/installer/translations/locale/de_DE/messages.po similarity index 74% rename from installer/translations/German.po rename to installer/translations/locale/de_DE/messages.po index 3dbbe8b..2198d8e 100644 --- a/installer/translations/German.po +++ b/installer/translations/locale/de_DE/messages.po @@ -2,80 +2,63 @@ msgid "" msgstr "" "Project-Id-Version: kolibri-windows-installer\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-10-25T16:10:15.833345+03:00\n" -"PO-Revision-Date: 2025-10-25T16:10:15.833345+03:00\n" -"Last-Translator: FULL NAME \n" -"Language-Team: \n" +"POT-Creation-Date: 2025-11-27T10:48:24.094016+02:00\n" +"PO-Revision-Date: 2025-11-27T10:48:24.094016+02:00\n" "Language: de_DE\n" -"MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -#. [LangOptions]languagename -msgid "English" -msgstr "German" - -#. [LangOptions]languageid -msgid "$0409" -msgstr "$0407" - -#. [LangOptions]languagecodepage -msgid "0" -msgstr "0" - -#. [Messages]SetupAppTitle +msgctxt "[Messages]SetupAppTitle" msgid "Setup" msgstr "Setup" -#. [Messages]SetupWindowTitle +msgctxt "[Messages]SetupWindowTitle" msgid "Setup - %1" msgstr "Setup - %1" -#. [Messages]UninstallAppTitle +msgctxt "[Messages]UninstallAppTitle" msgid "Uninstall" msgstr "Entfernen" -#. [Messages]UninstallAppFullTitle +msgctxt "[Messages]UninstallAppFullTitle" msgid "%1 Uninstall" msgstr "%1 entfernen" -#. [Messages]InformationTitle +msgctxt "[Messages]InformationTitle" msgid "Information" msgstr "Information" -#. [Messages]ConfirmTitle +msgctxt "[Messages]ConfirmTitle" msgid "Confirm" msgstr "Bestätigen" -#. [Messages]ErrorTitle +msgctxt "[Messages]ErrorTitle" msgid "Error" msgstr "Fehler" -#. [Messages]SetupLdrStartupMessage +msgctxt "[Messages]SetupLdrStartupMessage" msgid "This will install %1. Do you wish to continue?" msgstr "%1 wird jetzt installiert. Möchten Sie fortfahren?" -#. [Messages]LdrCannotCreateTemp +msgctxt "[Messages]LdrCannotCreateTemp" msgid "Unable to create a temporary file. Setup aborted" msgstr "" "Es konnte keine temporäre Datei erstellt werden. Das Setup wurde abgebrochen" -#. [Messages]LdrCannotExecTemp +msgctxt "[Messages]LdrCannotExecTemp" msgid "Unable to execute file in the temporary directory. Setup aborted" msgstr "" "Die Datei konnte nicht im temporären Ordner ausgeführt werden. Das Setup " "wurde abgebrochen" -#. [Messages]HelpTextNote +msgctxt "[Messages]HelpTextNote" msgid "" msgstr "" -#. [Messages]LastErrorMessage +msgctxt "[Messages]LastErrorMessage" msgid "%1.%n%nError %2: %3" msgstr "%1.%n%nFehler %2: %3" -#. [Messages]SetupFileMissing +msgctxt "[Messages]SetupFileMissing" msgid "" "The file %1 is missing from the installation directory. Please correct the " "problem or obtain a new copy of the program." @@ -83,14 +66,14 @@ msgstr "" "Die Datei %1 fehlt im Installationsordner. Bitte beheben Sie das Problem " "oder besorgen Sie sich eine neue Kopie des Programms." -#. [Messages]SetupFileCorrupt +msgctxt "[Messages]SetupFileCorrupt" msgid "" "The setup files are corrupted. Please obtain a new copy of the program." msgstr "" "Die Setup-Dateien sind beschädigt. Besorgen Sie sich bitte eine neue Kopie " "des Programms." -#. [Messages]SetupFileCorruptOrWrongVer +msgctxt "[Messages]SetupFileCorruptOrWrongVer" msgid "" "The setup files are corrupted, or are incompatible with this version of " "Setup. Please correct the problem or obtain a new copy of the program." @@ -99,15 +82,15 @@ msgstr "" "Setups. Bitte beheben Sie das Problem oder besorgen Sie sich eine neue Kopie" " des Programms." -#. [Messages]InvalidParameter +msgctxt "[Messages]InvalidParameter" msgid "An invalid parameter was passed on the command line:%n%n%1" msgstr "Ein ungültiger Parameter wurde auf der Kommandozeile übergeben:%n%n%1" -#. [Messages]SetupAlreadyRunning +msgctxt "[Messages]SetupAlreadyRunning" msgid "Setup is already running." msgstr "Setup läuft bereits." -#. [Messages]WindowsVersionNotSupported +msgctxt "[Messages]WindowsVersionNotSupported" msgid "" "This program does not support the version of Windows your computer is " "running." @@ -115,19 +98,19 @@ msgstr "" "Dieses Programm unterstützt die auf Ihrem Computer installierte Windows-" "Version nicht." -#. [Messages]WindowsServicePackRequired +msgctxt "[Messages]WindowsServicePackRequired" msgid "This program requires %1 Service Pack %2 or later." msgstr "Dieses Programm benötigt %1 Service Pack %2 oder höher." -#. [Messages]NotOnThisPlatform +msgctxt "[Messages]NotOnThisPlatform" msgid "This program will not run on %1." msgstr "Dieses Programm kann nicht unter %1 ausgeführt werden." -#. [Messages]OnlyOnThisPlatform +msgctxt "[Messages]OnlyOnThisPlatform" msgid "This program must be run on %1." msgstr "Dieses Programm muss unter %1 ausgeführt werden." -#. [Messages]OnlyOnTheseArchitectures +msgctxt "[Messages]OnlyOnTheseArchitectures" msgid "" "This program can only be installed on versions of Windows designed for the " "following processor architectures:%n%n%1" @@ -135,24 +118,24 @@ msgstr "" "Dieses Programm kann nur auf Windows-Versionen installiert werden, die " "folgende Prozessor-Architekturen unterstützen:%n%n%1" -#. [Messages]WinVersionTooLowError +msgctxt "[Messages]WinVersionTooLowError" msgid "This program requires %1 version %2 or later." msgstr "Dieses Programm benötigt %1 Version %2 oder höher." -#. [Messages]WinVersionTooHighError +msgctxt "[Messages]WinVersionTooHighError" msgid "This program cannot be installed on %1 version %2 or later." msgstr "" "Dieses Programm kann nicht unter %1 Version %2 oder höher installiert " "werden." -#. [Messages]AdminPrivilegesRequired +msgctxt "[Messages]AdminPrivilegesRequired" msgid "" "You must be logged in as an administrator when installing this program." msgstr "" "Sie müssen als Administrator angemeldet sein, um dieses Programm " "installieren zu können." -#. [Messages]PowerUserPrivilegesRequired +msgctxt "[Messages]PowerUserPrivilegesRequired" msgid "" "You must be logged in as an administrator or as a member of the Power Users " "group when installing this program." @@ -160,7 +143,7 @@ msgstr "" "Sie müssen als Administrator oder als Mitglied der Hauptbenutzer-Gruppe " "angemeldet sein, um dieses Programm installieren zu können." -#. [Messages]SetupAppRunningError +msgctxt "[Messages]SetupAppRunningError" msgid "" "Setup has detected that %1 is currently running.%n%nPlease close all " "instances of it now, then click OK to continue, or Cancel to exit." @@ -169,7 +152,7 @@ msgstr "" "Sie jetzt alle laufenden Instanzen und klicken Sie auf \"OK\", um " "fortzufahren, oder auf \"Abbrechen\", um zu beenden." -#. [Messages]UninstallAppRunningError +msgctxt "[Messages]UninstallAppRunningError" msgid "" "Uninstall has detected that %1 is currently running.%n%nPlease close all " "instances of it now, then click OK to continue, or Cancel to exit." @@ -178,15 +161,15 @@ msgstr "" "schließen Sie jetzt alle laufenden Instanzen und klicken Sie auf \"OK\", um " "fortzufahren, oder auf \"Abbrechen\", um zu beenden." -#. [Messages]PrivilegesRequiredOverrideTitle +msgctxt "[Messages]PrivilegesRequiredOverrideTitle" msgid "Select Setup Install Mode" msgstr "Installationsmodus auswählen" -#. [Messages]PrivilegesRequiredOverrideInstruction +msgctxt "[Messages]PrivilegesRequiredOverrideInstruction" msgid "Select install mode" msgstr "Bitte wählen Sie den Installationsmodus" -#. [Messages]PrivilegesRequiredOverrideText1 +msgctxt "[Messages]PrivilegesRequiredOverrideText1" msgid "" "%1 can be installed for all users (requires administrative privileges), or " "for you only." @@ -194,7 +177,7 @@ msgstr "" "%1 kann für alle Benutzer (erfordert Administrationsrechte) oder nur für Sie" " installiert werden." -#. [Messages]PrivilegesRequiredOverrideText2 +msgctxt "[Messages]PrivilegesRequiredOverrideText2" msgid "" "%1 can be installed for you only, or for all users (requires administrative " "privileges)." @@ -202,27 +185,27 @@ msgstr "" "%1 kann nur für Sie oder für alle Benutzer (erfordert Administrationsrechte)" " installiert werden." -#. [Messages]PrivilegesRequiredOverrideAllUsers +msgctxt "[Messages]PrivilegesRequiredOverrideAllUsers" msgid "Install for &all users" msgstr "Installation für &alle Benutzer" -#. [Messages]PrivilegesRequiredOverrideAllUsersRecommended +msgctxt "[Messages]PrivilegesRequiredOverrideAllUsersRecommended" msgid "Install for &all users (recommended)" msgstr "Installation für &alle Benutzer (empfohlen)" -#. [Messages]PrivilegesRequiredOverrideCurrentUser +msgctxt "[Messages]PrivilegesRequiredOverrideCurrentUser" msgid "Install for &me only" msgstr "Installation nur für &Sie" -#. [Messages]PrivilegesRequiredOverrideCurrentUserRecommended +msgctxt "[Messages]PrivilegesRequiredOverrideCurrentUserRecommended" msgid "Install for &me only (recommended)" msgstr "Installation nur für &Sie (empfohlen)" -#. [Messages]ErrorCreatingDir +msgctxt "[Messages]ErrorCreatingDir" msgid "Setup was unable to create the directory \"%1\"" msgstr "Das Setup konnte den Ordner \"%1\" nicht erstellen." -#. [Messages]ErrorTooManyFilesInDir +msgctxt "[Messages]ErrorTooManyFilesInDir" msgid "" "Unable to create a file in the directory \"%1\" because it contains too many" " files" @@ -230,11 +213,11 @@ msgstr "" "Das Setup konnte eine Datei im Ordner \"%1\" nicht erstellen, weil er zu " "viele Dateien enthält." -#. [Messages]ExitSetupTitle +msgctxt "[Messages]ExitSetupTitle" msgid "Exit Setup" msgstr "Setup verlassen" -#. [Messages]ExitSetupMessage +msgctxt "[Messages]ExitSetupMessage" msgid "" "Setup is not complete. If you exit now, the program will not be " "installed.%n%nYou may run Setup again at another time to complete the " @@ -245,114 +228,114 @@ msgstr "" "Zeitpunkt nochmals ausführen, um die Installation zu " "vervollständigen.%n%nSetup verlassen?" -#. [Messages]AboutSetupMenuItem +msgctxt "[Messages]AboutSetupMenuItem" msgid "&About Setup..." msgstr "&Über das Setup ..." -#. [Messages]AboutSetupTitle +msgctxt "[Messages]AboutSetupTitle" msgid "About Setup" msgstr "Über das Setup" -#. [Messages]AboutSetupMessage +msgctxt "[Messages]AboutSetupMessage" msgid "%1 version %2%n%3%n%n%1 home page:%n%4" msgstr "%1 Version %2%n%3%n%n%1 Webseite:%n%4" -#. [Messages]AboutSetupNote +msgctxt "[Messages]AboutSetupNote" msgid "" msgstr "" -#. [Messages]TranslatorNote +msgctxt "[Messages]TranslatorNote" msgid "" msgstr "" "German translation maintained by Jens Brand (jens.brand@wolf-software.de)" -#. [Messages]ButtonBack +msgctxt "[Messages]ButtonBack" msgid "< &Back" msgstr "< &Zurück" -#. [Messages]ButtonNext +msgctxt "[Messages]ButtonNext" msgid "&Next >" msgstr "&Weiter >" -#. [Messages]ButtonInstall +msgctxt "[Messages]ButtonInstall" msgid "&Install" msgstr "&Installieren" -#. [Messages]ButtonOK +msgctxt "[Messages]ButtonOK" msgid "OK" msgstr "OK" -#. [Messages]ButtonCancel +msgctxt "[Messages]ButtonCancel" msgid "Cancel" msgstr "Abbrechen" -#. [Messages]ButtonYes +msgctxt "[Messages]ButtonYes" msgid "&Yes" msgstr "&Ja" -#. [Messages]ButtonYesToAll +msgctxt "[Messages]ButtonYesToAll" msgid "Yes to &All" msgstr "J&a für Alle" -#. [Messages]ButtonNo +msgctxt "[Messages]ButtonNo" msgid "&No" msgstr "&Nein" -#. [Messages]ButtonNoToAll +msgctxt "[Messages]ButtonNoToAll" msgid "N&o to All" msgstr "N&ein für Alle" -#. [Messages]ButtonFinish +msgctxt "[Messages]ButtonFinish" msgid "&Finish" msgstr "&Fertigstellen" -#. [Messages]ButtonBrowse +msgctxt "[Messages]ButtonBrowse" msgid "&Browse..." msgstr "&Durchsuchen ..." -#. [Messages]ButtonWizardBrowse +msgctxt "[Messages]ButtonWizardBrowse" msgid "B&rowse..." msgstr "Du&rchsuchen ..." -#. [Messages]ButtonNewFolder +msgctxt "[Messages]ButtonNewFolder" msgid "&Make New Folder" msgstr "&Neuen Ordner erstellen" -#. [Messages]SelectLanguageTitle +msgctxt "[Messages]SelectLanguageTitle" msgid "Select Setup Language" msgstr "Setup-Sprache auswählen" -#. [Messages]SelectLanguageLabel +msgctxt "[Messages]SelectLanguageLabel" msgid "Select the language to use during the installation." msgstr "" "Wählen Sie die Sprache aus, die während der Installation benutzt werden " "soll:" -#. [Messages]ClickNext +msgctxt "[Messages]ClickNext" msgid "Click Next to continue, or Cancel to exit Setup." msgstr "\"Weiter\" zum Fortfahren, \"Abbrechen\" zum Verlassen." -#. [Messages]BeveledLabel +msgctxt "[Messages]BeveledLabel" msgid "" msgstr "" -#. [Messages]BrowseDialogTitle +msgctxt "[Messages]BrowseDialogTitle" msgid "Browse For Folder" msgstr "Ordner suchen" -#. [Messages]BrowseDialogLabel +msgctxt "[Messages]BrowseDialogLabel" msgid "Select a folder in the list below, then click OK." msgstr "Wählen Sie einen Ordner aus und klicken Sie danach auf \"OK\"." -#. [Messages]NewFolderName +msgctxt "[Messages]NewFolderName" msgid "New Folder" msgstr "Neuer Ordner" -#. [Messages]WelcomeLabel1 +msgctxt "[Messages]WelcomeLabel1" msgid "Welcome to the [name] Setup Wizard" msgstr "Willkommen zum [name] Setup-Assistenten" -#. [Messages]WelcomeLabel2 +msgctxt "[Messages]WelcomeLabel2" msgid "" "This will install [name/ver] on your computer.%n%nIt is recommended that you" " close all other applications before continuing." @@ -361,15 +344,15 @@ msgstr "" "installieren.%n%nSie sollten alle anderen Anwendungen beenden, bevor Sie mit" " dem Setup fortfahren." -#. [Messages]WizardPassword +msgctxt "[Messages]WizardPassword" msgid "Password" msgstr "Passwort" -#. [Messages]PasswordLabel1 +msgctxt "[Messages]PasswordLabel1" msgid "This installation is password protected." msgstr "Diese Installation wird durch ein Passwort geschützt." -#. [Messages]PasswordLabel3 +msgctxt "[Messages]PasswordLabel3" msgid "" "Please provide the password, then click Next to continue. Passwords are " "case-sensitive." @@ -377,26 +360,26 @@ msgstr "" "Bitte geben Sie das Passwort ein und klicken Sie danach auf \"Weiter\". " "Achten Sie auf korrekte Groß-/Kleinschreibung." -#. [Messages]PasswordEditLabel +msgctxt "[Messages]PasswordEditLabel" msgid "&Password:" msgstr "&Passwort:" -#. [Messages]IncorrectPassword +msgctxt "[Messages]IncorrectPassword" msgid "The password you entered is not correct. Please try again." msgstr "" "Das eingegebene Passwort ist nicht korrekt. Bitte versuchen Sie es noch " "einmal." -#. [Messages]WizardLicense +msgctxt "[Messages]WizardLicense" msgid "License Agreement" msgstr "Lizenzvereinbarung" -#. [Messages]LicenseLabel +msgctxt "[Messages]LicenseLabel" msgid "Please read the following important information before continuing." msgstr "" "Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren." -#. [Messages]LicenseLabel3 +msgctxt "[Messages]LicenseLabel3" msgid "" "Please read the following License Agreement. You must accept the terms of " "this agreement before continuing with the installation." @@ -404,81 +387,81 @@ msgstr "" "Lesen Sie bitte die folgenden Lizenzvereinbarungen. Benutzen Sie bei Bedarf " "die Bildlaufleiste oder drücken Sie die \"Bild Ab\"-Taste." -#. [Messages]LicenseAccepted +msgctxt "[Messages]LicenseAccepted" msgid "I &accept the agreement" msgstr "Ich &akzeptiere die Vereinbarung" -#. [Messages]LicenseNotAccepted +msgctxt "[Messages]LicenseNotAccepted" msgid "I &do not accept the agreement" msgstr "Ich &lehne die Vereinbarung ab" -#. [Messages]WizardInfoBefore +msgctxt "[Messages]WizardInfoBefore" msgid "Information" msgstr "Information" -#. [Messages]InfoBeforeLabel +msgctxt "[Messages]InfoBeforeLabel" msgid "Please read the following important information before continuing." msgstr "" "Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren." -#. [Messages]InfoBeforeClickLabel +msgctxt "[Messages]InfoBeforeClickLabel" msgid "When you are ready to continue with Setup, click Next." msgstr "" "Klicken Sie auf \"Weiter\", sobald Sie bereit sind, mit dem Setup " "fortzufahren." -#. [Messages]WizardInfoAfter +msgctxt "[Messages]WizardInfoAfter" msgid "Information" msgstr "Information" -#. [Messages]InfoAfterLabel +msgctxt "[Messages]InfoAfterLabel" msgid "Please read the following important information before continuing." msgstr "" "Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren." -#. [Messages]InfoAfterClickLabel +msgctxt "[Messages]InfoAfterClickLabel" msgid "When you are ready to continue with Setup, click Next." msgstr "" "Klicken Sie auf \"Weiter\", sobald Sie bereit sind, mit dem Setup " "fortzufahren." -#. [Messages]WizardUserInfo +msgctxt "[Messages]WizardUserInfo" msgid "User Information" msgstr "Benutzerinformationen" -#. [Messages]UserInfoDesc +msgctxt "[Messages]UserInfoDesc" msgid "Please enter your information." msgstr "Bitte tragen Sie Ihre Daten ein." -#. [Messages]UserInfoName +msgctxt "[Messages]UserInfoName" msgid "&User Name:" msgstr "&Name:" -#. [Messages]UserInfoOrg +msgctxt "[Messages]UserInfoOrg" msgid "&Organization:" msgstr "&Organisation:" -#. [Messages]UserInfoSerial +msgctxt "[Messages]UserInfoSerial" msgid "&Serial Number:" msgstr "&Seriennummer:" -#. [Messages]UserInfoNameRequired +msgctxt "[Messages]UserInfoNameRequired" msgid "You must enter a name." msgstr "Sie müssen einen Namen eintragen." -#. [Messages]WizardSelectDir +msgctxt "[Messages]WizardSelectDir" msgid "Select Destination Location" msgstr "Ziel-Ordner wählen" -#. [Messages]SelectDirDesc +msgctxt "[Messages]SelectDirDesc" msgid "Where should [name] be installed?" msgstr "Wohin soll [name] installiert werden?" -#. [Messages]SelectDirLabel3 +msgctxt "[Messages]SelectDirLabel3" msgid "Setup will install [name] into the following folder." msgstr "Das Setup wird [name] in den folgenden Ordner installieren." -#. [Messages]SelectDirBrowseLabel +msgctxt "[Messages]SelectDirBrowseLabel" msgid "" "To continue, click Next. If you would like to select a different folder, " "click Browse." @@ -486,26 +469,26 @@ msgstr "" "Klicken Sie auf \"Weiter\", um fortzufahren. Klicken Sie auf " "\"Durchsuchen\", falls Sie einen anderen Ordner auswählen möchten." -#. [Messages]DiskSpaceGBLabel +msgctxt "[Messages]DiskSpaceGBLabel" msgid "At least [gb] GB of free disk space is required." msgstr "Mindestens [gb] GB freier Speicherplatz ist erforderlich." -#. [Messages]DiskSpaceMBLabel +msgctxt "[Messages]DiskSpaceMBLabel" msgid "At least [mb] MB of free disk space is required." msgstr "Mindestens [mb] MB freier Speicherplatz ist erforderlich." -#. [Messages]CannotInstallToNetworkDrive +msgctxt "[Messages]CannotInstallToNetworkDrive" msgid "Setup cannot install to a network drive." msgstr "Das Setup kann nicht in einen Netzwerk-Pfad installieren." -#. [Messages]CannotInstallToUNCPath +msgctxt "[Messages]CannotInstallToUNCPath" msgid "Setup cannot install to a UNC path." msgstr "" "Das Setup kann nicht in einen UNC-Pfad installieren. Wenn Sie auf ein " "Netzlaufwerk installieren möchten, müssen Sie dem Netzwerkpfad einen " "Laufwerksbuchstaben zuordnen." -#. [Messages]InvalidPath +msgctxt "[Messages]InvalidPath" msgid "" "You must enter a full path with drive letter; for example:%n%nC:\\APP%n%nor " "a UNC path in the form:%n%n\\\\server\\share" @@ -514,7 +497,7 @@ msgstr "" "z. B.:%n%nC:\\Beispiel%n%noder einen UNC-Pfad in der " "Form:%n%n\\\\Server\\Freigabe" -#. [Messages]InvalidDrive +msgctxt "[Messages]InvalidDrive" msgid "" "The drive or UNC share you selected does not exist or is not accessible. " "Please select another." @@ -522,11 +505,11 @@ msgstr "" "Das angegebene Laufwerk bzw. der UNC-Pfad existiert nicht oder es kann nicht" " darauf zugegriffen werden. Wählen Sie bitte einen anderen Ordner." -#. [Messages]DiskSpaceWarningTitle +msgctxt "[Messages]DiskSpaceWarningTitle" msgid "Not Enough Disk Space" msgstr "Nicht genug freier Speicherplatz" -#. [Messages]DiskSpaceWarning +msgctxt "[Messages]DiskSpaceWarning" msgid "" "Setup requires at least %1 KB of free space to install, but the selected " "drive only has %2 KB available.%n%nDo you want to continue anyway?" @@ -535,23 +518,23 @@ msgstr "" "aber auf dem ausgewählten Laufwerk sind nur %2 KB verfügbar.%n%nMöchten Sie " "trotzdem fortfahren?" -#. [Messages]DirNameTooLong +msgctxt "[Messages]DirNameTooLong" msgid "The folder name or path is too long." msgstr "Der Ordnername/Pfad ist zu lang." -#. [Messages]InvalidDirName +msgctxt "[Messages]InvalidDirName" msgid "The folder name is not valid." msgstr "Der Ordnername ist nicht gültig." -#. [Messages]BadDirName32 +msgctxt "[Messages]BadDirName32" msgid "Folder names cannot include any of the following characters:%n%n%1" msgstr "Ordnernamen dürfen keine der folgenden Zeichen enthalten:%n%n%1" -#. [Messages]DirExistsTitle +msgctxt "[Messages]DirExistsTitle" msgid "Folder Exists" msgstr "Ordner existiert bereits" -#. [Messages]DirExists +msgctxt "[Messages]DirExists" msgid "" "The folder:%n%n%1%n%nalready exists. Would you like to install to that " "folder anyway?" @@ -559,26 +542,26 @@ msgstr "" "Der Ordner:%n%n%1%n%n existiert bereits. Möchten Sie trotzdem in diesen " "Ordner installieren?" -#. [Messages]DirDoesntExistTitle +msgctxt "[Messages]DirDoesntExistTitle" msgid "Folder Does Not Exist" msgstr "Ordner ist nicht vorhanden" -#. [Messages]DirDoesntExist +msgctxt "[Messages]DirDoesntExist" msgid "" "The folder:%n%n%1%n%ndoes not exist. Would you like the folder to be " "created?" msgstr "" "Der Ordner:%n%n%1%n%nist nicht vorhanden. Soll der Ordner erstellt werden?" -#. [Messages]WizardSelectComponents +msgctxt "[Messages]WizardSelectComponents" msgid "Select Components" msgstr "Komponenten auswählen" -#. [Messages]SelectComponentsDesc +msgctxt "[Messages]SelectComponentsDesc" msgid "Which components should be installed?" msgstr "Welche Komponenten sollen installiert werden?" -#. [Messages]SelectComponentsLabel2 +msgctxt "[Messages]SelectComponentsLabel2" msgid "" "Select the components you want to install; clear the components you do not " "want to install. Click Next when you are ready to continue." @@ -586,23 +569,23 @@ msgstr "" "Wählen Sie die Komponenten aus, die Sie installieren möchten. Klicken Sie " "auf \"Weiter\", wenn Sie bereit sind, fortzufahren." -#. [Messages]FullInstallation +msgctxt "[Messages]FullInstallation" msgid "Full installation" msgstr "Vollständige Installation" -#. [Messages]CompactInstallation +msgctxt "[Messages]CompactInstallation" msgid "Compact installation" msgstr "Kompakte Installation" -#. [Messages]CustomInstallation +msgctxt "[Messages]CustomInstallation" msgid "Custom installation" msgstr "Benutzerdefinierte Installation" -#. [Messages]NoUninstallWarningTitle +msgctxt "[Messages]NoUninstallWarningTitle" msgid "Components Exist" msgstr "Komponenten vorhanden" -#. [Messages]NoUninstallWarning +msgctxt "[Messages]NoUninstallWarning" msgid "" "Setup has detected that the following components are already installed on " "your computer:%n%n%1%n%nDeselecting these components will not uninstall " @@ -613,31 +596,31 @@ msgstr "" "Komponenten werden nicht vom Computer entfernt.%n%nMöchten Sie trotzdem " "fortfahren?" -#. [Messages]ComponentSize1 +msgctxt "[Messages]ComponentSize1" msgid "%1 KB" msgstr "%1 KB" -#. [Messages]ComponentSize2 +msgctxt "[Messages]ComponentSize2" msgid "%1 MB" msgstr "%1 MB" -#. [Messages]ComponentsDiskSpaceGBLabel +msgctxt "[Messages]ComponentsDiskSpaceGBLabel" msgid "Current selection requires at least [gb] GB of disk space." msgstr "Die aktuelle Auswahl erfordert mindestens [gb] GB Speicherplatz." -#. [Messages]ComponentsDiskSpaceMBLabel +msgctxt "[Messages]ComponentsDiskSpaceMBLabel" msgid "Current selection requires at least [mb] MB of disk space." msgstr "Die aktuelle Auswahl erfordert mindestens [mb] MB Speicherplatz." -#. [Messages]WizardSelectTasks +msgctxt "[Messages]WizardSelectTasks" msgid "Select Additional Tasks" msgstr "Zusätzliche Aufgaben auswählen" -#. [Messages]SelectTasksDesc +msgctxt "[Messages]SelectTasksDesc" msgid "Which additional tasks should be performed?" msgstr "Welche zusätzlichen Aufgaben sollen ausgeführt werden?" -#. [Messages]SelectTasksLabel2 +msgctxt "[Messages]SelectTasksLabel2" msgid "" "Select the additional tasks you would like Setup to perform while installing" " [name], then click Next." @@ -646,15 +629,15 @@ msgstr "" "Installation von [name] ausführen soll, und klicken Sie danach auf " "\"Weiter\"." -#. [Messages]WizardSelectProgramGroup +msgctxt "[Messages]WizardSelectProgramGroup" msgid "Select Start Menu Folder" msgstr "Startmenü-Ordner auswählen" -#. [Messages]SelectStartMenuFolderDesc +msgctxt "[Messages]SelectStartMenuFolderDesc" msgid "Where should Setup place the program's shortcuts?" msgstr "Wo soll das Setup die Programm-Verknüpfungen erstellen?" -#. [Messages]SelectStartMenuFolderLabel3 +msgctxt "[Messages]SelectStartMenuFolderLabel3" msgid "" "Setup will create the program's shortcuts in the following Start Menu " "folder." @@ -662,7 +645,7 @@ msgstr "" "Das Setup wird die Programm-Verknüpfungen im folgenden Startmenü-Ordner " "erstellen." -#. [Messages]SelectStartMenuFolderBrowseLabel +msgctxt "[Messages]SelectStartMenuFolderBrowseLabel" msgid "" "To continue, click Next. If you would like to select a different folder, " "click Browse." @@ -670,36 +653,36 @@ msgstr "" "Klicken Sie auf \"Weiter\", um fortzufahren. Klicken Sie auf " "\"Durchsuchen\", falls Sie einen anderen Ordner auswählen möchten." -#. [Messages]MustEnterGroupName +msgctxt "[Messages]MustEnterGroupName" msgid "You must enter a folder name." msgstr "Sie müssen einen Ordnernamen eingeben." -#. [Messages]GroupNameTooLong +msgctxt "[Messages]GroupNameTooLong" msgid "The folder name or path is too long." msgstr "Der Ordnername/Pfad ist zu lang." -#. [Messages]InvalidGroupName +msgctxt "[Messages]InvalidGroupName" msgid "The folder name is not valid." msgstr "Der Ordnername ist nicht gültig." -#. [Messages]BadGroupName +msgctxt "[Messages]BadGroupName" msgid "The folder name cannot include any of the following characters:%n%n%1" msgstr "Der Ordnername darf keine der folgenden Zeichen enthalten:%n%n%1" -#. [Messages]NoProgramGroupCheck2 +msgctxt "[Messages]NoProgramGroupCheck2" msgid "&Don't create a Start Menu folder" msgstr "&Keinen Ordner im Startmenü erstellen" -#. [Messages]WizardReady +msgctxt "[Messages]WizardReady" msgid "Ready to Install" msgstr "Bereit zur Installation." -#. [Messages]ReadyLabel1 +msgctxt "[Messages]ReadyLabel1" msgid "Setup is now ready to begin installing [name] on your computer." msgstr "" "Das Setup ist jetzt bereit, [name] auf Ihrem Computer zu installieren." -#. [Messages]ReadyLabel2a +msgctxt "[Messages]ReadyLabel2a" msgid "" "Click Install to continue with the installation, or click Back if you want " "to review or change any settings." @@ -707,108 +690,108 @@ msgstr "" "Klicken Sie auf \"Installieren\", um mit der Installation zu beginnen, oder " "auf \"Zurück\", um Ihre Einstellungen zu überprüfen oder zu ändern." -#. [Messages]ReadyLabel2b +msgctxt "[Messages]ReadyLabel2b" msgid "Click Install to continue with the installation." msgstr "Klicken Sie auf \"Installieren\", um mit der Installation zu beginnen." -#. [Messages]ReadyMemoUserInfo +msgctxt "[Messages]ReadyMemoUserInfo" msgid "User information:" msgstr "Benutzerinformationen:" -#. [Messages]ReadyMemoDir +msgctxt "[Messages]ReadyMemoDir" msgid "Destination location:" msgstr "Ziel-Ordner:" -#. [Messages]ReadyMemoType +msgctxt "[Messages]ReadyMemoType" msgid "Setup type:" msgstr "Setup-Typ:" -#. [Messages]ReadyMemoComponents +msgctxt "[Messages]ReadyMemoComponents" msgid "Selected components:" msgstr "Ausgewählte Komponenten:" -#. [Messages]ReadyMemoGroup +msgctxt "[Messages]ReadyMemoGroup" msgid "Start Menu folder:" msgstr "Startmenü-Ordner:" -#. [Messages]ReadyMemoTasks +msgctxt "[Messages]ReadyMemoTasks" msgid "Additional tasks:" msgstr "Zusätzliche Aufgaben:" -#. [Messages]DownloadingLabel2 +msgctxt "[Messages]DownloadingLabel2" msgid "Downloading files..." msgstr "Lade Dateien herunter..." -#. [Messages]ButtonStopDownload +msgctxt "[Messages]ButtonStopDownload" msgid "&Stop download" msgstr "Download &abbrechen" -#. [Messages]StopDownload +msgctxt "[Messages]StopDownload" msgid "Are you sure you want to stop the download?" msgstr "Sind Sie sicher, dass Sie den Download abbrechen wollen?" -#. [Messages]ErrorDownloadAborted +msgctxt "[Messages]ErrorDownloadAborted" msgid "Download aborted" msgstr "Download abgebrochen" -#. [Messages]ErrorDownloadFailed +msgctxt "[Messages]ErrorDownloadFailed" msgid "Download failed: %1 %2" msgstr "Download fehlgeschlagen: %1 %2" -#. [Messages]ErrorDownloadSizeFailed +msgctxt "[Messages]ErrorDownloadSizeFailed" msgid "Getting size failed: %1 %2" msgstr "Fehler beim Ermitteln der Größe: %1 %2" -#. [Messages]ErrorProgress +msgctxt "[Messages]ErrorProgress" msgid "Invalid progress: %1 of %2" msgstr "Ungültiger Fortschritt: %1 von %2" -#. [Messages]ErrorFileSize +msgctxt "[Messages]ErrorFileSize" msgid "Invalid file size: expected %1, found %2" msgstr "Ungültige Dateigröße: erwartet %1, gefunden %2" -#. [Messages]ExtractingLabel +msgctxt "[Messages]ExtractingLabel" msgid "Extracting files..." msgstr "Entpacke Dateien..." -#. [Messages]ButtonStopExtraction +msgctxt "[Messages]ButtonStopExtraction" msgid "&Stop extraction" msgstr "Entpacken &abbrechen" -#. [Messages]StopExtraction +msgctxt "[Messages]StopExtraction" msgid "Are you sure you want to stop the extraction?" msgstr "Sind Sie sicher, dass Sie das Entpacken abbrechen wollen?" -#. [Messages]ErrorExtractionAborted +msgctxt "[Messages]ErrorExtractionAborted" msgid "Extraction aborted" msgstr "Entpacken abgebrochen" -#. [Messages]ErrorExtractionFailed +msgctxt "[Messages]ErrorExtractionFailed" msgid "Extraction failed: %1" msgstr "Entpacken fehlgeschlagen: %1" -#. [Messages]ArchiveIncorrectPassword +msgctxt "[Messages]ArchiveIncorrectPassword" msgid "The password is incorrect" msgstr "Ungültiges Passwort" -#. [Messages]ArchiveIsCorrupted +msgctxt "[Messages]ArchiveIsCorrupted" msgid "The archive is corrupted" msgstr "Das Archiv ist defekt" -#. [Messages]ArchiveUnsupportedFormat +msgctxt "[Messages]ArchiveUnsupportedFormat" msgid "The archive format is unsupported" msgstr "Das Archivformat wird nicht unterstützt" -#. [Messages]WizardPreparing +msgctxt "[Messages]WizardPreparing" msgid "Preparing to Install" msgstr "Vorbereitung der Installation" -#. [Messages]PreparingDesc +msgctxt "[Messages]PreparingDesc" msgid "Setup is preparing to install [name] on your computer." msgstr "" "Das Setup bereitet die Installation von [name] auf diesem Computer vor." -#. [Messages]PreviousInstallNotCompleted +msgctxt "[Messages]PreviousInstallNotCompleted" msgid "" "The installation/removal of a previous program was not completed. You will " "need to restart your computer to complete that installation.%n%nAfter " @@ -821,13 +804,13 @@ msgstr "" "Neustart Ihres Computers erneut, um die Installation von [name] " "durchzuführen." -#. [Messages]CannotContinue +msgctxt "[Messages]CannotContinue" msgid "Setup cannot continue. Please click Cancel to exit." msgstr "" "Das Setup kann nicht fortfahren. Bitte klicken Sie auf \"Abbrechen\" zum " "Verlassen." -#. [Messages]ApplicationsFound +msgctxt "[Messages]ApplicationsFound" msgid "" "The following applications are using files that need to be updated by Setup." " It is recommended that you allow Setup to automatically close these " @@ -836,7 +819,7 @@ msgstr "" "Die folgenden Anwendungen benutzen Dateien, die aktualisiert werden müssen. " "Es wird empfohlen, Setup zu erlauben, diese Anwendungen zu schließen." -#. [Messages]ApplicationsFound2 +msgctxt "[Messages]ApplicationsFound2" msgid "" "The following applications are using files that need to be updated by Setup." " It is recommended that you allow Setup to automatically close these " @@ -848,15 +831,15 @@ msgstr "" "Nachdem die Installation fertiggestellt wurde, versucht Setup, diese " "Anwendungen wieder zu starten." -#. [Messages]CloseApplications +msgctxt "[Messages]CloseApplications" msgid "&Automatically close the applications" msgstr "&Schließe die Anwendungen automatisch" -#. [Messages]DontCloseApplications +msgctxt "[Messages]DontCloseApplications" msgid "&Do not close the applications" msgstr "Schließe die A&nwendungen nicht" -#. [Messages]ErrorCloseApplications +msgctxt "[Messages]ErrorCloseApplications" msgid "" "Setup was unable to automatically close all applications. It is recommended " "that you close all applications using files that need to be updated by Setup" @@ -866,7 +849,7 @@ msgstr "" "empfohlen, alle Anwendungen zu schließen, die Dateien benutzen, die vom " "Setup vor einer Fortsetzung aktualisiert werden müssen." -#. [Messages]PrepareToInstallNeedsRestart +msgctxt "[Messages]PrepareToInstallNeedsRestart" msgid "" "Setup must restart your computer. After restarting your computer, run Setup " "again to complete the installation of [name].%n%nWould you like to restart " @@ -876,24 +859,24 @@ msgstr "" "Setup erneut aus, um die Installation von [name] abzuschließen.%n%nWollen " "Sie jetzt neu starten?" -#. [Messages]WizardInstalling +msgctxt "[Messages]WizardInstalling" msgid "Installing" msgstr "Installiere ..." -#. [Messages]InstallingLabel +msgctxt "[Messages]InstallingLabel" msgid "Please wait while Setup installs [name] on your computer." msgstr "Warten Sie bitte, während [name] auf Ihrem Computer installiert wird." -#. [Messages]FinishedHeadingLabel +msgctxt "[Messages]FinishedHeadingLabel" msgid "Completing the [name] Setup Wizard" msgstr "Beenden des [name] Setup-Assistenten" -#. [Messages]FinishedLabelNoIcons +msgctxt "[Messages]FinishedLabelNoIcons" msgid "Setup has finished installing [name] on your computer." msgstr "" "Das Setup hat die Installation von [name] auf Ihrem Computer abgeschlossen." -#. [Messages]FinishedLabel +msgctxt "[Messages]FinishedLabel" msgid "" "Setup has finished installing [name] on your computer. The application may " "be launched by selecting the installed shortcuts." @@ -902,11 +885,11 @@ msgstr "" "Die Anwendung kann über die installierten Programm-Verknüpfungen gestartet " "werden." -#. [Messages]ClickFinish +msgctxt "[Messages]ClickFinish" msgid "Click Finish to exit Setup." msgstr "Klicken Sie auf \"Fertigstellen\", um das Setup zu beenden." -#. [Messages]FinishedRestartLabel +msgctxt "[Messages]FinishedRestartLabel" msgid "" "To complete the installation of [name], Setup must restart your computer. " "Would you like to restart now?" @@ -914,7 +897,7 @@ msgstr "" "Um die Installation von [name] abzuschließen, muss das Setup Ihren Computer " "neu starten. Möchten Sie jetzt neu starten?" -#. [Messages]FinishedRestartMessage +msgctxt "[Messages]FinishedRestartMessage" msgid "" "To complete the installation of [name], Setup must restart your " "computer.%n%nWould you like to restart now?" @@ -922,31 +905,31 @@ msgstr "" "Um die Installation von [name] abzuschließen, muss das Setup Ihren Computer " "neu starten.%n%nMöchten Sie jetzt neu starten?" -#. [Messages]ShowReadmeCheck +msgctxt "[Messages]ShowReadmeCheck" msgid "Yes, I would like to view the README file" msgstr "Ja, ich möchte die LIESMICH-Datei sehen" -#. [Messages]YesRadio +msgctxt "[Messages]YesRadio" msgid "&Yes, restart the computer now" msgstr "&Ja, Computer jetzt neu starten" -#. [Messages]NoRadio +msgctxt "[Messages]NoRadio" msgid "&No, I will restart the computer later" msgstr "&Nein, ich werde den Computer später neu starten" -#. [Messages]RunEntryExec +msgctxt "[Messages]RunEntryExec" msgid "Run %1" msgstr "%1 starten" -#. [Messages]RunEntryShellExec +msgctxt "[Messages]RunEntryShellExec" msgid "View %1" msgstr "%1 anzeigen" -#. [Messages]ChangeDiskTitle +msgctxt "[Messages]ChangeDiskTitle" msgid "Setup Needs the Next Disk" msgstr "Nächsten Datenträger einlegen" -#. [Messages]SelectDiskLabel2 +msgctxt "[Messages]SelectDiskLabel2" msgid "" "Please insert Disk %1 and click OK.%n%nIf the files on this disk can be " "found in a folder other than the one displayed below, enter the correct path" @@ -957,11 +940,11 @@ msgstr "" "Ordner befinden, dann geben Sie bitte den korrekten Pfad ein oder klicken " "auf \"Durchsuchen\"." -#. [Messages]PathLabel +msgctxt "[Messages]PathLabel" msgid "&Path:" msgstr "&Pfad:" -#. [Messages]FileNotInDir2 +msgctxt "[Messages]FileNotInDir2" msgid "" "The file \"%1\" could not be located in \"%2\". Please insert the correct " "disk or select another folder." @@ -969,335 +952,335 @@ msgstr "" "Die Datei \"%1\" befindet sich nicht in \"%2\". Bitte Ordner ändern oder " "richtigen Datenträger einlegen." -#. [Messages]SelectDirectoryLabel +msgctxt "[Messages]SelectDirectoryLabel" msgid "Please specify the location of the next disk." msgstr "Geben Sie bitte an, wo der nächste Datenträger eingelegt wird." -#. [Messages]SetupAborted +msgctxt "[Messages]SetupAborted" msgid "" "Setup was not completed.%n%nPlease correct the problem and run Setup again." msgstr "" "Das Setup konnte nicht abgeschlossen werden.%n%nBeheben Sie bitte das " "Problem und starten Sie das Setup erneut." -#. [Messages]AbortRetryIgnoreSelectAction +msgctxt "[Messages]AbortRetryIgnoreSelectAction" msgid "Select action" msgstr "Bitte auswählen" -#. [Messages]AbortRetryIgnoreRetry +msgctxt "[Messages]AbortRetryIgnoreRetry" msgid "&Try again" msgstr "&Nochmals versuchen" -#. [Messages]AbortRetryIgnoreIgnore +msgctxt "[Messages]AbortRetryIgnoreIgnore" msgid "&Ignore the error and continue" msgstr "&Den Fehler ignorieren und fortfahren" -#. [Messages]AbortRetryIgnoreCancel +msgctxt "[Messages]AbortRetryIgnoreCancel" msgid "Cancel installation" msgstr "Installation abbrechen" -#. [Messages]RetryCancelSelectAction +msgctxt "[Messages]RetryCancelSelectAction" msgid "Select action" msgstr "Bitte auswählen" -#. [Messages]RetryCancelRetry +msgctxt "[Messages]RetryCancelRetry" msgid "&Try again" msgstr "&Wiederholen" -#. [Messages]RetryCancelCancel +msgctxt "[Messages]RetryCancelCancel" msgid "Cancel" msgstr "&Abbrechen" -#. [Messages]StatusClosingApplications +msgctxt "[Messages]StatusClosingApplications" msgid "Closing applications..." msgstr "Anwendungen werden geschlossen ..." -#. [Messages]StatusCreateDirs +msgctxt "[Messages]StatusCreateDirs" msgid "Creating directories..." msgstr "Ordner werden erstellt ..." -#. [Messages]StatusExtractFiles +msgctxt "[Messages]StatusExtractFiles" msgid "Extracting files..." msgstr "Dateien werden entpackt ..." -#. [Messages]StatusDownloadFiles +msgctxt "[Messages]StatusDownloadFiles" msgid "Downloading files..." msgstr "Dateien werden herunter geladen..." -#. [Messages]StatusCreateIcons +msgctxt "[Messages]StatusCreateIcons" msgid "Creating shortcuts..." msgstr "Verknüpfungen werden erstellt ..." -#. [Messages]StatusCreateIniEntries +msgctxt "[Messages]StatusCreateIniEntries" msgid "Creating INI entries..." msgstr "INI-Einträge werden erstellt ..." -#. [Messages]StatusCreateRegistryEntries +msgctxt "[Messages]StatusCreateRegistryEntries" msgid "Creating registry entries..." msgstr "Registry-Einträge werden erstellt ..." -#. [Messages]StatusRegisterFiles +msgctxt "[Messages]StatusRegisterFiles" msgid "Registering files..." msgstr "Dateien werden registriert ..." -#. [Messages]StatusSavingUninstall +msgctxt "[Messages]StatusSavingUninstall" msgid "Saving uninstall information..." msgstr "Deinstallationsinformationen werden gespeichert ..." -#. [Messages]StatusRunProgram +msgctxt "[Messages]StatusRunProgram" msgid "Finishing installation..." msgstr "Installation wird beendet ..." -#. [Messages]StatusRestartingApplications +msgctxt "[Messages]StatusRestartingApplications" msgid "Restarting applications..." msgstr "Neustart der Anwendungen ..." -#. [Messages]StatusRollback +msgctxt "[Messages]StatusRollback" msgid "Rolling back changes..." msgstr "Änderungen werden rückgängig gemacht ..." -#. [Messages]ErrorInternal2 +msgctxt "[Messages]ErrorInternal2" msgid "Internal error: %1" msgstr "Interner Fehler: %1" -#. [Messages]ErrorFunctionFailedNoCode +msgctxt "[Messages]ErrorFunctionFailedNoCode" msgid "%1 failed" msgstr "%1 schlug fehl" -#. [Messages]ErrorFunctionFailed +msgctxt "[Messages]ErrorFunctionFailed" msgid "%1 failed; code %2" msgstr "%1 schlug fehl; Code %2" -#. [Messages]ErrorFunctionFailedWithMessage +msgctxt "[Messages]ErrorFunctionFailedWithMessage" msgid "%1 failed; code %2.%n%3" msgstr "%1 schlug fehl; Code %2.%n%3" -#. [Messages]ErrorExecutingProgram +msgctxt "[Messages]ErrorExecutingProgram" msgid "Unable to execute file:%n%1" msgstr "Datei kann nicht ausgeführt werden:%n%1" -#. [Messages]ErrorRegOpenKey +msgctxt "[Messages]ErrorRegOpenKey" msgid "Error opening registry key:%n%1\\%2" msgstr "Registry-Schlüssel konnte nicht geöffnet werden:%n%1\\%2" -#. [Messages]ErrorRegCreateKey +msgctxt "[Messages]ErrorRegCreateKey" msgid "Error creating registry key:%n%1\\%2" msgstr "Registry-Schlüssel konnte nicht erstellt werden:%n%1\\%2" -#. [Messages]ErrorRegWriteKey +msgctxt "[Messages]ErrorRegWriteKey" msgid "Error writing to registry key:%n%1\\%2" msgstr "Fehler beim Schreiben des Registry-Schlüssels:%n%1\\%2" -#. [Messages]ErrorIniEntry +msgctxt "[Messages]ErrorIniEntry" msgid "Error creating INI entry in file \"%1\"." msgstr "Fehler beim Erstellen eines INI-Eintrages in der Datei \"%1\"." -#. [Messages]FileAbortRetryIgnoreSkipNotRecommended +msgctxt "[Messages]FileAbortRetryIgnoreSkipNotRecommended" msgid "&Skip this file (not recommended)" msgstr "Diese Datei &überspringen (nicht empfohlen)" -#. [Messages]FileAbortRetryIgnoreIgnoreNotRecommended +msgctxt "[Messages]FileAbortRetryIgnoreIgnoreNotRecommended" msgid "&Ignore the error and continue (not recommended)" msgstr "Den Fehler &ignorieren und fortfahren (nicht empfohlen)" -#. [Messages]SourceIsCorrupted +msgctxt "[Messages]SourceIsCorrupted" msgid "The source file is corrupted" msgstr "Die Quelldatei ist beschädigt" -#. [Messages]SourceDoesntExist +msgctxt "[Messages]SourceDoesntExist" msgid "The source file \"%1\" does not exist" msgstr "Die Quelldatei \"%1\" existiert nicht" -#. [Messages]SourceVerificationFailed +msgctxt "[Messages]SourceVerificationFailed" msgid "Verification of the source file failed: %1" msgstr "Überprüfung der Quelldatei fehlgeschlagen: %1" -#. [Messages]VerificationSignatureDoesntExist +msgctxt "[Messages]VerificationSignatureDoesntExist" msgid "The signature file \"%1\" does not exist" msgstr "Die Signaturdatei \"%1\" existiert nicht" -#. [Messages]VerificationSignatureInvalid +msgctxt "[Messages]VerificationSignatureInvalid" msgid "The signature file \"%1\" is invalid" msgstr "Die Signaturdatei \"%1\" ist ungültig" -#. [Messages]VerificationKeyNotFound +msgctxt "[Messages]VerificationKeyNotFound" msgid "The signature file \"%1\" uses an unknown key" msgstr "Die Signaturdatei \"%1\" verwendet einen unbekannten Schlüssel" -#. [Messages]VerificationFileNameIncorrect +msgctxt "[Messages]VerificationFileNameIncorrect" msgid "The name of the file is incorrect" msgstr "Der Name der Datei ist ungültig" -#. [Messages]VerificationFileTagIncorrect +msgctxt "[Messages]VerificationFileTagIncorrect" msgid "The tag of the file is incorrect" msgstr "Der Tag der Datei ist ungültig" -#. [Messages]VerificationFileSizeIncorrect +msgctxt "[Messages]VerificationFileSizeIncorrect" msgid "The size of the file is incorrect" msgstr "Die Größe der Datei ist ungültig" -#. [Messages]VerificationFileHashIncorrect +msgctxt "[Messages]VerificationFileHashIncorrect" msgid "The hash of the file is incorrect" msgstr "Der Hashwert der Datei ist ungültig" -#. [Messages]ExistingFileReadOnly2 +msgctxt "[Messages]ExistingFileReadOnly2" msgid "" "The existing file could not be replaced because it is marked read-only." msgstr "" "Die vorhandene Datei kann nicht ersetzt werden, da sie schreibgeschützt ist." -#. [Messages]ExistingFileReadOnlyRetry +msgctxt "[Messages]ExistingFileReadOnlyRetry" msgid "&Remove the read-only attribute and try again" msgstr "&Den Schreibschutz entfernen und noch einmal versuchen" -#. [Messages]ExistingFileReadOnlyKeepExisting +msgctxt "[Messages]ExistingFileReadOnlyKeepExisting" msgid "&Keep the existing file" msgstr "Die &vorhandene Datei behalten" -#. [Messages]ErrorReadingExistingDest +msgctxt "[Messages]ErrorReadingExistingDest" msgid "An error occurred while trying to read the existing file:" msgstr "Lesefehler in Datei:" -#. [Messages]FileExistsSelectAction +msgctxt "[Messages]FileExistsSelectAction" msgid "Select action" msgstr "Aktion auswählen" -#. [Messages]FileExists2 +msgctxt "[Messages]FileExists2" msgid "The file already exists." msgstr "Die Datei ist bereits vorhanden." -#. [Messages]FileExistsOverwriteExisting +msgctxt "[Messages]FileExistsOverwriteExisting" msgid "&Overwrite the existing file" msgstr "Vorhandene Datei &überschreiben" -#. [Messages]FileExistsKeepExisting +msgctxt "[Messages]FileExistsKeepExisting" msgid "&Keep the existing file" msgstr "Vorhandene Datei &behalten" -#. [Messages]FileExistsOverwriteOrKeepAll +msgctxt "[Messages]FileExistsOverwriteOrKeepAll" msgid "&Do this for the next conflicts" msgstr "&Dies auch für die nächsten Konflikte ausführen" -#. [Messages]ExistingFileNewerSelectAction +msgctxt "[Messages]ExistingFileNewerSelectAction" msgid "Select action" msgstr "Aktion auswählen" -#. [Messages]ExistingFileNewer2 +msgctxt "[Messages]ExistingFileNewer2" msgid "The existing file is newer than the one Setup is trying to install." msgstr "" "Die vorhandene Datei ist neuer als die Datei, die installiert werden soll." -#. [Messages]ExistingFileNewerOverwriteExisting +msgctxt "[Messages]ExistingFileNewerOverwriteExisting" msgid "&Overwrite the existing file" msgstr "Vorhandene Datei &überschreiben" -#. [Messages]ExistingFileNewerKeepExisting +msgctxt "[Messages]ExistingFileNewerKeepExisting" msgid "&Keep the existing file (recommended)" msgstr "Vorhandene Datei &behalten (empfohlen)" -#. [Messages]ExistingFileNewerOverwriteOrKeepAll +msgctxt "[Messages]ExistingFileNewerOverwriteOrKeepAll" msgid "&Do this for the next conflicts" msgstr "&Dies auch für die nächsten Konflikte ausführen" -#. [Messages]ErrorChangingAttr +msgctxt "[Messages]ErrorChangingAttr" msgid "" "An error occurred while trying to change the attributes of the existing " "file:" msgstr "Fehler beim Ändern der Datei-Attribute:" -#. [Messages]ErrorCreatingTemp +msgctxt "[Messages]ErrorCreatingTemp" msgid "" "An error occurred while trying to create a file in the destination " "directory:" msgstr "Fehler beim Erstellen einer Datei im Ziel-Ordner:" -#. [Messages]ErrorReadingSource +msgctxt "[Messages]ErrorReadingSource" msgid "An error occurred while trying to read the source file:" msgstr "Fehler beim Lesen der Quelldatei:" -#. [Messages]ErrorCopying +msgctxt "[Messages]ErrorCopying" msgid "An error occurred while trying to copy a file:" msgstr "Fehler beim Kopieren einer Datei:" -#. [Messages]ErrorDownloading +msgctxt "[Messages]ErrorDownloading" msgid "An error occurred while trying to download a file:" msgstr "Beim Download der Datei ist ein Fehler aufgetreten:" -#. [Messages]ErrorExtracting +msgctxt "[Messages]ErrorExtracting" msgid "An error occurred while trying to extract an archive:" msgstr "Beim Entpacken eines Archivs ist ein Fehler aufgetreten:" -#. [Messages]ErrorReplacingExistingFile +msgctxt "[Messages]ErrorReplacingExistingFile" msgid "An error occurred while trying to replace the existing file:" msgstr "Fehler beim Ersetzen einer vorhandenen Datei:" -#. [Messages]ErrorRestartReplace +msgctxt "[Messages]ErrorRestartReplace" msgid "RestartReplace failed:" msgstr "\"Ersetzen nach Neustart\" fehlgeschlagen:" -#. [Messages]ErrorRenamingTemp +msgctxt "[Messages]ErrorRenamingTemp" msgid "" "An error occurred while trying to rename a file in the destination " "directory:" msgstr "Fehler beim Umbenennen einer Datei im Ziel-Ordner:" -#. [Messages]ErrorRegisterServer +msgctxt "[Messages]ErrorRegisterServer" msgid "Unable to register the DLL/OCX: %1" msgstr "DLL/OCX konnte nicht registriert werden: %1" -#. [Messages]ErrorRegSvr32Failed +msgctxt "[Messages]ErrorRegSvr32Failed" msgid "RegSvr32 failed with exit code %1" msgstr "RegSvr32-Aufruf scheiterte mit Exit-Code %1" -#. [Messages]ErrorRegisterTypeLib +msgctxt "[Messages]ErrorRegisterTypeLib" msgid "Unable to register the type library: %1" msgstr "Typen-Bibliothek konnte nicht registriert werden: %1" -#. [Messages]UninstallDisplayNameMark +msgctxt "[Messages]UninstallDisplayNameMark" msgid "%1 (%2)" msgstr "%1 (%2)" -#. [Messages]UninstallDisplayNameMarks +msgctxt "[Messages]UninstallDisplayNameMarks" msgid "%1 (%2, %3)" msgstr "%1 (%2, %3)" -#. [Messages]UninstallDisplayNameMark32Bit +msgctxt "[Messages]UninstallDisplayNameMark32Bit" msgid "32-bit" msgstr "32 Bit" -#. [Messages]UninstallDisplayNameMark64Bit +msgctxt "[Messages]UninstallDisplayNameMark64Bit" msgid "64-bit" msgstr "64 Bit" -#. [Messages]UninstallDisplayNameMarkAllUsers +msgctxt "[Messages]UninstallDisplayNameMarkAllUsers" msgid "All users" msgstr "Alle Benutzer" -#. [Messages]UninstallDisplayNameMarkCurrentUser +msgctxt "[Messages]UninstallDisplayNameMarkCurrentUser" msgid "Current user" msgstr "Aktueller Benutzer" -#. [Messages]ErrorOpeningReadme +msgctxt "[Messages]ErrorOpeningReadme" msgid "An error occurred while trying to open the README file." msgstr "Fehler beim Öffnen der LIESMICH-Datei." -#. [Messages]ErrorRestartingComputer +msgctxt "[Messages]ErrorRestartingComputer" msgid "Setup was unable to restart the computer. Please do this manually." msgstr "" "Das Setup konnte den Computer nicht neu starten. Bitte führen Sie den " "Neustart manuell durch." -#. [Messages]UninstallNotFound +msgctxt "[Messages]UninstallNotFound" msgid "File \"%1\" does not exist. Cannot uninstall." msgstr "Die Datei \"%1\" existiert nicht. Entfernen der Anwendung fehlgeschlagen." -#. [Messages]UninstallOpenError +msgctxt "[Messages]UninstallOpenError" msgid "File \"%1\" could not be opened. Cannot uninstall" msgstr "" "Die Datei \"%1\" konnte nicht geöffnet werden. Entfernen der Anwendung " "fehlgeschlagen." -#. [Messages]UninstallUnsupportedVer +msgctxt "[Messages]UninstallUnsupportedVer" msgid "" "The uninstall log file \"%1\" is in a format not recognized by this version " "of the uninstaller. Cannot uninstall" @@ -1305,24 +1288,24 @@ msgstr "" "Das Format der Deinstallationsdatei \"%1\" konnte nicht erkannt werden. " "Entfernen der Anwendung fehlgeschlagen." -#. [Messages]UninstallUnknownEntry +msgctxt "[Messages]UninstallUnknownEntry" msgid "An unknown entry (%1) was encountered in the uninstall log" msgstr "" "In der Deinstallationsdatei wurde ein unbekannter Eintrag (%1) gefunden." -#. [Messages]ConfirmUninstall +msgctxt "[Messages]ConfirmUninstall" msgid "" "Are you sure you want to completely remove %1 and all of its components?" msgstr "" "Sind Sie sicher, dass Sie %1 und alle zugehörigen Komponenten entfernen " "möchten?" -#. [Messages]UninstallOnlyOnWin64 +msgctxt "[Messages]UninstallOnlyOnWin64" msgid "This installation can only be uninstalled on 64-bit Windows." msgstr "" "Diese Installation kann nur unter 64-Bit-Windows-Versionen entfernt werden." -#. [Messages]OnlyAdminCanUninstall +msgctxt "[Messages]OnlyAdminCanUninstall" msgid "" "This installation can only be uninstalled by a user with administrative " "privileges." @@ -1330,15 +1313,15 @@ msgstr "" "Diese Installation kann nur von einem Benutzer mit Administrator-Rechten " "entfernt werden." -#. [Messages]UninstallStatusLabel +msgctxt "[Messages]UninstallStatusLabel" msgid "Please wait while %1 is removed from your computer." msgstr "Warten Sie bitte, während %1 von Ihrem Computer entfernt wird." -#. [Messages]UninstalledAll +msgctxt "[Messages]UninstalledAll" msgid "%1 was successfully removed from your computer." msgstr "%1 wurde erfolgreich von Ihrem Computer entfernt." -#. [Messages]UninstalledMost +msgctxt "[Messages]UninstalledMost" msgid "" "%1 uninstall complete.%n%nSome elements could not be removed. These can be " "removed manually." @@ -1346,7 +1329,7 @@ msgstr "" "Entfernen von %1 beendet.%n%nEinige Komponenten konnten nicht entfernt " "werden. Diese können von Ihnen manuell gelöscht werden." -#. [Messages]UninstalledAndNeedsRestart +msgctxt "[Messages]UninstalledAndNeedsRestart" msgid "" "To complete the uninstallation of %1, your computer must be " "restarted.%n%nWould you like to restart now?" @@ -1354,15 +1337,15 @@ msgstr "" "Um die Deinstallation von %1 abzuschließen, muss Ihr Computer neu gestartet " "werden.%n%nMöchten Sie jetzt neu starten?" -#. [Messages]UninstallDataCorrupted +msgctxt "[Messages]UninstallDataCorrupted" msgid "\"%1\" file is corrupted. Cannot uninstall" msgstr "\"%1\"-Datei ist beschädigt. Entfernen der Anwendung fehlgeschlagen." -#. [Messages]ConfirmDeleteSharedFileTitle +msgctxt "[Messages]ConfirmDeleteSharedFileTitle" msgid "Remove Shared File?" msgstr "Gemeinsame Datei entfernen?" -#. [Messages]ConfirmDeleteSharedFile2 +msgctxt "[Messages]ConfirmDeleteSharedFile2" msgid "" "The system indicates that the following shared file is no longer in use by " "any programs. Would you like for Uninstall to remove this shared file?%n%nIf" @@ -1377,95 +1360,95 @@ msgstr "" "richtig. Wenn Sie unsicher sind, wählen Sie \"Nein\", um die Datei im System" " zu belassen. Es schadet Ihrem System nicht, wenn Sie die Datei behalten." -#. [Messages]SharedFileNameLabel +msgctxt "[Messages]SharedFileNameLabel" msgid "File name:" msgstr "Dateiname:" -#. [Messages]SharedFileLocationLabel +msgctxt "[Messages]SharedFileLocationLabel" msgid "Location:" msgstr "Ordner:" -#. [Messages]WizardUninstalling +msgctxt "[Messages]WizardUninstalling" msgid "Uninstall Status" msgstr "Entfernen (Status)" -#. [Messages]StatusUninstalling +msgctxt "[Messages]StatusUninstalling" msgid "Uninstalling %1..." msgstr "Entferne %1 ..." -#. [Messages]ShutdownBlockReasonInstallingApp +msgctxt "[Messages]ShutdownBlockReasonInstallingApp" msgid "Installing %1." msgstr "Installation von %1." -#. [Messages]ShutdownBlockReasonUninstallingApp +msgctxt "[Messages]ShutdownBlockReasonUninstallingApp" msgid "Uninstalling %1." msgstr "Deinstallation von %1." -#. [CustomMessages]installservicetask +msgctxt "[CustomMessages]installservicetask" msgid "Run Kolibri automatically when the computer starts" msgstr "" -#. [CustomMessages]newerversioninstalled +msgctxt "[CustomMessages]newerversioninstalled" msgid "" "A newer version of {#AppName} (%1) is already installed. This installer " "contains version %2, which is older. The setup will now exit." msgstr "" -#. [CustomMessages]sameversioninstalled +msgctxt "[CustomMessages]sameversioninstalled" msgid "" "This version of %1 is already installed. Do you want to repair the " "installation by reinstalling it?" msgstr "" -#. [CustomMessages]olderversioninstalled +msgctxt "[CustomMessages]olderversioninstalled" msgid "" "An older version of {#AppName} (%1) was detected. Do you want to upgrade to " "version {#AppVersion}?" msgstr "" -#. [CustomMessages]confirmuninstalldata +msgctxt "[CustomMessages]confirmuninstalldata" msgid "" "Do you want to completely remove all Kolibri user data? This includes all " "downloaded content, user accounts, and progress, and cannot be undone." msgstr "" -#. [CustomMessages]criticalerror +msgctxt "[CustomMessages]criticalerror" msgid "" "A critical error occurred while trying to run a setup command: %1. The " "installation cannot continue." msgstr "" -#. [CustomMessages]commanderror +msgctxt "[CustomMessages]commanderror" msgid "" "A command required for setup failed to execute correctly: %1. Error Code: " "%2. The installation cannot continue." msgstr "" -#. [CustomMessages]versionparseerror +msgctxt "[CustomMessages]versionparseerror" msgid "" "Could not compare versions due to an invalid version format. Please " "uninstall the previous version manually and try again." msgstr "" -#. [CustomMessages]migrationfailed +msgctxt "[CustomMessages]migrationfailed" msgid "" "The installer failed to migrate user data from the old location (%1) to the " "new location (%2). Your data has not been moved. Please contact support for " "assistance." msgstr "" -#. [CustomMessages]createdesktopicon +msgctxt "[CustomMessages]createdesktopicon" msgid "Create a &desktop icon" msgstr "" -#. [CustomMessages]additionalicons +msgctxt "[CustomMessages]additionalicons" msgid "Additional icons:" msgstr "" -#. [CustomMessages]launchprogram +msgctxt "[CustomMessages]launchprogram" msgid "Launch %1" msgstr "" -#. [CustomMessages]installationtype +msgctxt "[CustomMessages]installationtype" msgid "Installation Type:" msgstr "" diff --git a/installer/translations/po_to_isl.py b/installer/translations/po_to_isl.py index dde40d3..5b1e3c3 100644 --- a/installer/translations/po_to_isl.py +++ b/installer/translations/po_to_isl.py @@ -2,60 +2,61 @@ import configparser import polib +from definitions import LANG_DEFINITIONS -def convert_po_to_isl(template_isl_path, translated_po_path, output_isl_path): +def convert_po_to_isl( + template_isl_path, translated_po_path, output_isl_path, locale_code +): encoding = "utf-8-sig" - # 1. Load the translated .po file + # 1. Load PO po = polib.pofile(translated_po_path, encoding="utf-8") - # 2. Create a lookup map from msgid (English) to msgstr (Translated) + # 2. Create a lookup map using a Tuple: (msgid, msgctxt) translation_map = { - entry.msgid: entry.msgstr for entry in po if entry.msgstr and entry.msgid + (entry.msgid, entry.msgctxt): entry.msgstr for entry in po if entry.msgstr } - # 3. Load the template .isl file to get the structure and keys - template_config = configparser.ConfigParser(interpolation=None) - template_config.optionxform = str - template_config.read(template_isl_path, encoding=encoding) + # 3. Load Template + config = configparser.ConfigParser(interpolation=None) + config.optionxform = str + config.read(template_isl_path, encoding=encoding) - # 4. Iterate through the template and replace values with translations - for section in template_config.sections(): - for key in template_config[section]: - english_string = template_config[section][key] + # 4. Update Translations + for section in config.sections(): + for key in config[section]: + english_string = config[section][key] - translated_string = translation_map.get(english_string) + context_key = f"[{section}]{key}" + + translated_string = translation_map.get((english_string, context_key)) - # If a translation exists, update the value in our config object if translated_string: - template_config.set(section, key, translated_string) + config.set(section, key, translated_string) + + # 5. Add LangOptions section + if locale_code in LANG_DEFINITIONS: + lang_def = LANG_DEFINITIONS[locale_code] + if not config.has_section("LangOptions"): + config.add_section("LangOptions") + config.set("LangOptions", "LanguageName", lang_def["inno_name"]) + config.set("LangOptions", "LanguageID", lang_def["id"]) - print(f"Successfully created ISL file: {output_isl_path}") - with open(output_isl_path, "w", encoding="utf-8-sig") as f: - template_config.write(f, space_around_delimiters=False) + with open(output_isl_path, "w", encoding=encoding) as f: + config.write(f, space_around_delimiters=False) + + print(f"Generated: {output_isl_path}") if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Convert PO files back to ISL format.") - parser.add_argument( - "-t", - "--template", - required=True, - help="Path to the template ISL file (e.g., English.isl).", - ) - parser.add_argument( - "-i", - "--input", - required=True, - help="Path to the translated PO file (e.g., German.po).", - ) + parser = argparse.ArgumentParser() + parser.add_argument("-t", "--template", required=True) + parser.add_argument("-i", "--input", required=True) + parser.add_argument("-o", "--output", required=True) parser.add_argument( - "-o", - "--output", - required=True, - help="Path for the output ISL file (e.g., German.isl).", + "-l", "--lang", required=True, help="Locale code (e.g. 'es_ES')" ) args = parser.parse_args() - convert_po_to_isl(args.template, args.input, args.output) + convert_po_to_isl(args.template, args.input, args.output, args.lang) From 8d99c2d464ed84da05dce634281bf753c4dc4e9e Mon Sep 17 00:00:00 2001 From: Dimitrios Mylonas Date: Wed, 10 Dec 2025 13:18:55 +0200 Subject: [PATCH 4/4] Installer: standardize locales and add font/RTL support - Update `definitions.py` with native display names, custom fonts, and RTL flags. - Refactor locale codes (e.g., `de_DE` -> `de`) for consistency with kolbri intl-codes - Update `po_to_isl.py` to generate `LangOptions` based on new metadata. - Update `kolibri.iss` with the revised language list. --- installer/kolibri.iss | 34 +++- installer/translations/definitions.py | 192 +++++++++++++++++- .../locale/{de_DE => de}/messages.po | 6 +- installer/translations/po_to_isl.py | 16 +- 4 files changed, 231 insertions(+), 17 deletions(-) rename installer/translations/locale/{de_DE => de}/messages.po (99%) diff --git a/installer/kolibri.iss b/installer/kolibri.iss index a9602c7..a0a636a 100644 --- a/installer/kolibri.iss +++ b/installer/kolibri.iss @@ -42,8 +42,38 @@ ShowLanguageDialog=yes [Languages] Name: "en"; MessagesFile: "translations\en.isl" -; Name: "fr_FR"; MessagesFile: "translations\locale\fr_FR\fr_FR.isl" -Name: "de_DE"; MessagesFile: "translations\locale\de_DE\de_DE.isl" +; Name: "ar"; MessagesFile: "translations\locale\ar\ar.isl" +; Name: "bg_bg"; MessagesFile: "translations\locale\bg-bg\bg-bg.isl" +; Name: "bn_bd"; MessagesFile: "translations\locale\bn-bd\bn-bd.isl" +Name: "de"; MessagesFile: "translations\locale\de\de.isl" +; Name: "el"; MessagesFile: "translations\locale\el\el.isl" +; Name: "es_es"; MessagesFile: "translations\locale\es-es\es-es.isl" +; Name: "es_419"; MessagesFile: "translations\locale\es-419\es-419.isl" +; Name: "fa"; MessagesFile: "translations\locale\fa\fa.isl" +; Name: "fr_fr"; MessagesFile: "translations\locale\fr-fr\fr-fr.isl" +; Name: "ff_cm"; MessagesFile: "translations\locale\ff-cm\ff-cm.isl" +; Name: "gu_in"; MessagesFile: "translations\locale\gu-in\gu-in.isl" +; Name: "ha"; MessagesFile: "translations\locale\ha\ha.isl" +; Name: "hi_in"; MessagesFile: "translations\locale\hi-in\hi-in.isl" +; Name: "ht"; MessagesFile: "translations\locale\ht\ht.isl" +; Name: "id"; MessagesFile: "translations\locale\id\id.isl" +; Name: "it"; MessagesFile: "translations\locale\it\it.isl" +; Name: "ka"; MessagesFile: "translations\locale\ka\ka.isl" +; Name: "km"; MessagesFile: "translations\locale\km\km.isl" +; Name: "ko"; MessagesFile: "translations\locale\ko\ko.isl" +; Name: "mr"; MessagesFile: "translations\locale\mr\mr.isl" +; Name: "my"; MessagesFile: "translations\locale\my\my.isl" +; Name: "ny"; MessagesFile: "translations\locale\ny\ny.isl" +; Name: "pa"; MessagesFile: "translations\locale\pa\pa.isl" +; Name: "pt_br"; MessagesFile: "translations\locale\pt-br\pt-br.isl" +; Name: "pt_mz"; MessagesFile: "translations\locale\pt-mz\pt-mz.isl" +; Name: "sw_tz"; MessagesFile: "translations\locale\sw-tz\sw-tz.isl" +; Name: "te"; MessagesFile: "translations\locale\te\te.isl" +; Name: "uk"; MessagesFile: "translations\locale\uk\uk.isl" +; Name: "ur_pk"; MessagesFile: "translations\locale\ur-pk\ur-pk.isl" +; Name: "vi"; MessagesFile: "translations\locale\vi\vi.isl" +; Name: "yo"; MessagesFile: "translations\locale\yo\yo.isl" +; Name: "zh_hans"; MessagesFile: "translations\locale\zh-hans\zh-hans.isl" [Registry] ; This registry key is used to detect the installed version for upgrades/repairs. diff --git a/installer/translations/definitions.py b/installer/translations/definitions.py index 2166380..6b55c09 100644 --- a/installer/translations/definitions.py +++ b/installer/translations/definitions.py @@ -1,16 +1,192 @@ # Map functionality: -# Key: The ISO locale code (used for filenames, e.g., 'es_ES.isl', 'es_ES.po') # inno_name: The filename of the standard Inno Setup translation (e.g., 'Spanish.isl') # or just use the name you want to display in the installer's language selection. # id: The Microsoft Language ID required by Windows, can be found here: # MS IDs: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c +# font: (Optional) Only required if Segoe UI (Inno 6.6 default) does not support the language. +# International fonts: https://learn.microsoft.com/en-us/windows/apps/design/globalizing/loc-international-fonts +# rtl: (Optional) Set to True for Right-to-Left languages. LANG_DEFINITIONS = { - "en": {"inno_name": "English", "id": "$0409"}, # Exists in Inno Languages - "es_ES": {"inno_name": "Spanish", "id": "$040A"}, # Exists in Inno Languages - "de_DE": {"inno_name": "German", "id": "$0407"}, # Exists in Inno Languages - "ar_SA": {"inno_name": "Arabic", "id": "$0401"}, # Exists in Inno Languages - "fr_FR": {"inno_name": "French", "id": "$040C"}, # Exists in Inno Languages - "ko_KR": {"inno_name": "Korean", "id": "$0412"}, # Exists in Inno Languages - "yo_NG": {"inno_name": "Yoruba", "id": "$0438"}, # Does NOT exist in Inno Languages + # --- Official Inno Setup Languages --- + "ar": { + "inno_name": "Arabic", + "id": "$0401", + "rtl": True, + "display_name": "العَرَبِيَّة", + }, + "bg-bg": { + "inno_name": "Bulgarian", + "id": "$0402", + "display_name": "Български", + }, + "de": { + "inno_name": "German", + "id": "$0407", + "display_name": "Deutsch", + }, + "en": { + "inno_name": "English", + "id": "$0409", + "display_name": "English", + }, + "es-es": { + "inno_name": "Spanish", + "id": "$040A", + "display_name": "Español (España)", + }, + "fr-fr": { + "inno_name": "French", + "id": "$040C", + "display_name": "Français", + }, + "it": { + "inno_name": "Italian", + "id": "$0410", + "display_name": "Italiano", + }, + "ko": { + "inno_name": "Korean", + "id": "$0412", + "display_name": "한국어", + }, + "pt-br": { + "inno_name": "BrazilianPortuguese", + "id": "$0416", + "display_name": "Português (Brazil)", + }, + "uk": { + "inno_name": "Ukrainian", + "id": "$0422", + "display_name": "Украї́нська мо́ва", + }, + # --- Unofficial Inno Languages --- + "bn-bd": { + "inno_name": "Bengali", + "id": "$0845", + "font": "Nirmala UI", + "display_name": "বাংলা", + }, + "el": { + "inno_name": "Greek", + "id": "$0408", + "display_name": "Ελληνικά", + }, + "fa": { + "inno_name": "Persian", + "id": "$0429", + "rtl": True, + "display_name": "فارسی", + }, + "hi-in": { + "inno_name": "Hindi", + "id": "$0439", + "font": "Nirmala UI", + "display_name": "हिंदी (भारत)", + }, + "id": { + "inno_name": "Indonesian", + "id": "$0421", + "display_name": "Bahasa Indonesia", + }, + "ka": { + "inno_name": "Georgian", + "id": "$0437", + "display_name": "ქართული", + }, + "mr": { + "inno_name": "Marathi", + "id": "$044E", + "font": "Nirmala UI", + "display_name": "मराठी", + }, + "ur-pk": { + "inno_name": "Urdu", + "id": "$0420", + "font": "Nirmala UI", + "rtl": True, + "display_name": "اُردو (پاکستان)", + }, + "vi": { + "inno_name": "Vietnamese", + "id": "$042A", + "display_name": "Tiếng Việt", + }, + "zh-hans": { + "inno_name": "ChineseSimplified", + "id": "$0804", + "font": "Microsoft YaHei UI", + "display_name": "简体中文", + }, + # --- No Inno Translations --- + "es-419": { + "inno_name": "Spanish (Latin America)", + "id": "$580A", + "display_name": "Español", + }, + "ff-cm": { + "inno_name": "Fulah", + "id": "$0467", + "display_name": "Fulfulde Mbororoore", + }, + "gu-in": { + "inno_name": "Gujarati", + "id": "$0447", + "font": "Nirmala UI", + "display_name": "ગુજરાતી", + }, + "ha": { + "inno_name": "Hausa", + "id": "$0468", + "display_name": "Hausa", + }, + "ht": { + "inno_name": "Haitian Creole", + "id": "$1000", + "display_name": "Kreyòl Ayisyen", + }, + "km": { + "inno_name": "Khmer", + "id": "$0453", + "font": "Leelawadee UI", + "display_name": "ភាសាខ្មែរ", + }, + "my": { + "inno_name": "Burmese", + "id": "$0455", + "font": "Myanmar Text", + "display_name": "ဗမာစာ", + }, + "ny": { + "inno_name": "Chichewa", + "id": "$1000", + "display_name": "Chinyanja", + }, + "pa": { + "inno_name": "Punjabi", + "id": "$0446", + "font": "Nirmala UI", + "display_name": "ਪੰਜਾਬੀ", + }, + "pt-mz": { + "inno_name": "Portuguese (Mozambique)", + "id": "$0816", + "display_name": "Português (Moçambique)", + }, + "sw-tz": { + "inno_name": "Swahili", + "id": "$1000", + "display_name": "Kiswahili", + }, + "te": { + "inno_name": "Telugu", + "id": "$044A", + "font": "Nirmala UI", + "display_name": "తెలుగు", + }, + "yo": { + "inno_name": "Yoruba", + "id": "$046A", + "display_name": "Yorùbá", + }, } diff --git a/installer/translations/locale/de_DE/messages.po b/installer/translations/locale/de/messages.po similarity index 99% rename from installer/translations/locale/de_DE/messages.po rename to installer/translations/locale/de/messages.po index 2198d8e..6290234 100644 --- a/installer/translations/locale/de_DE/messages.po +++ b/installer/translations/locale/de/messages.po @@ -2,9 +2,9 @@ msgid "" msgstr "" "Project-Id-Version: kolibri-windows-installer\n" -"POT-Creation-Date: 2025-11-27T10:48:24.094016+02:00\n" -"PO-Revision-Date: 2025-11-27T10:48:24.094016+02:00\n" -"Language: de_DE\n" +"POT-Creation-Date: 2025-12-10T11:57:24.029462+02:00\n" +"PO-Revision-Date: 2025-12-10T11:57:24.029462+02:00\n" +"Language: de\n" "Content-Type: text/plain; charset=utf-8\n" msgctxt "[Messages]SetupAppTitle" diff --git a/installer/translations/po_to_isl.py b/installer/translations/po_to_isl.py index 5b1e3c3..fa7e0a1 100644 --- a/installer/translations/po_to_isl.py +++ b/installer/translations/po_to_isl.py @@ -40,9 +40,19 @@ def convert_po_to_isl( lang_def = LANG_DEFINITIONS[locale_code] if not config.has_section("LangOptions"): config.add_section("LangOptions") - config.set("LangOptions", "LanguageName", lang_def["inno_name"]) + ui_name = lang_def.get("display_name", lang_def["inno_name"]) + config.set("LangOptions", "LanguageName", ui_name) + config.set("LangOptions", "LanguageID", lang_def["id"]) + if "font" in lang_def: + font_name = lang_def["font"] + config.set("LangOptions", "DialogFontName", font_name) + config.set("LangOptions", "WelcomeFontName", font_name) + + if lang_def.get("rtl", False): + config.set("LangOptions", "RightToLeft", "yes") + with open(output_isl_path, "w", encoding=encoding) as f: config.write(f, space_around_delimiters=False) @@ -54,9 +64,7 @@ def convert_po_to_isl( parser.add_argument("-t", "--template", required=True) parser.add_argument("-i", "--input", required=True) parser.add_argument("-o", "--output", required=True) - parser.add_argument( - "-l", "--lang", required=True, help="Locale code (e.g. 'es_ES')" - ) + parser.add_argument("-l", "--lang", required=True) args = parser.parse_args() convert_po_to_isl(args.template, args.input, args.output, args.lang)