سؤال

سألت أ سؤال سابقا الذي كان فقط إجابة واحدة. كان لدي بعض الوقت للعب مع هذا الآن ولدي خطة ، لكنني أريد بعض التعليقات حول ما إذا كانت فكرة جيدة.

المشكلة:

أريد مكونًا له اسم (ثابت ، يستخدم لتحديد المكون) لإجراء اسمه في التطبيق الذي يستهلكه ، دون تلويث نموذج المكون باستخدام سمة الاسم العرض. قد يوجد المكون في DLL منفصل ويتم تحميله ديناميكيًا في وقت التشغيل.

شعوري هو أن المكون DLL يجب أن يكون مسؤولاً عن توفير الاسم المترجمة (يبدو هذا التغليف الجيد) ، ولكن يجب أن يكون التطبيق الذي يستهلك المكون مسؤولاً عن الحصول على/استخدام الاسم المترجمة (حقيقة أن المكون له اسم مختلف لـ أغراض العرض ليس مصدر قلق للمكون ، ولكن من "العرض" باستخدام هذا المكون)

الحل:

أضف موردًا إلى مكونات DLL بنفس اسم الملف الذي يوجد فيه فئة المكون. أضف سلسلة إلى المورد باستخدام مفتاح وهو اسم المكون.

في التطبيق ، احصل على الاسم الموضعي مثل ذلك:

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

من المحتمل أن يتم تغليف هذا الرمز في فئة Localiser ، ولكنه ينقل النقطة. يبدو أن هذا يعمل ، لكن هل هي فكرة جيدة ، أم أن هناك طريقة أفضل/أكثر قياسية للقيام بذلك؟

تحرير: يجب أن أشير إلى أن الشيء الوحيد الذي لست متأكدًا من هذا الحل هو أن الموارد يجب أن تكون في ملف .resx الذي له نفس اسم الملف الذي يعمل فيه الفصل. هذا يجعله يعمل ، كما يمكن تحديد ملف المورد من اسم النوع. هذا هو نفس التوطين في النماذج يبدو أنه يعمل ، ويجعل Visual Studio يضع .resx باعتباره "مكونًا فرعيًا" لملف .CS ، والذي يبدو كله لطيفًا. لكن Visual Studio بعد ذلك يلقي تحذيرًا (حول تحرير مورد جزء من عنصر مشروع آخر) إذا حاولت تحرير هذا الملف ، مما يجعلني أعتقد أنه ربما يكون هناك طريقة أخرى من المفترض أن أقوم بذلك.

هل كانت مفيدة؟

المحلول

أعتقد أن لديك الفكرة الصحيحة ، ولكن هناك طريقة أفضل لإنجاز هذا.

من المفترض أن يكون لديك واجهة ينفذها المكون القابل للتجميع. قل ، ipluggetable:

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

من ثنائي الرئيسي ، قم بتحميل التجميع القابل للتوصيل وقم بإنشاء مثيل قابل للانتقال باستخدام الانعكاس (أفترض أن هذا ما هو GetExternalObject() الطريقة التي لديك) ثم الوصول إلى الاسم المترجمة باستخدام LocalizedName منشأه. داخل تطبيق iPluggetable ، إنشاء أ ResourceManager والوصول إلى LocalizedName من Resx من تلك التجميع القابلة للتوصيل.

ما تحصل عليه من خلال القيام به هو التغليف الجيد للسلوك في التجميع القابل للتراكم - إنه مسؤول عن تزويدك بالاسم الموضع ResourceManager يمكن إنشاء للوصول إلى اسم محلي.

نصائح أخرى

لقد واجهت مشكلة منذ بعض الوقت في توطين قيم التعداد ، لست متأكدًا مما إذا كان يجيب على سؤالك ، ولكن على الأقل يمنحك طريقة أخرى في الاعتبار.

بدأت بإنشاء سمة الترجمة الخاصة بي

/// <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
}

ثم قمت بإنشاء محول نوع سيحضر مفتاح وصف التوطين والوصول إلى ملف المورد للحصول على التوطين (يجب أن يتطابق وصف السمة مع مفتاح الموارد :))

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;
        }
    }
}

أنا في الأصل نشر هذا الحل على مدونتي. أتمنى أن يساعدك ذلك :)

المشكلة في الطريقة التي اقترحتها هي أنه سيكون من الصعب تحديث الترجمات ، وقد تتطلب حتى مبرمج. أيضًا كيف ستقوم بتحديث الترجمات دون تحديث التطبيقات بأكملها؟

لقد فعلت الكثير من التطبيقات المترجمة ، وما فعلته هو أن يكون لديك ملف نصي منفصل مع ترجمة شكلت شيء من هذا القبيل:

إنجليزي
تم = القيام به

النرويجية
تم = ferdig

ولدي دالة تسمى TranslateForm () التي أسميها Inside Form Show Event ، والتي ستترجم جميع عناصر واجهة المستخدم. وظيفة الترجمة () سيكون لها أشياء مثل

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

الجزء الأخير مع TranslateForm ليس حلًا مثاليًا ، أعتقد مع مرور الوقت أنني سأهاجر إلى حل حيث يطلق على التحكم نفسه فئة الترجمة. ميزة استخدام هذا النظام هي أنه بسيط بالنسبة للبرنامج ، يمكنك الحصول على ترجمات أخرى لـ PPL دون الاضطرار إلى القيام بعمل يدوي بعد ذلك (هذا هو الأهمية بالنسبة لي لأن لدي ترجمات مدفوعة بالمجتمع) ، لذلك يتم تحديثها في كثير من الأحيان وأنا لا تريد قضاء بعض الوقت في ذلك. يمكنني أيضًا تحديث الترجمات أثناء تشغيل التطبيق ، دون الحاجة إلى إعادة التشغيل أو تحديثه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top