Redneck Engineering
i18n and L10n with DHTML
 .
Index

Für diese Seite gibt es noch keine deutsche Übersetzung.

i18n and L10n with DHTML

i18n und L10n mit DHTML

This article describes how to implement i18n (internatinalization) and L10n (localization) on websites with HTML, CSS and JavaScript.

HTML

We use the HTML-attribute lang to define an element's language.


<p lang="en">Hello world!</p>
<p lang="de">Hallo Welt!</p>

The <body>'s lang attribute is used to set the displayed language. In runtime we change the attribute with JavaScript (document.body.lang = 'de';).

Furthermore we need control elements to select the language. One solution is to use anchor-tags.


<a href="javascript:setLang('en');">english</a>
<a href="javascript:setLang('de');">deutsch</a>

CSS

We include the following CSS style rules either via the <style>-tag or through a linked, external file.

First we define a rule to hide each and every element inside the body with a language attribute set. Thereafter we define rules using the :lang pseudo-class to display elements depending on the selected language.


body *[lang] {display: none;}

body:lang(en) h1:lang(en),
body:lang(en) h2:lang(en),
body:lang(en) h3:lang(en),
body:lang(en) h4:lang(en),
body:lang(en) h5:lang(en),
body:lang(en) h6:lang(en),
body:lang(en) p:lang(en),
body:lang(en) div:lang(en)
{display:block;}

body:lang(en) span:lang(en),
body:lang(en) a:lang(en),
body:lang(en) img:lang(en)
{display:inline;}

body:lang(de) h1:lang(de),
body:lang(de) h2:lang(de),
body:lang(de) h3:lang(de),
body:lang(de) h4:lang(de),
body:lang(de) h5:lang(de),
body:lang(de) h6:lang(de),
body:lang(de) p:lang(de),
body:lang(de) div:lang(de)
{display:block;}

body:lang(de) span:lang(de),
body:lang(de) a:lang(de),
body:lang(de) img:lang(de)
{display:inline;}

JavaScript

The function setLang first checks if a language is given and if it's supported. If not, the default language is used. The language also is saved in a cookie, which is checked again after loading the document.


var langs = ':en:de:';
var defaultLang = 'en';
var cookieDuration = 30;

function setLang(lang) {
var dt = new Date();
lang && langs.indexOf(':' + lang + ':') != -1 || (lang = defaultLang);
document.body.lang = lang;
dt.setTime(dt.getTime() + cookieDuration * 24 * 60 * 60 * 1000);
document.cookie = 'lang=' + lang + '; expires=' + dt.toGMTString();
}

window.onload = function() {
var m;
m = document.cookie.match('(?:^|;)\\s*lang=([^;]*)');
m || (m = ['', '']);
setLang(m[1]);
}

Internet Explorer

As expected, it's not that easy with IE.

Internet Explorer 7 doesn't support the :lang pseudo-class. This is easily handled by some additional style-rules. We use the attribute selctor here.


body[lang=en] h1[lang=en]
...
{display:block;}

body[lang=en] span[lang=en],
...
{display:inline;}

body[lang=de] h1[lang=de]
...
{display:block;}

body[lang=de] span[lang=de],
...
{display:inline;}

Internet Explorer 6, moreover, isn't able to handle CSS attribute selectors. A workaround is to use class names instead of the lang attribute. As for IE 7 we need some additional CSS.


body .has_lang {display:none;}

body.lang_en h1.lang_en,
...
{display:block;}

body.lang_en span.lang_en,
...
{display:inline;}

body.lang_de h1.lang_de,
...
{display:block;}

body.lang_de span.lang_de,
...
{display:inline;}

The JavaScript code has to be extended, too. Additional code for the function setLang is:


if (window.ActiveXObject && !window.XMLHttpRequest)
{
document.body.className = 'lang_' + lang;
}

After loading the page we have to set the class name for each element with a lang attribute set. Additional code for the onload-handler:


if (window.ActiveXObject && !window.XMLHttpRequest)
{
var a = document.body.all;
for (var k in a) {
a[k].lang && (a[k].className += ' has_lang lang_' + a[k].lang);
}
}

Pro and contra

You do not need server-side code to determine the language to use and to extract the corresponding text from a storage.

