-
Notifications
You must be signed in to change notification settings - Fork 176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MSI language #1497
Comments
You can do it very easily by changing the language and calling project.Language = "en-US";
project.BuildMsi($"setup.{project.Language}.msi");
project.Language = "fr-FR";
project.BuildMsi($"setup.{project.Language}.msi"); If you want to use custom wxl files you can set them too: project.LocalizationFile = @".\languages\custom_de-de.wxl"; |
I'm trying to do this: project.Name = "!(loc.ApplicationName)"; But I get errors:
I want to set a name based on language otherwise I can directly set the name and not use wxl file. |
It's not how WixSharp works but you can achieve the desired outcome by simply reading the app name with C# from the wxl file: project.Name = XDocument.Load(project.LocalizationFile)
.FindAll("String")
.First(x => x.HasAttribute("Id", "ApplicationName"))
.Attr("Value"); And I just added a new more convenient extension method that embeds the code above. Thus from the next release you will be able to do it even as simple as below: project.Name = project.LocalizationFile.GetLocalizedString("ApplicationName"); |
One last question which is somewhat related. How can we retrieve the ApplicationName variable to display the correct translation in the interface. I want to replace "MESSAGE fr-FR or en-US" with "ApplicationName" variable which comes from the wxl file static void Msi_UIInitialized(SetupEventArgs e)
{
//MessageBox.Show(e.ToString(), "UIInitialized");
e.ManagedUI.Shell.CustomErrorDescription = "MESSAGE fr-FR or en-US";
e.ManagedUI.Shell.ErrorDetected = true;
e.Result = ActionResult.UserExit;
} |
It's good I found. static void Msi_UIInitialized(SetupEventArgs e)
{
//MessageBox.Show(e.ToString(), "UIInitialized");
MsiRuntime runtime = e.ManagedUI.Shell.MsiRuntime();
e.ManagedUI.Shell.CustomErrorDescription = runtime.UIText["ApplicationName"];
e.ManagedUI.Shell.ErrorDetected = true;
e.Result = ActionResult.UserExit;
} |
static void Msi_UIInitialized(SetupEventArgs e)
{
MsiRuntime runtime = e.ManagedUI.Shell.MsiRuntime();
// at this point `runtime` is initialized with the appropriate wxl so you do not need to decide
// as in "<String Id="CustomError" Overridable="yes" Value="MyCustom Error"></String>"
e.ManagedUI.Shell.CustomErrorDescription = runtime.Localize("CustomError");
e.ManagedUI.Shell.ErrorDetected = true;
e.Result = ActionResult.UserExit;
} |
Yep, the same thing :) |
Is it possible to chain the variables like this: <WixLocalization Culture="en-US" Codepage="1252" xmlns="http://wixtoolset.org/schemas/v4/wxl">
<String Id="Name" Value="Application test"></String>
<String Id="ApplicationName" Value="MyProduct - !(loc.Name)"></String>
</WixLocalization> ApplicationName => "MyProduct - Application test" Or should I do this: <WixLocalization Culture="en-US" Codepage="1252" xmlns="http://wixtoolset.org/schemas/v4/wxl">
<String Id="Name" Value="Application test"></String>
<String Id="ApplicationName" Value="MyProduct - Application test"></String>
</WixLocalization> I know that in Wix it is possible but in WixSharp, I don't know. |
There are two use-cases for that: Formatted localization with the dynamic template (C# string): var msg = "[ProductName] Setup".LocalizeWith(runtime.Localize);
MessageBox.Show(msg, "1"); With the product name being either MSI property or a string from the language file. And "[ProductName] Setup" is your template. BTW Another use-case is the template in the language file. Every entry there can reference another entry from the same language file by enclosing the entry Id in the square brackets: And now you can use it like this: msg = "[CustomError]".LocalizeWith(runtime.Localize);
MessageBox.Show(msg, "2"); |
Great, thank you @oleg-shilo |
I encounter another problem, I want to have 2 identical products with the same guid, but when I do this: static void Main()
{
var project = new ManagedProject("MyProduct",
new Dir(@"%AppData%\My Company\My Product",
new File("Program.cs")));
project.GUID = new Guid("6fe30b47-2577-43ad-9095-1861ba25889b");
project.ManagedUI = ManagedUI.DefaultWpf;
project.Language = "fr-FR";
project.LocalizationFile = $@".\languages\custom_{project.Language}.wxl";
project.Name = $"Test-{language}";
project.BuildMsi($"{project.Name}.msi");
project.Language = "en-US";
project.LocalizationFile = $@".\languages\custom_{project.Language}.wxl";
project.Name = $"Test-{language}";
project.BuildMsi($"{project.Name}.msi");
} It doesn't compile and tells me this: I think it doesn't save the :
Because project name is redefined in : So I tried to create two ManagedProject : static void Main()
{
Generate("en-US");
Generate("fr-FR");
}
static void Generate(string language)
{
var project = new ManagedProject("MyProduct",
new Dir(@"%AppData%\My Company\My Product",
new File("Program.cs")));
project.GUID = new Guid("6fe30b47-2577-43ad-9095-1861ba25889b");
project.ManagedUI = ManagedUI.DefaultWpf;
project.Language = language;
project.LocalizationFile = $@".\languages\custom_{project.Language}.wxl";
project.Name = $"Test-{language}";
project.BuildMsi($"{project.Name}.msi");
} This works, it generates the two msi outputs :
The problem is found when executing the msi. For example I launch the msi: "en-US", everything is fine it installs it but subsequently if I launch the msi "fr-FR", I would like it to open the maintenance interface because it is the same product. Currently it shows me this: |
hallo, i had same issue with my standard language en-US msi. It happens, because you dont have set MajorUpdateStrategy. Just set it default . Should work after recreate msi new with newer version. |
I still get the same error adding this: project.MajorUpgradeStrategy = MajorUpgradeStrategy.Default; What I want is to have 2 msi, one in French and one in English that I install one or the other I want it to be the same product (they have the same version). It's just the name of the product that changes. |
import is codeline in sample : static void RunAsBA()
{
// Debug.Assert(false);
// A poor-man BA. Provided only as an example for showing how to let user select the language and run the corresponding localized msi.
// BuildMsiWithLanguageSelectionBootstrapper with a true BA is a better choice but currently WiX4 has a defect preventing
// showing msi internal UI from teh custom BA.
ConsoleHelper.HideConsoleWindow();
var msiFile = io.Path.GetFullPath("MyProduct.msi");
try
{
var installed = AppSearch.IsProductInstalled("{6fe30b47-2577-43ad-9095-1861ca25889c}");
if (installed)
{
Process.Start("msiexec", $"/x \"{msiFile}\"");
}
else
{
var view = new MainView();
if (view.ShowDialog() == true)
{
if (view.SupportedLanguages.FirstOrDefault().LCID == view.SelectedLanguage.LCID) // default language
Process.Start("msiexec", $"/i \"{msiFile}\"");
else
Process.Start("msiexec", $"/i \"{msiFile}\" TRANSFORMS=:{view.SelectedLanguage.LCID}");
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
} |
Neverind... It looks like @Torchok19081986 is handling it well :) |
ähm.. I got several similar problem / issues. I tested it, got info from example and could find out, how to deal with it. MSI Package is quit easier than BA Installer. BUT here you has best oppotunity to build cusom Installer, where you can build alwost everthing. Need some time and practice. That all. Just Changes by Wix Team or there breaking changes , i dont handle it immediatly. Just use Wix Toolset self and Wix# and practice, practice, practice. |
merge is paramter, just do remove it, second parameter is boolean, which is true. You dont need merge as variable. |
When I do "Go to Definition" in visual studio : #region assembly WixSharp.UI, Version=2.1.5.0, Culture=neutral, PublicKeyToken=3775edd25acc43c2
// emplacement inconnu
// Decompiled with ICSharpCode.Decompiler 8.1.1.7464
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace WixSharp;
//
// Résumé :
// Localization map. It is nothing else but a specialized version of a generic string-to-string
// Dictionary.
public class ResourcesData : Dictionary<string, string>
{
//
// Résumé :
// Gets or sets the value associated with the specified key.
//
// Paramètres :
// key:
// The key.
public new string this[string key]
{
get
{
if (!ContainsKey(key))
{
return null;
}
return base[key];
}
set
{
base[key] = value;
}
}
//
// Résumé :
// Initializes from WiX localization data (*.wxl).
//
// Paramètres :
// wxlData:
// The WXL file bytes.
public void InitFromWxl(byte[] wxlData)
{
Clear();
if (wxlData == null || !wxlData.Any())
{
return;
}
string tempFileName = Path.GetTempFileName();
XDocument xDocument;
try
{
System.IO.File.WriteAllBytes(tempFileName, wxlData);
xDocument = XDocument.Load(tempFileName);
}
catch
{
throw new Exception("The localization XML data is in invalid format.");
}
finally
{
System.IO.File.Delete(tempFileName);
}
Func<XElement, string> elementSelector = (XElement element) => element.GetAttribute("Value") ?? element.Value;
foreach (KeyValuePair<string, string> item in (from x in xDocument.Descendants()
where x.Name.LocalName == "String"
select x).ToDictionary((XElement x) => x.Attribute("Id").Value, elementSelector))
{
Add(item.Key, item.Value);
}
}
}
#if false // Journal de décompilation
'34' éléments dans le cache
------------------
Résoudre : 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Un seul assembly trouvé : 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Charger à partir de : 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\mscorlib.dll'
------------------
Résoudre : 'WixToolset.Mba.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=a7d136314861246c'
Un seul assembly trouvé : 'WixToolset.Mba.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=a7d136314861246c'
Charger à partir de : 'C:\Users\A.MINET\.nuget\packages\wixtoolset.mba.core\4.0.1\lib\net20\WixToolset.Mba.Core.dll'
------------------
Résoudre : 'WixSharp, Version=2.1.5.0, Culture=neutral, PublicKeyToken=3775edd25acc43c2'
Un seul assembly trouvé : 'WixSharp, Version=2.1.5.0, Culture=neutral, PublicKeyToken=3775edd25acc43c2'
Charger à partir de : 'C:\Users\A.MINET\.nuget\packages\wixsharp_wix4.bin\2.1.5\lib\WixSharp.dll'
------------------
Résoudre : 'System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Un seul assembly trouvé : 'System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Charger à partir de : 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Xml.Linq.dll'
------------------
Résoudre : 'WixToolset.Dtf.WindowsInstaller, Version=4.0.0.0, Culture=neutral, PublicKeyToken=a7d136314861246c'
Un seul assembly trouvé : 'WixToolset.Dtf.WindowsInstaller, Version=4.0.0.0, Culture=neutral, PublicKeyToken=a7d136314861246c'
Charger à partir de : 'C:\Users\A.MINET\.nuget\packages\wixtoolset.dtf.windowsinstaller\4.0.1\lib\net20\WixToolset.Dtf.WindowsInstaller.dll'
------------------
Résoudre : 'System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Un seul assembly trouvé : 'System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Charger à partir de : 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Drawing.dll'
------------------
Résoudre : 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Un seul assembly trouvé : 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Charger à partir de : 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.dll'
------------------
Résoudre : 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Un seul assembly trouvé : 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Charger à partir de : 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Windows.Forms.dll'
------------------
Résoudre : 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Un seul assembly trouvé : 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Charger à partir de : 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Core.dll'
------------------
Résoudre : 'System.IO.Compression.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Un seul assembly trouvé : 'System.IO.Compression.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Charger à partir de : 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.IO.Compression.FileSystem.dll'
#endif
``` |
Let me check the package in case it was a packaging problem. |
Ah... all good. The change to the new signature was done for WiX3 stream and has not yet propagated to WiX4 stream of work. |
No work : project.AddBinary(new Binary(new Id("de_xsl"), @"WixUI_de-DE.wxl"))
.AddBinary(new Binary(new Id("gr_xsl"), @"WixUI_el-GR.wxl")); Work : project.AddBinary(new Binary(new Id("de_xsl"), @"CycleScroller\WixSharp Setup1 WPF UI\WixUI_de-DE.wxl"))
.AddBinary(new Binary(new Id("gr_xsl"), @"CycleScroller\WixSharp Setup1 WPF UI\WixUI_el-GR.wxl")); |
The file path is relative to the "working dir". If you used VS template then it is where the project file is. You an always check it by putting in the script file: Console.WriteLine(Environment.CurrentDirectory); |
You can also overwrite this mechanism by providing a new root directory: |
Ah yes indeed, the problem came from here: project.SourceBaseDir = @"..\..\"; I'm closing the topic for now, thank you both again for your help ;) |
- #1503: %AppData% folder no replace by path wix4 - #1493: Question : Make Wix# Wix Toolset v5 compatible - #1491: How to set title and description for CustomDialogWith<T> - #1310: Problem during dynamic localization - Enhancement #1497: MSI language - Improved algorithm for locating compatible version of installed WiX extension file. - Added extension method for reading localized strings from wxl files: `product.LocalizationFile.GetLocalizedString("ProductName")`</releaseNotes>
Hi,
Need help with MSI language !
In Wix, it is possible to define languages:
And then we can create different language files :
fr-FR.wxl file :
en-US.wxl file :
Product.wxs file :
And this generates 2 msi output.
How can I do the same thing with wixsharp?
The text was updated successfully, but these errors were encountered: