Why would MST not include files with different content

十年热恋 提交于 2019-12-07 23:55:59

问题


Trying to make a multilingual installer - the process is working in general, but seems to be failing for localised files that are to be installed.

Each of the localised installers works fine as a standalone and installs the localised files like the eula.pdf.

I'm hoping that I'm just missing a flag on the transform generation step (or maybe using the wrong tool?)

Process being to start by having a bunch of installers 1 for each language.

To build each installer we are 'lighting' using -b "folder" and -loc "folder" option to specify each language which includes some alternate file content such as the licence.pdf.

The files to be localised have a common source name

<File Id='License.pdf' Name='eula.pdf' Source='License(EULA).pdf' KeyPath='yes'/>
<WixVariable Id="WixUILicenseRtf" Value="License.rtf" />

Folders for example being

en-US/License(EULA).pdf
en-US/License.rtf
en-US/Product.wxl
fr-FR/License(EULA).pdf
fr-FR/License.rtf
fr-FR/Product.wxl

There are also some files such as binary.dll and binary.exe which are not localised and are the same for all msi - don't expect to see them in MST.

Following the next step in the process is creating an MST diff between a base language (english) and each of the other languages. Using Windows\v7.1\Bin\MsiTran.exe from the Window SDK

The MST seem a bit small for the change in content.

Merging all the MST files into a single installer using the Windows\v7.1\Samples\sysmgmt\msi\scripts\wisubstg.vbs

Installing in a language other than english shows the whole installer UI including rtf version of the licence as being localised, but the eula.pdf on disk is always the base english.

Using the Ant-dotnet tasks to run the build (in case it makes a difference) The msi build task

    <wix mode="light" target="${outlocation}\${lang.folder}\my.msi" wixHome="${wixhome}">
        <lightArg line="-b &quot;${location}&quot;"/> <!-- provide the location of the signable binaries -->
        <lightArg line="-b &quot;${msiwixsource}\Localisation\${lang.folder}&quot;"/> <!-- provide the location of the localisation -->
        <lightArg line="-sice:ICE57"/>
        <lightArg line="-cultures:${lang.culture}"/>
        <lightArg line="-loc &quot;${msiwixsource}\Localisation\${lang.folder}\Product.wxl&quot;"/>
        <lightArg line="-ext &quot;${wixhome}\WixUtilExtension.dll&quot;"/>
        <lightArg line="-ext &quot;${wixhome}\WixUIExtension.dll&quot;"/>
        <lightArg line="-ext &quot;${wixhome}\WixFirewallExtension.dll&quot;"/>
        <lightArg line="-ext &quot;${wixhome}\WixNetFxExtension.dll&quot;"/>
        <sources dir="${msiwixobjects}">
          <include name="*.wixobj"/>
        </sources>
        <moresources dir="${msiwixsource}\Localisation\${lang.folder}">
          <include name="*"/>
        </moresources>
        <moresources dir="${location}">
          <include name="binary.dll,binary.exe"/>
        </moresources>
    </wix>

The transform task

    <exec executable="${windowsSDKBin}">
        <arg value="-g"/>
        <arg value="${outlocation}\en-US\my.msi"/>
        <arg value="${outlocation}\${lang.folder}\my.msi"/>
        <arg value="${outlocation}\${lang.folder}\my.mst"/>
    </exec>

The repack task

    <exec executable="cscript">
        <arg value="${windowsSDKMsi}"/>
        <arg value="${outlocation}\my.msi"/>
        <arg value="${outlocation}\${lang.folder}\my.mst"/>
        <arg value="${lang.id}"/>
    </exec>

Product/@Language="!(loc.Lang)" specified in Product.wxl for English base we listed all 1033,1028,1029,1031,1036,1040,1041,1043,1045,1046,2052,3082 for other languages just the specific such as 1036 for fr-FR


回答1:


Ok, so after a couple of days of searching I found an article that describes the issue. How To Localize the Setup GUI and Deliver Localized Files Using a MST.

The issue being that MST doesn't include '_Streams' table elements which is where the CAB files are stored.

You could go several ways from that -

1) make multiple file & component entries for the different languages with conditional inclusion based on language or culture

This means changing your wxs if you want to change which languages are supported.

<Component Directory="INSTALLDIR" Id='EULADoc' Guid='***'>
  <Condition><![CDATA[(ProductLanguage = "1033")]]></Condition>
  <File Id='License.pdf' Name='!(loc.EULA)' Source='en-US\License(EULA).pdf' KeyPath='yes'/>
</Component>
<Component Directory="INSTALLDIR" Id='EULADoc' Guid='***'>
  <Condition><![CDATA[(ProductLanguage = "1046")]]></Condition>
  <File Id='License.pdf' Name='!(loc.EULA)' Source='pt-BR\License(EULA).pdf' KeyPath='yes'/>
