使用WPF动态资源在Gtk3 C#中进行本地化

79 篇文章 2 订阅

目录

介绍

背景

实现

Windows

Linux

扩展

感谢...

参考和出处


GTK3示例

WPF示例

介绍

我的大多数Windows程序都是使用WPF/MVVM组合编写的。在本地化方面,我并不是卫星组件的忠​​实拥护者,因此从一开始,我就选择使用动态资源。当我转向Linux时,我的目标显然是尽可能地(重新)使用我现有的代码。由于我的Windows应用程序使用动态资源,并且以双语(英语和希腊语)编写,因此我已经拥有一堆将资源文件翻译成希腊语的功能,因此我有强烈的动机来利用它们。在本文中,我提出了一种在Gtk3 C#应用程序中重用Windows/WPF资源文件的方法。

背景

在本文中,我包括一个小型MVVM Windows WPF应用程序,该应用程序显示了WPF如何使用动态资源以及如何通过代码对其进行访问。简而言之,它是这样的:

资源文件包含键/值对的集合。每种语言都有一个资源文件。用于命名资源文件的约定是Dictionary.”+特定文化的语言代码+“.xaml”。因此,我的应用程序中的默认资源文件是Dictionary.en-US.xaml ”,希腊文的文件名是Dictionary.el-GR.xaml ”

XAML文件中,WPF绑定发挥了神奇的作用,您要做的就是将资源键绑定到控件的属性,而不是拥有不可翻译的string文字:

<Label Content="Hello World" />

您声明如下内容:

<Label Content="{DynamicResource HolaMundo}" />

在资源文件中的哪个位置,您拥有:

<sys:String x:Key="HolaMundo" >Hello World</sys:String>

WPF替您代劳。

要启用此功能,请在App.xml中将Resource字典声明为应用程序Resource

<Application.Resources>
  <ResourceDictionary>
   <ResourceDictionary.MergedDictionaries>
     <ResourceDictionary Source="\Resources\Dictionary.en-US.xaml"/>
   </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</Application.Resources>

App.config,您需要声明应用程序当前将使用的Language。为简单起见,我们使用Language的特定于语言环境的代码:

<appSettings>
    <add key="Language"  value="en-US" />

</appSettings>

App.xml.cs,事情变得更加有趣,因为在那里,我们还可以通过代码访问动态资源,这是通过以下功能完成的:

/// <summary>
/// This loads the Dictionary into the Application's Properties
/// IMPORTANT: Call this first, before everything else.
/// </summary>
private void InitializeLocalizedResources()
{
   String szLanguage = ConfigurationManager.AppSettings [ "Language" ];

   if ( String.IsNullOrEmpty( szLanguage ) )
      szLanguage = "en_US";

   ResourceDictionary dict = new ResourceDictionary();

   dict.Source = 
      new Uri( "\\Resources\\Dictionary." + szLanguage + ".xaml", UriKind.Relative );
   this.Resources.MergedDictionaries.Add( dict );
   // allows us to access it via code
   Properties [ szLanguage ] = dict;
}

唯一的限制是在启动时,您必须在其他所有操作之前调用它,因此:

private void OnAppStartup( object sender, StartupEventArgs e )
{
   try
   {
      // Initialize these here *before* everything else!!
      InitializeLocalizedResources();
      // rest of the code ..

最后,在.cs代码文件中,要从资源中检索string,您需要类似以下内容:

String GetStringFromDynamicResources( String szLang, String szKey )
{
   if( Application.Current == null )
      return String.Empty;

   ResourceDictionary rd = ( ResourceDictionary ) Application.Current.Properties [ szLang ];

   return ( rd != null ) ? ( rd [ szKey ] as String ) : String.Empty ;
}

就是这样。

实现

遵循GOF格言对接口进行编程,而不是对实现进行编程之后,我们从一个最能描述我们要完成的任务的接口开始:

public interface ITranslator
{
  String GetResourceString( String szKey, String szDefault );
}

第二个参数非常有用,因为如果在字典中找不到条目,​​则默认将其返回给调用方。具有讽刺意味的是,事实证明,创建Translator static类更方便,因此该接口似乎是多余的。但是,它可以帮助我们专注于大局。

Windows

Windows上,我们有一个WPFTranslator类,其中的实现实质上封装了我们上面描述的代码(请参阅随附的示例应用程序),因此,由于本文的重点是Linux版本,所以我将省略其详细信息。

Linux

Linux版本之所以被称为Translator仅仅是因为它根本没有任何特定于Gtk的代码。尽管WPFTranslator可以利用Application的属性来访问字典,但Linux上却没有这种奢侈。这里的繁重工作是由Lexicon类完成的,该类包含一个Dictionary/值对。创建类后,它将从磁盘读取Resource文件,并将在该文件中找到的资源加载到其自己的内存字典中。

protected bool LoadDictionary()
{
    bool bRetVal = false;
    XmlDocument xDoc = new XmlDocument();

    int n = 1;
    
    try
    {
        xDoc.Load( m_szFileName );

        XmlNodeList lst = xDoc.GetElementsByTagName( "sys:String" );
        if( lst != null && lst.Count > 0 )
        {
            foreach( XmlNode node in lst )
            {
                m_lstDict.Add( node.Attributes[0].Value, node.InnerText );
                n++;
            }
        }
        bRetVal = true;
    }
    catch( Exception )
    {
        bRetVal = false ;
    }
    return bRetVal;
}

然后,如果需要的话,它将根据需要向翻译器提供所需的条目。

public String GetResourceString( String szKey, String szDefault )
{
    if( String.IsNullOrEmpty( szKey ) )
        return szDefault;

    try
    {
        String sz = m_lstDict[ szKey ];
        return ( !String.IsNullOrEmpty( sz ) ) ? sz : szDefault;
    }
    catch
    {
        return szDefault;
    }
}

WindowsLinux版本之间的主要区别在于,尽管Windows上的Dictionary.zzzzz.xaml文件被视为Pages并与所有其他XAML文件一起编译为可执行文件,但在Linux上不会发生。此处的解决方案是将文件复制到输出目录,Lexicon类可在其中找到它们。这样做的一个好处是,您可以对Resource文件进行更改,例如,以纠正输入错误,而不必重新编译可执行文件。

因此,在Linux上:

  1. 就像在Windows中一样,您可以在App.config文件中定义Language
  2. 在项目设置中,标记要复制到输出目录的资源文件。
  3. 在您的代码中,您调用Translator.GetResourceString( “key”, “Value” )

在那里,你有它。

请注意:在Linux上,文件名区分大小写,因此任何找不到文件错误都可能是由于该原因。

扩展

随附的示例程序目前仅适用于英语和希腊语,但也可以与其他多种语言一起使用。

通过更改App.config文件中的Language条目,您的应用程序将加载适当的资源。

感谢...

首先,对于MVVM“福音主义者Josh Smith, Sacha Barber, Jason_Dolinger等人。谁让我们看到了这种模式的巨大优势。

本文所述此处提供的示例程序可以将其起源追溯到Josh Smith的示例应用程序。实际上,在Linux示例程序中,您会发现我借用了他的SimpleCommand类。

还要特别感谢MonoMonoDevelop团队使在Linux上运行C#程序以及Gtk#团队的框架成为可能。

多亏了他们,我才能够重用大约80%的代码。:-)

有关示例程序的注释

本文的重点是Linux程序,但是我也包括Windows WPF程序,以便您可以比较不同的实现。您当然会注意到资源文件是相同的,这就是我们想要的。

拥有两个Windows程序的原因基本上是一个函数调用!Visual Studio 2008版本调用,ConfigurationSettings.AppSettings2012版本调用ConfigurationManager。在准备本文时,我决定不包括两个相同的WPF程序,而是决定修改VS 2012版本以使用ITranslator接口,以说明差异。在2012版本中,WPFTranslator类实现了ITranslator接口,所以没有实现static。因此,此类的用户必须实例化它。请参阅VS 2012项目的App.xaml.csMainViewModel.csFirstViewModel.cs。您可以从那里看到静态版本使用起来更加方便。

我知道Visual Studio 2008可能已经有12年的历史了,但并不是每个人都有拥有最新版本的特权,我的目标是让这段代码(无论如何它都没有使用c#的最新特性)能够被尽可能多的人使用。

Linux上,提供的示例应用程序是MonoDevelop解决方案。它需要GtkSharp3软件包。使用MonoDevelop将其打开,然后选择恢复软件包,然后再进行编译。

参考和出处

可以在此处找到特定于语言环境的语言代码的完整列表。

如前所述,Gtk3应用程序使用的SimpleCommand类来自Sacha Barber's Cinch

Gtk3应用程序使用的MultiTab控件已从ApprenticeHacker的代码(此处找到)改编而成。

示例应用程序使用的图标来自iconpack研究文件夹(DesignerFixIconGreg)),位于此处

https://www.codeproject.com/Articles/5294456/Localization-in-Gtk3-Csharp-using-WPF-Dynamic-Reso

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值