Wow !
When I decided to build a contexts based multilingual site, I definitely didn’t expect it to necessitate so much research to reach a working implementation.
The different possible approaches of implementing the context switching mechanism has been a little confusing at first and the implications of choosing one or the other didn’t stand clear.
Happily, I finally got a working solution that I’m gonna try to summarize here as it most probably might help others in their quest
The "straightforward" solution presented at
http://churn.butter.com.hk/posts/2010/08/internationalization-in-modx-revolution.html isn’t satisfactory for everyone as it necessitates the usage of domain aliases. Whilst the solution presented here above by OpenGeek is only partially working, specifically when using a deeper that one level site structure (I won’t delve into the details of this but try for yourself if you are interested in learning
).
A "Pseudo Subdirectory Context Based" solution
The presented solution is "kind of" subdirectory based. What I mean by that is that any specific context will be reached using the first part of the url ( i.e.:
http://www.mydomain.com/context/ ).
But, in the end, you WILL NOT need to effectively create any subfolder in your root directory, only relying on the original MODx index.php file. This seemed much more cleaner to me and is achieved simply by adding one RewriteRule line in your .htaccess file. This also allows for a solution that does not need you to create any "special" system setting pointing to your base URL, you simply use the existing [[+base_url]] setting.
Once again, I won’t delve too deep into the details as it would be too long, but, simply put and quite obviously, using the first piece of the URL to identify the context you are targeting makes all your files (assets) references go wrong, as they will be fetched from one level deeper than the original index.php file. So here we reach the first step in building a "pseudo subdirectory" contexts based site:
1 - Referencing assets in your templates, chunks and snippets
As stated above, using the exposed technique implies all assets must be referenced from the base_url, and not from the apparent URL location (that is necessary whenever you activate FURLs along with use_alias_path).
To achieve this, simply reference all asset additions using the [[++base_url]] system setting. That is, in a
template or chunck element, reference you assets as follow:
<link rel="stylesheet" href="[[++base_url]]assets/templates/css/myrules.css" type="text/css" media="screen" />
<script type="text/javascript" src="[[++base_url]]assets/libs/myjscode.js"></script>
<img src="[[++base_url]]assets/templates/images/myimage.png" alt="description" />
<!-- or from a TV -->
<div class="img_container" style="background: url([[++base_url]][[*tv_image]]) no-repeat"></div>
When it comes to snippets (embedding code in the head part for example), reference your assets using:
$modx->regClientStartupScript( $modx->getOption('base_url') . 'assets/libs/myjscode.js' );
NOTE: a problem exists with images referenced into RTE (tineMCE) generated content which I had no time to search for, feel free to post a solution, or I’ll try to complete this information whenever I get the time to do it
2 - Setting up the contexts
That is easy !
Simply go to the System -> Contexts menu and create the ones you need.
Once they are created, click on their names in the "Ressources" tab in the site tree, displaying their parameters.
Select the "Context parameters " tab and create the "site_url", "cultureKey" and "site_start" parameters (skip the quotes of course...).
Set their values as in this example:
site_url = {base_url}fr/
cultureKey = fr
site_start = 20
Let’s say that this is set on the context named "francais", you will be able to reach this context using:
http://www.mydomain.com/fr/
You could also set the "error_page" and "unauthorized_page" parameters in case you need to localize them.
Finally, you have to grant the "Load Only" access policy for all your contexts to the anonymous group to let your users load the contexts.
Go to the "Security -> Access controls" menu, right click the (anonymous ) group name and select "Update User Group", select the "Context Access" tab. Add each of your contexts to the list using the "Add Context" button, select your context from the first menu, for the "Minimum Role" select "Member - 9999" and for the "Access Policy" select "Load Only".
3 - modifying your .htaccess file
Note: you have to activate FURLs in your system settings through the friendly_urls system setting first. Also set the friendly_alias_urls and use_alias_path according to your needs.
You now have to tweak your .htaccess file to rewrite upcoming requests, allowing your (to come) "gateway" plugin to function properly:
Open your .htaccess file and set up "The Friendly URLs part" as follow (don’t forget the RewriteBase in case your solution does not resides at the root level of your host) :
....
RewriteEngine On
RewriteBase /
....
# The Friendly URLs part
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Use this as the "regular" FURL rule
#RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
# Use this alternative rule for "pseudo subdirectory" context access
# you need to adapt the string in first parenthesis to your configuration
# note that an adapted "gateway" plugin is required to manage context switching
RewriteRule ^(en|fr|nl)?(\/)?(.*)$ index.php?c=$1&q=$3 [L,QSA]
....
This rule reads the passed url and rewrites it to call index.php with the passed URL as URL parameters split into two parts:
c -> the potentially selected context
q -> the requested page (in its FURL form, usable by the MODx engine)
Do not forget to adapt the first section of the RewriteRule - here (en|fr|nl) - accordingly to the settings you made on each of your contexts (i.e: {base_url}
en/ etc...).
4 - The "gateway" plugin
Your system is now set up, we still have to create the gateway plugin that’s going to manage the passed parameters, effectively switching to the targeted context.
Create a new plugin: select the elements tab on the site tree and click the new plugin button. Name it "gateway" (or whatever you like after all
).
Use the following code template for its content:
<?php
//make sure the plugin does not run on the mgr context (the manager)
if ( $modx->context->get( 'key' ) != 'mgr') {
/**
* grab the current context from the request "c" parameter (or context_param_alias from system settings)
* the alternative .htaccess friendly URL rewrite rule must be activated
*/
$cntxt_param = $modx->getOption('context_param_alias', null, 'c');
if ( isset( $_REQUEST[$cntxt_param] ) && $_REQUEST[$cntxt_param] != '' ) {
switch ( $_REQUEST[$cntxt_param] ) {
case 'en':
//switch the context
$modx->switchContext('web');
//set the cultureKey
$modx->setOption('cultureKey', 'en');
break;
case 'fr':
$modx->switchContext('francais');
$modx->setOption('cultureKey', 'fr');
break;
case 'nl':
$modx->switchContext('nederlands');
$modx->setOption('cultureKey', 'nl');
break;
default:
// Set the default language/context here
$modx->switchContext('web');
$modx->setOption('cultureKey', 'en');
break;
}
}
}
Save it.
The one last thing you need to do is link the plugin execution to the "OnHandleRequest" event. To do this, click on the plugin’s "System event" tab an scroll to the "OnHandleRequest" line, checking that checkbox and saving...
That should do it !
5 - Add-ons
Using Add-ons with such a configuration can sometimes lead to unexpected results, for example Wayfinder needs to be called with the "&fullLink=`TRUE`" parameter. It is, of course, impossible to offer a global solution for this, so you’ll probably have to explore and tweak some things a bit to get your working solution ( I’m currently working on a tagLister solution...).
Please feel free to post any solution you might find for specific add-ons as it might certainly help others gain some time
By the way, if you intend to build contexts based multilingual sites I strongly recommend you have a look at the fantastic Babel add-on:
http://modxcms.com/extras/package/?package=781
I
think I didn’t forget anything but in case I did, please notify here and I’ll update this post. I’ll also update it regarding the RTE images whenever I get the time to do it.
Hope this helps others as I couldn’t find any "Ready Made" context switching solution so far... now you have one
Regards