</Component>
... add a new block each time you add a language, changes to files have to be duplicated for every block.

Which in turn means recompiling instead of just relinking the wxl. You still need to repack the mst files.

2) manually adjust the localised MSI

As per the How To Localize the Setup GUI and Deliver Localized Files Using a MST.

3) automated split the localised items into a seperate CAB with a localised name

Rather than recompile this is then relinking and extra process for managing the CAB files. Extra process to - * extract the CAB file(s) along with generating the mst,
* then when merging the mst also add the cab files.

Add an extra media which has a localised name - I'm using the lang id as it is convenient

<Media Id="2" Cabinet="localised_!(loc.LANG).cab" EmbedCab="yes" />

Change the localised files/components to come from the new media

<Component Directory="INSTALLDIR" Id='EULADoc' Guid='***' DiskId='2'>
  <File Id='License.pdf' Name='!(loc.EULA)' Source='License(EULA).pdf' KeyPath='yes'/>
</Component>

When generating the transforms using MSITran.exe also export the localised CAB files using MsiDb.Exe When merging the transforms into the base MSI using WiSubStg.vbs also add the CAB files to the _Streams using WiStram.vbs

I've gone with option 3 I hope somebody else finds this useful. Note:

  • I don't write alot of ANT so feel free to offer suggestions
  • we build an unsigned for testing and signed version for release so need to adjust the input/output locations to find binaries and msi.

and the ant build looks something like the following.

<taskdef resource="net/sf/antcontrib/antcontrib.properties" classpathref="buildjars"/>
<taskdef name="for" classname="net.sf.antcontrib.logic.ForTask" classpathref="buildjars"/> 
<taskdef name="wix" classname="org.apache.ant.dotnet.wix.WixTask" classpathref="buildjars"/>

<property name="wixhome" value="C:\Program Files (x86)\Windows Installer XML v3.5\bin"/>

<property name="binarieslocation" value="build"/>
<property name="msiwixsource" value="install"/>
<property name="msiwixobjects" value="${msiwixsource}\obj\x64\Release"/>
<!-- <dirname property="windowsSDK" file="C:\Program Files\Microsoft SDKs\Windows\v7.1\"/> Ant doesn't like path segments with . -->
<property name="windowsSDKBin" location="C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\MsiTran.exe"/>
<property name="windowsSDKCab" location="C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\MsiDb.Exe"/>
<property name="windowsSDKMsiStorage" location="C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\sysmgmt\msi\scripts\WiSubStg.vbs"/>
<property name="windowsSDKMsiStream" location="C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\sysmgmt\msi\scripts\WiStream.vbs"/>
<property name="windowsSDKMsiLanguages" location="C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\sysmgmt\msi\scripts\WiLangId.vbs"/>  

<property name="cultureBase" value="en-US:en-US:1033"/>
<property name="cultures" value="pt-BR:pt-BR:1046,cs-CZ:en-US:1029"/> 

<target name="installer">
    <echo>Building ${culture} msi using binaries in "${location}"...</echo>
    <propertyregex property="lang.folder" input="${culture}" regexp="(.*):(.*):(.*)" select="\1"/>
    <propertyregex property="lang.culture" input="${culture}" regexp="(.*):(.*):(.*)" select="\2"/>

<wix mode="light" target="${outlocation}\${lang.folder}\my.msi" wixHome="${wixhome}">
    <lightArg line="-b &quot;${location}&quot;"/> <!-- provide the location of the signable binaries -->
    <lightArg line="-b &quot;${msiwixsource}\Localisation\${lang.folder}&quot;"/> <!-- provide the location of the localisation -->
    <lightArg line="-sice:ICE57"/>
    <lightArg line="-cultures:${lang.culture}"/>
    <lightArg line="-loc &quot;${msiwixsource}\Localisation\${lang.folder}\Product.wxl&quot;"/>
    <lightArg line="-ext &quot;${wixhome}\WixUtilExtension.dll&quot;"/>
    <lightArg line="-ext &quot;${wixhome}\WixUIExtension.dll&quot;"/>
    <sources dir="${msiwixobjects}">
      <include name="*.wixobj"/>
    </sources>
    <moresources dir="${msiwixsource}\Localisation\${lang.folder}">
      <include name="*"/>
    </moresources>
    <moresources dir="${location}">
      <include name="binary.dll,binary.exe"/>
    </moresources>
</wix>

</target>

<target name="checkTransform" depends="installer">
    <uptodate property="transform.notRequired" targetfile="${outlocation}\${culture}\my.mst" >
        <srcfiles dir= "${outlocation}\en-US\" includes="my.msi"/>
        <srcfiles dir= "${outlocation}\${lang.culture}\" includes="my.msi"/>
    </uptodate>
