How to detect and change frontend langage with lexicon i18n?

Hi :slight_smile:

I want to translate a website by using lexicon topic, but without context (because I don’t want to duplicate my html layout).

So I have created 2 news files :

  • core/lexicon/en/mywebsite.inc.php
  • core/lexicon/fr/mywebsite.inc.php

Inside my resource contents, I’m using theses tags to get lexicon entries :

  • for the first entry : [[%home.title? &topic=mywebsite]]
  • for the others : [[%home.subtitle]]

It’s working well for my current cultureKey (fr) but I don’t know how to switch to the other cultureKey (english for now).
I think the best way is to detect the preferred language inside the browser and move to the correct url (https://mywebsite.com/fr or https://mywebsite.com/en) and change the correct cultureKey but I don’t know how to doing this.

After some research, I have tried with a plugin called DetectCulture :

<?php
// get lang from URI
$uri= ($_SERVER['REQUEST_URI']);
$langFromUri = substr($uri, 1, 2);
switch ($langFromUri) {
  case 'fr':
    //set the cultureKey
    $modx->setOption('cultureKey', 'fr');
    break;
  case 'en':
    //set the cultureKey
    $modx->setOption('cultureKey', 'en');
    break;
  default:
    // detect language and call corresponding start-page
    $langPrefered = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
    switch ($langPrefered) {
      case 'fr':
        $targetId = 1;
        break;
      case 'en':
        $targetId = 1;
        break;
      default:
        $targetId = 1;
        $langPrefered="fr";
        break;
    }
    //set the cultureKey
    $modx->setOption('cultureKey', $langPrefered);
    //call correct start page
    $url=$modx->makeUrl($targetId);
    $modx->sendRedirect($url);	

  break;
}

return;

… but it’s doesn’t work

What’s going wrong ? Should I use context ? But how to avoid the html duplication ?

Maybe you could use the Lingua extra to create a multilingual website without different contexts.

You have to create the lexicon calls uncached in your case, since it can be changed with the plugin on the same page.

[[!%home.title? &topic=`mywebsite`]]

@halftrainedharry : I’m not sure for the Lingua addon in my use case. I want to externalize the translated strings on separate files, eventually accessible from the lexicon manager, but it’s another story :slight_smile:

@jako I try your tip but it’s not enough : the cultureKey is not changed. By the way, how should I change the browser language properly ? Is changing the default language is enough to ask MODX plugin to detect the other cultureKey ?
I’m also not sure about the code of my plugin. Maybe there is a, issue with it !

Maybe you also have to set $modx->cultureKey after $modx->setOption('cultureKey', …);

Honestly, I don’t exactly understand what your plugin does.

I could be wrong, but I think when you set the culture key $modx->setOption('cultureKey', $langPrefered); and then immediately make a redirect $modx->sendRedirect($url); the value you set the culture key to doesn’t persist for the next request, but is lost right away.

Maybe it works if you set the culture key in the session:

$_SESSION['cultureKey'] = $langPrefered;

Indeed, the switch to other language still doesn’t work :frowning:

To be clear, my need is :

Is it possible to doing this stuff ?

So you have 3 different resources for https://mysite.com, https://mysite.com/en and https://mysite.com/fr?
Does any of them work?

No I only have one resource per page !

I though I could have only one context, with several pages/resources and in each resource the strings are called by a tag like [[!%home.title? &topic='mywebsite']]
It’s working well for french language, but my problem is to switch language from specific URL (https://mysite.com/en) or by detecting the browser language.

I already used Babel and Context on another website but on this new project, I would test another way for the internationalization by using lexicon, in the purpose to avoid to duplicate the HTML (and get a more maintainable code).

Maybe I can’t get what I want on this way !

So how exactly does MODx know, that a call to https://mysite.com/en should open the same resource as https://mysite.com/fr?
Do you have some rules for that in your .htaccess or do you use another plugin or an extra like CustomRequest?

Oh… for now I don’t have rules on .htaccess neither CustomRequest…
Do you have example for my purpose ?

Maybe you could do something like this in your .htaccess, that converts /en, /fr into a GET-parameter lang.

# The new rules
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(en|fr)$ index.php?lang=$1 [L,QSA]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(en|fr)/(.*)$ index.php?lang=$1&q=$2 [L,QSA]

# The original part for Friendly URLs
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

and then in your plugin read $_GET['lang'] (instead of $_SERVER['REQUEST_URI']) and change the cultureKey based on that.

Thanks :slight_smile:
I have set the .htaccess rules as you said and modified my plugin like this :

<?php
// get lang from URI
//$uri = ($_GET['lang']);
//$langFromUri = substr($uri, 1, 2);
$langFromUri = $_GET['lang'];

$_SESSION['cultureKey'] = $_GET['lang'];

switch ($langFromUri) {
  case 'fr':
    //set the cultureKey
    $modx->setOption('cultureKey', 'fr');
    $modx->cultureKey;
    break;
  case 'en':
    //set the cultureKey
    $modx->setOption('cultureKey', 'en');
    $modx->cultureKey;
    break;
  default:
    // detect language and call corresponding start-page
    $langPrefered = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
    switch ($langPrefered) {
      case 'fr':
        $targetId = 1;
        break;
      case 'en':
        $targetId = 1;
        break;
      default:
        $targetId = 1;
        $langPrefered="fr";
        break;
    }
    //set the cultureKey
    $modx->setOption('cultureKey', $langPrefered);
    $modx->cultureKey;
    //call correct start page
    $url=$modx->makeUrl($targetId);
    $modx->sendRedirect($url);	

  break;
}

return;

I have also set the OnInitCulture system event to on.
but it’s still not working.
I’m not a developer and I’m not very good with php :frowning:

Some problems I see with your plugin code:
This line $modx->cultureKey; does nothing at all.
The redirect $modx->sendRedirect($url); isn’t necessary (in my opinion) and leads to recurring redirects when I try to test it.

I made some changes to your code:

<?php
if ($modx->context->key === 'mgr') {
    return;
}

if(!empty($_GET['lang']) && in_array($_GET['lang'], array('fr', 'en'))){
    $lang = $_GET['lang'];
    $modx->setOption('cultureKey', $lang);
    $modx->cultureKey = $lang;
    $_SESSION['cultureKey'] = $lang;
    //$modx->log(modX::LOG_LEVEL_ERROR,'language set to ' . $lang . ' from get-parameter');
}

if (empty($_SESSION['cultureKey'])) {
    $langPrefered = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
    if (in_array($langPrefered, array('fr', 'en'))){
        $modx->setOption('cultureKey', $langPrefered);
        $modx->cultureKey = $langPrefered;
        $_SESSION['cultureKey'] = $langPrefered;
        //$modx->log(modX::LOG_LEVEL_ERROR,'language set to ' . $langPrefered . ' from browser');
    }
}
  • After changing the plugin-code clear the cache in MODx.
  • Test the site with the url-parameter too. If it works with https://mysite.com/?lang=en but not with https://mysite.com/en, then the problem is the .htaccess file.
  • If it doesn’t work you can uncomment the $modx->log() lines and check the error file.
1 Like

It’s working like a charm !
Thanks a lot for your @halftrainedharry :slight_smile: :+1:

This topic was automatically closed 2 days after discussion ended and a solution was marked. New replies are no longer allowed. You can open a new topic by clicking the link icon below the original post or solution and selecting “+ New Topic”.