feat(bundler): allow setting wix language, closes #1976 (#1988)

This commit is contained in:
Lucas Fernandes Nogueira 2021-06-15 21:12:34 -03:00 committed by GitHub
parent 463fd00d06
commit 4791961981
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 247 additions and 29 deletions

View File

@ -0,0 +1,5 @@
---
"tauri-bundler": patch
---
Allow setting the Windows installer language and using project names that contains non-Unicode characters.

View File

@ -0,0 +1,5 @@
---
"cli.rs": patch
---
Adds `tauri > bundle > windows > wix > language` config option. See https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables.

View File

@ -160,6 +160,7 @@ It's composed of the following properties:
{ property: "certificateThumbprint", optional: true, type: "string[]", description: `Specifies the SHA1 hash of the signing certificate.` },
{ property: "timestampUrl", optional: true, type: "string[]", description: `Server to use during timestamping.` },
{ property: "wix", optional: true, type: "object", child: <Properties anchorRoot="tauri.bundle.windows.wix" rows={[
{ property: "language", optional: true, type: "string", description: `The installer language. See https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables.` },
{ property: "template", optional: true, type: "string", description: `A custom .wxs template to use.` },
{ property: "fragmentPaths", optional: true, type: "string[]", description: `A list of paths to .wxs files with WiX fragments to use.` },
{ property: "componentGroupRefs", optional: true, type: "string[]", description: `The ComponentGroup element ids you want to reference from the fragments.` },

View File

@ -175,6 +175,8 @@ pub struct MacOsSettings {
/// Settings specific to the WiX implementation.
#[derive(Clone, Debug, Default)]
pub struct WixSettings {
/// The app language. See https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables.
pub language: String,
/// By default, the bundler uses an internal template.
/// This option allows you to define your own wix file.
pub template: Option<PathBuf>,

View File

@ -0,0 +1,154 @@
{
"ar-SA": {
"langId": 1025,
"asciiCode": 1256
},
"ca-ES": {
"langId": 1027,
"asciiCode": 1252
},
"zh-TW": {
"langId": 1028,
"asciiCode": 950
},
"zh-CN": {
"langId": 2052,
"asciiCode": 936
},
"cs-CZ": {
"langId": 1029,
"asciiCode": 1250
},
"da-DK": {
"langId": 1030,
"asciiCode": 1252
},
"de-DE": {
"langId": 1031,
"asciiCode": 1252
},
"el-GR": {
"langId": 1032,
"asciiCode": 1253
},
"en-US": {
"langId": 1033,
"asciiCode": 1252
},
"es-ES": {
"langId": 3082,
"asciiCode": 1252
},
"et-EE": {
"langId": 1061,
"asciiCode": 1257
},
"fi-FI": {
"langId": 1035,
"asciiCode": 1252
},
"fr-FR": {
"langId": 1036,
"asciiCode": 1252
},
"he-IL": {
"langId": 1037,
"asciiCode": 1255
},
"hu-HU": {
"langId": 1038,
"asciiCode": 1250
},
"it-IT": {
"langId": 1040,
"asciiCode": 1252
},
"jp-JP": {
"langId": 1041,
"asciiCode": 932
},
"ko-KO": {
"langId": 1042,
"asciiCode": 949
},
"lt-LT": {
"langId": 1063,
"asciiCode": 1257
},
"lv-LV": {
"langId": 1062,
"asciiCode": 1257
},
"nl-NL": {
"langId": 1043,
"asciiCode": 1252
},
"nb-NO": {
"langId": 1044,
"asciiCode": 1252
},
"pl-PL": {
"langId": 1045,
"asciiCode": 1250
},
"pt-BR": {
"langId": 1046,
"asciiCode": 1252
},
"pt-PT": {
"langId": 2070,
"asciiCode": 1252
},
"ro-RO": {
"langId": 1048,
"asciiCode": 1250
},
"ru-RU": {
"langId": 1049,
"asciiCode": 1251
},
"hr-HR": {
"langId": 1050,
"asciiCode": 1250
},
"sk-SK": {
"langId": 1051,
"asciiCode": 1250
},
"sv-SE": {
"langId": 1053,
"asciiCode": 1252
},
"th-TH": {
"langId": 1054,
"asciiCode": 874
},
"tr-TR": {
"langId": 1055,
"asciiCode": 1254
},
"sl-SI": {
"langId": 1060,
"asciiCode": 1250
},
"vi-VN": {
"langId": 1066,
"asciiCode": 1258
},
"eu-ES": {
"langId": 1069,
"asciiCode": 1252
},
"bg-BG": {
"langId": 1026,
"asciiCode": 1251
},
"uk-UA": {
"langId": 1058,
"asciiCode": 1251
},
"sr-Latn-CS": {
"langId": 2074,
"asciiCode": 1250
}
}

View File

@ -11,14 +11,14 @@ use crate::bundle::{
use handlebars::{to_json, Handlebars};
use regex::Regex;
use serde::Serialize;
use serde::{Deserialize, Serialize};
use sha2::Digest;
use uuid::Uuid;
use zip::ZipArchive;
use std::{
collections::BTreeMap,
fs::{create_dir_all, remove_dir_all, write, File},
collections::{BTreeMap, HashMap},
fs::{create_dir_all, remove_dir_all, rename, write, File},
io::{Cursor, Read, Write},
path::{Path, PathBuf},
process::{Command, Stdio},
@ -52,6 +52,14 @@ const UUID_NAMESPACE: [u8; 16] = [
/// Mapper between a resource directory name and its ResourceDirectory descriptor.
type ResourceMap = BTreeMap<String, ResourceDirectory>;
#[derive(Debug, Deserialize)]
struct LanguageMetadata {
#[serde(rename = "asciiCode")]
ascii_code: usize,
#[serde(rename = "langId")]
lang_id: usize,
}
/// A binary to bundle with WIX.
/// External binaries or additional project binaries are represented with this data structure.
/// This data structure is needed because WIX requires each path to have its own `id` and `guid`.
@ -313,10 +321,10 @@ fn run_candle(
fn run_light(
wix_toolset_path: &Path,
build_path: &Path,
wixobjs: &[&str],
arguments: Vec<String>,
output_path: &Path,
settings: &Settings,
) -> crate::Result<PathBuf> {
) -> crate::Result<()> {
let light_exe = wix_toolset_path.join("light.exe");
let mut args: Vec<String> = vec![
@ -326,8 +334,8 @@ fn run_light(
output_path.display().to_string(),
];
for p in wixobjs {
args.push((*p).to_string());
for p in arguments {
args.push(p);
}
let mut cmd = Command::new(&light_exe);
@ -336,19 +344,16 @@ fn run_light(
.stdout(Stdio::piped())
.current_dir(build_path);
common::print_info(format!("running light to produce {}", output_path.display()).as_str())?;
common::execute_with_verbosity(&mut cmd, settings)
.map(|_| output_path.to_path_buf())
.map_err(|_| {
crate::Error::ShellScriptError(format!(
"error running light.exe{}",
if settings.is_verbose() {
""
} else {
", try running with --verbose to see command output"
}
))
})
common::execute_with_verbosity(&mut cmd, settings).map_err(|_| {
crate::Error::ShellScriptError(format!(
"error running light.exe{}",
if settings.is_verbose() {
""
} else {
", try running with --verbose to see command output"
}
))
})
}
// fn get_icon_data() -> crate::Result<()> {
@ -406,6 +411,29 @@ pub fn build_wix_app_installer(
let mut data = BTreeMap::new();
let language_map: HashMap<String, LanguageMetadata> =
serde_json::from_str(include_str!("./languages.json")).unwrap();
let (language, language_metadata) = if let Some(wix) = &settings.windows().wix {
let metadata = language_map.get(&wix.language).unwrap_or_else(|| {
panic!(
"Language {} not found. It must be one of {}",
wix.language,
language_map
.keys()
.cloned()
.collect::<Vec<String>>()
.join(", ")
)
});
(wix.language.clone(), metadata)
} else {
common::print_info("Wix settings not found. Using `en-US` as language.")?;
("en-US".into(), language_map.get("en-US").unwrap())
};
data.insert("language_id", to_json(language_metadata.lang_id));
data.insert("ascii_codepage", to_json(language_metadata.ascii_code));
data.insert("product_name", to_json(settings.product_name()));
data.insert("version", to_json(settings.version_string()));
let manufacturer = settings.bundle_identifier().to_string();
@ -511,16 +539,26 @@ pub fn build_wix_app_installer(
run_candle(settings, wix_toolset_path, &output_path, wxs)?;
}
let wixobjs = vec!["*.wixobj"];
let target = run_light(
let arguments = vec![
format!("-cultures:{}", language.to_lowercase()),
"*.wixobj".into(),
];
let msi_output_path = output_path.join("output.msi");
let msi_path = app_installer_dir(settings)?;
create_dir_all(msi_path.parent().unwrap())?;
common::print_info(format!("running light to produce {}", msi_path.display()).as_str())?;
run_light(
wix_toolset_path,
&output_path,
&wixobjs,
&app_installer_dir(settings)?,
arguments,
&msi_output_path,
settings,
)?;
rename(&msi_output_path, &msi_path)?;
Ok(target)
Ok(msi_path)
}
/// Generates the data required for the external binaries and extra binaries bundling.

View File

@ -13,18 +13,18 @@
Id="*"
Name="{{{product_name}}}"
UpgradeCode="{{{upgrade_code}}}"
Language="1033"
Codepage="1252"
Language="{{language_id}}"
Codepage="{{ascii_codepage}}"
Manufacturer="{{{manufacturer}}}"
Version="{{{version}}}">
<Package Id="*"
Keywords="Installer"
InstallerVersion="450"
Languages="1033"
Languages="{{language_id}}"
Compressed="yes"
InstallScope="perMachine"
SummaryCodepage="1252"/>
SummaryCodepage="{{ascii_codepage}}"/>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed."
MigrateFeatures="yes" />

View File

@ -53,9 +53,16 @@ pub struct MacConfig {
pub entitlements: Option<String>,
}
fn default_language() -> String {
"en-US".into()
}
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct WixConfig {
/// App language. See https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables.
#[serde(default = "default_language")]
pub language: String,
pub template: Option<PathBuf>,
#[serde(default)]
pub fragment_paths: Vec<PathBuf>,

View File

@ -1289,6 +1289,11 @@
"type": "string"
}
},
"language": {
"description": "App language. See https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables.",
"default": "en-US",
"type": "string"
},
"mergeRefs": {
"default": [],
"type": "array",

View File

@ -16,6 +16,7 @@ pub use config_definition::*;
impl From<WixConfig> for tauri_bundler::WixSettings {
fn from(config: WixConfig) -> tauri_bundler::WixSettings {
tauri_bundler::WixSettings {
language: config.language,
template: config.template,
fragment_paths: config.fragment_paths,
component_group_refs: config.component_group_refs,