</target>

<target name="transform" depends="checkTransform" unless="transform.notRequired">
    <echo>Building ${culture} mst ...</echo>
    <propertyregex property="lang.folder" input="${culture}" regexp="(.*):(.*):(.*)" select="\1"/>
    <propertyregex property="lang.id" input="${culture}" regexp="(.*):(.*):(.*)" select="\3"/> 

    <!-- Generate the mst 'diff' file - this does not include exporting the language specific cab file to match -->
    <exec executable="${windowsSDKBin}">
        <arg value="-g"/>
        <arg value="${outlocation}\en-US\my.msi"/>
        <arg value="${outlocation}\${lang.folder}\my.msi"/>
        <arg value="${outlocation}\${lang.folder}\my.mst"/>
    </exec>

    <!-- Exporting the language specific cab file to match -->
    <delete file="localised_${lang.id}.cab" />
    <delete file="${outlocation}\${lang.folder}\localised_${lang.id}.cab" />
    <exec executable="${windowsSDKCab}">
        <arg value="-d"/>
        <arg value="${outlocation}\${lang.folder}\my.msi"/>
        <arg value="-x"/>
        <arg value="localised_${lang.id}.cab"/>
    </exec>
    <move file="localised_${lang.id}.cab" tofile="${outlocation}\${lang.folder}\localised_${lang.id}.cab"/>
</target>

<!-- Target to build MSIs using unsigned binaries -->
<target name="MSIs">
    <!-- we always need english as it is the base multilingual -->
    <antcall target="installer">
        <param name="culture" value="${cultureBase}" />
        <param name="location" value="${location}" />
        <param name="outlocation" value="${outlocation}" />
    </antcall>
    <!-- build the different cultures and make transforms 
    parallel="true" sometimes fails-->
    <for list="${cultures}" param="culture" >
      <sequential>
        <antcall target="transform">
            <param name="culture" value="@{culture}" />
            <param name="location" value="${location}" />
            <param name="outlocation" value="${outlocation}" />
        </antcall>
      </sequential>
    </for>
</target>

<!-- depends="transform" -->
<target name="transformRepack" >
    <echo>Packing ${culture} mst into multilingual installer...</echo>
    <propertyregex property="lang.folder" input="${culture}" regexp="(.*):(.*):(.*)" select="\1"/>
    <propertyregex property="lang.id" input="${culture}" regexp="(.*):(.*):(.*)" select="\3"/> 

    <exec executable="cscript">
        <arg value="${windowsSDKMsiStream}"/>
        <arg value="${outlocation}\my.msi"/>
        <arg value="${outlocation}\${lang.folder}\localised_${lang.id}.cab"/>
        <arg value="localised_${lang.id}.cab"/>
    </exec> 
    <exec executable="cscript">
        <arg value="${windowsSDKMsiStorage}"/>
        <arg value="${outlocation}\my.msi"/>
        <arg value="${outlocation}\${lang.folder}\my.mst"/>
        <arg value="${lang.id}"/>
    </exec>
</target>

<target name="MSIMulti" depends="MSIs">
    <echo>Making multilingual installer...</echo>

    <copy file="${outlocation}\en-US\my.msi" todir="${outlocation}"/>

    <for list="${cultures}" param="culture">
      <sequential>
        <antcall target="transformRepack">
            <param name="culture" value="@{culture}" />
            <param name="location" value="${location}" />
            <param name="outlocation" value="${outlocation}" />
        </antcall>
      </sequential>
    </for>
    <!-- report what was packed -->
    <propertyregex property="lang.ids" input="${cultures}" regexp="([^:,]*):([^:]*):([^,]*)" replace="\3" global="true" defaultvalue="failed"/> 
    <echo/>
    <echo>Multilingual installer should include transform language ids </echo>
    <echo>${lang.ids}</echo>
    <echo>Multilingual installer reports transform language ids...</echo>
    <exec executable="cscript">
        <arg value="${windowsSDKMsiStorage}"/>
        <arg value="${outlocation}\my.msi"/>
    </exec>
    <exec executable="cscript">
        <arg value="${windowsSDKMsiLanguages}"/>
        <arg value="${outlocation}\my.msi"/>
        <arg value="Package"/>
        <arg value="1033,${lang.ids}"/>
    </exec>
</target>

<target name="UnsignedMSIMulti" >
    <antcall target="MSIMulti">
        <param name="location" value="${binarieslocation}" />
        <param name="outlocation" value="${binarieslocation}" />
    </antcall>
</target>


来源:https://stackoverflow.com/questions/7424221/why-would-mst-not-include-files-with-different-content

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!