diff --git a/README-english.md b/README-english.md
index 1e674b0..6706b5c 100644
--- a/README-english.md
+++ b/README-english.md
@@ -159,22 +159,23 @@ Currency of number.
| `'eur'` | Euro | 124 **евро** 42 **цента** |
| `'number'` | Number without currency | 124 **целых** 42 **сотых** |
-
+**Note**: For all common currencies except `number` set `fractionalPartMinLength: 2`. Also these currencies will be rounded to `2`.
- Own currency:
```js
{
- currencyNameCases: ['рубль', 'рубля', 'рублей'], // Integer currency names
- fractionalPartNameCases: ['копейка', 'копейки', 'копеек'], // Fractional number currency names
+ currencyNameCases: ['рубль', 'рубля', 'рублей'], // [1 рубль, 2-4 рубля, 5-9 рублей]
+ fractionalPartNameCases: ['копейка', 'копейки', 'копеек'],
currencyNounGender: {
integer: 0, // 0 => ('один', 'два'...)
fractionalPart: 1 // 1 => ('одна', 'две'...)
}
+ fractionalPartMinLength: 2
}
// or
{
- currencyNameCases: ['сообщение', 'сообщения', 'сообщений'], // [1 сообщение, 2-4 сообщения, 5-9 сообщений]
+ currencyNameCases: ['сообщение', 'сообщения', 'сообщений'],
fractionalPartNameCases: ['', '', ''],
currencyNounGender: {
integer: 2, // 2 => ('одно', 'два'...)
@@ -185,6 +186,22 @@ Currency of number.
**Note**: If currency object will not be filled completely then missing data will be taken from default currency (`'rub'`).
+#### Parameters of object `currency`
+
+`currencyNameCases: (Array)`: Currency form name of integer part. 3 elements in array.
+
+`fractionalPartNameCases: (Array)`: Currency form name of fractional part. 3 elements in array.
+
+`currencyNounGender: (Object)`: Form of number: 0 - ("один"), 1 - ("одна"), 2 - ("одно").
+
+- `integer` - For integer part.
+
+- `fractionalPart` - For fractional part.
+
+`fractionalPartMinLength: (number)`: Minimal length of fractional part. For example if set `3` then in fractional part mey be number `002`.
+
+**Note**: In arrays `currencyNameCases` and `fractionalPartNameCases`: first element for digit 1 (1 `рубль`), second elemet for digits 2-4 (2 `рубля`), third element for digits 5-9 and 0 (5 `рублей`).
+
```
@@ -203,25 +220,25 @@ Round number to specified precision.
- `-1` - Disable rounding.
-**Note**: If option `currency` is a common currency (`rub` / `usd` / `eur`) then after rounding it will be rounded again to 2 digits. Also in this case the result always will have 2 digits in fractional part (for example "00", "05").
+**Note**: If option `currency` is a common currency (`rub` / `usd` / `eur`) then after rounding it will be rounded again to 2 digits.
#### Example
```js
numberToWordsRu.convert('129.6789', {
- currency: 'eur',
+ currency: 'rub',
roundNumber: 5,
});
// Сто двадцать девять рублей 68 копеек
numberToWordsRu.convert('129.6789', {
- currency: 'eur',
+ currency: 'rub',
roundNumber: 1,
});
// Сто двадцать девять рублей 70 копеек
numberToWordsRu.convert('129.6789', {
- currency: 'eur',
+ currency: 'rub',
roundNumber: 0,
});
// Сто тридцать рублей 00 копеек
diff --git a/README.md b/README.md
index e7d4d89..26e4540 100644
--- a/README.md
+++ b/README.md
@@ -159,22 +159,23 @@ currency: (string|Object)
| `'eur'` | Евро | 124 **евро** 42 **цента** |
| `'number'` | Число без реальной валюты | 124 **целых** 42 **сотых** |
-
+**Примечание**: Для всех стандартных валют, кроме `number` установлено `fractionalPartMinLength: 2`. Также эти валюты автоматически округляются до `2` знаков после запятой.
- Своя валюта:
```js
{
- currencyNameCases: ['рубль', 'рубля', 'рублей'], // Падежи названия целой части числа
- fractionalPartNameCases: ['копейка', 'копейки', 'копеек'], // Падежи названия дробной части числа
+ currencyNameCases: ['рубль', 'рубля', 'рублей'], // [1 рубль, 2-4 рубля, 5-9 рублей]
+ fractionalPartNameCases: ['копейка', 'копейки', 'копеек'],
currencyNounGender: {
integer: 0, // 0 => Мужской род ('один', 'два'...)
fractionalPart: 1 // 1 => Женский род ('одна', 'две'...)
- }
+ },
+ fractionalPartMinLength: 2
}
// или
{
- currencyNameCases: ['сообщение', 'сообщения', 'сообщений'], // [1 сообщение, 2-4 сообщения, 5-9 сообщений]
+ currencyNameCases: ['сообщение', 'сообщения', 'сообщений'],
fractionalPartNameCases: ['', '', ''],
currencyNounGender: {
integer: 2, // 2 => Средний род ('одно', 'два'...)
@@ -183,7 +184,23 @@ currency: (string|Object)
}
```
-**Примечание**: Если объект валюты заполнить не полностью, то недостающие данные будут взяты из объекта валюты по умолчанию (`'rub'`).
+**Примечание**: Если объект валюты заполнить не полностью, то недостающие параметры будут взяты из объекта валюты по умолчанию (`'rub'`).
+
+#### Параметры объекта `currency`
+
+`currencyNameCases: (Array)`: Формы названия валюты целой части числа. 3 элемента в массиве.
+
+`fractionalPartNameCases: (Array)`: Формы названия валюты дробной части числа. 3 элемента в массиве.
+
+`currencyNounGender: (Object)`: Род числа: 0 - мужской род (один), 1 - женский род (одна), 2 - средний род (одно).
+
+- `integer` - Для целой части числа.
+
+- `fractionalPart` - Для дробной части числа.
+
+`fractionalPartMinLength: (number)`: Минимальное количество знаков, котрое может остаться в дробной части. Например, при значении `3` в дробной части возможно число `002`.
+
+**Примечание**: В массивах `currencyNameCases` и `fractionalPartNameCases`: первый элемент для цифры 1 (1 `рубль`), второй элемент для цифр 2-4 (2 `рубля`), третий элемент для цифр 5-9 и 0 (5 `рублей`).
@@ -203,25 +220,25 @@ roundNumber: (number)
- `-1` - Отключить округление.
-**Примечание**: Если опция `currency` является стандартной валютой (`'rub'` / `'usd'` / `'eur'`), то даже после округления число будет еще раз округлено до 2 знаков после запятой. Также в этом случае у результата в дробной части всегда будет 2 знака (например "00", "05").
+**Примечание**: Если опция `currency` является стандартной валютой (`'rub'` / `'usd'` / `'eur'`), то даже после округления число будет еще раз округлено до 2 знаков после запятой.
#### Пример
```js
numberToWordsRu.convert('129.6789', {
- currency: 'eur',
+ currency: 'rub',
roundNumber: 5,
});
// Сто двадцать девять рублей 68 копеек
numberToWordsRu.convert('129.6789', {
- currency: 'eur',
+ currency: 'rub',
roundNumber: 1,
});
// Сто двадцать девять рублей 70 копеек
numberToWordsRu.convert('129.6789', {
- currency: 'eur',
+ currency: 'rub',
roundNumber: 0,
});
// Сто тридцать рублей 00 копеек
diff --git a/package.json b/package.json
index 1db92bb..e60573e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "number-to-words-ru",
- "version": "2.1.2",
+ "version": "2.2.0",
"description": "Convert a number to words on russian language.",
"license": "MIT",
"repository": "Ant1mas/number-to-words-ru",
diff --git a/src/combineResultData.js b/src/combineResultData.js
index 22041d1..b36ba66 100644
--- a/src/combineResultData.js
+++ b/src/combineResultData.js
@@ -1,6 +1,7 @@
import textValues from 'textValues';
import getOptions from 'getOptions';
import roundNumber from 'roundNumber';
+import fractionalPartToMinLength from 'fractionalPartToMinLength';
import getCurrencyObject from 'getCurrencyObject';
import numberToScales from 'numberToScales';
import convertsEachScaleToWords from 'convertsEachScaleToWords';
@@ -30,28 +31,18 @@ const combineResultData = (numberArray, options) => {
convertedNumberArr[0] = '-';
}
}
- // Если разделитель - не дробная черта
- if (numberArray[2] !== '/') {
- // Округлить число до заданной точности
- modifiedNumberArray = roundNumber(numberArray, useOptions.roundNumber);
- }
+ // Округлить число до заданной точности
+ modifiedNumberArray = roundNumber(numberArray, useOptions.roundNumber);
// Если указана валюта
if (
typeof useOptions.currency === 'string' &&
useOptions.currency !== 'number'
) {
- // Если разделитель - не дробная черта
- if (numberArray[2] !== '/') {
- // Округлить число до 2 знаков после запятой
- modifiedNumberArray = roundNumber(modifiedNumberArray, 2);
- // Если в дробной части < 2 цифр
- if (modifiedNumberArray[3].length < 2) {
- // Заполнить нулями
- modifiedNumberArray[3] = modifiedNumberArray[3] + '0'
- .repeat(2 - modifiedNumberArray[3].length);
- }
- }
+ // Округлить число до 2 знаков после запятой
+ modifiedNumberArray = roundNumber(modifiedNumberArray, 2);
}
+ // Обеспечить минимальную длину дробной части числа
+ modifiedNumberArray = fractionalPartToMinLength(modifiedNumberArray, currencyObject);
// Если нужно отображать целую часть числа
if (useOptions.showNumberParts.integer === true) {
convertedNumberArr[1] = modifiedNumberArray[1];
@@ -105,7 +96,7 @@ const combineResultData = (numberArray, options) => {
).result;
}
} else {
- // Если не нужно конвертировать в слова
+ // Если не нужно конвертировать число в слова
// Если валюта "number"
if (useOptions.currency === 'number') {
// Если в дробной части есть цифры
diff --git a/src/fractionalPartToMinLength.js b/src/fractionalPartToMinLength.js
new file mode 100644
index 0000000..405c0c3
--- /dev/null
+++ b/src/fractionalPartToMinLength.js
@@ -0,0 +1,23 @@
+/**
+ * Сделать так, чтобы у дробной части числа
+ * минимальная длина соответствовала currencyObject.fractionalPartMinLength
+ * @param {Array} numberArray - Число в виде массива ['-', '150', '/', '25'].
+ * @param {Object} currencyObject - Объект с параметрами валюты.
+ * @return {Array} Обновленный массив числа.
+ */
+const fractionalPartToMinLength = (numberArray, currencyObject) => {
+ // Если разделитель - дробная черта
+ if (numberArray[2] === '/') {
+ return numberArray;
+ }
+ const updatedNumberArray = [...numberArray];
+ // Если в дробной части цифр меньше, чем fractionalPartMinLength
+ if (updatedNumberArray[3].length < currencyObject.fractionalPartMinLength) {
+ // Заполнить нулями
+ updatedNumberArray[3] = updatedNumberArray[3] + '0'
+ .repeat(currencyObject.fractionalPartMinLength - updatedNumberArray[3].length);
+ }
+ return updatedNumberArray;
+};
+
+export default fractionalPartToMinLength;
diff --git a/src/getCurrencyObject.js b/src/getCurrencyObject.js
index 1075dcd..c048dd2 100644
--- a/src/getCurrencyObject.js
+++ b/src/getCurrencyObject.js
@@ -1,6 +1,5 @@
import textValues from 'textValues';
import defaultOptions from 'defaultOptions';
-import stringCurrencies from 'stringCurrencies';
import updateObjectDeep from 'updateObjectDeep';
/**
@@ -10,22 +9,17 @@ import updateObjectDeep from 'updateObjectDeep';
*/
const getCurrencyObject = (convertOptions) => {
let currencyObject;
- // Если отображение без валюты
- if (convertOptions.currency === 'number') {
- currencyObject = {
- currencyNameCases: ['целая', 'целых', 'целых'],
- getFractionalPartNameCases: textValues.getFractionalUnits,
- currencyNounGender: {
- integer: 1,
- fractionalPart: 1,
- },
- };
// Если валюта указана словами
- } else if (typeof convertOptions.currency === 'string') {
+ if (typeof convertOptions.currency === 'string') {
// Если такая валюта есть в списке
if (textValues.currency[convertOptions.currency] !== undefined) {
// Получить данные найденной валюты
currencyObject = textValues.currency[convertOptions.currency];
+ // Если валюта указана как "number"
+ if (convertOptions.currency === 'number') {
+ // Добавить функцию для заполнения fractionalPartNameCases
+ currencyObject.getFractionalPartNameCases = textValues.getFractionalUnits;
+ }
} else {
throw new Error(
'Wrong currency name [' + convertOptions.currency + ']. '
@@ -35,13 +29,13 @@ const getCurrencyObject = (convertOptions) => {
// Если валюта описана объектом
} else if (typeof convertOptions.currency === 'object') {
// Объект валюты по умолчанию
- const defaultCurrencyObject = stringCurrencies[defaultOptions['currency']];
+ const defaultCurrencyObject = textValues.currency[defaultOptions['currency']];
// Обновить объект валюты новым объектом валюты
const updatedCurrencyObject = updateObjectDeep(defaultCurrencyObject, convertOptions.currency);
// Если объект оформлен правильно
if (
typeof updatedCurrencyObject === 'object' &&
- Object.keys(updatedCurrencyObject).length === 3 &&
+ Object.keys(updatedCurrencyObject).length === 4 &&
updatedCurrencyObject.currencyNameCases.length === 3 &&
updatedCurrencyObject.fractionalPartNameCases.length === 3 &&
typeof updatedCurrencyObject.currencyNounGender === 'object' &&
diff --git a/src/methods/convert.js b/src/methods/convert.js
index 91c0cbd..fb49119 100644
--- a/src/methods/convert.js
+++ b/src/methods/convert.js
@@ -9,7 +9,7 @@ import combineResultData from 'combineResultData';
*/
const convert = (number, options = {}) => {
// Обработать введенное число
- const numberArray = splitNumberToArray(number);
+ const numberArray = splitNumberToArray(number, options);
// Собрать конечный словестный результат
const convertedNumberString = combineResultData(numberArray, options);
return convertedNumberString;
diff --git a/src/roundNumber.js b/src/roundNumber.js
index fc58837..620744f 100644
--- a/src/roundNumber.js
+++ b/src/roundNumber.js
@@ -11,6 +11,10 @@ const roundNumber = (numberArray, precision = 2) => {
if (precision < 0) {
return numberArray;
}
+ // Если разделитель - дробная черта то не округлять
+ if (numberArray[2] === '/') {
+ return numberArray;
+ }
// Если количество знаков после запятой <= precision, то не округлять
if (numberArray[3].length <= precision) {
return numberArray;
diff --git a/src/splitNumberToArray.js b/src/splitNumberToArray.js
index 63725e2..a705589 100644
--- a/src/splitNumberToArray.js
+++ b/src/splitNumberToArray.js
@@ -1,9 +1,10 @@
/**
* Разделить число на части.
* @param {(number|string)} number - Число, которое нужно обработать.
+ * @param {Object} options - Параметры конвертирования.
* @return {Array} Обработанное число в виде ['-', '150', '/', '25'].
*/
-const splitNumberToArray = (number) => {
+const splitNumberToArray = (number, options) => {
// Максимальная длинна целой части числа
const maxIntegerPartLength = 306;
// Конвертировать в String
@@ -33,8 +34,11 @@ const splitNumberToArray = (number) => {
numberArray[3] = numberArray[3] === undefined ? '' : numberArray[3];
// Убрать лишние нули из целой части
numberArray[1] = numberArray[1].replace(/^0+/, '');
- // Если разделитель не дробная черта
- if (numberArray[2] !== '/') {
+ // Если разделитель не дробная черта и валюта не 'number'
+ if (
+ numberArray[2] !== '/'
+ && options.currency !== 'number'
+ ) {
// Убрать лишние нули из дробной части
numberArray[3] = numberArray[3]
.split('')
diff --git a/src/stringCurrencies.js b/src/stringCurrencies.js
index d9a1142..1dda9d6 100644
--- a/src/stringCurrencies.js
+++ b/src/stringCurrencies.js
@@ -1,5 +1,17 @@
+const defaultParams = {
+ fractionalPartMinLength: 2,
+};
+
const stringCurrencies = {
+ number: {
+ currencyNameCases: ['целая', 'целых', 'целых'],
+ currencyNounGender: {
+ integer: 1,
+ fractionalPart: 1,
+ },
+ },
rub: {
+ ...defaultParams,
currencyNameCases: ['рубль', 'рубля', 'рублей'],
fractionalPartNameCases: ['копейка', 'копейки', 'копеек'],
currencyNounGender: {
@@ -8,6 +20,7 @@ const stringCurrencies = {
},
},
usd: {
+ ...defaultParams,
currencyNameCases: ['доллар', 'доллара', 'долларов'],
fractionalPartNameCases: ['цент', 'цента', 'центов'],
currencyNounGender: {
@@ -16,6 +29,7 @@ const stringCurrencies = {
},
},
eur: {
+ ...defaultParams,
currencyNameCases: ['евро', 'евро', 'евро'],
fractionalPartNameCases: ['цент', 'цента', 'центов'],
currencyNounGender: {
diff --git a/test/index.test.js b/test/index.test.js
index 9c2a86d..5805d5b 100644
--- a/test/index.test.js
+++ b/test/index.test.js
@@ -374,6 +374,9 @@ describe('Options', () => {
expect(numberToWordsRu.convert('1234567.12345', {
currency: 'number',
})).toBe('Один миллион двести тридцать четыре тысячи пятьсот шестьдесят семь целых 12345 стотысячных');
+ expect(numberToWordsRu.convert('1.8000', {
+ currency: 'number',
+ })).toBe('Одна целая 8000 десятитысячных');
});
test("'number' words", () => {
expect(numberToWordsRu.convert('1234567.12345', {
@@ -382,6 +385,12 @@ describe('Options', () => {
fractional: true,
},
})).toBe('Один миллион двести тридцать четыре тысячи пятьсот шестьдесят семь целых двенадцать тысяч триста сорок пять стотысячных');
+ expect(numberToWordsRu.convert('1.8000', {
+ currency: 'number',
+ convertNumbertToWords: {
+ fractional: true,
+ },
+ })).toBe('Одна целая восемь тысяч десятитысячных');
});
});
describe('object values', () => {
@@ -402,12 +411,44 @@ describe('Options', () => {
currencyNameCases: ['доллар', 'доллара', 'долларов'],
fractionalPartNameCases: ['цент', 'цента', 'центов'],
currencyNounGender: {
- integer: 0, // Мужской род
- fractionalPart: 1, // Женский род
+ integer: 0,
+ fractionalPart: 1,
},
},
roundNumber: 2,
})).toBe('Один миллион двести тридцать четыре тысячи пятьсот шестьдесят семь долларов 12 центов');
+ expect(numberToWordsRu.convert('1.6789', {
+ currency: {
+ currencyNameCases: ['доллар', 'доллара', 'долларов'],
+ fractionalPartNameCases: ['цент', 'цента', 'центов'],
+ fractionalPartMinLength: 2,
+ },
+ roundNumber: 1,
+ })).toBe('Один доллар 70 центов');
+ expect(numberToWordsRu.convert('1.6789', {
+ currency: {
+ currencyNameCases: ['доллар', 'доллара', 'долларов'],
+ fractionalPartNameCases: ['цент', 'цента', 'центов'],
+ fractionalPartMinLength: 2,
+ },
+ roundNumber: 0,
+ })).toBe('Два доллара 00 центов');
+ expect(numberToWordsRu.convert('1.6789', {
+ currency: {
+ currencyNameCases: ['доллар', 'доллара', 'долларов'],
+ fractionalPartNameCases: ['цент', 'цента', 'центов'],
+ fractionalPartMinLength: 1,
+ },
+ roundNumber: 0,
+ })).toBe('Два доллара 0 центов');
+ expect(numberToWordsRu.convert('1.6789', {
+ currency: {
+ currencyNameCases: ['доллар', 'доллара', 'долларов'],
+ fractionalPartNameCases: ['цент', 'цента', 'центов'],
+ fractionalPartMinLength: 0,
+ },
+ roundNumber: 0,
+ })).toBe('Два доллара');
});
test('not full objects', () => {
expect(numberToWordsRu.convert('1234561.12345', {
@@ -589,7 +630,7 @@ describe('Options', () => {
},
},
roundNumber: 0,
- })).toBe('Одна тысяча двести тридцать пять рублей');
+ })).toBe('Одна тысяча двести тридцать пять рублей 00 копеек');
expect(numberToWordsRu.convert('1234.6789', {
currency: {
currencyNameCases: ['рубль', 'рубля', 'рублей'],