Skip to content
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 locale option #39

Merged
merged 27 commits into from
May 6, 2018
Merged

Add locale option #39

merged 27 commits into from
May 6, 2018

Conversation

meisterlampe
Copy link
Contributor

This is meant to close #4 (I copied the parameters for .toLocaleString(..) from @silverwind , who opened the issue)

Uses .toLocaleString(...) to create the human readable strings for a locale.
Specifying the locale is optional.
If ommited, the default language will be used.

Please add your thoughts on this. It was only a first shot.

index.js Outdated
@@ -17,7 +17,7 @@ module.exports = num => {
}

const exponent = Math.min(Math.floor(Math.log10(num) / 3), UNITS.length - 1);
const numStr = Number((num / Math.pow(1000, exponent)).toPrecision(3));
const numStr = (num / Math.pow(1000, exponent)).toLocaleString(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
Copy link

@silverwind silverwind Nov 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just use argument-less .toLocaleString() which will automatically format in the user's current locale, which I think is what 99% of users want.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, keep the Number().

index.js Outdated
@@ -1,7 +1,7 @@
'use strict';
const UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

module.exports = num => {
module.exports = (num, locale = undefined) => {
Copy link

@silverwind silverwind Nov 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagined a boolean option like localize which enables .toLocaleString(). I'd say default it to false.

Copy link
Contributor Author

@meisterlampe meisterlampe Nov 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to pass the locale, because I need to enable the user to change the language during runtime in my ionic-app.

What do you think about using your approach (boolean option localize, default to false) plus adding an option to set the locale to use in case of localize? (This is how moment.js does it)

Example for default locale de:

> prettybytes(1230000);
1.23 MB
> prettybytes(1230000, true); // Default system locale 'de' is used
1,23 MB

>  prettybytes.locale('rn'); // Changes the locale for all subsequent calls with localize = true;
>  prettybytes(1230000, true): // Locale 'rn' is used
1.23 MB

Just to make xo linter happy :)
Some tests failed indicating, that no minimumFractionDigits are wanted.
E.g.: 10.1 should be 10.1 and not 10.10
Node 4 doesn't support them (Travis CI build failed because of that).
Default value isn't needed though, because checking for localize should work nevertheless.
E.g.: 
- undefined == true => false
- false == true => false
- 0 == true => false
- true == true => true
- 1 == true => true
index.js Outdated
@@ -1,7 +1,7 @@
'use strict';
const UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

module.exports = num => {
module.exports = (num, localize) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to mention this last time, but could you make an option object as the second argument, e.g. {localize: true}.

@silverwind
Copy link

silverwind commented Nov 30, 2017

LGTM once the option object is in. I think we can also do some unit tests for various locales (have to verify they work on Travis), but I can add those after merging this one.

@meisterlampe
Copy link
Contributor Author

Added an options object.

In my case I need to pass in the locale-key as I change the language during runtime in an app using Ionic. Any chance to add this in another PR later on?

index.js Outdated
@@ -17,7 +17,8 @@ module.exports = num => {
}

const exponent = Math.min(Math.floor(Math.log10(num) / 3), UNITS.length - 1);
const numStr = Number((num / Math.pow(1000, exponent)).toPrecision(3));
const numTmp = Number((num / Math.pow(1000, exponent)).toPrecision(3));
const numStr = options && options.localize ? numTmp.toLocaleString() : numTmp;
Copy link
Contributor

@kevva kevva Dec 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe do options = Object.assign({}, options) after the Number.isFinite(num) if statement at the start of the function. This ensures that options is an object too.

Copy link

@silverwind silverwind Dec 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that Object.assign required Node.js 5 or greater which breaks compatibilty on the current minimum version 4. I'd just to opts = opts || {} on the start of the function.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@silverwind Object.assign is supported on Node.js 4

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh, you're right, carry on. (I was misinterpreting http://node.green/)

Copy link
Contributor Author

@meisterlampe meisterlampe Dec 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late reply. You're right. Using object.assign is way better than checking for undefined on each use. I'll add this.

@silverwind
Copy link

silverwind commented Dec 1, 2017

In my case I need to pass in the locale-key

Then let's change the option name to locale and typecheck it. On string, pass it to toLocaleString, otherwise use it as a boolean which decides on whether to use toLocaleString.

@meisterlampe
Copy link
Contributor Author

That would be a good solution for me. Thanks. I will add it.

Don't check options on each use. Check it at the beginning of the method instead.
If locale = true => localize using the default locale
If locale = string => the value is expected to be a locale-key-string and is used as parameter for toLocaleString(..)
...and use single quoted string. To pass linter checks
Removed separate check of options.local. typeof has no problems with undefined-arguments
@meisterlampe
Copy link
Contributor Author

@kevva Are you fine with the changes?

@sindresorhus
Copy link
Owner

sindresorhus commented Dec 11, 2017

I'm fine with the change, but it needs docs and tests.

See https://github.com/sindresorhus/boxen#api for how to format the docs.

@meisterlampe
Copy link
Contributor Author

OK I'll look into that.

@meisterlampe
Copy link
Contributor Author

meisterlampe commented Dec 19, 2017

Added those lines, but it still isn't working (same error during test-execution).
Travis-CI build says: libicu-dev is already the newest version (52.1-3ubuntu0.7). So maybe, this had no effect. (https://travis-ci.org/sindresorhus/pretty-bytes/jobs/318665413)
Any other commands I can try? I wasn't able to find any useful info using google (beside building node with a special flag).

@silverwind
Copy link

silverwind commented Dec 19, 2017

I assume Travis installed the official Node.js packages, so I checked them in both Ubuntu 14.04 and 16.04 and I discovered that both are actually built with small-icu, not system-icu, which means it won't detect a system ICU library at all. We can use the full-icu module thought, try:

before_install:
  - npm install full-icu
env:
  - NODE_ICU_DATA=node_modules/full-icu

You're still missing a option description in README.md, I'd note there that the option generally works in browsers, but for Node, the user has to make sure that ICU is working, probably by linking them to full-icu.

@meisterlampe
Copy link
Contributor Author

meisterlampe commented Dec 20, 2017

Hm.. the environment is set before installing the npm package and with the variable set, installing seems to error out. (https://travis-ci.org/sindresorhus/pretty-bytes/jobs/319039889)
I tried to export the variable in after_install, but had no luck (https://travis-ci.org/sindresorhus/pretty-bytes/jobs/319047209)

@silverwind
Copy link

There's no after_install step according to this, try exporting in a before_script.

because there is no after_install step :)
@silverwind
Copy link

Ah, it finally passed. Can you document the new option in the README and add a note that users may need to install the full-icu package for it to work?

@meisterlampe
Copy link
Contributor Author

You were right.. there is no `after_install. Ouch. Thanks for the hint on this :)
I tried to document the new option in the readme. I'm happy to get corrections, if something is missing, not well verbalized or just a typo

index.js Outdated
const neg = num < 0;

if (neg) {
num = -num;
}

if (num < 1) {
num = toLocaleString(num, options.locale);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor, but I'd declare let numStr earlier and then assign it here, making it clearer that num is always a number.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. Also changed line 24, where the result is always a number and not a numStr

readme.md Outdated

**Note:** Localization should generally work in browsers. Node-Users have to ensure, there Node version has [full ICU-Support](https://github.com/nodejs/node/wiki/Intl):
- if your using linux, node should be able to link to the installed system-icu automatically
- or you install the [full-icu-package](https://github.com/unicode-org/full-icu-npm) and set the environment variable [NODE-ICU-DATA](https://github.com/nodejs/node/wiki/Intl#using-and-customizing-the-small-icu-build) to `node_modules/full-icu`
Copy link

@silverwind silverwind Dec 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not entirely true that all node versions need the module. The Node.js on macOS' homebrew for example comes built with system-icu. I'd word it like this:

Localization should generally work in browsers. Node.js needs to be built with full-icu or system-icu. Alternatively, the full-icu module can be used to provide support at runtime.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added your wording.

@silverwind
Copy link

LGTM, this should be ready to merge, @sindresorhus.

@meisterlampe
Copy link
Contributor Author

It would be nice, if you could merge this. If something is missing, I'm happy to add/fix it.

@silverwind
Copy link

ping @sindresorhus and @kevva.

@meisterlampe
Copy link
Contributor Author

re-ping @sindresorhus and @kevva :)

index.js Outdated
if (num < 1) {
return (neg ? '-' : '') + num + ' B';
numStr = toLocaleString(num, options.locale);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const numStr = toLocaleString(num, options.locale);

index.js Outdated
}

const exponent = Math.min(Math.floor(Math.log10(num) / 3), UNITS.length - 1);
const numStr = Number((num / Math.pow(1000, exponent)).toPrecision(3));
num = Number((num / Math.pow(1000, exponent)).toPrecision(3));
numStr = toLocaleString(num, options.locale);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const numStr = toLocaleString(num, options.locale);

index.js Outdated
/**
* Formats the given number using number.toLocaleString(..).
* If locale is a string, the value is expected to be a locale-key (e.g. 'de').
* If locale is true or 1, the system default locale is used for translation.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If locale is true or 1

Should only be when it's true.

index.js Outdated
let result = num;
if (typeof locale === 'string') {
result = num.toLocaleString(locale);
} else if (locale) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

} else if (locale === true) {

@meisterlampe
Copy link
Contributor Author

@sindresorhus: Thanks for your feedback. I agree with the requested changes and added them to the PR.

@meisterlampe
Copy link
Contributor Author

@sindresorhus and @kevva: Can you merge this please? If something is missing, I'm happy to fix things

@meisterlampe
Copy link
Contributor Author

Can this be merged please? I would like to remove my forked version from my project.

@silverwind
Copy link

silverwind commented Mar 7, 2018

Not sure what the holdup here is.

One suggestion for the full-icu dependency: Add it under both peerDependencies and devDependencies. That way, users will notice it when installing dependencies and it will be included for developers so npm test can pass locally for them, while also making sure it's not included in browser builds.

Oh, and you could make sure that environment variable is set during npm test by using cross-env.

These two changes should make the adjustments in travis.yml unneccesary.

@sindresorhus
Copy link
Owner

Not sure what the holdup here is.

Just time. I have over 300 PRs to review…

Add it under both peerDependencies and

I don't want it under peerDependencies. It could make people think it's a requirement.

@meisterlampe
Copy link
Contributor Author

Not sure what the holdup here is.

Just time. I have over 300 PRs to review…

That is ok.. Just thought, this PR has been forgotten.
Take your time and thanks for voluntarily maintaining so many open source projects.

@silverwind
Copy link

silverwind commented Mar 7, 2018

I don't want it under peerDependencies. It could make people think it's a requirement.

Hmm okay. We should still have it in devDependencies so tests pass unconditionally.

On the topic of ICU, I meant to do some research on the binary sizes and propose building Node.js with full ICU by default, so hopefully this dependency won't be required some day.

Edit: see nodejs/node#19214

@sindresorhus sindresorhus changed the title Make use of .toLocaleString Add locale option May 6, 2018
@sindresorhus sindresorhus merged commit 73a7955 into sindresorhus:master May 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Locale-aware decimal seperator
4 participants