WiX - Jak na instalace, část 3: Lokalizace

Jan Holan       29. 4. 2011       Architektura       7887 zobrazení

V minulé části jsme k instalaci přidali obrazovky a nastavili (natvrdo), aby se zobrazovali v češtině. Nyní toto změníme a vytvoříme instalaci multijazykovou (multi-language MSI), tj. v našem příkladu bude instalace obsahovat anglické a české texty.

MSI balíček jako takový je pouze v jednom jazyku, nicméně MSI systém podporuje transformace MSI balíčku, kterou využijeme na změnu textů v instalaci. Celý postup tvorby takového balíčku s podporou transformace bude následující:

  1. Instalaci ve WiX projektu rozšíříme, aby byla lokalizovatelná, a doplníme české a anglické texty. Tím při buildu instalace ve Visual Studiu vzniknou samostatné dva MSI balíčky, jeden s angličtinou, druhý s češtinou.
  2. Jeden MSI soubor zvolíme jako základní (Base) a na základě porovnáním s druhým vytvoříme transformační soubor (.mst) pro druhý jazyk.
  3. Dalším krokem bude zahrnout tento transformační soubor přímo do MSI souboru.
  4. Posledním krokem bude změna vlastnosti výsledného MSI tak, aby v něm byla uložena informace, že obsahuje oba jazyky, tím se automaticky bude provádět v něm uložená transformace.

Lokalizace instalace

Po projektu přidáme nové soubory lokalizace instalace – wxl, do nich z wxs souboru vytáhneme všechny naše texty, které budeme chtít mít lokalizovatelné. Název souboru je libovolný, ale je dobré, aby v něm bylo uvedeno pro jaký je jazyk (já jsem zvolil jména Strings.cs.wxl a Strings.en.wxl). Zvolíme tedy ve studiu volbu Add/New Item a vytvoříme nový WiX Localization File. Visual Studio nám připraví element WixLocalization, zde je nutné v atributu Culture uvést označení jazyka (language short string – např. en-us, cs-cz), seznam možných hodnot je zde.

První string, který budeme potřebovat pro různé jazyky měnit je vlastní číselný identifikátor jazyka LCID (Locale ID), máme ho uvedený v atributu Language elementu Product. String hodnotu zavedeme v souboru wxl elementem String, tedy konkrétně pro český jazyk takto:

<WixLocalization Culture="cs-cz" xmlns="http://schemas.microsoft.com/wix/2006/localization">
  <String Id="Language" Overridable="yes">1029</String>
</WixLocalization>

a takto pro anglický jazyk:

<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
  <String Id="Language" Overridable="yes">1033</String>  
</WixLocalization>

Odkaz na tuto hodnotu bude !(loc.Language), provedeme tedy změnu elementu Product takto:

<Product Id="9d1087df-cf07-4e86-ada3-ea51be107197" Name="$(var.ProductName)" Language="!(loc.Language)" Codepage="1250"
          Version="$(var.ProductVersion)" Manufacturer="$(var.ManufacturerName)" UpgradeCode="37af4021-842f-4fc4-a3f1-f2e7861e3c21">

Pozn.: Všimneme si ještě také atributu Codepage, mnohdy stačí mít hodnotu nastavenou stejně pro všechny jazyky, pokud ale potřebujeme Codepage v lokalizačním souboru změnit, má na to WiX přímo podporu: hodnotu u elementu nastavíme na 0 a v wxi souboru tento atribut přidáme k elementu WixLocalization.

Nyní dodáme další potřebné texty a zaměníme je v wxs za patřičné odkazy. Výsledek vypadá takto:
Strings.cz.wxi:

<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="cs-cz" Codepage="1250" xmlns="http://schemas.microsoft.com/wix/2006/localization">
  <String Id="Language" Overridable="yes">1029</String>
  <String Id="ProductName">Testovací aplikace</String>
  <String Id="ProductDescription">Testovací aplikace pro WiX setup</String>

  <String Id="DocumentationShortcut" Overridable="yes">Dokumentace Testovací aplikace</String>
  <String Id="DocumentationShortcutDescription" Overridable="yes">Uživatelská dokumentace Test Application</String>
  <String Id="UninstallShortcut" Overridable="yes">Odinstalovat Testovací aplikaci</String>

  <String Id="WelcomeDlgDescription" Overridable="yes">Průvodce instalací nainstaluje do počítače Testovací aplikaci. Pokračujte kliknutím na tlačítko Další, nebo kliknutím na tlačítko Storno Průvodce instalací ukončete.</String>
</WixLocalization>

a změny v souboru Product.wxs:

