WPF中包含下标和内联图像的文本本地化

WPF中包含下标和内联图像的文本本地化,wpf,xaml,localization,user-interface,Wpf,Xaml,Localization,User Interface,我有一个小的WPF应用程序,我正在本地化。我已经阅读了大量文档,但没有找到处理“丰富”内容的良好信息来源,例如: <ResourceDictionary> <ControlTempate x:Key="Something" TargetType="ContentControl"> <DockPanel> <ContentPresenter DockPanel.Dock="Left" /> <TextBloc

我有一个小的WPF应用程序,我正在本地化。我已经阅读了大量文档,但没有找到处理“丰富”内容的良好信息来源,例如:

<ResourceDictionary>
  <ControlTempate x:Key="Something" TargetType="ContentControl">
    <DockPanel>
      <ContentPresenter DockPanel.Dock="Left" />
      <TextBlock Text="En español en el botón a la izquierda del texto" />
        <!-- In spanish the button is to the left of the text -->
    </DockPanel>
  </ControlTemplate>
</ResourceDictionary>
我有一个ui元素(TextBlock),它包含了文本与格式、内联图像和符号的混合。我想本地化这个元素。我认为,在另一种语言中,以一种自然的方式对该元素进行本地化,即公式/符号的位置需要相对于周围文本进行移动,并且文本的最佳格式在其他语言中也可能略有不同

我正在寻找在XAML/WPF中本地化“丰富”内容(混合文本、格式和内联ui元素的内容)的建议、资源和/或方法。考虑到WPF中对合成和“丰富”UI的强调,我很惊讶没有找到关于上述场景的任何信息——我遗漏了什么

我曾考虑过将XAML存储在资源文件中,然后在运行时对其进行解析,以便包含在UI中,并考虑过创建一个基于区域设置的视图/用户控件,但我没有看到任何关于这些方法的提及(这让我怀疑我是否走错了方向)我希望有人有经验或信息可以分享


谢谢

假设您有一条文本:

"Hello, my <b>dear</b> user!"
“你好,我亲爱的用户!”
您希望将该文本本地化为其他语言:

"Привет, мой <b>дорогой</b> пользователь!!" 
“Пццццццццзззазаава1072
因此,您的本地化框架应该将其存储在一个包含所有格式的完整字符串中,并依靠翻译人员耐心、努力工作并保留所有格式标记。或者,如果格式化非常重要,则应将字符串拆分为(3)个部分,并在构造字符串时应用格式化,并将每个部分作为单个条目存储在翻译存储中

编辑:如果您的富文本包含图像引用,则应使用以下内容本地化图像链接的生成方式:

<img src="$current_locale/logo.jpg" />

或者甚至有一个函数,如果当前区域设置的图像丢失,该函数将返回默认图像位置:

<img src="$get_current_locale_or_default_locale_image(logo.jpg)" />

对于您试图实现的目标,
静态资源
标记扩展非常有效。使用StaticResource几乎可以包含任何内容,即使DynamicSource不工作:

<Window ...>
  <Window.Resources>

    <Span x:Key="Whatever">
      <Bold>Hello</Bold> there<LineBreak/>
      A green circle:
      <InlineUIContainer>
        <Ellipse Width="10" Height="10" Fill="Green" />
      </InlineUIContainer>
    </Inline>

  </Window.Resources>

  ...
  <TextBlock>
    <StaticResource ResourceKey="Whatever" />
  </TextBlock>
请注意,消息类似,但对于西班牙语,圆圈为红色,文本的布局不同

如果愿意,您可以使用ControlTemplates进一步了解这一点。使用ControlTemplates将允许您根据区域设置以不同的顺序排列按钮。例如,如果您的通用词典包含:

<ResourceDictionary>
  <ControlTempate x:Key="Something" TargetType="ContentControl">
    <StackPanel>
      <TextBlock Text="In English we want the text above the button" />
      <ContentPresenter />
    </StackPanel>
  </ControlTemplate>
</ResourceDictionary>

