-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lib: externalized messages support #4311
Conversation
"Incorrect value for stdio stream: {0}": { | ||
"key": "ERR000010" | ||
}, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the spaces for?
This isn't JSON, so we could add comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just visual separation for now. As I said, it's a work in progress ;-) I'm not in love with the idea of stuffing all these into a single js file
It might be neat if the mechanisms behind this could be usable in userland. Just a thought. |
@jasnell what do you think about precompiling this as we currently do for What I don't like about this approach is that it adds runtime cost to the most (if not all) textual reporting in core. Ideally we may use some kind of macro in C++ or whenever to replace this |
'use strict'; | ||
|
||
// adapted from the approach documented at: | ||
// http://jaysoo.ca/2014/03/20/i18n-with-es6-template-strings/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we maybe note why we are doing it like this a bit more here?
Also since this won;t be in the API docs it may be useful to have a quick API-doc thing here. (i.e. what to put in, what comes out)
I think the approach is pretty nice, but I also agree with @indutny. |
just to be certain, I'm definitely not sold on this approach yet. @Fishrock123 @indutny ... we could certainly use compiled variants to improve performance. That does get a bit difficult to manage (one binary for each supported language) but it's certainly not out of the question (it's just a bit more work for the build and release team). I'd be favorable of that approach but we'd need to be clear about the impact and we'd still need to have the clear ID to message mapping. A pre-processor that runs during make wouldn't be too difficult to build. |
Are we really worried about runtime costs in error situations anyway? |
likely not, but there's a trade off. I'd rather not beef up the binary size to hold a bunch of translated strings if we can avoid it. |
That's great seeing progress in this area, as a non-native English speaker I rejoice. Even though I like my errors to be in English (mainly because they are easier to search, and I am lazy), translated errors were really helpful when my English was poor. A couple of things: packagers (deb, rpm) usually package lang files separately. There are reasons for doing this: lots of languages, not requiring a release for adding a locale, ecc. However, if these are not in the main bundle, it is unlikely that a newbie would install them in the first place. On Windows, we can possibly show a nice dialog. But on Mac and Linux? We need to have a clear story for packagers. Regarding performance: what is the impact? Most platforms were performance is important (e.g. iOS, Android) have externalized errors/strings. Really really dumb question: why can't we just have functions? Basically we would have a const ERR000009 = I18N.ERR000009
throw new Error(ERR000009('a', 'b')) Last thing to consider: a lot of userland modules might want/would benefit of similar functionality. |
At very least, it would probably be a good standard to have. @jasnell Maybe consider prefixing with |
@mcollina .. the main issue with the function form (which I considered also) is that we'd have to create the function objects for each message -- which isn't out of the question but that ends up being a lot of additional objects kept around. Not sure if it's enough of an impact to worry about tho. The main challenge with this is that there are several approaches we can take to the API and it's easy to bike shed. For the most part, we simply need to come up with one approach that everyone can at least work with. Once that's settled I can get it implemented and run performance benchmarks. @Fishrock123 ... the other question I have is whether there should be a single generic naming pattern or if we should tie it to the module... for instance instead of |
@jasnell ooh, that could be even better. |
@mcollina ... btw, as part of this effort, once the approach is settled on, I'm planning to implement a command line tool that can accept one of the message identifiers and output the explanation for it, preferably with localization as well. In other words, if you get an |
@jasnell
Can you explain? |
I am ok for trading a bit a of memory for speed. It would probably be negligible, given all the functions return strings that would also need to be maintained in memory. However, it is something to worry about for low-memory devices (IoT?).
I agree. We should possibly iterate on it between releases.
👍, much better.
Yes, but it is really needed. There are some incomplete/bad explanations around the net. |
@Fishrock123 @mcollina @indutny @Qard @nodejs/ctc @nodejs/collaborators ... Ok, I've taken a step back and did a major refactoring on this and force pushed and update. The new approach is documented in the new commit log in 68792d5. The changes are:
Please take a look and let me know if this is heading in the right direction. |
I would note that this is a work in progress! The list of messages is not complete. Fortunately, we do not have a large number of messages that we output. |
Interesting, will think about it more tomorrow. |
I am generally 👍 regarding this, the API is simple enough and we can possibly change the implementation later. |
return this.error('Breakpoint not found on line ' + line); | ||
} | ||
if (breakpoint === undefined) | ||
return this.error(I18N(I18N.NODE_DEBUGGER_BREAKPOINT_NOT_FOUND,line)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space after the comma.
Refactor to allow the `new` keyword and proper callsite reporting for the externalized error objects.
// I18N(key[, ...args]) | ||
// Returns: string | ||
function message() { | ||
const key = arguments[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the function always has one argument it's better to declare it as function message(key) {
, that avoids an ArgumentsAdaptorTrampoline stack frame.
This is likely to go a different direction, currently pending @srl295's work to make ICU always available as a dependency. Closing this for now, will reopen when it's closer to a full solution. |
@nodejs/ctc @nodejs/collaborators ...
externalizing the error and output messages in lib
string based mechanism described here
that I am working on in src: initial localization support (work in progress) #3413
This introduces a new internal/messages module that exports a
template string tag function. The externalized messages are in
internal/messages_en.js for now but can be moved to a different
location.
Within the lib src, we can use this mechanism using tagged template
strings:
In the
messages_en.js
file, we'd have something like:The template string would expand into:
ERR000009: Example Error: testing
Later on, when we get into actually translating messages, we
would have other message_{locale}.js files (or however else we'd
like to separate it out) that would look something like:
I'm not yet convinced this approach is ideal, but it's functional.
There are a few gotchas with template strings currently that are less
than ideal (e.g. line wrapping issues, lookup is a bit inefficient).
Getting this out now, tho, to solicit input on the approach.
This is still a work in progress