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

  1. Create a Bilingual PHP Website
    1. Outline
    2. Features
  2. Simple Example
    1. View Demo
    2. View Code
  3. Considerations
    1. File Naming and Apache type-map files
    2. Apache Sesson Variables
    3. Page Encoding
    4. PHP Session Start
    5. Site Maps
  4. Example with Includes
    1. View Demo
    2. language.php
    3. index.php
    4. index.de.php
    5. header.php
    6. navigation.php
    7. navigation.en.php
    8. navigation.de.php

Features

Here is a list of functionality this multilingual website method offers.

Simple Example

View Demo »

<?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

View Demo »

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>

<?php
if($_SESSION['language']=='de'){
 include(
"navigation.de.php");
}else{
 include(
"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>


<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>