您可以将其添加到窗口或用户控件:

<ContentControl Template="{StaticResource Something}">
  <Button Command="Save">Save File</Button>
</ContentControl>

保存文件
然后更改另一种语言的布局,例如:

<ResourceDictionary>
  <ControlTempate x:Key="Something" TargetType="ContentControl">
    <DockPanel>
      <ContentPresenter DockPanel.Dock="Left" />
      <TextBlock Text="En español en el botón a la izquierda del texto" />
        <!-- In spanish the button is to the left of the text -->
    </DockPanel>
  </ControlTemplate>
</ResourceDictionary>

注意:如果您只在DependencyProperties中使用本地化(例如没有InlineCollections等),您可以使用
{DynamicResource}
,它允许通过即时更新UI随时更改区域设置。要在我的第一个示例中实现这一点,您可以将TextBlock放在ResourceDictionary中的ControlTemplate中,而不是将
包含在
ResourceDictionary
中并将其包含在TextBlock中


这只是WPF本地化灵活性的开始。你可以更进一步。

我用StaticResource扩展标记了Ray Burns的答案,作为公认的答案,我认为关于该方法的很多细节都是完美的。我还想展示另一个想法——使用T4模板生成“松散”xaml文件,这些文件包含在输出中,并在运行时基于CurrentCulture进行解析

下面的代码是base_block.tt文件的内容。下面一个重要的细节是encoding=“Unicode”的使用(我假设Utf-8可以工作,但是当模板指定Utf-8时,XamlParser会在某些字符上出错,这显然是因为BOM设置)


base_block.tt可用于指定所需值的.tt文件中的include中-对于英语,这里是我的en.tt文件,它将生成en.xaml:

<# 

xml_lang = @"en-US";

textblock_constant_C_contents = 
    @"Enter a constant, <Italic>C</Italic>, that satisfies
            <InlineUIContainer Style='{StaticResource image_container_style}'>
                    <Image x:Name='formula_11' Source='{StaticResource equation_11}' Style='{StaticResource image_style}' Tag='3.0'>
                    <Image.Height>
                        <MultiBinding Converter='{StaticResource image_size}'>
                            <Binding Mode='OneWay' ElementName='formula_11' Path='Tag'/>                        
                            <Binding Mode='OneWay' ElementName='c_textblock' Path='FontSize'/>
                        </MultiBinding>
                    </Image.Height>
                </Image>
            </InlineUIContainer>";

textblock_automation_name = @"Enter a Constant, C, that satisfies the following equation: the standard error of the estimate is equal to the constant C over the square root of the sample size";

hyperlink_textblock_contents = @"(<Hyperlink AutomationProperties.Name='More information about the constant C' 
                                        x:Name='c_hyperlink'>more info</Hyperlink>)";

#>

<#@ include file="base_block.tt" #>

或者对于法语-fr.tt->fr.xaml:

<# 

xml_lang = @"fr";

textblock_constant_C_contents = 
    @"Entrez une constante, <Italic>C</Italic>, pour satisfaire
            <InlineUIContainer Style='{StaticResource image_container_style}'>
                    <Image x:Name='formula_11' Source='{StaticResource equation_11}' Style='{StaticResource image_style}' Tag='3.0'>
                    <Image.Height>
                        <MultiBinding Converter='{StaticResource image_size}'>
                            <Binding Mode='OneWay' ElementName='formula_11' Path='Tag'/>                        
                            <Binding Mode='OneWay' ElementName='c_textblock' Path='FontSize'/>
                        </MultiBinding>
                    </Image.Height>
                </Image>
            </InlineUIContainer>";

textblock_automation_name = @"Entrez une constante, C, qui satisfait l'équation suivante: l'erreur-type de l'estimation est égale à la constante C sur la racine carrée de la taille de l'échantillon.";

hyperlink_textblock_contents = @"(<Hyperlink AutomationProperties.Name=""Plus d'informations sur la constante C"">en savoir plus</Hyperlink>)";

#>

<#@ include file="base_block.tt" #>

