Remembering the user language choice

Recently, I had to develop a small web portal for a client. Since the portal consisted mostly of static pages which the client wanted to update himself, and I had limited time for development, WordPress platform was an obvious choice. We agreed to derive the design from the standard “Responsive” theme (WordPress Codex has a great article on how to do that).

The portal had to be multi-lingual, most pages would be in English, but some would have translations in Latvian. I found WordPress qTranslate plugin the best solution for my needs. It changes the way WordPress dashboard forms work, now a blog post has two fields “Title (Latvian)” and “Title (English)” as well as “Post content (Latvian)” and “Post content (English)”. If you don’t fill the fields for a particular language, the page would be treated as not translated and may be hidden in the navigation as well. You have to pick the default language of the site – what content to show if the user has not picked any language.

qTranslate provides several ways how you can do localization:

  • using a subdomain, e.g. lv.yourdomain.com and en.yourdomain.com
  • by adding a GET parameter to each page, eg. yourdomain.com/article_title/?lang=lv
  • using a directory prefix, e.g. yourdomain.com/lv/articletitle, yourdomain.com/en/articletitle

I picked the latter, as it seemed most rational of the three. Now every page had two addresses and everything seemed to be running just fine. However, I found it a bit annoying that a returning visitor always sees the default language, regardless which language he had chosen in the previous visit. It would seem logical that qTranslate could just set a cookie “last language” or something like that. I found out, it does not. Moreover, qTranslate authors are not going to implement it, they say “it’s a wanted behavior”.

Not wanting to mess with plugin’s PHP code, I decided to fix this at the web server level (as you may know, Apache Mod_Rewrite can both read and set cookies).

So, I needed two parts of the algorithm:

— when the user requests a page where the URL contains language code, save that language in a cookie. In “.htaccess language” it is

    #Only for requests which start with "/lv/" or "/en/". 
    RewriteCond %{REQUEST_URI} ^/(lv|en)/.*$ [NC]

    #no need to set a cookie if you already have one with the same value
    RewriteCond %{HTTP_COOKIE} !lang=%1 [NC] 

    #rewrite to the same address, but set a cookie to the value captured in first RewriteCond
    RewriteRule . - [cookie=lang:%1:.%{HTTP_HOST}:144000:/]

— when the user requests the “root” of the portal and there is a “lang” cookie set, do a redirect to the particular language root page

  #only for the root page /
  RewriteCond %{REQUEST_URI} ^/$ [NC]

  #only if you have a "lang" cookie
  RewriteCond %{HTTP_COOKIE} lang=(en|lv) [NC] \

  #redirect (not rewrite!) to either /en/ or /lv/
  RewriteRule ^(.*)$ /%1/ [R=302,L]

So, after all modifications my .htaccess file looks like this:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteCond %{REQUEST_URI} ^/$ [NC]
RewriteCond %{HTTP_COOKIE} lang=(lv|en) [NC] 
RewriteRule ^(.*)$ /%1/ [R=302,L]

RewriteCond %{REQUEST_URI} ^/(lv|en)/.*$ [NC] 
RewriteCond %{HTTP_COOKIE} !lang=%1 [NC] 
RewriteRule . - [cookie=lang:%1:.%{HTTP_HOST}:144000:/]

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress