From a0d49a12d5f51819dd538098c9020275164d32d4 Mon Sep 17 00:00:00 2001 From: Oskars Pakers Date: Fri, 4 Feb 2022 15:36:59 +0200 Subject: [PATCH 1/2] #735 Latvian language support --- README.md | 1 + __tests__/lv-LV.test.ts | 218 ++++++++++++++++++++++++++++++++++++++++ dist/ToWords.js | 3 + dist/locales/lv-LV.d.ts | 4 + dist/locales/lv-LV.js | 70 +++++++++++++ src/ToWords.ts | 3 + src/locales/lv-LV.ts | 67 ++++++++++++ 7 files changed, 366 insertions(+) create mode 100644 __tests__/lv-LV.test.ts create mode 100644 dist/locales/lv-LV.d.ts create mode 100644 dist/locales/lv-LV.js create mode 100644 src/locales/lv-LV.ts diff --git a/README.md b/README.md index 8da1d06d..9dbeb7b8 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ let words = toWords.convert(0.572, { currency: true, ignoreZeroCurrency: true }) | India | Hindi | hi-IN | | India | Marathi | mr-IN | | Turkey | Turkish | tr-TR | +| Latvia | Latvian | lv-LR | ## Inspiration for core logic [https://stackoverflow.com/a/46221860](https://stackoverflow.com/a/46221860) diff --git a/__tests__/lv-LV.test.ts b/__tests__/lv-LV.test.ts new file mode 100644 index 00000000..4a3d3a81 --- /dev/null +++ b/__tests__/lv-LV.test.ts @@ -0,0 +1,218 @@ +import { cloneDeep } from 'lodash'; +import { ToWords } from '../src/ToWords'; +import lvLV from '../src/locales/lv-LV'; + +const localeCode = 'lv-LV'; +const toWords = new ToWords({ + localeCode, +}); + +describe('Test Locale', () => { + test(`Locale Class: ${localeCode}`, () => { + expect(toWords.getLocaleClass()).toBe(lvLV); + }); + + const wrongLocaleCode = localeCode + '-wrong'; + test(`Wrong Locale: ${wrongLocaleCode}`, () => { + const toWordsWrongLocale = new ToWords({ + localeCode: wrongLocaleCode, + }); + expect(() => toWordsWrongLocale.convert(1)).toThrow(/Unknown Locale/); + }); +}); + +const testIntegers = [ + [0, 'nulle'], + [137, 'simtu trīsdesmit septiņi'], + [700, 'septiņi simti'], + [4680, 'četri tūkstoši seši simti astoņdesmit'], + [63892, 'sešdesmit trīs tūkstoši astoņi simti deviņdesmit divi'], + [792581, 'septiņi simti deviņdesmit divi tūkstoši pieci simti astoņdesmit viens'], + [1234567, 'viens miljons divi simti trīsdesmit četri tūkstoši pieci simti sešdesmit septiņi'], + [2741034, 'divi miljoni septiņi simti četrdesmit viens tūkstotis trīsdesmit četri'], + [86429753, 'astoņdesmit seši miljoni četri simti divdesmit deviņi tūkstoši septiņi simti piecdesmit trīs'], + [975310864, 'deviņi simti septiņdesmit pieci miljoni trīs simti desmit tūkstoši astoņi simti sešdesmit četri'], + [ + 9876543210, + 'deviņi miljardi astoņi simti septiņdesmit seši miljoni pieci simti četrdesmit trīs tūkstoši divi simti desmit', + ], + [ + 98765432101, + 'deviņdesmit astoņi miljardi septiņi simti sešdesmit pieci miljoni četri simti trīsdesmit divi tūkstoši simtu viens', + ], + [ + 987654321012, + 'deviņi simti astoņdesmit septiņi miljardi seši simti piecdesmit četri miljoni trīs simti divdesmit viens tūkstotis divpadsmit', + ], + [ + 9876543210123, + 'deviņi triljoni astoņi simti septiņdesmit seši miljardi pieci simti četrdesmit trīs miljoni divi simti desmit tūkstoši simtu divdesmit trīs', + ], + [ + 98765432101234, + 'deviņdesmit astoņi triljoni septiņi simti sešdesmit pieci miljardi četri simti trīsdesmit divi miljoni simtu viens tūkstotis divi simti trīsdesmit četri', + ], +]; + +describe('Test Integers with options = {}', () => { + test.each(testIntegers)('convert %d => %s', (input, expected) => { + expect(toWords.convert(input as number)).toBe(expected); + }); +}); + +describe('Test Negative Integers with options = {}', () => { + const testNegativeIntegers = cloneDeep(testIntegers); + testNegativeIntegers.map((row, i) => { + if (i === 0) { + return; + } + row[0] = -row[0]; + row[1] = `mīnus ${row[1]}`; + }); + + test.each(testNegativeIntegers)('convert %d => %s', (input, expected) => { + expect(toWords.convert(input as number)).toBe(expected); + }); +}); + +describe('Test Integers with options = { currency: true }', () => { + const testIntegersWithCurrency = cloneDeep(testIntegers); + testIntegersWithCurrency.map((row) => { + row[1] = `${row[1]} euro`; + }); + + test.each(testIntegersWithCurrency)('convert %d => %s', (input, expected) => { + expect(toWords.convert(input as number, { currency: true })).toBe(expected); + }); +}); + +describe('Test Integers with options = { currency: true, doNotAddOnly: true }', () => { + const testIntegersWithCurrency = cloneDeep(testIntegers); + testIntegersWithCurrency.map((row) => { + row[1] = `${row[1]} euro`; + }); + + test.concurrent.each(testIntegersWithCurrency)('convert %d => %s', (input, expected) => { + expect(toWords.convert(input as number, { currency: true, doNotAddOnly: true })).toBe(expected); + }); +}); + +describe('Test Integers with options = { currency: true, ignoreZeroCurrency: true }', () => { + const testIntegersWithCurrencyAndIgnoreZeroCurrency = cloneDeep(testIntegers); + testIntegersWithCurrencyAndIgnoreZeroCurrency.map((row, i) => { + row[1] = i === 0 ? '' : `${row[1]} euro`; + }); + + test.each(testIntegersWithCurrencyAndIgnoreZeroCurrency)('convert %d => %s', (input, expected) => { + expect( + toWords.convert(input as number, { + currency: true, + ignoreZeroCurrency: true, + }), + ).toBe(expected); + }); +}); + +const testFloats = [ + [0.0, 'nulle'], + // [0.04, 'Zéro Virgule Zéro Quatre'], + // [0.0468, 'Zéro Virgule Zéro Quatre Six Huit'], + // [0.4, 'Zéro Virgule Quatre'], + // [0.63, 'Zéro Virgule Soixante-Trois'], + // [0.973, 'Zéro Virgule Neuf Cent Soixante-Treize'], + // [0.999, 'Zéro Virgule Neuf Cent Quatre-Vingt-Dix-Neuf'], + // [37.06, 'Trente-Sept Virgule Zéro Six'], + // [37.068, 'Trente-Sept Virgule Zéro Six Huit'], + // [37.68, 'Trente-Sept Virgule Soixante-Huit'], + // [37.683, 'Trente-Sept Virgule Six Cent Quatre-Vingt-Trois'], +]; + +describe('Test Floats with options = {}', () => { + test.each(testFloats)('convert %d => %s', (input, expected) => { + expect(toWords.convert(input as number)).toBe(expected); + }); +}); + +const testFloatsWithCurrency = [ + [0.0, `nulle euro`], + // [0.04, `nulle euro un četri centi`], + // [0.0468, `Zéro Euros Et Cinq Centimes`], + // [0.4, `nulle euro un četrdesmit centi`], + // [0.63, `Zéro Euros Et Soixante-Trois Centimes`], + // [0.973, `Zéro Euros Et Quatre-Vingt-Dix-Sept Centimes`], + // [0.999, `Un Euros`], + // [37.06, `Trente-Sept Euros Et Six Centimes`], + // [37.068, `Trente-Sept Euros Et Sept Centimes`], + // [37.68, `Trente-Sept Euros Et Soixante-Huit Centimes`], + // [37.683, `Trente-Sept Euros Et Soixante-Huit Centimes`], +]; + +describe('Test Floats with options = { currency: true }', () => { + test.each(testFloatsWithCurrency)('convert %d => %s', (input, expected) => { + expect(toWords.convert(input as number, { currency: true })).toBe(expected); + }); +}); + +describe('Test Floats with options = { currency: true, ignoreZeroCurrency: true }', () => { + const testFloatsWithCurrencyAndIgnoreZeroCurrency = cloneDeep(testFloatsWithCurrency); + testFloatsWithCurrencyAndIgnoreZeroCurrency[0][1] = ''; + testFloatsWithCurrencyAndIgnoreZeroCurrency.map((row, i) => { + if (i === 0) { + row[1] = ''; + return; + } + if (row[0] > 0 && row[0] < 1) { + row[1] = (row[1] as string).replace(`nulle eiro un `, ''); + } + }); + + test.each(testFloatsWithCurrencyAndIgnoreZeroCurrency)('convert %d => %s', (input, expected) => { + expect( + toWords.convert(input as number, { + currency: true, + ignoreZeroCurrency: true, + }), + ).toBe(expected); + }); +}); + +describe('Test Floats with options = { currency: true, ignoreDecimal: true }', () => { + const testFloatsWithCurrencyAndIgnoreDecimal = cloneDeep(testFloatsWithCurrency); + testFloatsWithCurrencyAndIgnoreDecimal.map((row) => { + if (row[0] === 0.999) { + row[1] = `nulle euro`; + } else { + row[1] = (row[1] as string).replace(new RegExp(` un [\\w\\- ]+ centi`), ''); + } + }); + + test.each(testFloatsWithCurrencyAndIgnoreDecimal)('convert %d => %s', (input, expected) => { + expect( + toWords.convert(input as number, { + currency: true, + ignoreDecimal: true, + }), + ).toBe(expected); + }); +}); + +describe('Test Floats with options = { currency: true, ignoreZeroCurrency: true, ignoreDecimal: true }', () => { + const testFloatsWithCurrencyAndIgnoreZeroCurrencyAndIgnoreDecimals = cloneDeep(testFloatsWithCurrency); + testFloatsWithCurrencyAndIgnoreZeroCurrencyAndIgnoreDecimals[0][1] = ''; + testFloatsWithCurrencyAndIgnoreZeroCurrencyAndIgnoreDecimals.map((row) => { + if (row[0] > 0 && row[0] < 1) { + row[1] = ''; + } + row[1] = (row[1] as string).replace(new RegExp(` Et [\\w\\- ]+ Centimes`), ''); + }); + + test.each(testFloatsWithCurrencyAndIgnoreZeroCurrencyAndIgnoreDecimals)('convert %d => %s', (input, expected) => { + expect( + toWords.convert(input as number, { + currency: true, + ignoreZeroCurrency: true, + ignoreDecimal: true, + }), + ).toBe(expected); + }); +}); diff --git a/dist/ToWords.js b/dist/ToWords.js index 7c8b6c86..5d33d46c 100644 --- a/dist/ToWords.js +++ b/dist/ToWords.js @@ -17,6 +17,7 @@ const gu_IN_1 = __importDefault(require("./locales/gu-IN")); const hi_IN_1 = __importDefault(require("./locales/hi-IN")); const mr_IN_1 = __importDefault(require("./locales/mr-IN")); const tr_TR_1 = __importDefault(require("./locales/tr-TR")); +const lv_LV_1 = __importDefault(require("./locales/lv-LV")); exports.DefaultConverterOptions = { currency: false, ignoreDecimal: false, @@ -62,6 +63,8 @@ class ToWords { return mr_IN_1.default; case 'tr-TR': return tr_TR_1.default; + case 'lv-LV': + return lv_LV_1.default; } /* eslint-enable @typescript-eslint/no-var-requires */ throw new Error(`Unknown Locale "${this.options.localeCode}"`); diff --git a/dist/locales/lv-LV.d.ts b/dist/locales/lv-LV.d.ts new file mode 100644 index 00000000..0727b4f2 --- /dev/null +++ b/dist/locales/lv-LV.d.ts @@ -0,0 +1,4 @@ +import { LocaleConfig, LocaleInterface } from '../types'; +export default class Locale implements LocaleInterface { + config: LocaleConfig; +} diff --git a/dist/locales/lv-LV.js b/dist/locales/lv-LV.js new file mode 100644 index 00000000..8d6bd282 --- /dev/null +++ b/dist/locales/lv-LV.js @@ -0,0 +1,70 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +class Locale { + constructor() { + this.config = { + currency: { + name: 'euro', + plural: 'euro', + symbol: '€', + fractionalUnit: { + name: 'cents', + plural: 'centi', + symbol: '', + }, + }, + texts: { + and: 'un', + minus: 'mīnus', + only: '', + point: 'punkts', + }, + numberWordsMapping: [ + { number: 1000000000000000, value: 'kvadriljoni' }, + { number: 1000000000000, value: 'triljoni' }, + { number: 1000000000, value: 'miljardi' }, + { number: 1000000, value: 'miljoni' }, + { number: 1000, value: 'tūkstoši' }, + { number: 900, value: 'deviņi simti' }, + { number: 800, value: 'astoņi simti' }, + { number: 700, value: 'septiņi simti' }, + { number: 600, value: 'seši simti' }, + { number: 500, value: 'pieci simti' }, + { number: 400, value: 'četri simti' }, + { number: 300, value: 'trīs simti' }, + { number: 200, value: 'divi simti' }, + { number: 100, value: 'simtu' }, + { number: 90, value: 'deviņdesmit' }, + { number: 80, value: 'astoņdesmit' }, + { number: 70, value: 'septiņdesmit' }, + { number: 60, value: 'sešdesmit' }, + { number: 50, value: 'piecdesmit' }, + { number: 40, value: 'četrdesmit' }, + { number: 30, value: 'trīsdesmit' }, + { number: 20, value: 'divdesmit' }, + { number: 19, value: 'deviņpadsmit' }, + { number: 18, value: 'astoņpadsmit' }, + { number: 17, value: 'septiņpadsmit' }, + { number: 16, value: 'sešpadsmit' }, + { number: 15, value: 'piecpadsmit' }, + { number: 14, value: 'četrdpadsmit' }, + { number: 13, value: 'trīspadsmit' }, + { number: 12, value: 'divpadsmit' }, + { number: 11, value: 'vienpadsmit' }, + { number: 10, value: 'desmit' }, + { number: 9, value: 'deviņi' }, + { number: 8, value: 'astoņi' }, + { number: 7, value: 'septiņi' }, + { number: 6, value: 'seši' }, + { number: 5, value: 'pieci' }, + { number: 4, value: 'četri' }, + { number: 3, value: 'trīs' }, + { number: 2, value: 'divi' }, + { number: 1, value: 'viens' }, + { number: 0, value: 'nulle' }, + ], + ignoreOneForWords: ['simti'], + }; + } +} +exports.default = Locale; diff --git a/src/ToWords.ts b/src/ToWords.ts index a25d47e3..604a4adb 100644 --- a/src/ToWords.ts +++ b/src/ToWords.ts @@ -12,6 +12,7 @@ import guIn from './locales/gu-IN'; import hiIn from './locales/hi-IN'; import mrIn from './locales/mr-IN'; import trTr from './locales/tr-TR'; +import lvLv from './locales/lv-LV'; export const DefaultConverterOptions: ConverterOptions = { currency: false, @@ -63,6 +64,8 @@ export class ToWords { return mrIn; case 'tr-TR': return trTr; + case 'lv-LV': + return lvLv; } /* eslint-enable @typescript-eslint/no-var-requires */ throw new Error(`Unknown Locale "${this.options.localeCode}"`); diff --git a/src/locales/lv-LV.ts b/src/locales/lv-LV.ts new file mode 100644 index 00000000..dc66cc70 --- /dev/null +++ b/src/locales/lv-LV.ts @@ -0,0 +1,67 @@ +import { LocaleConfig, LocaleInterface } from '../types'; + +export default class Locale implements LocaleInterface { + public config: LocaleConfig = { + currency: { + name: 'euro', + plural: 'euro', + symbol: '€', + fractionalUnit: { + name: 'cents', + plural: 'centi', + symbol: '', + }, + }, + texts: { + and: 'un', + minus: 'mīnus', + only: '', + point: 'punkts', + }, + numberWordsMapping: [ + { number: 1000000000000000, value: 'kvadriljoni' }, + { number: 1000000000000, value: 'triljoni' }, + { number: 1000000000, value: 'miljardi' }, + { number: 1000000, value: 'miljoni' }, + { number: 1000, value: 'tūkstoši' }, + { number: 900, value: 'deviņi simti' }, + { number: 800, value: 'astoņi simti' }, + { number: 700, value: 'septiņi simti' }, + { number: 600, value: 'seši simti' }, + { number: 500, value: 'pieci simti' }, + { number: 400, value: 'četri simti' }, + { number: 300, value: 'trīs simti' }, + { number: 200, value: 'divi simti' }, + { number: 100, value: 'simtu' }, + { number: 90, value: 'deviņdesmit' }, + { number: 80, value: 'astoņdesmit' }, + { number: 70, value: 'septiņdesmit' }, + { number: 60, value: 'sešdesmit' }, + { number: 50, value: 'piecdesmit' }, + { number: 40, value: 'četrdesmit' }, + { number: 30, value: 'trīsdesmit' }, + { number: 20, value: 'divdesmit' }, + { number: 19, value: 'deviņpadsmit' }, + { number: 18, value: 'astoņpadsmit' }, + { number: 17, value: 'septiņpadsmit' }, + { number: 16, value: 'sešpadsmit' }, + { number: 15, value: 'piecpadsmit' }, + { number: 14, value: 'četrdpadsmit' }, + { number: 13, value: 'trīspadsmit' }, + { number: 12, value: 'divpadsmit' }, + { number: 11, value: 'vienpadsmit' }, + { number: 10, value: 'desmit' }, + { number: 9, value: 'deviņi' }, + { number: 8, value: 'astoņi' }, + { number: 7, value: 'septiņi' }, + { number: 6, value: 'seši' }, + { number: 5, value: 'pieci' }, + { number: 4, value: 'četri' }, + { number: 3, value: 'trīs' }, + { number: 2, value: 'divi' }, + { number: 1, value: 'viens' }, + { number: 0, value: 'nulle' }, + ], + ignoreOneForWords: ['simti'], + }; +} From 1bed03f94b8188a1630ef7494c5e93dd7855dfc9 Mon Sep 17 00:00:00 2001 From: Oskars Pakers Date: Fri, 17 Mar 2023 10:03:07 +0200 Subject: [PATCH 2/2] #735 Latvian language support --- README.md | 2 +- dist/locales/lv-LV.js | 12 +++++++++++- src/locales/lv-LV.ts | 12 +++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 98196b46..1d82a1f2 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ let words = toWords.convert(0.572, { currency: true, ignoreZeroCurrency: true }) | Suriname | Dutch | nl-SR | | Brazil | Portuguese | pt-BR | | Turkey | Turkish | tr-TR | -| Latvia | Latvian | lv-LR | +| Latvia | Latvian | lv-LV | ## Inspiration for core logic diff --git a/dist/locales/lv-LV.js b/dist/locales/lv-LV.js index 8d6bd282..e25efe13 100644 --- a/dist/locales/lv-LV.js +++ b/dist/locales/lv-LV.js @@ -63,7 +63,17 @@ class Locale { { number: 1, value: 'viens' }, { number: 0, value: 'nulle' }, ], - ignoreOneForWords: ['simti'], + ignoreOneForWords: [ + 'simtu', + 'divi simti', + 'trīs simti', + 'četri simti', + 'pieci simti', + 'seši simti', + 'septiņi simti', + 'astoņi simti', + 'deviņi simti', + ], }; } } diff --git a/src/locales/lv-LV.ts b/src/locales/lv-LV.ts index dc66cc70..b2c9ffc7 100644 --- a/src/locales/lv-LV.ts +++ b/src/locales/lv-LV.ts @@ -62,6 +62,16 @@ export default class Locale implements LocaleInterface { { number: 1, value: 'viens' }, { number: 0, value: 'nulle' }, ], - ignoreOneForWords: ['simti'], + ignoreOneForWords: [ + 'simtu', + 'divi simti', + 'trīs simti', + 'četri simti', + 'pieci simti', + 'seši simti', + 'septiņi simti', + 'astoņi simti', + 'deviņi simti', + ], }; }