在MvvmCross ViewModels中本地化文本

时间:2013-02-14 17:04:16

标签: localization xamarin.ios xamarin.android windows-phone-8 mvvmcross

我想从ViewModel获取我的所有本地化文本(因为它通常是动态的),我想知道如何使用转换器从用于本地化的json文件中获取文本。例如,在下面的代码中,我希望LocalisedString使用我目前在我的视图中用于静态文本绑定的转换器 -

public string MyText // used in the binding in the View
{
    get
    {
        string exclamation;

        if (MyValue <= 3.3)
        {
            exclamation = LocalisedString("Rubbish!");
        }
        else if (OverallScore > 3.3 && OverallScore <= 6.6)
        {
            exclamation = LocalisedString("Good!");
        }
        else
        {
            exclamation = LocalisedString("Excellent!");
        }

        return exclamation;
    }
}

目前正在使用MvvmCross的第1版。

任何帮助都非常感激。

2 个答案:

答案 0 :(得分:9)

注意:这个答案是关于vNext的 - 它应该很容易移植回主人......区域的差异并不大。


MvvmCross内置了一个文本本地化机制。

使用它的唯一公共样本是会议样本。


此示例包含特定于共享和ViewModel的Json文件 - see

这些Json文件都包含简单的键值对,如:

{
"Title":"SQLBits X",
"Welcome":"Welcome",
"Sessions":"Sessions",
"Sponsors":"Sponsors",
"Tweets":"Tweets",
"Favorites":"Favorites"
}

它们作为内容或资产链接到Droid,Touch和WP ......所有这些都由平台使用ResourceLoader插件访问。


要在运行时使用这些JSON文件,核心项目会在TextProviderBuilder中加载它们:

    protected override IDictionary<string, string> ResourceFiles
    {
        get
        {
            var dictionary = this.GetType()
                .Assembly
                .GetTypes()
                .Where(t => t.Name.EndsWith("ViewModel"))
                .Where(t => !t.Name.StartsWith("Base"))
                .ToDictionary(t => t.Name, t => t.Name);

            dictionary[Constants.Shared] = Constants.Shared;
            return dictionary;
        }
    }

如果你愿意,你可以在这里轻松加载其他JSON文件。我的一些应用程序出现的情况并不罕见:

  • 错误文件
  • 一般共享语句的文件
  • 特定组件的文件
  • 每个ViewModel的文件

虽然其他人有:

  • 只是一个大文件!

国际化 - 完成后 - 通过加载一组不同的JSON文件来完成。通常,您首先加载默认设置,然后加载增量覆盖 - 因此您可以加载英语作为默认值,Cat作为覆盖加载,Cat-Lol作为进一步细化。

有关此问题的一些讨论,请参阅:


假设每个ViewModel有一个共享文件和一个文件,那么为了提供对JSON中文本值的运行时访问,BaseViewModel提供了2个属性:

    public IMvxLanguageBinder TextSource
    {
        get { return new MvxLanguageBinder(Constants.GeneralNamespace, GetType().Name); }
    }

    public IMvxLanguageBinder SharedTextSource
    {
        get { return new MvxLanguageBinder(Constants.GeneralNamespace, Constants.Shared); }
    }

这些属性用于数据绑定:

  • 指定是使用SharedTextSource还是TextSource
  • 的路径
  • MvxLanguageBinderConverter作为转换器
  • 文本键作为ConverterParameter

例如,在Droid中,这是:

<TextView
  style="@style/AboutPageBodyText"
  local:MvxBind="{'Text':{'Path':'TextSource','Converter':'Language','ConverterParameter':'Title'}}"
  />

虽然在现代的“瑞士”绑定中,这将写成:

<TextView
  style="@style/AboutPageBodyText"
  local:MvxBind="Text TextSource, Converter=Language, ConverterParameter='Title'"
  />

任何希望使用Text的代码也可以这样做 - 例如,参见TimeAgoConverter.cs中使用资源字符串的资源字符串创建TimeAgo文本的方式:

{
"TimeAgo.JustNow":"just now",
"TimeAgo.SecondsAgo":"{0}s ago",
"TimeAgo.MinutesAgo":"{0}m ago",
"TimeAgo.HoursAgo":"{0}h ago",
"TimeAgo.DaysAgo":"{0}d ago",
"TimeAgo.Never":"never"
}

这个代码实际上是:

 var valueToFormat = 42;
 var whichFormat = "TimeAgo.DaysAgo";

 var textProvider = this.GetService<IMvxTextProvider>();
 var format = textProvider.GetText(Constants.GeneralNamespace, Constants.Shared, whichFormat);

 return string.Format(format, valueToFormat)

语言Binder和ValueConverter是非常简单的代码

如果您需要,可以随意为您的应用构建更复杂的内容。


其他跨平台的文本本地化技术可用 - 我自己特别想有一天尝试白话 - https://github.com/rdio/vernacular

答案 1 :(得分:0)

也许您应该返回枚举而不是字符串并处理视图中的本地化。