@vocab/phrase 1.2.6 → 1.2.8

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/README.md CHANGED
@@ -450,7 +450,7 @@ $ vocab pull --branch my-branch
450
450
 
451
451
  When uploading translations, Phrase identifies keys that exist in the Phrase project, but were not
452
452
  referenced in the upload. These keys can be deleted from Phrase by providing the
453
- `---delete-unused-keys` flag to `vocab push`. E.g.
453
+ `--delete-unused-keys` flag to `vocab push`. E.g.
454
454
 
455
455
  ```sh
456
456
  $ vocab push --branch my-branch --delete-unused-keys
@@ -1,10 +1,10 @@
1
1
  import type { TranslationsByLanguage } from '@vocab/core';
2
2
  export declare function translationsToCsv(translations: TranslationsByLanguage, devLanguage: string): {
3
- csvString: string;
4
- localeMapping: {
5
- [k: string]: number;
3
+ csvFileStrings: {
4
+ [k: string]: string;
6
5
  };
7
6
  keyIndex: number;
7
+ messageIndex: number;
8
8
  commentIndex: number;
9
9
  tagColumn: number;
10
10
  };
@@ -6,7 +6,7 @@ export declare function pushTranslations(translationsByLanguage: TranslationsByL
6
6
  devLanguage: string;
7
7
  branch: string;
8
8
  }): Promise<{
9
- uploadId: string;
9
+ devLanguageUploadId: string;
10
10
  }>;
11
11
  export declare function deleteUnusedKeys(uploadId: string, branch: string): Promise<void>;
12
12
  export declare function ensureBranch(branch: string): Promise<void>;
@@ -31,34 +31,43 @@ const log = (...params) => {
31
31
  function translationsToCsv(translations, devLanguage) {
32
32
  const languages = Object.keys(translations);
33
33
  const altLanguages = languages.filter(language => language !== devLanguage);
34
- // Ensure languages are ordered for locale mapping
35
- const orderedLanguages = [devLanguage, ...altLanguages];
36
34
  const devLanguageTranslations = translations[devLanguage];
37
- const csv = Object.entries(devLanguageTranslations).map(([key, {
35
+ const csvFilesByLanguage = Object.fromEntries(languages.map(language => [language, []]));
36
+ Object.entries(devLanguageTranslations).map(([key, {
38
37
  message,
39
38
  description,
40
39
  tags
41
40
  }]) => {
42
- const altTranslationMessages = altLanguages.map(language => {
41
+ const sharedData = [key, description, tags === null || tags === void 0 ? void 0 : tags.join(',')];
42
+ const devLanguageRow = [...sharedData, message];
43
+ csvFilesByLanguage[devLanguage].push(devLanguageRow);
44
+ altLanguages.map(language => {
43
45
  var _translations$languag, _translations$languag2;
44
- 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;
46
+ const altTranslationMessage = (_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;
47
+ if (altTranslationMessage) {
48
+ csvFilesByLanguage[language].push([...sharedData, altTranslationMessage]);
49
+ }
45
50
  });
46
- return [message, ...altTranslationMessages, key, description, tags === null || tags === void 0 ? void 0 : tags.join(',')];
47
- });
48
- const csvString = sync.stringify(csv, {
49
- delimiter: ',',
50
- header: false
51
51
  });
52
+ const csvFileStrings = Object.fromEntries(Object.entries(csvFilesByLanguage)
53
+ // Ensure CSV files are only created if the language has at least 1 translation
54
+ .filter(([_, csvFile]) => csvFile.length > 0).map(([language, csvFile]) => {
55
+ const csvFileString = sync.stringify(csvFile, {
56
+ delimiter: ',',
57
+ header: false
58
+ });
59
+ return [language, csvFileString];
60
+ }));
52
61
 
53
62
  // Column indices start at 1
54
- const localeMapping = Object.fromEntries(orderedLanguages.map((language, index) => [language, index + 1]));
55
- const keyIndex = orderedLanguages.length + 1;
63
+ const keyIndex = 1;
56
64
  const commentIndex = keyIndex + 1;
57
65
  const tagColumn = commentIndex + 1;
66
+ const messageIndex = tagColumn + 1;
58
67
  return {
59
- csvString,
60
- localeMapping,
68
+ csvFileStrings,
61
69
  keyIndex,
70
+ messageIndex,
62
71
  commentIndex,
63
72
  tagColumn
64
73
  };
@@ -139,46 +148,50 @@ async function pushTranslations(translationsByLanguage, {
139
148
  devLanguage,
140
149
  branch
141
150
  }) {
142
- const formData = new FormData__default["default"]();
143
151
  const {
144
- csvString,
145
- localeMapping,
152
+ csvFileStrings,
146
153
  keyIndex,
147
154
  commentIndex,
148
- tagColumn
155
+ tagColumn,
156
+ messageIndex
149
157
  } = translationsToCsv(translationsByLanguage, devLanguage);
150
- const fileContents = Buffer.from(csvString);
151
- formData.append('file', fileContents, {
152
- contentType: 'text/csv',
153
- filename: 'translations.csv'
154
- });
155
- formData.append('file_format', 'csv');
156
- formData.append('branch', branch);
157
- formData.append('update_translations', 'true');
158
- formData.append('update_descriptions', 'true');
159
- for (const [locale, index] of Object.entries(localeMapping)) {
160
- formData.append(`locale_mapping[${locale}]`, index);
161
- }
162
- formData.append('format_options[key_index]', keyIndex);
163
- formData.append('format_options[comment_index]', commentIndex);
164
- formData.append('format_options[tag_column]', tagColumn);
165
- formData.append('format_options[enable_pluralization]', 'false');
166
- log('Uploading translations');
167
- const result = await callPhrase(`uploads`, {
168
- method: 'POST',
169
- body: formData
170
- });
171
- trace('Upload result:\n', result);
172
- if (result && 'id' in result) {
173
- log('Upload ID:', result.id, '\n');
174
- log('Successfully Uploaded\n');
175
- } else {
176
- log(`Error uploading: ${result === null || result === void 0 ? void 0 : result.message}\n`);
177
- log('Response:', result);
178
- throw new Error('Error uploading');
158
+ let devLanguageUploadId = '';
159
+ for (const [language, csvFileString] of Object.entries(csvFileStrings)) {
160
+ const formData = new FormData__default["default"]();
161
+ const fileContents = Buffer.from(csvFileString);
162
+ formData.append('file', fileContents, {
163
+ contentType: 'text/csv',
164
+ filename: `${language}.translations.csv`
165
+ });
166
+ formData.append('file_format', 'csv');
167
+ formData.append('branch', branch);
168
+ formData.append('update_translations', 'true');
169
+ formData.append('update_descriptions', 'true');
170
+ formData.append(`locale_mapping[${language}]`, messageIndex);
171
+ formData.append('format_options[key_index]', keyIndex);
172
+ formData.append('format_options[comment_index]', commentIndex);
173
+ formData.append('format_options[tag_column]', tagColumn);
174
+ formData.append('format_options[enable_pluralization]', 'false');
175
+ log(`Uploading translations for language ${language}`);
176
+ const result = await callPhrase(`uploads`, {
177
+ method: 'POST',
178
+ body: formData
179
+ });
180
+ trace('Upload result:\n', result);
181
+ if (result && 'id' in result) {
182
+ log('Upload ID:', result.id, '\n');
183
+ log('Successfully Uploaded\n');
184
+ } else {
185
+ log(`Error uploading: ${result === null || result === void 0 ? void 0 : result.message}\n`);
186
+ log('Response:', result);
187
+ throw new Error('Error uploading');
188
+ }
189
+ if (language === devLanguage) {
190
+ devLanguageUploadId = result.id;
191
+ }
179
192
  }
180
193
  return {
181
- uploadId: result.id
194
+ devLanguageUploadId
182
195
  };
183
196
  }
184
197
  async function deleteUnusedKeys(uploadId, branch) {
@@ -324,13 +337,13 @@ async function push({
324
337
  }
325
338
  }
326
339
  const {
327
- uploadId
340
+ devLanguageUploadId
328
341
  } = await pushTranslations(phraseTranslations, {
329
342
  devLanguage: config.devLanguage,
330
343
  branch
331
344
  });
332
345
  if (deleteUnusedKeys$1) {
333
- await deleteUnusedKeys(uploadId, branch);
346
+ await deleteUnusedKeys(devLanguageUploadId, branch);
334
347
  }
335
348
  }
336
349
 
@@ -31,34 +31,43 @@ const log = (...params) => {
31
31
  function translationsToCsv(translations, devLanguage) {
32
32
  const languages = Object.keys(translations);
33
33
  const altLanguages = languages.filter(language => language !== devLanguage);
34
- // Ensure languages are ordered for locale mapping
35
- const orderedLanguages = [devLanguage, ...altLanguages];
36
34
  const devLanguageTranslations = translations[devLanguage];
37
- const csv = Object.entries(devLanguageTranslations).map(([key, {
35
+ const csvFilesByLanguage = Object.fromEntries(languages.map(language => [language, []]));
36
+ Object.entries(devLanguageTranslations).map(([key, {
38
37
  message,
39
38
  description,
40
39
  tags
41
40
  }]) => {
42
- const altTranslationMessages = altLanguages.map(language => {
41
+ const sharedData = [key, description, tags === null || tags === void 0 ? void 0 : tags.join(',')];
42
+ const devLanguageRow = [...sharedData, message];
43
+ csvFilesByLanguage[devLanguage].push(devLanguageRow);
44
+ altLanguages.map(language => {
43
45
  var _translations$languag, _translations$languag2;
44
- 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;
46
+ const altTranslationMessage = (_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;
47
+ if (altTranslationMessage) {
48
+ csvFilesByLanguage[language].push([...sharedData, altTranslationMessage]);
49
+ }
45
50
  });
46
- return [message, ...altTranslationMessages, key, description, tags === null || tags === void 0 ? void 0 : tags.join(',')];
47
- });
48
- const csvString = sync.stringify(csv, {
49
- delimiter: ',',
50
- header: false
51
51
  });
52
+ const csvFileStrings = Object.fromEntries(Object.entries(csvFilesByLanguage)
53
+ // Ensure CSV files are only created if the language has at least 1 translation
54
+ .filter(([_, csvFile]) => csvFile.length > 0).map(([language, csvFile]) => {
55
+ const csvFileString = sync.stringify(csvFile, {
56
+ delimiter: ',',
57
+ header: false
58
+ });
59
+ return [language, csvFileString];
60
+ }));
52
61
 
53
62
  // Column indices start at 1
54
- const localeMapping = Object.fromEntries(orderedLanguages.map((language, index) => [language, index + 1]));
55
- const keyIndex = orderedLanguages.length + 1;
63
+ const keyIndex = 1;
56
64
  const commentIndex = keyIndex + 1;
57
65
  const tagColumn = commentIndex + 1;
66
+ const messageIndex = tagColumn + 1;
58
67
  return {
59
- csvString,
60
- localeMapping,
68
+ csvFileStrings,
61
69
  keyIndex,
70
+ messageIndex,
62
71
  commentIndex,
63
72
  tagColumn
64
73
  };
@@ -139,46 +148,50 @@ async function pushTranslations(translationsByLanguage, {
139
148
  devLanguage,
140
149
  branch
141
150
  }) {
142
- const formData = new FormData__default["default"]();
143
151
  const {
144
- csvString,
145
- localeMapping,
152
+ csvFileStrings,
146
153
  keyIndex,
147
154
  commentIndex,
148
- tagColumn
155
+ tagColumn,
156
+ messageIndex
149
157
  } = translationsToCsv(translationsByLanguage, devLanguage);
150
- const fileContents = Buffer.from(csvString);
151
- formData.append('file', fileContents, {
152
- contentType: 'text/csv',
153
- filename: 'translations.csv'
154
- });
155
- formData.append('file_format', 'csv');
156
- formData.append('branch', branch);
157
- formData.append('update_translations', 'true');
158
- formData.append('update_descriptions', 'true');
159
- for (const [locale, index] of Object.entries(localeMapping)) {
160
- formData.append(`locale_mapping[${locale}]`, index);
161
- }
162
- formData.append('format_options[key_index]', keyIndex);
163
- formData.append('format_options[comment_index]', commentIndex);
164
- formData.append('format_options[tag_column]', tagColumn);
165
- formData.append('format_options[enable_pluralization]', 'false');
166
- log('Uploading translations');
167
- const result = await callPhrase(`uploads`, {
168
- method: 'POST',
169
- body: formData
170
- });
171
- trace('Upload result:\n', result);
172
- if (result && 'id' in result) {
173
- log('Upload ID:', result.id, '\n');
174
- log('Successfully Uploaded\n');
175
- } else {
176
- log(`Error uploading: ${result === null || result === void 0 ? void 0 : result.message}\n`);
177
- log('Response:', result);
178
- throw new Error('Error uploading');
158
+ let devLanguageUploadId = '';
159
+ for (const [language, csvFileString] of Object.entries(csvFileStrings)) {
160
+ const formData = new FormData__default["default"]();
161
+ const fileContents = Buffer.from(csvFileString);
162
+ formData.append('file', fileContents, {
163
+ contentType: 'text/csv',
164
+ filename: `${language}.translations.csv`
165
+ });
166
+ formData.append('file_format', 'csv');
167
+ formData.append('branch', branch);
168
+ formData.append('update_translations', 'true');
169
+ formData.append('update_descriptions', 'true');
170
+ formData.append(`locale_mapping[${language}]`, messageIndex);
171
+ formData.append('format_options[key_index]', keyIndex);
172
+ formData.append('format_options[comment_index]', commentIndex);
173
+ formData.append('format_options[tag_column]', tagColumn);
174
+ formData.append('format_options[enable_pluralization]', 'false');
175
+ log(`Uploading translations for language ${language}`);
176
+ const result = await callPhrase(`uploads`, {
177
+ method: 'POST',
178
+ body: formData
179
+ });
180
+ trace('Upload result:\n', result);
181
+ if (result && 'id' in result) {
182
+ log('Upload ID:', result.id, '\n');
183
+ log('Successfully Uploaded\n');
184
+ } else {
185
+ log(`Error uploading: ${result === null || result === void 0 ? void 0 : result.message}\n`);
186
+ log('Response:', result);
187
+ throw new Error('Error uploading');
188
+ }
189
+ if (language === devLanguage) {
190
+ devLanguageUploadId = result.id;
191
+ }
179
192
  }
180
193
  return {
181
- uploadId: result.id
194
+ devLanguageUploadId
182
195
  };
183
196
  }
184
197
  async function deleteUnusedKeys(uploadId, branch) {
@@ -324,13 +337,13 @@ async function push({
324
337
  }
325
338
  }
326
339
  const {
327
- uploadId
340
+ devLanguageUploadId
328
341
  } = await pushTranslations(phraseTranslations, {
329
342
  devLanguage: config.devLanguage,
330
343
  branch
331
344
  });
332
345
  if (deleteUnusedKeys$1) {
333
- await deleteUnusedKeys(uploadId, branch);
346
+ await deleteUnusedKeys(devLanguageUploadId, branch);
334
347
  }
335
348
  }
336
349
 
@@ -19,34 +19,43 @@ const log = (...params) => {
19
19
  function translationsToCsv(translations, devLanguage) {
20
20
  const languages = Object.keys(translations);
21
21
  const altLanguages = languages.filter(language => language !== devLanguage);
22
- // Ensure languages are ordered for locale mapping
23
- const orderedLanguages = [devLanguage, ...altLanguages];
24
22
  const devLanguageTranslations = translations[devLanguage];
25
- const csv = Object.entries(devLanguageTranslations).map(([key, {
23
+ const csvFilesByLanguage = Object.fromEntries(languages.map(language => [language, []]));
24
+ Object.entries(devLanguageTranslations).map(([key, {
26
25
  message,
27
26
  description,
28
27
  tags
29
28
  }]) => {
30
- const altTranslationMessages = altLanguages.map(language => {
29
+ const sharedData = [key, description, tags === null || tags === void 0 ? void 0 : tags.join(',')];
30
+ const devLanguageRow = [...sharedData, message];
31
+ csvFilesByLanguage[devLanguage].push(devLanguageRow);
32
+ altLanguages.map(language => {
31
33
  var _translations$languag, _translations$languag2;
32
- 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;
34
+ const altTranslationMessage = (_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;
35
+ if (altTranslationMessage) {
36
+ csvFilesByLanguage[language].push([...sharedData, altTranslationMessage]);
37
+ }
33
38
  });
34
- return [message, ...altTranslationMessages, key, description, tags === null || tags === void 0 ? void 0 : tags.join(',')];
35
- });
36
- const csvString = stringify(csv, {
37
- delimiter: ',',
38
- header: false
39
39
  });
40
+ const csvFileStrings = Object.fromEntries(Object.entries(csvFilesByLanguage)
41
+ // Ensure CSV files are only created if the language has at least 1 translation
42
+ .filter(([_, csvFile]) => csvFile.length > 0).map(([language, csvFile]) => {
43
+ const csvFileString = stringify(csvFile, {
44
+ delimiter: ',',
45
+ header: false
46
+ });
47
+ return [language, csvFileString];
48
+ }));
40
49
 
41
50
  // Column indices start at 1
42
- const localeMapping = Object.fromEntries(orderedLanguages.map((language, index) => [language, index + 1]));
43
- const keyIndex = orderedLanguages.length + 1;
51
+ const keyIndex = 1;
44
52
  const commentIndex = keyIndex + 1;
45
53
  const tagColumn = commentIndex + 1;
54
+ const messageIndex = tagColumn + 1;
46
55
  return {
47
- csvString,
48
- localeMapping,
56
+ csvFileStrings,
49
57
  keyIndex,
58
+ messageIndex,
50
59
  commentIndex,
51
60
  tagColumn
52
61
  };
@@ -127,46 +136,50 @@ async function pushTranslations(translationsByLanguage, {
127
136
  devLanguage,
128
137
  branch
129
138
  }) {
130
- const formData = new FormData();
131
139
  const {
132
- csvString,
133
- localeMapping,
140
+ csvFileStrings,
134
141
  keyIndex,
135
142
  commentIndex,
136
- tagColumn
143
+ tagColumn,
144
+ messageIndex
137
145
  } = translationsToCsv(translationsByLanguage, devLanguage);
138
- const fileContents = Buffer.from(csvString);
139
- formData.append('file', fileContents, {
140
- contentType: 'text/csv',
141
- filename: 'translations.csv'
142
- });
143
- formData.append('file_format', 'csv');
144
- formData.append('branch', branch);
145
- formData.append('update_translations', 'true');
146
- formData.append('update_descriptions', 'true');
147
- for (const [locale, index] of Object.entries(localeMapping)) {
148
- formData.append(`locale_mapping[${locale}]`, index);
149
- }
150
- formData.append('format_options[key_index]', keyIndex);
151
- formData.append('format_options[comment_index]', commentIndex);
152
- formData.append('format_options[tag_column]', tagColumn);
153
- formData.append('format_options[enable_pluralization]', 'false');
154
- log('Uploading translations');
155
- const result = await callPhrase(`uploads`, {
156
- method: 'POST',
157
- body: formData
158
- });
159
- trace('Upload result:\n', result);
160
- if (result && 'id' in result) {
161
- log('Upload ID:', result.id, '\n');
162
- log('Successfully Uploaded\n');
163
- } else {
164
- log(`Error uploading: ${result === null || result === void 0 ? void 0 : result.message}\n`);
165
- log('Response:', result);
166
- throw new Error('Error uploading');
146
+ let devLanguageUploadId = '';
147
+ for (const [language, csvFileString] of Object.entries(csvFileStrings)) {
148
+ const formData = new FormData();
149
+ const fileContents = Buffer.from(csvFileString);
150
+ formData.append('file', fileContents, {
151
+ contentType: 'text/csv',
152
+ filename: `${language}.translations.csv`
153
+ });
154
+ formData.append('file_format', 'csv');
155
+ formData.append('branch', branch);
156
+ formData.append('update_translations', 'true');
157
+ formData.append('update_descriptions', 'true');
158
+ formData.append(`locale_mapping[${language}]`, messageIndex);
159
+ formData.append('format_options[key_index]', keyIndex);
160
+ formData.append('format_options[comment_index]', commentIndex);
161
+ formData.append('format_options[tag_column]', tagColumn);
162
+ formData.append('format_options[enable_pluralization]', 'false');
163
+ log(`Uploading translations for language ${language}`);
164
+ const result = await callPhrase(`uploads`, {
165
+ method: 'POST',
166
+ body: formData
167
+ });
168
+ trace('Upload result:\n', result);
169
+ if (result && 'id' in result) {
170
+ log('Upload ID:', result.id, '\n');
171
+ log('Successfully Uploaded\n');
172
+ } else {
173
+ log(`Error uploading: ${result === null || result === void 0 ? void 0 : result.message}\n`);
174
+ log('Response:', result);
175
+ throw new Error('Error uploading');
176
+ }
177
+ if (language === devLanguage) {
178
+ devLanguageUploadId = result.id;
179
+ }
167
180
  }
168
181
  return {
169
- uploadId: result.id
182
+ devLanguageUploadId
170
183
  };
171
184
  }
172
185
  async function deleteUnusedKeys(uploadId, branch) {
@@ -312,13 +325,13 @@ async function push({
312
325
  }
313
326
  }
314
327
  const {
315
- uploadId
328
+ devLanguageUploadId
316
329
  } = await pushTranslations(phraseTranslations, {
317
330
  devLanguage: config.devLanguage,
318
331
  branch
319
332
  });
320
333
  if (deleteUnusedKeys$1) {
321
- await deleteUnusedKeys(uploadId, branch);
334
+ await deleteUnusedKeys(devLanguageUploadId, branch);
322
335
  }
323
336
  }
324
337
 
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@vocab/phrase",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
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.3.1",
9
+ "@vocab/core": "^1.4.0",
10
10
  "chalk": "^4.1.0",
11
11
  "csv-stringify": "^6.2.3",
12
12
  "debug": "^4.3.1",