Create a Bilingual PHP Website
When I wanted to add German content to my website, I didn't find any single good set of instructions for how to do what I wanted. I eventually figured out a great way to make any php site bilingual or semi-bilingual.
Outline
Features
Here is a list of functionality this multilingual website method offers.
- Works even if every page isn't translated in all languages. The program will search for each page in the user's preferred language but will default to English if there is not translation found.
- It's easy to implement! Because you don't need to have a translation for every page, you can add it to your existing site easily and work on translating content later.
- The website remembers the user's preference as a PHP session cookie.
- No JavaScript required. So it is compatible with more clients and search engines.
- Works great with PHP includes. If you have standard content on every page (like navigation/header/footer) you can easily specify alternate translations for those parts of the page too. That way, even if a page's main content isn't available in another language, the navigation and such can still show a translation.
- If a user enters the site via a bookmark or search engine result, the user's preferred language is set by the language of the page linked too.
Simple Example
<?php session_start();
// session start must be first statement
// do not leave any white space before the php declaration
//the url ? language declaration should have preference over the page name
$pagename = basename($_SERVER['PHP_SELF'],".php");
$pagenamearray = explode(".",$pagename);
if (count($pagenamearray) == 2){ //there is currently a bi-lingual site page loaded
$_SESSION['language'] = $pagenamearray[1];
$urllang = $pagenamearray[1];
}else{ //this page must be a non bi-lingual page
$urllang = 'en';
}
//check for a language selection on the url
if(isset($_GET["lang"])){//language has been passed via url
$_SESSION['language'] = htmlspecialchars($_GET["lang"]); //set it what was found
}
///if there still is no language set, go with english for a default
if(!isset($_SESSION['language'])){
$_SESSION['language'] = 'en';
}
//now we think we have the session language figured out
//
//now check for a version of the current page in the desired language
//lets make some things clear first
//the current page url is either en or de from $urllang
if($urllang != $_SESSION['language']){ //if the url isn't the same as the $_SESSION
if($_SESSION['language'] == 'en'){//if it should be english then load the english
header("Location: $pagenamearray[0].php");
exit;
}
if($_SESSION['language'] == 'de'){
//construct the name of the file if it existed filename.de.php
$deVersion = $pagenamearray[0] . ".de.php";
//we have to check if a de version actually exists of this page
if(file_exists($deVersion)){//redirect if it exists
header("Location: $deVersion");
exit;//stop executing things
}else{$pagelangnotfound = ture;}
}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- do not change the doctype languages as these don't refer to the content language -->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<!-- again, do not ever change xml:lang property.
however one should set the lang property ot reflect the content language -->
<head>
<title>PHP Language Simple Demo</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<!--The charset declaration is very important here-->
<meta name="description" content="This is the multilingual php website Demo" />
<meta name="keywords" content="php language simple example code" />
</head>
<body>
<?php
if ($_SESSION['language'] != 'en'){
echo 'Sprache: <a href="'. $_SERVER['PHP_SELF'] . '?lang=en">English</a>';
}else{echo 'Language: English';}
?> |
<?php
if ($_SESSION['language'] != 'de'){
echo '<a href="'. $_SERVER['PHP_SELF'] . '?lang=de">Deutsch</a>';
}else{
echo 'Deutsch';
if($pagelangnotfound){
//if the user has selected german but the current page is not found, this text is displayed
echo " (Leider gibt es noch keine Übersetzung für diese Seite.)";
}
}
?>
<p><a href="./../../proj_phplanguage.php#simpex">back</a></p>
</body>
</html>
Considerations
Okay, so you're sold. You want to offer multilingual content. Read the sections below to find out what needs to be done to implement such a system.
When you are ready to get started, use the example section to get you started. Read all the comments to figure out how it works.
File Naming and Apache type-map files
File names for pages in the default language remain unchanged. (index.php contact.php content.php etc.) Files for alternative languages add the language code to the file name. (index.de.php contact.de.php content.de.php) Apache can be set to recognize a pages language based on the added language code. This allows Apache to tell browsers and search engines the page's language via response headers.
Use the AddLanguage Directive of the Apache Module mod_mine to set this up. I use this method because it is easy to set up. I only had to add one line to my server config file. If you don't have access to your server's config, it can also be set in virtual host config and .htaccess files. Apache AddLanguage documentation
Apache Sesson Variables
See the following link if you have questions about PHP sessions. http://php.net/manual/en/function.session-start.php
Page Encoding
Encode all your pages in Unicode. Unicode encoding supports those extra letters that other languages often have. If your file is encoded in Unicode, you won't have to worry about escaping characters with ampersands. You will save time translating as you can type characters like: ö ä ü ß If you load a page and you see little boxes in your type, that means there is an encoding problem
Now you don't necessarily have to convert all your files to Unicode, but it will make it a lot easier for yourself. It is one less variable to communicate to the browser.
Setting up your editor to do this can be tricky though. After I changed the default encoding on my editor to UTF-8, it was still only saving new files in the new encoding. To change old files to new encoding, I would either have to copy and past them to a new file and save over the old one, or go to Edit -> Current File Settings.... in my editor, Komodo. In file settings, I set the line breaks to Unix and unselected the preserve old breaks check box to convert old files. How you set encoding is of course going to vary from editor to editor so just Google for program specific instructions.
PHP Session Start
The PHP session_(); needs to be at the top of every file and should be followed by the language source script!
Site Maps
You should publish some sort of site map that search engines can find. Each page should have a link for each translation with the ?lang=XX appended too the link too. This way a search engine (that really doesn't have a language preference) sees both versions of every file without the session cookies getting in the way. For example, a site map for the demo below should include the following links:
<a href="index.php?lang=en">homepage</a>
<a href="index.de.php?lang=de">homepage in german</a>
<a href="content.php?lang=en">content</a>
Example with Includes
language.php
<?php
//the url ? language declaration should have preference over the page name
$pagename = basename($_SERVER['PHP_SELF'],".php");
$pagenamearray = explode(".",$pagename);
if (count($pagenamearray) == 2){ //there is currently a bi-lingual site page loaded
$_SESSION['language'] = $pagenamearray[1];
$urllang = $pagenamearray[1];
}else{ //this page must be a non bi-lingual page
$urllang = 'en';
}
//check for a language selection on the url
if(isset($_GET["lang"])){//language has been passed via url
$_SESSION['language'] = htmlspecialchars($_GET["lang"]); //set it what was found
}
///if there still is no language set, go with english for a default
if(!isset($_SESSION['language'])){
$_SESSION['language'] = 'en';
}
//now we think we have the session language figured out
//
//now check for a version of the current page in the desired language
//lets make some things clear first
//the current page url is either en or de from $urllang
if($urllang != $_SESSION['language']){ //if the url isn't the same as the $_SESSION
if($_SESSION['language'] == 'en'){//if it should be english then load the english
header("Location: $pagenamearray[0].php");
exit;
}
if($_SESSION['language'] == 'de'){
//construct the name of the file if it existed filename.de.php
$deVersion = $pagenamearray[0] . ".de.php";
//we have to check if a de version actually exists of this page
if(file_exists($deVersion)){//redirect if it exists
header("Location: $deVersion");
exit;//stop executing things
}else{$pagelangnotfound = ture;}
}
}
?>
index.php
<?php session_start();
include "language.php";
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- the session start and language script are called first followed by our doc type conversion -->
<!-- do not change the doctype languages as these don't refer to the content language -->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<!-- again, do not ever change xml:lang property.
however one should set the lang property ot reflect the content language -->
<head>
<title>PHP Language Demo index.php</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<!--The charset declaration is very important here-->
<meta name="description" content="This is the multilingual php website Demo" />
<meta name="keywords" content="php language example code" />
</head>
<body>
<?php
include "header.php";
?>
<hr />
<?php
include "navigation.php";
?>
<hr />
<p>English Content would be here!</p>
<hr />
</body>
</html>
index.de.php
<?php session_start();
include "language.php";
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- the session start and language script are called first followed by our doc type conversion -->
<!-- do not change the doctype languages as these don't refer to the content language -->
<html xmlns="http://www.w3.org/1999/xhtml" lang="de" xml:lang="en">
<!-- again, do not ever change xml:lang property.
however one should set the lang property ot reflect the content language -->
<head>
<title>PHP Language Demo index.de.php</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<!--The charset declaration is very important here-->
<meta name="description" content="This is the multilingual php website Demo" />
<meta name="keywords" content="php language example code" />
</head>
<body>
<?php
include "header.php";
?>
<hr />
<?php
include "navigation.php";
?>
<hr />
<p>German Content would be here!</p>
<hr />
</body>
</html>
header.php
<h1>Demo Header</h1>This header uses one file and many if else statements<h4>
<?php if($_SESSION['language']=='de'){
echo'Zuspringen: <a href="#content">Inhalt</a> | <a href="#sidebar">Navagation</a> | <a href="#footer">Fußbereich</a>';
}else{
echo 'Skip to: <a href="#content">Content</a> | <a href="#sidebar">Navigation</a> | <a href="#footer">Footer</a>';
}?></h4>
<?php
if ($_SESSION['language'] != 'en'){
echo 'Sprache: <a href="'. $_SERVER['PHP_SELF'] . '?lang=en">English</a>';
}else{echo 'Language: English';}
?> |
<?php
if ($_SESSION['language'] != 'de'){
echo '<a href="'. $_SERVER['PHP_SELF'] . '?lang=de">Deutsch</a>';
}else{
echo 'Deutsch';
if($pagelangnotfound){
echo " (Leider gibt es noch keine Übersetzung für diese Seite.)";
}
}
?>
<h3 id="slogan">Slogan:<?php
if ($_SESSION['language']=='en'){
echo "Electrical Engineer";
}else{
echo "Elektroingenier";
}?></h3>
<a href="./../../proj_phplanguage.php#files">Back</a>
navigation.php
<?php
if($_SESSION['language']=='de'){
include("navigation.de.php");
}else{
include("navigation.en.php");
}
?>
navigation.en.php
<h5>These navigation links are from navigation.en.php</h5>
<ul><li>
<a href="index.php">index.php</a> This has two languages</li>
<li><a href="content.php">content.php</a> This has one language</li>
</ul>
navigation.de.php
<h5>Diese seite kommen von navigation.de.php</h5>
<ul><li>
<a href="index.php">index.php</a> zwei sprache</li>
<li><a href="content.php">content.php</a> nur ein sprache</li>
</ul>