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

__n() throws error if setLocale not called, despite defaultLocale #429

Open ucacoin opened 4 years ago

ucacoin commented 4 years ago

HI,

if you call __n() without setLocale beforehand it will throw:

var lc = targetLocale.toLowerCase().split(/[_-\s]+/)
                              ^

TypeError: Cannot read property 'toLowerCase' of undefined
    at Object.i18nTranslatePlural [as __n] (path/node_modules/i18n/i18n.js:371:31)
    at Module._compile (internal/modules/cjs/loader.js:1147:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1167:10)
    at Module.load (internal/modules/cjs/loader.js:996:32)
    at Function.Module._load (internal/modules/cjs/loader.js:896:14)
    at Module.require (internal/modules/cjs/loader.js:1036:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at Module._compile (internal/modules/cjs/loader.js:1147:30)

Even if you define a default locale with:

i18n.configure({
    locales:['en', 'de'],
    directory: __dirname + '/../locales',
    defaultLocale: 'de',
});

There should be a fallback that if no targetLocale is found the defaultLocale should be used.

mashpie commented 4 years ago

Maybe you can add some code to reproduce your setup?

latagore commented 3 years ago

I don't have a project setup, but I was able to reproduce the issue with

const path = require('path');
const {I18n} = require('i18n');
const i18n = new I18n({
    locales: ['en', 'es'],
    directory: path.join(__dirname, '..', '..', 'locales'),
});

let {__n} = i18n;
__n('%s cats', 1);

This can be fixed by doing

let {__n} = i18n;
__n = __n.bind(i18n);
__n('%s cats', 1);

edit: I missed this fix I had locally. seems that you must set the locale before using __n as well.

let {__n} = i18n;
i18n.setLocale('en');
__n = __n.bind(i18n);
__n('%s cats', 1);
beytarovski commented 2 years ago

Adding setLocale was enough for me just after initializing I18n.

const i18n = new I18n({ ... })
i18n.setLocale('en')
mathmul commented 6 months ago

Works for me without setLocale on minimal setup.

package.json

{
  "name": "tmp",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "test"
  },
  "author": "me",
  "license": "ISC",
  "dependencies": {
    "i18n": "^0.15.1"
  }
}

index.js

import i18n from 'i18n';
import path from 'path';
import { fileURLToPath } from 'url'

const __dirname = path.dirname( fileURLToPath( import.meta.url ) )

i18n.configure( {
  locales: ['en', 'de'],
  fallbacks: { 'en-*': 'en', 'de-*': 'de' },
  defaultLocale: 'en',
  register: global,
  queryParameter: 'lang',
  directory: path.join( __dirname, 'locales' ),
} );

console.log( i18n.getLocale() )
console.log( i18n.__( '%s cat', 1 ) )

Outputs

*personal information redacted

user@machine tmp % node index.js
current locale: en
__   : 1 cat
user@machine tmp % npm list
tmp@1.0.0 /.../tmp
└── i18n@0.15.1

user@machine tmp % npm -v
9.8.1
user@machine tmp % nvm -v
0.39.1
user@machine tmp % node -v
v21.6.2