Creating a Multilingual CMSMS Site Using MleCMS Module

There are often discussions in the CMS Made Simple Board about setting up a Multilingual site using CMSMS, so this time we are going to walk through the setup process of a Multilingual site using MleCMS Module.

I have already written an alternative way of setting up a Multilingual site, which you can find in my Blog:  “Another method of Multilignaul CMSMS Page“.  Shortly after my Blog post, the MleCMS Module was released and it became my preferred method when it comes to building a Multilingual site using CMSMS.

I still hope that someday a built-in solution will be introduced, or a module with better Workflow will be released; for now, I  think MleCMS gets as close as possible to a decent solution.

First let’s have a look what will we need:
MleCMS Module
CGExtensions Module
CGContentUtils (if pages exist in one language)
CGSimpleSmarty 

Usually, you can find all of these modules and install them by simply using Module Manager (Extensions » ModuleManager). Once you have these modules installed you will need to Setup languages that should be used for your site.

Setting up pages:

As an example, we are going to setup a site using English and German languages. Let’s assume that in our example we already have some pages setup using the English language, so we can have a look how easy you can copy existing site using CGContentUtils module (I will work with sample content that comes with default CMSMS setup).

Create English page

Create English page

The first step is to click “Content » Pages” and create a new page called “English”. In the “Options” tab, we will change the Alias of the page to “en” (or whatever you prefer to use as language identifier) and then hit “Submit”.

 

 

 

 

 

Reorder pagesAs we have our “English” language page created, we have to move our existing pages as “children” of English page.  To do so, click on “Reorder Pages” in the “Current Pages” interface and move all parent pages including their children one level to the right using simple “drag & drop”.

 

 

 

 

 

When you are done click on “Submit” to save your changes.

I mentioned before that we are also going to have a look at CGContentUtils module, as we want to copy our existing pages to new language. In this case, to create the “German” part of the site.
Go to “Extensions » Calguys Content Utils” and click on tab “Export Content”. Select from dropdown “1. English” and leave “Export Children” checkbox checked, then press “Submit”. By clicking on “Submit” a file called cms_content.xml will be exported.

To import that content, click on “Import Content” tab select cms_content.xml file after clicking on “Upload” button and click “Submit”. If there was no error you should see see a list of Imported pages. Now when you go back to “Content » Pages” you will see two parent pages (if you followed so far, hierarchy numbers should be 1 and 2 for these pages) both named “English”. Open “English” page with hierarchy number 2 and change the Title and Menu Text to “German” and change page alias to “de” under “Options” tab.
In same procedure  we can change this page to “Content Type: Internal Page Link” and select our “2.1 Home” page as “Desitnation page”. Repeat this process also for our original “English” page.

 

 

If you have done everything as described above you should see a page structure like this:

Configuring MleCMS Module:

 

 

 

 

 

 

As we have our page structure ready we can move on to configuring MleCMS module. After installing, the module can be found in “Content » MleCMS“. The first thing we have to do is define which languages we are about to use. To do so, click on “Add” in “Multilang config” tab.
In the next Interface enter name, Root alias (this is alias of our Lanugage parent pages) and Locale of the language. In our case, this would be “english, en, English” and “Deutsch, de, Deutsch”.

Now you can go on to “Multilang template” and edit, create or choose one of Language switching templates. For this example, we are simply going to set “Separator” tempalte to default.

We have everything we need setup so far and can move on to our page Template.

Configuring our Template:

For our demonstration we will simply use the NCleanBlue Template that comes with Default CMSMS installation. Go to “Layout » Template” and open the Template for editing. First thing we need to is initialize the MleCMS module in our Template. This will give us variables {$lang_parent} and {$lang_locale} later on.
To do so add  {MleCMS action=’init’} on top of Template before anything else (where {process_pagedata} is).

The next step is adding our “Language Switch”, so choose a place in your Template where you want it to appear and add {MleCMS action=’langs’}. This will create links to our Parent pages (English, Deutsch).

