@vocab/phrase 0.0.0-phrase-pull-dev-language-202281412540 → 0.0.0-tags-support-20231724743
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/dist/declarations/src/csv.d.ts +10 -0
- package/dist/declarations/src/phrase-api.d.ts +8 -3
- package/dist/declarations/src/pull-translations.d.ts +1 -0
- package/dist/declarations/src/push-translations.d.ts +4 -2
- package/dist/vocab-phrase.cjs.dev.js +121 -28
- package/dist/vocab-phrase.cjs.prod.js +121 -28
- package/dist/vocab-phrase.esm.js +121 -28
- package/package.json +8 -4
- package/CHANGELOG.md +0 -128
- package/src/file.ts +0 -4
- package/src/index.ts +0 -2
- package/src/logger.ts +0 -9
- package/src/phrase-api.ts +0 -147
- package/src/pull-translations.test.ts +0 -250
- package/src/pull-translations.ts +0 -119
- package/src/push-translations.test.ts +0 -77
- package/src/push-translations.ts +0 -55
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TranslationsByLanguage } from '@vocab/types';
|
|
2
|
+
export declare function translationsToCsv(translations: TranslationsByLanguage, devLanguage: string): {
|
|
3
|
+
csvString: string;
|
|
4
|
+
localeMapping: {
|
|
5
|
+
[k: string]: number;
|
|
6
|
+
};
|
|
7
|
+
keyIndex: number;
|
|
8
|
+
commentIndex: number;
|
|
9
|
+
tagColumn: number;
|
|
10
|
+
};
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { TranslationsByKey } from './../../types/src/index';
|
|
2
1
|
import type { TranslationsByLanguage } from '@vocab/types';
|
|
3
2
|
import fetch from 'node-fetch';
|
|
4
|
-
export declare function callPhrase(relativePath: string, options?: Parameters<typeof fetch>[1]): Promise<
|
|
3
|
+
export declare function callPhrase<T = any>(relativePath: string, options?: Parameters<typeof fetch>[1]): Promise<T>;
|
|
5
4
|
export declare function pullAllTranslations(branch: string): Promise<TranslationsByLanguage>;
|
|
6
|
-
export declare function
|
|
5
|
+
export declare function pushTranslations(translationsByLanguage: TranslationsByLanguage, { devLanguage, branch }: {
|
|
6
|
+
devLanguage: string;
|
|
7
|
+
branch: string;
|
|
8
|
+
}): Promise<{
|
|
9
|
+
uploadId: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function deleteUnusedKeys(uploadId: string, branch: string): Promise<void>;
|
|
7
12
|
export declare function ensureBranch(branch: string): Promise<void>;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { UserConfig } from '@vocab/types';
|
|
2
2
|
interface PushOptions {
|
|
3
3
|
branch: string;
|
|
4
|
+
deleteUnusedKeys?: boolean;
|
|
4
5
|
}
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
+
* Uploads translations to the Phrase API for each language.
|
|
8
|
+
* A unique namespace is appended to each key using the file path the key came from.
|
|
7
9
|
*/
|
|
8
|
-
export declare function push({ branch }: PushOptions, config: UserConfig): Promise<void>;
|
|
10
|
+
export declare function push({ branch, deleteUnusedKeys }: PushOptions, config: UserConfig): Promise<void>;
|
|
9
11
|
export {};
|
|
@@ -9,6 +9,7 @@ var FormData = require('form-data');
|
|
|
9
9
|
var fetch = require('node-fetch');
|
|
10
10
|
var chalk = require('chalk');
|
|
11
11
|
var debug = require('debug');
|
|
12
|
+
var sync = require('csv-stringify/sync');
|
|
12
13
|
|
|
13
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
14
15
|
|
|
@@ -27,6 +28,44 @@ const log = (...params) => {
|
|
|
27
28
|
console.log(chalk__default['default'].yellow('Vocab'), ...params);
|
|
28
29
|
};
|
|
29
30
|
|
|
31
|
+
function translationsToCsv(translations, devLanguage) {
|
|
32
|
+
const languages = Object.keys(translations);
|
|
33
|
+
const altLanguages = languages.filter(language => language !== devLanguage);
|
|
34
|
+
const devLanguageTranslations = translations[devLanguage];
|
|
35
|
+
const csv = Object.entries(devLanguageTranslations).map(([key, {
|
|
36
|
+
message,
|
|
37
|
+
description,
|
|
38
|
+
tags
|
|
39
|
+
}]) => {
|
|
40
|
+
const altTranslationMessages = altLanguages.map(language => {
|
|
41
|
+
var _translations$languag, _translations$languag2;
|
|
42
|
+
|
|
43
|
+
return (_translations$languag = translations[language]) === null || _translations$languag === void 0 ? void 0 : (_translations$languag2 = _translations$languag[key]) === null || _translations$languag2 === void 0 ? void 0 : _translations$languag2.message;
|
|
44
|
+
});
|
|
45
|
+
return [message, ...altTranslationMessages, key, description, tags === null || tags === void 0 ? void 0 : tags.join(',')];
|
|
46
|
+
}); // Not spreading `languages` to ensure correct ordering of dev language first
|
|
47
|
+
// then alt languages
|
|
48
|
+
|
|
49
|
+
const csvString = sync.stringify(csv, {
|
|
50
|
+
delimiter: ',',
|
|
51
|
+
header: false
|
|
52
|
+
}); // Column indices start at 1
|
|
53
|
+
|
|
54
|
+
const localeMapping = Object.fromEntries(languages.map((language, index) => [language, index + 1]));
|
|
55
|
+
const keyIndex = languages.length + 1;
|
|
56
|
+
const commentIndex = keyIndex + 1;
|
|
57
|
+
const tagColumn = commentIndex + 1;
|
|
58
|
+
return {
|
|
59
|
+
csvString,
|
|
60
|
+
localeMapping,
|
|
61
|
+
keyIndex,
|
|
62
|
+
commentIndex,
|
|
63
|
+
tagColumn
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* eslint-disable no-console */
|
|
68
|
+
|
|
30
69
|
function _callPhrase(path, options = {}) {
|
|
31
70
|
const phraseApiToken = process.env.PHRASE_API_TOKEN;
|
|
32
71
|
|
|
@@ -44,14 +83,14 @@ function _callPhrase(path, options = {}) {
|
|
|
44
83
|
}).then(async response => {
|
|
45
84
|
console.log(`${path}: ${response.status} - ${response.statusText}`);
|
|
46
85
|
console.log(`Rate Limit: ${response.headers.get('X-Rate-Limit-Remaining')} of ${response.headers.get('X-Rate-Limit-Limit')} remaining. (${response.headers.get('X-Rate-Limit-Reset')} seconds remaining})`);
|
|
47
|
-
|
|
86
|
+
trace('\nLink:', response.headers.get('Link'), '\n'); // Print All Headers:
|
|
48
87
|
// console.log(Array.from(r.headers.entries()));
|
|
49
88
|
|
|
50
89
|
try {
|
|
51
90
|
var _response$headers$get;
|
|
52
91
|
|
|
53
92
|
const result = await response.json();
|
|
54
|
-
|
|
93
|
+
trace(`Internal Result (Length: ${result.length})\n`);
|
|
55
94
|
|
|
56
95
|
if ((!options.method || options.method === 'GET') && (_response$headers$get = response.headers.get('Link')) !== null && _response$headers$get !== void 0 && _response$headers$get.includes('rel=next')) {
|
|
57
96
|
var _response$headers$get2, _response$headers$get3;
|
|
@@ -59,10 +98,10 @@ function _callPhrase(path, options = {}) {
|
|
|
59
98
|
const [, nextPageUrl] = (_response$headers$get2 = (_response$headers$get3 = response.headers.get('Link')) === null || _response$headers$get3 === void 0 ? void 0 : _response$headers$get3.match(/<([^>]*)>; rel=next/)) !== null && _response$headers$get2 !== void 0 ? _response$headers$get2 : [];
|
|
60
99
|
|
|
61
100
|
if (!nextPageUrl) {
|
|
62
|
-
throw new Error('
|
|
101
|
+
throw new Error("Can't parse next page URL");
|
|
63
102
|
}
|
|
64
103
|
|
|
65
|
-
console.log('Results
|
|
104
|
+
console.log('Results received with next page: ', nextPageUrl);
|
|
66
105
|
const nextPageResult = await _callPhrase(nextPageUrl, options);
|
|
67
106
|
return [...result, ...nextPageResult];
|
|
68
107
|
}
|
|
@@ -109,23 +148,73 @@ async function pullAllTranslations(branch) {
|
|
|
109
148
|
|
|
110
149
|
return translations;
|
|
111
150
|
}
|
|
112
|
-
async function
|
|
151
|
+
async function pushTranslations(translationsByLanguage, {
|
|
152
|
+
devLanguage,
|
|
153
|
+
branch
|
|
154
|
+
}) {
|
|
113
155
|
const formData = new FormData__default['default']();
|
|
114
|
-
const
|
|
156
|
+
const {
|
|
157
|
+
csvString,
|
|
158
|
+
localeMapping,
|
|
159
|
+
keyIndex,
|
|
160
|
+
commentIndex,
|
|
161
|
+
tagColumn
|
|
162
|
+
} = translationsToCsv(translationsByLanguage, devLanguage);
|
|
163
|
+
const fileContents = Buffer.from(csvString);
|
|
115
164
|
formData.append('file', fileContents, {
|
|
116
|
-
contentType: '
|
|
117
|
-
filename:
|
|
165
|
+
contentType: 'text/csv',
|
|
166
|
+
filename: `translations.csv`
|
|
118
167
|
});
|
|
119
|
-
formData.append('file_format', '
|
|
120
|
-
formData.append('locale_id', locale);
|
|
168
|
+
formData.append('file_format', 'csv');
|
|
121
169
|
formData.append('branch', branch);
|
|
122
170
|
formData.append('update_translations', 'true');
|
|
123
|
-
|
|
124
|
-
|
|
171
|
+
|
|
172
|
+
for (const [locale, index] of Object.entries(localeMapping)) {
|
|
173
|
+
formData.append(`locale_mapping[${locale}]`, index);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
formData.append('format_options[key_index]', keyIndex);
|
|
177
|
+
formData.append('format_options[comment_index]', commentIndex);
|
|
178
|
+
formData.append('format_options[tag_column]', tagColumn);
|
|
179
|
+
formData.append('format_options[enable_pluralization]', 'false');
|
|
180
|
+
log('Uploading translations');
|
|
181
|
+
const res = await callPhrase(`uploads`, {
|
|
125
182
|
method: 'POST',
|
|
126
183
|
body: formData
|
|
127
184
|
});
|
|
128
|
-
|
|
185
|
+
trace('Upload result:\n', res); // TODO: Figure out error handling
|
|
186
|
+
|
|
187
|
+
const {
|
|
188
|
+
id
|
|
189
|
+
} = res;
|
|
190
|
+
|
|
191
|
+
if (id) {
|
|
192
|
+
log('Upload ID:', id, '\n');
|
|
193
|
+
log('Successfully Uploaded\n');
|
|
194
|
+
} else {
|
|
195
|
+
log('Error uploading');
|
|
196
|
+
throw new Error('Error uploading');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
uploadId: id
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
async function deleteUnusedKeys(uploadId, branch) {
|
|
204
|
+
const query = `unmentioned_in_upload:${uploadId}`;
|
|
205
|
+
const {
|
|
206
|
+
records_affected
|
|
207
|
+
} = await callPhrase('keys', {
|
|
208
|
+
method: 'DELETE',
|
|
209
|
+
headers: {
|
|
210
|
+
'Content-Type': 'application/json'
|
|
211
|
+
},
|
|
212
|
+
body: JSON.stringify({
|
|
213
|
+
branch,
|
|
214
|
+
q: query
|
|
215
|
+
})
|
|
216
|
+
});
|
|
217
|
+
log('Successfully deleted', records_affected, 'unused keys from branch', branch);
|
|
129
218
|
}
|
|
130
219
|
async function ensureBranch(branch) {
|
|
131
220
|
await callPhrase(`branches`, {
|
|
@@ -137,7 +226,7 @@ async function ensureBranch(branch) {
|
|
|
137
226
|
name: branch
|
|
138
227
|
})
|
|
139
228
|
});
|
|
140
|
-
|
|
229
|
+
log('Created branch:', branch);
|
|
141
230
|
}
|
|
142
231
|
|
|
143
232
|
async function pull({
|
|
@@ -149,14 +238,10 @@ async function pull({
|
|
|
149
238
|
const allPhraseTranslations = await pullAllTranslations(branch);
|
|
150
239
|
trace(`Pulling translations from Phrase for languages ${config.devLanguage} and ${alternativeLanguages.join(', ')}`);
|
|
151
240
|
const phraseLanguages = Object.keys(allPhraseTranslations);
|
|
152
|
-
|
|
153
|
-
const phraseTranslationsForLanguage = allPhraseTranslations[language];
|
|
154
|
-
return Object.keys(phraseTranslationsForLanguage).length > 0;
|
|
155
|
-
});
|
|
156
|
-
trace(`Found Phrase translations for languages ${phraseLanguagesWithTranslations.join(', ')}`);
|
|
241
|
+
trace(`Found Phrase translations for languages ${phraseLanguages.join(', ')}`);
|
|
157
242
|
|
|
158
|
-
if (!
|
|
159
|
-
throw new Error(`Phrase did not return any translations for
|
|
243
|
+
if (!phraseLanguages.includes(config.devLanguage)) {
|
|
244
|
+
throw new Error(`Phrase did not return any translations for the configured development language "${config.devLanguage}".\nPlease ensure this language is present in your Phrase project's configuration.`);
|
|
160
245
|
}
|
|
161
246
|
|
|
162
247
|
const allVocabTranslations = await core.loadAllTranslations({
|
|
@@ -216,14 +301,17 @@ async function pull({
|
|
|
216
301
|
}
|
|
217
302
|
|
|
218
303
|
/**
|
|
219
|
-
*
|
|
304
|
+
* Uploads translations to the Phrase API for each language.
|
|
305
|
+
* A unique namespace is appended to each key using the file path the key came from.
|
|
220
306
|
*/
|
|
221
307
|
async function push({
|
|
222
|
-
branch
|
|
308
|
+
branch,
|
|
309
|
+
deleteUnusedKeys: deleteUnusedKeys$1
|
|
223
310
|
}, config) {
|
|
224
311
|
const allLanguageTranslations = await core.loadAllTranslations({
|
|
225
312
|
fallbacks: 'none',
|
|
226
|
-
includeNodeModules: false
|
|
313
|
+
includeNodeModules: false,
|
|
314
|
+
withTags: true
|
|
227
315
|
}, config);
|
|
228
316
|
trace(`Pushing translations to branch ${branch}`);
|
|
229
317
|
const allLanguages = config.languages.map(v => v.name);
|
|
@@ -250,10 +338,15 @@ async function push({
|
|
|
250
338
|
}
|
|
251
339
|
}
|
|
252
340
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
341
|
+
const {
|
|
342
|
+
uploadId
|
|
343
|
+
} = await pushTranslations(phraseTranslations, {
|
|
344
|
+
devLanguage: config.devLanguage,
|
|
345
|
+
branch
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
if (deleteUnusedKeys$1) {
|
|
349
|
+
await deleteUnusedKeys(uploadId, branch);
|
|
257
350
|
}
|
|
258
351
|
}
|
|
259
352
|
|
|
@@ -9,6 +9,7 @@ var FormData = require('form-data');
|
|
|
9
9
|
var fetch = require('node-fetch');
|
|
10
10
|
var chalk = require('chalk');
|
|
11
11
|
var debug = require('debug');
|
|
12
|
+
var sync = require('csv-stringify/sync');
|
|
12
13
|
|
|
13
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
14
15
|
|
|
@@ -27,6 +28,44 @@ const log = (...params) => {
|
|
|
27
28
|
console.log(chalk__default['default'].yellow('Vocab'), ...params);
|
|
28
29
|
};
|
|
29
30
|
|
|
31
|
+
function translationsToCsv(translations, devLanguage) {
|
|
32
|
+
const languages = Object.keys(translations);
|
|
33
|
+
const altLanguages = languages.filter(language => language !== devLanguage);
|
|
34
|
+
const devLanguageTranslations = translations[devLanguage];
|
|
35
|
+
const csv = Object.entries(devLanguageTranslations).map(([key, {
|
|
36
|
+
message,
|
|
37
|
+
description,
|
|
38
|
+
tags
|
|
39
|
+
}]) => {
|
|
40
|
+
const altTranslationMessages = altLanguages.map(language => {
|
|
41
|
+
var _translations$languag, _translations$languag2;
|
|
42
|
+
|
|
43
|
+
return (_translations$languag = translations[language]) === null || _translations$languag === void 0 ? void 0 : (_translations$languag2 = _translations$languag[key]) === null || _translations$languag2 === void 0 ? void 0 : _translations$languag2.message;
|
|
44
|
+
});
|
|
45
|
+
return [message, ...altTranslationMessages, key, description, tags === null || tags === void 0 ? void 0 : tags.join(',')];
|
|
46
|
+
}); // Not spreading `languages` to ensure correct ordering of dev language first
|
|
47
|
+
// then alt languages
|
|
48
|
+
|
|
49
|
+
const csvString = sync.stringify(csv, {
|
|
50
|
+
delimiter: ',',
|
|
51
|
+
header: false
|
|
52
|
+
}); // Column indices start at 1
|
|
53
|
+
|
|
54
|
+
const localeMapping = Object.fromEntries(languages.map((language, index) => [language, index + 1]));
|
|
55
|
+
const keyIndex = languages.length + 1;
|
|
56
|
+
const commentIndex = keyIndex + 1;
|
|
57
|
+
const tagColumn = commentIndex + 1;
|
|
58
|
+
return {
|
|
59
|
+
csvString,
|
|
60
|
+
localeMapping,
|
|
61
|
+
keyIndex,
|
|
62
|
+
commentIndex,
|
|
63
|
+
tagColumn
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* eslint-disable no-console */
|
|
68
|
+
|
|
30
69
|
function _callPhrase(path, options = {}) {
|
|
31
70
|
const phraseApiToken = process.env.PHRASE_API_TOKEN;
|
|
32
71
|
|
|
@@ -44,14 +83,14 @@ function _callPhrase(path, options = {}) {
|
|
|
44
83
|
}).then(async response => {
|
|
45
84
|
console.log(`${path}: ${response.status} - ${response.statusText}`);
|
|
46
85
|
console.log(`Rate Limit: ${response.headers.get('X-Rate-Limit-Remaining')} of ${response.headers.get('X-Rate-Limit-Limit')} remaining. (${response.headers.get('X-Rate-Limit-Reset')} seconds remaining})`);
|
|
47
|
-
|
|
86
|
+
trace('\nLink:', response.headers.get('Link'), '\n'); // Print All Headers:
|
|
48
87
|
// console.log(Array.from(r.headers.entries()));
|
|
49
88
|
|
|
50
89
|
try {
|
|
51
90
|
var _response$headers$get;
|
|
52
91
|
|
|
53
92
|
const result = await response.json();
|
|
54
|
-
|
|
93
|
+
trace(`Internal Result (Length: ${result.length})\n`);
|
|
55
94
|
|
|
56
95
|
if ((!options.method || options.method === 'GET') && (_response$headers$get = response.headers.get('Link')) !== null && _response$headers$get !== void 0 && _response$headers$get.includes('rel=next')) {
|
|
57
96
|
var _response$headers$get2, _response$headers$get3;
|
|
@@ -59,10 +98,10 @@ function _callPhrase(path, options = {}) {
|
|
|
59
98
|
const [, nextPageUrl] = (_response$headers$get2 = (_response$headers$get3 = response.headers.get('Link')) === null || _response$headers$get3 === void 0 ? void 0 : _response$headers$get3.match(/<([^>]*)>; rel=next/)) !== null && _response$headers$get2 !== void 0 ? _response$headers$get2 : [];
|
|
60
99
|
|
|
61
100
|
if (!nextPageUrl) {
|
|
62
|
-
throw new Error('
|
|
101
|
+
throw new Error("Can't parse next page URL");
|
|
63
102
|
}
|
|
64
103
|
|
|
65
|
-
console.log('Results
|
|
104
|
+
console.log('Results received with next page: ', nextPageUrl);
|
|
66
105
|
const nextPageResult = await _callPhrase(nextPageUrl, options);
|
|
67
106
|
return [...result, ...nextPageResult];
|
|
68
107
|
}
|
|
@@ -109,23 +148,73 @@ async function pullAllTranslations(branch) {
|
|
|
109
148
|
|
|
110
149
|
return translations;
|
|
111
150
|
}
|
|
112
|
-
async function
|
|
151
|
+
async function pushTranslations(translationsByLanguage, {
|
|
152
|
+
devLanguage,
|
|
153
|
+
branch
|
|
154
|
+
}) {
|
|
113
155
|
const formData = new FormData__default['default']();
|
|
114
|
-
const
|
|
156
|
+
const {
|
|
157
|
+
csvString,
|
|
158
|
+
localeMapping,
|
|
159
|
+
keyIndex,
|
|
160
|
+
commentIndex,
|
|
161
|
+
tagColumn
|
|
162
|
+
} = translationsToCsv(translationsByLanguage, devLanguage);
|
|
163
|
+
const fileContents = Buffer.from(csvString);
|
|
115
164
|
formData.append('file', fileContents, {
|
|
116
|
-
contentType: '
|
|
117
|
-
filename:
|
|
165
|
+
contentType: 'text/csv',
|
|
166
|
+
filename: `translations.csv`
|
|
118
167
|
});
|
|
119
|
-
formData.append('file_format', '
|
|
120
|
-
formData.append('locale_id', locale);
|
|
168
|
+
formData.append('file_format', 'csv');
|
|
121
169
|
formData.append('branch', branch);
|
|
122
170
|
formData.append('update_translations', 'true');
|
|
123
|
-
|
|
124
|
-
|
|
171
|
+
|
|
172
|
+
for (const [locale, index] of Object.entries(localeMapping)) {
|
|
173
|
+
formData.append(`locale_mapping[${locale}]`, index);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
formData.append('format_options[key_index]', keyIndex);
|
|
177
|
+
formData.append('format_options[comment_index]', commentIndex);
|
|
178
|
+
formData.append('format_options[tag_column]', tagColumn);
|
|
179
|
+
formData.append('format_options[enable_pluralization]', 'false');
|
|
180
|
+
log('Uploading translations');
|
|
181
|
+
const res = await callPhrase(`uploads`, {
|
|
125
182
|
method: 'POST',
|
|
126
183
|
body: formData
|
|
127
184
|
});
|
|
128
|
-
|
|
185
|
+
trace('Upload result:\n', res); // TODO: Figure out error handling
|
|
186
|
+
|
|
187
|
+
const {
|
|
188
|
+
id
|
|
189
|
+
} = res;
|
|
190
|
+
|
|
191
|
+
if (id) {
|
|
192
|
+
log('Upload ID:', id, '\n');
|
|
193
|
+
log('Successfully Uploaded\n');
|
|
194
|
+
} else {
|
|
195
|
+
log('Error uploading');
|
|
196
|
+
throw new Error('Error uploading');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
uploadId: id
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
async function deleteUnusedKeys(uploadId, branch) {
|
|
204
|
+
const query = `unmentioned_in_upload:${uploadId}`;
|
|
205
|
+
const {
|
|
206
|
+
records_affected
|
|
207
|
+
} = await callPhrase('keys', {
|
|
208
|
+
method: 'DELETE',
|
|
209
|
+
headers: {
|
|
210
|
+
'Content-Type': 'application/json'
|
|
211
|
+
},
|
|
212
|
+
body: JSON.stringify({
|
|
213
|
+
branch,
|
|
214
|
+
q: query
|
|
215
|
+
})
|
|
216
|
+
});
|
|
217
|
+
log('Successfully deleted', records_affected, 'unused keys from branch', branch);
|
|
129
218
|
}
|
|
130
219
|
async function ensureBranch(branch) {
|
|
131
220
|
await callPhrase(`branches`, {
|
|
@@ -137,7 +226,7 @@ async function ensureBranch(branch) {
|
|
|
137
226
|
name: branch
|
|
138
227
|
})
|
|
139
228
|
});
|
|
140
|
-
|
|
229
|
+
log('Created branch:', branch);
|
|
141
230
|
}
|
|
142
231
|
|
|
143
232
|
async function pull({
|
|
@@ -149,14 +238,10 @@ async function pull({
|
|
|
149
238
|
const allPhraseTranslations = await pullAllTranslations(branch);
|
|
150
239
|
trace(`Pulling translations from Phrase for languages ${config.devLanguage} and ${alternativeLanguages.join(', ')}`);
|
|
151
240
|
const phraseLanguages = Object.keys(allPhraseTranslations);
|
|
152
|
-
|
|
153
|
-
const phraseTranslationsForLanguage = allPhraseTranslations[language];
|
|
154
|
-
return Object.keys(phraseTranslationsForLanguage).length > 0;
|
|
155
|
-
});
|
|
156
|
-
trace(`Found Phrase translations for languages ${phraseLanguagesWithTranslations.join(', ')}`);
|
|
241
|
+
trace(`Found Phrase translations for languages ${phraseLanguages.join(', ')}`);
|
|
157
242
|
|
|
158
|
-
if (!
|
|
159
|
-
throw new Error(`Phrase did not return any translations for
|
|
243
|
+
if (!phraseLanguages.includes(config.devLanguage)) {
|
|
244
|
+
throw new Error(`Phrase did not return any translations for the configured development language "${config.devLanguage}".\nPlease ensure this language is present in your Phrase project's configuration.`);
|
|
160
245
|
}
|
|
161
246
|
|
|
162
247
|
const allVocabTranslations = await core.loadAllTranslations({
|
|
@@ -216,14 +301,17 @@ async function pull({
|
|
|
216
301
|
}
|
|
217
302
|
|
|
218
303
|
/**
|
|
219
|
-
*
|
|
304
|
+
* Uploads translations to the Phrase API for each language.
|
|
305
|
+
* A unique namespace is appended to each key using the file path the key came from.
|
|
220
306
|
*/
|
|
221
307
|
async function push({
|
|
222
|
-
branch
|
|
308
|
+
branch,
|
|
309
|
+
deleteUnusedKeys: deleteUnusedKeys$1
|
|
223
310
|
}, config) {
|
|
224
311
|
const allLanguageTranslations = await core.loadAllTranslations({
|
|
225
312
|
fallbacks: 'none',
|
|
226
|
-
includeNodeModules: false
|
|
313
|
+
includeNodeModules: false,
|
|
314
|
+
withTags: true
|
|
227
315
|
}, config);
|
|
228
316
|
trace(`Pushing translations to branch ${branch}`);
|
|
229
317
|
const allLanguages = config.languages.map(v => v.name);
|
|
@@ -250,10 +338,15 @@ async function push({
|
|
|
250
338
|
}
|
|
251
339
|
}
|
|
252
340
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
341
|
+
const {
|
|
342
|
+
uploadId
|
|
343
|
+
} = await pushTranslations(phraseTranslations, {
|
|
344
|
+
devLanguage: config.devLanguage,
|
|
345
|
+
branch
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
if (deleteUnusedKeys$1) {
|
|
349
|
+
await deleteUnusedKeys(uploadId, branch);
|
|
257
350
|
}
|
|
258
351
|
}
|
|
259
352
|
|