TYPO3 multi language & multi domain site with RealURL and language menu

This is a step-by-step tutorial which describes in detail how to setup TYPO3 for a multilingual website with "domain language switching". It will describe how to properly configure RealURL, extend it's configuration with simple PHP statements in the RealURL configuration file and last but not least, probably the most important thing: the language switch menu with cross domain support.
I started with a clean TYPO3 installation and created two page trees in order to test the setup in a multiple page tree setup. Therefore I defined that on my local Linux box typo3-ml.local listens to the default language, while typo3-ml-en.local and typo3-ml-it.local - you guessed it - listens to the english and italian language versions of the page tree.
Note: This article is deprecated. Please see the latest comments. I'll post a follow-up as soon as possible!
Deprecated article
This article is deprecated. Please see Dmitry Dulepovs comment.
I'll post a follow up to this article as soon as possible.
Overview
The setup for a multi domain/language environment in a One-Tree-Fits-All page tree splits in 3 steps:
Conditions
The following conditions must be met to ensure the correct functionality of this setup guide:
- within one page tree every page has a unique page title in every language
- every page in a page tree has an alternative page language
- at root level, all domains must be created as domain records which should be available for the specific page tree
- the main domain records (no redirects) must not have set the "Always prepend this domain in links" option
- the root level page must have set the "Is root of website" option in the page properties
- for this sample setup the default language (sys_language_uid = 0) is german
RealURL Setup
The RealURL Setup is built upon a default setup which is built on the typo3.org news area RealURL setup then again.
At the end of this default setup you must add three lines which configures some parts of the default setup for every domain. These settings first of all affect the rootpage_id and the preVars setting for the multi domain language switch.
At first, the selected domain inherits the default setup:
$TYPO3_CONF_VARS['EXTCONF']['realurl']['typo3-ml.local'] = $TYPO3_CONF_VARS['EXTCONF']['realurl']['_DEFAULT'];
Then, you have to configure the rootpage_id:
$TYPO3_CONF_VARS['EXTCONF']['realurl']['typo3-ml.local']['pagePath']['rootpage_id'] = 1;
At last you have to override the preVars segment with a dummy array because the language switch isn't part of the URL but of the domain:
$TYPO3_CONF_VARS['EXTCONF']['realurl']['typo3-ml.local']['preVars'] = $byPassLVar;
The dummy preVars array might look like the following, but should be adjusted to fit the requirements of your preVars setting:
$byPassLVar = array(
array(
'GETvar' => 'L',
'valueMap' => array(),
'noMatch' => 'bypass'
)
);
With these settings, the well known paths de/, en/ or it/ aren't part of the URL anymore. But how do we tell TYPO3 to switch the language?
The first part of this definition is done in the RealURL configuration. You have to ensure that the L parameter is set. The best solution is to implement a switch() statement like this one:
switch (t3lib_div::getIndpEnv('HTTP_HOST')) {
case 'typo3-ml-en.local':
case 'typo3-ml2-en.local':
$_GET['L'] = 1;
break;
case 'typo3-ml-it.local':
case 'typo3-ml2-it.local':
$_GET['L'] = 2;
break;
default:
$_GET['L'] = 0;
break;
}
TypoScript setup
The language switch is done with the very well known TypoScript conditions like the following:
[globalVar = GP:L = 1]
config.sys_language_uid = 1
config.language = en
[global]
This must be adjusted in such a way to enable TYPO3 to switch the language if a specific domain request exists instead of the L parameter.
[globalString = IENV:HTTP_HOST = typo3-ml-en.local]
config.sys_language_uid = 1
config.language = en
[global]
[globalString = IENV:HTTP_HOST = typo3-ml-it.local]
config.sys_language_uid = 2
config.language = it
[global]
Additionally the following CONFIG TLO settings are very important for a proper internal language switch (as an example for the english language):
config.htmlTag_langKey = en_US
config.locale_all = en_US.utf8
config.baseURL = http://typo3-ml-en.local/
The language menu
The final step: the language switcher. I've spent a lot of time for investigating the best approach for this issue. Finally, I found two solutions:
Upon a closer view I think the solution of Bernhard is the better one because it allows a better maintainability and extendability if it comes to adjust the typolink setup or add more domains.
temp.menu.language.de = COA
temp.menu.language.de {
stdWrap.wrap = <li>|</li>
10 = TEXT
// the german domain
10.value = typo3-ml.local
// note to add "www." in production environment
10.wrap = <a href="http://|/
20 = TEXT
20.typolink {
parameter.data = TSFE:id
returnLast = url
additionalParams = &L=0
addQueryString = 1
addQueryString.method = GET
// must be set, otherwise id parameter appears 2 times
addQueryString.exclude = id
}
30 = TEXT
30.value = DE
30.wrap =">|</a>
}
temp.menu.language.en < temp.menu.language.de
temp.menu.language.en {
10.value = typo3-ml-en.local
20.typolink.additionalParams = &L=1
30.value = EN
}
temp.menu.language.it < temp.menu.language.de
temp.menu.language.it {
10.value = typo3-ml-it.local
20.typolink.additionalParams = &L=2
30.value = IT
}
// compile language menu
lib.menu.language = COA
lib.menu.language {
wrap = <ul id="menu-language">|</ul>
10 < temp.menu.language.de
20 < temp.menu.language.en
30 < temp.menu.language.it
}
// set active state according to domain/L parameter
// the active item won't be linked
[globalVar = GP:L = 0] OR [globalString = IENV:HTTP_HOST = typo3-ml.local]
lib.menu.language.10 = TEXT
lib.menu.language.10 {
value = DE
stdWrap.wrap = <li class="active">|</li>
}
[global]
[globalVar = GP:L = 1] OR [globalString = IENV:HTTP_HOST = typo3-ml-en.local]
lib.menu.language.20 = TEXT
lib.menu.language.20 {
value = EN
stdWrap.wrap = <li class="active">|</li>
}
[global]
[globalVar = GP:L = 2] OR [globalString = IENV:HTTP_HOST = typo3-ml-it.local]
lib.menu.language.30 = TEXT
lib.menu.language.30 {
value = IT
stdWrap.wrap = <li class="active">|</li>
}
[global]
Important notice: during testing I experienced that the following configuration keys must not be set:
config.typolinkCheckRootline = 1
config.typolinkEnableLinksAcrossDomains = 1
Improvement suggestions
This version of the language menu is built with other TypoScript cObjects than the well known and maybe preferred HMENU cObject, which also supports a language menu creation via the special. configuration key.
For example it's possible to define the language menu item state for non-existing page translations. I think that's the only drawback but you get a much more important feature: domain driven language switching.
Another approach is to use the _DOMAINS feature which was introduced in RealURL v 1.5. But during testing this you'll experience not properly translated URL paths because of a bug in RealURL.
Downloads
Sample page tree export with TypoScript setup
14.3 K
RealURL configuration, place in typo3conf/ directory
1.4 K
Links & sources
The following ressources gave me a better understanding for writing this article:
- keilblock.com: RealURL mehrsprachig: pro Domain eine Sprache ohne Get-Parameter / preVars (german)
- TYPO3 Mailinglist: Jo Hasenau "Link mittels typolink auf anderen Domain" (german)
- Bernhard Berger on typo3blogger.de: "Sprachwechsler mit TypoScript und Domainwechsel (german)
- Lina Wolf on typo3-blog.net: "Mit RealURL Multilanguage Site mit Multidomains realisieren" (german)
- TYPO3 Bugtracker: Bug 001074: localized pagePath encoding by tx_realurl_advanced not working when using new _DOMAINS config