As we don’t want to show our Languages as part of Navigation we also have to edit our MenuManager tag in the template. Search for {menu} in your Template and change it to {menu childrenof=$lang_parent}. In my case (using NCleanBlue) it looks like this:

{menu loadprops=’0′ childrenof=$lang_parent template=’cssmenu_ulshadow.tpl’}.
And this is what we have so far.

Unfortunately, when you look at “Breadcrumbs” you will see that there is also “English” shown, so if you are like me you will not like that in your Breadcrumb. Luckily we have a solution for this too, by simply using MenuManager instead of Breadcrumbs tag (Thank you Foaly*).
Go to “Layout » MenuManager” and create new Template, name it for example “menu_breadcrumbs” and add following code.

<div class="breadcrumbs core-float-right">
  {translate text='You are here:'}
{if $lang_parent == 'en' && $content_id != '15'}
  {cms_selflink dir='start' menu='1'} &raquo;
{elseif $lang_parent == 'de' && $content_id != '62'}
  {cms_selflink page='62' menu='1'} &raquo;
{/if}
{foreach from=$nodelist item=node}
  {if $node->parent}
    <a href="{$node->url}">{$node->menutext}</a> &raquo;
  {elseif $node->current}
    <a href="{$node->url}"{if !isset($get_title)}class="selected"{/if}>{$node->menutext}</a>
  {/if}
{/foreach}
{if isset($get_title)} &raquo; <span class="selected">{$get_title}</span>{/if}
</div>

So what have we done above?
The {translate} tag comes from MleCMS module, this is used to translate strings using MleCMS module (see tab Translate) , you can also use output from modules like {translate text=$entry->somefield} or even assign that tag and reuse it.

Next we check which language we are in, and if content_id (the id of the page, hover over “page title” in backend to find the id)  is not the same as id of English or German “Home” page we show link to “Home”, then the rest of the Breadcrumb path is built.

