4

以前、答えが 1 つしかない質問をしました。私は今これをいじって計画を立てる時間がありましたが、それが良いアイデアであるかどうかについてのフィードバックが欲しい.

問題:

コンポーネントのモデルを DisplayName 属性で汚染することなく、名前 (コンポーネントを識別するために使用される不変) を持つコンポーネントの名前を、それを消費するアプリケーションでローカライズする必要があります。コンポーネントは別の dll に存在し、実行時に動的にロードされる場合があります。

私の感じでは、コンポーネント dll はローカライズされた名前を提供する責任があるべきですが (これは良いカプセル化のようです)、コンポーネントを消費するアプリケーションはローカライズされた名前を取得/使用する責任があるはずです (コンポーネントが別の名前を持っているという事実)。表示目的はコンポーネントの問題ではなく、そのコンポーネントを使用する「ビュー」の問題です)

ソリューション:

コンポーネント クラスが含まれるファイルと同じ名前のコンポーネント dll にリソースを追加します。コンポーネントの名前であるキーを使用して文字列をリソースに追加します。

アプリケーションで、次のようにローカライズされた名前を取得します。

ExternalObject obj = GetExternalObject ();            
ResourceManager manager = new ResourceManager (obj.GetType ());
string localisedName= manager.GetString (obj.Name);

このコードはおそらく Localiser クラスにカプセル化されますが、ポイントを伝えます。これはうまくいくようですが、それは良い考えですか、それともこれを行うためのより良い/より標準的な方法はありますか?

編集:このソリューションでよくわからないことの1つは、クラスが含まれているファイルと同じ名前の.resxファイルにリソースが含まれている必要があることです。これにより、機能します。タイプ名からリソースファイルを識別できるためです。これは、フォームのローカリゼーションが機能しているように見えるのと同じで、Visual Studio に .cs ファイルの「サブコンポーネント」として .resx を配置させます。しかし、このファイルを編集しようとすると、Visual Studio は (別のプロジェクト アイテムの一部であるリソースの編集に関する) 警告をスローします。

4

3 に答える 3

1

あなたは正しい考えを持っていると思いますが、これを達成するためのより良い方法があります。

おそらく、プラガブルコンポーネントが実装するインターフェイスがあります。言う、IPluggable:

interface IPluggable {
    ...
    string LocalizedName {get;}
    ...
}

メインのバイナリから、プラガブルアセンブリをロードし、リフレクションを使用してIPluggableインスタンスを作成し(これがGetExternalObject()あなたの方法だと思います)、プロパティを使用してローカライズされた名前にアクセスしLocalizedNameます。IPluggable実装内で、を作成し、そのプラガブルアセンブリのresxからにResourceManagerアクセスします。LocalizedName

あなたがすることによって得られるのは、プラグ可能なアセンブリでの動作の適切なカプセル化です-それはあなたにローカライズされた名前を提供する責任があります、しかしそれはあなたのmanプログラムResourceManagerがローカライズされた名前にアクセスするために作成できると仮定することなくそれをすることを選択します。

于 2009-10-13T20:29:34.213 に答える
0

列挙型の値をローカライズするのに少し前に問題がありました。それがあなたの質問に答えるかどうかはわかりませんが、少なくとも覚えておくべき別のアプローチを提供します。

独自のローカライズ属性を作成することから始めました

/// <SUMMARY>
/// Attribute used for localization. Description field should contain a reference to the Resource file for correct localization
/// </SUMMARY>
public class LocalizationAttribute : Attribute
{
    public LocalizationAttribute(string description)
    {
        this._description = description;
    }

    private string _description;
    /// <SUMMARY>
    /// Used to reference a resource key
    /// </SUMMARY>
    public string Description
    {
        get
        {
            return this._description;
        }
    }
}

そこから列挙型自体を作成します

[TypeConverter(typeof(EnumToLocalizedString))]
public enum ReviewReason
{
    [LocalizationAttribute("ReviewReasonNewDocument")]
    NewDocument = 1,


    [LocalizationAttribute("ReviewReasonInternalAudit")]
    InternalAudit = 2,


    [LocalizationAttribute("ReviewReasonExternalAudit")]
    ExternalAudit = 3,


