feat: allow setting of thousand/decimal separators (#1722)

* feat: allow setting of thousand/decimal separators

* fix: add file header and fix lint errors

* fix: move getSeparator to format
This commit is contained in:
Aleš Ferlan
2023-02-07 14:56:27 +02:00
committed by GitHub
parent 769b953983
commit 913bf65dab
8 changed files with 152 additions and 9 deletions
@@ -189,6 +189,24 @@ describe('formatBalance', (): void => {
formatBalance(TESTVAL, { decimals: 15, forceUnit: 'µ' })
).toEqual('123.4567 µUnit');
});
it('formats 123,456 (decimals=0, locale=sl)', (): void => {
expect(
formatBalance(123456, { decimals: 0, locale: 'sl', withSi: true })
).toEqual('123,4560 kUnit');
});
it('formats BigInt numbers (locale=sl)', (): void => {
expect(
formatBalance(123456789000n, { decimals: 15, locale: 'sl', withSi: true })
).toEqual('123,4567 µUnit');
});
it('formats 123,456,789,000 (decimals=7, forceUnit=base locale=sl)', (): void => {
expect(
formatBalance(TESTVAL, { decimals: 7, forceUnit: '-', locale: 'sl' })
).toEqual('12.345,6789 Unit');
});
});
describe('calcSi', (): void => {
+9 -2
View File
@@ -7,6 +7,7 @@ import type { SiDef, ToBn } from '../types';
import { bnToBn } from '../bn/toBn';
import { isBoolean } from '../is/boolean';
import { formatDecimal } from './formatDecimal';
import { getSeparator } from './getSeparator';
import { calcSi, findSi, SI, SI_MID } from './si';
interface Defaults {
@@ -48,6 +49,10 @@ interface Options {
* @description Returns all trailing zeros, otherwise removes (default = true)
*/
withZero?: boolean;
/**
* @description The locale to use
*/
locale?: string;
}
interface BalanceFormatter {
@@ -66,7 +71,7 @@ let defaultDecimals = DEFAULT_DECIMALS;
let defaultUnit = DEFAULT_UNIT;
// Formats a string/number with <prefix>.<postfix><type> notation
function _formatBalance <ExtToBn extends ToBn> (input?: number | string | BN | bigint | ExtToBn, { decimals = defaultDecimals, forceUnit, withAll = false, withSi = true, withSiFull = false, withUnit = true, withZero = true }: Options = {}): string {
function _formatBalance <ExtToBn extends ToBn> (input?: number | string | BN | bigint | ExtToBn, { decimals = defaultDecimals, forceUnit, withAll = false, withSi = true, withSiFull = false, withUnit = true, withZero = true, locale = 'en' }: Options = {}): string {
// we only work with string inputs here - convert anything
// into the string-only value
let text = bnToBn(input).toString();
@@ -127,7 +132,9 @@ function _formatBalance <ExtToBn extends ToBn> (input?: number | string | BN | b
: ` ${withSiFull ? `${si.text}${withUnit ? ' ' : ''}` : si.value}${withUnit ? unit : ''}`
: '';
return `${sign}${formatDecimal(pre)}${post && `.${post}`}${units}`;
const { decimal, thousand } = getSeparator(locale);
return `${sign}${formatDecimal(pre, thousand)}${post && `${decimal}${post}`}${units}`;
}
export const formatBalance = _formatBalance as BalanceFormatter;
+3 -3
View File
@@ -6,9 +6,9 @@ const NUMBER_REGEX = new RegExp('(\\d+?)(?=(\\d{3})+(?!\\d)|$)', 'g');
/**
* @name formatDecimal
* @description Formats a number into string format with thousand seperators
* @description Formats a number into string format with thousand separators
*/
export function formatDecimal (value: string): string {
export function formatDecimal (value: string, separator = ','): string {
// We can do this by adjusting the regx, however for the sake of clarity
// we rather strip and re-add the negative sign in the output
const isNegative = value[0].startsWith('-');
@@ -17,6 +17,6 @@ export function formatDecimal (value: string): string {
: value.match(NUMBER_REGEX);
return matched
? `${isNegative ? '-' : ''}${matched.join(',')}`
? `${isNegative ? '-' : ''}${matched.join(separator)}`
: value;
}
@@ -37,4 +37,22 @@ describe('formatNumber', (): void => {
})
).toEqual('12,345');
});
it('formats negative numbers (locale=sl)', (): void => {
expect(
formatNumber(-123456, { locale: 'sl' })
).toEqual('-123.456');
});
it('formats BN numbers (locale=sl)', (): void => {
expect(
formatNumber(new BN(12345), { locale: 'sl' })
).toEqual('12.345');
});
it('formats BigInt numbers (locale=sl)', (): void => {
expect(
formatNumber(123456789n, { locale: 'sl' })
).toEqual('123.456.789');
});
});
+16 -3
View File
@@ -6,11 +6,24 @@ import type { ToBn } from '../types';
import { bnToBn } from '../bn/toBn';
import { formatDecimal } from './formatDecimal';
import { getSeparator } from './getSeparator';
interface Options {
/**
* @description The locale to use
*/
locale?: string;
}
/**
* @name formatNumber
* @description Formats a number into string format with thousand seperators
* @description Formats a number into string format with thousand separators
*/
export function formatNumber <ExtToBn extends ToBn> (value?: ExtToBn | BN | bigint | number | null): string {
return formatDecimal(bnToBn(value).toString());
export function formatNumber <ExtToBn extends ToBn> (
value?: ExtToBn | BN | bigint | number | null,
{ locale = 'en' }: Options = {}
): string {
const { thousand } = getSeparator(locale);
return formatDecimal(bnToBn(value).toString(), thousand);
}
@@ -0,0 +1,72 @@
// Copyright 2017-2023 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { getSeparator } from './getSeparator';
describe('getSeparator', (): void => {
it('uses system locale', (): void => {
const n = 1000.1;
const locale = {
decimal: n.toLocaleString().substring(5, 6),
thousand: n.toLocaleString().substring(1, 2)
};
expect(
getSeparator()
).toEqual(locale);
});
it('uses en locale', (): void => {
expect(
getSeparator('en')
).toEqual({
decimal: '.',
thousand: ','
});
});
it('uses en-gb locale', (): void => {
expect(
getSeparator('en-gb')
).toEqual({
decimal: '.',
thousand: ','
});
});
it('uses sl locale', (): void => {
expect(
getSeparator('sl')
).toEqual({
decimal: ',',
thousand: '.'
});
});
it('uses sl-si locale', (): void => {
expect(
getSeparator('sl-si')
).toEqual({
decimal: ',',
thousand: '.'
});
});
it('uses it-it locale', (): void => {
expect(
getSeparator('it-it')
).toEqual({
decimal: ',',
thousand: '.'
});
});
it('uses ja-jp locale', (): void => {
expect(
getSeparator('ja-jp')
).toEqual({
decimal: '.',
thousand: ','
});
});
});
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2017-2023 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/**
* Get the decimal and thousand separator of a locale
* @param locale
* @returns {decimal: string, thousand: string}
*/
export function getSeparator (locale?: string):
{ thousand: string, decimal: string } {
return {
decimal: (0.1).toLocaleString(locale).substring(1, 2),
thousand: (1000).toLocaleString(locale).substring(1, 2)
};
}