oleg-shilo / wixsharp

Framework for building a complete MSI or WiX source code by using script files written with C# syntax.
MIT License
1.12k stars 175 forks source link

Some strings in Dialogs from .wxl are not replaced in Custom WPF UI #1604

Closed kipamgs closed 1 month ago

kipamgs commented 3 months ago

Nuget: WixSharp-wix4.WPF Version 2.3.1 (Also happens in earlier versions) Project was created with the WixSharp Managed Setup - Custom WPF UI (WiX4)template.

As you can see in the image below not all strings are replaced with their value. The only of my custom values that is replaced is the lower left "Test Connection" button but all of them are defined in the same wxl file.

For now I can do a workaround and add DatabaseURLHint.Text = _session?.Format(Host?.MsiRuntime().UIText["UIDatabaseURLHint"]); for all strings to the Init function of the dialog but it would be nice to find the cause of this problem.

I'm merging the wxl file with the existing english one with runtime.UIText.InitFromWxl(e.Session.ReadBinary(lang_file), true);.

image

.wxl:

<!--
  <copyright file="WixUI_de-de.wxl" company="Outercurve Foundation">
    Copyright (c) 2004, Outercurve Foundation.
    This software is released under Microsoft Reciprocal License (MS-RL).
    The license and further copyright text can be found in the file
    LICENSE.TXT at the root directory of the distribution.
  </copyright>
-->
<WixLocalization Culture="en-us" Codepage="1252" xmlns="http://wixtoolset.org/schemas/v4/wxl">
  <!-- _locID@Culture="en-US" _locComment="American English" -->
  <!-- _locID@Codepage="1252" _locComment="Windows-1252" -->
  <String Id="UITestConnection" Value="Test connection"></String>
  <String Id="UIDatabaseURLHint" Value="Test 1"></String>
  <String Id="UIDatabaseAuthenticationMethod" Value="Test 2"></String>
  <String Id="UIDatabaseUsername" Value="Test 3"></String>
  <String Id="UIUseDefaultDatabasePassword" Value="Test 4"></String>
  <String Id="UIDatabase" Value="Test 5"></String>
  <String Id="UIDatabaseConnectionName" Value="Test 6"></String>
</WixLocalization>

XAML:

<wixsharp:WpfDialog
    x:Class="XRange.SQLConnectionDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:wixsharp="clr-namespace:WixSharp.UI.WPF;assembly=WixSharp.UI.WPF"
    d:DesignHeight="408"
    d:DesignWidth="512"
    DialogTitle="[ProductName] Setup"
    mc:Ignorable="d">
    <Grid x:Name="Root">
        <Grid.RowDefinitions>
            <RowDefinition Height="60" />
            <RowDefinition Height="*" />
            <RowDefinition Height="53" />
        </Grid.RowDefinitions>
        <Border
            Margin="-1,-1,-1,0"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch"
            BorderBrush="Gray"
            BorderThickness="1">
            <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="80" />
                </Grid.ColumnDefinitions>

                <Image
                    x:Name="Banner"
                    Grid.Row="1"
                    Grid.ColumnSpan="2"
                    HorizontalAlignment="Stretch"
                    VerticalAlignment="Stretch" />
                <StackPanel Margin="9">
                    <TextBlock
                        Grid.Column="0"
                        FontSize="12"
                        FontWeight="Bold">
                        [SetupTypeDlgTitle]
                    </TextBlock>
                    <TextBlock
                        x:Name="DialogDescription1"
                        Margin="17,5"
                        VerticalAlignment="Stretch"
                        TextWrapping="WrapWithOverflow">
                        [SetupTypeDlgDescription]
                    </TextBlock>                
                </StackPanel>
            </Grid>
        </Border>
        <ScrollViewer Grid.Row="1">
            <StackPanel x:Name="DatabaseGrid" Grid.Row="1" Margin="20,10,20,10">
                <TextBlock x:Name="DatabaseURLHint" TextWrapping="Wrap" Text="[UIDatabaseURLHint]" />

                <TextBox x:Name="SQLServerAddress" TextWrapping="Wrap" TextChanged="SQLServerAddress_TextChanged" RenderTransformOrigin="0.491,-0.021" Height="20"/>
                <TextBlock
                    x:Name="DatabaseAuthenticationMethod"
                    TextWrapping="WrapWithOverflow" Text="[UIDatabaseAuthenticationMethod]" Margin="0,5,0,0"/>
                <ComboBox x:Name="Authentication" Height="24"/>
                <TextBlock
                    x:Name="UIDatabaseUsername"
                    TextWrapping="WrapWithOverflow" Text="[UIDatabaseUsername]" Margin="0,5,0,0"/>
                <TextBox x:Name="Username" TextWrapping="Wrap" Text="User" Height="20"/>

                <CheckBox x:Name="UseDefaultPassword" Content="[UIUseDefaultDatabasePassword]" Checked="UseDefaultPassword_Checked" Unchecked="UseDefaultPassword_Unchecked" IsChecked="True"/>
                <PasswordBox x:Name="Password" Height="20" Password="Password" IsEnabled="False"/>
                <TextBlock
                    x:Name="UIDatabase"
                    TextWrapping="WrapWithOverflow" Text="[UIDatabase]"/>
                <TextBox x:Name="Database" TextWrapping="Wrap" Height="19" Text=""/>
                <TextBlock
                    x:Name="UIDatabaseConnectionName"
                    TextWrapping="WrapWithOverflow" Text="[UIDatabaseConnectionName]"/>
                <TextBox x:Name="ConnectionName" TextWrapping="Wrap" Height="20" Text="DB"/>

            </StackPanel>
        </ScrollViewer>
        <Border
            Grid.Row="2"
            Margin="-1,0,-1,-1"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch"
            BorderBrush="Gray"
            BorderThickness="1">
            <StackPanel
                HorizontalAlignment="Right"
                VerticalAlignment="Center"
                Orientation="Horizontal">
                <Button
                    x:Name="TestConnectionButton"
                    Height="23"
                    MinWidth="73" Content="[UITestConnection]" Click="TestConnectionButton_Click"/>
                <Separator Width="20" Opacity="0" />
                <Button
                    x:Name="GoPrev"
                    Height="23"
                    MinWidth="73" Content="[WixUIBack]" Click="GoPrev_Click"/>
                <Separator Width="10" Opacity="0" />
                <Button
                    x:Name="GoNext"
                    Height="23"
                    MinWidth="73"
                    IsEnabled="false" Content="[WixUINext]" Click="GoNext_Click"/>
                <Separator Width="20" Opacity="0" />
                <Button
                    x:Name="Cancel"
                    Height="23"
                    MinWidth="73" Content="[WixUICancel]"/>
                <Separator Width="10" Opacity="0" />
            </StackPanel>
        </Border>

    </Grid>
