From 9dc330ff676f8261f9df50115ab4117db710aad2 Mon Sep 17 00:00:00 2001 From: Lai Weng Han Date: Thu, 21 Nov 2019 19:46:36 +0800 Subject: [PATCH 1/2] add format currency with names --- src/index.js | 120 +++++++++++++++++++++++++++++++++++++++++++-------- src/test.js | 36 ++++++++++++++-- 2 files changed, 136 insertions(+), 20 deletions(-) diff --git a/src/index.js b/src/index.js index 2fb740a..231cf16 100644 --- a/src/index.js +++ b/src/index.js @@ -57,7 +57,11 @@ const symbolOverrides = { // Feature detection for Intl.NumberFormat function IntlNumberFormatSupported() { - return !!(typeof Intl == "object" && Intl && typeof Intl.NumberFormat == "function"); + return !!( + typeof Intl == "object" && + Intl && + typeof Intl.NumberFormat == "function" + ); } function isBTCETH(isoCode) { @@ -77,8 +81,15 @@ function formatCurrencyOverride(formattedCurrency, locale = "en") { // Replace currency code with symbol if whitelisted. const overrideObj = symbolOverrides[code]; - if (overrideObj && overrideObj.location.start && overrideObj.forLocales[locale]) { - return formattedCurrency.replace(currencyCodeFrontMatch[0], supportedCurrencySymbols[code]); + if ( + overrideObj && + overrideObj.location.start && + overrideObj.forLocales[locale] + ) { + return formattedCurrency.replace( + currencyCodeFrontMatch[0], + supportedCurrencySymbols[code] + ); } else { return formattedCurrency; } @@ -91,7 +102,11 @@ function formatCurrencyOverride(formattedCurrency, locale = "en") { // Replace currency code with symbol if whitelisted. const overrideObj = symbolOverrides[code]; - if (overrideObj && overrideObj.location.end && overrideObj.forLocales[locale]) { + if ( + overrideObj && + overrideObj.location.end && + overrideObj.forLocales[locale] + ) { return formattedCurrency.replace(code, supportedCurrencySymbols[code]); } else { return formattedCurrency; @@ -194,10 +209,14 @@ function initializeFormatters(isoCode, locale) { if (cachedFormatter == null) { formattersCache[cacheKey] = {}; formattersCache[cacheKey].currencyFormatterNormal = currencyFormatterNormal; - formattersCache[cacheKey].currencyFormatterNoDecimal = currencyFormatterNoDecimal; + formattersCache[ + cacheKey + ].currencyFormatterNoDecimal = currencyFormatterNoDecimal; formattersCache[cacheKey].currencyFormatterMedium = currencyFormatterMedium; formattersCache[cacheKey].currencyFormatterSmall = currencyFormatterSmall; - formattersCache[cacheKey].currencyFormatterVerySmall = currencyFormatterVerySmall; + formattersCache[ + cacheKey + ].currencyFormatterVerySmall = currencyFormatterVerySmall; } } @@ -228,19 +247,37 @@ export function formatCurrency(amount, isoCode, locale = "en", raw = false) { } if (amount === 0.0) { - return formatCurrencyOverride(currencyFormatterNormal.format(amount), locale); + return formatCurrencyOverride( + currencyFormatterNormal.format(amount), + locale + ); } else if (price >= LARGE_CRYPTO_THRESHOLD) { // Large crypto amount, show no decimal value - return formatCurrencyOverride(currencyFormatterNoDecimal.format(amount), locale); - } else if (price >= MEDIUM_CRYPTO_THRESHOLD && price < LARGE_CRYPTO_THRESHOLD) { + return formatCurrencyOverride( + currencyFormatterNoDecimal.format(amount), + locale + ); + } else if ( + price >= MEDIUM_CRYPTO_THRESHOLD && + price < LARGE_CRYPTO_THRESHOLD + ) { // Medium crypto amount, show 3 fraction digits - return formatCurrencyOverride(currencyFormatterMedium.format(amount), locale); + return formatCurrencyOverride( + currencyFormatterMedium.format(amount), + locale + ); } else if (price >= 1.0 && price < MEDIUM_CRYPTO_THRESHOLD) { // crypto amount, show 6 fraction digits - return formatCurrencyOverride(currencyFormatterSmall.format(amount), locale); + return formatCurrencyOverride( + currencyFormatterSmall.format(amount), + locale + ); } else { // Crypto amount < 1, show 8 fraction digits - return formatCurrencyOverride(currencyFormatterVerySmall.format(amount), locale); + return formatCurrencyOverride( + currencyFormatterVerySmall.format(amount), + locale + ); } } else { if (raw) { @@ -254,16 +291,65 @@ export function formatCurrency(amount, isoCode, locale = "en", raw = false) { } if (amount === 0.0) { - return formatCurrencyOverride(currencyFormatterNormal.format(amount), locale); + return formatCurrencyOverride( + currencyFormatterNormal.format(amount), + locale + ); } else if (amount < 0.05) { - return formatCurrencyOverride(currencyFormatterVerySmall.format(amount), locale); + return formatCurrencyOverride( + currencyFormatterVerySmall.format(amount), + locale + ); } else if (amount < 1.0) { - return formatCurrencyOverride(currencyFormatterSmall.format(amount), locale); + return formatCurrencyOverride( + currencyFormatterSmall.format(amount), + locale + ); } else if (amount > 20000) { - return formatCurrencyOverride(currencyFormatterNoDecimal.format(amount), locale); + return formatCurrencyOverride( + currencyFormatterNoDecimal.format(amount), + locale + ); } else { // Let the formatter do what it seems best. In particular, we should not set any fraction amount for Japanese Yen - return formatCurrencyOverride(currencyFormatterNormal.format(amount), locale); + return formatCurrencyOverride( + currencyFormatterNormal.format(amount), + locale + ); } } } + +export function formatCurrencyWithNames(amount, isoCode, locale = "en") { + isoCode = isoCode.toUpperCase(); + if (currentISOCode !== isoCode || currentLocale != locale) { + currentISOCode = isoCode; + currentLocale = locale; + + // Formatters are tied to currency code, we try to initialize as infrequently as possible. + initializeFormatters(isoCode, locale); + } + + const absPrice = Math.abs(Number(amount)); + let price = 0; + let suffix = ""; + if (absPrice >= 1.0e9) { + // If Billion + price = absPrice / 1.0e9; + suffix = "B"; + } else if (abs >= 1.0e6) { + // If Million + price = absPrice / 1.0e6; + suffix = "M"; + } else if (absPrice >= 1.0e3) { + // If Thousands + price = absPrice / 1.0e3; + suffix = "K"; + } + if (isCrypto(isoCode)) { + price = Number(price.toFixed(3)); + return `${price}${suffix} ${isoCode}`; + } else { + return formatCurrency(price, isoCode, locale, false) + suffix; + } +} diff --git a/src/test.js b/src/test.js index 0b3ced3..aad5870 100644 --- a/src/test.js +++ b/src/test.js @@ -1,4 +1,9 @@ -import { formatCurrency, isCrypto, clearCache } from "./index"; +import { + formatCurrency, + isCrypto, + clearCache, + formatCurrencyWithNames +} from "./index"; test("isCrypto", () => { expect(isCrypto("BTC")).toBe(true); @@ -11,7 +16,9 @@ describe("is crypto", () => { describe("raw = true", () => { test("returns precision of 8", () => { expect(formatCurrency(0.00001, "BTC", "en", true)).toBe("0.000010000000"); - expect(formatCurrency(0.00001, "DOGE", "en", true)).toBe("0.000010000000"); + expect(formatCurrency(0.00001, "DOGE", "en", true)).toBe( + "0.000010000000" + ); }); }); @@ -82,7 +89,9 @@ describe("Intl.NumberFormat not supported", () => { describe("is BTC or ETH", () => { describe("raw = true", () => { test("returns precision of 8", () => { - expect(formatCurrency(0.00001, "BTC", "en", true)).toBe("0.000010000000"); + expect(formatCurrency(0.00001, "BTC", "en", true)).toBe( + "0.000010000000" + ); }); }); @@ -144,3 +153,24 @@ describe("Intl.NumberFormat not supported", () => { }); }); }); + +describe("large number", () => { + describe("Billion", () => { + const billionVal1 = 9.101222e9; + const billionResVal1 = "9.101B"; + const billionVal2 = 9e9; + const billionResVal2 = "9B"; + + test("format USD", () => { + expect(formatCurrencyWithNames(billionVal1, "USD", "en")).toEqual( + "USD " + billionResVal1 + ); + }); + + test("format BTC", () => { + expect(formatCurrencyWithNames(billionVal2, "BTC", "en")).toEqual( + billionResVal2 + " BTC" + ); + }); + }); +}); From 1f2cfe2173780e68bf2f567bf7475159ef20e639 Mon Sep 17 00:00:00 2001 From: Lai Weng Han Date: Thu, 21 Nov 2019 19:50:36 +0800 Subject: [PATCH 2/2] add in types --- src/index.d.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/index.d.ts b/src/index.d.ts index ad6d31e..d9f1f73 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -17,3 +17,10 @@ export function formatCurrency( locale: string, raw: boolean ): string; + +// format currency with names +export function formatCurrencyWithNames( + amount: number, + isoCode: string, + locale: string +): string;