    [LocalizationAttribute("ReviewReasonChangedWorkBehaviour")]
    ChangedWorkBehaviour = 4,


    [LocalizationAttribute("ReviewReasonChangedWorkBehaviourBecauseOfComplaints")]
    ChangedWorkBehaviourBecauseOfComplaints = 5,


    [LocalizationAttribute("ReviewReasonMovedFromOlderSystem")]
    MovedFromOlderSystem = 6,


    [LocalizationAttribute("ReviewReasonPeriodicUpdate")]
    PeriodicUpdate = 7,


    [LocalizationAttribute("ReviewReasonDocumentChanged")]
    DocumentChanged = 8
}

次に、LocalizationAttribute記述キーをフェッチし、リソースファイルにアクセスしてローカリゼーションを取得する型コンバーターを作成しました(属性記述はリソースキーと一致する必要があります:))

public class EnumToLocalizedString : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return (sourceType.Equals(typeof(Enum)));
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return (destinationType.Equals(typeof(String)));
        }

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            return base.ConvertFrom(context, culture, value);
        }

        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (!destinationType.Equals(typeof(String)))
            {
                throw new ArgumentException("Can only convert to string.", "destinationType");
            }
            if (!value.GetType().BaseType.Equals(typeof(Enum)))
            {
                throw new ArgumentException("Can only convert an instance of enum.", "value");
            }

            string name = value.ToString();
            object[] attrs = value.GetType().GetField(name).GetCustomAttributes(typeof(LocalizationAttribute), false);
            if (attrs.Length != 1  !(attrs[0] is LocalizationAttribute))
            {
                throw new ArgumentException("Invalid enum argument");
            }
            return Handbok.Code.Resources.handbok.ResourceManager.GetString(((LocalizationAttribute)attrs[0]).Description);
        }
    }

最後に、TypeConverterを使用するクライアントを作成しました。この場合はコレクションです。

public class ReviewReasonCollection
{
    private static Collection<KEYVALUEPAIR<REVIEWREASON,>> _reviewReasons;

    public static Collection<KEYVALUEPAIR<REVIEWREASON,>> AllReviewReasons
    {
        get
        {
            if (_reviewReasons == null)
            {
                _reviewReasons = new Collection<KEYVALUEPAIR<REVIEWREASON,>>();
                TypeConverter t = TypeDescriptor.GetConverter(typeof(ReviewReason));

                foreach (ReviewReason reviewReason in Enum.GetValues(typeof(ReviewReason)))
                {
                    _reviewReasons.Add(new KeyValuePair<REVIEWREASON,>(reviewReason, t.ConvertToString(reviewReason)));
                }
            }
            return _reviewReasons;
        }
    }
}

私はもともとこのソリューションをブログに投稿しました。それがあなたを助けることを願っています:)

于 2009-10-13T13:10:57.133 に答える
-1

あなたが提案した方法の問題は、翻訳を更新するのが難しくなり、プログラマーが必要になることさえあるということです. また、アプリケーション全体を更新せずに翻訳を更新するにはどうすればよいですか?

私は多くの翻訳されたアプリケーションを作成しました。私が行ったのは、次のような形式の翻訳を含む別のテキスト ファイルを作成することです。

[日本語]
Done=Done

[ノルウェー語]
Done=フェルディグ

そして、フォーム表示イベント内で呼び出す TranslateForm() という関数があり、すべての UI 要素を変換します。TranslateForm() 関数には次のようなものがあります

buttonDone.Text = Translate.GetTranslation("Done");

TranslateForm の最後の部分は最適なソリューションではありません。時間の経過とともに、コントロール自体が Translate クラスを呼び出すソリューションに移行すると思います。このシステムを使用する利点は、プログラマーにとって簡単なことです。後で手作業を行うことなく、他の人に翻訳を追加してもらうことができます (コミュニティ主導の翻訳があるので、これは私にとって重要です)。したがって、頻繁に更新され、私はそれに時間を費やしたくありません。アプリケーションを再起動したり更新したりすることなく、アプリケーションの実行中に翻訳を更新することもできます。

于 2009-10-13T12:27:14.577 に答える