</wixsharp:WpfDialog>
oleg-shilo commented 3 months ago

Will have a look at this on the weekend.

oleg-shilo commented 3 months ago

I'm merging the wxl file

Yes this is the correct technique. Is it possible that you are not doing it at right time that is UIInitialized project event:

https://github.com/oleg-shilo/wixsharp/blob/6be8a97236b57ea00dcfa18276560a1111da3276/Source/src/WixSharp.Samples/Wix%23%20Samples/Managed%20Setup/MultiLanguageUI/setup.cs#L82-L98

You can find the relevant samples in the samples library:

kipamgs commented 3 months ago

I initialized it exactly as in the example. I created a small example project with the problem. Example.zip

oleg-shilo commented 3 months ago

Great, I will have a look on weekend.

oleg-shilo commented 3 months ago

OK, there are a few problems here. It's kinda a perfect localization storm :)

Please note I am reviewing your example that you shared.

  1. Small problem with your code You probably noticed that your TestConnecttionButton is localized. But your TextBlocks are not. This is because WixzSharp localization is translating ContentControl.Content (e.g. in buttons) and TextBlock.Text text. Though in your case did not set TextBlock.Text property but a TextBlock.Content property`
    <TextBlock TextWrapping="Wrap"><Run Text="[UI_DB_URL_HINT]" /></TextBlock>

    Thus WixSharp is translating the empty property Text. To solve this problem you either need to set text manually or simply roll it back to TextBlock.Text approach.

    <TextBlock TextWrapping="Wrap" Text="[UI_DB_URL_HINT]"></TextBlock>
  1. Bigger problem with auto localization in WixSharp () It is a WixSharp limitation that is simply triggered by you placing your StackPanel in the ScrollViewer. The problem is that WixSharp translates the content of the WPF dialog (e.g. SQLConnectionDialog) when its parent Loaded event is called. It works fine in all cases except when the visual tree generation is somehow delayed (e.g. because of the ScrollViewers). I just have fixed this problem by executing the dialog localization from the actual dialog Loaded event (not from its parent). It works now fine and the fix will be available in the very next release. In the meantime you can solve this problem by calling localization manually from the dialog onload event:
    public SQLConnectionDialog()
    {
       InitializeComponent();
       this.Loaded += (s, e) => this.Localize();
    }

There are quite a few moving parts here, but basically, you will need to get rid of <Run and call Localize from the onLoad handler (or get rid of the ScrollViewer. But when the next release is out, the only constraint will be the use of <Run...

===========================

I have also added this information to the Localization wiki.

kipamgs commented 3 months ago

Thanks for the quick reply.

OK, there are a few problems here. It's kinda a perfect localization storm :)

Please note I am reviewing your example that you shared.

1. Small problem with your code
   ```
   <TextBlock TextWrapping="Wrap"><Run Text="[UI_DB_URL_HINT]" /></TextBlock>
   ```

I overlooked that one.

2. Bigger problem with auto localization in WixSharp ()
   In a meantime you can solve this problem by calling localization manually from the dialog onload event:
   ```cs
   public SQLConnectionDialog()
   {
       InitializeComponent();
       this.Loaded += (s, e) => this.Localize();
   }
   ```

There are quite a few moving parts here, but basically, you will need to get rid of <Run and call Localize from the onLoad handler (or get rid of the ScrollViewer. But when the next release is out, the only constraint will be is the use of <Run...

I couldn't ask for more than a 1 line solution :)

===========================

I have also added this information to the Localization wiki.

Thanks.