We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 9021
    • 40 Posts
    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.
      • 2306
      • 7 Posts
      Hi!

      This is very neat snippet! Thanks. Its better now that I dont have to define TVs for each page.

      It would be superb if you could add a functionality to get the current language code. This is useful for example if there are images such as:

      order_en.png, order_fi.png, etc.

      Though I made it using a snippet, it would be better to have it as a part of language.inc.php:

      
      <?php
      $id = $modx->documentIdentifier;
      $parent_id = $modx->runSnippet('UltimateParent', array("id" => $id));
      // default
      if (empty($id)) return "fi";
      $doc = $modx->getDocumentObject('id',$parent_id);
      return $doc['alias'];
      ?>
      
      
        • 9021
        • 40 Posts
        good idea! I will incorporate the placeholder functions of modx and include the language code.

        note that you can also do the following in your template files (or somewhere else) if your ultimate parent is named after the language code:

        <img src="order_[[UltimateParent]].gif">

        thanks!
          • 32611
          • 3 Posts
          First off all, I like to thank all contributors with their outstanding work.
          Being a novice to PHP and of course MODx, I did however manage to put a fairly working site online.
          Since I needed a bi-lingual site, I did try to make use of this language snippet, and I have it working, but not the right way.
          When I use the language drop-down box, it points out to a page in the second language, but not the corresponding language and if you use the language drop-down box, to go back to the original language, it does not respond. I set up my web-tree, having even pages assigned to 1 language, the odd pages to the second languages.
          Maybe 1 off you might help me by pointing me out in the right direction?

          Bas
            • 9021
            • 40 Posts
            Hi Bas,

            The problem lies firstly in the structure of your page tree. The snippets assumes you organize your pages like this:

            /root
            -> en
            ->-> home
            ->-> software
            ->->-> product1
            ->-> services
            ->->-> product1
            -> nl
            ->-> home
            ->-> software
            ->->-> product1
            ->-> services
            ->->-> product1

            that way, your friendly urls will be most straightforward (e.g. /en/software/product1). I would really advice you to do the same, it will pay off in the end.

            also, you need to configure the snippet, which is a little bit of php but nothing you can’t handle. the $langnames and $rootpages have to contain the correct languages.

            hope this helps!
              • 32611
              • 3 Posts
              Hi Erik,

              Thanks for your time,

              following is a copy of the tree:

              -Site Name
              -Indext (1)
              -gb (3)
              +Welcome (5)
              +Rooms (7)
              +Meeting & Conferences (9)
              +Saturday’s Dazzling Jazz (11)
              +Wellness & Spa (13)
              -Facilities Active Spa (59)
              -Specials & Events (61)
              -Opening times (63)
              -Memberships (65)
              -Tariffs (67)
              -Diplan (69)
              +Restaurants & Bar (15)
              -nl (2)
              +Welkom (4)
              +Kamers (6)
              +Meeting & Conferences (8)
              +Saturday’s Dazzling Jazz (10)
              -Wellness & Spa (12)
              -Faciliteiten Active Spa (58)
              -Acties & Evenementen (60)
              -Openingstijden (62)
              -Abonnementen (64)
              -Tarieven (66)
              -Diplan (68)
              +Restaurants & Bar (14)
              So I assume the tree is organized....
              the language snippet is actually a copy of the one you posted, with $langnames and $rootpages pointing to page 2 resp. 3
              The languages.inc.php is a 100% copy of yours....
              So acually I am clueless at the moment about what I am doing wrong!
                • 9021
                • 40 Posts
                Hello Bas,

                The structure looks good, but the problem is the ’indext’ page, can you explain what the function is of that page? Because if you would use friendly urls, the link to your welcome page would be:

                www.yourdomain.com/indext/gb/welcome

                while

                www.yourdomain.com/gb/welcome

                would make more sense. It is correct that the snippet doesn’t work because it uses the ’ultimateparent’ snippet to distinguish between the branches. If the indext page is a splash/language select page, I would put it in a separate branch. So I would organize it like:
                -Site Name
                -Indext (or splash page)
                -gb
                ..
                -nl
                ..

                I will take a look at the snippet to see if I can make it a little more robust so it can handle your structure as well.
                hope this helps.
                  • 32611
                  • 3 Posts
                  Thank you Erik!
                  Sometimes you can’t see the horse you’re sitting on.....
                  I just moved both en and nl trees directly under the root..... and now all works!
                  I am such a happy man now!
                  grin grin grin

                  Bas
                    • 9021
                    • 40 Posts
                    Good to hear smiley Glad it works.
                      • 22290
                      • 1 Posts
                      Hi,

                      I am also using this multi language plugin. I noticed every time I chose an other language I am redirect to the first page (home) of that language. Is it possible you stay on the same page while changing to an other language?

                      Eddy