I have a multilingual site with three languages (English, Spanish and Catalan) and my set up is nginx (with Perurio's config, thanks a lot António for sharing it, it is a really good job) + Drupal 7 + Boost + APC.
My site is configured so all traffic is redirected to https, and my goal was to detect user's browser language and redirect him to the correct section (ie, https://www.mysite.com/es, https://www.mysite.com/ca or https://www.mysite.com).
All my attemps of configuring a rewrite (the like of rewrite (.*) $1/$lang;) on the server named www.mysite.com and listening on 443 resulted on either an infinite loop or a Drupal's "page not found" error.
What I did at the end was to select the url the user was less likely to type (https://www.mysite.com) and redirect all other options (http://mysite.com, http://www.mysite.com & https://mysite.com) to it in the following way:
server {
listen 80;
server_name mysite.com;
if ($lang ~ (es|ca) ){
return 301 https://www.mysite.com/$lang$request_uri;
}
return 301 https://www.mysite.com$request_uri;
}
server {
listen 80;
server_name www.mysite.com;
if ($lang ~ (es|ca) ){
return 301 https://www.mysite.com/$lang$request_uri;
}
return 301 https://www.mysite.com$request_uri;
}
server {
listen 443;
server_name mysite.com;
ssl_certificate certs/server.crt;
ssl_certificate_key certs/server.key;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
if ($lang ~ (es|ca) ){
return 301 https://www.mysite.com/$lang$request_uri;
}
return 301 https://www.mysite.com$request_uri;
}
server {
listen 443 ssl;
server_name www.mysite.com;
ssl_certificate certs/server.crt;
ssl_certificate_key certs/server.key;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
limit_conn arbeit 32;
---REST OF THE CONFIGURATION GOES HERE----
}So my solution works well if the user types mysite.com or www.mysite.com, but it will not make language detection if the user types https://www.mysite.com.
My question is, how could I make it so mysite.com (on ports 80 & and 443) and www.mysite.com (on port 80) are redirected to www.mysite.com (on port 443) and to perform the laguage check on this last server and do a rewrite for all cases?
Similarly to this issue, I have certain pages that I would like to serve different content depending on the country the user is coming from. For achiving so, I could use geoip to detect the country, add locations for the individual pages that need to be localised and and rewrite the url for these location to add an extra parameter like country=COUNTRY at the end of the URL. What would be the best way to get it working?
Thanks and regards,
Andrés
Comments
nginx accept language module
Hi Andres,
I'm on my way to make the switch to NGINX too, and I had to deal with your same problem in the past with Apache, which I solved with some htaccess rewrite rule.
I plan to use this nginx module, did you give it a try yet ?:
https://github.com/giom/nginx_accept_language_module
Hi Pedro, No, I haven't tried
Hi Pedro,
No, I haven't tried nginx_accept_language_module. From its description, what it does is parsing the Accept-Language header and setting a variable to a language that you can then use.
If your set up is not very complex (mine is not), you can easily do it yourself. This is how mine looks like:
I created a file called multilingual.conf looking like:
map $http_accept_language $lang {default en;
~es es;
~ca ca;
}
Then in nginx.conf, before including the virtual hosts I have the following line:
include multilingual.conf;So I can use the $lang variable as shown in my fisrt post.
I hope that helps. Let me know if you finally try nginx_accept_language_module how does it works for you, and what benefits does it give you over the "do it yourself" approach.
Cheers,
Andrés
Indeed
Why install a module for something that can be handled by the standard Nginx.
Andrés solution is the one to use if need a
$langvariable to use later.You can make it more generic. This works for any language.
map $http_accept_language $lang {default en;
~(?<current_lang>.*)$ $current_lang;
}
So be it
Learning and following the "best-seller" perusio's repo Drupal+Nginx , this is it :)
Thanks and congrats btw.
no language link available
Walking the final steps of the nginx-ation of my sites, I'm stuck with the language negotiation.
Well, not exactly negotiation as shown in this thread, but just the i18n of the links.
All the links with mysite.com/language-code are not available and shown as not found.
I can still access any of direct links such as mysite.com/admin but no mysite.com/en/admin , mysite.com/es/admin etc...
Any tips ?
Thanks.
Hi @pedrosp, that's strange,
Hi @pedrosp, that's strange, perusio's configuration worked for me with multilingual support just out of the box (I mean, no links were broken, mysite.com/es/admin worked as well as mysite.com/admin). The only issue I had was with the sitemap.xml, which I needed to add an extra location for /es/sitemap.xml.
Where is the not found error comming from, nginx or Drupal?
Language header redirect recipe
I just want to share here my finale recipe to handle redirect for language header, mainly based on @amacias config, with a twist.
1) create a multilingual.conf file on /etc/nginx/ to set the $lang variable:
map $http_accept_language $lang {default en;
~en en;
~en-ca en;
~es es;
~fr-ca fr;
~ca es;
~fr fr;
}
Notes:
a) "~(?.*)$ $current_lang;" as suggested by @perusio does not work when you have several languages on your browser settings (at least on chrome).
b) sorting matters, the first valid match will go on, that's why you have to declare ~fr-ca (french canadian) before ~ca (catalan), it seems that nginx check for xx characters match even on xx-xx definitions.
2) edit nginx.conf and add include multilingual.conf; before vhosts:
...
http {
...
include multilingual.conf;
## Include all vhosts.
include /etc/nginx/sites-enabled/;
...
}
3) edit example.com.conf and include rewrites with the $lang parameter:
server {
...
## return to the valid url http / https / www ...
return 301 https://example.com/$lang$request_uri;
}
server {
...
## place at the end of the valid server definition
location = / {rewrite /. /$lang redirect;}
}
So, finally it works :) but I'm pretty sure there is room for optimization. This only redirect a call to the homepage, since there is no need normally to rewrite a formed URL.
Thanks for your help.
BTW: This config worked on my current D7 installation, but I couldn't solve the problem exposed months ago on a previous comment, since I was running back on time an old pressflow 6 installation with domain access and a pretty twisted configuration.