Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Even though I have 'Browser language redirect' activated at WMPL's setup screen, users aren't being correctly redirected according to browser language.

I currently have three languages selected: en (default), es and pt-br. Only es users are automatically redirected to spanish page. pt-br users aren't, no matter what browser I use.

share|improve this question
    
With the source being hidden by at least $29 you might want to contact WPML for support instead. Also, in this questions, paste in the headers that are being sent by each browser. –  soulseekah May 8 '13 at 8:27
    
Their support did nothing, had to find it out for my own... –  esauvisky May 8 '13 at 15:30
add comment

1 Answer

I've found what was going on, so I'm going to answer it for future reference, as it's a common issue without clear solution.

TL;DR: If the WPML language which's not redirecting has a country code (eg. en-US instead of en) then you probably have the same bug. Jump to section "How to fix it".


The Problem

The problem arises at the redirection javascript provided by WPML (browser-redirect.js):

[...]

1  // Get page language and browser language
2  var pageLanguage = wpml_browser_redirect_params.pageLanguage;
3  var browserLanguage = navigator.language? navigator.language : navigator.userLanguage;
4  browserLanguage = browserLanguage.substr(0,2); // browser language may have double code (i.e. en-us)

[...]

5  // Compare page language and browser language
6  if (pageLanguage != browserLanguage) {
7     var redirectUrl;
8     // First try to find the redirect url from parameters passed to javascript
9     var languageUrls = wpml_browser_redirect_params.languageUrls;
10    if (languageUrls[browserLanguage] != undefined) {
11            redirectUrl = languageUrls[browserLanguage];
12    }
13    // Finally do the redirect
14    if (redirectUrl != undefined) {
15            window.location = redirectUrl;
16    }    
17 }

As you can see at line 4, browserLanguage is trimmed, in a way that pt-br becomes pt, en-us becomes en, and so on. That's probably there so users from different locations but with same language would both be redirected.

The actual problem is at line 10. languageUrls is an array which contains all languages codes with their respective urls, but the codes aren't trimmed!

languageUrls[]
en: "http://sitehere.com"
es: "http://sitehere.com?lang=es"
pt-br: "http://sitehere.com?lang=pt-br"

So, if browserLanguage was trimmed, the if condition at line 10 returns false, and then you won't get redirected:

if (languageUrls[pt] != undefined ) {
    // this part doesn't runs
}

Also, even if browserLanguage wasn't trimmed at all, it still wouldn't work completely, because some browsers pass browserLanguage with capital letters, like pt_BR, and it just wouldn't match.

My fix is to use two browserLanguage variables, one trimmed and one in lowercase. Then you compare pageLanguage against both of them, so the behaviour for 'different location, same language' users will likely stay the same and you fix the bug.


The Solution

Replace the content of /wp-content/plugins/sitepress-multilingual-cms/res/js/browser-redirect.js with this:

jQuery(document).ready(function(){
    if(jQuery.cookie != undefined) {
        // Check if cookie are enabled
        jQuery.cookie('wpml_browser_redirect_test', '1');
        var cookie_enabled = jQuery.cookie('wpml_browser_redirect_test') == 1;
        jQuery.removeCookie('wpml_browser_redirect_test');

        if (cookie_enabled) {
            var cookie_params = wpml_browser_redirect_params.cookie
            var cookie_name = cookie_params.name;
            // Check if we already did a redirect

            if (!jQuery.cookie(cookie_name)) {
                // Get page language and browser language
                var pageLanguage = wpml_browser_redirect_params.pageLanguage;
                var browserLanguage = navigator.language? navigator.language : navigator.userLanguage;
                browserLanguage = browserLanguage.toLowerCase()
                browserLanguageTrim = browserLanguage.substr(0,2); // browser language may have double code (i.e. en-us)

                // Build cookie options
                var cookie_options = {
                    expires: cookie_params.expiration / 24,
                    path: cookie_params.path? cookie_params.path : '/',
                    domain: cookie_params.domain? cookie_params.domain : ''
                };

                // Set the cookie so that the check is made only on the first visit
                jQuery.cookie(cookie_name, browserLanguage, cookie_options);

                // Compare page language and browser language
                if ((pageLanguage != browserLanguage) && (pageLanguage != browserLanguageTrim)) {
                    var redirectUrl;
                    // First try to find the redirect url from parameters passed to javascript
                    var languageUrls = wpml_browser_redirect_params.languageUrls;
                    if (languageUrls[browserLanguage] != undefined) {
                        redirectUrl = languageUrls[browserLanguage];
                    } else if (languageUrls[browserLanguageTrim] != undefined) {
                        redirectUrl = languageUrls[browserLanguageTrim];
                    }
                    // Finally do the redirect
                    if (redirectUrl != undefined) {
                        window.location = redirectUrl;
                    }    
                }
            }
        }
    }
});

Bonus Solution

Users will get redirected only once. This is proposital (and horrible) behaviour. If you're not satisfied with that, you can try another alternative. Just keep in mind this is a hack that will redirect all users based on their browser language no matter what language they choose, so you MUST have all pages translated and avoid showing a language switcher, as it wont work.

jQuery(document).ready(function(){
    if(jQuery.cookie != undefined) {
        // Check if cookies are enabled
        jQuery.cookie('wpml_browser_redirect_test', '1');
        var cookie_enabled = jQuery.cookie('wpml_browser_redirect_test') == 1;
        jQuery.removeCookie('wpml_browser_redirect_test');

        if (cookie_enabled) {
            var cookie_params = wpml_browser_redirect_params.cookie
            var cookie_name = cookie_params.name;
            var pageLanguage = wpml_browser_redirect_params.pageLanguage;
            var browserLanguage = navigator.language? navigator.language : navigator.userLanguage;
            var languageUrls = wpml_browser_redirect_params.languageUrls;
            browserLanguage = browserLanguage.toLowerCase()
            browserLanguageTrim = browserLanguage.substr(0,2);

            // First time cookie gets set
            if (!jQuery.cookie(cookie_name)) {
                // Build cookie options
                var cookie_options = {
                    expires: cookie_params.expiration / 24,
                    path: cookie_params.path? cookie_params.path : '/',
                    domain: cookie_params.domain? cookie_params.domain : ''
                };
                // Sets the cookie in a way that matches avaible languageUrls
                if (languageUrls[browserLanguage] != undefined) {
                    jQuery.cookie(cookie_name, browserLanguage, cookie_options);
                } else if (languageUrls[browserLanguageTrim] != undefined) {
                    jQuery.cookie(cookie_name, browserLanguageTrim, cookie_options);
                }  
            }
            /* If cookie language != page language then redirect
               !! WARNING: THIS DOESN'T ALLOWS LANGUAGE SWITCHING,
               !! BUT GUARANTEES ALL USERS ALWAYS GET REDIRECTED,
               !! ASSUMING BROWSERLANGUAGE IS THE RIGHT LANGUAGE.
               For better behaviour you should make the language switcher
               update the cookie. Bad, bad hack, but I like it better. */
            if (jQuery.cookie(cookie_name) != pageLanguage) {
                var redirectUrl;
                // Sets the url for redirection
                if (languageUrls[jQuery.cookie(cookie_name)] != undefined) {
                    redirectUrl = languageUrls[jQuery.cookie(cookie_name)];
                }
                // Finally do the redirect
                if (redirectUrl != undefined) {
                    window.location = redirectUrl;
                }
            }
        }
    }
});
share|improve this answer
    
Good job. You can accept your own answer to mark the question as solved. –  soulseekah May 8 '13 at 18:16
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.