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
It just works! Thanks a lot!
Works perfectly. Thanks.
Just a note. You can’t hide the default language prefix from the url for this to work. I guess everyone will find this an easy fix and luckily wordpress will load the content from both urls example.com/content and example.com/en/content so manually entered url that won’t update dynamically won’t have to be updated.
Thanks for the help here! And thanks as well for the info regarding the hiding of the prefix. I guess there’s no way to hide it anyway…? Best rergards, Marco