如何使用.RESX文件本地化基于Neutronium的UI?

时间:2017-09-24 18:14:15

标签: c# wpf neutronium

我将Neutronium库用于基于HTML的C#UI。

我希望能够方便地使用.RESX资源中的字符串,而不是将每个字符串包装在ViewModel的资源访问属性中。

如何更轻松地实现这一目标?

3 个答案:

答案 0 :(得分:2)

您可以使用ResourceManager.GetResourceSet转换字典中的资源,然后在ViewModel中使用此字典

这是一个与即将推出的1.0.0版兼容的完整解决方案

<强>视图模型:

public class MainViewModel : ViewModelBase
{
   private Dictionary<string, string> _Localization;
   public Dictionary<string, string> Localization
   {
       get { return _Localization; }
       private set { Set(ref _Localization, value, nameof(Localization)); }
   }

   private string _Langage;
   public string Langage
   {
        get { return _Langage; }
        set
        {
            if (Set(ref _Langage, value, nameof(Langage)))
            {
                 UpdateLangage();
            }           
        }
   }

   private void UpdateLangage()
   {
       var rs = Resource.ResourceManager
                        .GetResourceSet(new CultureInfo(_Langage), true, true);
       Localization = rs.Cast<DictionaryEntry>()
                        .ToDictionary(dicEntry => (string)dicEntry.Key, dicEntry => (string)dicEntry.Value);            
   }

   public string[] Langages => new[] {"en-US", "pt-BR", "fr-FR"};

   public MainViewModel()
   {
     Langage = "en-US";
   }
}

Vue文件:

 <template>
        <div id="app" class="fluid container">
            <div id="main-menu" class="jumbotron logo">
                <img src="./assets/logo.png">
                <p>{{Localization.NeutroniumLocalizationExample}}</p>
            </div>

            <div class="col-md-2">
                <span>{{Localization.Language}}</span>
                <select v-model="Langage">
                    <option v-for="lang in Langages" :value="lang">{{lang}}</option>
                </select>
            </div>

            <div class="col-md-10">
                <h1>{{Localization.Hello}}</h1>
                <h2>{{Localization.Welcome}}</h2>
                <h3>{{Localization.MyFriend}}</h3>
            </div>
        </div>
    </template>

完整解决方案here

答案 1 :(得分:2)

Neutronium v​​.1.0.0还有另一种可能的选择,刚刚发布。 解决方案使用vue-i18n有基础设施和T4模板将.resx文件转换为JSON文件,然后由webpack在javascript中导入。

配置(install.js文件):

import VueI18n from 'vue-i18n'
import messages from './Dictionary'

function install(vue) {
    //Call vue use here if needed
    vue.use(VueI18n);
}

function vueInstanceOption() {
    const i18n = new VueI18n({
        locale: 'fr-FR', // set locale
        messages, // set locale messages
    });

    //Return vue global option here, such as vue-router, vue-i18n, mix-ins, .... 
    return {i18n}
}

export {
    install,
    vueInstanceOption
}

t4模板:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Resources" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".json" #>
<# 
    Langages = new [] { "en-US", "fr-FR", "pt-BR" };
    Resources = new []{"Resource"};
#>
{
 <# var first = true;
 PushIndent("    ");
 foreach (var langage in Langages) {
    if (!first){
        WriteLine("},");
    }
    first =false;
    WriteLine($@"""{langage}"":{{");
    PushIndent("    ");
    foreach(var resource in Resources){
        WriteLine($@"""{resource}"":{{");
        PushIndent("    ");
        var dic = GetDictionary(resource, langage);
        DisplayDictionary(dic);
        PopIndent();
        WriteLine("}");
    }
    PopIndent();
 } 
 WriteLine("}");
 PopIndent();
 #>
}
<#+
private string[] Langages;

private string[] Resources;

private void DisplayDictionary(IDictionary<string,string> dictionary){
    var first = true;
    foreach(var entry in dictionary){
        if (!first){
            WriteLine(",");
        }
        first = false;
        Write($@"""{entry.Key}"":""{entry.Value}""");
    }
    WriteLine("");
}

private IDictionary<string,string> GetDictionary(string resourceName, string langage){
    var path = this.Host.ResolveAssemblyReference("$(TargetPath)");
    var asm = Assembly.LoadFrom(path);
    var resourceManager = new ResourceManager("Example.Option.CFx.Vue." + resourceName, asm);
    var rs = resourceManager.GetResourceSet(new CultureInfo(langage), true, true);
    return rs.Cast<DictionaryEntry>().ToDictionary(dicEntry => (string)dicEntry.Key, dicEntry => (string)dicEntry.Value);            
}
#>

然后,您可以在所有文件中正常使用本地化。

Ex:App.vue

<template>
  <div>
    <h1>{{ $t("Resource.Welcome") }}</h1>
    <h2>{{ $t("Resource.MyFriend") }}</h2>     
  </div>
</template>

完整代码here

答案 2 :(得分:1)

我不熟悉该框架,但一种选择可能是使用动态类型。警告 - 这些都没有经过测试......

创建一个“动态”类,负责公开字符串资源:

public class ResourceProvider : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        var resourceName = binder.Name;

        result = MyResources.ResourceManager.GetString(resourceName);
        // You'll want some error checking here, and return false if the resource does not exist 
        // (or throw an exception, return a default string, etc).
        return true;
    }
}

MyResources是resx文件的名称。如果它位于一个单独的项目中,请记住将资源文件的访问修饰符组合框从内部更改为公共。)

接下来,在您的VM(或VM基类中,如果您在其他视图中需要此功能)中,创建上述类的实例并将其作为“动态”属性类型公开,例如

public dynamic ViewResources { get; private set; }

...

ViewResources = new ResourceProvider();

在HTML中,虽然我不知道该框架的确切语法,但您现在应该可以使用以下表达式进行绑定:

"ViewResources.Hello"

(其中“Hello”是resx文件中字符串资源的名称)。

这也适用于您的VM C#代码,即

var s = ViewResources.Hello;