-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
add support for number format internationalization #14019
Conversation
value: 'en', | ||
type: 'select', | ||
options: ['be-nl', 'chs', 'cs', 'da-dk', 'de-ch', 'de', 'en', 'en-gb', 'es-ES', 'es', 'et', 'fi', 'fr-CA', 'fr-ch', 'fr', 'hu', 'it', 'ja', 'nl-nl', 'pl', 'pt-br', 'pt-pt', 'ru-UA', 'ru', 'sk', 'th', 'tr', 'uk-UA'], | ||
description: '<a href="http://numeraljs.com/" target="_blank">numeral language</a>' |
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.
Could you please add rel="noopener"
to this link.
@@ -26,6 +26,15 @@ export class Numeral extends FieldFormat { | |||
} | |||
|
|||
getParamDefaults() { | |||
var language = this.getConfig('format:language'); |
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.
var
-> const
@@ -26,6 +26,15 @@ export class Numeral extends FieldFormat { | |||
} | |||
|
|||
getParamDefaults() { | |||
var language = this.getConfig('format:language'); | |||
if (language != numeral.language()) { |
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.
!=
→ !==
var language = this.getConfig('format:language'); | ||
if (language != numeral.language()) { | ||
if (language != 'en') { | ||
var languageData = require('@elastic/numeral/languages/' + language); |
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.
Please use a template string here.
@@ -26,6 +26,15 @@ export class Numeral extends FieldFormat { | |||
} | |||
|
|||
getParamDefaults() { | |||
var language = this.getConfig('format:language'); | |||
if (language != numeral.language()) { | |||
if (language != 'en') { |
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.
!=
→ !==
@timroes |
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.
LGTM
@@ -226,6 +226,12 @@ export function getUiSettingDefaults() { | |||
value: '($0,0.[00])', | |||
description: 'Default <a href="http://numeraljs.com/" target="_blank">numeral format</a> for the "currency" format' | |||
}, | |||
'format:language': { |
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 consider moving this to format:numeral:language
as this is only where it's used currently?
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.
👍 to making this setting more specific. I'm also slightly concerned about how this is a global setting. Perhaps format:number:defaultLanguage
will keep it in line with format:number:defaultPattern
and leaves room for a per-field language setting should we want to add one down the road.
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.
Hi,
format:number:defaultLanguage
looks a good idea.
That said, few points about that :
- first, this setting will apply on every type format concerned by numeraljs, so : number, bytes, percent, and currency. Not only number.
- then, currently (and since a long time), numeraljs allows only to define a global static language, not one for each formatter.
- would it make sense to have a dashboard with different numeric fields formatted with different languages ?
- in the future, an interesting evolution could be to detect browser language.
=> Given these points, what setting name do you choose ? :)
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.
numeraljs allows only to define a global static language
ugh, bummer. Is it unrealistic to call numeral.language() before every conversion?
would it make sense to have a dashboard with different numeric fields formatted with different languages?
The numeral language defines the currency symbol right? If so I think it makes sense to have a unique language per field if two fields represent different currencies.
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.
Looks like numeral.language()
is just setting an internal value inside the library, so if we called it before calling numeralInst.set().format(this.param('pattern'))
we could use a different language for each field.
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 we do move forward with applying this language to all instances of numeral
, it'd be more consistent to do so in the manner described in this comment
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.
@spalger I agree with you, it's fine to have defaultLanguage
here to be able to add per-field value later.
And yes, numeral language defines the currency symbol.
That said, in original numeraljs project (https://github.com/adamwdraper/Numeral-js), the last version use the "locale" term instead of "language" term.
So question is : do you prefer format:number:defaultLanguage
or format:number:defaultLocale
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.
I'm not too concerned about updates in numeral; I don't think we'll ever upgrade because of it's breaking changes and how that would impact everyone who has saved formats already. It's more likely that we will do something like we have done with kuery and offer a choice between legacy numeral and some custom solution we could build in the future.
That said, I think that locale is more accurate description of the choice, so I would go with format:number:defaultLocale
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.
OK, for this new name format:number:defaultLocale
, I will commit it.
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.
@spalger
new name format:number:defaultLocale
is commited
const language = this.getConfig('format:language'); | ||
if (language !== numeral.language()) { | ||
if (language !== 'en') { | ||
var languageData = require(`@elastic/numeral/languages/${language}`); |
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.
Replace var
usage with const
per our style-guide https://github.com/elastic/kibana/blob/master/style_guides/js_style_guide.md#use-const-for-variables
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.
@kobelb
Sorry for this mistalke. I just pushed the fix.
@@ -26,6 +26,15 @@ export class Numeral extends FieldFormat { | |||
} | |||
|
|||
getParamDefaults() { | |||
const language = this.getConfig('format:language'); |
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.
We really shouldn't be setting the numeral
language here, this method is only meant to return the param defaults. This situation appears to be very similar to setting the timezone for moment
which is being done in the KibanaRootController
here but then we're also having to do so in other app controllers, example here.
Perhaps @spalger can comment on a better place to put logic like this without these deficiencies.
Additionally, I have hesitations to setting the language for the global instance of numeral as this could have unintended side-effects outside of modifying the behavior of field formatters specifically.
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.
I agree it's probably not the best place to set this code.
If you find a better place, I would be glad to hear it.
I set it there because this method is called at app loading beginning and is rarely called then.
Concerning your hesitations, currently, numeraljs allows only to set this setting globally, not locally for each formatter. Then, would it make sense to have several language formats on the same kibana app ?
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.
This thread is kind of merging with #14019 (comment)
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.
@spalger do you see a better place (method) to put the javascript code which changes numeral language ?
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.
I'd just put it in the _convert function, then adding per-field params is just about exposing the UI to do so.
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 I set it there, it would require static import
of all languages.
Because, dynamic require
call shouldn't be called at convert
time, as it is an asynchronous load.
'format:language': { | ||
value: 'en', | ||
type: 'select', | ||
options: ['be-nl', 'chs', 'cs', 'da-dk', 'de-ch', 'de', 'en', 'en-gb', 'es-ES', 'es', 'et', 'fi', 'fr-CA', 'fr-ch', 'fr', 'hu', 'it', 'ja', 'nl-nl', 'pl', 'pt-br', 'pt-pt', 'ru-UA', 'ru', 'sk', 'th', 'tr', 'uk-UA'], |
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.
It's a shame that we're hard-coding these, but I'm not seeing a way to access all possible languages...
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.
@kobelb
I think exactly like you :)
I'm sad to hard-code these values, but I didn't find another way to do that.
That said, this array is likely to change very rarely (maybe never)...
const language = this.getConfig('format:language'); | ||
if (language !== numeral.language()) { | ||
if (language !== 'en') { | ||
const languageData = require(`@elastic/numeral/languages/${language}`); |
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.
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.
@fbaligand feel free to add the ability to do so at https://github.com/elastic/numeral-js
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.
@spalger
One option for that is to use v3.0.0 that is already released. This version is compatible with static import
. We can change the package.json file to depend on this version.
Are you OK to depend on this version ? Or do you consider this major version implies so much breaking changes ?
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.
@spalger
I just commited migration to @elastic/numeral v3.0.0
I had no particular problem, it works fine !
And now I can import
successfully all languages using a static way.
And so, I moved the code to _convert
method as you wish.
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.
@spalger
What do you think about ?
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.
Sorry, I should have deprecated @elastic/[email protected]
months ago. Unfortunately the way that numeral transforms format strings in v3 is not backwards compatible with v2. This means that in order to upgrade to numeral v3 we would either have to track down all the differences between the two versions, or users to recreate/double-check all of their numeric field formatters. We're currently not planning to do either, so this isn't going to work. I've updated elastic/numeral-js to reflect the current state of the package and changed https://github.com/elastic/numeral-js/blob/kibana-fork/languages.js
The file now exports the languages as an array. each item has an id
, name
, and lang
property.
id
: the filename of the langname
: the english description of the language, extracted from each language filelang
: the value that should be passed tonumeral.language(id, lang)
The file doesn't automatically register the languages, maybe we want it to do that, but it should be a suitable replacement for the current languages import, right? To test it out install @elastic/numeral
from github:
npm install https://github.com/elastic/numeral-js#kibana-fork
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.
@spalger
OK.
Thanks for all your work to transform "languages.js" in a way it can be imported easily !
So I'm ready to cancel my upgrade to 3.0.0 and write the code to register all languages in _numeral.js
using your new languages.js
version.
Hope to test it tonight.
The conversation is flattened in my view of the PR, but I responded here |
f6d8f5e
to
f6277e3
Compare
@spalger |
'format:number:defaultLocale': { | ||
value: 'en', | ||
type: 'select', | ||
options: ['be-nl', 'chs', 'cs', 'da-dk', 'de-ch', 'de', 'en', 'en-gb', 'es-ES', 'es', 'et', 'fi', 'fr-CA', 'fr-ch', 'fr', 'hu', 'it', 'ja', 'nl-nl', 'pl', 'pt-br', 'pt-pt', 'ru-UA', 'ru', 'sk', 'th', 'tr', 'uk-UA'], |
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.
We should be able to replace this array with the ids from @elastic/numeral/languages
right?
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.
Yes, it would be great to dynamically inject all language ids from "languages.js" array.
That said, this configuration file seems to be completely static.
=> do you know how to dynamically object values here ?
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.
You can require files at the top just like everything else, it's not actually static, just doesn't have any dependencies yet.
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.
You're right, sorry for this remark. Even more, I just saw that there is already one dependency.
I will fix this file to dynamically inject array from "languages.js".
Jenkins, test this |
@spalger |
Looks like jenkins build failed for linting reasons (run |
Just published |
Thanks for the release ! |
@spalger I guess I can't launch Jenkins tests for myself. Could you launch Jenkins tests ? |
Jenkins, test this |
@spalger There are errors during tests. The main problem seems to be :
I don't arrive to localize this test in Kibana sources, given the test label. Honestly, I don't know how to fix this test. Any idea ? |
@spalger => What do you think about ? |
@spalger |
jenkins, test this |
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.
LGTM
I believe I brought this up earlier, and it might've already been addressed... are we not concerned that we're modifying the global numeral language from within the numeral field_formatter? It's conceivable that another Kibana application would be relying upon Numeral to do it's own formatting, and this would affect it's behavior as well. This could be incredibly confusing to the user in the following scenario. If there were two applications Kibana: App-1 relies upon numeraljs and NOT our field formatters; App-2 relies upon our field formatters and in turn numeraljs. When the user first opens Kibana they go directly to App-1, bypassing the field-formatter code that sets the default language. They then navigate to App-2 which is setting the global numeral language. Later if they go back to App-1 they see the number formats change. |
Ah, sorry about that @fbaligand go ahead and keep your version. Can you try running the tests locally and see if they fail? In one terminal tab run: npm run test:ui:server Once the Kibana server has started up in the first terminal run this in a second tab: node scripts/functional_test_runner --grep "management scripted fields" That will run the tests in test/functional/apps/management/_scripted_fields.js and might give you an indication if this is caused be the number formatters changing (a possibility if you ask me) |
4442c3f
to
5f3c8f5
Compare
@spalger Now, I have to go to sleep ;) |
Okay, that failure wasn't because of your code, for sure. One more jenkins run should do it |
Thanks @kobelb for the approval ! |
@fbaligand yup! I can merge this a little later today. Thanks for working through this with us and your patience. |
Great ! |
@spalger |
Is it too late to merge it in Kibana 6.1 ? |
Yes |
Ok. Thanks for the answer @nreese. |
6.x/6.2: 91777d2 |
Hi all, would anyone know from which Kibana version a problem previously discussed in (and later merged with this discussion) : Thanks & Cheers, J. |
Hey, i currently looking how to change the number format of a column in visualize to german format. what is the current state? Is there a possibility to achive this? Marcel (currently i use kibana 5.1.1 and i wanna know is this feature released and it is worth to upgrade?) |
Hi @MarcelZOI As you can see in this PR tags, this feature is available since Kibana 6.2.0. Important point : this setting is a Kibana advanced setting, so it is global. You currently can't have a custom locale per field. |
@fbaligand okay, thanks. |
This PR adds a new advanced setting named "format:language".
This setting allows to choose a language to format numbers, among all numeraljs supported languages.
Number format is about decimal delimiter, thousand delimiter and currency symbol.
This feature is particularly useful to format every language specific number formats (not only english).
Precision : given how numeraljs works, it could only be a global option, this can't be customized for each field. Up to me, not a problem since it would be weird to display on a same dashboard different numeral fields with different language formats.
Fixes #9228.
Partially fixes #8983.