Laden...

Lokalisierbarkeit bei Plugins erzwingen

Erstellt von herbivore vor 16 Jahren Letzter Beitrag vor 16 Jahren 1.721 Views
herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 16 Jahren
Lokalisierbarkeit bei Plugins erzwingen

Hallo Community,

folgende Situation: Ein Programm kann Plugins laden. Die Plugins können von unterschiedlichen Autoren stammen. Die Plugins haben einige Properties, über die sie (momentan direkt) Texte in natürlicher Sprache zurückgeben, z.B. eine Beschreibung des Plugin.

Ich möchte nun erzwingen, dass die Plugins lokalisierbar sind und zwar ohne das man den Code des Plugins besitzen muss. Der Plugin-Autor schickt eine DLL und eine andere Person soll das Plugin lokalisieren können.

Welche Ansätze seht ihr da?

herbivore

4.207 Beiträge seit 2003
vor 16 Jahren

Mal doof zurückgefragt - warum nicht wie üblich in .NET mit Hilfe von Ressource-Dateien?

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 16 Jahren

Hallo Golo,

ich gehe mal davon aus, dass die eine Rolle spielen würden. Ich will auch keine neue Art der Lokalisierung erfinden.

Das auch nicht der Kern der Frage. Die Frage ist, wie man die Lokalisierbarkeit erzwingen kann (möglichst ohne die Flexibilität einzuschränken).

herbivore

S
709 Beiträge seit 2005
vor 16 Jahren

Hallo herbivore!

Du willst also, dass der AddIn Autor gar nichts machen muss um sein Plugin lokalisierbar zu machen?

Willst du nur die Beschreibung lokalisieren (die Property ist ja bekannt) oder z.B. auch das UI des Plugins?

Eventuell mit Reflection die Properties zur Laufzeit setzen. Aus einer XML Datei werden die lokalisierten Strings gelesen. Die ID steht für die Property und der Wert wird dann halt gesetzt. Ich weiß aber nicht, wie stark das zu lasen der Performance geht.

vg,
Simon

4.207 Beiträge seit 2003
vor 16 Jahren

Okay, wenn ich Dich richtig verstanden habe, geht es Dir nicht darum, WIE lokalisiert wird, sondern DASS lokalisiert wird ...

Wie wäre es mit einem Interface ILocalizable (oder so ^^), das die Plugins implementieren müssen. Dieses Interface definiert eine Methode, die von der Hauptanwendung am Plugin aufgerufen wird, und den ganzen lokalisierten Krams nachlädt ...

Da das Plugin "weiß", dass diese Methode aufgerufen wird, muss sie bereitgestellt werden, und Du hast sichergestellt, dass dem Autor zumindest bewusst ist, dass er lokalisieren sollte ...

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 16 Jahren

Hallo SimonKnight6600,

Du willst also, dass der AddIn Autor gar nichts machen muss um sein Plugin lokalisierbar zu machen?

Grundsätzlich wäre natürlich schön, wenn der Plugin-Autor möglichst wenig Aufwand mit der für die Lokalisierbarkeit hätte. Ich will vor allem verhindern, dass er die Lokalisierbarkeit verhindert, z.B. indem er String-Literale hardcodiert. 🙂

Willst du nur die Beschreibung lokalisieren (die Property ist ja bekannt) oder z.B. auch das UI des Plugins?

Die Plugins können selbst kein Form erstellen, sondern sagen per Attribut, welche Controls sie brauchen. Auch da soll die Lokalisierbarkeit greifen. Also letztendlich für alle Texte in natürlicher Sprache, die vom Plugin verwendet werden.

Eventuell mit Reflection die Properties zur Laufzeit setzen. Aus einer XML Datei werden die lokalisierten Strings gelesen. Die ID steht für die Property und der Wert wird dann halt gesetzt. Ich weiß aber nicht, wie stark das zu lasen der Performance geht.

Eins der Probleme ist, dass das Plugin an manchen Stellen einen zusammengesetzten String liefern muss. Ein Beispiel könnte sein "12 Treffer von 18787 durchsuchten Themen". Wenn man das Plugin nun einfach einen String zurückgeben lassen würden, dann wäre ja nicht sichergestellt, dass der Autor einfach "Treffer von" und "durchsuchten Themen" als Literale fest codiert hat.

