Feb 27, 2009

RealURL: separate language domains in an easy way

TYPO3 fully supports the making of multilanguage web sites. Everyone know the L URL parameter. But what if you want to have a separate domain for each language and keep a single page tree? Until recently it was not easy and required certain TYPO3 black magic. In this article I will describe how to do it in 5 minutes (or less!) and give you a bonus: better site position in Google.
Typically when user switches to another language, the URL changes to contain L var ('&L=1'). In case of RealURL it looks better, URL will become http://example.com/en/. This is nice looking. So far, so good.
The problem is that Google and other search engines prefer domains from the user's domain zone. If relevancy is the same, Google will prefer "es" domain to "com" domain for Spain and "de" domain for Germany. It becomes essential to have domains in the corresponding country for better search engine optimization. Registering domains is easy but how to make TYPO3 use them and keep the single page tree?
Solving this task means removing language segments from URL and converting http://example.com/de/mypage to http://example.de/mypage/.
It is possible to have language domains with TYPO3 after doing certain non–trivial TypoScript magic. Alternatively it is possible with some coding. However there is a much better, faster and more simple solution. It is brought to you by RealURL (surprise, surprise!)

RealURL 'language domains' feature

Starting from version 1.5.0 RealURL supports 'language domains' feature. It does exactly what was described above: it converts http://example.com/de/mypage to http://example.de/mypage/ transparently and without other major efforts in TYPO3. This feature needs only a small adjustment in the RealURL configuration.

Configuration requirements for language domains

To enable language domains you must have the following in you RealURL configuration:
  • language variables defined in the preVars section. See 'Making preVar section' in the 'RealURL made easy: part 1' on this site.
  • a special _DOMAINS configuration.
There is no problem with the first part. Everyone knows how to do it. The second part is new. Let's master it!

_DOMAINS RealURL configuration

_DOMAINS configuration defines how to transform a value of the URL parameter to the domain name. In other words, it links &L=0 to the example.de and &L=1 to the example.es.
Suppose that languages are configured like this in preVars:
'preVars' => array(
array(
'GETvar' => 'L',
'valueMap' => array(
'de' => 0,
'es' => 1
),
),
),
Now we need to define how this preVar maps to domains. Here it is:
'_DOMAINS' => array(
'encode' => array(
array(
'GETvar' => 'L',
'value' => '0',
'useConfiguration' => 'example.com',
'urlPrepend' => 'http://example.de'
),
array(
'GETvar' => 'L',
'value' => '1',
'useConfiguration' => 'example.com',
'urlPrepend' => 'http://example.es'
)
),
'decode' => array(
'example.de' => array(
'GETvars' => array(
'L' => '0',
),
'useConfiguration' => 'example.com'
),
'example.es' => array(
'GETvars' => array(
'L' => '1',
),
'useConfiguration' => 'example.com'
)
)
)
What does it do?
The first part is for encoding URLs. It tells that for L=0 RealURL should prepend http://example.de to the URL (notice: no slash in the end!). For L=1 RealURL should prepend http://example.es to the URL. Simple, isn't it?
The second part is for decoding. It tells RealURL what L to set when user comes for the corresponding domain. Also simple.
And the final addition to the configuration is:
$TYPO3_CONF_VARS['EXTCONF']['realurl']['example.de'] =
$TYPO3_CONF_VARS['EXTCONF']['realurl']['example.es'] = 'example.com';
Do not forget to add two new domain records for your language domains in the List module.
That's it! A couple of lines in the RealURL configuration and you have language domains without any mangling with TypoScript or hooks!
Life is good! Enjoy!

