Jump to content

Language Switching using multiple domains


Samuel
 Share

Recommended Posts

I would like to create a language switch using Multi-language page names, but I have for each language a different domain. 

For example:

domain.com instead of domain.com/en/

domain.de instead of domain.com/de

I was finding various approaches and explanations, outdated and brand-new, but I think It would be great to gather everything in one place. So there are basically two questions:

A) How to autodetect the browser language and redirect to the specific domain or default when not available.

My approach would be to direct all domains to the default, in this case domain.com, and then let processwire redirect depending on the browserlanguage. 

B) How to create a manual switch with flags, to choose the language for the current page you are viewing,

changing the path from:

domain.com/about/

domain.de/ueber-uns/

Thanks a lot and I will update this post with the code we together brainstorm.

Starting with connecting the domain to the language in processwire.

<?php // Redirect to language fields of processwire
     if($config->httpHost == 'domain.de') {
          $user->language = $languages->get("deutsch");
     } 
?>
Link to comment
Share on other sites

A) How to autodetect the browser language and redirect to the specific domain or default when not available.

My approach would be to direct all domains to the default, in this case domain.com, and then let processwire redirect depending on the browserlanguage. 

First things first, the $user->language should be set based on the current domain its being accessed from. We'll assume that the subdomains match the language names, i.e. subdomain "fr.domain.com" corresponds with language "fr", as named in ProcessWire. Code like this should exist at the top of a common include file that gets run/included before others (I recommend using $config->prependTemplateFile to automate it for you, see /site/config.php). 

/site/templates/_init.php: 

foreach($languages as $language) {
  if(strpos($config->httpHost, "$language->name.domain.com") === 0) {
    $user->language = $language; 
    break;
  }
}  

Next, I'm not necessarily sure it's ideal to autodetect the browser language and redirect based on that. There will always be cases where this doesn't actually match the user's preference. It might (possibly?) be an SEO concern too. It also limits what you can do in terms of caching, since you have detection code that always needs to run. I think it might be better to present a default language and an easy path for the user to find their language. However, if you still want to do language detection from the browser, you can look at the http_accept_language header. We'll assume that your languages are subdomains use the same naming convention as the http_accept_language, which would be "fr", "en", "es", etc. 

$name = $sanitizer->pageName(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2)); 
$language = $languages->get($name); 
if($language->id && $name != $user->language->name) {
  $url = "http://$name.domain.com" . $page->localUrl($language);
  $session->redirect($url); 
}

B) How to create a manual switch with flags, to choose the language for the current page you are viewing,

changing the path from:

domain.com/about/

domain.de/ueber-uns/

I've found that flags don't always represent language well. For instance, for Spanish do you show a Spain, Mexico, or some other flag? I think what's better is to make the selection based on the native language name, i.e. "Espanol" for Spanish. This is easily recognizable to people looking for the language. As for implementation, there is a good code example for this in the API documentation: How to implement a language switcher. In your case, using different domains, the same strategy would apply except that you'd need to include the domain as part of the $url, i.e. 

// this for: de.domain.com
$url = "http://$language->name.domain.com" . $page->localUrl($language); 
// or this for: domain.de
$url = "http://domain.$language->name" . $page->localUrl($language); 
  • Like 3
Link to comment
Share on other sites

  • 8 months later...

I tried to build upon Ryan's code above and to add the possibility of setting a cookie, so that a users language selection is remembered. Here's what I came up with.

/site/templates/_init.php:

if(isset($_COOKIE["user_language"])) {
	$language = $_COOKIE["user_language"];
} else {
	$name = $sanitizer->pageName(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2));
	if($name == "en") $name = "default"; // because default language cannot be renamed to en
	$language = $languages->get($name);
	setcookie("user_language", $language, time()+3600*24*365, "/");
}
	
if($language != $user->language) {
	$url = substr($pages->get('/')->httpUrl, 0, -1) . $page->localUrl($language);
	$session->redirect($url);
}

Then, I've added an event handler to the language select:

function createCookie(name, value, days) {
    var expires;

    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        expires = "; expires=" + date.toGMTString();
    } else {
        expires = "";
    }
    document.cookie = encodeURI(name) + "=" + encodeURI(value) + expires + "; path=/";
}

$(".select-language a").click(function() {
	var value = $(this).attr("data-language");
	createCookie("user_language", value, 365);
});

The language select itself within the template file looks like this (source):

$savedLanguage = $user->language;
foreach($languages as $language) {
	if(!$page->viewable($language)) continue;
	$user->language = $language;
	if($language->isDefault()){$out = "en";} else {$out = $language->name;}
	echo "<a href='{$page->url}' data-language='{$language->id}'>{$out}</a>";
}
$user->language = $savedLanguage;

Everything seems to work so far. But as I just began to work with processwire; does anyone of the more experienced guys see a potential problem with this solution? Ryan also mentioned possible problems with caching in his post above. Is there a way around this? Could it help if I run this code only on the startpage (instead of _init.php)?

Link to comment
Share on other sites

Ok, I've found a minor bug: If the page is open simultaneously in two browser tabs, then change change the language from english (/) to german (/de/) in the first tab, then reload the second tab, everything works fine and the second tab is redirected to the german page as well. However, if I switch back to english on the first tab and then again reload the second tab (which is still on the german page), I get a "too many redirects" error. Any idea why this happens?

Link to comment
Share on other sites

Uff, a though one without having this code and exact setup for testing out the code and trace.  

There's a lot that can go wrong when using cookies for storing settings while using server side... I mean it can get complicated and tricky. Looking at the code I don't really see obvious flaw, but that's from looking.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...