c++ - Bester Weg für die Lokalisierung von Strings




windows mfc localization (7)

Ihre Lösung ist der Unix / Linux " gettext " -Lösung sehr ähnlich. In der Tat müssten Sie die Extraktionsroutinen nicht schreiben.

Ich bin mir nicht sicher, warum das _RESTRING-Makro mehrere Argumente behandeln soll. Mein Code (unter Verwendung von wxWidgets 'support for gettext) sieht so aus: MyString.Format(_("Some string with variable %ls"), _("variable")); .. Das heißt, String :: Format (...) erhält zwei einzeln übersetzte Argumente. Im Nachhinein wäre Boost :: Format besser gewesen, aber es würde auch boost::format(_("Some string with variable %1")) % _("variable"); erlauben boost::format(_("Some string with variable %1")) % _("variable");

(Wir verwenden das _() Makro zur Kürze)

Das ist eine allgemeine Frage, offen für Meinungen. Ich habe versucht, einen guten Weg für die Lokalisierung von String-Ressourcen für eine Windows MFC-Anwendung und verwandte Dienstprogramme zu entwerfen. Meine Wunschliste ist:

  • Muss Zeichenfolgenliterale im Code beibehalten (im Gegensatz zum Ersetzen durch Makro #define-Ressourcen-IDs), damit die Nachrichten noch inline lesbar sind
  • Muss lokalisierte String-Ressourcen zulassen (duh)
  • Darf keine zusätzlichen Laufzeitumgebungsbeschränkungen auferlegen (zB: Abhängigkeit von .NET, etc.)
  • Sollte minimale Eindringlichkeit in bestehenden Code haben (je weniger Modifikation desto besser)
  • Sollte debugbar sein
  • Generiert Ressourcendateien, die mit gängigen Tools bearbeitet werden können (dh: gemeinsames Format)
  • Verwenden Sie keine Copy / Paste-Kommentar-Blöcke, um Literal-Strings im Code oder irgendetwas anderes zu speichern, das das Potential für die Desynchronisation schafft
  • Wäre nett, statische (Kompilierungszeit) Überprüfung zu erlauben, dass jeder "notierte" String in der / den Ressource-Datei (en) ist
  • Es wäre schön, ein sprachspezifisches Ressourcen-String-Pooling zu ermöglichen (für Komponenten in verschiedenen Sprachen, zB: native C ++ und .NET)

Ich habe einen Weg, der alle meine Wunschliste bis zu einem gewissen Grad erfüllt, außer für die statische Überprüfung, aber ich musste ein bisschen benutzerdefinierten Code entwickeln, um es zu erreichen (und es hat Einschränkungen). Ich frage mich, ob jemand dieses Problem besonders gut gelöst hat.

Edit: Die Lösung, die ich momentan habe, sieht so aus:

ShowMessage( RESTRING( _T("Some string") ) );
ShowMessage( RESTRING( _T("Some string with variable %1"), sNonTranslatedStringVariable ) );

Ich habe dann ein benutzerdefiniertes Dienstprogramm, um die Zeichenfolgen innerhalb der 'RESTRING'-Blöcke zu analysieren und sie in eine RESX-Datei für die Lokalisierung und ein separates C # COM-Objekt zu platzieren, um sie aus lokalisierten Ressourcendateien mit Fallback zu laden. Wenn das C # -Objekt nicht verfügbar ist (oder nicht geladen werden kann), greife ich auf die Zeichenfolge im Code zurück. Das Makro wird zu einer Vorlagenklasse erweitert, die das COM-Objekt aufruft und die Formatierung usw. ausführt.

Wie auch immer, ich dachte, es wäre nützlich, das hinzuzufügen, was ich jetzt als Referenz habe.


Wir verwenden die englische Zeichenfolge als ID.

Wenn das Nachschlagen aus dem internationalen Ressourcenobjekt fehlschlägt (das von der installierten I18N-DLL geladen wird), wird standardmäßig die ID-Zeichenfolge verwendet.

Code sieht aus wie:

doAction(I18N.get("Press OK to continue"));

Als Teil der Build-Prozesse haben wir ein Perl-Skript, das alle Quellen nach String-Konstanten parst. Es erstellt eine temporäre Datei aller Strings in der Anwendung und vergleicht diese dann mit den Ressourcenstrings in den einzelnen lokalen Strings, um festzustellen, ob sie vorhanden sind. Alle fehlenden Strings erzeugen eine E-Mail an das entsprechende Übersetzungsteam.

Wir können mehrere DLL für jeden lokalen haben. Der Name der DLL basiert auf RFC 3066
Sprache [_territory] [. Codeset] [@ Modifikator]

Wir versuchen, das Gebietsschema aus der Maschine zu extrahieren und so spezifisch wie möglich zu sein, wenn wir die I18N-dll laden, aber auf weniger spezifische lokale Variationen zurückgreifen, wenn die spezifischere Version nicht vorhanden ist.

Beispiel:

In Großbritannien: Wenn das lokale en_DE.UTF-8 war
(Ich benutze den Begriff dll locker nicht im spezifischen Windows Sinn).

Suchen Sie zuerst nach der I18N.en_GB.UTF-8- DLL. Wenn diese DLL nicht existiert, können Sie auf I18N.en_GB zurückgreifen . Wenn diese DLL nicht existiert, zurück zu I18N.en Wenn diese DLL nicht vorhanden ist, fallen Sie auf I18N.default zurück.

Die einzige Ausnahme von dieser Regel ist: Vereinfachtes Chinesisch (zh_CN), wobei der Fallback US-Englisch ist (en_US). Wenn das Gerät kein vereinfachtes Chinesisch unterstützt, ist es unwahrscheinlich, dass es volles Chinesisch unterstützt.


Ich weiß nicht viel darüber, wie dies normalerweise unter Windows geschieht, aber die Art und Weise, wie lokalisierte Zeichenketten in Apples Cocoa-Framework behandelt werden, funktioniert ziemlich gut. Sie haben eine sehr einfache Textformatdatei, die Sie an einen Übersetzer senden können, und einige Präprozessor-Makros, um die Werte aus den Dateien abzurufen.

In Ihrem Code sehen Sie die Zeichenfolgen in Ihrer Muttersprache und nicht als undurchsichtige IDs.


Der einfache Weg besteht darin, nur String-IDs in Ihrem Code zu verwenden - keine literalen Strings. Sie können dann für jede Sprache verschiedene Versionen der Datei .rc erstellen und entweder DLLs für Ressourcen oder einfach nur unterschiedliche Sprachversionen erstellen.

Es gibt ein paar Shareware utilstohelp, die die rc-Datei lokalisieren, die die Größe der Dialogelemente für Sprachen mit längeren Wörtern behandelt und vor fehlenden Übersetzungen warnt.

Ein komplizierteres Problem ist die Wortreihenfolge, wenn Sie mehrere Zahlen in einem printf haben, die für die Grammatik der verschiedenen Sprachen in einer anderen Reihenfolge sein müssen. Es gibt einige erweiterte printf-Klassen in Codeproject, mit denen Sie Dinge wie printf ("word% 1s und% 2s", var1, var2) angeben können, sodass Sie bei Bedarf auch% 1s und% 2s wechseln können.


In einem Projekt, das ich in mehr als 10 Sprachen lokalisiert hatte, habe ich alles, was lokalisiert werden sollte, in eine einzige dll-Datei mit nur einer Ressource geschrieben. Zur Installationszeit hat der Benutzer ausgewählt, welche DLL mit ihrer Anwendung installiert wurde.

Ich musste nur die englische DLL an das Lokalisierungsteam liefern. Sie haben mir für jede Sprache, die ich in den Build aufgenommen habe, eine lokalisierte DLL zurückgegeben.

Ich weiß, es ist nicht perfekt, aber es hat funktioniert.


Sie möchten ein fortgeschrittenes Dienstprogramm, das ich schon immer schreiben wollte, aber nie die Zeit dazu hatte. Wenn Sie ein solches Tool nicht finden, können Sie auf meine Wrapper-Klassen CMsg () und CFMsg () zurückgreifen, die es erlauben, Strings sehr einfach aus der Ressourcentabelle zu ziehen. (CFMsg bietet sogar einen FormatMessage-Einzeilen-Wrapper. Und ja, in Ermangelung dieses Werkzeugs, nach dem Sie suchen, ist es eine gute Lösung, eine Kopie des Strings im Kommentar zu behalten. Bezüglich der Desynchronisation des Kommentars denken Sie daran, dass String-Literale sehr selten geändert.

http://www.codeproject.com/KB/string/stringtable.aspx

BTW, native Win32-Programme und .NET-Programme haben eine völlig andere Ressourcenverwaltung. Sie werden es schwer haben, eine gemeinsame Lösung für beide zu finden.


Vielleicht haben die Programmierer so etwas gedacht ...

!! myAnswer ist boolesch. Im Kontext sollte es boolean werden, aber ich liebe es einfach, Dinge zu knallen, um sicher zu gehen, denn es war einmal ein mysteriöser Bug, der mich biss, und Bang, ich tötete ihn.







c++ windows mfc localization