Simple multi-language web site
There are many ways to direct users of a multi lingual web site to the pages
in their language. But the quick search I made didn't return solutions which
I liked, so I did my own. I'm sure the same method has been used many times,
but it's sometimes faster to re-invent a little wheel than to go through zillions
of Google search results.
I had to work on a small site with about 20 pages, in which every language
is in it's own subdirectory (www.example.com/fr/, www.example.com/en/, etc.)
and the file names remain the same.
This simple structure made it pretty easy, and the solution makes it trivial
to add another language.
(For a lot of background about languages and a different solution involving the standard "content language negotiation", see Dan's Web Tips: Languages).
The way I choose works like this:
- One line in every page calls a PHP script to display the language menu.
- A cookie holds the visitor's preferred language.
- Javascript updates the cookie when the visitor switches languages.
- The main index page redirects visitors to the correct language, using:
- either the cookie set in a previous visit,
- or the browsers preferred language,
- or a pre-configured default language.
- Finally, a few CSS rules take care of the menu's look
The redirector script
I used a little Perl script on www.example.com/index.cgi. It first looks for
a cookie with the user's preferred language. If there is no cookie (usually
because this is a first-time visit), it uses the HTTP_ACCEPT_LANGUAGE
header sent by the browser to find the best guess. If that doesn't work either,
it uses a default language. Finally, it redirects the user to the selected language,
while also setting the cookie for the next visit.
I probably could have done the index page in PHP, but I didn't know PHP at
all when I started so it was easier for me in Perl. (If someone feels like sharing
a PHP translation, you are welcome to post it here as a comment).
#!/usr/bin/perl
# Redirect to correct language version of the site.
# Use cookie if present. Otherwise, parse the HTTP_ACCEPT_LANGUAGE header
# Author: Milivoj Ivkovic "mi\x40alma.ch"
use CGI qw(:cgi);
my $VERSION = 0.3;
my %available_languages = (
fr => 'fr/',
de => 'de/',
en => 'en/',
default => 'fr/',
);
my $wanted_language = 'default';
my $q = new CGI;
# try cookie
my $cookie_lang = $q->cookie("lang");
if ( exists $available_languages{$cookie_lang} ) {
$wanted_language = $cookie_lang;
}
else { # try HTTP_ACCEPT_LANGUAGE
# Get languages from HTTP_ACCEPT_LANGUAGE, (ignore local variants like en_US, en_GB, etc.).
# Don't bother removing duplicates
my @langs = map { substr($_, 0, 2) } split(/,/, $ENV{HTTP_ACCEPT_LANGUAGE});
foreach my $l (@langs) {
if (exists $available_languages{$l}) {
$wanted_language = $l;
last;
}
}
}
# if nothing worked, we still have the default in $wanted_language which was set at the beginning
# fix URL
my $url = $q->url(-path_info=>1);
# (some servers give us a url ending with 2 "/", so we need "/+" in the
# regex below instead of just "/".
# Otherwise we may end up with "http://example.com//en/" which doesn't look nice.)
$url =~ s|/+[^/]*$|/$available_languages{$wanted_language}|;
# redirect, and also set the cookie for next time
print $q->redirect ( -uri => $url,
-cookie => cookie( -name=>"lang",
-value=>$wanted_language,
-path=>"/",
-expires=>"+1y",
),
);
The javascript setLang
function
Anytime the user switches the language, this small javascript function is called
to update a cookie, so the preference is saved between sessions.
function setLang(l) {
// Called from links which switch the language.
// Sets cookie with "lang=fr" or other language code, valid for 1 year, on all the site
var expire = new Date();
expire.setTime(expire.getTime() + 3600000*24*365);
document.cookie = 'lang='+l+";expires="+expire.toGMTString()+";path=/";
}
The language menu
Since all the pages happened to be in PHP, I did the language menu in PHP,
and added an include()
to every page.
<?php include("../common/lang-selector.php") ?>
The PHP lang-selector.php script
This is the PHP script which displays the language menu.
<!-- php lang selector -->
<div id="lang-selector">
<?php
$langs = array(
"fr" => "Français",
"de" => "Deutsch",
"en" => "English",
);
$self=$_SERVER['PHP_SELF'];
$pattern = "{^/[^\/]+/}i";
$links = array();
foreach ($langs as $l => $lang) {
$is_current = ! ( strpos($self, "/$l/") === false );
$url = preg_replace($pattern, "/$l/", $self);
$link = "<a href=\"$url\" class=\"lang-"
. ($is_current ? "current\">" : "other\" onclick=\"setLang('$l')\">")
. " $lang </a> ";
array_push($links, $link);
}
echo " " . implode(" | ", $links) . "\n";
?>
</div>
<!-- end php lang selector -->
The finishing touch: CSS
The look of the language menu is done with CSS. This is what I used for that
particular site:
#lang-selector {
font-size: x-small;
text-align: left;
white-space: nowrap;
padding-bottom: 1em;
color: #CCCCCC;
}
a.lang-current,
a.lang-current:visited,
a.lang-current:hover
{
color: #CCCCCC;
text-decoration: underline;
}
a.lang-other,
a.lang-other:visited
{
color: #333333;
text-decoration: none;
}
a.lang-other:hover
{
text-decoration: underline;
background: #F7EBDB;
}
@media print {
#lang-selector {
display: none;
}
}
By the way, the site for which this was first set up is http://lesouffledudesert.com/.
When we added English to the site, the steps were:
- Copy the
/fr
directory to a new/en
directory - Add
"en" => "English",
to lang-selector.php - Add
en => 'en/', to index.cgi
- And of course, translate all pages, which was the real work and where
this little multi-language system doesn't help...
Labels: code, computers, en, javascript, perl, web-design