Multilingual Websites with MODx
After reading the solutions in this forum, none of them convinced me. I wanted that the user stays on the same page if he switches the language.
But i didn´t want to assign the relation between the languages via a template variable where i have to put the corresponding ID of the actual page for every language.
It should function automatic.
So i found a solution for myself. It performs well, but surely has potential for improvements.
Comments and improvements are welcome. Hope my solution helps someone.
Update 02/17/2009
I was asked how to redirect different TLDs to the corresponding language, so updated my code.
Update 02/17/2009
German version available at:
http://www.modxcms.de/forum/comments.php?DiscussionID=1771
Update 01/28/2009
Now the connection between languages is made with a template variable called "languageIdentifier". You only need to write a unique name in this field once and then it will be duplicated when you duplicate your language folder.
End Update
Here we go:
1. Modify your configuration under Tools/Configuration
Use the following settings:
friendly URLs: yes
Use friendly aliases: yes
Use friendly alias path: yes
Create a new template variable with name "languageIdentifier"
2. build Site Tree
First make a new page and in the page settings tab click "container" and name the page with your main language as the title. For example „english“, „deutsch“, „français“.
This is what a visitor sees to select his language.
The alias for this folder is a two-letter ISO Country Code that you can find here:
http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
Now you create your pages as you would normally. Enter a languageIdentifier for every page. It could be the same as your alias for example.
After that you duplicate the whole folder for your next language and change the title and the country code in the root folder of that language.
Example:
english / alias: gb / type: folder (1)
|-> Welcome (2)
deutsch / alias: de / type: folder (3)
|-> Willkommen (4)
Be sure to check the option ’Show in menu’ and set the status to ’published’ for the folders!
Now under configuration "set Site start": enter the id of the first page of your main language (2 in this example).
You can also set the Site start to the id of the root folder (for example 1) and then use the [[FirstChildRedirect]] snippet on this page.
3. create snippets
Snippet Name: „language“.
Description: creates placeholders and stores the actual language
<?php
$debugMsg = '$language is: '.$language.'<br />';
$debugMsg = 'LanguageID from cookie: '.$_COOKIE['LanguageID'].'<br />';
$params['topLevel'] =1;
// Regular Page
// find Ultimate Parent of this page. The alias of this page sets the language variable
if ($modx->config['error_page'] != $modx->documentIdentifier){
$up = $modx->runSnippet("UltimateParent", $params);
$tv = $modx->getTemplateVar('alias', "", $up);
$language = $tv['value'];
setcookie("Language",$language,time()+604800, "/", "", 0);
// LanguageID is needed for the 404 error page, to show the sitemap in the actual language
setcookie("LanguageID",$up,time()+604800, "/", "", 0);
$modx->setPlaceholder('LanguageID',$up);
$modx->setPlaceholder('language',$language);
}
else{
// If Error Page
$debugMsg .= '<p>Error Page Start<br />';
if ( !empty ($_COOKIE['LanguageID'])){
$debugMsg .='$language is empty, try to read from cookie';
$language = $_COOKIE['Language'];
$LanguageID = $_COOKIE['LanguageID'];
$params['id'] = $LanguageID;
$up = $modx->runSnippet("UltimateParent", $params);
//setcookie("LanguageID",$up,time()+604800, "/", "", 0);
$modx->setPlaceholder('LanguageID',$up);
}
else {
$debugMsg .= '<p>LanguageID Cookie is empty, get ID from Site start</p>'.$modx->config['site_start'];
$params['id'] = $modx->config['site_start'];
$up = $modx->runSnippet("UltimateParent", $params);
//setcookie("LanguageID",$up,time()+604800, "/", "", 0);
$modx->setPlaceholder('LanguageID',$up);
}
}
$debugMsg .= 'LanguageID at finish: [+LanguageID+]<br />';
$debugMsg .= '$language: '.$language.'<br />';
$modx->setPlaceholder('debugMsg', $debugMsg);
//echo $debugMsg;
$modx->setPlaceholder('language', $language);
if (file_exists("assets/languages/$language.php")) include_once "assets/languages/$language.php";
?>
Snippet Name: „LanguageChooser“
Description: „shortcut for the wayfinder“
<?php
$langMenu = $modx->runSnippet(
"Wayfinder",
array(
"startId" => "0",
"level"=>"1",
"textOfLinks"=>"alias",
"rowTpl"=>'flagAndLanguage',
"outerTpl"=>'LanguageChooser'
)
);
echo $langMenu;
?>
Snippet name "link_to_language"
Description: "gets link to actual page in other languages"
<?php
if (! function_exists('getdocs_with_same_values')){
function getdocs_with_same_values($id = 'default', $field = 'description')
{
global $modx;
// Initialize ids
$ids = array ();
if ($id == 'default')
{
$id = $modx->documentIdentifier;
}
$table = $modx->getFullTableName('site_tmplvars');
$result = $modx->db->select('id', $table, ' name = "'.$field.'"');
$array_result = $modx->db->makeArray($result);
if (count($array_result) > 0)
{
$tvid = $array_result[0]['id'];
$table = $modx->getFullTableName('site_tmplvar_contentvalues');
$result = $modx->db->select('*', $table, 'contentid = "'.$id.'" and tmplvarid = "'.$tvid.'"');
$array_result = $modx->db->makeArray($result);
$fieldvalue = $array_result[0]['value'];
$result = $modx->db->select('contentid', $table, 'value = "'.$fieldvalue.'"');
$array_result = $modx->db->makeArray($result);
foreach ($array_result as $value)
{
$ids[] = $value['contentid'];
}
}
else
{
$table = $modx->getFullTableName('site_content');
$result = $modx->db->select($field, $table, ' id = "'.$id.'"');
$array_result = $modx->db->makeArray($result);
$fieldvalue = $array_result[0][$field];
$table = $modx->getFullTableName('site_content');
$result = $modx->db->select($field, $table, ' id = "'.$id.'"');
$array_result = $modx->db->makeArray($result);
$fieldvalue = $array_result[0][$field];
$result = $modx->db->select('id', $table, $field.' = "'.$fieldvalue.'"');
$array_result = $modx->db->makeArray($result);
foreach ($array_result as $value)
{
$ids[] = $value['id'];
}
}
return $ids;
}
}
$pages = getdocs_with_same_values('default','languageIdentifier');
$langFolder = $modx->getDocumentObject('id', $id);
$langFolderID = $langFolder['id'];
$langFolderAlias = $langFolder['alias'];
// set theURL to the root of the language
$theURL = $modx->makeURL($id,'','','full');
foreach ($pages as $page){
//echo $page;
// Now check if the id of the $value is a child of the UltimateParent
$UltimateParent = $modx->runSnippet('UltimateParent', array('id' => $page));
//echo "\n".$UltimateParent." ".$langFolderID;
//$checks[$counter]['id'] = $value['id'];
// if the UltimateParent is equal to to folderID make link to the actual page in the other language
if ($UltimateParent == $langFolderID) {
$theURL = $modx->makeURL($page,'','','full');
}
}
return $theURL;
?>
create Chunks
Chunk Name: „flagAndLanguage“
Description: „prints a flag and the name of the language as a list item“
Content:
<li class="[+wf.classnames+]"><a href="[[link_to_language?id=`[+wf.docid+]`&link=`[+wf.link+]`&actualid=`[*id*]`]]"><img src="[(base_url)]assets/images/flags/gif/[+wf.linktext+].gif" alt="[+wf.linktext+]" /> [+wf.title+]</a></li>
Chunk Name: "LanguageChooser"
Description: "Outer template for the Language chooser"
Content:
<ul [+wf.classes+] id="sprachwahl">
[+wf.wrapper+]
</ul>
4. modify Site-Template
Now you insert the follwing code in your template:
in the first row of your template insert the placeholder "[[language]]"
<div id="languageselection">
[[LanguageChooser]]
</div>
<div id="navigation">
[!Wayfinder? &startId=`[+LanguageID+]`!]
</div>
This includes the languageChooser and a php-file "assets/languages/currentlanguage.php" (currentlanguage is the two-letter ISO Country Code) . And you get a navigation with only the pages in the current language.
Add the placeholder [+language+] where you need it. For example if you have different images in your languages.
Add the placeholder "[+debugMsg+]" for tracing the language snippet
5. Download Icons
This is an optional step. However, if you skip this step, you will need to change the "flagAndLanguage" snippet below.
6. Forms
Open the language file under assets/snippets/eform/lang and add your variables to it
$_lang['yourname'] = "Your Name";
You can add as many variables as you need.
Now you have to assign those variables to the fields array:
Create a new snippet „setPrompts“
<?php
function setPrompts(&$fields) {
global $_lang;
$fields['yourname'] = $_lang['yourname'];
return true;
}
?>
When you create your form chunk you have access to all the placeholders that you defined in the setPrompts snippet:
[+validationmessage+]
<form method="post" action="[~[*id*]~]">
<input type="hidden" name="formid" value="feedbackForm" />
<label for="cf[+yourname+]">[+yourname+]: </label>
<input name="Your Name" id="cf[+yourname+]" class="required text" type="text" eform="[+yourname+]::1:" />
Now insert your form on your contact page with the following code:
[!setPrompts!]
[!eForm? &formid=`feedbackForm` &to=`[email protected]`&eFormOnBeforeFormMerge=`setPrompts` &language=`german` &subject=`Web site feedback`!]
Most important are the parameters „&language = `german`“ (name needs to be the same as in the assets/snippets/eform/lang folder) and „eFormOnBeforeFormMerge=`setPrompts`“ !
Multilingual 404 Error Page
Create a new folder in MODx that is unpublished.
Then create and publish a new page with the title "[+errorpage+]" in it.
Alias: "404"
[[language]]
[+errorpage+]
[!Wayfinder? &startId=`[+LanguageID+]` &showDescription=`1`!]
Now in your assets/languages/en.php (enter your 2 letter-language-code), add the following:
<?php
$modx->setPlaceholder("errorpage",'404 - Page not found');
?>
Translate this message for all of your languages and insert it in the language files.
Your 404 error page is done and provides a sitemap in the current language.
Thats it. Please comment for suggestions.
Redirect TLD to specific language
Quote from: c-m at Jul 13, 2009, 08:10 AM
Hi sorry to bother you. But I was wondering how your website redirects to different TLDs as I need to do this for a site at www.naturediet.co.uk
So you want different TLDs, huh? There you go
$e = &$modx->event;
$domains[] = array('url'=>'www.mydomain.de','id'=>72);
$domains[] = array('url'=>'www.mydomain.ch','id'=>920);
$domains[] = array('url'=>'www.mydomain.nl','id'=>242);
$domains[] = array('url'=>'www.mydomain.fr','id'=>494);
$umleitung = false;
$host = $_SERVER['HTTP_HOST'];
if($e->name=='OnWebPageInit') {
foreach ($domains as $domain){
// Wenn beim ersten Aufruf der Seite (site_start) der host == URL ist
if($host == $domain['url'] && $modx->documentIdentifier == $modx->config['site_start']){
$modx->sendRedirect($modx->makeUrl($domain['id'], '', '', 'full'));
exit;
}
}
}
In the array $domains enter your domainnames and the id of the corresponding parent folder and you have it.