33 comments:

  1. Hey,



    thanks a lot for that tut, I will try it! ;)



    ps: can you please modify the captcha to just show numbers?

    ReplyDelete
  2. Why just numbers? :)

    ReplyDelete
  3. Gread stuff! Thanks for coding and sharing!

    ReplyDelete
  4. Great feature and crystal clear explanations. Thanks a lot!

    ReplyDelete
  5. Great article. This will definitely be a better solution than the one we are using now for a couple of sites. We did something like this in Typoscript



    [globalString = IENV:HTTP_HOST = www.domain.com]

    config.baseURL = http://www.domain.com/

    config.sys_language_uid = 0

    config.language = en

    config.locale_all = en_EN



    [globalString = IENV:HTTP_HOST = www.domain.nl]

    config.baseURL = http://www.domain.nl/

    config.sys_language_uid = 1

    config.language = nl

    config.locale_all = nl_NL

    [end]



    This also did the trick (maybe we needed just a little bit more). But we weren't able to use the language selector to only switch the L parameter. Our language selector was a link to the proper domain. Which of course will loose the functionality as well that we cannot directly view the page in another language if we change the language.

    ReplyDelete
  6. I wonder why the information must be configured twice? Wouldn't it be possible to compute the 'decode' configuration automatically?

    ReplyDelete
  7. I used the typoscript method as described by Mark.

    This makes stuff easier. Thanks for sharing.



    There is some debate on wether google still prefers the local domains... Don't know where they are now though..

    ReplyDelete
  8. I have been working around RealURL (version 1.5.3) all day yet, and I think I found some bugs when working with multiple domains and multiple languages.

    First the URL translation field is not showing. For that I had to modified the last line in the ext_tables.php as follow:

    t3lib_extMgm::addToAllTCAtypes('pages_language_overlay', 'tx_realurl_pathsegment', (t3lib_div::compat_version('4.2') ? '' : '2,4,254') . '', 'after:nav_title');



    2. I'm not able stil to make the multiple domains with the path translation work correctly together. When one is working the other one is not. I found that if I don't define the _DOMAINS array it work more or less correctly, but the function typolink don't use the domains. That is ok as long as I don't try to make any cross language link.



    I would apreciate if you can give me a hand with this second issue.



    Thanks.

    ReplyDelete
  9. The tutorial was indeed nice reading, but unfortunately I never succeeded in making this work (using latest RealURL). Frankly, there are a lot of error sources too. Some I could think of:



    1. Should one still use the "Redirect to:"-field in the foreign domain-records to reach "example.com/de/" or not?



    2. How should one write the _DOMAINS-rules to handle domains both with and without www-prefix? Or is this handled by only using "domain.tld"?



    3. Should the baseurl still be set to http://www.domain.com/ or are there special-cases depending on which language?



    I guess a full realurl_conf.php-example with a little typoscript-example would help out tremendously. :)



    Best regards,

    ReplyDelete
  10. I have the same problem reported by Mikkel: when I configure the multidomain (according to Dmitry instructions) I loose the path translation. That's probably due because the 'encode' rule removes the 'L' variable BEFORE the link is processed by pagepath rule.



    I worked it around in this way:



    1) Don't use the 'encode' rule



    2) Change the preVars rule this way:

    'preVars' => array (

    array (

    'GETvar' => 'L',

    'valueMap' => array (),

    'noMatch' => 'bypass'

    ),

    ),



    of course you lose the possibility to switch domain just changing L, but it is a minor problem compared to the untranslated path.



    PS: Dmitry thanks for your great blog!

    ReplyDelete
    Replies
    1. Hi ! I've got the same problem, but using your method do not solve any problems.

      Ommiting the encode config bring back the localisation of the path segment, but then the translated domains are not working anymore.

      Does anyone get anthing to work properly at this time ?

      Delete
  11. Dmitry, you have no idea how much you helped me with this tutorial. I had to try on error a few times to figure out the right way since i'm a newb, but now i have the url perfectly switching where before it sometimes didnt catch up with the right language and i started to digg into the ID-to-path mapping.. that's now completely obsolete, it works like a charm.

    Thank you!

    ReplyDelete
  12. And by the way.. to some of the comments above i disagree completely.. there is no such as an "easier way", because a simple globalString = IENV:HTTP_HOST does not make the job at all... you might be able to come from 2 different domainnames, but language switching will not work without that really clever solution of yours.

    ReplyDelete
  13. This works very well for me. But now I have the following Situation in a Multi-Domain, Multi-Language, Multi-Site Setup



    siteA-germanname.com

    siteA-frenchname.com



    siteB-samenameforbothlanguages.com



    I would appreciate a hint on how to solve this (with _DOMAINS feature) very much!



    Thanks for all the work

    Urs

    ReplyDelete
  14. this tutorial is great helping to configure a multi-language installation into one domain per language.

    But, like Urs, I am challenged by a multi-domain-multi-language single-tree single installation. Something like:



    domainA.de/dk --> domainA.dk/

    domainA.de/de --> domainA.de/

    domainA.de/en --> domainA.com/



    domainB.de/dk --> domainB.dk/

    domainB.de/de --> domainB.de/

    domainB.de/en --> domainB.com/



    Could anybody solve a similar problem using realurl and the _DOMAINS feature?

    ReplyDelete
    Replies
    1. Hello Josef,

      have you found a solution to this problem yet??

      Kind regards, mtness.

      Delete
  15. Great!

    It works, but I'm using sr_language_menu and it work incorrect - it always link to main language.

    ReplyDelete
  16. Hi Dmitry!

    here is my config

    http://cht.net.ua/typo3conf/realurl_autoconf.txt



    for

    http://cht.net.ua



    but i cant understand how to config my site for subdomains proper.

    Now all links are generated properly but not resolve properly.

    can you drop config for multilanguage subdomain site?

    ReplyDelete
  17. _DOMAINS feature seems to be NOT compatible with tt_news 3.01 to rewrite URL in single view. I have posted a bug report here:

    http://bugs.typo3.org/view.php?id=15929

    When I deactivate _DOMAINS block, URL rewrite works fine with tt_news. It would be great to solve that annoying bug, isn't it?

    Anyone has tested _DOMAINS with tt_news by the way?

    Thanks

    ReplyDelete
  18. i cannot get it to work. i tried about 5 examples found with a google search several times, including this one, but none seem to work, at least not completely. it works perfect for the first domain (the default), but for the second i only get "not found page", even if the path is translated correctly and it looks like it should. i'm so frustrated. can't figure if it's something wrong with the htaccess or the realurl configuration which for me still looks like "black magic" :(. i tried all examples on my installation and then also on clean install following every step (thinking something in my old typoscript is messing it) but still nothing. it's even more frustrating since everybody here and on other blogs seem to have solved the problem. :(

    ReplyDelete
  19. I've got the same problem like other people commenting on this. I can't get it to work. I've checked the realURL manual but I couldn't find any additional information. How can I debug the configuration to find out what's wrong? Furthermore I don't understand the decode block. What string has to be provided for 'example.de' => array(?

    ReplyDelete
  20. I only can say, that I'm trying now for hours getting it work. The url still keep the standard language, while the page content is translated into the right language. Also the tld is right, but why not the speaking path? What could be the problem?

    ReplyDelete
  21. I also would love to see a functional TS setup for this example. For hours I try to set it up, the en- / decode of the domain works, the content is in the right language but the URLs are only in the default language...

    ReplyDelete
  22. Hi,

    I am using TYPO3 4.5.2 and facing a strange problem with Language setting. My condition [globalVar = GP:L=0] is not working for default language. It works for L=1. Do I need to set L=0 and how?

    I have not faced this issue before. Its very strange.

    ReplyDelete
  23. Think: do you need that condition at all?

    ReplyDelete
  24. Hi all & especially Dmitry,

    My goal was to change a multilingual site to a multidomain site. I almost did it, but there are some tricky moments, that's why i need your help. There are four languages (Serbian Cyrilic, Serbian Latin, Russian and English). These 4 languages should be diveded in 2 domains:
    - xxxxxx.rs - Serbian Cyrilic (L=2)
    - xxxxxx.rs/sh - Serbian Latin (L=1)
    - xxxxxx.rs/ru - Russian (L=3)
    - xxxxxx.eu - English (L=0)

    My realurl configuration:
    ##################
    $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']=array (
    '_DEFAULT' =>
    array (
    'init' =>
    array (
    'enableCHashCache' => true,
    'appendMissingSlash' => 'ifNotFile,redirect',
    'adminJumpToBackend' => true,
    'enableUrlDecodeCache' => true,
    'enableUrlEncodeCache' => true,
    'emptyUrlReturnValue' => '/',
    'respectSimulateStaticURLs' => true,
    'postVarSet_failureMode'=>'redirect_goodUpperDir',
    ),
    ...
    ...
    ...
    'preVars' => array(
    // Langue
    array(
    'GETvar' => 'L',
    'valueMap' => array(
    'en' => '0',
    'sh' => '1',
    'sr' => '2',
    'ru' => '3',
    ),
    'valueDefault' => 'en',
    'noMatch' => 'bypass',
    ),
    // No cache
    array(
    'GETvar' => 'no_cache',
    'valueMap' => array(
    'no_cache' => 1,
    ),
    'noMatch' => 'bypass',
    ),
    ),
    ...
    ...
    ...
    ),
    '_DOMAINS' => array(
    'encode' => array(
    array(
    'GETvar' => 'L',
    'value' => '0',
    'ifDifferentToCurrent' => true,
    'useConfiguration' => '_DEFAULT',
    'urlPrepend' => 'http://xxxxxx.eu',
    ),
    array(
    'GETvar' => 'L',
    'value' => '2',
    'ifDifferentToCurrent' => true,
    'useConfiguration' => '_DEFAULT',
    'urlPrepend' => 'http://xxxxxx.rs',
    ),
    ),
    'decode' => array(
    'xxxxxx.eu' => array(
    'GETvars' => array(
    'L' => '0',
    ),
    'useConfiguration' => '_DEFAULT',
    ),
    'xxxxxx.rs' => array(
    'GETvars' => array(
    'L' => '2',
    ),
    'useConfiguration' => '_DEFAULT',
    ),
    ),
    ),

    );
    ##################

    SEE the message below...

    ReplyDelete
  25. And my typoscript configuration:
    ##################
    ...
    ...
    ...
    ### RealURl config

    config.baseURL = http://xxxxxx.eu/

    [globalVar = GP:L = 3]
    config.baseURL = http://xxxxxx.rs/
    [global]

    [globalVar = GP:L = 2]
    config.baseURL = http://xxxxxx.rs/
    [global]

    [globalVar = GP:L = 1]
    config.baseURL = http://xxxxxx.rs/
    [global]

    config.tx_realurl_enable = 1
    config.prefixLocalAnchors = all
    ...
    ...
    ...
    ##################

    As I say everything is almost perfect, except one thing(obviously). When user is on "xxxxxx.rs" domain, the language links are right(sr cyr - http://xxxxxx.rs/, sr lat - http://xxxxxx.rs/sh/, ru - http://xxxxxx.rs/ru/, en - http://xxxxxx.eu), but then is on "xxxxxx.eu" domain 2 of language links are wrong (sr cyr - http://xxxxxx.rs/, sr lat - http://xxxxxx.eu/sh/, ru - http://xxxxxx.eu/ru/, en - http://xxxxxx.eu). That's happened because only the other two was specified in [_DOMAIN] description.

    Is there a solution for that?

    ReplyDelete
  26. Great extension.
    In a multidomain typo3 there is one website with separate language domains. There have been some encoding url troubles with rootpage_id after adjustConfigurationByHost.
    This seemed to be solved adding rootpage_id to _DOMAINS RealURL configuration, eg.
    $TYPO3_CONF_VARS['EXTCONF']['realurl']['_DOMAINS']['encode']['rootpage_id'] = '123'

    In this case the configuration adjustment is only done, if: "$disposal['rootpage_id'] == $this->extConf['pagePath']['rootpage_id']"

    Or is there a better solution?

    ReplyDelete
  27. Hi Dmitry, thanks so much for keeping up the great work.
    I have one multilanguage/multidomain project up and running smoothly on TYO3 4.7.10 thanks to realurl, but I just can not upgrade this to TYPO3 6.1.
    Is there anything I had to watch out for? I really appreciate your comment on this.

    ReplyDelete
  28. I had problems with this configuration, I always got "page not found" on subpages (startpage worked), but after removing "preVars" all is fine.
    I think I know why: If you define "preVars", realurl expects a PREfixed value, that means, when calling URL www.mypage.de/subpage1/, this prefixed value is "subpage1" and, according to the configuration, realurl thinks this is the language value.

    ReplyDelete
  29. Great Extension. Thanks.
    We have a multilanguage multidomain and multi pagetree website. One domain for each language. In an other pagetree we have an other website in only one language (the default language). This means that in the _DOMAINS section we define L=0 to use a domain from the first pagetree. It makes no difference to add the domain from the second page tree for the same language.
    Can this work somehow? How?


    '_DOMAINS' => array(
    'encode' => array(
    array(
    'GETvar' => 'L',
    'value' => '0',
    'useConfiguration' => 'www.firstpagetree.com',
    'urlPrepend' => 'http://www.firstpagetree.com'
    ),
    array(
    'GETvar' => 'L',
    'value' => '1',
    'useConfiguration' => 'www.firstpagetree.com',
    'urlPrepend' => 'http://www.firstpagetree.dk'
    ),
    array( // this section seems to be ignored, presumably because L=0 is allready defined.
    'GETvar' => 'L',
    'value' => '0',
    'useConfiguration' => 'www.secondpagetree.com',
    'urlPrepend' => 'http://www.secondpagetree.com'
    ),

    ReplyDelete
  30. I am struggeling with the following setup:

    domain1.de/page-has-no-lang-key-and-does-not-need-one/
    domain2.com/en/page/
    domain2.com/fr/page/

    The problem is that from what I understand I need to mix two lang setup types that exclude each other. Domain 1 needs a setup without a language key, using a default language, but domain 2 needs the lang key.

    Is there a way to accomplish this? The only workaround I found is to set urlPrepend to "http://www.domain2.com/en", but this causes several problems. The initial page redirect when calling the root directory does not work reliably any more and the generated sitemap (using tq_seo here) generates all sort of wrong realurl encoded urls.

    ReplyDelete