MikZuit
MikZuit

Reputation: 734

Node express api routes for multilingual directory like url

Does any one knows an example or could explain here how node.js and express would have to route for a multilanguage site? I'm using i18n-node for translation and folder like routing ( /es/, /de/ , etc ) for different languages. This all are static routes but I also have routes like apiRoutes.route('/user/profile') using 'app' at the begining ( app.get('/app/user/profile') so please consider this in your answer so is NOT necesary route to : app.get('/es/app/user/profile') .

having 15 routes like this now:

app.get('/terms', function(req, res) {
    res.render('terms',{
...
    });
});

how it have to be set for routes like:

app.get('/es/terms', function(req, res) {
    res.render('terms',{
   ...
    });
});
  1. Should I duplicate this routes and add for example a locale for each like:

    app.get('/es/terms', function(req, res) {
        res.render('terms',{
        ...
         });
     });
    
  2. Or Should do something like:

     if cookie['lang'] && cookie['lang'] is in locales 
        // then redirect to /:lang/terms
      else
        // show default language in /terms
     if req.headers["accept-language"] && req.headers["accept-language"] 
        // then redirect to /:lang/terms
     else 
        //show default language in /terms
    
  3. Or there is another way I should approach this that follows good practices or is better respecting standards?

  4. Miro's Answer in : How can I get the browser language in node.js (express.js)? says I should use app.all('*', ...

Is this all I need?, ..still, it might have a syntax error or i'm not understanding well this two parts

    var rxLocal = /^\/(de|en)/i;
    ...
    app.get(/\/(de|en)\/login/i, routes.login);

thanks in advance

Upvotes: 0

Views: 4066

Answers (3)

Sergey Li
Sergey Li

Reputation: 1

You can have a middleware to extract locale before sending to your routes' handlers.

The middleware could be like:

function extractLocale(req, res, next) {
    const pathParts = req.path.split("/").filter(Boolean);
    const firstDir = pathParts[0];
    if (checkLocalsExisted(firstDir)) {
        req.lang = firstDir;
        req.url = req.url.replace(`/${firstDir}`, "");
    } else {
        req.lang = "en";
    }
    next();
}

The middleware does two things:

  1. Locale Extraction: It checks if the first URL segment is a valid locale.
  2. URL Rewriting: If a locale is found, it's removed from the URL and stored in req.lang.

The URL rewriting step allows subsequent routes' handlers to match the path without considering the locale prefix.

So when defining your routes' handlers, you can write them without the locale in the url, e.g.,:

app.get('/terms', function(req, res) {
    const lang = req.lang;
    // do lang specific things before rendering 
    res.render('terms',{
...
    });
});

Ps. We faced the same problem before and the entire solution is documented, read more if you need.

Upvotes: 0

Techniv
Techniv

Reputation: 1967

You need to consider 2 things :

1. How get the local :

Accept-Language

The HTTP protocole define the Accept-Language header to manage the local. This is a normalized method. You can access it with the req.acceptsLanguages method of express.

  • +Normalized
  • +Natively support by brower
  • -Not easy to by passe by the end user

Path / Cookies

You can get the local from the path. In express it can be do with a parameter patter like /:local/rest/of/path and retrieve in the request object with the req.param method.

You can also get the information from the cookies with the req.cookies properties (don't forgot to set it).

Both

To increase the user experience you can mix the both method. For exemple get the default language from the HTTP header send by the browser but permite to the user to override this in you application and store this parameter in the cookies.

2. Use the local:

Each methods to get the local can be used from different way. I will use random of them in exemple but they are all compatible.

Top level configuration.

In case of you use a template Engine and you controller can be local agnostic. You can use a middleware to get the local information and configure the render engine.

app.use('/:local' (req, res, next) => {
  let localKey = req.param('local');
  res.locals = // Some ingenious method to get the locales from localKey

  next();
}

Check res.locals and your engine documentation.

Use it in controller.

If the local is part of the contoller process. You can get directly is value in controller.

In case of you use a complexe method to determine the final value of the local, you can also use a middleware to determine this value and enrich the request with it.

app.use((req, res, next) => {
  let local = req.cookies.local;
  if(!local) local = req.acceptsLanguages();
  if(!local) local = 'en-US';
  req.local = local;
}

Both

You can use both method too. It depend of what you need. Find the best way to get a maintainable code and avoid replication for your use case.

When you use middle where witch impact the controllers, be sure you declare them before your routes.

Upvotes: 3

Patrick Hund
Patrick Hund

Reputation: 20236

You can use a route parameter to get the locale from the URL, like this:

app.get('/:lang/terms', function (req, res) {
    if (req.params === 'es') {
        res.send('¡Hola!');
    else {
        res.send('Hi!');
    }
});

The colon character tells Express to put whatever is between the first to slashes of the path in req.params.lang. See express routing documentation for details.

Upvotes: 1

Related Questions