mashpie / i18n-node

Lightweight simple translation module for node.js / express.js with dynamic json storage. Uses common __('...') syntax in app and templates.
MIT License
3.09k stars 421 forks source link

How to set locale global ? #460

Closed golubvladimir closed 3 years ago

golubvladimir commented 3 years ago

I use template - https://github.com/januwA/nest-i18n-example.

I set up i18n global.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as i18n from 'i18n';
import * as path from 'path';
import * as cookieParser from 'cookie-parser';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  //app.use(cookieParser());

  i18n.configure({
    header: 'accept-language',
    locales: ['ru', 'en'],
    directory: path.join(__dirname, '/locales'),
  });

  app.use(i18n.init);

  await app.listen(3000);
}
bootstrap();

Use in module

import { Injectable, Inject, Scope } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
import * as i18n from 'i18n';

@Injectable({ scope: Scope.REQUEST })
export class AppService {
  constructor(@Inject(REQUEST) private req: Request) {}

  getHello() {
    return i18n.__('hello');
  }
}

I try to change accept-language header in postman, but lang don't change.

mashpie commented 3 years ago

This won't work in global mode! Global is suitable for server side cli use only. You somehow need to use the requests translation method, like

req.__('hello')

or maybe

this.req.__('hello')

Unfortunately, I can't help with nest. Never tried that framework - but hey, maybe a module intended to be used with nest will help out: https://www.npmjs.com/package/nestjs-i18n

Another nice article you might consider for inspiration https://phrase.com/blog/posts/node-js-i18n-guide/

golubvladimir commented 3 years ago

I fix in main.ts and it works

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as i18n from 'i18n';
import * as path from 'path';
import * as parser from 'accept-language-parser';

function getLocale(req) {
  console.log(parser.parse(req.headers['accept-language']));

  return parser.parse(req.headers['accept-language'])[0]['code'];
}

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  i18n.configure({
    locales: ['ru', 'en'],
    directory: path.join(__dirname, '/locales')
  });

  app.use((req, res, next) => {
    i18n.setLocale(getLocale(req));

    next();
  })

  app.use(i18n.init);

  await app.listen(3000);
}
bootstrap();
mashpie commented 3 years ago

Still this looks like to raise issues on concurrent requests, because I can't see i18n bound to any request context or scope. If I am right, you will encounter situations where multiple requests will overwrite each others "global" settings. AFAIK your middleware should be implemented like so:

  app.use((req, res, next) => {
    i18n.setLocale(req, getLocale(req));

    next();
  })

and any later translation should use the scoped api like req.__(), req.__n() etc.