上面的法语生成以下.xaml文件:

<UserControl
    xml:lang="fr"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="basic_styles.xaml" />
                <ResourceDictionary Source="equations.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>

        <WrapPanel Style="{StaticResource description_wrap_panel_style}">

                <TextBlock  x:Name="c_textblock"
                            Style="{StaticResource description_textblock_style}" 
                            AutomationProperties.Name = "Entrez une constante, C, qui satisfait l'équation suivante: l'erreur-type de l'estimation est égale à la constante C sur la racine carrée de la taille de l'échantillon.">
                        Entrez une constante, <Italic>C</Italic>, pour satisfaire
                    <InlineUIContainer Style='{StaticResource image_container_style}'>
                            <Image x:Name='formula_11' Source='{StaticResource equation_11}' Style='{StaticResource image_style}' Tag='3.0'>
                            <Image.Height>
                                <MultiBinding Converter='{StaticResource image_size}'>
                                    <Binding Mode='OneWay' ElementName='formula_11' Path='Tag'/>                        
                                    <Binding Mode='OneWay' ElementName='c_textblock' Path='FontSize'/>
                                </MultiBinding>
                            </Image.Height>
                        </Image>
                    </InlineUIContainer>
                </TextBlock>

                <TextBlock  Style="{StaticResource description_textblock_style}"
                            KeyboardNavigation.TabIndex="1">
                        (<Hyperlink AutomationProperties.Name="Plus d'informations sur la constante C">en savoir plus</Hyperlink>)
                </TextBlock>

                <TextBox    Style="{StaticResource entry_textbox_style}"
                            AutomationProperties.LabeledBy="{Binding ElementName=c_textblock}"
                            KeyboardNavigation.TabIndex="0">
                </TextBox>

        </WrapPanel>
</UserControl>

君士坦丁主菜,C,令人满意
(en savoir plus)

在运行时,我查看CurrentCulture,将其与生成的可用xaml文件进行比较,将文件提供给XamlReader.Load(),并在需要的地方添加生成的Usercontrol。一个小样本应用程序演示了这一点。

本地化的“丰富”内容和非“丰富”内容有什么区别?本地化是否应该关心这一点?我猜它只是把文本数据存储在一些普通的地方,格式化标签就是PAR。
<UserControl
    xml:lang="fr"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="basic_styles.xaml" />
                <ResourceDictionary Source="equations.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>

        <WrapPanel Style="{StaticResource description_wrap_panel_style}">

                <TextBlock  x:Name="c_textblock"
                            Style="{StaticResource description_textblock_style}" 
                            AutomationProperties.Name = "Entrez une constante, C, qui satisfait l'équation suivante: l'erreur-type de l'estimation est égale à la constante C sur la racine carrée de la taille de l'échantillon.">
                        Entrez une constante, <Italic>C</Italic>, pour satisfaire
                    <InlineUIContainer Style='{StaticResource image_container_style}'>
                            <Image x:Name='formula_11' Source='{StaticResource equation_11}' Style='{StaticResource image_style}' Tag='3.0'>
                            <Image.Height>
                                <MultiBinding Converter='{StaticResource image_size}'>
                                    <Binding Mode='OneWay' ElementName='formula_11' Path='Tag'/>                        
                                    <Binding Mode='OneWay' ElementName='c_textblock' Path='FontSize'/>
                                </MultiBinding>
                            </Image.Height>
                        </Image>
                    </InlineUIContainer>
                </TextBlock>

                <TextBlock  Style="{StaticResource description_textblock_style}"
                            KeyboardNavigation.TabIndex="1">
                        (<Hyperlink AutomationProperties.Name="Plus d'informations sur la constante C">en savoir plus</Hyperlink>)
                </TextBlock>

                <TextBox    Style="{StaticResource entry_textbox_style}"
                            AutomationProperties.LabeledBy="{Binding ElementName=c_textblock}"
                            KeyboardNavigation.TabIndex="0">
                </TextBox>

        </WrapPanel>
</UserControl>