Okay, wenn ich Dich richtig verstanden habe, geht es Dir nicht darum, WIE lokalisiert wird, sondern DASS lokalisiert wird ...

Noch genauer, das sichergestellt ist, dass lokalisiert werden kann.

Wie wäre es mit einem Interface ILocalizable

Mit ist noch nicht ganz klar, wie ILocalizable mit dem existierenden IFilterPlugin verknüpft werden würde. Was für Methoden oder Properties hätte ILocalizable?

herbivore

S
709 Beiträge seit 2005
vor 16 Jahren

Hallo herbivore!

Ich denke, dass dann ein kleiner Aufwand immer nötig ist. Zumindest wüsste ich ansonsten keine Lösung.

vg,
Simon

herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 16 Jahren

Hallo SimonKnight6600,

Ich denke, dass dann ein kleiner Aufwand immer nötig ist.

der Aufwand ist nur ein Nebenkriterium:

Grundsätzlich wäre natürlich schön, wenn der Plugin-Autor möglichst wenig Aufwand mit der für die Lokalisierbarkeit hätte. Ich will vor allem verhindern, dass er die Lokalisierbarkeit verhindert, z.B. indem er String-Literale hardcodiert. 🙂

Zumindest wüsste ich ansonsten keine Lösung.

Ich sehe leider nicht mal mit Aufwand eine Lösung. 🙂

herbivore

S
709 Beiträge seit 2005
vor 16 Jahren

Hallo herbivore!

Eventuell für die Beschreibung etc. das Lesen aus einer XML Datei erzwingen. Soweit ich weiß werden bei dem Filter Programm um das es ja geht eh Xml-Dateien mitgeliefert.

Für die restlichen Strings müsste man sich halt etwas überlegen.

vg,
Simon

2.921 Beiträge seit 2005
vor 16 Jahren

ohne das man den Code des Plugins besitzen muss

Also wenn das wirklich nur eine DLL ist und sonst gar nichts, wüsste ich zuerst mal auch nicht wie.

Mal abgesehen von der in diesem Kontext wohl verrückten und wahrscheinlich völlig schwachsinnigen Idee einen Enhancer zu benutzen.

Der Plugin-Autor schickt eine DLL und eine andere Person soll das Plugin lokalisieren können.

Um das ganze mehr zu konkretisieren, schickt er NUR die DLL? Oder kann z.B. auch eine XML-Datei dabei sein? Weil dann, müsste ja einfach nur die XML-Datei geändert werden.

Gibt es irgendwelche Interfaces die das definieren? So dass man evtl. auch mit Reflection das erledigen könnte?

Ist das SharpDevelop Konzept da evtl. was für Dich?

Gibt es irgendwelche Richtlinien, die sowieso schon eingehalten werden müssen, oder seid ihr da im Entwicklungsteam noch völlig frei? Wie sind da die Rahmenbedingungen?

Was wäre mit einem Aspektorientierten Ansatz, der speziell mit einem Attribut gekennzeichnete Zeichenketten ersetzt?

Enhancer oder Technologien lassen sich vermutlich nicht einsetzen, wenn der Code obfuskiert wird.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 16 Jahren

Hallo dr4g0n76, hallo zusammen,

Also wenn das wirklich nur eine DLL ist und sonst gar nichts, wüsste ich zuerst mal auch nicht wie.

wenn die Lokalisierung mit Satelliten-Assemblies erfolgen würde, dann würde man natürlich eine Plugin-DLL und mindestens eine Satelliten-Assembly erhalten. Wenn die Lokalisierung mit XML-Dateien oder INI-Dateien erfolgen würde, bekäme man natürlich eine Plugin-DLL und mindestens eine XML- bzw. INI-Datei. Vorausgesetzt der Plugin-Programmierer wäre eben zur Lokalisierbarkeit gezwungen.

