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:
@@ -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 => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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: ','
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user