-
Notifications
You must be signed in to change notification settings - Fork 272
Add @superset-ui/translation #12
Changes from 9 commits
1dcc72e
a3afb8e
4c90cf4
a14da20
739692e
02ec7d6
540c8a7
a2ff322
539b3af
60185fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
## `@superset-ui/translation` | ||
|
||
[![Version](https://img.shields.io/npm/v/@superset-ui/translation.svg?style=flat)](https://img.shields.io/npm/v/@superset-ui/translation.svg?style=flat) | ||
|
||
`i18n` locales and translation for Superset | ||
|
||
### SupersetTranslation | ||
|
||
#### Example usage | ||
|
||
```js | ||
import { configure, t } from '@superset-ui/translation'; | ||
|
||
configure({ | ||
languagePack: {...}, | ||
}); | ||
|
||
console.log(t('text to be translated')); | ||
``` | ||
|
||
#### API | ||
|
||
`configure({ [languagePack] })` | ||
|
||
- Initialize the translator | ||
- Initialize with the default language if no `languagePack` is specified. | ||
|
||
`t(text[, args])` | ||
|
||
- Translate `text` when no `args` is provided. | ||
- Translate `text` and substitute `args` into the placeholders specified within `text`. | ||
|
||
For example | ||
|
||
```js | ||
t('Hello %(name)s', user) | ||
``` | ||
|
||
See [sprintf-js](/~https://github.com/alexei/sprintf.js) for more details on how to define placeholders. | ||
|
||
### Development | ||
|
||
`@data-ui/build-config` is used to manage the build configuration for this package including babel | ||
builds, jest testing, eslint, and prettier. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
{ | ||
"name": "@superset-ui/translation", | ||
"version": "0.0.0", | ||
"description": "Superset UI translation", | ||
"sideEffects": false, | ||
"main": "lib/index.js", | ||
"module": "esm/index.js", | ||
"files": [ | ||
"esm", | ||
"lib" | ||
], | ||
"scripts": { | ||
"build:cjs": "beemo babel ./src --out-dir lib/ --minify", | ||
"build:esm": "beemo babel ./src --out-dir esm/ --esm --minify", | ||
"build": "yarn run build:cjs && yarn run build:esm", | ||
"dev": "beemo babel --watch ./src --out-dir esm/ --esm", | ||
"jest": "beemo jest --color --coverage", | ||
"eslint": "beemo eslint \"./{src,test}/**/*.{js,jsx,json,md}\"", | ||
"lint": "yarn run prettier && yarn run eslint", | ||
"lint:fix": "yarn run prettier --write && yarn run eslint --fix", | ||
"test": "yarn run jest", | ||
"prettier": "beemo prettier \"./{src,test}/**/*.{js,jsx,json,md}\"", | ||
"prepublish": "yarn run build" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+/~https://github.com/apache-superset/superset-ui.git" | ||
}, | ||
"keywords": [ | ||
"superset", | ||
"client", | ||
"translation" | ||
], | ||
"author": "", | ||
"license": "Apache-2.0", | ||
"bugs": { | ||
"url": "/~https://github.com/apache-superset/superset-ui/issues" | ||
}, | ||
"homepage": "/~https://github.com/apache-superset/superset-ui#readme", | ||
"devDependencies": { | ||
"@data-ui/build-config": "^0.0.23", | ||
"react": "^16.4.1" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes! |
||
}, | ||
"dependencies": { | ||
"@babel/runtime": "^7.1.2", | ||
"jed": "^1.1.1", | ||
"sprintf-js": "^1.1.1" | ||
}, | ||
"peerDependencies": { | ||
"react": "^16.4.1" | ||
}, | ||
"beemo": { | ||
"module": "@data-ui/build-config", | ||
"drivers": [ | ||
"babel", | ||
"eslint", | ||
{ | ||
"driver": "jest", | ||
"env": { | ||
"NODE_ENV": "test" | ||
} | ||
}, | ||
"prettier" | ||
], | ||
"eslint": { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not a big deal since my PR is moving this config to the root but you can prob remove the app-specific There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool |
||
"rules": { | ||
"prefer-promise-reject-errors": "off" | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import Jed from 'jed'; | ||
import { sprintf } from 'sprintf-js'; | ||
|
||
const DEFAULT_LANGUAGE_PACK = { | ||
domain: 'superset', | ||
locale_data: { | ||
superset: { | ||
'': { | ||
domain: 'superset', | ||
lang: 'en', | ||
plural_forms: 'nplurals=1; plural=0', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
export default class Translator { | ||
constructor({ languagePack = DEFAULT_LANGUAGE_PACK } = {}) { | ||
kristw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this.i18n = new Jed(languagePack); | ||
} | ||
|
||
translate(input, ...args) { | ||
if (input === null || input === undefined) { | ||
return input; | ||
} | ||
const text = this.i18n.gettext(input); | ||
return (args.length > 0) ? sprintf(text, ...args) : text; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import Translator from './Translator'; | ||
|
||
let singleton; | ||
|
||
function configure(config) { | ||
singleton = new Translator(config); | ||
return singleton; | ||
}; | ||
|
||
function getInstance() { | ||
if (!singleton) { | ||
throw new Error('You must call configure(...) before calling other methods'); | ||
} | ||
return singleton; | ||
} | ||
|
||
function t(...args) { | ||
return getInstance().translate(...args); | ||
} | ||
|
||
export { configure, t }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { configure, t } from './TranslatorSingleton'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import Translator from '../src/Translator'; | ||
import languagePackZh from './languagePacks/zh.json'; | ||
|
||
describe('Translator', () => { | ||
it('exists', () => { | ||
expect(Translator).toBeDefined(); | ||
}); | ||
describe('new Translator(config)', () => { | ||
it('initializes when config is not specified', () => { | ||
expect(new Translator()).toBeInstanceOf(Translator); | ||
}); | ||
it('initializes when config is an empty object', () => { | ||
expect(new Translator({})).toBeInstanceOf(Translator); | ||
}); | ||
it('initializes when config is specified', () => { | ||
expect(new Translator({ | ||
languagePack: languagePackZh, | ||
})).toBeInstanceOf(Translator); | ||
}); | ||
}); | ||
describe('.translate(input, ...args)', () => { | ||
const translator = new Translator({ | ||
languagePack: languagePackZh, | ||
}); | ||
it('returns null for null input', () => { | ||
expect(translator.translate(null)).toBeNull(); | ||
}); | ||
it('returns undefined for undefined input', () => { | ||
expect(translator.translate(undefined)).toBeUndefined(); | ||
}); | ||
it('translates simple text', () => { | ||
expect(translator.translate('second')).toEqual('η§'); | ||
}); | ||
it('translates template text with arguments', () => { | ||
expect(translator.translate('Copy of %s', 1)).toEqual('1 ηε―ζ¬'); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import Translator from '../src/Translator'; | ||
import { configure, t } from '../src/TranslatorSingleton'; | ||
import languagePackZh from './languagePacks/zh.json'; | ||
|
||
describe('TranslatorSingleton', () => { | ||
describe('before configure()', () => { | ||
describe('t()', () => { | ||
it('throws error', () => { | ||
expect(() => t('second')).toThrow(); | ||
}); | ||
}); | ||
}); | ||
describe('after configure()', () => { | ||
describe('configure()', () => { | ||
it('creates and returns a translator', () => { | ||
expect(configure()).toBeInstanceOf(Translator); | ||
}); | ||
}); | ||
describe('t()', () => { | ||
it('after configure() returns translated text', () => { | ||
configure({ | ||
languagePack: languagePackZh, | ||
}); | ||
expect(t('second')).toEqual('η§'); | ||
}); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { configure, t } from '../src/index'; | ||
|
||
describe('index', () => { | ||
it('exports configure()', () => { | ||
expect(configure).toBeDefined(); | ||
expect(configure).toBeInstanceOf(Function); | ||
}); | ||
it('exports t()', () => { | ||
expect(t).toBeDefined(); | ||
expect(t).toBeInstanceOf(Function); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"domain": "superset", | ||
"locale_data": { | ||
"superset": { | ||
"": { | ||
"domain": "superset", | ||
"plural_forms": "nplurals=2; plural=(n != 1)", | ||
"lang": "en" | ||
}, | ||
"second": [""], | ||
"Copy of %s": [""] | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"domain": "superset", | ||
"locale_data": { | ||
"superset": { | ||
"": { | ||
"domain": "superset", | ||
"plural_forms": "nplurals=1; plural=0", | ||
"lang": "zh" | ||
}, | ||
"second": ["η§"], | ||
"Copy of %s": ["%s ηε―ζ¬"] | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what to do about these. whoever inits the package could put their name, or maybe we can omit the field in
package.json
s to make it a non-issue π€There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll put
Superset
for now.