10

テキスト翻訳クラスから翻訳されたテキストを提供するWPFMarkupExtensionクラスを作成しようとしています。翻訳はうまく機能しますが、翻訳されたテキストを返すには、テキストキーを使用した静的メソッド呼び出しが必要です。このような:

ImportLabel.Text = Translator.Translate("import files");
// will be "Dateien importieren" in de or "Import files" in en

その専門は、より良い表現を提供するためにカウント値を受け入れることです。

ImportLabel.Text = Translator.Translate("import n files", FileCount);
// will be "Import 7 files" or "Import 1 file"

別の例:何かがまだ4分かかる場合、それは1分しかかからない場合とは別の言葉です。テキストキー「minutes」が任意の数の「Minuten」および1のカウントの「Minute」として定義されている場合、次のメソッド呼び出しは使用する正しい単語を返します。

Translator.Translate("minutes", numberOfMinutes)
// will be "minute" if it's 1, and "minutes" for anything else

現在、WPFアプリケーションには、多くのXAMLコードがあり、それには多くのリテラルテキストが含まれています。ナッツを使わずに翻訳できるようにするには、テキストキーを渡すことができ、実行時に翻訳されたテキストを返すマークアップ拡張機能が必要です。この部分はかなり簡単です。MarkupExtensionから継承するクラスを作成し、テキストキーを引数として受け入れるコンストラクターを追加し、それをプライベートフィールドに格納し、そのProvideValueメソッドが格納されたキーの翻訳テキストを返すようにします。

私の本当の問題はこれです:マークアップ拡張機能がデータにバインドされ、カウント値が変更されたときにそれに応じて翻訳テキストが更新されるように、カウント値を受け入れるようにするにはどうすればよいですか?

次のように使用する必要があります。

<TextBlock Text="{t:Translate 'import files', {Binding FileCount}}"/>

FileCountのバインディング値が変更されるたびに、TextBlockは変更を反映し、適切な表現を提供するために新しいテキスト値を受け取る必要があります。

私はあそこに似たような解決策を見つけました:http://blogs.microsoft.co.il/blogs/tomershamam/archive/2007/10/30/wpf-localization-on-the-fly-language-selection。 aspxしかし、私がそれをフォローしようとすると、それが何をするのか、なぜそれが機能するのかさえ理解できません。すべてがWPF内で発生しているように見えます。提供されたコードは、WPFを正しい方向にプッシュするだけですが、その方法は不明です。私はそれを適応させて何か役に立つことをすることができません。

実行時に翻訳言語を変更することが役立つかどうかはわかりません。そのためには、別のレベルのバインディングが必要だと思います。複雑さを低く抑えるために、基本バージョンが機能するまではそうしようとはしません。

現時点では、お見せできるコードはありません。それは単にひどい状態にあり、それがする唯一のことは例外を投げるか、何も翻訳しないことです。簡単な例は大歓迎です(この場合、そのようなものが存在する場合)。

4

1 に答える 1

16

気にしないでください、私はついに参照されたコードがどのように機能するかを知り、解決策を思い付くことができました。これがレコードの簡単な説明です。

<TextBlock Text="{t:Translate 'import files', {Binding FileCount}}"/>

これには、MarkupExtensionから継承されたクラスTranslateExtensionが必要であり、コンストラクターは2つのパラメーター(1つはString、もう1つはBinding)を受け入れます。両方の値をインスタンスに保存します。次に、クラスのProvideValueメソッドは、取得したバインディングを使用し、カスタムコンバータインスタンスを追加して、BindingExpressionインスタンスIIRCであるbinding.ProvideValueからの結果を返します。

public class TranslateExtension : MarkupExtension
{
    public TranslateExtension(string key, Binding countBinding)
    {
        // Save arguments to properties
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        countBinding.Converter = new TranslateConverter(key);
        return countBinding.ProvideValue(serviceProvider);
    }
}

コンバーター、たとえばクラスTranslateConverterには、1つのパラメーターであるStringを受け入れるコンストラクターがあります。これは、上記のTranslateExtensionからの私の重要な議論です。後で使用するために記憶します。

カウント値が変更されるたびに(バインディングを介して取得されます)、WPFはその値を新たに要求します。バインディングのソースからコンバーターを経由して、表示されているサーフェスまで歩いているようです。コンバーターを使用することで、バインディングについてまったく心配する必要がなくなります。これは、コンバーターがバインディングの現在の値をメソッド引数として取得し、別のものを返すことが期待されるためです。カウント値(int)in、翻訳されたテキスト(string)out。これは私のコードです。

したがって、数値を定式化されたテキストに適合させるのはコンバーターのタスクです。そのために保存されたテキストキーを使用します。つまり、基本的には逆方向のデータフローが発生します。テキストキーがメイン情報であり、それにカウント値が追加される代わりに、カウント値をプライマリ情報として扱い、テキストキーをサイドパラメータとして使用して全体を作成する必要があります。これは正確には単純ではありませんが、バインディングが主要なトリガーである必要があります。キーは変更されないため、コンバーターのインスタンスに永久に保存できます。また、翻訳されたテキストが出現するたびに、コンバーターの独自のコピーが取得され、それぞれに個別のキーがプログラムされます。

コンバーターは次のようになります。

class TranslateConverter : IValueConverter
{
    private string key;
    public TranslateConverter(string key)
    {
        this.key = key;
    }
    public object Convert(object value, ...)
    {
        return Translator.Translate(key, (int) value);
    }
}

それが魔法です。エラー処理とその他の機能を追加して、解決策を入手してください。

于 2013-02-12T18:41:57.780 に答える