<Product Id="9d1087df-cf07-4e86-ada3-ea51be107197" Name="!(loc.ProductName)" Language="!(loc.Language)" Codepage="0"
         Version="$(var.ProductVersion)" Manufacturer="$(var.ManufacturerName)" UpgradeCode="37af4021-842f-4fc4-a3f1-f2e7861e3c21">
  ...
  <Property Id='ARPCOMMENTS'>!(loc.ProductDescription)</Property>
  ...
  
  <!--Product components-->
  <Directory Id="TARGETDIR" Name="SourceDir">
    ...
    <Directory Id="ProgramMenuFolder">
      <Directory Id="ApplicationProgramsFolder" Name="$(var.ProductName)">
        <Component Id="ApplicationShortcuts" Guid="6e618011-8885-4dd7-9565-ac2281e36186">
          <RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
          <Shortcut Id="ApplicationStartMenuShortcut" Directory="ApplicationProgramsFolder" Name="!(loc.ProductName)" Description="!(loc.ProductDescription)"
                    Target="[APPLICATIONROOTDIRECTORY]TestApplication.exe" WorkingDirectory="APPLICATIONROOTDIRECTORY" IconIndex="0"/>
          <Shortcut Id="DocumentationStartMenuShortcut" Directory="ApplicationProgramsFolder" Name="!(loc.DocumentationShortcut)" Description="!(loc.DocumentationShortcutDescription)"
                    Target="[APPLICATIONROOTDIRECTORY]Test Application.pdf" WorkingDirectory="APPLICATIONROOTDIRECTORY" IconIndex="0"/>
          <Shortcut Id="ApplicationDesktopShortcut" Directory="DesktopFolder" Name="!(loc.ProductName)" Description="!(loc.ProductDescription)"
                    Target="[APPLICATIONROOTDIRECTORY]TestApplication.exe" WorkingDirectory="APPLICATIONROOTDIRECTORY" IconIndex="0"/>
          <Shortcut Id="UninstallShortcut" Name="!(loc.UninstallShortcut)" Description="!(loc.UninstallShortcut)"
                    Target="[System64Folder]msiexec.exe" Arguments="/x [ProductCode]"
                    Icon="UninstallIcon" IconIndex="0"/>
          <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" KeyPath="yes" />
        </Component>
      </Directory>
    </Directory>
    <Directory Id="DesktopFolder" Name="Desktop" />
  </Directory>
  
  ...
</Product>

Všimněte si dále, že string WelcomeDlgDescription není nikde v souboru wxs uveden, tím totiž měním přímo text použitý v zabudovaném úvodním dialogu na vlastní text. Původní text je definovaný součástí knihovny WixUIExtension.dll s obrazovkami a vypadal takto (je v něm použita záměna [ProductName]):

<String Id="WelcomeDlgDescription" Overridable="yes">Průvodce instalací nainstaluje do počítače produkt [ProductName]. Pokračujte kliknutím na tlačítko Další, nebo kliknutím na tlačítko Storno Průvodce instalací ukončete.</String>

Druhou věcí co je potřeba ještě také zmínit je to, že texty uvedené v atributech elementu Package jsem nelokalizoval. Důvodem je to, že tyto texty (Description, Comments) jsou použity pro informace o instalaci ve vlastnostech přímo souboru MSI, a zde se transformace nespouští, takže jejich překlad je zbytečný. (Překlady by se uplatnili pouze v případě, že by jsme k lokalizaci využívali přímo rozdílné MSI soubory pro dané jazyky a nepoužívali transformační soubory.)

Pro úplnost ještě uvedu soubor Strings.en.wxl:

<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" Codepage="1250" xmlns="http://schemas.microsoft.com/wix/2006/localization">
  <String Id="Language" Overridable="yes">1033</String>
  <String Id="ProductName">Test Application</String>
  <String Id="ProductDescription">WiX setup Test Application</String>

  <String Id="DocumentationShortcut" Overridable="yes">Test Application Documentation</String>
  <String Id="DocumentationShortcutDescription" Overridable="yes">Test Application User Documentation</String>
  <String Id="UninstallShortcut" Overridable="yes">Test Application Uninstall</String>

  <String Id="WelcomeDlgDescription" Overridable="yes">The Setup Wizard will install [ProductName] on your computer. Click Next to continue or Cancel to exit the Setup Wizard.</String>
</WixLocalization>

Pokud jste v části 2 ve vlastnostech projektu nastavili Cultures to build na hodnotou cs-cz, toto nastavení nyní zase zrušte. Po přeložení projektu nyní v adresáři Debug vzniknou MSI soubory dva, Visual Studio totiž volá linkování (Light.exe) tolikrát, kolik lokalizací v projektu najde. Podadresáře jsou nazvané podle jednotlivých jazyků, v našem případě jsou tedy výstupem tyto dva soubory:
cs-cz\TestApplication.msi
en-us\TestApplication.msi

