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

时间:2009-11-02 07:07:50

标签: wpf xaml localization user-interface

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

我有一个ui元素(TextBlock),其中包含文本与格式,内嵌图像和符号的混合。我想本地化这个元素。我相信本地化这个元素的方式在另一种语言中很自然,公式/符号的位置需要相对于周围的文本移动 - 并且文本的最佳格式在其他语言中可能略有不同好。

我正在寻找在XAML / WPF中本地化“丰富”内容(混合文本,格式和内联ui元素的内容)的建议,资源和/或方法。考虑到WPF中的构图和“丰富”UI的重点,我很惊讶没有找到有关上述场景的任何信息 - 我缺少什么?

我考虑过将XAML存储在资源文件中,然后在运行时解析它以包含在UI中,以及创建基于区域设置换出的view / usercontrol - 但我没有看到任何提及这些方法(这让我想知道我是否在“错误的轨道”上,并希望有人有经验或信息分享?

谢谢!

3 个答案:

答案 0 :(得分:2)

StaticResource标记扩展程序非常适合您要完成的任务。即使DynamicResource不起作用,您也可以使用StaticResource包含几乎所有内容:

<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>

现在本地化很容易:

  1. Span资源移至单独的ResourceDictionary并合并到应用程序的资源字典中。
  2. 在应用程序启动期间以及创建任何窗口之前,使用代码获取当前文化,并向ResourceDictionary添加其他特定于语言的application.Resources.MergedDictionaries。可以使用WPF的内置本地化机制加载卫星字典。
  3. 只要dictionares以正确的顺序合并到应用程序字典中,在本地化的字典中找到的任何命名资源将优先于主字典中的那个,例如您的西班牙语本地化dll可能具有xaml包含此文件的文件:

    <ResourceDictionary>
      <Span x:Key="Whatever">
        El círculo rojo
          <InlineUIContainer>
            <Ellipse Width="10" Height="10" Fill="Red" />
          </InlineUIContainer>
        dice <Bold>hola!</Bold>
      </Span>
    </ResourceDictionary>
    

    请注意,该消息类似,但对于西班牙语,圆圈为红色,文本的布局也不同。

    如果您愿意,可以使用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,从而改变语言环境。要使用我的第一个示例执行此操作,而不是在<Span>中包含ResourceDictionary并将其包含在TextBlock中,您可以将TextBlock放在ResourceDmplate内的ControlTemplate中。

    这只是WPF本地化灵活性的开始。你可以走得更远。

答案 1 :(得分:0)

假设你有一个文字:

"Hello, my <b>dear</b> user!"

并且您希望将该文本本地化为其他语言:

"Привет, мой <b>дорогой</b> пользователь!!" 

因此,您的本地化框架应该将其存储在一个包含所有格式的整个字符串中,并依赖于翻译人员耐心和勤奋并保留所有格式标签。或者,如果格式非常重要,那么您应该将字符串拆分为(3)部分并在构造字符串时应用格式,并将每个部分存储为翻译存储中的单个条目。

编辑:如果您的富文本包含图片参考,那么您应该本地化使用以下内容生成图像链接的方式:

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

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

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

答案 2 :(得分:0)

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

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

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".xaml" encoding="Unicode"#>

<UserControl
    xml:lang="<#= this.xml_lang #>"
    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 = "<#= this.textblock_automation_name #>">
                        <#= this.textblock_constant_C_contents #>
                </TextBlock>

                <TextBlock  Style="{StaticResource description_textblock_style}"
                                KeyboardNavigation.TabIndex="1">
                        <#= this.hyperlink_textblock_contents #>
                </TextBlock>

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

        </WrapPanel>

</UserControl>

<#+ 

private string xml_lang = @"";
private string textblock_constant_C_contents = @"";
private string textblock_automation_name = @"";
private string hyperlink_textblock_contents = @"";

#>

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 - &gt; 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>

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