Skip to content

Commit

Permalink
Merge branch 'release/v1.3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
lisez committed Jun 22, 2019
2 parents 4116019 + 1318399 commit 39246e5
Show file tree
Hide file tree
Showing 15 changed files with 270 additions and 94 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ A library for converting from Arabic numbers to Chinese numbers. For example, `8
- Support customized prefix/suffix.
- Support customized output style of signed symbols.
- Support `Nubmer` and `BigInt`.
- Support `Traditional` and `Simplified` Chinese.

## Installation

Expand Down Expand Up @@ -67,6 +68,11 @@ assert.equal(test8, '海拔負壹佰貳拾參');
// Able to customize the output of signed symbols, default: 正 for plus, 負 for minus
const test9 = converter('-123', { signedOutput: { minusSigned: '下降' } });
assert.equal(test9, '下降壹佰貳拾參');

// Support Simplified/Traditional Chinese, default: `zh-tw`
const test10 = converter('-123', { lang: 'zh-cn' });
assert.equal(test10, '负壹佰贰十参');

```

### `Important`: BigInt and Number
Expand Down Expand Up @@ -94,9 +100,10 @@ The default configuration options would be:

```javascript
{ caseType: 'upper', // `upper` | `lower`
lang: 'zh-tw', // 'zh-tw' | 'zh-cn'
showPlusSigned: false,
showMinusSigned: true,
signedOutput: { plusSigned: '', minusSigned: '' },
signedOutput: { },
prefix: '',
suffix: '',
prefixPosition: 'after-signed' // `after-signed` | `before-signed`
Expand All @@ -105,9 +112,10 @@ The default configuration options would be:

## Todo & Roadmap

- [ ] Support Simple Chinese. (ex. `億/亿`)
- [x] Support Simple Chinese. (ex. `億/亿`)
- [x] Support Positive numbers (integer).
- [x] Support Negative numbers (integer).
- [ ] Support Floating numbers. (ex. `3.14` to `三點一四`)
- [ ] Support Fraction numbers. (ex. `4/5` to `五分之四`)
- [ ] Support Mixing numbers. (ex. `4,500萬` to `四千五百萬`)
- [ ] Support Metric unit rule.
4 changes: 4 additions & 0 deletions demo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ assert.equal(test8, '海拔負壹佰貳拾參');
// Able to customize the output of signed symbols, default: 正 for plus, 負 for minus
const test9 = converter('-123', { signedOutput: { minusSigned: '下降' } });
assert.equal(test9, '下降壹佰貳拾參');

// Support Simplified/Traditional Chinese, default: `zh-tw`
const test10 = converter('-123', { lang: 'zh-cn' });
assert.equal(test10, '负壹佰贰十参');
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lib-arabic-chinese",
"version": "1.2.0",
"version": "1.3.0",
"description": "A library for converting from Arabic numbers to Chinese numbers",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
110 changes: 35 additions & 75 deletions src/Digit.ts
Original file line number Diff line number Diff line change
@@ -1,83 +1,26 @@
export type TSymbol<T> = [T, T, T, T, T, T, T, T, T, T];
import DigitLang, { TDigitMapping } from './lang/Digit';
import { IConverterConfig } from './index';

export type TUnit = '1' | '2' | '3';

export type TLargeUnit = '4' | '8' | '12' | '16' | '20' | '24' | '28' | '32' | '36' | '40' | '44';

export type TUnitMapping = { [unit in TUnit]: string };

export type TLargeUnitMapping = { [unit in TLargeUnit]: string };

export type TConfig = {
export type TDigitConfig = {
readonly caseType: 'lower' | 'upper';
readonly placeUnit: number;
readonly lang: IConverterConfig['lang'];
};

export const upperCaseMapping: TSymbol<string> = [
'零',
'壹',
'貳',
'參',
'肆',
'伍',
'陸',
'柒',
'捌',
'玖'
];

export const lowerCaseMapping: TSymbol<string> = [
'零',
'一',
'二',
'三',
'四',
'五',
'六',
'七',
'八',
'九'
];

export const upperCaseUnitMapping: TUnitMapping = {
'1': '拾',
'2': '佰',
'3': '仟'
};

export const lowerCaseUnitMapping: TUnitMapping = {
'1': '十',
'2': '百',
'3': '千'
};

export const largeUnitMapping: TLargeUnitMapping = {
'4': '萬',
'8': '億',
'12': '兆',
'16': '京',
'20': '垓',
'24': '秭',
'28': '穰',
'32': '溝',
'36': '澗',
'40': '正',
'44': '載'
};

export const defaultConfig: TConfig = {
export const defaultConfig: TDigitConfig = {
caseType: 'upper',
placeUnit: -1
placeUnit: -1,
lang: 'zh-tw'
};

export default class Digit extends String {
config: TConfig;
config: TDigitConfig;

prev: Digit;
next: Digit;

// @ts-ignore
constructor(digit: number | string, config: Partial<TConfig> = {}) {
constructor(digit: number | string, config: Partial<TDigitConfig> = {}) {
// @ts-ignore
this = new String(digit);
// @ts-ignore
Expand All @@ -94,8 +37,8 @@ export default class Digit extends String {
}
}

public setup(config: Partial<TConfig>): this {
this.config = { ...defaultConfig, ...this.config, ...config };
public setup(config: Partial<TDigitConfig>): this {
this.config = { ...defaultConfig, ...config };
return this;
}

Expand Down Expand Up @@ -163,11 +106,26 @@ export default class Digit extends String {
return true;
}

private get mapping(): { symbol: TSymbol<string>; unit: TUnitMapping } {
const symbol = this.config.caseType === 'lower' ? lowerCaseMapping : upperCaseMapping;
const unit = this.config.caseType === 'lower' ? lowerCaseUnitMapping : upperCaseUnitMapping;
private get mapping(): {
symbol: TDigitMapping['lowerCaseMapping'] | TDigitMapping['upperCaseMapping'];
unit: TDigitMapping['lowerCaseUnitMapping'] | TDigitMapping['upperCaseUnitMapping'];
largeUnit: TDigitMapping['largeUnitMapping'];
} {
const { lang } = this.config;
const digitMapping = DigitLang[lang];

const symbol =
this.config.caseType === 'lower'
? digitMapping.lowerCaseMapping
: digitMapping.upperCaseMapping;
const unit =
this.config.caseType === 'lower'
? digitMapping.lowerCaseUnitMapping
: digitMapping.upperCaseUnitMapping;

const largeUnit = digitMapping.largeUnitMapping;

return { symbol, unit };
return { symbol, unit, largeUnit };
}

private get unitType(): number {
Expand All @@ -185,12 +143,14 @@ export default class Digit extends String {
}

if (this.unitType <= 3) {
const index = String(this.unitType) as TUnit;
const index = String(this.unitType) as keyof (
| TDigitMapping['lowerCaseUnitMapping']
| TDigitMapping['upperCaseUnitMapping']);
return this.mapping.unit[index];
}

const index = String(this.unitType) as TLargeUnit;
return largeUnitMapping[index];
const index = String(this.unitType) as keyof TDigitMapping['largeUnitMapping'];
return this.mapping.largeUnit[index];
}

public get value(): string {
Expand Down
19 changes: 8 additions & 11 deletions src/Signed.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
export type TSigned = 'plusSigned' | 'minusSigned';

export type TSignedMapping = { [signed in TSigned]: string };
import SignedLang, { TSignedMapping } from './lang/Signed';
import { IConverterConfig } from './index';

export type TSignedConfig = {
readonly signedOutput: TSignedMapping;
readonly signedOutput: Partial<TSignedMapping>;
readonly showPlusSigned: boolean;
readonly showMinusSigned: boolean;
};

export const signedMapping: TSignedMapping = {
plusSigned: '正',
minusSigned: '負'
readonly lang: IConverterConfig['lang'];
};

export const defaultSignedConfig: TSignedConfig = {
showPlusSigned: false,
showMinusSigned: true,
signedOutput: signedMapping
signedOutput: {},
lang: 'zh-tw'
};

export default class Signed extends String {
Expand Down Expand Up @@ -55,7 +51,7 @@ export default class Signed extends String {
}

private get mapping(): { symbol: TSignedMapping } {
const symbol = this.config.signedOutput;
let symbol = <TSignedMapping>this.config.signedOutput;
return { symbol };
}

Expand Down Expand Up @@ -90,6 +86,7 @@ export default class Signed extends String {
...(config || {}),
signedOutput: {
...defaultSignedConfig.signedOutput,
...((config || {}).lang ? SignedLang[config.lang!] : {}),
...((config || {}).signedOutput || {})
}
};
Expand Down
17 changes: 12 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import Signed, { TSignedConfig, defaultSignedConfig } from './Signed';
import Digit, { TConfig, defaultConfig } from './Digit';
import Digit, { TDigitConfig, defaultConfig } from './Digit';
import { TLangCode, Langs } from './lang';

type prefixPosition = 'before-signed' | 'after-signed';

export interface IConverterConfig
extends Pick<TConfig, Exclude<keyof TConfig, 'placeUnit'>>,
extends Pick<TDigitConfig, Exclude<keyof TDigitConfig, 'placeUnit' | 'lang'>>,
TSignedConfig {
readonly prefix: string;
readonly suffix: string;
readonly prefixPosition: prefixPosition;
readonly lang: TLangCode;
}

const defaultConverterConfig: IConverterConfig = {
...defaultConfig,
...defaultSignedConfig,
prefix: '',
suffix: '',
prefixPosition: 'after-signed'
prefixPosition: 'after-signed',
lang: 'zh-tw'
};

function objectize(numbers: string[], config: RecursivePartial<IConverterConfig> = {}): Digit[] {
function objectize(numbers: string[], config: IConverterConfig): Digit[] {
const digits: Digit[] = [];
numbers.forEach((n, i) => {
const digit = new Digit(n, { ...config, placeUnit: i });
Expand All @@ -38,7 +41,7 @@ function isValidNumberText(nText: string): boolean {

export default function main(
text: string | number | bigint,
userConfig: RecursivePartial<IConverterConfig> = defaultConverterConfig
userConfig: Partial<IConverterConfig> = defaultConverterConfig
): string {
if (typeof text === 'number' || typeof text === 'bigint') {
return main(text.toString(), userConfig);
Expand All @@ -51,6 +54,10 @@ export default function main(
throw new Error('invalid number or number has exponent symbol after it has been converted. ');
}

if (!Langs.includes(config.lang)) {
throw new Error('invalid lang code');
}

const hasSigned = Signed.hasSigned(toNormal);

let signed: string = '';
Expand Down
31 changes: 31 additions & 0 deletions src/lang/Digit/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { TLangCode } from '../index';

import zhTW from './zh-tw';
import zhCN from './zh-cn';

export type TSymbol<T> = [T, T, T, T, T, T, T, T, T, T];

export type TUnit = '1' | '2' | '3';

export type TLargeUnit = '4' | '8' | '12' | '16' | '20' | '24' | '28' | '32' | '36' | '40' | '44';

export type TUnitMapping = { [unit in TUnit]: string };

export type TLargeUnitMapping = { [unit in TLargeUnit]: string };

export type TDigitMapping = {
readonly upperCaseMapping: TSymbol<string>;
readonly lowerCaseMapping: TSymbol<string>;
readonly upperCaseUnitMapping: TUnitMapping;
readonly lowerCaseUnitMapping: TUnitMapping;
readonly largeUnitMapping: TLargeUnitMapping;
};

export type TDigitLang = { [langCode in TLangCode]: TDigitMapping };

const langs: TDigitLang = {
'zh-tw': zhTW,
'zh-cn': zhCN
};

export default langs;
35 changes: 35 additions & 0 deletions src/lang/Digit/zh-cn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { TDigitMapping } from './index';

const mapping: TDigitMapping = {
upperCaseMapping: ['零', '壹', '贰', '参', '肆', '伍', '陆', '柒', '捌', '玖'],

lowerCaseMapping: ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'],

upperCaseUnitMapping: {
'1': '十',
'2': '佰',
'3': '仟'
},

lowerCaseUnitMapping: {
'1': '十',
'2': '百',
'3': '千'
},

largeUnitMapping: {
'4': '万',
'8': '亿',
'12': '兆',
'16': '京',
'20': '垓',
'24': '秭',
'28': '穰',
'32': '沟',
'36': '涧',
'40': '正',
'44': '载'
}
};

export default mapping;
Loading

0 comments on commit 39246e5

Please sign in to comment.