From 2f5211253cf43e9b7186710fb306f89a7de9f64e Mon Sep 17 00:00:00 2001 From: Krist Wongsuphasawat Date: Fri, 26 Oct 2018 14:50:34 -0700 Subject: [PATCH] Merge pull request #15 from apache-superset/kristw--translation-num Add tn / translateWithNumber --- .../superset-ui-translation/README.md | 20 ++++++++-- .../superset-ui-translation/package.json | 3 +- .../superset-ui-translation/src/Translator.js | 18 +++++++-- .../src/TranslatorSingleton.js | 6 ++- .../superset-ui-translation/src/index.js | 2 +- .../test/Translator.test.js | 39 ++++++++++++++++++- .../test/TranslatorSingleton.test.js | 15 ++++++- .../test/index.test.js | 6 ++- .../test/languagePacks/zh.json | 4 +- 9 files changed, 97 insertions(+), 16 deletions(-) diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/README.md b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/README.md index eca188f9606c4..cefd1e7d59d18 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/README.md +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/README.md @@ -9,13 +9,14 @@ #### Example usage ```js -import { configure, t } from '@superset-ui/translation'; +import { configure, t, tn } from '@superset-ui/translation'; configure({ languagePack: {...}, }); console.log(t('text to be translated')); +console.log(tn('singular text', 'plural text', value)); ``` #### API @@ -27,17 +28,28 @@ console.log(t('text to be translated')); `t(text[, args])` -- Translate `text` when no `args` is provided. -- Translate `text` and substitute `args` into the placeholders specified within `text`. +- Translate `text`. +- If `args` is provided, substitute `args` into the `sprintf` placeholders specified within `text` translation. For example ```js -t('Hello %(name)s', user) +t('Hello %(name)s', user); ``` See [sprintf-js](https://github.com/alexei/sprintf.js) for more details on how to define placeholders. +`tn(singular, plural, num, [, args])` + +- Translate and choose between `singular` and `plural` based on `num`. +- If `args` is provided, substitute `args` into the `sprintf` placeholders specified within `singular` or `plural` translations. + +For example + +```js +tn('%d duck', '%d ducks', 2, 2); +``` + ### Development `@data-ui/build-config` is used to manage the build configuration for this package including babel diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/package.json b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/package.json index d0be216680b3a..f67320c75cb3b 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/package.json +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/package.json @@ -29,8 +29,7 @@ }, "dependencies": { "@babel/runtime": "^7.1.2", - "jed": "^1.1.1", - "sprintf-js": "^1.1.1" + "jed": "^1.1.1" }, "beemo": { "module": "@data-ui/build-config", diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/Translator.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/Translator.js index e197d4b340907..b0944f4a8cdb4 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/Translator.js +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/Translator.js @@ -1,5 +1,4 @@ import Jed from 'jed'; -import { sprintf } from 'sprintf-js'; const DEFAULT_LANGUAGE_PACK = { domain: 'superset', @@ -23,8 +22,21 @@ export default class Translator { if (input === null || input === undefined) { return input; } - const text = this.i18n.gettext(input); - return args.length > 0 ? sprintf(text, ...args) : text; + return this.i18n.translate(input).fetch(...args); + } + + translateWithNumber(singular, plural, num = 0, ...args) { + if (singular === null || singular === undefined) { + return singular; + } + if (plural === null || plural === undefined) { + return plural; + } + + return this.i18n + .translate(singular) + .ifPlural(num, plural) + .fetch(...args); } } diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/TranslatorSingleton.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/TranslatorSingleton.js index aaa0ed0682814..ee00b6678d746 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/TranslatorSingleton.js +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/TranslatorSingleton.js @@ -20,4 +20,8 @@ function t(...args) { return getInstance().translate(...args); } -export { configure, t }; +function tn(...args) { + return getInstance().translateWithNumber(...args); +} + +export { configure, t, tn }; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/index.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/index.js index dc0dee5a48be4..5ed37f1bbd1b6 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/index.js +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/src/index.js @@ -1 +1 @@ -export { configure, t } from './TranslatorSingleton'; +export { configure, t, tn } from './TranslatorSingleton'; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/Translator.test.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/Translator.test.js index 6373a821fc601..906fabe50239c 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/Translator.test.js +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/Translator.test.js @@ -30,11 +30,48 @@ describe('Translator', () => { it('returns undefined for undefined input', () => { expect(translator.translate(undefined)).toBeUndefined(); }); + it('returns original text for unknown text', () => { + expect(translator.translate('abc')).toEqual('abc'); + }); it('translates simple text', () => { expect(translator.translate('second')).toEqual('秒'); }); - it('translates template text with arguments', () => { + it('translates template text with an argument', () => { expect(translator.translate('Copy of %s', 1)).toEqual('1 的副本'); }); + it('translates template text with multiple arguments', () => { + expect(translator.translate('test %d %d', 1, 2)).toEqual('test 1 2'); + }); + }); + describe('.translateWithNumber(singular, plural, num, ...args)', () => { + const translator = new Translator({ + languagePack: languagePackZh, + }); + it('returns null if singular or plural is null', () => { + expect(translator.translateWithNumber(null, 'plural')).toBeNull(); + expect(translator.translateWithNumber('singular', null)).toBeNull(); + expect(translator.translateWithNumber(null, null)).toBeNull(); + }); + it('returns undefined if singular or plural is undefined', () => { + expect(translator.translateWithNumber(undefined, 'plural')).toBeUndefined(); + expect(translator.translateWithNumber('singular', undefined)).toBeUndefined(); + expect(translator.translateWithNumber(undefined, undefined)).toBeUndefined(); + }); + it('returns original text for unknown text', () => { + expect(translator.translateWithNumber('fish', 'fishes', 1)).toEqual('fish'); + }); + it('translates simple text', () => { + expect(translator.translateWithNumber('second', 'seconds', 1)).toEqual('秒'); + }); + it('translates template text with an argument', () => { + expect(translator.translateWithNumber('Copy of %s', 'Copies of %s', 12, 12)).toEqual( + '12 的副本本本', + ); + }); + it('translates template text with multiple arguments', () => { + expect(translator.translateWithNumber('%d glass %s', '%d glasses %s', 3, 3, 'abc')).toEqual( + '3 glasses abc', + ); + }); }); }); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/TranslatorSingleton.test.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/TranslatorSingleton.test.js index b7814d8681b42..493dd2ac59d44 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/TranslatorSingleton.test.js +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/TranslatorSingleton.test.js @@ -1,5 +1,5 @@ import Translator from '../src/Translator'; -import { configure, t } from '../src/TranslatorSingleton'; +import { configure, t, tn } from '../src/TranslatorSingleton'; import languagePackZh from './languagePacks/zh.json'; describe('TranslatorSingleton', () => { @@ -9,6 +9,11 @@ describe('TranslatorSingleton', () => { expect(() => t('second')).toThrow(); }); }); + describe('tn()', () => { + it('throws error', () => { + expect(() => tn('ox', 'oxen', 2)).toThrow(); + }); + }); }); describe('after configure()', () => { describe('configure()', () => { @@ -24,5 +29,13 @@ describe('TranslatorSingleton', () => { expect(t('second')).toEqual('秒'); }); }); + describe('tn()', () => { + it('after configure() returns translated text with singular/plural', () => { + configure({ + languagePack: languagePackZh, + }); + expect(tn('ox', 'oxen', 2)).toEqual('oxen'); + }); + }); }); }); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/index.test.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/index.test.js index daceb76cca180..15c07204ca085 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/index.test.js +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/index.test.js @@ -1,4 +1,4 @@ -import { configure, t } from '../src/index'; +import { configure, t, tn } from '../src/index'; describe('index', () => { it('exports configure()', () => { @@ -9,4 +9,8 @@ describe('index', () => { expect(t).toBeDefined(); expect(t).toBeInstanceOf(Function); }); + it('exports tn()', () => { + expect(tn).toBeDefined(); + expect(tn).toBeInstanceOf(Function); + }); }); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/languagePacks/zh.json b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/languagePacks/zh.json index 6baace9cca4ae..d93afdbe11f12 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/languagePacks/zh.json +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-translation/test/languagePacks/zh.json @@ -4,11 +4,11 @@ "superset": { "": { "domain": "superset", - "plural_forms": "nplurals=1; plural=0", + "plural_forms": "nplurals=2; plural=(n != 1)", "lang": "zh" }, "second": ["秒"], - "Copy of %s": ["%s 的副本"] + "Copy of %s": ["%s 的副本", "%s 的副本本本"] } } }