mashpie / i18n-node Goto Github PK
View Code? Open in Web Editor NEWLightweight simple translation module for node.js / express.js with dynamic json storage. Uses common __('...') syntax in app and templates.
License: MIT License
Lightweight simple translation module for node.js / express.js with dynamic json storage. Uses common __('...') syntax in app and templates.
License: MIT License
Hi All,
I am using i18n-node with express.js and hogan templating. When user logges in the values are not replaced. Nothing coming in that place (not even default language). Where to check? Any clues?
It would be nice to let the user change the language and save that preference in a cookie. Are you planning to add this? Otherwise I will try to add it.
Currently the i18n.init Module adds an anon. Function to the ExpressJS Stack.
[ { route: '', handle: [Function: query] },
{ route: '', handle: [Function: expressInit] },
{ route: '', handle: [Function: toobusy] },
{ route: '', handle: [Function: cookieParser] },
{ route: '', handle: [Function: bodyParser] },
{ route: '', handle: [Function: session] },
{ route: '', handle: [Function] },
{ route: '', handle: [Function: setMomentLocale] },
{ route: '', handle: [Function: router] },
{ route: '', handle: [Function: errorHandler404] } ]
For debugging it would be nice if the Function has a name.
using "de" might get extended by "de-AT" or "de_CH" for example allowing to hold "defaults" in de and only add exeptions to "de-AT"
Ok,
// 1 apple
__n('%s apple', '%s apples', 1);
// 3 apples
__n('%s apple', '%s apples', 3);
For english languge it's awesome, but for (as example) russian it's wrong. I mean:
{
// Singular (or 21... 31... 121... 131...)
"1 apple": "1 яблоко",
// Plural (2-4, 22-24, 32-34... 122-124...)
"2 apples": "2 яблока",
// Plural (5-20, 25-30, 35-40... 105-120...)
"5 apples": "5 яблок"
}
Are there any plans like that?
If I have a node application in /path/to/myapp, with /path/to/myapp/app.js as the runner and /path/to/myapp/locales with i18n language definitions in, then i18n works if I:
cd /path/to/myapp
node app.js
however, if i start the app from outside the directory, i18n does not load up locales, searching within the current dir:
cd /path/to
node myapp/app.js
No languages will load in the 2nd instance.
I have the following expressjs-structure:
app.js
app.use( i18n.init );
...
i18n.configure({
locales: ['en', 'de']
});
app.all( '*', function( req, res ) {
/* user-auth and get language from database */
i18n.setLocale( /*language*/ );
});
...
app.all( '/something/', function( req, res ) {
console.log( i18n.getLocale( /*language*/ ) ); /* prints the correct language */
res.render('something.jade')
});
But the template gets rendered in the wrong language. Do I miss something?
Thanks.
I've built an application with Express and Jade, using i18n for internationalization. I've built this application when 0.3.5 was the latest version and everything worked fine. Now I'm trying to get it to work with the latest version, but I'm only getting results with the default locale (en).
I reverted to 0.3.5 and tried to determine what the cause is. First thing I noticed where a lot of these messages in the console, when enabling debugging:
WARN: No locale found - check the context of the call to $__. Using de (set by request) as current locale
I realized that my working solution relied entirely on having the defaultLocale
set to the detected locale. This was changed in d773772#i18n.js
When getLocaleFromObject
is called, the passed object never seems to be an instance that contains the previously detected locale.
I'd love to resolve this, but, so far, I don't have a clue how to approach it properly. Any guidance would be appreciated.
Hi,
Thank you for very nice module.
The latest npm release is a bit old now, is there a planned release soon?
At the moment i18n supports something like that: __('Hello %s, how are you today?', 'Marcus');
But if you now have to strings for example firstname and lastname and in one language you say Hello firstname lastname
and in another Hello lastname firstname
then you see that this system dosen't work. It would be better to have something like this __('Hello %firstname% %lastname%', {'%firstname%': 'Max', '%lastname%: 'Mustermann'});
because now I can change the order of using parameters within a local. What do you think about that?
Is there a way to distinguish between 0 and 1 for the singular case?
Right now if the quantity is 0 it uses the singular case:
0 cat
but really grammatically it should be
0 cats
?
I'm wondering if and how i18n-node could be used together with the new Mustache.js helpers discussed here:
janl/mustache.js#139
Please specifically see this example:
janl/mustache.js#139 (comment)
How would you devise the template-i18n bridge/helper so that the plural/singular etc. functions in i18n-node would still work?
Thanks for the module, I'm interested but I have error when try to install with npm ( v1.0.106) , this is my log :
npm ERR! Error: No compatible version found: i18n@'>=0.3.3'
npm ERR! Valid install targets:
npm ERR! ["0.0.1a","0.1.0","0.3.0"]
npm ERR! at installTargetsError (/usr/local/lib/node_modules/npm/lib/cache.js:424:10)
npm ERR! at /usr/local/lib/node_modules/npm/lib/cache.js:406:17
npm ERR! at saved (/usr/local/lib/node_modules/npm/lib/utils/npm-registry-client/get.js:136:7)
npm ERR! at Object.cb as oncomplete
Works fine if I download the module from github, of course .
Hi. I use express 3.x.
And I have all times en language.
I add i18n.init in app.use before app.locals. In app.locals I use i18n.__('some phrase').
In setLocale method it is fine set request.locale to right language. But in translate method locale is undefined, cause this.scope and this.locale is undefined in __ method. And it set locale to defaultLocale (i. e. 'en')
If I add this code:
if (locales[target_locale]) {
defaultLocale = target_locale; // this line is added
if (request === undefined) {
defaultLocale = target_locale;
}
else {
request.locale = target_locale;
}
}
to setLocale method it works fine again.
What I am do wrong or this is a bug? I tried it with 0.3.6 version it doesn't work, but with 0.3.5 - it works fine. May be I missed something?
Sorry for my Engish, it isn't my native language.
Support for structured json would be nice:
{
"home": {
"title": "Home",
"subtitle": "Here is you home."
}
}
Equivalent to:
{
"home-title": "Home",
"home-subtitle": "Here is you home."
}
So you can translate: i18n.__('home-title')
.
An alternative could be to have the possibilities to import JavaScript files and not only JSON Format.
line 240 in file i18n.js
function write(locale) {
try {
stats = fs.lstatSync(directory);
} catch(e) {
...
}
You might be inspired by the work on multiple dictionaries in Uber's fork
https://github.com/uber/i18n-node/commit/6a414a819fc0b07201080fcb7bab571956341d9b
I like the flexible singular/plural API. It's great for node on the server side, but it'd be super nice to be able to re-use the mappings produced in en.js on the client side too with a port of the node library to a client library.
In my express app, I need to pass the current locale data (the whole js object that I'll stringify) for client-side rendering, however locales
being private, we can't access it easily and must manually reload the json files.
Is there a reason for being so "greedy" with your local variables ;-)?
I have a use case in which I need to translate long texts. The json file gets pretty uggly with long texts, so I think on supporting files.
Basically in your locale entry you put a file path like this:
{
'content.file': '/locales/parts/mycontent.en.part'
}
And in your code you can use this with arguments included using the current sprintf like this:
i18n.__f('content.file','myparam1');
For this I added this function right after __p (which is similar to __):
i18n.__f = function i18nTranslateUsingFile(phrase) {
// get translated filename with locale from scope (deprecated) or object
var msg = translate(getLocaleFromObject(this), phrase);
//reads the file
var fileContent = fs.readFileSync("./" + msg, 'utf8');
// if we have extra arguments with strings to get replaced,
// an additional substition injects those strings afterwards
if (arguments.length > 1) {
fileContent = vsprintf(fileContent, Array.prototype.slice.call(arguments, 1));
}
//return file content
return fileContent;
};
Hope it helps.
You can add it into the module if you want to.
Regards.
Today I was trying to internationalize my Angular frontend using the translation files I already created with i18n-node. I also wanted phrases which I add in my services/controllers/... to be automatically added to the translation files, as it already happens when I use a new term on the backend.
I wrote a little guide on how to solve that and I thought I'd share it: https://github.com/oliversalzburg/i18n-node-angular
Cheers
if there is syntax error (e.g. extra comma) in locale file, it's been cleared and rewritten totally. Could you add some option to overcome it, maybe create backup ?
thx
line 226 in file i18n.js
try {
localeFile = fs.readFileSync(file);
console.log('read ' + file + ' for locale: ' + locale);
} catch(e) {
console.log('initializing ' + file);
write(locale);
//should RETURN immediately, otherwise the bad localeFile will lead to JSON parse(localeFIle) failed
}
// try to parse to JSON
try {
locales[locale] = JSON.parse(localeFile);
} catch(e) {
...
}
In #24 the code was altered to use __dirname. However this leads to i18n using the wrong locales directory.
The used locales directory should be
/path/to/myapp/locales
However the path actually used is
/path/to/myapp/node_modules/i18n/locales
This is due to the usage of__dirname
It appears that there are no tests that verify that two requests happening at the same time will not cause problems with "setLocale" and "getLocale."
Reading the code, it looks like there will be problems in that the module-level variable 'locale' is used.
The method "renameSync" throw an error when trying to write a language file.
The error details:
unexpected error writing files (either locales\en.js.tmp or locales\en.js are not writeable?): {
[Error: EEXIST, file already exists 'MY_PATH\locales\en.js.tmp']
errno: 47,
code: 'EEXIST',
path: 'MY_PATH\locales\en.js.tmp',
syscall: 'rename' }
I think we need to delete the file first on Windows.
Hi, I have an app that needs to switch language quite often (I have multiple sockets that need to return text depending on the user settings).
Am I right to assume that for now, the only reason to get a translation for a specific local is by setting the locale with setLocale()
and then using __
or __n
?
Wouldn't it make sense to expose translate(locale, singular, plural)
as well? Or am I missing something?
Hi, I think that if you change the locale runtime using i18n.setLocale, Jade templates does not take the changes because it's taking it from the locale setted in the initial request.
I fixed it by touching the initial configuration code to this (maybe you want to refresh the README file, add this note, or I don't know):
app.use(i18n.init);
app.use(function(req, res, next) {
req.locale = i18n.getLocale(); //added by me
res.locals.__ = res.__ = function() {
return i18n.__.apply(req, arguments);
};
res.locals.__ = res.__n = function() {
return i18n.__.apply(req, arguments);
};
next();
});
Regards
When I use __(...)
with specified locale
i18n.__({phrase: 'Have you ever met %s?', locale: 'zh_CN'}, 'Ted');
Error occurred
TypeError: Object #<Object> has no method 'substring'
at Function.str_format.parse (/opt/stub/node_modules/i18n/node_modules/sprintf/lib/sprintf.js:175:16)
at str_format (/opt/stub/node_modules/i18n/node_modules/sprintf/lib/sprintf.js:75:48)
at vsprintf (/opt/stub/node_modules/i18n/node_modules/sprintf/lib/sprintf.js:185:17)
at Object.i18nTranslate [as __] (/opt/stub/node_modules/i18n/i18n.js:88:11)
at repl:1:6
at REPLServer.self.eval (repl.js:111:21)
at rli.on.e (repl.js:260:20)
at REPLServer.self.eval (repl.js:118:5)
at Interface.<anonymous> (repl.js:250:12)
at Interface.EventEmitter.emit (events.js:93:17)
Am I misunderstanding the document? or, shall I use the latest version from github instead of a package from npm?
Edit
Found that code in package from npm for __(...)
i18n.__ = function i18nTranslate(phrase) {
// get translated message with locale from scope (deprecated) or object
var msg = translate(getLocaleFromObject(this), phrase);
// if we have extra arguments with strings to get replaced,
// an additional substition injects those strings afterwards
if (arguments.length > 1) {
msg = vsprintf(msg, Array.prototype.slice.call(arguments, 1));
}
return msg;
};
and the package.json file
{
"name": "i18n",
"description": "lightweight simple translation module with dynamic json storage",
"version": "0.4.0",
"homepage": "http://github.com/mashpie/i18n-node",
"repository": {
"type": "git",
"url": "http://github.com/mashpie/i18n-node.git"
},
"author": {
"name": "Marcus Spiegel",
"email": "[email protected]"
},
"main": "./index",
"keywords": [
"template",
"i18n",
"l10n"
],
...
}
Maybe the package on NPM is broken?
Hi
the guessLanguage function don't make a distinction between ZH-CN and ZH-TW,
when i set the browser preferred language to zh-tw, the locale still is zh
but the ZH-CN and ZH-TW are not same language.
any solutions ?
defaultLocale
is hard coded to en
. But what if my page is de
and falls back to es
or some other combination? I was expecting that the locale with index 0 will be used as default.
Like pgettext(msgctxt, msgid) in node-gettext module
I like very much, that i18n writes the locale file automatically when a new translation string is used. What I am missing is a possibility to update the other locale files as well.
An example:
I have to locales, german (de) and english (en). I develop in german and use a new string. This string is added to the de.js file. The string is not added in the en.js file. Therefore I cannot create a translation of it. When I deploy the application now and an english user receives the translation he will get the german text as a translation was not done yet.
Are there any simple ways to deal with this?
Would it make sense to modify i18n, so that when a locale file is written, all locale files are updated?
It would be nice to be able to configure the character(s) used for indentation of the generated dictionnaries instead of being hardcoded to "\t".
I don't like to use 'accept-language' header to guess language settings...
But you don't say anything about set the language manually in README.md :(
The document states that locale in the request scope can be changed by req.setLocale('en')
. But that's not true. In fact it requires res.setLocale('en')
. Is this this intended behavior and and typo in docs, or is it a bug?
I read Readme.md, and it said "above code will automatically generate json", but how?
I'm using i18n-node in combinaison with expressjs and jade and I've been the warning "WARN: No locale found - check the context of the call to $__?" on every strings since I've upgraded to 0.3.3.
The message comes from:
function translate(locale, singular, plural) {
if (locale === undefined) {
console.warn("WARN: No locale found - check the context of the call to $__?");
locale = defaultLocale;
}
Which is called by:
i18n.__ = function() {
var locale;
if (this && this.scope) {
locale = this.scope.locale;
}
var msg = translate(locale, arguments[0]);
A quick debug allowed me to see that this.scope is undefined and this is:
{ version: '0.3.3',
configure: [Function],
init: [Function],
__: [Function],
__n: [Function],
setLocale: [Function],
getLocale: [Function],
overrideLocaleFromQuery: [Function] }
Thanksfully, defaultLocale is always set to the correct locale so strings end up being translated correctly but I still wonder what I'm doing wrong in my integration.
The locale is set using:
i18n.setLocale(req, locale);
And I call the translation using:
app.locals({
__i : i18n.__,
__n : i18n.__n,
});
Any help will be greatly appreciated! Thanks :D.
I use i18n-node with jade in an express web app. After updating express no view worked any longer. I received the error message:
Cannot read property 'filename' of undefined
I tracked down the problem and found out that Jade uses a function "" during view generation. As I registered a helper function "" for i18n this caused the problem. After using a different name, like "msg" for my i18n helper function everything worked fine.
Since this took me many hours I want to share this experience. Perhaps it would make sense for node-i18n to use a different default helper name function?
Hi !
I didn't find a way to change the locales directory : it seems to be defined only in the module as a local var, not available from outside scripts.
Is there a function to set this locales directory ? (other than updating the module source code itself, or course :-)
Thanks !
Sorry I don't get it, and the documentation for plural support is insufficient.
Why do I need to use two %
signs in the example provided in the readme:
__n('There is one monkey in the %%s', 'There are %d monkeys in the %%s', 3, 'tree')
Is this a special case because of the plural? What if there was another string parameter after that? Would I need to use 3 %
signs?
Hi, i need to __noop() global function like Qt QT_TRANSALTE_NOOP. This function append new text to translation file. But return source string.
My suggestion :
i18n.__noop = function () {
var locale;
if (this && this.scope) {
locale = this.scope.locale;
}
translate(locale, arguments[0]);
return arguments[0];
};
It would be good if there is a option to reload the locale manual. For example if env is development I like to watch the locale directory for changes and if there is a change I like to reload the changed file.
Is there any way that I can use html code in __() function?
for example,
"html":"<strong>html</strong>"
res.send(___("html"));
the result was plain text <strong>html</strong>, I was expecting html
__
and __n
may be a common syntax but they are not expressive. Configuration options should be included to choose other names.
This would also help with the conflict with the jade internals.
In file i18n.js:
header = l.split(';', 1)[0];
lr = header.split('-', 2);
This two vars are created as globals and could potentially generate memory leaks or problems between independent requests.
When configuring i18n with the "cookie" setting set to something, and then making sure it gets the locale from either the headers or the cookie with:
app.use(i18n.init)
there's a TypeError on line 203:
11:56:19 web.1 | TypeError: Cannot read property 'locale' of undefined
11:56:19 web.1 | at guessLanguage (/home/pedro/lahlah/node_modules/i18n/i18n.js:203:38)
11:56:19 web.1 | at Object.i18n.init (/home/pedro/lahlah/node_modules/i18n/i18n.js:74:5)
11:56:19 web.1 | at Object.handle (/home/pedro/lahlah/app.js:37:14)
11:56:19 web.1 | at next (/home/pedro/lahlah/node_modules/express/node_modules/connect/lib/proto.js:199:15)
11:56:19 web.1 | at resume (/home/pedro/lahlah/node_modules/express/node_modules/connect/lib/middleware/static.js:60:7)
11:56:19 web.1 | at SendStream.error (/home/pedro/lahlah/node_modules/express/node_modules/connect/lib/middleware/static.js:73:37)
11:56:19 web.1 | at SendStream.EventEmitter.emit (events.js:126:20)
11:56:19 web.1 | at SendStream.error (/home/pedro/lahlah/node_modules/express/node_modules/send/lib/send.js:147:51)
11:56:19 web.1 | at SendStream.onStatError (/home/pedro/lahlah/node_modules/express/node_modules/send/lib/send.js:248:48)
11:56:19 web.1 | at SendStream.pipe (/home/pedro/lahlah/node_modules/express/node_modules/send/lib/send.js:320:26)
In README.md file
__({phrase: 'Hello', 'Hello %s', locale: 'fr'}, Marcus); // Salut Marcus
seems to be an invalid syntax in my nodejs interpreter.
I am trying to use i18n with hbs and express.
I tried to register a i18n helper for the translation, but I don't seem to manage to have both the request (to get the locale of the request) and the text to be translated in the same place.
I have tried two different ways to do that:
the first (have the request but not the text, from the i18n-node project examples):
// binding template helpers to request (Credits to https://github.com/enyo #12)
app.use(function(req, res, next) {
res.locals.__ = function() {
return i18n.__.apply(req, arguments);
};
res.locals.__n = function() {
return i18n.__n.apply(req, arguments);
};
// do not forget this, otherwise your app will hang
next();
});
The second (have the text but no the request):
hbs.registerHelper '__i', (options)->
if i18n?
return i18n.__.apply this, [options.fn this]
return options.fn this
hbs.registerHelper '__n', (options)->
if i18n?
return i18n.__n.apply this, [options.fn this]
return options.fn this
What I am currently doing, is defining a middleware that sets the locale of the i18n object on every request, and using the second way for registering the partial:
app.use (req, res, next) ->
i18n.setLocale i18n.getLocale req
do next
It works, but I am worried from concurrency issues.
Am I doing it wrong or is this the intended way of doing it?
Is there really a concurrency issue?
Should the hbs module be adjusted so that registering the partials work like other templating engines (the first example)
Thanks.
We have deployed an app with i18n and from time to time, the language files get completely emptied. There seems to be either an issue with either the save to file or with the stringification.
To avoid the paranoïa of having this happen in prod, we have had to disable the file saving.
We can give you access to our private repo if you wish to investigate.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.