Search code examples
angularnginxinternationalization

Nginx configuration for Angular with multi language (i18n) support


I am trying to configure an Nginx server to automatically redirect the user to their preferred browser language.

I know the solution is not perfect and dosn't take into account the qualifier for the language. This would require the AcceptLanguageModule, but that's currently not necessary.

The current situation is as follows, for each language there is a folder with the respective files inside the dist folder (nginx root). This is the standard for Angular multi language projects.

dist/
├─ de/
│  ├─ index.html
├─ en/
│  ├─ index.html
├─ pl/
│  ├─ index.html

The current Nginx configuration (unnecessary elements removed):

# Browser preferred language detection (does NOT require AcceptLanguageModule)
map $http_accept_language $accept_language {
    default    de;
    ~*^en      en;
    ~*^pl      pl;
}

server {
    listen 80;
    server_name example.com;
    root /var/www/dist;

    index index.html index.htm;

    location / {
        rewrite ^/(.*)$ /$accept_language/$1 permanent;
    }

    location ~ ^/(de|en|pl) {
        try_files $uri $uri/ /$1/index.html?$args;
    }
}

The language should be prefixed to the URL so for example: /en for the English language version. This works well if the user navigates to the root path of the domain.

But if a user calls a URL without a prefix for the language, this should be set automatically in front. If I call e.g. /account the user should be redirected to /en/account.

So a curl -I http://example.com/account -H "Accept-Language: en" should return /en/account but instead it returns /en. If Accept-Language is set to de it works and returns the correct /de/account location.

So how do I configure Nginx to correctly redirect the user if they have not specified a language prefix? Is it possible to redirect URLs like /EN/account to the correct URL? So if the prefix for the language is not correct.


Solution

  • After some trial and error, I solved the problem. It was probably due to the type of redirecting. With a return it works as desired.

    Also the Nginx page with common config pitfalls recommends to use a return instead of a redirect.

    I have further extended the configuration, which stores the selected language of the user in a cookie, named language and prefers it over the accept language from the browser. This cookie can be easily set in the Angular application when the user selects another language.

    The updated Nginx configuration (unnecessary elements removed):

    # Browser preferred language detection (does NOT require AcceptLanguageModule)
    map $http_accept_language $accept_language {
        default    de;
        ~*^en      en;
        ~*^pl      pl;
    }
    
    # Get preferred language from cookie or default to accept language
    map $http_cookie $preferred_language {
        default $accept_language;
        "~*language=(?<language>(de|en|pl))" $language;
    }
    
    server {
        listen 80;
        server_name example.com;
        root /var/www/dist;
    
        index index.html index.htm;
    
        location / {
            return 302 $scheme://$host/$preferred_language$request_uri;
        }
    
        location ~ ^/(de|en|pl) {
            try_files $uri $uri/ /$1/index.html?$args;
        }
    }