• Plugin for Multilanguage support#

  • sottwell Reply #1, 6 years, 11 months ago

    Reply
    I have been manually editing all snippets to add a value "&lang=$lang" to all links and link-creating code, such as menu snippets. The $lang variable is determined at the top of every snippet with "$lang = isset($_GET['lang'] ? $_GET['lang'] : $modx->config['site_start'];". The $lang variable is initially determined by the docID of the root folder acting as home page and containing the content pages for that langauge, as selected from a menu generated by a simple list menu snippet using 0 as its base and that does have its links modifed to seed the $lang variable into the system. The language files are also simply named after the same root docID. If it's the initial visit to the site, or for some reason the query string value gets lost, it defaults to the site_start document ID.

    This works well, but is really not desireable. It seems to me that I could use a plugin on the DocumentPreRender event to add the value to the query string of all links on the page. If I understand this correctly, I can do something like the "filter words" plugin example in the documentation. I would use a regular expression to find all "<a href=.....> and add the query string value at the end of the text before the final ">".

    Am I on the right track here? And can somebody recommend a good site for a crash course on regular expressions? I already tried hacking the core in the rewriteURLs function, and that worked, but it ended up with multiple "lang" fields in the query string, and while the last one was the desired one and it worked, it's sloppy, and besides, I don't want to have to have a hacked core for this to work. This way, all I'd need is one modified simple list menu snippet and the plugin for instant multilanguage support. Snippets written to use the feature would simply include their own "snippet/langs/$lang.php" language file as needed.



  • xwisdom Reply #2, 6 years, 11 months ago

    Reply
    Hi Susan,

    You're on the right track. The OnDocumentPreRender event makes it very easy for you to append &lang to every <a> tag inside the document.

    I'm not good at the regx stuff either but you can try this:

    $pattern='/<a [^>]*href=([\\"\\\']?)([^>]*)\1[^>]*>/i';
    preg_match_all($pattern,$x,$ahrefs);
    echo $ahrefs[0][0]." Original "; //orig
    echo $ahrefs[2][0]." Url "; // url

    I borrowed th regx from the PNGAlpha4MSIE plugin


  • Lammikko Reply #3, 6 years, 11 months ago

    Reply
    Quote from: sottwell at Jun 15, 2005, 10:30 PM
    And can somebody recommend a good site for a crash course on regular expressions?

    These two are very useful:
    Excellent regular expressions tutorial: http://www.regular-expressions.info/
    Regular expressions library: http://www.regxlib.com/


  • Carsten Reply #4, 6 years, 11 months ago

    Reply
    Actually, a bit off topic. But I've always been leary of using regex for replacements (ie, in regards to templates and such). How much of hit is regex compared to say caching the language didies and just using a require?


  • sottwell Reply #5, 6 years, 11 months ago

    Reply
    This isn't about substituting the text strings, I do use included language files for that. This is about how to pass the $lang variable from page to page via the query string and recover it as needed from the GET array.

    Anyway, I've about given up on this idea; not all links on a page are to the local site, and friendly URLs would make it extremely difficult to determine which links were to local pages and which were not. Looks like I'll be studying up on cookies after all.

    Session works great, and is the easiest, but if the user's session times out he gets dumped back into the site's default language. Plus, sessions require fiddling the web login snippet core scripts, and I want this to be a stand-alone solution, a plug-in or a snippet that is easy to use.


  • sottwell Reply #6, 6 years, 11 months ago

    Reply
    Ok, here's my take on a multilanguage site. One snippet, one TV, a folder for language files. That's it, no hacked core modules or anything nasty.

    Have the language home page documents in the root. i.e. "French", "Italian", "English". These are the only published documents in the root. These documents act as folders for the content for their respective languages. Anything else goes into unpublished folders.

    Have language files to replace placeholders for any generic text, such as login forms, contact forms, etc. These kind of things are what would go in the unpublished folder and get called from all languages. The language files are named after the ID of the language home page, 3.php, 45.php, etc.

    Use this modifed CSS Dropdown Menu snippet to create the language menu and seed the system with the $lang variables:
    // CSSDropMenu
    // simple drop=down menu for ModX
    // usage: [[DropDown?id=x&tt=y]]
    // where x is the parent of the documents to be listed
    // and y is the text you want for the top of the menu
    
    $id = isset($id)?$id:0;
    $toptext = isset($tt)?$tt:"Menu";
    $children = $modx->getActiveChildren($id);
    if($children == false) return;
    $childrenCount = count($children);
    $lang = $modx->documentIdentifier;
    $dm = "";
    
      // a bit of javascript for those whose browsers aren't 
      // CSS2 compliant (and we all know who they are)
    $dm .= "<script type='text/javascript'>
    function showList(thistag) {
       styleObj = document.getElementById(thistag).style;
       if (styleObj.display=='none') {styleObj.display = 'block';}
       else {styleObj.display = 'none';}
    }
    </script>";
    
      // set up the style for the list
    $dm .= "<style type='text/css'>
      #CSSMenu {
          position:relative;
          width:100px;
          z-index:10;
          background:yellow;
      }
      #CSSMenu ul, #CSSMenu li {list-style:none;}
      #cmTopItem {display:block;cursor:pointer;}
      #cmTopItem ul {display: none;} 
      #cmTopItem:hover ul {display: block;}
    </style>";
    
      // generate the list
    $dm .= "<div id='CSSMenu'>";
    $dm .= "<ul class='cmList' id='cmTopList'>";
    $dm .= "<li id='cmTopItem' class='cmItem' onClick='showList(\"cmList\");'>$toptext";
    $dm .= "<ul class='cmList' id='cmList'";
      // individual items
    for($x=0; $x<$childrenCount; $x++) {
       $dm .= "<li class='cmList'><a href='[~".$children[$x]['id']."~]&lang=".$children[$x]['id']."'>".$children[$x]['pagetitle']."</a></li>";
    }
    $dm .= "</ul></li></ul></div>";
    
    return $dm;
    


    Use this snippet to set the cookie; put it in each of your language home page documents:
    // SetLangCookie snippet for ModX
    // set cookie with language ID
    
    $lang=$modx->documentIdentifier;
    setcookie("Language",$lang,time()+604800, "/", "", 0);
    


    And finally, this Template Variable to make the $lang variable available anywhere you like, such as the value for the id in the main menu generation snippet, or the logouthomeid in the web login snippet.
    @EVAL
    if(isset($_GET['lang'])) {$lang=$_GET['lang'];}
    else if(isset($_COOKIE['Language'])) {$lang=$_COOKIE['Language'];}
    else {$lang=$modx->config['site_start'];}
    return $lang;
    


    Now, the user stays in the language area he selects, until he selects another.


  • xwisdom Reply #7, 6 years, 11 months ago

    Reply

    Very nice susan. Very nice


  • sottwell Reply #8, 6 years, 11 months ago

    Reply
    Dumb. Don't need a modified menu generation snippet to put a lang variable into the URL query string. The snippet in the language home page determines the lang by its document ID. So any simple list menu would work.


  • sottwell Reply #9, 6 years, 11 months ago

    Reply
    Ok, here's the final (I do hope! ) simplified, actually functional version:

    snippet SetLang (put in each of the language's homepage document/folders):

    // SetLangCookie snippet for ModX
    // set cookie with language ID
    
    $lang=$modx->documentIdentifier;
    setcookie("Language",$lang,time()+604800, "/", "", 0);
    if($_COOKIE['Language'] != $lang) {
        $url = $modx->makeURL($lang);
        $modx->sendRedirect($url);
    }
    


    And the TV:
    
    @EVAL
     if(isset($_COOKIE['Language'])) {$lang=$_COOKIE['Language'];}
    else {$lang=$modx->config['site_start'];}
    return $lang;
    


    Put it wherever you need the language variable; for example in the main menu snippet : [[MenuBuilder?id=[*lang*]]]

    Full instructions attached.


  • rthrash Reply #10, 6 years, 11 months ago

    Reply
    Thanks for a great and elegant solution Susan!

    Just a note for those that might not be aware, using this method requires duplicating the "language version(s)" of your site into a seperate folder, with each version being manually translated into the appropriate language(s). Probably the best way to procede is to build your site in your native language in a folder, then duplicate the folder and rename to the appropriate language(s) then start translating. Is that has what works best in your exprience, Susan?