Why isn’t WMPL correctly redirecting users based on browser language?

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.

Related posts

1 comment

  1. 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;
                    }
                }
            }
        }
    });
    

Comments are closed.