Rewrite installer using Inno Setup instead of NSIS.

For #467.

Korean and Simplified Chinese expect the unofficial translation
files to be dropped into the folder that holds the rest of the
translation files. If the files are missing, their translations
will not be included when the installer is built.

The translated strings were done in Google Translate and checked
in Bing Translate. They should at least be legible, if not great
quality.

The README now refers to Inno Setup, and the CONTRIBUTING file
has been generally updated both for the switch to Inno and the
recent code refactoring.
This commit is contained in:
Oliver Hamlet
2015-07-18 01:20:56 +01:00
parent 9b8b7ef5f2
commit d9dd2f2357
4 changed files with 281 additions and 648 deletions
+12 -10
View File
@@ -8,7 +8,7 @@ A general guide to contributing to LOOT, may be found on [LOOT's wiki](https://g
The repository branching structure is pretty simple:
* The `master` branch is a ready-to-release branch. It will generally hold code newer than the latest release, but which could be prepared (ie. update version number, changelog) and packaged for release fairly quickly and easily. Code on this branch *should* be reasonably bug free and features will be complete.
* The `dev` branch is a next-release branch. It holds code that's working towards the next big release but which isn't there yet. Code is generally buggy and features incomplete (though this will vary considerably through the development cycle.
* The `dev` branch is a next-release branch. It holds code that's working towards the next big release but which isn't there yet. Code is generally buggy and features incomplete (though this will vary considerably through the development cycle).
* Other branches are generally themed on specific features or groups of changes, and come and go as they are merged into one of the two above, or discarded.
## Getting Involved
@@ -33,11 +33,13 @@ To translate everything but masterlist messages, first fork this repository. All
### Translating the Installer
1. Open the installer script at `src/installer.nsi` in a text editor of your choice.
2. The English strings are located in the section with the heading `English Strings`. Create a copy of this section below the original.
3. Translate the quoted strings in the copied section, replacing the English text. For the lines beginning `VIAddVersionKey`, only translate the second quoted string.
4. Add an `!insertmacro MUI_LANGUAGE "<name>"` line to the section with the headering `Languages`. `<name>` is the NSIS name for your language: a perhaps incomplete example of accepted values can be found in [this script](http://nsis.sourceforge.net/Examples/Modern%20UI/MultiLanguage.nsi).
3. Save your changes.
First check that an [Inno Setup translation](http://www.jrsoftware.org/files/istrans/) exists for your language. Unofficial translations are acceptable, but require a bit of extra handling. If there isn't an official or unofficial translation for Inno Setup, you're better off making a translation and getting it listed on the linked page before continuing.
1. Open the installer script at `src/installer.iss` in a text editor of your choice.
2. If your language only has an unofficial translation, add a `#define <Language>Exists` block for it near the top of the script, like it has been done for Korean and Simplified Chinese.
3. Add your language to the `[Languages]` section. The `Name` must be the POSIX locale code for your language. The `MessagesFile` filename is the filename of the Inno Setup translation that you checked exists. If your language only has an unofficial translation, wrap its line in `#ifdef` and `#endif` lines, again like it has been done for Korean and Simplified Chinese.
4. Translate the string(s) in the `[CustomMessages]` into your language, following the example of the existing translations. Again, if your language only has an unofficial translation, wrap its line(s) in `#ifdef` and `#endif` lines.
5. Save your changes.
### Translating the LOOT application
@@ -45,7 +47,7 @@ To translate everything but masterlist messages, first fork this repository. All
2. If you are starting a new translation, select `File->New catalogue from POT file...` and choose the template file at `resources/l10n/template.pot`. In the `Catalog properties` dialog, just click `OK` without changing anything.
3. If you are updating a previous translation, open in Poedit the `loot.po` translation file in the relevant subdirectory of `resources/l10n`, then select `Catalogue->Update from POT file...` and choose the template file you downloaded. Click `OK` in the `Update summary` dialog.
4. Edit the translation file to add or update translations of the programs' text. Strings that were added since the last translation are displayed in bold and dark blue, and strings you have edited the translations of are marked with a star to the left of their source text in the main list.
5. Save the translation file with the filename `loot.po` in `resources/l10n/<locale>/LC_MESSAGES/`, where `<locale>` is your language's locale code.
5. Save the translation file with the filename `loot.po` in `resources/l10n/<locale>/LC_MESSAGES/`, where `<locale>` is your language's POSIX locale code.
Some languages may use different words or phrases for different contexts where only one word or phrase may be used for all contexts in English. While no contextual information is supplied to translators by default, it can be added on request. To request the addition of contextual information to a text string, create an issue for your request in LOOT's [source code issue tracker](https://github.com/loot/loot/issues), quoting the string for which you are requesting contextual information.
@@ -58,9 +60,9 @@ Some strings to be translated may contain special characters. Different types of
If you're adding a new translation, LOOT's source code must be updated to recognise it. You can do this yourself and include the changes in your translation's pull request if you wish. The files and functions which must be updated are given below.
* In [helpers.h](src/backend/helpers.h), add a constant for the language to the `Language` class, and update `Language::Names()`.
* In [helpers.cpp](src/backend/helpers.cpp), update `Language::Language(const std::string& nameOrCode)` and `Language::Construct(const unsigned int code)`.
* In [language.h](src/backend/helpers/language.h), add a static constant for the language to the `Language` class.
* In [language.cpp](src/backend/helpers/language.cpp), define the value for the constant you added, and update `Language::Language(const std::string& locale)`, `Language::Construct(const unsigned int code)` and `Language::Codes({...})` to include lines for your language.
* Add constants for the language in [api.h](src/api/api.h) and [api.cpp](src/api/api.cpp).
* In [archive.py](src/archive.py), add the language folder to the inline list on line 68.
* In [installer.nsi](src/installer.nsi), add entries for the language folder to the install and uninstall sections.
* In [installer.iss](src/installer.iss), add an entry for your language's translation file to the `[Files]` section.
* In [LOOT Metadata Syntax.html](docs/LOOT%20Metadata%20Syntax.html), add a row for your language to the Language Codes table.
+3 -1
View File
@@ -47,7 +47,9 @@ To install Bower and Vulcanize, first install [Node](http://nodejs.org/), and ru
## Packaging Releases
Installer and zip archive releases for the main LOOT application can be handled by running the scripts `installer.nsi` and `archive.py` in the `src` folder respectively. The installer script requires [NSIS 3](http://nsis.sourceforge.net/), while the archive script requires [Python](http://www.python.org/) (2 or 3). The installer and archive files are created in the `build/` folder, relative to the repository root.
Installer and zip archive releases for the main LOOT application can be handled by running the `src/installer.iss` and `src/archive.py` scripts respectively. The installer script requires [Inno Setup](http://www.jrsoftware.org/isinfo.php), with the unofficial Korean and Simplified C, while the archive script requires [Python](http://www.python.org/) (2 or 3). The installer and archive files are created in the `build/` folder, relative to the repository root.
If the unofficial Korean and Simplified Chinese Inno Setup translation files are installed alongside the official translation files, then the installer script will also offer those language options. If they are not found, the installer will be built without them.
If you have [Git for Windows (msysGit)](https://msysgit.github.io/) or [GitHub for Windows](https://windows.github.com/) installed and you're building from a clone of this repository, the archive script will give archives descriptive names using the output of `git describe --tags --long`. If you have [7-Zip](http://7-zip.org) installed, `.7z` archives will be created. Otherwise, archives will be named `LOOT Archive` and created as deflate-compressed zip files.
+266
View File
@@ -0,0 +1,266 @@
; LOOT installer Inno Setup script.
; This file must be encoded in UTF-8 WITH a BOM for Unicode text to
; be displayed correctly.
#define MyAppName "LOOT"
#define MyAppVersion "0.8.0"
#define MyAppPublisher "LOOT Team"
#define MyAppURL "http://loot.github.io"
#define MyAppExeName "LOOT.exe"
#if FileExists(AddBackslash(CompilerPath) + 'Languages\Korean.isl')
#define KoreanExists
#endif
#if FileExists(AddBackslash(CompilerPath) + 'Languages\ChineseSimplified.isl')
#define SimplifiedChineseExists
#endif
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{BF634210-A0D4-443F-A657-0DCE38040374}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppCopyright=Copyright (C) 2009-2015 {#MyAppPublisher}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
SourceDir=..\
OutputBaseFilename=LOOT Installer
OutputDir=build
SetupIconFile=resources\icon.ico
Compression=lzma
SolidCompression=yes
DisableReadyPage=yes
[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl"
Name: "pt_BR"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl"
Name: "da"; MessagesFile: "compiler:Languages\Danish.isl"
Name: "fi"; MessagesFile: "compiler:Languages\Finnish.isl"
Name: "fr"; MessagesFile: "compiler:Languages\French.isl"
Name: "de"; MessagesFile: "compiler:Languages\German.isl"
#ifdef KoreanExists
Name: "ko"; MessagesFile: "compiler:Languages\Korean.isl"
#endif
Name: "pl"; MessagesFile: "compiler:Languages\Polish.isl"
Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl"
#ifdef SimplifiedChineseExists
Name: "zh_CN"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
#endif
Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "build\Release\LOOT.exe"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "build\Release\cef.pak"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "build\Release\cef_100_percent.pak"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "build\Release\cef_200_percent.pak"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "build\Release\d3dcompiler_47.dll"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "build\Release\devtools_resources.pak"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "build\Release\icudtl.dat"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "build\Release\libcef.dll"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "build\Release\libEGL.dll"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "build\Release\libGLESv2.dll"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "build\Release\wow_helper.exe"; \
DestDir: "{app}"; Flags: ignoreversion
Source: "docs\LOOT Metadata Syntax.html"; \
DestDir: "{app}\docs"; Flags: ignoreversion
Source: "docs\LOOT Readme.html"; \
DestDir: "{app}\docs"; Flags: ignoreversion isreadme
Source: "docs\licenses\*"; \
DestDir: "{app}\docs\licenses"; Flags: ignoreversion
Source: "docs\images\main.png"; \
DestDir: "{app}\docs\images"; Flags: ignoreversion
Source: "docs\images\settings.png"; \
DestDir: "{app}\docs\images"; Flags: ignoreversion
Source: "resources\report\index.html"; \
DestDir: "{app}\resources\report"; Flags: ignoreversion
Source: "resources\report\bower_components\marked\lib\marked.js"; \
DestDir: "{app}\resources\report\bower_components\marked\lib"; Flags: ignoreversion
Source: "resources\report\bower_components\Jed\jed.js"; \
DestDir: "{app}\resources\report\bower_components\Jed"; Flags: ignoreversion
Source: "resources\report\bower_components\jed-gettext-parser\jedGettextParser.js"; \
DestDir: "{app}\resources\report\bower_components\jed-gettext-parser"; Flags: ignoreversion
Source: "resources\report\css\dark-theme.css"; \
DestDir: "{app}\resources\report\css"; Flags: ignoreversion
Source: "resources\report\js\events.js"; \
DestDir: "{app}\resources\report\js"; Flags: ignoreversion
Source: "resources\report\js\filters.js"; \
DestDir: "{app}\resources\report\js"; Flags: ignoreversion
Source: "resources\report\js\helpers.js"; \
DestDir: "{app}\resources\report\js"; Flags: ignoreversion
Source: "resources\report\js\l10n.js"; \
DestDir: "{app}\resources\report\js"; Flags: ignoreversion
Source: "resources\report\js\loot.js"; \
DestDir: "{app}\resources\report\js"; Flags: ignoreversion
Source: "resources\report\js\plugin.js"; \
DestDir: "{app}\resources\report\js"; Flags: ignoreversion
Source: "resources\report\fonts\*"; \
DestDir: "{app}\resources\report\fonts"; Flags: ignoreversion
Source: "resources\l10n\da\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\da\LC_MESSAGES"; Flags: ignoreversion
Source: "resources\l10n\de\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\de\LC_MESSAGES"; Flags: ignoreversion
Source: "resources\l10n\es\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\es\LC_MESSAGES"; Flags: ignoreversion
Source: "resources\l10n\fi\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\fi\LC_MESSAGES"; Flags: ignoreversion
Source: "resources\l10n\fr\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\fr\LC_MESSAGES"; Flags: ignoreversion
Source: "resources\l10n\ko\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\ko\LC_MESSAGES"; Flags: ignoreversion
Source: "resources\l10n\pl\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\pl\LC_MESSAGES"; Flags: ignoreversion
Source: "resources\l10n\pt_BR\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\pt_BR\LC_MESSAGES"; Flags: ignoreversion
Source: "resources\l10n\ru\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\ru\LC_MESSAGES"; Flags: ignoreversion
Source: "resources\l10n\zh_CN\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\zh_CN\LC_MESSAGES"; Flags: ignoreversion
Source: "resources\settings.yaml"; \
DestDir: "{localappdata}\{#MyAppName}"; Flags: onlyifdoesntexist uninsneveruninstall; AfterInstall: SetLOOTLanguage
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
[Registry]
; Store install path for backwards-compatibility with old NSIS install script behaviour.
Root: HKLM; Subkey: "Software\LOOT"; ValueType: string; ValueName: "Installed Path"; ValueData: "{app}"; Flags: deletekey uninsdeletekey
[UninstallDelete]
Type: files; Name: "{localappdata}\{#MyAppName}\";
Type: files; Name: "{localappdata}\{#MyAppName}\";
Type: files; Name: "{localappdata}\{#MyAppName}\Oblivion\masterlist.yaml";
Type: files; Name: "{localappdata}\{#MyAppName}\Skyrim\masterlist.yaml";
Type: files; Name: "{localappdata}\{#MyAppName}\Fallout3\masterlist.yaml";
Type: files; Name: "{localappdata}\{#MyAppName}\FalloutNV\masterlist.yaml";
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\Oblivion\.git";
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\Skyrim\.git";
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\Fallout3\.git";
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\FalloutNV\.git";
Type: dirifempty; Name: "{localappdata}\{#MyAppName}\Oblivion";
Type: dirifempty; Name: "{localappdata}\{#MyAppName}\Skyrim";
Type: dirifempty; Name: "{localappdata}\{#MyAppName}\Fallout3";
Type: dirifempty; Name: "{localappdata}\{#MyAppName}\FalloutNV";
Type: dirifempty; Name: "{localappdata}\{#MyAppName}";
[CustomMessages]
en.DeleteUserFiles=Do you want to delete your settings and user metadata?
;pt_BR.DeleteUserFiles=
da.DeleteUserFiles=Ønsker du at slette dine indstillinger og bruger metadata?
fi.DeleteUserFiles=Haluatko poistaa asetukset ja käyttäjä metatiedot?
fr.DeleteUserFiles=Voulez-vous supprimer vos paramètres et les métadonnées de l'utilisateur?
de.DeleteUserFiles=Möchten Sie Ihre Einstellungen und Benutzer-Metadaten löschen?
#ifdef KoreanExists
ko.DeleteUserFiles=당신은 당신의 설정과 사용자 메타 데이터를 삭제 하시겠습니까?
#endif
pl.DeleteUserFiles=Czy chcesz usunąć ustawienia i metadane użytkownika?
ru.DeleteUserFiles=Вы хотите, чтобы удалить настройки и метаданные пользователя?
#ifdef SimplifiedChineseExists
zh_CN.DeleteUserFiles=你想删除您的设置和用户的元数据?
#endif
es.DeleteUserFiles=¿Quieres borrar sus ajustes y metadatos de usuario?
[Code]
// Set LOOT's language in settings.yaml
procedure SetLOOTLanguage();
var
SearchLineStart: String;
ReplaceLine: String;
Lines: TArrayOfString;
I: Integer;
begin
if ActiveLanguage = 'en' then
exit;
SearchLineStart := 'language:';
ReplaceLine := 'language: ' + ActiveLanguage;
if LoadStringsFromFile(ExpandConstant(CurrentFileName), Lines) = True then begin
for I := 0 to GetArrayLength(Lines) - 1 do begin
if Copy(Lines[I], 0, Length(SearchLineStart)) = SearchLineStart then begin
Lines[I] := ReplaceLine;
SaveStringsToUTF8File(ExpandConstant(CurrentFileName), Lines, False)
Break;
end;
end;
end;
end;
// Query user whether their data files should be deleted on uninstall.
procedure CurUninstallStepChanged (CurUninstallStep: TUninstallStep);
begin
// Don't remove user data if the uninstall is silent.
if UninstallSilent then
exit;
if CurUninstallStep = usUninstall then begin
if MsgBox(CustomMessage('DeleteUserFiles'), mbConfirmation, MB_YESNO or MB_DEFBUTTON2) = IDYES
then begin
DeleteFile(ExpandConstant('{localappdata}\{#MyAppName}\LOOTDebugLog.txt'));
DeleteFile(ExpandConstant('{localappdata}\{#MyAppName}\CEFDebugLog.txt'));
DeleteFile(ExpandConstant('{localappdata}\{#MyAppName}\settings.yaml'));
DeleteFile(ExpandConstant('{localappdata}\{#MyAppName}\Oblivion\userlist.yaml'));
DeleteFile(ExpandConstant('{localappdata}\{#MyAppName}\Skyrim\userlist.yaml'));
DeleteFile(ExpandConstant('{localappdata}\{#MyAppName}\Fallout3\userlist.yaml'));
DeleteFile(ExpandConstant('{localappdata}\{#MyAppName}\FalloutNV\userlist.yaml'));
end;
end;
end;
// Run a previous install's uninstaller before starting this installation.
procedure CurStepChanged(CurStep: TSetupStep);
var
RegKey: String;
RegValue: String;
ResultCode: Integer;
begin
if CurStep = ssInstall then begin
// First try using the Inno Setup installer's uninstall Registry key to get
// the uninstaller's path. This is necessary instead of just using the
// backwards-compatible key because the filename of the uninstaller created
// by Inno Setup can vary.
RegKey := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
if RegQueryStringValue(HKLM, RegKey, 'UninstallString', RegValue) then begin
Exec(RemoveQuotes(RegValue), '/VERYSILENT', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
// Now try using the backwards-compatible Registry key, and run the NSIS
// uninstaller, which has a fixed filename.
end
else begin
if RegQueryStringValue(HKLM, 'Software\LOOT', 'Installed Path', RegValue) then begin
Exec(RegValue + '\Uninstall.exe', '/VERYSILENT', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
end;
end;
end;
-637
View File
File diff suppressed because it is too large Load Diff