Comments
Loved the downloads (t3d & realurl_conf.php), not everybody think about this.
Thank you for sharing this! =)
thank you for your comment. Glad, you like the article. Yes that's what I thought while writing: never seen downloads of page trees of archived configuration (just code fields in the text which are sometimes difficult to handle and copy & paste) ;)
Best wishes,
tommy
With the combined t3d download and your information, I got finally the right understanding for multi language implementations. No other documentation did do that :-)
Thanks a lot.
You should use this approach. It is plain wrong. There are too many conditions, that would cause a lot of entries in cache_hash, slower web site and problems if you want to add a new domain. Instead, you should use _DOMAINS feature of RealURL. It handles languages depending on domain name. Just read the manual (or see links at the bottom of my post).
In addition, you should not use _DEFAULT when you have multiple domains because that causes other hard to solve issues.
More reading:
http://dmitry-dulepov.com/article/realurl-made-easy-part-2.html
http://dmitry-dulepov.com/article/realurl-separate-language-domains-in-an-easy-way.html
thank you for your kind and valuable comment. I'll post a follow up to this article as soon as possible and mark this one as deprecated.
Greetings,
tommy
very nice step by step! what would also be interesting maybe is how to set up automatic language detection.
Greetings
thanks for your comment. I wouldn't recommend a server side language detection because of the search engine spiders which will be misled with this functionality.
E.g. let's assume the Google bot starts a crawl of your website for the german search index, but the bot resides on a computer in England - guess what? The automatic language detection (e.g. it's IP/geolocation based) will switch to english.
I think a better approach will be a client side redirect. With JavaScript. That won't hurt any search engine spiders. If you're interested, I'll write an article how to achieve this goal.
Best regards,
tommy