我有一个小型的WPF应用程序,我正在进行本地化。我已阅读了大量文件,但我没有找到关于处理“丰富”内容的良好信息来源 - 例如:
我有一个ui元素(TextBlock),其中包含文本与格式,内嵌图像和符号的混合。我想本地化这个元素。我相信本地化这个元素的方式在另一种语言中很自然,公式/符号的位置需要相对于周围的文本移动 - 并且文本的最佳格式在其他语言中可能略有不同好。
我正在寻找在XAML / WPF中本地化“丰富”内容(混合文本,格式和内联ui元素的内容)的建议,资源和/或方法。考虑到WPF中的构图和“丰富”UI的重点,我很惊讶没有找到有关上述场景的任何信息 - 我缺少什么?
我考虑过将XAML存储在资源文件中,然后在运行时解析它以包含在UI中,以及创建基于区域设置换出的view / usercontrol - 但我没有看到任何提及这些方法(这让我想知道我是否在“错误的轨道”上,并希望有人有经验或信息分享?
谢谢!
答案 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>
现在本地化很容易:
Span
资源移至单独的ResourceDictionary
并合并到应用程序的资源字典中。ResourceDictionary
添加其他特定于语言的application.Resources.MergedDictionaries
。可以使用WPF的内置本地化机制加载卫星字典。只要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的小型示例应用程序。