wix 工具集:如何创建具有针对多种语言本地化的产品名称的单个 exe
wix toolset: how to create a single exe with product name localized for multiple languages
我正在使用 WiX v3.9 R2 创建我的安装程序。我将安装程序本地化为多种语言,效果很好。但是,无论格式和显示语言设置为什么语言,它始终使用程序和功能中应用程序的英文名称。
如何在“程序和功能”中告诉它为我的应用程序使用本地化名称?
编辑:
澄清一下:我认为我需要的是一种在安装时根据用户语言更改 Bundle 名称属性(或 [WixBundleName])的方法。这可能吗?
否则,人们目前如何使用 WiX Bundle,并最终在程序和功能中本地化程序名称?
编辑 2:
来自 WiX site:
WixBundleName - gets the name of the bundle (from Bundle/@Name). This
variable can also be set by the bootstrapper application to modify the
bundle name at runtime.
听起来这是可以做到的 - 但是怎么做呢?
编辑 3:
这是我目前的 Bundle,供参考。链中的最后一项是我的申请。
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Bundle Name="Map Creator"
Version="$(var.ProductVersion)"
Manufacturer="FMOsoft"
IconSourceFile="$(var.KarteDir)\assets\logo\ico\icon.ico"
UpgradeCode="[GUID]"
AboutUrl="http://fmosoft.com/MapCreator"
Copyright="Copyright© 2015, FMOsoft">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkSidebarLicense">
<bal:WixStandardBootstrapperApplication
LocalizationFile="$(var.KarteDir)\install\win\L10n\installer\thm_en_us.wxl"
ThemeFile="$(var.KarteDir)\install\win\HyperlinkSidebarTheme_fmosoft.xml"
LogoFile="$(var.KarteDir)\assets\logo\bmp\logo_64.bmp"
LogoSideFile="logoside.bmp"
ShowVersion="yes"
LicenseFile="$(var.KarteDir)\install\license_en.html"
SuppressOptionsUI="yes"
LaunchTarget="[ProgramFiles6432Folder]\FMOsoft\MapCreator\MapCreator.exe"
/>
<!-- WixStdBa requires specific names, at run time, in the temporary .BA1 folder. XML and png file is only needed for layout changes.
Payload/@Name for .wxl must be <lcid>\thm.wxl
Payload/@Name for .xml must be <lcid>\thm.xml AND must also have logo.png in same folder.-->
<Payload Id="theme_en_us" Compressed="yes" Name="1033\thm.wxl" SourceFile="$(var.KarteDir)\install\win\L10n\installer\thm_en_us.wxl"/>
<Payload Id="license_en_us" Compressed="yes" Name="1033\license.html" SourceFile="$(var.KarteDir)\install\license_en.html"/>
<Payload Id="theme_es_es" Compressed="yes" Name="1034\thm.wxl" SourceFile="$(var.KarteDir)\install\win\L10n\installer\thm_es_es.wxl"/>
<Payload Id="license_es_es" Compressed="yes" Name="1034\license.html" SourceFile="$(var.KarteDir)\install\license_es.html"/>
<Payload Id="theme_fr_fr_xml" Compressed="yes" Name="1036\thm.xml" SourceFile="$(var.KarteDir)\install\win\L10n\installer\HyperlinkSidebarTheme_fmosoft_fr.xml"/>
<Payload Id="theme_fr_fr" Compressed="yes" Name="1036\thm.wxl" SourceFile="$(var.KarteDir)\install\win\L10n\installer\thm_fr_fr.wxl"/>
<Payload Id="theme_fr_fr_logo" Compressed="yes" Name="1036\logo.png" SourceFile="$(var.KarteDir)\assets\logo\bmp\logo_64.bmp"/>
<Payload Id="theme_fr_fr_sidelogo" Compressed="yes" Name="1036\logoside.png" SourceFile="$(var.KarteDir)\install\win\logoside.bmp"/>
<Payload Id="license_fr_fr" Compressed="yes" Name="1036\license.html" SourceFile="$(var.KarteDir)\install\license_fr.html"/>
<Payload Id="theme_pt_br" Compressed="yes" Name="1046\thm.wxl" SourceFile="$(var.KarteDir)\install\win\L10n\installer\thm_pt_br.wxl"/>
<Payload Id="license_pt_br" Compressed="yes" Name="1046\license.html" SourceFile="$(var.KarteDir)\install\license_pt.html"/>
<Payload Id="theme_id" Compressed="yes" Name="1057\thm.wxl" SourceFile="$(var.KarteDir)\install\win\L10n\installer\thm_id.wxl"/>
<Payload Id="license_id" Compressed="yes" Name="1057\license.html" SourceFile="$(var.KarteDir)\install\license_id.html"/>
</BootstrapperApplicationRef>
<WixVariable Id="WixStdbaLicenseUrl" Value="license.html" />
<Variable Name="MyProductVersion" Value="$(var.ProductVersion)" />
<!-- There must be a better way to show the localized name of the app in the setup, but this works. -->
<Variable Name="AppName_es" Value="Creador de Mapas"/>
<Variable Name="AppName_fr" Value="Créateur de Carte"/>
<Variable Name="AppName_pt" Value="Criador de Mapas"/>
<Variable Name="AppName_id" Value="Pencipta Peta"/>
<Chain>
<ExePackage SourceFile="vcredist_x64.exe" PerMachine="yes" Permanent="yes" Vital="yes" Compressed="yes" InstallCommand="/quiet /norestart" InstallCondition="VersionNT64"/>
<ExePackage SourceFile="vcredist_x86.exe" PerMachine="yes" Permanent="yes" Vital="yes" Compressed="yes" InstallCommand="/quiet /norestart" InstallCondition="NOT VersionNT64"/>
<PackageGroupRef Id="OldMapEditorPackage"/>
<MsiPackage Vital="yes" SourceFile="$(var.BuildDir)out\map-creator-$(var.Platform).msi" />
</Chain>
</Bundle>
</Wix>
有一个开放的功能请求:http://wixtoolset.org/issues/4045/。此解决方案将允许您提供资源 dll,程序和功能将查询显示名称,因此如果用户更改 OS 语言,它会发生变化。
在有人实施该功能之前,您说得对,这可以通过设置 WixBundleName
变量来完成。如果您正在编写自定义 BA,您将调用 IBootstrapperEngine::SetVariableString
.
如果您使用的是 WixStdBA,则必须使用没有很好记录的 BAFunctions dll 来调用此方法。最近刚刚添加了一个示例项目 here. Note that the WixStdBALanguageId variable,它可以帮助您了解当前的语言是什么。
要添加 BAFunctions.dll,只需将其添加为负载:
<BootstrapperApplicationRef ...>
<Payload Name="BAFunctions.dll" SourceFile="path\to\your.dll" />
</BootstrapperApplicationRef>
如果它有帮助,因为我花了很长时间才弄清楚,这是我本地化 WixBundleName 的方式,所以它在程序和功能中本地化。这是基于 Sean Hall 的回答和评论。
这适用于 WiX 3.10.0.1519 weekly build, built on Thursday, Mar. 19 2015。
/* This document describes how we build bafunctions.dll.
1. Install the version of WiX you want to use. This is necessary because it sets some environment variables or something,
and provides some .h files needed to get the BAFunctions project to compile.
2. Download the wixXX-debug.zip file from the same page where the WiX installer is for the version of WiX you want.
3. Unzip and browse to [wixXX-debug\src\burn\Samples\bafunctions\ and open the project in Visual Studio 2010.
4. In WixBootstrapperBAFunction.cpp, add our code as shown below.
5. Rebuild solution in Release configuration.
6. copy bafunctions\release\bafunctions.dll to Map Creator build machine, [map_creator]\install\win\[Wix_X.X]
*/
// In WixBootstrapperBAFunction.cpp:
// comment out this line (line 32 in WiX 3.10):
STDMETHODIMP OnDetectComplete() { return S_OK; }
/* uncomment the commented-out OnDetectComplete procedure, and in the section marked
// YOUR CODE GOES HERE
add this code:
*/
LONGLONG lang_id = NULL;
LPWSTR bundle_name = NULL;
LPWSTR platform = NULL;
LPWSTR orig_name = NULL;
// get the language the user is using
BalGetNumericVariable(L"WixStdBALanguageId", &lang_id);
BalExitOnFailure(hr, "Failed to get variable 'WixStdBALanguageId'.");
// log the language id
char msg[66]; // 66 I'm sure is big enough
sprintf_s(msg, 67, "%s%d", "WixStdBALanguageId is ", lang_id);
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, msg);
/* I don't know how to pass custom variables from the .wxs, so I tried below to use the built-in HelpTelephone.
That doesn't work either - apparently we can only get variables listed in:
http://wixtoolset.org/documentation/manual/v3/bundle/bundle_built_in_variables.html
BalGetStringVariable(L"WixBundleHelpTelephone", &platform);
BalExitOnFailure(hr, "Failed to get WixBundleHelpTelephone variable.");*/
// Since I don't know how to pass a custom variable from the .wxs, I get the @Name attribute of the Bundle (from the .wxs),
// and I parse out the platform.
BalGetStringVariable(L"WixBundleName", &orig_name);
BalExitOnFailure(hr, "Failed to get WixBundleName variable.");
platform = wcsrchr(orig_name, '(');
// log the platform.
char msg5[66]; // 66 I'm sure is big enough
sprintf_s(msg5, 67, "%s%s", "platform is ", platform);
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, msg5);
// Select the localized bundle name
// I got the language codes from https://msdn.microsoft.com/en-us/goglobal/bb964664.aspx
switch (lang_id) {
case 1036:
case 2060:
case 3084:
case 4108:
case 5132:
case 6156:
case 7180:
case 8204:
case 9228:
case 10252:
case 11276:
case 12300:
case 13324:
case 14348:
case 15372:
case 58380:
// French
bundle_name = L"Créateur de Carte";
break;
case 1057:
// Indonesian
bundle_name = L"Pencipta Peta";
break;
case 1046:
case 2070:
// Portuguese
bundle_name = L"Criador de Mapas";
break;
case 1034:
case 2058:
case 3082:
case 4106:
case 5130:
case 6154:
case 7178:
case 8202:
case 9226:
case 10250:
case 11274:
case 12298:
case 13322:
case 14346:
case 15370:
case 16394:
case 17418:
case 18442:
case 19466:
case 20490:
case 21514:
case 22538:
// Spanish
bundle_name = L"Creador de Mapas";
break;
default:
bundle_name = L"Map Creator";
}
// log the new bundle name.
char msg2[66]; // 66 I'm sure is big enough
sprintf_s(msg2, 67, "%s%s", "bundle_name is ", bundle_name);
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, msg2);
// append the platform to the end of the bundle name
wchar_t bundle_name_platform[80];
wcscpy_s(bundle_name_platform, bundle_name);
wcscat_s(bundle_name_platform, L" ");
wcscat_s(bundle_name_platform, platform);
// log the final bundle name (which includes the platform)
char msg3[66]; // 66 I'm sure is big enough
sprintf_s(msg3, 67, "%s%s", "bundle_name_platform is ", bundle_name_platform);
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, msg3);
// set the name of our bundle
hr = m_pEngine->SetVariableString(L"WixBundleName", bundle_name_platform);
BalExitOnFailure(hr, "Failed to set WixBundleName variable.");
我正在使用 WiX v3.9 R2 创建我的安装程序。我将安装程序本地化为多种语言,效果很好。但是,无论格式和显示语言设置为什么语言,它始终使用程序和功能中应用程序的英文名称。
如何在“程序和功能”中告诉它为我的应用程序使用本地化名称?
编辑:
澄清一下:我认为我需要的是一种在安装时根据用户语言更改 Bundle 名称属性(或 [WixBundleName])的方法。这可能吗?
否则,人们目前如何使用 WiX Bundle,并最终在程序和功能中本地化程序名称?
编辑 2: 来自 WiX site:
WixBundleName - gets the name of the bundle (from Bundle/@Name). This variable can also be set by the bootstrapper application to modify the bundle name at runtime.
听起来这是可以做到的 - 但是怎么做呢?
编辑 3: 这是我目前的 Bundle,供参考。链中的最后一项是我的申请。
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Bundle Name="Map Creator"
Version="$(var.ProductVersion)"
Manufacturer="FMOsoft"
IconSourceFile="$(var.KarteDir)\assets\logo\ico\icon.ico"
UpgradeCode="[GUID]"
AboutUrl="http://fmosoft.com/MapCreator"
Copyright="Copyright© 2015, FMOsoft">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkSidebarLicense">
<bal:WixStandardBootstrapperApplication
LocalizationFile="$(var.KarteDir)\install\win\L10n\installer\thm_en_us.wxl"
ThemeFile="$(var.KarteDir)\install\win\HyperlinkSidebarTheme_fmosoft.xml"
LogoFile="$(var.KarteDir)\assets\logo\bmp\logo_64.bmp"
LogoSideFile="logoside.bmp"
ShowVersion="yes"
LicenseFile="$(var.KarteDir)\install\license_en.html"
SuppressOptionsUI="yes"
LaunchTarget="[ProgramFiles6432Folder]\FMOsoft\MapCreator\MapCreator.exe"
/>
<!-- WixStdBa requires specific names, at run time, in the temporary .BA1 folder. XML and png file is only needed for layout changes.
Payload/@Name for .wxl must be <lcid>\thm.wxl
Payload/@Name for .xml must be <lcid>\thm.xml AND must also have logo.png in same folder.-->
<Payload Id="theme_en_us" Compressed="yes" Name="1033\thm.wxl" SourceFile="$(var.KarteDir)\install\win\L10n\installer\thm_en_us.wxl"/>
<Payload Id="license_en_us" Compressed="yes" Name="1033\license.html" SourceFile="$(var.KarteDir)\install\license_en.html"/>
<Payload Id="theme_es_es" Compressed="yes" Name="1034\thm.wxl" SourceFile="$(var.KarteDir)\install\win\L10n\installer\thm_es_es.wxl"/>
<Payload Id="license_es_es" Compressed="yes" Name="1034\license.html" SourceFile="$(var.KarteDir)\install\license_es.html"/>
<Payload Id="theme_fr_fr_xml" Compressed="yes" Name="1036\thm.xml" SourceFile="$(var.KarteDir)\install\win\L10n\installer\HyperlinkSidebarTheme_fmosoft_fr.xml"/>
<Payload Id="theme_fr_fr" Compressed="yes" Name="1036\thm.wxl" SourceFile="$(var.KarteDir)\install\win\L10n\installer\thm_fr_fr.wxl"/>
<Payload Id="theme_fr_fr_logo" Compressed="yes" Name="1036\logo.png" SourceFile="$(var.KarteDir)\assets\logo\bmp\logo_64.bmp"/>
<Payload Id="theme_fr_fr_sidelogo" Compressed="yes" Name="1036\logoside.png" SourceFile="$(var.KarteDir)\install\win\logoside.bmp"/>
<Payload Id="license_fr_fr" Compressed="yes" Name="1036\license.html" SourceFile="$(var.KarteDir)\install\license_fr.html"/>
<Payload Id="theme_pt_br" Compressed="yes" Name="1046\thm.wxl" SourceFile="$(var.KarteDir)\install\win\L10n\installer\thm_pt_br.wxl"/>
<Payload Id="license_pt_br" Compressed="yes" Name="1046\license.html" SourceFile="$(var.KarteDir)\install\license_pt.html"/>
<Payload Id="theme_id" Compressed="yes" Name="1057\thm.wxl" SourceFile="$(var.KarteDir)\install\win\L10n\installer\thm_id.wxl"/>
<Payload Id="license_id" Compressed="yes" Name="1057\license.html" SourceFile="$(var.KarteDir)\install\license_id.html"/>
</BootstrapperApplicationRef>
<WixVariable Id="WixStdbaLicenseUrl" Value="license.html" />
<Variable Name="MyProductVersion" Value="$(var.ProductVersion)" />
<!-- There must be a better way to show the localized name of the app in the setup, but this works. -->
<Variable Name="AppName_es" Value="Creador de Mapas"/>
<Variable Name="AppName_fr" Value="Créateur de Carte"/>
<Variable Name="AppName_pt" Value="Criador de Mapas"/>
<Variable Name="AppName_id" Value="Pencipta Peta"/>
<Chain>
<ExePackage SourceFile="vcredist_x64.exe" PerMachine="yes" Permanent="yes" Vital="yes" Compressed="yes" InstallCommand="/quiet /norestart" InstallCondition="VersionNT64"/>
<ExePackage SourceFile="vcredist_x86.exe" PerMachine="yes" Permanent="yes" Vital="yes" Compressed="yes" InstallCommand="/quiet /norestart" InstallCondition="NOT VersionNT64"/>
<PackageGroupRef Id="OldMapEditorPackage"/>
<MsiPackage Vital="yes" SourceFile="$(var.BuildDir)out\map-creator-$(var.Platform).msi" />
</Chain>
</Bundle>
</Wix>
有一个开放的功能请求:http://wixtoolset.org/issues/4045/。此解决方案将允许您提供资源 dll,程序和功能将查询显示名称,因此如果用户更改 OS 语言,它会发生变化。
在有人实施该功能之前,您说得对,这可以通过设置 WixBundleName
变量来完成。如果您正在编写自定义 BA,您将调用 IBootstrapperEngine::SetVariableString
.
如果您使用的是 WixStdBA,则必须使用没有很好记录的 BAFunctions dll 来调用此方法。最近刚刚添加了一个示例项目 here. Note that the WixStdBALanguageId variable,它可以帮助您了解当前的语言是什么。
要添加 BAFunctions.dll,只需将其添加为负载:
<BootstrapperApplicationRef ...>
<Payload Name="BAFunctions.dll" SourceFile="path\to\your.dll" />
</BootstrapperApplicationRef>
如果它有帮助,因为我花了很长时间才弄清楚,这是我本地化 WixBundleName 的方式,所以它在程序和功能中本地化。这是基于 Sean Hall 的回答和评论。
这适用于 WiX 3.10.0.1519 weekly build, built on Thursday, Mar. 19 2015。
/* This document describes how we build bafunctions.dll.
1. Install the version of WiX you want to use. This is necessary because it sets some environment variables or something,
and provides some .h files needed to get the BAFunctions project to compile.
2. Download the wixXX-debug.zip file from the same page where the WiX installer is for the version of WiX you want.
3. Unzip and browse to [wixXX-debug\src\burn\Samples\bafunctions\ and open the project in Visual Studio 2010.
4. In WixBootstrapperBAFunction.cpp, add our code as shown below.
5. Rebuild solution in Release configuration.
6. copy bafunctions\release\bafunctions.dll to Map Creator build machine, [map_creator]\install\win\[Wix_X.X]
*/
// In WixBootstrapperBAFunction.cpp:
// comment out this line (line 32 in WiX 3.10):
STDMETHODIMP OnDetectComplete() { return S_OK; }
/* uncomment the commented-out OnDetectComplete procedure, and in the section marked
// YOUR CODE GOES HERE
add this code:
*/
LONGLONG lang_id = NULL;
LPWSTR bundle_name = NULL;
LPWSTR platform = NULL;
LPWSTR orig_name = NULL;
// get the language the user is using
BalGetNumericVariable(L"WixStdBALanguageId", &lang_id);
BalExitOnFailure(hr, "Failed to get variable 'WixStdBALanguageId'.");
// log the language id
char msg[66]; // 66 I'm sure is big enough
sprintf_s(msg, 67, "%s%d", "WixStdBALanguageId is ", lang_id);
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, msg);
/* I don't know how to pass custom variables from the .wxs, so I tried below to use the built-in HelpTelephone.
That doesn't work either - apparently we can only get variables listed in:
http://wixtoolset.org/documentation/manual/v3/bundle/bundle_built_in_variables.html
BalGetStringVariable(L"WixBundleHelpTelephone", &platform);
BalExitOnFailure(hr, "Failed to get WixBundleHelpTelephone variable.");*/
// Since I don't know how to pass a custom variable from the .wxs, I get the @Name attribute of the Bundle (from the .wxs),
// and I parse out the platform.
BalGetStringVariable(L"WixBundleName", &orig_name);
BalExitOnFailure(hr, "Failed to get WixBundleName variable.");
platform = wcsrchr(orig_name, '(');
// log the platform.
char msg5[66]; // 66 I'm sure is big enough
sprintf_s(msg5, 67, "%s%s", "platform is ", platform);
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, msg5);
// Select the localized bundle name
// I got the language codes from https://msdn.microsoft.com/en-us/goglobal/bb964664.aspx
switch (lang_id) {
case 1036:
case 2060:
case 3084:
case 4108:
case 5132:
case 6156:
case 7180:
case 8204:
case 9228:
case 10252:
case 11276:
case 12300:
case 13324:
case 14348:
case 15372:
case 58380:
// French
bundle_name = L"Créateur de Carte";
break;
case 1057:
// Indonesian
bundle_name = L"Pencipta Peta";
break;
case 1046:
case 2070:
// Portuguese
bundle_name = L"Criador de Mapas";
break;
case 1034:
case 2058:
case 3082:
case 4106:
case 5130:
case 6154:
case 7178:
case 8202:
case 9226:
case 10250:
case 11274:
case 12298:
case 13322:
case 14346:
case 15370:
case 16394:
case 17418:
case 18442:
case 19466:
case 20490:
case 21514:
case 22538:
// Spanish
bundle_name = L"Creador de Mapas";
break;
default:
bundle_name = L"Map Creator";
}
// log the new bundle name.
char msg2[66]; // 66 I'm sure is big enough
sprintf_s(msg2, 67, "%s%s", "bundle_name is ", bundle_name);
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, msg2);
// append the platform to the end of the bundle name
wchar_t bundle_name_platform[80];
wcscpy_s(bundle_name_platform, bundle_name);
wcscat_s(bundle_name_platform, L" ");
wcscat_s(bundle_name_platform, platform);
// log the final bundle name (which includes the platform)
char msg3[66]; // 66 I'm sure is big enough
sprintf_s(msg3, 67, "%s%s", "bundle_name_platform is ", bundle_name_platform);
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, msg3);
// set the name of our bundle
hr = m_pEngine->SetVariableString(L"WixBundleName", bundle_name_platform);
BalExitOnFailure(hr, "Failed to set WixBundleName variable.");