Frage

, fragte ich eine Frage zuvor, die eine einzige Antwort nur hatte. Ich habe einige Zeit habe jetzt damit spielen, um und einen Plan hat, will aber ein Feedback auf, wenn es eine gute Idee ist.

Das Problem:

Ich möchte eine Komponente, die einen Namen (invariant, verwendet, um die Komponente zu identifizieren) hat seinen Namen in der Anwendung lokalisiert zu haben, die es verbraucht, ohne das Modell des Bauteils mit einem Attribut Displayname verschmutzen. Die Komponente kann in einer separaten DLL existiert und dynamisch zur Laufzeit geladen werden.

mein Gefühl ist, dass die Komponente DLL für die Bereitstellung der lokalisierten Namen verantwortlich sein sollte (dies scheint wie eine gute Kapselung), aber die Anwendung die Komponente raubend sollte für immer / mit dem lokalisierten Namen (die Tatsache verantwortlich, dass die Komponente a hat andere Namen für die Anzeige ist nicht ein Anliegen der Komponente, sondern die ‚Ansicht‘ die Verwendung dieser Komponente)

Die Lösung:

Fügen Sie eine Ressource der Komponenten mit dem gleichen Namen wie die Datei dll die Komponentenklasse in ist. Einen String an die Ressource mit einem Schlüssel hinzufügen, die der Name der Komponente ist.

Bei der Anwendung erhält die lokalisierten Namen wie folgt:

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

Dieser Code wird wahrscheinlich in einer Localiser Klasse gekapselt werden, sondern vermittelt den Punkt. Dies scheint zu funktionieren, aber ist es eine gute Idee, oder gibt es einen besseren / Standard-Weg, dies zu tun?

EDIT:. Ich möchte darauf hinweisen, dass eine Sache, die ich bin mir nicht sicher mit dieser Lösung ist, dass die Ressourcen in einer RESX-Datei sein, die den gleichen Namen wie die Datei hat, dass die Klasse in ist dies macht es funktioniert, wie die Ressource-Datei aus dem Typnamen identifiziert werden. Dies ist das gleiche wie die Lokalisierung für Formulare Arbeit scheint, und macht Visual Studio die .resx als ‚Unterkomponente‘ setzte der CS-Datei, die alle schön scheinen. Aber Visual Studio wirft dann eine Warnung (über eine Ressource bearbeiten, die Teil eines anderen Projektelement ist), wenn ich versuche, und bearbeiten Sie diese Datei, die mich denken lässt, dass es vielleicht eine andere Möglichkeit ist, dass ich soll dies zu tun.

War es hilfreich?

Lösung

Ich glaube, Sie die richtige Idee haben, aber es gibt bessere Art und Weise, dies zu erreichen.

Vermutlich haben Sie eine Schnittstelle, die die steckbaren Komponenten implementiert. Sprich IPluggable:

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

Von Ihrem Haupt binär, laden Sie die steckbare Baugruppe und erstellen Sie die IPluggable Instanz mit Reflexion (ich nehme an das ist, was die GetExternalObject() Methode Sie hat) und dann Zugriff auf den lokalisierten Namen der LocalizedName Eigenschaft. Innerhalb die IPluggable Implementierung erstellen ResourceManager und den Zugang der LocalizedName vom resx dieser steckbaren Baugruppe.

Was Sie erhalten, indem Sie ist eine gute Kapselung des Verhaltens in der steckbaren Baugruppe - es verantwortlich ist, dass Sie den lokalisierten Namen für die Bereitstellung, aber wählt sie es zu tun, ohne Ihren Mann-Programm davon aus, dass ein ResourceManager erstellt werden kann eine lokalisierte zugreifen Name.

Andere Tipps

Ich hatte ein Problem vor einiger Zeit ENUM-Werte von lokalisierende, ich bin nicht sicher, ob es Ihnen Frage beantwortet, aber zumindest gibt Ihnen eine anderen Ansatz im Auge zu haben.

Erste durch die Schaffung von meinem eigenen Localizing Attribut

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

Von dort schaffe ich die ENUM selbst

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

Dann habe ich einen Typ-Wandler, der die LocalizationAttribute Beschreibung Schlüssel und Zugriff auf die Ressourcen-Datei, um die Lokalisierung (Attribut Beschreibung muss den Ressourcenschlüssel passen :)) bekommen holen

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

Schließlich habe ich den Client, der die Typeconverter verwendet, die in diesem Fall ist eine Sammlung

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

ich ursprünglich gepostet diese Lösung auf meinem Blog . Hoffe, es hilft Ihnen aus:)

Das Problem mit der Art und Weise Sie vorgeschlagen haben, ist, dass sein wird schwer sein, die Übersetzungen zu aktualisieren, und es kann sogar ein Programmierer benötigen. Auch, wie wollen Sie Update Übersetzungen, ohne die gesamten Anwendungen zu aktualisieren?

Ich habe eine Menge von übersetzten Anwendungen getan, und was ich getan habe, ist eine separate Textdatei mit translatations so etwas wie dieses formated:

  

[Englisch]
  Done = Fertig

     

[Norwegian]
  Done = Ferdig

Und ich habe eine Funktion namens TranslateForm (), dass ich innen Formular anzeigen Ereignis nennen, die alle die UI-Elemente übersetzen. Die TranslateForm () -Funktion werden die Dinge haben wie

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

Der letzte Teil mit dem TranslateForm ist keine optimale Lösung, denke ich Zeit über i zu einer Lösung migrieren, dass, wenn die Steuerung selbst die Klasse Übersetzen nennt. Der Vorteil dieses Systems besteht darin, dass seine einfach für den programer, können Sie andere ppl Übersetzungen hinzufügen haben, ohne dass Sie danach manuelle Arbeit zu tun haben (Dies ist importent mir, wie ich Gemeinschaft angetrieben Übersetzungen haben), so dass sie oft aktualisiert werden und i möchte keine auf die Zeit verbringen. Ich kann auch die Übersetzungen aktualisieren, während die Anwendung ausgeführt wird, ohne dass die Anwendung, die Aktualisierung neu zu starten oder werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top