Skip to content
This repository has been archived by the owner on Dec 10, 2021. It is now read-only.

Add tn / translateWithNumber #15

Merged
merged 2 commits into from
Oct 26, 2018
Merged
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
20 changes: 16 additions & 4 deletions packages/superset-ui-translation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
3 changes: 1 addition & 2 deletions packages/superset-ui-translation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
18 changes: 15 additions & 3 deletions packages/superset-ui-translation/src/Translator.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Jed from 'jed';
import { sprintf } from 'sprintf-js';

const DEFAULT_LANGUAGE_PACK = {
domain: 'superset',
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
2 changes: 1 addition & 1 deletion packages/superset-ui-translation/src/index.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { configure, t } from './TranslatorSingleton';
export { configure, t, tn } from './TranslatorSingleton';
39 changes: 38 additions & 1 deletion packages/superset-ui-translation/test/Translator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need another test, but curious how it behaves with 0 since that is the default num. is that singular?

Copy link
Contributor Author

@kristw kristw Oct 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that depends on each languagePack. I saw there are DSL-ish field in the language packs that defines n for singular and plural.

"plural_forms": "nplurals=2; plural=(n != 1)",

});
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',
);
});
});
});
Original file line number Diff line number Diff line change
@@ -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', () => {
Expand All @@ -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()', () => {
Expand All @@ -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');
});
});
});
});
6 changes: 5 additions & 1 deletion packages/superset-ui-translation/test/index.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { configure, t } from '../src/index';
import { configure, t, tn } from '../src/index';

describe('index', () => {
it('exports configure()', () => {
Expand All @@ -9,4 +9,8 @@ describe('index', () => {
expect(t).toBeDefined();
expect(t).toBeInstanceOf(Function);
});
it('exports tn()', () => {
expect(tn).toBeDefined();
expect(tn).toBeInstanceOf(Function);
});
});
4 changes: 2 additions & 2 deletions packages/superset-ui-translation/test/languagePacks/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 的副本本本"]
}
}
}