No, it doesn't mean you need the second configuration file in any way.
First of all, your way of checking the Accept-Language
HTTP header (documented in RFC 7231) is far from perfect. For example, it can be equal to de;q=0.9,pt;q=0.8,en;q=0.7
. The first two characters is de
, but the user still prefer Portuguese over the English. With PHP you have an ability to check all the preferred languages list and additionally check the weight of each language, but the nginx config isn't a programming language, so lets simplify things assuming the preferred languages list is sorted by the weights as most of modern browsers does. Assume the following tree structure:
mywebsite.com
└── html
├── 404.html
├── css
│ ├── bootstrap.css
│ └── style.css
├── jquery
│ └── jquery.js
├── js
│ ├── bootstrap.js
│ └── vue.js
├── en
│ ├── index.php
│ ├── logout.php
│ ├── signin.php
│ └── signup.php
└── pt
├── index.php
├── logout.php
├── signin.php
└── signup.php
Now you can use a different root folder for the PHP files the following way:
map $http_accept_language $used_language {
~en.*pt(*SKIP)(*F)|pt pt; # when "pt" substring present and not preceded with "en"
~pt.*en(*SKIP)(*F)|en en; # when "en" substring present and not preceded with "pt"
default en; # or use "pt" if you want the Portuguese to be default
}
server {
root /var/www/mywebsite.com/html;
...
location ~ .php$ {
root /var/www/mywebsite.com/html/$used_language; # override root folder
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
internal;
}
...
}
(Regex provided by Wiktor Stribi?ew)
The map
block can be simplified to
map $http_accept_language $used_language {
~en.*pt(*SKIP)(*F)|pt pt; # when "pt" substring present and not preceded with "en"
default en;
}
or
map $http_accept_language $used_language {
~pt.*en(*SKIP)(*F)|en en; # when "en" substring present and not preceded with "pt"
default pt;
}
You can duplicate the whole tree structure (css
, js
, etc.) to the both en
and pt
folders and use dynamic root folder as global site root with the only one root
directive, but if you have the localized content only within the PHP files, I don't think it makes sense.
An important caveat
Since now you are providing different content via same URLs, you should specify the Vary
header to notify any caching layer between your server and visiting user that your content can vary upon the Accept-Language
HTTP header value:
location ~ .php$ {
add_header Vary "Accept-Language";
...
}
Cookies
Now to the Richard Smith's suggestion. I'm completely agree that the user should be able to switch the language. Here is an example combined with the previous answer:
nginx config
map $http_accept_language $language_by_header {
~en.*pt(*SKIP)(*F)|pt pt; # when "pt" substring present and not preceded with "en"
~pt.*en(*SKIP)(*F)|en en; # when "en" substring present and not preceded with "pt"
default en; # or use "pt" if you want the Portuguese to be default
}
map $cookie_language $used_language {
pt pt;
en en;
# detect language from "Accept-Language" header when no "language" cookie present
default $language_by_header;
}
server {
root /var/www/mywebsite.com/html;
...
location ~ .php$ {
root /var/www/mywebsite.com/html/$used_language; # override root folder
add_header Vary "Accept-Language";
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
internal;
}
...
}
en/index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>English</title>
<script type='text/javascript' src='/js/functions.js'></script>
</head>
<body>
<h1>Welcome! You're browsing the website with the English language.</h1>
<a onclick="setCookie('pt');" href="<?php echo $_SERVER['REQUEST_URI']; ?>">pt</a>
</body>
</html>
pt/index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Português</title>
<script type='text/javascript' src='/js/functions.js'></script>
</head>
<body>
<h1>Bem vindo! Você está navegando no website com o idioma Português.</h1>
<a onclick="setCookie('en');" href="<?php echo $_SERVER['REQUEST_URI']; ?>">en</a>
</body>
</html>
js/functions.js
function setCookie(lc) {
var today = new Date();
// cookie expiry date - plus 30 days from today
var expiry = new Date(today.getTime() + 30 * 24 * 3600 * 1000);
document.cookie = 'language=' + lc + '; path=/; expires=' + expiry.toGMTString();
}
Of course this example needs some explanation, like the previous nginx config, but writing long explanations is a very time-consuming task for a non-native English speakers like me, and I really have a lack of time right now, try to understand whatever you can yourself, and if you'll need some additional explanations, ask me a question(s) in comments.