You can also see that I used the variable $get_title. If you have followed some of my other Blog posts like “How to put Your CMSMS Metatags on Autopilot” you will probably know that we can assign a title from other modules and use that in our Template as title (for example in News Detailtemplate: {assign var=’get_title’ value=$entry->title}.

In this example, if we happen to be on page “News”  and reading a full News article on News Detail page, our breadcrumb would look like “Home » News » Some news article title”

 What about “Global Content Blocks”?

If you have been using CMSMS regularly, you will know that Global Content Blocks are very useful when it comes to content that is the same on all pages (for example having some teaser text in sidebar or something). When using MleCMS Module you have another way of using this sort of content, especially if it has to be translated to used languages.

In this case, when we would have some “Call for Action” text in sidebar which should be displayed in English and German, we would make use of MleCMS module features by using “Snippets” and “Blocks” options in Module interface.

What i am trying to say is, you should avoid usage of “Global Content Blocks” if you need these multilingual. Instead use MleCMS Snippets and Blocks to keep your database requests to a limit.

At this point we have a functional multilingual site and we can start using it, but if we want to make our site more flexible and use it for more then some plain text, we will most possibly also need some modules.

Using modules with MleCMS

Currently, there isn’t much flexibility when it comes to multilingual sites and modules, and we have no control over module output based on language. Even worse, we have no control when it comes to URL structure of the module.
The majority of content based modules within CMSMS offer either some sort of “Category” settings or ability to add “Extra Fields”. These are the solutions we can use when building a multilingual site.

Let’s have a quick look at the News module.

The News module is probably most common module you will use in most of your projects. Best way to use this module within a multilingual site is by setting up two categories, “English” and “German” in our example, and as subcategories are supported, we can create common categories as subcategories in each language.

After creating our categories as seen in the screenshot, we can select subcategories based on language when writing an article. When adding our News tag in the template we have to make sure that we also use the “category” parameter. Also, make sure if  you are using News in your sidebar, to show latest news that you specify in the “detailpage” parameter, this way you can keep your page structure clean and avoid landing in “German” language when reading English news article.

Basically, you could make use of “Snippets” in MleCMS Module, but in my opinion this results in unneeded database requests, so you could also use something along these lines to come to your goal.

{if $lang_parent == 'de'}
{news detailpage ='aktuelles' category='Deutsch*' number='5' lang='de_DE'}
{else}
{news detailpage='news' category='English*' number='5' lang='en_US'}
{/if}

What we have done here is check if we are currently located on a page where the parent page alias is “de” using $lang_parent variable from MleCMS Module. If that is the case, we have our News tag which shows News from “Deutsch” and with * we specify that Subcategories should be included.

If the above isn’t the case, “English” is shown. You may have noticed that I simply used {else} instead of checking for “en” as we have only two languages. English may be used as the default language if other fails.

So far so good, but one Problem remains.

You will probably want to show “Published Date” when showing News on the frontend, but you will notice that no matter which language you are in, “English” (in case this is your default language set in “Global Settings”)  will be shown.
With a regular one language setup you could simply “fix” this problem by setting locale in config.php file to  $config[‘locale’] = ‘de_DE';  but as we use a Multilingual site this doesn’t help us much.

A solution to this problem is a small UDT that makes use of PHP setlocale function. The idea comes from a Blog post “Localize your Dates” written by CMSMS user Manuel, but i wanted to prevent all if statements inside a Template (to keep it cleaner), so i made use of stripped down UDT “get_root_page” which can be found on cmsmadesimple.org site under “Share your tags” section.

Go to “Extensions » User Defined Tags” and create a new UDT with the following content and name it “set_locale”.

$gCms = cmsms();
$smarty = $gCms -> GetSmarty();

$op = $smarty->get_template_vars('content_obj');
$current_id = $smarty->get_template_vars('content_id');
$temp = explode('/', $op->mHierarchyPath);
$root_alias = $temp[0];
$temp = explode('.', $op->mIdHierarchy);

if ($root_alias == 'de') {
	setlocale(LC_ALL, array('de_DE.UTF-8','de_DE@euro','de_DE','german'));
} else {
	setlocale(LC_ALL, array('en_US.UTF-8','en_US','english'));
}

This UDT checks for the page alias of root parent page, in our case that would be “de” and “en”, then in an if statement we look for “de” and change locale setting using “setlocale” to German, as default we have “English”. When you save this UDT by hitting “Submit” go to your page template and add this newly created UDT on top of the tempalte using {set_locale} tag (set_locale comes from name of the UDT).

Now when you switch language in the Frontend, date language displayed in News article should change according to current language to.

When a module doesn’t offer “Categories” you will have to make use of “Extra fields”. Basically what you would do is create a Module template using same technique as  described above where we used $lang_parent variable to show correct News category.

Another option is also to simply use {translate} tag that comes with MleCMS module. An ideal example for this kind of usage would be FormBuilder module where all you need to translate are some Form labels and notifications.

I hope you get the basic idea about how to work with modules in Multilingual site using MleCMS.

What about Search results?

This is a very common question when it comes to Multilingual sites in CMSMS, as there is no built in function to filter results based on language. As limited as the Search module is, it doesn’t mean it is not possible.Since the release of CMSMS 1.10 Martinique, there is also a preference for selecting standard Search module, meaning if some Module developer has a good idea about an alternative Search module, it is just a matter of time that we will see an alternative module.

So what can we do about Search results?

We will make use of another UDT. I actually blogged about that in “How to Add Content Summary for Search Results“, but it is slightly different as we check for “URL” output from Searchresults.

Go to “Extensions » User Defined Tags” and create new UDT called “get_alias” with following content.

/** Get page alias from url
* @params string $params['url']
*/
$gCms = cmsms();
$cntnt = cmsms()->GetContentOperations();

foreach ($cntnt->GetAllContent() as $page) {
if ($page->GetURL() == $params['url']) {
   $return = ($page->mAlias);
   break;
}
}
if(!empty($params['assign'])){
        $smarty = cmsms()->GetSmarty();
        $smarty->assign(trim($params['assign']), $return);
}
else{
        return $return;
}

When you have your UDT ready go to “Extensions » Search” and edit “Result Template”. What we are about to do is make use of created “get_alias” UDT to get alias of the page from search result URL, then using that result we will make use of CGSimpleSmarty module to get root alias of that page, which should return “en” or “de”. When we have that result we can then use $lang_parent variable to compare our search result with current page language and display results relevant to this language.

So our “Result Template” should look something like this:

{strip} <h3>{translate text=$searchresultsfor} &quot;{$phrase}&quot;</h3>
{if $itemcount > 0}
	{foreach from=$results item=entry}

	{get_alias url=$entry->url assign='set_alias'}
	{$cgsimple->get_root_alias($set_alias, 'is_lang')}
	    {if $entry->module == 'News'}
		{if $lang_parent == 'de'}
		{news category="Deutsch*" detailpage='aktuelles'}
                {* you could create searchresult template and use summarytemplate parameter for that *}
		{else}
		{news category="English*" detailpage='news'}
	   {/if}
           {if $is_lang == $lang_parent}
             <a href="{$entry->url}">{$entry->urltxt}</a> 
           {/if}
        {/foreach}
{/if}
{/strip}

Thats it! We have our Search results that should be shown based on current page language. The part with News module should be repeated for every module that you use and that returns search results.

I hope you have enjoyed this post and found some useful hints.

Happy hosting,

Goran Ilic

Looking for a great CMSMS hosting option? Look no further than Arvixe Hosting!

 

Tags: , , , , | Posted under CMS Made Simple, Programming/Coding | RSS 2.0

Author Spotlight

Goran Ilic

Goran Ilic is a designer, all-rounder, husband, father, and founder of a CMS Made Simple related blog called: I do this (www.i-do-this.com). After long search for a perfect tool for his clients he has found CMSMS and devoted his passion to it.

20 Comments on Creating a Multilingual CMSMS Site Using MleCMS Module

  1. hello, great post Goran, but wouldnt be more simple to create our own custom class to provide multilingual content? As you know classes are dynamic objects that can be set programmatically, for instance i can provide the class with a database connection and all what it takes to request the translation of a sentence in language X to language Y to be shown on the webpage.

  2. Goran Ilic says:

    Hi Stefano,

    i would say if you have a decent solution, why not submit it to DEV Team as Feature Request?

  3. bzh says:

    Hi
    Thanks for this article.
    I have a simple question how did you manage your multilangage site if you have more than 2 language ? for example the “Result Template” ?
    bzh

  4. Petr says:

    Hi,

    When using the parameter {menu childrenof=$lang_parent} parameters do not work collapse, items, number_of_levels, start_level, start_page. They work only excludeprefix and includeprefix.

    Petr

  5. Goran Ilic says:

    Hi Petr,

    that is correct and this is MenuManager feature.

  6. Petr says:

    It goes some way to replace? Thanks

  7. Goran Ilic says:

    No.
    But you can read through this post http://www.i-do-this.com/blog/25/Another-method-of-Multilingual-CMSMS-Page i used start_element there, so basically you can adopt that to use with MleCMS.
    What you would need is a UDT that checks for root parent like “en” and “de” and the returns it’s firendly position number.

  8. Goran Ilic says:

    @bzh well you would need {if $lang_parent == ‘second_language’} do something {elseif $lang_parent == ‘third_language’} do something {else} something else {/if}

  9. Bertus says:

    UDT for root_alias:

    ———————————-

    global $gCms;
    global $smarty;

    $manager =& $gCms->GetHierarchyManager();

    $var = ‘root_page_alias';
    if( isset($params[‘assign’]) && $params[‘assign’] != ” )
    {
    $var = $params[‘assign’];
    }
    $result = “NO RESULT”;
    $thisPage = $gCms->variables[‘content_id’];
    $currentNode = &$manager->sureGetNodeById($thisPage);
    while( isset($currentNode) && $currentNode->getLevel() >= 0 )
    {
    $currentContent =& $currentNode->getContent();
    $result = $currentContent->Alias();
    $currentNode =& $currentNode->getParentNode();
    }
    $smarty->assign(“root_alias”,$result);

    // name the udt “root_alias”, insert {root_alias} at the top of the template. When using {$root_alias}, it dislays the root_alias of the current page.

    —-

  10. Goran Ilic says:

    @Bertus

    If you followed this post you will see that at the very start i mentioned we will also install CGSimpleSmarty, with this module you can easily get root_alias without a UDT.

  11. Mae says:

    Hi! Is there any way in which I can choose items not to be translated, for example if my company name is Golden Balls I want it to stay the same regardless of translation as ‘Pelotas de Oro’ just doesn’t have the same ring to it. Any ideas? :)

  12. Mr. Bacan says:

    Simply a Great tutorial. Once again, you saved my life Goran.
    Thanks for another excellent and easy to follow tutorial.
    Keep the good work.

  13. Dominik Lenné says:

    Hi,

    AFAICS the set_locale UDT doesn’t work any more like this, at least I get an

    “Cannot access protected property Content::…” – error

    at this point

    $op->mHierarchyPath.

    . I tried to use $cgsimple->get_root_alias(), but somehow I can’t get it to work, the $cgsiimple-Objekt seems to be unknown.

    it would be very generous ba you to address this issue somehow.

    Dominik

  14. Dominik Lenné says:

    Hi,

    I got it to work, now it looks like this:

    $gCms = cmsms();
    $smarty = $gCms -> GetSmarty();
    $cgsimple = $smarty->get_template_vars(‘cgsimple’);

    $root_alias = $cgsimple->get_root_alias();

    if ($root_alias == ‘de’) {
    setlocale(LC_ALL, array(‘de_DE.UTF-8′,’de_DE@euro’,’de_DE’,’german’));
    } else {
    setlocale(LC_ALL, array(‘en_US.UTF-8′,’en_US’,’english’));
    }

    thanks anyway

  15. Hi Goran,

    Thank you for this complete walkthrough!
    I have everything working as I wanted, I only need to translate the content ;)
    But that is not the question I wanted to ask.

    Maybe you could check my site, http://www.cedexis.nl where you will see that the 4th tab of the menu is shows without layout.
    It doesn’t matter if I change the name, make a new page or change the order of the pages. Everytime the 4th tab is without layout.

    This was not the case before I made my page multilang with this walkthrough!
    Hopefully you can help?

    With kind regards,
    Luuk van der Heijden

  16. Bill Cadwallader says:

    First off, thanks Goran!

    The get_alias UDT referenced in the search section of this article doesn’t work in 1.10.x and up, but there’s a new version written by Goran at http://www.i-do-this.com/blog/58/Get-alias-from-a-page-URL

    Here it is for reference:

    /** Get page alias from url
    * @params string $params[‘url’]
    */

    $gCms = cmsms();
    $cntnt = cmsms()->GetContentOperations();

    foreach ($cntnt->GetAllContent() as $page)
    {if ($page->GetURL() == $params[‘url’]) {
    $return = $page->Alias();
    break;}}
    if(!empty($params[‘assign’])){
    $smarty = cmsms()->GetSmarty();
    $smarty->assign(trim($params[‘assign’]), $return);
    }
    else
    {
    return $return;
    }

  17. Alex says:

    Hi Goran!

    You should add that you HAVE to install the corresponding language packs. Your example worked because the english language pack is default. If you want to set up e.g. a french version, you HAVE to install the CMSMS fr_FR language pack, otherwise the pages won’t show.

    Cheers,
    Alex

  18. Jack4ya says:

    For search results I use

    {foreach from=$results item=entry}
    {if $entry->url|replace:’http://www.yourdomain.com/':”|truncate:5:” == $languagesetting}
    {$entry->title} – url}”>{$entry->urltxt}
    {/if}
    {/foreach}

    But it might be ugly filtering?

    Btw: {$languagesetting} >> comes from {$cgsimple->get_root_alias() assign=”languagesetting”}

    As the page structure is
    root
    – en_US
    – – child
    – – and so on
    – nl_NL
    – – child
    – – and so on

  19. Martin says:

    Thank a lot Goran!
    Martin

  20. Marcus says:

    Thank you for this guide!

Leave a Reply

Your email address will not be published. Required fields are marked *


8 − 7 =

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>