Eine Möglichkeit ihn zu zwingen wäre, wenn er als Rückgabe einer Property nicht den eigentlichen Text zurückliefern könnte, sondern eine Ressource-Id zurückgeben müsste. Das Hostprogramm würde dann die Ressource mit dieser Id laden und dann diesen geladenen Text verwenden. Das wäre wirklich ein nicht zu umgehender Zwang zur Lokalisierung. Wenn der Plugin-Autor keine vorhandene und passende Ressource-Id liefern würde, würde nicht der von ihm gewünschte Text verwendet werden.

Leider stößt das Konzept auf seine Grenzen, wenn ein zusammengesetzten String oder formatierter String verwendet werden können soll.

Gibt es irgendwelche Interfaces die das definieren?

Ja, es gibt ein IFilterPlugin-Interface, dass der Plugin-Autor implementieren muss.

Gibt es irgendwelche Richtlinien, die sowieso schon eingehalten werden müssen, oder seid ihr da im Entwicklungsteam noch völlig frei?

Nein, im Prinzip vollkommen frei. Allerdings habe ich die Vorstellung, dass man einen Plugin-Autor - ohne Einschränkungen in der Flexibilität - zur Lokalisierung zwingen kann, aufgegeben und das jetzige Konzept basiert darauf, dass man es dem Plugin-Autor einfach sehr leicht macht zu lokalisieren.

Dreh und Angelpunkt des Konzepts ist eine Methode "String GetLocalizedString (String strStringId)". Wie diese genau implementiert ist, sei erstmal dahingestellt. Jedenfalls liefert sie zu einer StringId den zugehörigen String oder Text in der jeweils eingestellten Sprache. Wenn GetLocalizedString den passenden String nicht findet, könnte es den String in der Default-Sprache zurückgeben und wenn es den auch nicht gibt, sollte es "<" + strStringId + ">" zurückgeben. Durch die spitzen Klammern wird angezeigt, dass dies nur ein Platzhalter ist. Das ist sicher während der Entwicklung von Plugins sehr praktisch, weil man gleich sieht, für welche StringId noch die Texte fehlen.

Natürlich kann ein Plugin-Implementierer GetLocalizedString bei Bedarf auch selbst aufrufen, z.B. um einen Formatstring zu laden, in den er noch bestimmte Werte einsetzen will.

Ein Vorteil des Konzepts ist, dass die bisherige Plugin-Schnittstelle komplett unverändert bleiben und wo bisher ein String zurückgegeben wird, wird auch weiterhin der echte String und nicht etwa eine StringId zurückgegeben.

Der Trick ist, dass man eine Basisklasse verwendet, in der die Properties so implementiert sind, dass GetLocalizedString jeweils mit einer standardisierten StringId aufgerufen und das Ergebnis zu rückgeliefert wird. Im Prinzip muss der Plugin-Programmierer also nicht mehr die Properties implementieren, sondern kann die Default-Implementierung übernehmen und muss nur noch in den Ressourcen oder INI-Dateien zu den standardisierten StringIds die entsprechenden Texte ablegen.

Die spanende Frage ist nun, wie GetLocalizedString implementiert werden kann. Und hier zeigt sich ein weiterer Vorteil des Konzepts. GetLocalizedString muss sich gar nicht auf eine einzige Art der Ermittlung von Strings zu StringIds festlegen. Eine Möglichkeit der Zuordnung, die sicher implementiert sein sollte, sind die Sateliten(ressourcen)assemblies. Aber es muss nicht darauf beschränkt bleiben. Viele Programme verwenden das INI-Dateiformat, um Lokalisierung zu erlauben. Dieses Format hat den Vorteil ausgesprochen einfach zu sein und entsprechend wenig Aufwand zu erfordern. Solche Dateien können mit dem TextEditor erstellt und gepflegt werden. Sie erfordern keine Compilierung, sondern müssten einfach nur im Plugin-Verzeichnis vorhanden sein.

So wie LoadAssembly eine Assembly an verschiedenen Orten in einer bestimmten Reihenfolge sucht, kann und sollte GetLocalizedString den passenden Text zu einer StringId ebenfalls in einer bestimmten Reihenfolge suchen. Außer meinen beiden Vorschlägen mit den Satelitenassemblies und den INI-Dateien können jetzt oder später noch weitere Formen lokalisierte Strings zu speichern, berücksichtigt werden.

