Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What is going on with this article?
@tor4kichi

【.Net/Xamarin】I18N-Portableによる多言語対応

I18N-Portable

Xamarinと.Netに対応していて、UWPアプリでも利用できます。

i18nの初期化

アプリリソース内からローカリゼーションデータのテキストリソースを巡回するため、初期化にはAppクラスのAssemblyが必要です。

I18NPortable.I18N.Current
    .Init(GetType().Assembly);

Localesフォルダに翻訳データを配置

デフォルトではKeyValuePairの形式で翻訳テキストを記述します。

  • 翻訳データファイルはファイルのプロパティからビルドアクションを「埋め込みリソース」に指定する
  • ファイル名は言語コード(ja-JPやen-USなど)である必要があります。
Locales/ja-JP.txt

# key = value (the key will be the same across locales)
one = uno
two = dos
three = tres 
four = cuatro
five = cinco

# Enums are supported
Animals.Dog = Perro
Animals.Cat = Gato
Animals.Rat = Rata
Animals.Tiger = Tigre
Animals.Monkey = Mono

# Support for string.Format()
stars.count = Tienes {0} estrellas

TextWithLineBreakCharacters = Line One\nLine Two\r\nLine Three

Multiline = Line One
    Line Two
    Line Three

Jsonで扱いたい場合は別途Readerの追加指定が必要
https://github.com/xleon/I18N-Portable#supported-formats

使用例:コードからローカライズ

Locales/ja-JP.txt
YourName = 君の名は
var localizedText = "YourName".Translate();

使用例:Xamlでローカライズ

MarkupExtensionを利用する場合

using System;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Markup;

namespace I18NPortable.Xaml.Extensions 
{
    [MarkupExtensionReturnType(ReturnType = typeof(string))]
    public class LocalizeExtension : MarkupExtension
    {
        public object Key { get; set; }

        public object[] Parameters { get; set; }

        protected override object ProvideValue()
        {
            if (Key is Enum enumValue)
            {
                return enumValue.Translate();
            }
            else if (Key is string keyStr)
            {
                if (Parameters is null)
                {
                    return I18N.Current.Translate(keyStr);
                }
                else
                {
                    return I18N.Current.Translate(keyStr, Parameters);
                }
            }
            else
            {
                throw new NotSupportedException("LocalizeExtension not supported Type: " + Key?.GetType().Name);
            }
        }
    }
}
<Page xmlns:i18nExt="using:I18NPortable.Xaml.Extensions">
  <Text Text="{i18nExt:Localize Key=YourName}" />
</Page>

ValueConverterを利用する場合

LocalizeConverter.cs

using System;
using Windows.UI.Xaml.Data;
using I18NPortable;

namespace MyApp.Views.Conveters
{
    public sealed class LocalizeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if (value is Enum enumValue)
            {
                return enumValue.Translate();
            }
            else if (value is string stringValue)
            {
                if (parameter is string str)
                {
                    return stringValue.Translate(str);
                }
                else if (parameter is object[] p)
                {
                    return stringValue.Translate(p);
                }
                else
                {
                    return stringValue.Translate();
                }
            }
            else
            {
                throw new ArgumentException("Failed localize : " + value?.ToString());
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
}


Page.xaml
<Page xmlns:localization="using:MyApp.Views.Conveters">
  <prism:PrismApplication.Resources>
    <localization:LocalizeConverter x:Key="LocalizeConverter" />
  </prism:PrismApplication.Resources>

  <Grid>
    <TextBlock Text="{Binding Source=YourName, Converter={StaticResource LocalizeConverter}}" />
  </Grid>
</prism:PrismApplication>

Resourcesにi18n.Currentを配置する場合

App.xaml
Resources["Strings"] = I18NPortable.I18N.Current;
Text="{Binding Source={StaticResource Strings}, Path=[YourName]}"

(UWPでチェックしただけなのでWPFで動作するかはわかりません)

MarkupExtensionとValueConverterの使い分けについて

Bindingが絡む動的な値に対応したいところではConverterを使い、それ以外の固定テキストのローカライズにはMarkupExtension(i18nExt:Localize)や Resourcesにi18n.Currentを配置する方の方法を使用してます。

本当はText="i18nExt:Localize Key={Binding SomeValue}"みたいな書き方がしたいんですが、MarkupExtensionクラスがDependencyObjectを継承していないため無理な模様。(WPF/UWPの両方で無理)

MarkupExtension with binding parameters - stack overflow
https://stackoverflow.com/questions/10328802/markupextension-with-binding-parameters/10328974

また、MarkupExtensionの方について、WPFの場合は引数付きコンストラクタを定義するとKey=を省いて記述出来ます。UWPではおそらく非対応。

注意点

本家で紹介されているViewModelからi18N.Currentをプロパティとして公開して{Binding Strings[key]}とする方法でなければ言語変更に動的に対応することが出来ません。

ここで紹介したConveterを使った方法でアプリ内から言語を変更する場合には、ページのキャッシュを破棄してロードし直すか、言語変更後にアプリ再起動を促すUIを追加し再起動して貰う、などする必要があります。

4
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
tor4kichi
シンプルで"使える"アプリを作ろう

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
4
Help us understand the problem. What is going on with this article?