Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Chinese (Traditional and Simplified) #85

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ lcov
.tern-port
.DS_Store
package-lock.json
.vs*
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ Currently supported languages are:
| Ukrainian | `uk` |
| Indonesian | `id` |
| Russian | `ru` |
| Chinese (Traditional) | `zhTW` |
| Chinese (Simplified) | `zhCN` |


## Contributing
Expand All @@ -83,13 +85,15 @@ The following parameters have been used for the currently available languages:
| Parameter | Type | Description | Examples |
|-----------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `useLongScale` | boolean | Indicates if it uses [long or short scale](http://en.wikipedia.org/wiki/Long_and_short_scales). | This differs the meaning of the words `billion`, `trillion` and so on. |
| `baseSeparator` | string | Separates the base cardinal numbers. | 29 -> twenty`-`eight. Spanish uses the connector " y " |
| `baseSeparator` | string | Separates the base cardinal numbers. | 29 -> twenty`-`eight. Spanish uses the connector " y " |
| `unitSeparator` | string | Separates the units from the last base cardinal numbers. | 1234 -> one thousand two hundred **and** thirty-four |
| `joinSeparator` | string | Separates all words, default is `" "` | 100 -> one hundred. Chinese has no spaces, so it uses the connector `""` |
| `allSeparator` | string | Separates all cardinals, not only the last one. | 1125 -> ألف **و**مائة **و**خمسة **و**عشرون |
| `base` | Object | Base cardinals numbers. Numbers that have unique names and are used to build others. | |
| `alternativeBase` | Object | Alternative versions of base cardinals numbers for usage with specific units. These bases will be treated as an extension for the default `base`. | ``` "alternativeBase": { "feminine": {"1":"одна","2":"дві"} } ``` |
| `units` | Array | A list of number units (string or Object). Gives support to singular, dual an plural units. Check the Object parameters below. | |
| `units` | Array | A list of number units (string or Object). Gives support to singular, dual an plural units. Check the Object parameters below. | |
| `unitExceptions` | Object | Sometimes grammar exceptions affect the base cardinal joined to the unit. You can set specific exceptions to any base cardinal number. | Converting 1232000 in Spanish: Without Exception (Wrong): -> **uno** millón doscientos treinta y dos mil With Exception: -> **un** millón doscientos treinta y dos mil |
| `prependZero` | boolean | If `true`, all contiguous strings of 0s (except leading and trailing) are replaced by one "zero" word before the following number word. | 102003 -> 十萬<u>零</u>二千<u>零</u>三 |

### Units parameters

Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "Convert numbers to words - their written form",
"homepage": "https://yamadapc.github.io/js-written-number",
"main": "./dist/written-number.js",
"version": "0.11.0",
"version": "0.12.0",
"keywords": [
"numbers",
"words",
Expand Down
39 changes: 39 additions & 0 deletions lib/i18n/zh-CN.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"useLongScale": null,
"baseSeparator": "",
"unitSeparator": "",
"joinSeparator": "",
"allSeparator": "",
"prependZero": true,
"base": {
"0": "〇",
"1": "一",
"2": "二",
"3": "三",
"4": "四",
"5": "五",
"6": "六",
"7": "七",
"8": "八",
"9": "九"
},
"units": {
"1": "十",
"2": "百",
"3": "千",
"4": "万",
"8": "亿"
},
"unitExceptions": {
"10": "十",
"11": "十一",
"12": "十二",
"13": "十三",
"14": "十四",
"15": "十五",
"16": "十六",
"17": "十七",
"18": "十八",
"19": "十九"
}
}
40 changes: 40 additions & 0 deletions lib/i18n/zh-TW.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"useLongScale": null,
"baseSeparator": "",
"unitSeparator": "",
"joinSeparator": "",
"allSeparator": "",
"prependZero": true,
"base": {
"0": "零",
"1": "一",
"2": "二",
"3": "三",
"4": "四",
"5": "五",
"6": "六",
"7": "七",
"8": "八",
"9": "九"
},
"units": {
"1": "十",
"2": "百",
"3": "千",
"4": "萬",
"8": "億",
"12": "兆"
},
"unitExceptions": {
"10": "十",
"11": "十一",
"12": "十二",
"13": "十三",
"14": "十四",
"15": "十五",
"16": "十六",
"17": "十七",
"18": "十八",
"19": "十九"
}
}
80 changes: 64 additions & 16 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
exports = module.exports = writtenNumber;
var util = require("./util");

