Skip to content

Commit ca73de9

Browse files
author
Gertjan Reynaert
committed
Merge pull request #1 from GertjanReynaert/gr-setup-tooling
Setup tooling + WIP version
2 parents 87dc51d + 91ae3fa commit ca73de9

20 files changed

+819
-252
lines changed

.babelrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"presets": ["es2015", "stage-2", "react"],
3+
"plugins": ["babel-root-import"]
4+
}

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
**/node_modules

.eslintrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"parser": "babel-eslint",
3+
"extends": "airbnb",
4+
"globals": {
5+
"describe": false,
6+
"it": false
7+
}
8+
}

.travis.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
sudo: false
2+
language: node_js
3+
cache:
4+
directories:
5+
- node_modules
6+
notifications:
7+
email: false
8+
node_js:
9+
- '4'
10+
before_install:
11+
- npm i -g npm@^2.0.0
12+
before_script:
13+
- npm prune
14+
script:
15+
- npm run test
16+
- npm run coverage
17+
after_success:
18+
- npm run report:coverage
19+
- npm run build
20+
- npm run semantic-release
21+
branches:
22+
only:
23+
- master

README.md

Lines changed: 291 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,291 @@
1-
# react-intl-translations-manager
1+
# React-intl-translations-manager
2+
[![travis-ci][travis-image]][travis-url]
3+
[![Codecov][codecov-image]][codecov-url]
4+
[![Commitizen friendly][comitizen-image]][comitizen-url]
5+
[![semantic-release][semantic-image]][semantic-url]
6+
[![npm-downloads][npm-downloads-image]][npm-downloads-url]
7+
[![npm-version][npm-version-image]][npm-version-url]
8+
[![npm-license][npm-license-image]][npm-license-url]
9+
10+
[travis-image]: https://img.shields.io/travis/GertjanReynaert/react-intl-translations-manager.svg
11+
[travis-url]: https://travis-ci.org/GertjanReynaert/react-intl-translations-manager
12+
[codecov-image]: https://img.shields.io/codecov/c/github/GertjanReynaert/react-intl-translations-manager.svg
13+
[codecov-url]: https://codecov.io/github/GertjanReynaert/react-intl-translations-manager
14+
[comitizen-image]: https://img.shields.io/badge/commitizen-friendly-brightgreen.svg
15+
[comitizen-url]: http://commitizen.github.io/cz-cli
16+
[semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
17+
[semantic-url]: https://github.com/semantic-release/semantic-release
18+
[npm-downloads-image]: https://img.shields.io/npm/dt/react-intl-translations-manager.svg
19+
[npm-downloads-url]: https://www.npmjs.com/package/react-intl-translation-manager
20+
[npm-version-image]: https://img.shields.io/npm/v/npm.svg
21+
[npm-version-url]: https://www.npmjs.com/package/react-intl-translation-manager
22+
[npm-license-image]: https://img.shields.io/npm/l/express.svg
23+
[npm-license-url]: https://www.npmjs.com/package/react-intl-translation-manager
24+
25+
## Installing
26+
27+
```
28+
npm install --save-dev react-intl-translations-manager
29+
```
30+
31+
## Usage
32+
### Basic
33+
34+
Since you need the `babel-plugin-react-intl` to extract the messages, I'll assume you're using babel in your project.
35+
36+
This is an example of the most basic usage of this plugin, in the API documentation below you can find more options.
37+
38+
Create a script in your package.json
39+
```json
40+
{
41+
"scripts": {
42+
"manage:translations": "babel-node ./translationRunner.js"
43+
}
44+
}
45+
```
46+
Create a file with your config you can run with the npm script
47+
```js
48+
// translationRunner.js
49+
import manageTranslations from 'react-intl-translations-manager';
50+
51+
manageTranslations({
52+
messagesDirectory: 'src/translations/extractedMessages',
53+
translationsDirectory: 'src/translations/locales/',
54+
languages: ['nl'], // any language you need
55+
});
56+
```
57+
58+
Run the translation manager with your new npm script
59+
60+
```
61+
npm run manage:translations
62+
```
63+
64+
### Advanced
65+
66+
Build your own translationManager based on the core of this package, or it's
67+
exposed helper methods.
68+
69+
## API
70+
71+
### manageTranslations
72+
73+
This will maintain all translation files. Based on your config you will get output for duplicate ids, and per specified language you will get the deleted translations, added messages (new messages that need to be translated), and not yet translated messages. It will also maintain a whitelist file per language where you can specify translation keys where the translation is identical to the default message. This way you can avoid untranslated message warnings for these messages.
74+
75+
You can optionally pass a printer object to this method. This way you can override the console logging with your own logging logic. If you want custom file writing logic, it is advised to roll your own translationManager based on the core.
76+
77+
#### Config
78+
79+
- `messagesDirectory` (required),
80+
- Directory where the babel plugin puts the extracted messages. This path is
81+
relative to your projects root.
82+
- example: `src/locales/extractedMessages`
83+
- `translationsDirectory` (required),
84+
- Directory of the translation files the translation manager needs to maintain.
85+
- example: `src/locales/lang`
86+
- `whitelistsDirectory` (optional, default: `translationsDirectory`)
87+
- Directory of the whitelist files the translation manager needs to maintain.
88+
These files contain the key of translations that have the exact same text in a specific language as the defaultMessage. Specifying this key will suppress
89+
`unmaintained translation` warnings.
90+
- example: `Dashboard` in english is also accepted as a valid translation for
91+
dutch.
92+
- `languages` (optional, default: `[]`)
93+
- What languages the translation manager needs to maintain. Specifying no
94+
languages actually doesn't make sense, but won't break the translationManager
95+
either.
96+
- example: for `['nl', 'fr']` the translation manager will maintain a `nl.json`, `fr.json`, `whitelist_nl.json` and a `whitelist_fr.json` file
97+
- `singleMessagesFile` (optional, default: `false`)
98+
- Option to output a single JSON file containing the aggregate of all extracted messages,
99+
grouped by the file they were extracted from.
100+
- example:
101+
```json
102+
[
103+
{
104+
"path": "src/components/foo.json",
105+
"descriptors": [
106+
{
107+
"id": "bar",
108+
"description": "Text for bar",
109+
"defaultMessage": "Bar",
110+
}
111+
]
112+
}
113+
]
114+
```
115+
- `detectDuplicateIds` (optional, default: `true`)
116+
- If you want the translationManager to log duplicate message ids or not
117+
- `printers` (optional, default: {})
118+
- Here you can specify custom logging methods. If not specified a default printer is used.
119+
- Possible printers to configure:
120+
```js
121+
const printers = {
122+
printDuplicateIds: ( duplicateIds ) => { console.log(`You have ${duplicateIds.length } duplicate IDs`) },
123+
printLanguageReport: ( report ) => { console.log('Log report for a language') },
124+
printNoLanguageFile: ( lang ) => { console.log(`No existing ${lang} translation file found. A new one is created.`) },
125+
printNoLanguageWhitelistFile: ( lang ) => { console.log(`No existing ${lang} file found. A new one is created.`) },
126+
};
127+
```
128+
129+
### core
130+
```js
131+
core(languages, hooks);
132+
```
133+
134+
This is the core of the translationManager. It just takes a list of languages
135+
and an object with all kinds of hooks it will execute when running. Below you
136+
can find all hooks.
137+
138+
```js
139+
const hooks = {
140+
provideExtractedMessages,
141+
outputSingleFile,
142+
outputDuplicateKeys,
143+
beforeReporting,
144+
provideLangTemplate,
145+
provideTranslationsFile,
146+
provideWhitelistFile,
147+
reportLanguage,
148+
afterReporting,
149+
};
150+
```
151+
152+
#### provideExtractedMessages
153+
```js
154+
const extractedMessages = provideExtractedMessages();
155+
```
156+
157+
Here you should return all extracted messages. This should be an array, with an object per file. Each object should at least contain a `descriptors` key which in turn has an array of message objects. Each message object should at least contain the id and message.
158+
Example:
159+
```js
160+
// Minimal expected return value
161+
const extractedMessages = [
162+
{
163+
descriptors: [
164+
{
165+
id: 'foo_ok',
166+
defaultMessage: 'OK',
167+
},
168+
],
169+
},
170+
];
171+
```
172+
173+
#### outputSingleFile
174+
```js
175+
outputSingleFile(extractedMessages);
176+
```
177+
178+
This gives you the option to output the extractedMessages. This way you can for example shrink all extracted files into a single File containing all messages.
179+
180+
#### outputDuplicateKeys
181+
```js
182+
outputDuplicateKeys(duplicateIds);
183+
```
184+
185+
This gives you the option to warn for duplicate ids.
186+
187+
#### beforeReporting
188+
```js
189+
beforeReporting();
190+
```
191+
192+
Here you can do the preparation of the reporting, like creating the necessary folders, or printing a start message
193+
194+
#### provideLangTemplate
195+
```js
196+
const languageResults = provideLangTemplate(lang);
197+
```
198+
199+
Here you should provide the template for the language results. This is just a basic object (`{}`) which can contain pre-filled in data, potentially based on the language.
200+
The following keys are restricted and will be overridden by the core: `report`, `noTranslationFile` and `noWhitelistFile`.
201+
202+
#### provideTranslationsFile
203+
```js
204+
const translationsFile = provideTranslationsFile(lang);
205+
```
206+
207+
Here you should return the translations for the specified language. This must be an object with the message id and message in a key value format.
208+
```js
209+
const translationsFile = {
210+
messageId: 'message',
211+
};
212+
```
213+
214+
#### provideWhitelistFile
215+
```js
216+
const whitelistFile = provideWhitelistFile(lang);
217+
```
218+
219+
Here you should return the whitelisted messsage ids for the specified language. This must be an array of strings.
220+
```js
221+
const whitelistFile = [
222+
'messageId',
223+
];
224+
```
225+
226+
#### reportLanguage
227+
```js
228+
reportLanguage(languageResults)
229+
```
230+
231+
Here you can handle the reporting of the results for a language, like logging and creating files based on the results.
232+
233+
#### afterReporting
234+
```js
235+
afterReporting()
236+
```
237+
238+
Here you can do actions after all reports are made, like cleanup or printing a finished message.
239+
240+
### readMessageFiles
241+
```js
242+
const extractedMessages = readMessageFiles(messagesDirectory);
243+
```
244+
245+
This is a `babel-plugin-react-intl` specific helper method. It will read all extracted JSON file for the specified directory, filter out all files without any messages, and output an array with all messages.
246+
247+
Example output:
248+
```js
249+
const extractedMessages = [
250+
{
251+
path: 'src/components/Foo.json',
252+
descriptors: [
253+
{
254+
id: 'foo_ok',
255+
description: 'Ok text',
256+
defaultMessage: 'OK',
257+
},
258+
],
259+
},
260+
];
261+
```
262+
263+
### createSingleMessagesFile
264+
```js
265+
createSingleMessagesFile({ messages, directory });
266+
```
267+
268+
This helper method will output all messages (potentially read by `readMessageFiles`) in a single jsonFile.
269+
270+
- messages: (required)
271+
- directory: (required, string) contains the path to the directory where the file should be written into.
272+
- fileName: (optional, default: `defaultMessages.json`) this filename should contain the `.json` extension
273+
- jsonSpaceIndentation: (optional, default: `2`) number of spaces used for indentation (0-10)
274+
275+
### getDefaultMessages
276+
```js
277+
const messages = getDefaultMessages(extractedMessages);
278+
```
279+
280+
This helper method will flatten all files (as returned from `readMessageFiles`) into a single object.
281+
282+
```js
283+
const messages = {
284+
messages: {
285+
messageId: 'message',
286+
},
287+
duplicateIds: [
288+
// potentially double used message keys,
289+
]
290+
};
291+
```

package.json

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
{
22
"name": "react-intl-translations-manager",
3-
"version": "0.0.1",
43
"description": "Manage all translations based on the extracted messages of the babel-plugin-react-intl",
5-
"main": "index.js",
4+
"main": "./dist/react-intl-translations-manager.js",
65
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
6+
"clean:install": "rm -rf node_modules && npm cache clean && npm install",
7+
"test": "NODE_ENV=test mocha --compilers js:babel-core/register --recursive",
8+
"test:watch": "npm test -- --watch",
9+
"coverage": "./node_modules/.bin/babel-node ./node_modules/.bin/babel-istanbul cover node_modules/mocha/bin/_mocha",
10+
"report:coverage": "cat ./coverage/coverage.json | ./node_modules/codecov.io/bin/codecov.io.js",
11+
"build": "NODE_ENV=development webpack -p --config webpack.config.js",
12+
"manage:translations": "babel-node ./src/locales/translationManager.js",
13+
"semantic-release": "semantic-release pre && npm publish && semantic-release post"
814
},
915
"repository": {
1016
"type": "git",
11-
"url": "git+https://github.com/GertjanReynaert/react-intl-translations-manager.git"
17+
"url": "https://github.com/GertjanReynaert/react-intl-translations-manager.git"
1218
},
1319
"keywords": [
1420
"react",
@@ -24,5 +30,38 @@
2430
"bugs": {
2531
"url": "https://github.com/GertjanReynaert/react-intl-translations-manager/issues"
2632
},
27-
"homepage": "https://github.com/GertjanReynaert/react-intl-translations-manager#readme"
33+
"homepage": "https://github.com/GertjanReynaert/react-intl-translations-manager#readme",
34+
"dependencies": {
35+
"chalk": "^1.1.1",
36+
"fs": "0.0.2",
37+
"glob": "^6.0.1",
38+
"mkdirp": "^0.5.1"
39+
},
40+
"devDependencies": {
41+
"babel-cli": "^6.4.0",
42+
"babel-core": "^6.4.0",
43+
"babel-eslint": "^5.0.0-beta6",
44+
"babel-istanbul": "^0.6.0",
45+
"babel-loader": "^6.2.1",
46+
"babel-preset-es2015": "^6.3.13",
47+
"babel-preset-react": "^6.3.13",
48+
"babel-preset-stage-2": "^6.3.13",
49+
"babel-root-import": "^3.1.0",
50+
"chai": "^3.4.1",
51+
"codecov.io": "^0.1.6",
52+
"cz-conventional-changelog": "^1.1.5",
53+
"eslint": "^1.10.3",
54+
"eslint-config-airbnb": "^2.1.1",
55+
"eslint-plugin-react": "^3.15.0",
56+
"ghooks": "^1.0.3",
57+
"mocha": "^2.3.4",
58+
"semantic-release": "^4.3.5",
59+
"webpack": "^1.12.11"
60+
},
61+
"config": {
62+
"ghooks": {},
63+
"commitizen": {
64+
"path": "./node_modules/cz-conventional-changelog"
65+
}
66+
}
2867
}

0 commit comments

Comments
 (0)