@vocab/phrase 0.0.0-package-files-20231142931 → 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.
@@ -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,10 +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
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 pushTranslationsByLocale(contents: TranslationsByKey, locale: string, branch: string): Promise<{
5
+ export declare function pushTranslations(translationsByLanguage: TranslationsByLanguage, { devLanguage, branch }: {
6
+ devLanguage: string;
7
+ branch: string;
8
+ }): Promise<{
7
9
  uploadId: string;
8
10
  }>;
9
- export declare function deleteUnusedKeys(uploadId: string, locale: string, branch: string): Promise<void>;
11
+ export declare function deleteUnusedKeys(uploadId: string, branch: string): Promise<void>;
10
12
  export declare function ensureBranch(branch: string): Promise<void>;
@@ -4,7 +4,8 @@ interface PushOptions {
4
4
  deleteUnusedKeys?: boolean;
5
5
  }
6
6
  /**
7
- * Uploading to the Phrase API for each language. Adding a unique namespace to each key using file path they key came from
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.
8
9
  */
9
10
  export declare function push({ branch, deleteUnusedKeys }: PushOptions, config: UserConfig): Promise<void>;
10
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
 
@@ -109,31 +148,59 @@ async function pullAllTranslations(branch) {
109
148
 
110
149
  return translations;
111
150
  }
112
- async function pushTranslationsByLocale(contents, locale, branch) {
151
+ async function pushTranslations(translationsByLanguage, {
152
+ devLanguage,
153
+ branch
154
+ }) {
113
155
  const formData = new FormData__default['default']();
114
- const fileContents = Buffer.from(JSON.stringify(contents));
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: 'application/json',
117
- filename: `${locale}.json`
165
+ contentType: 'text/csv',
166
+ filename: `translations.csv`
118
167
  });
119
- formData.append('file_format', 'json');
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
- log('Starting to upload:', locale, '\n');
124
- const {
125
- id
126
- } = await callPhrase(`uploads`, {
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`, {
127
182
  method: 'POST',
128
183
  body: formData
129
184
  });
130
- log('Upload ID:', id, '\n');
131
- log('Successfully Uploaded:', locale, '\n');
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
+
132
199
  return {
133
200
  uploadId: id
134
201
  };
135
202
  }
136
- async function deleteUnusedKeys(uploadId, locale, branch) {
203
+ async function deleteUnusedKeys(uploadId, branch) {
137
204
  const query = `unmentioned_in_upload:${uploadId}`;
138
205
  const {
139
206
  records_affected
@@ -144,7 +211,6 @@ async function deleteUnusedKeys(uploadId, locale, branch) {
144
211
  },
145
212
  body: JSON.stringify({
146
213
  branch,
147
- locale_id: locale,
148
214
  q: query
149
215
  })
150
216
  });
@@ -235,7 +301,8 @@ async function pull({
235
301
  }
236
302
 
237
303
  /**
238
- * Uploading to the Phrase API for each language. Adding a unique namespace to each key using file path they key came from
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.
239
306
  */
240
307
  async function push({
241
308
  branch,
@@ -243,7 +310,8 @@ async function push({
243
310
  }, config) {
244
311
  const allLanguageTranslations = await core.loadAllTranslations({
245
312
  fallbacks: 'none',
246
- includeNodeModules: false
313
+ includeNodeModules: false,
314
+ withTags: true
247
315
  }, config);
248
316
  trace(`Pushing translations to branch ${branch}`);
249
317
  const allLanguages = config.languages.map(v => v.name);
@@ -270,16 +338,15 @@ async function push({
270
338
  }
271
339
  }
272
340
 
273
- for (const language of allLanguages) {
274
- if (phraseTranslations[language]) {
275
- const {
276
- uploadId
277
- } = await pushTranslationsByLocale(phraseTranslations[language], language, branch);
341
+ const {
342
+ uploadId
343
+ } = await pushTranslations(phraseTranslations, {
344
+ devLanguage: config.devLanguage,
345
+ branch
346
+ });
278
347
 
279
- if (deleteUnusedKeys$1) {
280
- await deleteUnusedKeys(uploadId, language, branch);
281
- }
282
- }
348
+ if (deleteUnusedKeys$1) {
349
+ await deleteUnusedKeys(uploadId, branch);
283
350
  }
284
351
  }
285
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
 
@@ -109,31 +148,59 @@ async function pullAllTranslations(branch) {
109
148
 
110
149
  return translations;
111
150
  }
112
- async function pushTranslationsByLocale(contents, locale, branch) {
151
+ async function pushTranslations(translationsByLanguage, {
152
+ devLanguage,
153
+ branch
154
+ }) {
113
155
  const formData = new FormData__default['default']();
114
- const fileContents = Buffer.from(JSON.stringify(contents));
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: 'application/json',
117
- filename: `${locale}.json`
165
+ contentType: 'text/csv',
166
+ filename: `translations.csv`
118
167
  });
119
- formData.append('file_format', 'json');
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
- log('Starting to upload:', locale, '\n');
124
- const {
125
- id
126
- } = await callPhrase(`uploads`, {
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`, {
127
182
  method: 'POST',
128
183
  body: formData
129
184
  });
130
- log('Upload ID:', id, '\n');
131
- log('Successfully Uploaded:', locale, '\n');
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
+
132
199
  return {
133
200
  uploadId: id
134
201
  };
135
202
  }
136
- async function deleteUnusedKeys(uploadId, locale, branch) {
203
+ async function deleteUnusedKeys(uploadId, branch) {
137
204
  const query = `unmentioned_in_upload:${uploadId}`;
138
205
  const {
139
206
  records_affected
@@ -144,7 +211,6 @@ async function deleteUnusedKeys(uploadId, locale, branch) {
144
211
  },
145
212
  body: JSON.stringify({
146
213
  branch,
147
- locale_id: locale,
148
214
  q: query
149
215
  })
150
216
  });
@@ -235,7 +301,8 @@ async function pull({
235
301
  }
236
302
 
237
303
  /**
238
- * Uploading to the Phrase API for each language. Adding a unique namespace to each key using file path they key came from
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.
239
306
  */
240
307
  async function push({
241
308
  branch,
@@ -243,7 +310,8 @@ async function push({
243
310
  }, config) {
244
311
  const allLanguageTranslations = await core.loadAllTranslations({
245
312
  fallbacks: 'none',
246
- includeNodeModules: false
313
+ includeNodeModules: false,
314
+ withTags: true
247
315
  }, config);
248
316
  trace(`Pushing translations to branch ${branch}`);
249
317
  const allLanguages = config.languages.map(v => v.name);
@@ -270,16 +338,15 @@ async function push({
270
338
  }
271
339
  }
272
340
 
273
- for (const language of allLanguages) {
274
- if (phraseTranslations[language]) {
275
- const {
276
- uploadId
277
- } = await pushTranslationsByLocale(phraseTranslations[language], language, branch);
341
+ const {
342
+ uploadId
343
+ } = await pushTranslations(phraseTranslations, {
344
+ devLanguage: config.devLanguage,
345
+ branch
346
+ });
278
347
 
279
- if (deleteUnusedKeys$1) {
280
- await deleteUnusedKeys(uploadId, language, branch);
281
- }
282
- }
348
+ if (deleteUnusedKeys$1) {
349
+ await deleteUnusedKeys(uploadId, branch);
283
350
  }
284
351
  }
285
352
 
@@ -5,6 +5,7 @@ import FormData from 'form-data';
5
5
  import fetch from 'node-fetch';
6
6
  import chalk from 'chalk';
7
7
  import debug from 'debug';
8
+ import { stringify } from 'csv-stringify/sync';
8
9
 
9
10
  const mkdir = promises.mkdir;
10
11
  const writeFile = promises.writeFile;
@@ -15,6 +16,44 @@ const log = (...params) => {
15
16
  console.log(chalk.yellow('Vocab'), ...params);
16
17
  };
17
18
 
19
+ function translationsToCsv(translations, devLanguage) {
20
+ const languages = Object.keys(translations);
21
+ const altLanguages = languages.filter(language => language !== devLanguage);
22
+ const devLanguageTranslations = translations[devLanguage];
23
+ const csv = Object.entries(devLanguageTranslations).map(([key, {
24
+ message,
25
+ description,
26
+ tags
27
+ }]) => {
28
+ const altTranslationMessages = altLanguages.map(language => {
29
+ var _translations$languag, _translations$languag2;
30
+
31
+ 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;
32
+ });
33
+ return [message, ...altTranslationMessages, key, description, tags === null || tags === void 0 ? void 0 : tags.join(',')];
34
+ }); // Not spreading `languages` to ensure correct ordering of dev language first
35
+ // then alt languages
36
+
37
+ const csvString = stringify(csv, {
38
+ delimiter: ',',
39
+ header: false
40
+ }); // Column indices start at 1
41
+
42
+ const localeMapping = Object.fromEntries(languages.map((language, index) => [language, index + 1]));
43
+ const keyIndex = languages.length + 1;
44
+ const commentIndex = keyIndex + 1;
45
+ const tagColumn = commentIndex + 1;
46
+ return {
47
+ csvString,
48
+ localeMapping,
49
+ keyIndex,
50
+ commentIndex,
51
+ tagColumn
52
+ };
53
+ }
54
+
55
+ /* eslint-disable no-console */
56
+
18
57
  function _callPhrase(path, options = {}) {
19
58
  const phraseApiToken = process.env.PHRASE_API_TOKEN;
20
59
 
@@ -97,31 +136,59 @@ async function pullAllTranslations(branch) {
97
136
 
98
137
  return translations;
99
138
  }
100
- async function pushTranslationsByLocale(contents, locale, branch) {
139
+ async function pushTranslations(translationsByLanguage, {
140
+ devLanguage,
141
+ branch
142
+ }) {
101
143
  const formData = new FormData();
102
- const fileContents = Buffer.from(JSON.stringify(contents));
144
+ const {
145
+ csvString,
146
+ localeMapping,
147
+ keyIndex,
148
+ commentIndex,
149
+ tagColumn
150
+ } = translationsToCsv(translationsByLanguage, devLanguage);
151
+ const fileContents = Buffer.from(csvString);
103
152
  formData.append('file', fileContents, {
104
- contentType: 'application/json',
105
- filename: `${locale}.json`
153
+ contentType: 'text/csv',
154
+ filename: `translations.csv`
106
155
  });
107
- formData.append('file_format', 'json');
108
- formData.append('locale_id', locale);
156
+ formData.append('file_format', 'csv');
109
157
  formData.append('branch', branch);
110
158
  formData.append('update_translations', 'true');
111
- log('Starting to upload:', locale, '\n');
112
- const {
113
- id
114
- } = await callPhrase(`uploads`, {
159
+
160
+ for (const [locale, index] of Object.entries(localeMapping)) {
161
+ formData.append(`locale_mapping[${locale}]`, index);
162
+ }
163
+
164
+ formData.append('format_options[key_index]', keyIndex);
165
+ formData.append('format_options[comment_index]', commentIndex);
166
+ formData.append('format_options[tag_column]', tagColumn);
167
+ formData.append('format_options[enable_pluralization]', 'false');
168
+ log('Uploading translations');
169
+ const res = await callPhrase(`uploads`, {
115
170
  method: 'POST',
116
171
  body: formData
117
172
  });
118
- log('Upload ID:', id, '\n');
119
- log('Successfully Uploaded:', locale, '\n');
173
+ trace('Upload result:\n', res); // TODO: Figure out error handling
174
+
175
+ const {
176
+ id
177
+ } = res;
178
+
179
+ if (id) {
180
+ log('Upload ID:', id, '\n');
181
+ log('Successfully Uploaded\n');
182
+ } else {
183
+ log('Error uploading');
184
+ throw new Error('Error uploading');
185
+ }
186
+
120
187
  return {
121
188
  uploadId: id
122
189
  };
123
190
  }
124
- async function deleteUnusedKeys(uploadId, locale, branch) {
191
+ async function deleteUnusedKeys(uploadId, branch) {
125
192
  const query = `unmentioned_in_upload:${uploadId}`;
126
193
  const {
127
194
  records_affected
@@ -132,7 +199,6 @@ async function deleteUnusedKeys(uploadId, locale, branch) {
132
199
  },
133
200
  body: JSON.stringify({
134
201
  branch,
135
- locale_id: locale,
136
202
  q: query
137
203
  })
138
204
  });
@@ -223,7 +289,8 @@ async function pull({
223
289
  }
224
290
 
225
291
  /**
226
- * Uploading to the Phrase API for each language. Adding a unique namespace to each key using file path they key came from
292
+ * Uploads translations to the Phrase API for each language.
293
+ * A unique namespace is appended to each key using the file path the key came from.
227
294
  */
228
295
  async function push({
229
296
  branch,
@@ -231,7 +298,8 @@ async function push({
231
298
  }, config) {
232
299
  const allLanguageTranslations = await loadAllTranslations({
233
300
  fallbacks: 'none',
234
- includeNodeModules: false
301
+ includeNodeModules: false,
302
+ withTags: true
235
303
  }, config);
236
304
  trace(`Pushing translations to branch ${branch}`);
237
305
  const allLanguages = config.languages.map(v => v.name);
@@ -258,16 +326,15 @@ async function push({
258
326
  }
259
327
  }
260
328
 
261
- for (const language of allLanguages) {
262
- if (phraseTranslations[language]) {
263
- const {
264
- uploadId
265
- } = await pushTranslationsByLocale(phraseTranslations[language], language, branch);
329
+ const {
330
+ uploadId
331
+ } = await pushTranslations(phraseTranslations, {
332
+ devLanguage: config.devLanguage,
333
+ branch
334
+ });
266
335
 
267
- if (deleteUnusedKeys$1) {
268
- await deleteUnusedKeys(uploadId, language, branch);
269
- }
270
- }
336
+ if (deleteUnusedKeys$1) {
337
+ await deleteUnusedKeys(uploadId, branch);
271
338
  }
272
339
  }
273
340
 
package/package.json CHANGED
@@ -1,22 +1,23 @@
1
1
  {
2
2
  "name": "@vocab/phrase",
3
- "version": "0.0.0-package-files-20231142931",
3
+ "version": "0.0.0-tags-support-20231724743",
4
4
  "main": "dist/vocab-phrase.cjs.js",
5
5
  "module": "dist/vocab-phrase.esm.js",
6
6
  "author": "SEEK",
7
7
  "license": "MIT",
8
8
  "dependencies": {
9
- "@vocab/core": "^1.0.0",
10
- "@vocab/types": "^0.0.0-package-files-20231142931",
9
+ "@vocab/core": "^0.0.0-tags-support-20231724743",
10
+ "@vocab/types": "^0.0.0-tags-support-20231724743",
11
11
  "chalk": "^4.1.0",
12
+ "csv-stringify": "^6.2.3",
12
13
  "debug": "^4.3.1",
13
14
  "form-data": "^3.0.0",
14
15
  "node-fetch": "^2.6.1"
15
16
  },
16
- "files": [
17
- "dist"
18
- ],
19
17
  "devDependencies": {
20
18
  "@types/node-fetch": "^2.5.7"
21
- }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ]
22
23
  }
package/CHANGELOG.md DELETED
@@ -1,154 +0,0 @@
1
- # @vocab/phrase
2
-
3
- ## 0.0.0-package-files-20231142931
4
-
5
- ### Patch Changes
6
-
7
- - [`29c81d3`](https://github.com/seek-oss/vocab/commit/29c81d370799f631d97c45e727b8cf81453bd398) Thanks [@askoufis](https://github.com/askoufis)! - Exclude source files from package build
8
-
9
- - Updated dependencies [[`29c81d3`](https://github.com/seek-oss/vocab/commit/29c81d370799f631d97c45e727b8cf81453bd398)]:
10
- - @vocab/types@0.0.0-package-files-20231142931
11
-
12
- ## 1.1.0
13
-
14
- ### Minor Changes
15
-
16
- - [`66ed22c`](https://github.com/seek-oss/vocab/commit/66ed22cac6f89018d5fd69fd6f6408e090e1a382) [#93](https://github.com/seek-oss/vocab/pull/93) Thanks [@askoufis](https://github.com/askoufis)! - Add an optional `deleteUnusedKeys` flag to the `push` function. If set to `true`, unused keys will be deleted from Phrase after translations are pushed.
17
-
18
- **EXAMPLE USAGE**:
19
-
20
- ```js
21
- import { push } from '@vocab/phrase';
22
-
23
- const vocabConfig = {
24
- devLanguage: 'en',
25
- language: ['en', 'fr'],
26
- };
27
-
28
- await push({ branch: 'myBranch', deleteUnusedKeys: true }, vocabConfig);
29
- ```
30
-
31
- ### Patch Changes
32
-
33
- - [`159d559`](https://github.com/seek-oss/vocab/commit/159d559c87c66c3e91c707fb45a1f67ebec07b4d) [#91](https://github.com/seek-oss/vocab/pull/91) Thanks [@askoufis](https://github.com/askoufis)! - Improve error message when Phrase doesn't return any translations for the dev language
34
-
35
- ## 1.0.1
36
-
37
- ### Patch Changes
38
-
39
- - [`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
40
-
41
- ## 1.0.0
42
-
43
- ### Major Changes
44
-
45
- - [`3031054`](https://github.com/seek-oss/vocab/commit/303105440851db6126f0606e1607745b27dd981c) [#51](https://github.com/seek-oss/vocab/pull/51) Thanks [@jahredhope](https://github.com/jahredhope)! - Release v1.0.0
46
-
47
- Release Vocab as v1.0.0 to signify a stable API and support future [semver versioning](https://semver.org/) releases.
48
-
49
- Vocab has seen a lot of iteration and changes since it was first published on 20 November 2020. We are now confident with the API and believe Vocab is ready for common use.
50
-
51
- ### Patch Changes
52
-
53
- - Updated dependencies [[`0074382`](https://github.com/seek-oss/vocab/commit/007438273ef70f5d5ded45777933651ad8df36f6), [`3031054`](https://github.com/seek-oss/vocab/commit/303105440851db6126f0606e1607745b27dd981c)]:
54
- - @vocab/core@1.0.0
55
- - @vocab/types@1.0.0
56
-
57
- ## 0.0.11
58
-
59
- ### Patch Changes
60
-
61
- - Updated dependencies [[`5b1fdc0`](https://github.com/seek-oss/vocab/commit/5b1fdc019522b12e7ef94b2fec57b54a9310d41c)]:
62
- - @vocab/core@0.0.11
63
- - @vocab/types@0.0.9
64
-
65
- ## 0.0.10
66
-
67
- ### Patch Changes
68
-
69
- - Updated dependencies [[`7c96a14`](https://github.com/seek-oss/vocab/commit/7c96a142f602132d38c1df1a47a1f4657dc5c94c)]:
70
- - @vocab/core@0.0.10
71
-
72
- ## 0.0.9
73
-
74
- ### Patch Changes
75
-
76
- - Updated dependencies [[`3034bd3`](https://github.com/seek-oss/vocab/commit/3034bd3de610a9d1f3bfbd8caefa27064dee2710), [`c110745`](https://github.com/seek-oss/vocab/commit/c110745b79df1a8ade6b1d8a49e798b04a7b95e1)]:
77
- - @vocab/core@0.0.9
78
-
79
- ## 0.0.8
80
-
81
- ### Patch Changes
82
-
83
- - Updated dependencies [[`f2fca67`](https://github.com/seek-oss/vocab/commit/f2fca679c66ae65405a0aa24f0a0e472026aad0d)]:
84
- - @vocab/core@0.0.8
85
- - @vocab/types@0.0.8
86
-
87
- ## 0.0.7
88
-
89
- ### Patch Changes
90
-
91
- - [`283bcad`](https://github.com/seek-oss/vocab/commit/283bcada06e622ab14ed891743ed3f55cf09e245) [#33](https://github.com/seek-oss/vocab/pull/33) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Move all vocab files to single directory with configurable suffix
92
-
93
- - Updated dependencies [[`283bcad`](https://github.com/seek-oss/vocab/commit/283bcada06e622ab14ed891743ed3f55cf09e245), [`ad0d240`](https://github.com/seek-oss/vocab/commit/ad0d2404545ded8e11621eae8f29467ff3352366), [`f3992ef`](https://github.com/seek-oss/vocab/commit/f3992efbf08939ebf853fac650a49cc46dc51dfb), [`f3992ef`](https://github.com/seek-oss/vocab/commit/f3992efbf08939ebf853fac650a49cc46dc51dfb)]:
94
- - @vocab/core@0.0.7
95
- - @vocab/types@0.0.7
96
-
97
- ## 0.0.6
98
-
99
- ### Patch Changes
100
-
101
- - [`80a46c0`](https://github.com/seek-oss/vocab/commit/80a46c01a55408675f5822c3618519f80136c3ab) [#27](https://github.com/seek-oss/vocab/pull/27) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Add `ignore` config for ignoring files/folders from cli scripts
102
-
103
- * [`80a46c0`](https://github.com/seek-oss/vocab/commit/80a46c01a55408675f5822c3618519f80136c3ab) [#27](https://github.com/seek-oss/vocab/pull/27) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Ignore node_modules from push, pull and compile scripts
104
-
105
- * Updated dependencies [[`80a46c0`](https://github.com/seek-oss/vocab/commit/80a46c01a55408675f5822c3618519f80136c3ab), [`80a46c0`](https://github.com/seek-oss/vocab/commit/80a46c01a55408675f5822c3618519f80136c3ab)]:
106
- - @vocab/core@0.0.6
107
- - @vocab/types@0.0.6
108
-
109
- ## 0.0.5
110
-
111
- ### Patch Changes
112
-
113
- - Updated dependencies [[`371ed16`](https://github.com/seek-oss/vocab/commit/371ed16a232a04dab13afa7e2b352dfb6724eea4), [`c222d68`](https://github.com/seek-oss/vocab/commit/c222d68a3c0c24723a338eccb959798881f6a118)]:
114
- - @vocab/core@0.0.5
115
-
116
- ## 0.0.4
117
-
118
- ### Patch Changes
119
-
120
- - [`5f5c581`](https://github.com/seek-oss/vocab/commit/5f5c581a65bff28729ee19e1ec0bdea488a9d6c2) [#19](https://github.com/seek-oss/vocab/pull/19) Thanks [@jahredhope](https://github.com/jahredhope)! - Compile useable TypeScript importable files with `vocab compile`.
121
-
122
- The new `vocab compile` step replaces `vocab generate-types` in creating a fully functional **translations.ts** file.
123
-
124
- This allows vocab to be used **without the Webpack Plugin**, however use of the plugin is still heavily advised to ensure optimal loading of translation content on the web.
125
-
126
- Support for unit testing is now better than ever! The newly created **translations.ts** means your unit test code will see the same code as available while rendering.
127
-
128
- See the [documentation](https://github.com/seek-oss/vocab) for further usage details.
129
-
130
- * [`02f943c`](https://github.com/seek-oss/vocab/commit/02f943ca892913b41f9e4720a72400777cf14b3d) [#17](https://github.com/seek-oss/vocab/pull/17) Thanks [@jahredhope](https://github.com/jahredhope)! - Add additional debug traces
131
-
132
- * Updated dependencies [[`5f5c581`](https://github.com/seek-oss/vocab/commit/5f5c581a65bff28729ee19e1ec0bdea488a9d6c2), [`02f943c`](https://github.com/seek-oss/vocab/commit/02f943ca892913b41f9e4720a72400777cf14b3d)]:
133
- - @vocab/core@0.0.4
134
- - @vocab/types@0.0.5
135
-
136
- ## 0.0.3
137
-
138
- ### Patch Changes
139
-
140
- - [`08de30d`](https://github.com/seek-oss/vocab/commit/08de30d338c2a5ebdcf14da7c736dddf22e7ca9e) [#14](https://github.com/seek-oss/vocab/pull/14) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Add ability to override files namespace with \$namespace
141
-
142
- * [`26b52f4`](https://github.com/seek-oss/vocab/commit/26b52f4878ded440841e08c858bdc9e685500c2a) [#16](https://github.com/seek-oss/vocab/pull/16) Thanks [@jahredhope](https://github.com/jahredhope)! - Enable debugging with DEBUG environment variable
143
-
144
- * Updated dependencies [[`08de30d`](https://github.com/seek-oss/vocab/commit/08de30d338c2a5ebdcf14da7c736dddf22e7ca9e), [`ed6cf40`](https://github.com/seek-oss/vocab/commit/ed6cf408973f2e9c4d07a71fcb52f40294ebaf65), [`26b52f4`](https://github.com/seek-oss/vocab/commit/26b52f4878ded440841e08c858bdc9e685500c2a), [`b5a5a05`](https://github.com/seek-oss/vocab/commit/b5a5a05a5bb87b48e6e9160af75f555728143ea2)]:
145
- - @vocab/core@0.0.3
146
- - @vocab/types@0.0.4
147
-
148
- ## 0.0.2
149
-
150
- ### Patch Changes
151
-
152
- - Updated dependencies [[`4710f34`](https://github.com/seek-oss/vocab/commit/4710f341f2827643e3eff69ef7e26d44ec6e8a2b), [`4710f34`](https://github.com/seek-oss/vocab/commit/4710f341f2827643e3eff69ef7e26d44ec6e8a2b)]:
153
- - @vocab/types@0.0.3
154
- - @vocab/core@0.0.2