@vocab/phrase 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +6 -4
- package/dist/vocab-phrase.cjs.dev.js +21 -20
- package/dist/vocab-phrase.cjs.prod.js +21 -20
- package/dist/vocab-phrase.esm.js +21 -20
- package/package.json +1 -1
- package/src/phrase-api.ts +0 -1
- package/src/pull-translations.test.ts +85 -17
- package/src/pull-translations.ts +33 -30
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @vocab/phrase
|
|
2
2
|
|
|
3
|
+
## 1.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`20eec77`](https://github.com/seek-oss/vocab/commit/20eec770705d05048ad8b32575cb92720b887f5b) [#76](https://github.com/seek-oss/vocab/pull/76) Thanks [@askoufis](https://github.com/askoufis)! - `vocab pull` no longer errors when phrase returns no translations for a configured language
|
|
8
|
+
|
|
3
9
|
## 1.0.0
|
|
4
10
|
|
|
5
11
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -110,7 +110,7 @@ So far, your app will run, but you're missing any translations other than the in
|
|
|
110
110
|
}
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
### Step 6: [Optional]
|
|
113
|
+
### Step 6: [Optional] Set up Webpack plugin
|
|
114
114
|
|
|
115
115
|
Right now every language is loaded into your web application all the time, which could lead to a large bundle size. Ideally you will want to switch out the Node/default runtime for web runtime that will load only the active language.
|
|
116
116
|
|
|
@@ -171,8 +171,10 @@ In the below example we use two messages, one that passes in a single parameter
|
|
|
171
171
|
Vocab will automatically parse these strings as ICU messages, identify the required parameters and ensure TypeScript knows the values must be passed in.
|
|
172
172
|
|
|
173
173
|
```tsx
|
|
174
|
-
t('my key with param', {name: 'Vocab'});
|
|
175
|
-
t('my key with component', {
|
|
174
|
+
t('my key with param', { name: 'Vocab' });
|
|
175
|
+
t('my key with component', {
|
|
176
|
+
Link: (children) => <a href="/foo">{children}</a>
|
|
177
|
+
});
|
|
176
178
|
```
|
|
177
179
|
|
|
178
180
|
## Configuration
|
|
@@ -194,7 +196,7 @@ module.exports = {
|
|
|
194
196
|
* The root directory to compile and validate translations
|
|
195
197
|
* Default: Current working directory
|
|
196
198
|
*/
|
|
197
|
-
projectRoot:
|
|
199
|
+
projectRoot: './example/';
|
|
198
200
|
/**
|
|
199
201
|
* A custom suffix to name vocab translation directories
|
|
200
202
|
* Default: '.vocab'
|
|
@@ -83,7 +83,6 @@ async function callPhrase(relativePath, options = {}) {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
return _callPhrase(`https://api.phrase.com/v2/projects/${projectId}/${relativePath}`, options).then(result => {
|
|
86
|
-
// console.log('Result:', result);
|
|
87
86
|
if (Array.isArray(result)) {
|
|
88
87
|
console.log('Result length:', result.length);
|
|
89
88
|
}
|
|
@@ -174,31 +173,33 @@ async function pull({
|
|
|
174
173
|
await writeFile(loadedTranslation.filePath, `${JSON.stringify(defaultValues, null, 2)}\n`);
|
|
175
174
|
|
|
176
175
|
for (const alternativeLanguage of alternativeLanguages) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
176
|
+
if (alternativeLanguage in allPhraseTranslations) {
|
|
177
|
+
const altTranslations = { ...loadedTranslation.languages[alternativeLanguage]
|
|
178
|
+
};
|
|
179
|
+
const phraseAltTranslations = allPhraseTranslations[alternativeLanguage];
|
|
180
|
+
|
|
181
|
+
for (const key of localKeys) {
|
|
182
|
+
var _phraseAltTranslation;
|
|
180
183
|
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
const phraseKey = core.getUniqueKey(key, loadedTranslation.namespace);
|
|
185
|
+
const phraseTranslationMessage = (_phraseAltTranslation = phraseAltTranslations[phraseKey]) === null || _phraseAltTranslation === void 0 ? void 0 : _phraseAltTranslation.message;
|
|
183
186
|
|
|
184
|
-
|
|
185
|
-
|
|
187
|
+
if (!phraseTranslationMessage) {
|
|
188
|
+
trace(`Missing translation. No translation for key ${key} in phrase as ${phraseKey} in language ${alternativeLanguage}.`);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
186
191
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
192
|
+
altTranslations[key] = { ...altTranslations[key],
|
|
193
|
+
message: phraseTranslationMessage
|
|
194
|
+
};
|
|
190
195
|
}
|
|
191
196
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
197
|
+
const altTranslationFilePath = core.getAltLanguageFilePath(loadedTranslation.filePath, alternativeLanguage);
|
|
198
|
+
await mkdir(path__default['default'].dirname(altTranslationFilePath), {
|
|
199
|
+
recursive: true
|
|
200
|
+
});
|
|
201
|
+
await writeFile(altTranslationFilePath, `${JSON.stringify(altTranslations, null, 2)}\n`);
|
|
195
202
|
}
|
|
196
|
-
|
|
197
|
-
const altTranslationFilePath = core.getAltLanguageFilePath(loadedTranslation.filePath, alternativeLanguage);
|
|
198
|
-
await mkdir(path__default['default'].dirname(altTranslationFilePath), {
|
|
199
|
-
recursive: true
|
|
200
|
-
});
|
|
201
|
-
await writeFile(altTranslationFilePath, `${JSON.stringify(altTranslations, null, 2)}\n`);
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
}
|
|
@@ -83,7 +83,6 @@ async function callPhrase(relativePath, options = {}) {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
return _callPhrase(`https://api.phrase.com/v2/projects/${projectId}/${relativePath}`, options).then(result => {
|
|
86
|
-
// console.log('Result:', result);
|
|
87
86
|
if (Array.isArray(result)) {
|
|
88
87
|
console.log('Result length:', result.length);
|
|
89
88
|
}
|
|
@@ -174,31 +173,33 @@ async function pull({
|
|
|
174
173
|
await writeFile(loadedTranslation.filePath, `${JSON.stringify(defaultValues, null, 2)}\n`);
|
|
175
174
|
|
|
176
175
|
for (const alternativeLanguage of alternativeLanguages) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
176
|
+
if (alternativeLanguage in allPhraseTranslations) {
|
|
177
|
+
const altTranslations = { ...loadedTranslation.languages[alternativeLanguage]
|
|
178
|
+
};
|
|
179
|
+
const phraseAltTranslations = allPhraseTranslations[alternativeLanguage];
|
|
180
|
+
|
|
181
|
+
for (const key of localKeys) {
|
|
182
|
+
var _phraseAltTranslation;
|
|
180
183
|
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
const phraseKey = core.getUniqueKey(key, loadedTranslation.namespace);
|
|
185
|
+
const phraseTranslationMessage = (_phraseAltTranslation = phraseAltTranslations[phraseKey]) === null || _phraseAltTranslation === void 0 ? void 0 : _phraseAltTranslation.message;
|
|
183
186
|
|
|
184
|
-
|
|
185
|
-
|
|
187
|
+
if (!phraseTranslationMessage) {
|
|
188
|
+
trace(`Missing translation. No translation for key ${key} in phrase as ${phraseKey} in language ${alternativeLanguage}.`);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
186
191
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
192
|
+
altTranslations[key] = { ...altTranslations[key],
|
|
193
|
+
message: phraseTranslationMessage
|
|
194
|
+
};
|
|
190
195
|
}
|
|
191
196
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
197
|
+
const altTranslationFilePath = core.getAltLanguageFilePath(loadedTranslation.filePath, alternativeLanguage);
|
|
198
|
+
await mkdir(path__default['default'].dirname(altTranslationFilePath), {
|
|
199
|
+
recursive: true
|
|
200
|
+
});
|
|
201
|
+
await writeFile(altTranslationFilePath, `${JSON.stringify(altTranslations, null, 2)}\n`);
|
|
195
202
|
}
|
|
196
|
-
|
|
197
|
-
const altTranslationFilePath = core.getAltLanguageFilePath(loadedTranslation.filePath, alternativeLanguage);
|
|
198
|
-
await mkdir(path__default['default'].dirname(altTranslationFilePath), {
|
|
199
|
-
recursive: true
|
|
200
|
-
});
|
|
201
|
-
await writeFile(altTranslationFilePath, `${JSON.stringify(altTranslations, null, 2)}\n`);
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
}
|
package/dist/vocab-phrase.esm.js
CHANGED
|
@@ -71,7 +71,6 @@ async function callPhrase(relativePath, options = {}) {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
return _callPhrase(`https://api.phrase.com/v2/projects/${projectId}/${relativePath}`, options).then(result => {
|
|
74
|
-
// console.log('Result:', result);
|
|
75
74
|
if (Array.isArray(result)) {
|
|
76
75
|
console.log('Result length:', result.length);
|
|
77
76
|
}
|
|
@@ -162,31 +161,33 @@ async function pull({
|
|
|
162
161
|
await writeFile(loadedTranslation.filePath, `${JSON.stringify(defaultValues, null, 2)}\n`);
|
|
163
162
|
|
|
164
163
|
for (const alternativeLanguage of alternativeLanguages) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
if (alternativeLanguage in allPhraseTranslations) {
|
|
165
|
+
const altTranslations = { ...loadedTranslation.languages[alternativeLanguage]
|
|
166
|
+
};
|
|
167
|
+
const phraseAltTranslations = allPhraseTranslations[alternativeLanguage];
|
|
168
|
+
|
|
169
|
+
for (const key of localKeys) {
|
|
170
|
+
var _phraseAltTranslation;
|
|
168
171
|
|
|
169
|
-
|
|
170
|
-
|
|
172
|
+
const phraseKey = getUniqueKey(key, loadedTranslation.namespace);
|
|
173
|
+
const phraseTranslationMessage = (_phraseAltTranslation = phraseAltTranslations[phraseKey]) === null || _phraseAltTranslation === void 0 ? void 0 : _phraseAltTranslation.message;
|
|
171
174
|
|
|
172
|
-
|
|
173
|
-
|
|
175
|
+
if (!phraseTranslationMessage) {
|
|
176
|
+
trace(`Missing translation. No translation for key ${key} in phrase as ${phraseKey} in language ${alternativeLanguage}.`);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
174
179
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
180
|
+
altTranslations[key] = { ...altTranslations[key],
|
|
181
|
+
message: phraseTranslationMessage
|
|
182
|
+
};
|
|
178
183
|
}
|
|
179
184
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
185
|
+
const altTranslationFilePath = getAltLanguageFilePath(loadedTranslation.filePath, alternativeLanguage);
|
|
186
|
+
await mkdir(path.dirname(altTranslationFilePath), {
|
|
187
|
+
recursive: true
|
|
188
|
+
});
|
|
189
|
+
await writeFile(altTranslationFilePath, `${JSON.stringify(altTranslations, null, 2)}\n`);
|
|
183
190
|
}
|
|
184
|
-
|
|
185
|
-
const altTranslationFilePath = getAltLanguageFilePath(loadedTranslation.filePath, alternativeLanguage);
|
|
186
|
-
await mkdir(path.dirname(altTranslationFilePath), {
|
|
187
|
-
recursive: true
|
|
188
|
-
});
|
|
189
|
-
await writeFile(altTranslationFilePath, `${JSON.stringify(altTranslations, null, 2)}\n`);
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
}
|
package/package.json
CHANGED
package/src/phrase-api.ts
CHANGED
|
@@ -2,6 +2,7 @@ import path from 'path';
|
|
|
2
2
|
import { pull } from './pull-translations';
|
|
3
3
|
import { pullAllTranslations } from './phrase-api';
|
|
4
4
|
import { writeFile } from './file';
|
|
5
|
+
import { LanguageTarget } from '@vocab/types';
|
|
5
6
|
|
|
6
7
|
jest.mock('./file', () => ({
|
|
7
8
|
writeFile: jest.fn(() => Promise.resolve),
|
|
@@ -13,28 +14,83 @@ jest.mock('./phrase-api', () => ({
|
|
|
13
14
|
pullAllTranslations: jest.fn(() => Promise.resolve({ en: {}, fr: {} })),
|
|
14
15
|
}));
|
|
15
16
|
|
|
16
|
-
function runPhrase() {
|
|
17
|
+
function runPhrase(options: { languages: LanguageTarget[] }) {
|
|
17
18
|
return pull(
|
|
18
19
|
{ branch: 'tester' },
|
|
19
20
|
{
|
|
21
|
+
...options,
|
|
20
22
|
devLanguage: 'en',
|
|
21
|
-
languages: [{ name: 'en' }, { name: 'fr' }],
|
|
22
23
|
projectRoot: path.resolve(__dirname, '..', '..', '..', 'fixtures/phrase'),
|
|
23
24
|
},
|
|
24
25
|
);
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
describe('pull', () => {
|
|
28
|
-
|
|
29
|
-
(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
describe('pull translations', () => {
|
|
29
|
+
describe('when pulling translations for languages that already have translations', () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
(pullAllTranslations as jest.Mock).mockClear();
|
|
32
|
+
(writeFile as jest.Mock).mockClear();
|
|
33
|
+
});
|
|
34
|
+
(pullAllTranslations as jest.Mock).mockImplementation(() =>
|
|
35
|
+
Promise.resolve({
|
|
36
|
+
en: {
|
|
37
|
+
'hello.mytranslations': {
|
|
38
|
+
message: 'Hi there',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
fr: {
|
|
42
|
+
'hello.mytranslations': {
|
|
43
|
+
message: 'merci',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
34
48
|
|
|
35
|
-
|
|
49
|
+
const options = {
|
|
50
|
+
languages: [{ name: 'en' }, { name: 'fr' }],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
it('should resolve', async () => {
|
|
54
|
+
await expect(runPhrase(options)).resolves.toBeUndefined();
|
|
55
|
+
|
|
56
|
+
expect(writeFile as jest.Mock).toHaveBeenCalledTimes(2);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should update keys', async () => {
|
|
60
|
+
await expect(runPhrase(options)).resolves.toBeUndefined();
|
|
61
|
+
|
|
62
|
+
expect(
|
|
63
|
+
(writeFile as jest.Mock).mock.calls.map(
|
|
64
|
+
([_filePath, contents]: [string, string]) => JSON.parse(contents),
|
|
65
|
+
),
|
|
66
|
+
).toMatchInlineSnapshot(`
|
|
67
|
+
Array [
|
|
68
|
+
Object {
|
|
69
|
+
"hello": Object {
|
|
70
|
+
"message": "Hi there",
|
|
71
|
+
},
|
|
72
|
+
"world": Object {
|
|
73
|
+
"message": "world",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
Object {
|
|
77
|
+
"hello": Object {
|
|
78
|
+
"message": "merci",
|
|
79
|
+
},
|
|
80
|
+
"world": Object {
|
|
81
|
+
"message": "monde",
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
]
|
|
85
|
+
`);
|
|
86
|
+
});
|
|
36
87
|
});
|
|
37
|
-
|
|
88
|
+
|
|
89
|
+
describe('when pulling translations and some languages do not have any translations', () => {
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
(pullAllTranslations as jest.Mock).mockClear();
|
|
92
|
+
(writeFile as jest.Mock).mockClear();
|
|
93
|
+
});
|
|
38
94
|
(pullAllTranslations as jest.Mock).mockImplementation(() =>
|
|
39
95
|
Promise.resolve({
|
|
40
96
|
en: {
|
|
@@ -50,13 +106,24 @@ describe('pull', () => {
|
|
|
50
106
|
}),
|
|
51
107
|
);
|
|
52
108
|
|
|
53
|
-
|
|
109
|
+
const options = {
|
|
110
|
+
languages: [{ name: 'en' }, { name: 'fr' }, { name: 'ja' }],
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
it('should resolve', async () => {
|
|
114
|
+
await expect(runPhrase(options)).resolves.toBeUndefined();
|
|
115
|
+
|
|
116
|
+
expect(writeFile as jest.Mock).toHaveBeenCalledTimes(2);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should update keys', async () => {
|
|
120
|
+
await expect(runPhrase(options)).resolves.toBeUndefined();
|
|
54
121
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
122
|
+
expect(
|
|
123
|
+
(writeFile as jest.Mock).mock.calls.map(
|
|
124
|
+
([_filePath, contents]: [string, string]) => JSON.parse(contents),
|
|
125
|
+
),
|
|
126
|
+
).toMatchInlineSnapshot(`
|
|
60
127
|
Array [
|
|
61
128
|
Object {
|
|
62
129
|
"hello": Object {
|
|
@@ -76,5 +143,6 @@ describe('pull', () => {
|
|
|
76
143
|
},
|
|
77
144
|
]
|
|
78
145
|
`);
|
|
146
|
+
});
|
|
79
147
|
});
|
|
80
148
|
});
|
package/src/pull-translations.ts
CHANGED
|
@@ -59,41 +59,44 @@ export async function pull(
|
|
|
59
59
|
);
|
|
60
60
|
|
|
61
61
|
for (const alternativeLanguage of alternativeLanguages) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
if (alternativeLanguage in allPhraseTranslations) {
|
|
63
|
+
const altTranslations = {
|
|
64
|
+
...loadedTranslation.languages[alternativeLanguage],
|
|
65
|
+
};
|
|
66
|
+
const phraseAltTranslations =
|
|
67
|
+
allPhraseTranslations[alternativeLanguage];
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
for (const key of localKeys) {
|
|
70
|
+
const phraseKey = getUniqueKey(key, loadedTranslation.namespace);
|
|
71
|
+
const phraseTranslationMessage =
|
|
72
|
+
phraseAltTranslations[phraseKey]?.message;
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
if (!phraseTranslationMessage) {
|
|
75
|
+
trace(
|
|
76
|
+
`Missing translation. No translation for key ${key} in phrase as ${phraseKey} in language ${alternativeLanguage}.`,
|
|
77
|
+
);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
altTranslations[key] = {
|
|
82
|
+
...altTranslations[key],
|
|
83
|
+
message: phraseTranslationMessage,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
84
86
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
const altTranslationFilePath = getAltLanguageFilePath(
|
|
88
|
+
loadedTranslation.filePath,
|
|
89
|
+
alternativeLanguage,
|
|
90
|
+
);
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
await mkdir(path.dirname(altTranslationFilePath), {
|
|
93
|
+
recursive: true,
|
|
94
|
+
});
|
|
95
|
+
await writeFile(
|
|
96
|
+
altTranslationFilePath,
|
|
97
|
+
`${JSON.stringify(altTranslations, null, 2)}\n`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
102
|
}
|