Hi guys,
For a multilanguage website, I needed a language drop box like explained here:
http://wiki.modxcms.com/index.php/Make_Multi_Lingual_Site
However I really didn’t feel like going through every single page and adding all the language id’s in the template variable. I modified the snippet so it tries to match the trees to each other based on how they appear in the menu index (not the actual menu index because there may be indexes missing , just the order). You can still override the algorithm by assigning the template variable when the algorithm fails, the tv will have preference over the approximation.
The algorithm traverses up in the tree until it finds the root page or a page that has a corresponding page set in the language variable. From there, it traverses down in the other language following the path it just compiled. If a page doesnt exist, it stops and returns the current value.
I’m posting it here for your convenience and also to get comments on it. I am aware of the following issues:
- Currently there are no settings. Please let me know what kind of settings you would prefer.
- The form itself should be in a separate chunk, however I was not sure how placeholders would behave when applied dynamically
Please inform me of any other (performance) improvements you might think of. Any other ideas are very welcome as well.
To use:
- Follow the tutorial in the link above.
- Replace the snippet ’Languages’ with the code below
<?php
/**
* name Language
* version 1.0 alpha (requires MODx 0.9.5+)
* author Erik Pols <[email protected]>
*
* license Public Domain, use as you like.
*
* This snippet creates a language switch drop box. The page it points to is
* approximated by trying to duplicate the path the current page is in, in the
* other branches which are defined below in 'rootpages'.
*/
//$id= isset ($id) && intval($id) ? intval($id) : $modx->documentIdentifier;
include_once("assets/snippets/language/language.inc.php");
// define ISO codes -> Languages
$langnames = array(
"en" => "English",
"fr" => "Français",
"nl" => "Nederlands",
"de" => "Deutsch"
);
// define rootpages
$rootpages = array(
"en" => 2,
"fr" => 68,
"nl" => 67,
"de" => 69
);
show_language_dropbox($langnames,$rootpages);
?>
- change the above code according to your personal preferences
- Also, place the following code in a file named language.inc.php in the directory assets/snippets/language/
<?php
function show_language_dropbox($langnames, $rootpages){
global $modx;
// get this ultimate parent
$ultimate_parent = $modx->runSnippet('UltimateParent');
// grab the tv's from every page in the path to the root for performance reasons
$doc = $modx->getDocument($modx->documentIdentifier, "id");
while ($doc['id'] != $ultimate_parent){
$tvars[$doc['id']] = get_language_tv_array($doc['id']);
$doc = $modx->getParent($doc['id'],1, 'id');
}
// there is a different path for every match we try to make because we stop the path when a TV helps us out
foreach($langnames as $isocode => $langname){
// first, we need to find the path to this page
$mypath = array();
$approximation = 0;
// get the current doc
$doc = $modx->getDocument($modx->documentIdentifier, "id, menuindex");
// traverse up in the tree, putting the path taken in mypath (note: it is in reversed order)
while ($doc['id'] != $ultimate_parent){
$tv_languages = $tvars[$doc['id']];
// if this page has a tv with the corresponding page, we can begin our approximation here
if($tv_languages[$isocode]){
// we found a match in the tree structure, don't traverse any further
$approximation = $tv_languages[$isocode];
break;
}
else{
// no luck. we have to add this one to the path and continue with the parent.
$parent = $modx->getParent($doc['id'],1, 'id, menuindex');
// we cannot trust the menuindex because indexes may be missing. base decision on the order. this is assuming getdocumentchildren is sorting on menuindex
$index = 0;
$siblings = $modx->getDocumentChildren($parent['id'],1,0,'id');
foreach($siblings as $sibling){
if($sibling['id']==$doc['id']) break;
else $index++;
}
// add the current doc to the path
$entry['menuindex'] = $doc['menuindex'];
$entry['id'] = $doc['id'];
$entry['index'] = $index;
$mypath[] = $entry;
// now assign the new doc
$doc = $parent;
}
}
// if there was no page in the path with a template var set, assign the rootpage (we know that one at least)
if(!$approximation) $approximation = $rootpages[$isocode];
// walk down the branch, taking turns based on the menuindex
for($i = count($mypath)-1;$i >= 0; $i--){
// get the children
$children = $modx->getDocumentChildren($approximation, 1,0, 'id, menuindex');
// if the child exists in the good position, take it as the next approximation
if($children[$mypath[$i]['index']]) $approximation = $children[$mypath[$i]['index']]['id'];
else break;
}
// well that's it.
$languages[$isocode] = $approximation;
//echo $isocode.":".$approximation."<BR>";
}
?>
<img src='assets/images/flags/<?php echo $rootpages[$ultimate_parent];?>.gif'>
<form name="langform" action="#" method="post">
<select name="langselect" id="langselect" onchange="window.location=document.langform.langselect.options[document.langform.langselect.selectedIndex].value">
<?php
foreach ($languages as $lang => $page){ ?>
<option value="<?php echo $modx->makeUrl($page);?>" <?php if($ultimate_parent == $rootpages[$lang]) echo 'SELECTED';?>><?php echo $langnames[$lang];?></option>
<?}?>
</select>
</form>
<?
}
function get_language_tv_array($id){
global $modx;
// get languages info from the TV
$tv = $modx->getTemplateVar('languages', "", $id);
$languagestring = $tv['value'];
// modx copies 'default' to 'value'. we want an empty array instead of the default because we are going to approximate the path
if($tv['value'] == $tv['default_text']) return array();
// get entries in languages list
$entries = explode(",", $languagestring);
// parse the entries into a language->value array
foreach($entries as $e){
list($lang, $targetid) = explode("=", $e);
$languages[$lang] = $targetid;
}
return $languages;
}
?>
I hope some people find some use for this. I will update this post in the future, until I think it is finished and then submit it to the repository.