Tim Tepaße: mehrsprachige Texte in Scripten

Beitrag lesen

Hallo Gunnar,

Wie würdet Ihr das implementieren?

Ich würde mich einfach am System von GNU gettext orientieren. In diesem sind Programmierung und Übersetzung stark getrennt, weil man im Prinzip erst nach der Programmierung weiss, welche Strings zu übersetzen sind. Also erstmal in Phase 1 fröhlich drauf los programmieren:

~~~javascript var heading = document.createElement("h1");
  heading.appendChild(document.createTextNode(_("Die Allgemeine Erklärung der
                                                 Menschenrechte")));
  document.body.appendChild(heading);

var article1 = document.createElement("p");
  article1.appendChild(document.createTextNode(_("Alle Menschen sind frei und
           gleich an Würde und Rechten geboren. Sie sind mit Vernunft und
           Gewissen begabt und sollen einander im Geist der Brüderlichkeit
           begegnen.")));
  document.body.appendChild(article1);

  
Beachte, dass ich die Texte in einen unauffälligen Funktionsaufruf eingebettet habe, die Funktion heisst aus Konvention "\_". In Phase 1 tut die erstmal noch nix:  
  
  `var _ = function (text) { return text; }`{:.language-javascript}  
  
Ist die Programmierung der Logik fröhlich abgeschlossen, kommt nun Phase 2, das Extrahieren der Strings. Die billigste – aber nicht serh gute – Version wäre dies hier:  
  
  ~~~javascript
var strings = [];  
  var _ = function (text) { strings.push(text); return text; }

D.h. im Prinzip wird bei jedem Aufruf von _() der jeweilige String in einer Datenstruktur gesammelt. Der Nachteil ist, dass dies aus dem Programm selber geschieht, man weiss also nicht, ob alle Aufrufe von _() überhaupt durch die Programmlogik vorgenommen wird.

Geschickter wäre es, seine Javascript-Datei durch ein anderes Programm analysieren zu lassen. xgettext - das bei GNU gettext benutzt wird - hat offenbar keine Unterstützung für Javascript. Und es hat auch einen Nachteil, dass es seine Übersetzungs-Datenstrukturen in einem Format auswirft, das für Javascript nicht besonders geeignet ist. Ich würde mir wohl ein Skript basteln, dass programmlogik.js mit einen Regulären Ausdruck durchgeht, nach dem Muster „_(" irgendwas ") sucht, das irgendwas extrahiert und als JSON ausspuckt.

Man kann das natürlich auch per Hand machen, hauptsache man hat hinterher ein JSON-Objekt, in dem die verschiedenen Strings der Programmierphase die Schlüsseln sind. Dieses JSON-Objekt liefert nämlich dann die Datenstruktur zum übersetzen:

~~~javascript var translations = {
      "Die Allgemeine Erklärung der Menschenrechte" : {
          de : "Die Allgemeine Erklärung der Menschenrechte",
          en : "Universal Declaration of Human Rights"
      },
      "Alle Menschen sind frei und gleich an Würde und Rechten geboren. Sie sind mit Vernunft und Gewissen begabt und sollen einander im Geist der Brüderlichkeit begegnen." : {
          de : "Alle Menschen sind frei und gleich an Würde und Rechten geboren. Sie sind mit Vernunft und Gewissen begabt und sollen einander im Geist der Brüderlichkeit begegnen.",
          en : "All human beings are born free and equal in dignity and rights. They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood."
      }
  };

  
Und nun kann man die ominöse Unterstrich-Funktion einfach in die Übersetzungsfunktion umwandeln:  
  
  ~~~javascript
var locale = "en";  
  var _ = function (text) { return translations[text][locale] || text; };

Die zu übersetzenden Texte als Schlüssel zu benutzen hat den Vorteil, dass man sich anders als in Deinem Beispiel sich nicht mehr um die jeweilige Struktur kümmern muss. Unzählige Variablen wie "text.en.heading1" sind also überflüssig.

Dies ist natürlich nur so hinskizziert. Idealerweise macht man die Übersetzungsfunktion noch intelligenter, z.B. indem man ihr Unterstützung für Language Tags einbaut, wie ich das hier mal skizziert habe. Die Königsklasse wäre es wohl noch, die Sprache automatisch aus dem Dokument bzw. den Elternelementen zu ermitteln – aber ich glaube nicht, dass das möglich wäre, wenn man nicht das DOM komplett kapselt und in jeder DOM-Einfüge-Funktion die derzeit aktuelle Sprache des Dokumentes zur Verfügung hat. Dieses könnte man dann _() übergeben. Komisch, dass es das noch nicht in den jeweiligen Bibliotheken gibt. ;)

Tim