On the other side, the document size grows and each languages is loaded, if needed or not.

Sample


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<style type="text/css">
body *[lang] {display: none;}

body:lang(en) h1:lang(en),
body:lang(en) h2:lang(en),
body:lang(en) h3:lang(en),
body:lang(en) h4:lang(en),
body:lang(en) h5:lang(en),
body:lang(en) h6:lang(en),
body:lang(en) p:lang(en),
body:lang(en) div:lang(en)
{display:block;}

body:lang(en) span:lang(en),
body:lang(en) a:lang(en),
body:lang(en) img:lang(en)
{display:inline;}

body:lang(de) h1:lang(de),
body:lang(de) h2:lang(de),
body:lang(de) h3:lang(de),
body:lang(de) h4:lang(de),
body:lang(de) h5:lang(de),
body:lang(de) h6:lang(de),
body:lang(de) p:lang(de),
body:lang(de) div:lang(de)
{display:block;}

body:lang(de) span:lang(de),
body:lang(de) a:lang(de),
body:lang(de) img:lang(de)
{display:inline;}
</style>

<!--[if IE 7]>
<style>
body[lang=en] h1[lang=en],
body[lang=en] h2[lang=en],
body[lang=en] h3[lang=en],
body[lang=en] h4[lang=en],
body[lang=en] h5[lang=en],
body[lang=en] h6[lang=en],
body[lang=en] p[lang=en],
body[lang=en] div[lang=en]
{display:block;}

body[lang=en] span[lang=en],
body[lang=en] a[lang=en],
body[lang=en] img[lang=en]
{display:inline;}

body[lang=de] h1[lang=de],
body[lang=de] h2[lang=de],
body[lang=de] h3[lang=de],
body[lang=de] h4[lang=de],
body[lang=de] h5[lang=de],
body[lang=de] h6[lang=de],
body[lang=de] p[lang=de],
body[lang=de] div[lang=de]
{display:block;}

body[lang=de] span[lang=de],
body[lang=de] a[lang=de],
body[lang=de] img[lang=de]
{display:inline;}
</style>
<![endif]-->

<!--[if IE 6]>
<style>
body .has_lang {display:none;}

body.lang_en h1.lang_en,
body.lang_en h2.lang_en,
body.lang_en h3.lang_en,
body.lang_en h4.lang_en,
body.lang_en h5.lang_en,
body.lang_en h6.lang_en,
body.lang_en p.lang_en,
body.lang_en div.lang_en
{display:block;}

body.lang_en span.lang_en,
body.lang_en a.lang_en,
body.lang_en img.lang_en
{display:inline;}

body.lang_de h1.lang_de,
body.lang_de h2.lang_de,
body.lang_de h3.lang_de,
body.lang_de h4.lang_de,
body.lang_de h5.lang_de,
body.lang_de h6.lang_de,
body.lang_de p.lang_de,
body.lang_de div.lang_de
{display:block;}

body.lang_de span.lang_de,
body.lang_de a.lang_de,
body.lang_de img.lang_de
{display:inline;}
</style>
<![endif]-->

<script type="text/javascript">
var langs = ':en:de:';
var defaultLang = 'en';
var cookieDuration = 30;

function setLang(lang) {
var dt = new Date();
lang && langs.indexOf(':' + lang + ':') != -1 || (lang = defaultLang);
document.body.lang = lang;
dt.setTime(dt.getTime() + cookieDuration * 24 * 60 * 60 * 1000);
document.cookie = 'lang=' + lang + '; expires=' + dt.toGMTString();

if (window.ActiveXObject && !window.XMLHttpRequest)
{
document.body.className = 'lang_' + lang;
}
}

window.onload = function() {
var m;
m = document.cookie.match('(?:^|;)\\s*lang=([^;]*)');
m || (m = ['', '']);
setLang(m[1]);

if (window.ActiveXObject && !window.XMLHttpRequest)
{
var a = document.body.all;
for (var k in a) {
a[k].lang && (a[k].className += ' has_lang lang_' + a[k].lang);
}
}
}
</script>
</head>
<body>
<a href="javascript:setLang('en');">english</a>
<a href="javascript:setLang('de');">deutsch</a>
<p lang="en">Hello world!</p>
<p lang="de">Hallo Welt!</p>
</body>
</html>