var languages = ["en", "es", "ar", "az", "pt", "fr", "eo", "it", "vi", "tr", "uk", "ru", "id"];
var languages = ["en", "es", "ar", "az", "pt", "fr", "eo", "it", "vi", "tr", "uk", "ru", "id", "zh"];
var i18n = {
en: require("./i18n/en.json"),
es: require("./i18n/es.json"),
Expand All @@ -19,7 +19,9 @@ var i18n = {
enIndian: require("./i18n/en-indian.json"),
uk: require("./i18n/uk.json"),
ru: require("./i18n/ru.json"),
id: require("./i18n/id.json")
id: require("./i18n/id.json"),
zhTW: require("./i18n/zh-TW.json"),
zhCN: require("./i18n/zh-CN.json")
};
exports.i18n = i18n;

Expand All @@ -36,7 +38,8 @@ for (i = 1; i <= 15; i++) {
writtenNumber.defaults = {
noAnd: false,
alternativeBase: null,
lang: "en"
lang: "en",
smallMeans10: false
};

/**
Expand Down Expand Up @@ -68,7 +71,11 @@ function writtenNumber(n, options) {

language = i18n[writtenNumber.defaults.lang];
}


if (!language.hasOwnProperty('joinSeparator')) {
language.joinSeparator = " ";
}

var scale = language.useLongScale ? longScale : shortScale;
var units = language.units;
var unit;
Expand All @@ -86,19 +93,28 @@ function writtenNumber(n, options) {
}

var baseCardinals = language.base;
var alternativeBaseCardinals = options.alternativeBase
var alternativeBaseCardinals = options.alternativeBase
? language.alternativeBase[options.alternativeBase]
: {};
var smallFactor = options.smallMeans10 ? 10 : 100;

if (language.unitExceptions[n]) return language.unitExceptions[n];
if (alternativeBaseCardinals[n]) return alternativeBaseCardinals[n];
if (baseCardinals[n]) return baseCardinals[n];
if (n < 100)
if (n < smallFactor)
return handleSmallerThan100(n, language, unit, baseCardinals, alternativeBaseCardinals, options);

var m = n % 100;
setSmallMeans10(options, baseCardinals, alternativeBaseCardinals);
smallFactor = options.smallMeans10 ? 10 : 100;

var m = n % smallFactor;
var ret = [];

if (language.prependZero) {
var _n = n, _n10 = Math.pow(10, Math.floor(Math.log10(_n)));
var zero = writtenNumber(0, options);
}

if (m) {
if (
options.noAnd &&
Expand All @@ -108,6 +124,9 @@ function writtenNumber(n, options) {
} else {
ret.push(language.unitSeparator + writtenNumber(m, options));
}
if (language.prependZero && Math.floor(n / 10) % smallFactor == 0) {
ret[0] = zero + ret[0];
}
}

var firstSignificant;
Expand All @@ -125,6 +144,19 @@ function writtenNumber(n, options) {

if (!r) continue;
firstSignificant = scale[i];
var prependedZero = "";
if (
language.prependZero
&& i < len - 1
&& scale[i] < _n10
) {
var nextSpaceFloor = Math.floor(_n / scale[i] / (divideBy / 10));
var nextUnitFloor = Math.floor(_n / scale[i + 1]);
if (
(nextSpaceFloor && nextSpaceFloor % 10 == 0)
|| (nextUnitFloor && nextUnitFloor % 10 == 0)
) prependedZero = zero;
}

if (unit.useBaseInstead) {
var shouldUseBaseException =
Expand Down Expand Up @@ -153,10 +185,10 @@ function writtenNumber(n, options) {
str = unit.plural && (!unit.avoidInNumberPlural || !m)
? unit.plural
: unit.singular;

// Languages with dual
str = (r === 2 && unit.dual) ? unit.dual : str;

// "restrictedPlural" : use plural only for 3 to 10
str = (r > 10 && unit.restrictedPlural) ? unit.singular : str;
}
Expand Down Expand Up @@ -185,7 +217,7 @@ function writtenNumber(n, options) {
)
);
n -= r * scale[i];
ret.push(number + " " + str);
ret.push(prependedZero + number + language.joinSeparator + str);
}

var firstSignificantN = firstSignificant * Math.floor(n / firstSignificant);
Expand All @@ -201,24 +233,40 @@ function writtenNumber(n, options) {
ret.slice(1)
);
}

// Languages that have separators for all cardinals.
if (language.allSeparator) {
for (var j = 0; j < ret.length-1; j++) {
ret[j] = language.allSeparator + ret[j];
for (var j = 0; j < ret.length - 1; j++) {
ret[j] = language.allSeparator + ret[j];
}
}
var result = ret.reverse().join(" ");
var result = ret.reverse().join(language.joinSeparator);
return result;
}

function handleSmallerThan100(n, language, unit, baseCardinals, alternativeBaseCardinals, options) {
var smallMeans10 = options.smallMeans10;
setSmallMeans10(options, baseCardinals, alternativeBaseCardinals);
var dec = Math.floor(n / 10) * 10;
unit = n - dec;
var decCardinal = alternativeBaseCardinals[dec] || baseCardinals[dec];
if (smallMeans10) {
decCardinal = '';
} else if (!decCardinal) {
decCardinal = writtenNumber(dec, options);
}
if (unit) {
return (
alternativeBaseCardinals[dec] || baseCardinals[dec] + language.baseSeparator + writtenNumber(unit, options)
decCardinal + language.baseSeparator + writtenNumber(unit, options)
);
}
return alternativeBaseCardinals[dec] || baseCardinals[dec];
return decCardinal;
}

function setSmallMeans10(options, baseCardinals, alternativeBaseCardinals) {
if (options.smallMeans10) return;
var f = function (i) {return parseInt(i);};
var keys = Object.keys(baseCardinals).map(f);
keys = keys.concat(Object.keys(alternativeBaseCardinals).map(f));
options.smallMeans10 = Math.max.apply(null, keys) < 10;
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "written-number",
"version": "0.11.0",
"version": "0.12.0",
"description": "Convert numbers to words - their written form.",
"main": "lib/index.js",
"scripts": {
Expand Down
Loading