Ich denke, dass sich dieses Konzept leicht umsetzen lässt, den Plugin-Implementierer nicht einschränkt und ihm trotzdem die Lokalisierbarkeit von Plugins so nahelegt, dass er es mehr Mühe ist, die Lokalisierbarkeit zu vereiteln als sie zu ermöglichen.

Vielen Dank für eure Antworten. Mit diesem Konzept ist zwar keine Lösung auf die Eingangsfrage gefunden, aber zumindest eins, das es dem Plugin-Autor ausreichend nahelegt, die Lokalisierbarkeit nicht zu verbauen.

Wenn ihr Verbesserungsmöglichkeiten sehr, könnt ihr diese natürlich gerne schreiben.

herbivore

S
8.746 Beiträge seit 2005
vor 16 Jahren

Wie wäre es denn, wenn bei du zusammengesetzten Strings du mit Platzhaltern a la String.Format arbeitest? Außer den Platzhaltern nur Sondernzeichen und Whitespaces erlauben.

herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 16 Jahren

Hallo svenson,

naja, die Entscheidung ist doch, ob man die Properties direkt Strings zurückgeben lässt oder RessourcenIds. Im ersten Fall gibt es kein Zwang zur Lokalisierungen und im zweiten Fall fehlt die Flexibilität. Ich sehe nicht, wie dein Vorschlag daran etwas ändert.

Es ist ja nicht nur das Format, dass durch das Plugin festgelegt wird, sondern das Plugin muss auch darüber entscheiden, welche Werte gefüllt werden. Da Properties und nicht Methoden implementiert werden, kann man aber immer nur einen Wert zurückgeben.

herbivore

S
8.746 Beiträge seit 2005
vor 16 Jahren

Original von herbivore
Ich sehe nicht, wie dein Vorschlag daran etwas ändert.

Vielleicht auch zu kurz formuliert. Die Killer-Anforderung ist doch:

Eins der Probleme ist, dass das Plugin an manchen Stellen einen zusammengesetzten String liefern muss. Ein Beispiel könnte sein "12 Treffer von 18787 durchsuchten Themen". Wenn man das Plugin nun einfach einen String zurückgeben lassen würden, dann wäre ja nicht sichergestellt, dass der Autor einfach "Treffer von" und "durchsuchten Themen" als Literale fest codiert hat.

Wenn ich dich richtig verstehe, liefert das PlugIn nur "Textinformationen" an den Core. Wenn ich das richtig verstanden habe, müßte man eigentlich komplett auf den Typ String verzichten. Stattdessen vielleicht einen Typ LocalizedString erstellen, der es nur erlaubt, sowas zu definieren:

"12 {46} 18787 {47}"

wobei {46} die RessourceID von "Treffer von" und {47} von "durchsuchten Themen" bedeutet. Der Core führt dann die Termersetzung durch.

Allerdings wird mir beim Hinschreiben klar, dass der Ansatz aufgrund von Grammatik-Problemen nicht weit trägt. Das PlugIn muss wissen, welches Sprache eingestellt ist, um verschiedenen Grammatik-Varianten anbieten zu können. Letztlich aber kaum vermeidbar, da nur das PlugIn selbst die Text-Semantik kennt.

herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 16 Jahren

Hallo svenson,

ok, jetzt verstehe ich, worauf du hinaus willst. Das Problem ist - neben dem von dir erkannten - allerdings, dass für die Platzhalter (Konfigurations-)Informationen aus dem Plugin eingesetzt werden müssen. Die Situation wäre also eher andersherum, also dass man aus den Ressourcen eine lokalisierten String lädt und in die Platzhalter die (Konfigurations-)Informationen einsetzt. Der Formatstring wäre also je nach Sprache z.B. "Pattern: {0}" oder "Textmuster: {0}" und für {0} würde dann der im Plugin eingestellte Pattern eingesetzt.

Aber das ist auch nicht so schlimm: Ich bin eigentlich ganz glücklich mit dem oben beschriebenen Konzept mit dem GetLocalizedString & Co. Das zwingt den Autor zwar nicht zur Lokalisierbarkeit, aber legt sie ihm doch ausreichend nahe. Wenn er dann doch noch String-Literale in einer bestimmten Sprache hardcodiert ist es halt Pech.

herbivore