MSI soubory můžete otestovat, uvidíte, že jeden je v češtině včetně změněného textu v úvodní obrazovce, druhý v angličtině. Tím máme hotový bod 1. a nad těmito soubory budeme pokračovat vytvořením transformace.

Vytvoření a zahrnutí transformace do MSI

K dalším bodům nebudeme využívat WiX, ale přímo utility MSI installeru, ten je součástí Microsoft Windows SDK, který musíme nainstalovat, pro Windows 7 je zde. (Konkrétně stačí doinstalovat část Windows Native Code Development/Tools.

My si zvolíme jako hlavní (Base) MSI soubor ten v anglickém jazyce, je to z toho důvodu, že pokud bude instalaci spouštět uživatel, který nemá ani český ani anglický jazyk, bude mu asi bližší angličtina než čeština. Pokud se totiž požadovaný jazyk nenajde, je transformace vynechána a tím bude instalace mít jazyk z base MSI souboru.

Pro vygenerování transformačního souboru mst použijeme utilitu msitran.exe, v našem případě instalace Windows 7 SDK umístěnou v c:\Program Files\Microsoft SDKs\Windows\v7.1\Bin.
Příkaz pro vytvoření transformačního souboru s názvem cs-cz.mst je následující:

"c:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\msitran.exe" -g en-US\TestApplication.msi cs-cz\TestApplication.msi cs-cz.mst

(Na tento krok lze také použít utilitu WiXu s názvem torch.exe.)

Pro vložení transformačního souboru do MSI souboru použijeme program msidb.exe, příkaz bude následující:

"c:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\msidb.exe" -d TestApplication.msi -r cs-cz.mst

(V některých popisech také můžete najít k tomuto kroku použití WiSubStg.vbs scriptu.)

Pokud nyní TestApplication.msi spustíme, bude instalace v anglickém jazyce, pokud bychom chtěli vynutit transformaci, můžeme instalaci spustit následujícím příkazem a instalace se spustí česky:

msiexec /i TestApplication.msi TRANSFORMS=":cs-cz.mst"

(Určení jména transformace s dvojtečkou “:” znamená, odkaz na transformaci v MSI souboru, bez dvojtečky by se hledal externí soubor mst.)

Voláním s parametrem určující patřičnou transformaci se někdy v instalacích také využívá, např. pokud program setup.exe, kterým se taková instalace spouští, nejprve zobrazí výběr jazyka a uživatel si jazyk sám zvolí. My ale žádný takový program nemáme, a proto celý postup ještě trochu upravíme tak, aby byl jazyk vybrán automaticky při spuštění přímo MSI souboru (*). K tomu aby automatická transformace fungovala musejí být splněny následující podmínky:

  • Transformace se v MSI souboru musejí jmenovat číslem LCID (Locale ID) a to i bez přípony mst, tedy např. 1029 (čeština) nebo 1033 (angličtina).
  • Vlastnost Languages celého MSI balíku (nikoli Produktu) musí být nastavena na seznam LCID všech jazyků, který balík včetně transformací obsahuje, odděleny bez mezery čárkou, v našem případě tady “1033,1029” (první musí být jazyk, který je v base MSI).

Toto nastavení provedeme programem msiinfo.exe následujícím příkazem:

"c:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\msiinfo.exe" TestApplication.msi /p Intel;1033,1029

(V některých popisech se k tomuto používá script WiLangId.vbs.)

Abychom proces buildu zautomatizovali, využijeme v nastavení projektu ve Visual Studiu sekvenci Post-build Event Command Line, do které celé volání výše popsaných příkazů umístíme. Výsledek, který budeme při buildu volat, vypadá takto:

copy en-US\TestApplication.msi TestApplication.msi /Y
"c:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\msitran.exe" -g en-US\TestApplication.msi cs-cz\TestApplication.msi 1029
"c:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\msidb.exe" -d TestApplication.msi -r 1029

"c:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\msiinfo.exe" TestApplication.msi /p Intel;1033,1029 /t "Test Application"
del 1029
rd cs-cz /S /Q
rd en-us /S /Q

Všimněte si ještě těchto věcí:
Protože potřebujeme, aby se transformace jmenovala “1029", ale program msidb nastaví jméno transformace přímo podle jména transformačního souboru, musíme ho pod tímto názvem vytvořit (už ve volání msitran).
Při volání msiinfo kromě languages nastavujeme ještě parametrem /t titulek MSI souboru (ten nelze určit ve WiX XML souborech) (**).
Na konci provedeme odstranění již nepotřebných souborů.

Po zkompilování projektu vznikne výsledný soubor TestApplication.msi zase zpátky přímo v adresáři Debug. A jak že výsledek funguje? Po spuštění se při nastavené české kultury zobrazí instalace česky, při nastavení jiné je instalace spuštěna anglicky. (Instalace reaguje na nastavení Formát v Control Panel/Region and Language).

SetupRegionAndLanguageSettings

Na závěr této části ještě pár poznámek:
-Uvedený postup se samozřejmě dá rozšířit i na vytvoření více jazyků než dvou tj. jeden MSI balíček, který bude obsahovat více transformačních souborů.

-Hodnotu languages MSI souboru (kterou my nastavujeme pomoci msiinfo na “1033,1029”) umožňuje nastavit i přímo WiX atributem Languages v elementu Package. Důvod proč to přes WiX neděláme jsou dva, zaprvé by se nám toto nastavení nehodilo pokud bychom využívali původní vytvořené samostatné MSI, a proto je obecnější hodnotu ve WiX neuvádět. A zadruhé, pokud jsem hodnotu nastavil, WiX my zcela nepochopitelně nahlásil chybu:
Failed to open merge module for validation. The most common cause of this error is specifying that the merge module supports multiple languages (using the Package/@Languages attribute) but not including language-specific embedded transforms.
Proto moje doporučení je hodnotu atributu Language ve WiX kódu neuvádět a doplnit jí, až dodatečně, až když je teprve opravdu potřeba (ztratil jsem na tom den, než mě napadlo hodnotu odstranit).

V další části se podíváme jak postupovat při úpravě nebo vytváření vlastních obrazovek instalace.

Některé odkazy zdrojů:
http://wix.sourceforge.net/manual-wix3/build_a_localized_version.htm
http://www.codeproject.com/KB/install/WixWindowsInstallerDemo3.aspx
http://www.tramontana.co.hu/wix/lesson9.php
http://www.installsite.org/pages/en/msi/articles/embeddedlang/index.htm
http://www.geektieguy.com/2010/03/13/create-a-multi-lingual-multi-language-msi-using-wix-and-custom-build-scripts


(*) Tato vlastnost automatické transformace MSI není oficiálně podporovaná Microsoftem, přesto je ale velmi často využívána.

(**) Pokud bychom titulek potřebovali s českými znaky a volání msiinfo bychom prováděli v .bat souboru, je nutné ještě před ním volat příkaz “chcp 1250” pro nastavení příslušné kódové stránky.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

RE: WiX - Jak na instalace, část 3: Lokalizace

Ještě upozorním na jeden problém, na který můžete narazit při tvorbě multijazyčné WiX instalace.

Předpokládejme, že potřebujeme v závislosti na použitém jazyku instalace nainstalovat rozdílný soubor (např. nějaký config soubor, který by obsahoval rozdílné nastavení kultury).

Zde narazíme na problém, protože nelze udělat podmínku podle lokalizační proměnné, např. podmínka:

<?if !(loc.Language) = 1033 ?>

nefunguje.

Dále také nelze nastavit Source z lokalizačního stringu např.:

<Component Id="Config.ini">

<File Id="Config.ini" Name="Config.ini" ShortName="Config.ini" Source="!(loc.ConfigIni)" />

</Component>

Při nastavení lokalizačního stringu ConfigIni na různé zdrojové soubory, to způsobí, že jednotlivá MSI tj. cs-cz\produkt.msi a en-US\produkt.msi budou správně obsahovat rozdílné soubory. Pokud ale z nich provedeme transformace, tyto rozdílné soubory se do nich nezahrnují, a soubor zůstane ten, podle výchozího MSI a transformace ho nezmění.

Toto řešení by se tedy dalo použít tak, že by instalace obsahovala rozdílná MSI pro rozdílné jazyky a nějaký setup.exe by volal patřičný z nich.

Jiné řešení by bylo kopírovat soubor pomoci custom akce. Např. akce vytvořená v C# by mohla buď vytáhnout jazyk z MSI vlastnosti culture, nebo přímo podle nastavení Systém.Globalization.CultureInfo a na základě toho provést kopírování nebo vytvoření konfiguračního souboru.

A ještě konkrétně pro INI soubory, je možné provést v instalaci přímo zápis potřebného nastavení v souboru pomoci akce IniFile, kde můžeme hodnotu Value dosadit z lokalizační promenné.

Např.:

<Component Id="cmpConfigIni" Guid="94bc2173-822f-6ac3-a5c1-e7e2853e2023"

Permanent="yes" NeverOverwrite="yes" KeyPath="yes">

<File Id="filConfigIni" Source="$(var.SourceSupportWixDir)Config.ini"/>

<IniFile Id="filConfigIni" Directory="INSTALLDIR" Name="Config.ini"

Section="Debug" Key="Locale" Value="!(loc.IniLocale)" Action="addLine"/>

</Component>

Tímto se nainstaluje soubor Config.ini, který obsahuje pouze jazykově nezávislé nastavení, a následně se do jeho sekce Debug zapíše rozdílná hodnota Locale podle jazyka instalace.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback