template

Index :: Javascript :: Multilinguale Site

Siehe auch: Anhang :: Multilinguale Site (Mechanismen zur Sprachauswahl)

Eine Implementierung in reinem Javascript bietet folgende Vorteile:
Die Tatsache, dass jede Seite ihre individuellen Resourcen enthält, bedeutet natürlich, dass die Bearbeitung nicht zentral erfolgen kann, wie etwa bei einer Datenbank. Wenn also einer bestehenden Applikation z.B. eine neue Sprache hinzugefügt werden soll, müssen alle Dokumente editiert werden. Dies ist aber eher ein Ausnahmefall, denn normalerweise entscheidet es sich schon während der Entwicklungsphase eines Projekts, wieviele und welche alternativen Sprachen zur Auswahl stehen sollen.

Da der Quellcode einer Seite hier immer alle Sprachen enthält, existiert eine gewisse Redundanz, denn effektiv wird ja nur 1 Sprache davon benötigt. Man könnte das als Nachteil ansehen, weil das Volumen der Seite unnötig groß werden kann. Andererseits sind selten mehr als 2 Sprachen vorhanden, und auch der Umfang multilingualer Textabschnitte ist in interaktiven Formular-Dokumenten, die schnell geladen werden müssen, eher gering (im Gegensatz zu passiven Hilfeseiten oder reinen Text-Dokumenten - bei denen die Ladezeit aber wiederum nicht so kritisch ist).

In dieser Demo ist die Sprache des Kastens durch Anklicken des entsprechenden Flaggensymbols umschaltbar:

...
.

:





Die (hier 3-sprachige) Resource liegt in Form eines einfachen String-Arrays vor, wobei jeweils 3 aufeinanderfolgende Elemente (in deutsch, englisch und französisch) einen Datensatz bilden.
Sicherheitshalber sollten alle Sonderzeichen als Hexwert notiert werden, z.B. ä als \xE4, é als \xE9 oder ç als \xE7 - notfalls in der Unicode-Notation wie beim -Zeichen (\u20AC).

In der globalen Variablen LangID [0...N-1] wird die aktuelle SprachenID gespeichert. Ihre Initialisierung erfolgt beim Laden der Seite durch Auslesen eines entsprechenden Cookie-Wertes. Ist noch kein Cookie vorhanden, wird die SprachenID auf den Default-Wert 0 gesetzt, womit die erste Sprache aktiviert wird, also Deutsch.

Die Flaggensymbole für die Sprachauswahl sind Images, bei denen das onClick-Event abgefangen und auf die Funktion SetLang() umgeleitet wird. Diese benötigt als Parameter eine SprachenID. Unterscheidet sie sich von der aktuellen, wird die neue SprachenID ins Cookie geschrieben und die Seite geupdatet.


Textknoten ersetzen

Im HTML-Code des Dokuments werden an den multilingualen Stellen die benötigten Textfragmente mithilfe der Funktion WRSC() direkt eingesetzt. Sie benötigt als Parameter eine ResourceID [0...N] und holt sich den passenden String über die Funktion RSC(), welche ihrerseits anhand von ResourceID und SprachenID den korrekten Offset ins Resource-Array berechnet und das gewünschte String-Element zurückliefert.

Damit eine Aktualisierung durchgeführt werden kann, müssen alle multilingualen Stellen per DOM auffindbar sein. Deshalb sind sie jeweils von einem SPAN umschlossen, welcher eine charakteristische ID (zusammengesetzt aus 'RID' und der ResourceID) besitzt.
Mittels document.getElementsByTagName('span') erhält man ein Array mit allen SPAN-Tags der Seite. In einer Schleife kann nun jeder SPAN geprüft werden: hat er eine ID, die mit 'RID' beginnt, dann steht im Rest der ID die ResourceID; der SPAN wird per removeChild() geleert und erhält per appendChild() einen neuen Textknoten mit benötigtem Inhalt (geliefert von RSC() gemäß ResourceID).

Hier der relevante Quellcode - die multilingualen Stellen im BODY sind mit einem grünen Rahmen gekennzeichnet:
Javascript im Header
var Lang=[ 'Bitte w\xE4hlen Sie...','Please select...','Veuillez choisir...',//0
...
... weitere Zeilen für Resource ID 1 bis 5 ...
...
'Er fa\xDFt ihn sicher,...','He holds him sure...','Il l\xB4embrasse s\xFBr,...',//6 '']; var LangID=parseInt(CooGet('LangID')||0); function RSC(rid) { return Lang[rid*3+LangID]; } function WRSC(rid) { document.write(RSC(rid)); } function SetLang(lid) { if (lid==LangID) return; document.cookie='LangID='+(LangID=lid); var i,o,s=document.getElementsByTagName('span'),n=s.length; for (i=0;i<n;i++) if ((o=s[i]).id&&o.id.substr(0,3)=='RID') { while (o.firstChild) o.removeChild(o.firstChild); o.appendChild(document.createTextNode(RSC(o.id.slice(3)))); }} function CooGet(key) { var c=document.cookie,s=key+'=',val='',p; if ((p=c.indexOf(s))>-1) { p+=s.length; var p2=c.indexOf(';',p); if (p2<0) p2=c.length; val=unescape(c.substring(p,p2)); } return val; }
Weiter unten, im BODY:
<table align='center' width='50%' bgcolor='#A0A0A0' cellspacing='1' cellpadding='2'><tr bgcolor='#F0F0F0'> <td align='right'><span id='RID0'><SCRIPT>WRSC(0)</SCRIPT></span>... <img src='img/flgde.gif' onClick='SetLang(0)' style='CURSOR:pointer'> <img src='img/flgen.gif' onClick='SetLang(1)' style='MARGIN-LEFT:2;CURSOR:pointer'> <img src='img/flgfr.gif' onClick='SetLang(2)' style='MARGIN-LEFT:2;CURSOR:pointer'></td> </tr><tr bgcolor='#FFFFFF'> <td><i><span id='RID1'><SCRIPT>WRSC(1)</SCRIPT></span>.</i><br> <br> <font color='#909090'><span id='RID2'><SCRIPT>WRSC(2)</SCRIPT></span>:</font><br> <br> <div align='center'><span id='RID3'><SCRIPT>WRSC(3)</SCRIPT></span><br> <span id='RID4'><SCRIPT>WRSC(4)</SCRIPT></span><br> <span id='RID5'><SCRIPT>WRSC(5)</SCRIPT></span><br> <span id='RID6'><SCRIPT>WRSC(6)</SCRIPT></span></div></td> </tr></table>

Title-Attribute ersetzen

Oft betrifft die Sprachumschaltung nicht nur Textknoten sondern auch title-Attribute, d.h. Tooltips für Bilder, Formularfelder, Buttons, Zellen, u.s.w.

Da also ausser SPAN-Tags auch andere Elemente aktualisiert werden müssen, scannen wir das Dokument kurzerhand nach allen Elementen mit einer ID des Formats 'RID*'. Handelt es sich um einen SPAN, dann ersetzen wir seinen Textknoten; handelt es sich um ein anderes Element, dann ersetzen wir sein title-Attribut.
Die rekursive Abarbeitung aller Kindknoten wird dabei von der Funktion UpdateRSC() erledigt, die als Parameter das zu prüfende Objekt benötigt. Als Einstiegspunkt wird ihr von der Funktion SetLang() das BODY-Objekt übergeben.

Damit in obigem Beispiel die Tooltips der Flaggensymbole in der aktuellen Sprache erscheinen, wird das Resource-Array entsprechend erweitert.
Die Funktion SetLang() wird etwas schlanker, denn für die Hauptarbeit ist nun UpdateRSC() zuständig.
var Lang=[
...
... Zeilen für Resource ID 0 bis 6 ...
...
'deutsch','german','allemand',//7 'englisch','english','anglais',//8 'französisch','french','français',//9 ''];
...
function SetLang(lid) { if (lid==LangID) return; document.cookie='LangID='+(LangID=lid); UpdateRSC(document.getElementsByTagName('body')[0]); } function UpdateRSC(o) { if (o.id&&o.id.substr(0,3)=='RID') { var rid=parseInt(o.id.slice(3)); if (o.nodeName.toUpperCase()=='SPAN') { while (o.firstChild) o.removeChild(o.firstChild); o.appendChild(document.createTextNode(RSC(rid))); } else o.title=RSC(rid); } return; } var c=o.childNodes.length; while (c) UpdateRSC(o.childNodes[--c]); }
...
Unsere Flaggen-Images benötigen jeweils noch eine ID und einen SCRIPT-Block zur Initialisierung:
<img id='RID7' src='img/flgde.gif' onClick='SetLang(0)' style='CURSOR:pointer'>
<SCRIPT>document.getElementById('RID7').title=RSC(7);</SCRIPT>
<img id='RID8' src='img/flgen.gif' onClick='SetLang(1)' style='MARGIN-LEFT:2;CURSOR:pointer'>
<SCRIPT>document.getElementById('RID8').title=RSC(8);</SCRIPT>
<img id='RID9' src='img/flgfr.gif' onClick='SetLang(2)' style='MARGIN-LEFT:2;CURSOR:pointer'>
<SCRIPT>document.getElementById('RID9').title=RSC(9);</SCRIPT>

Index :: Javascript


template