@vocab/phrase 1.2.5 → 1.2.7

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,45 +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
- for (const [locale, index] of Object.entries(localeMapping)) {
159
- formData.append(`locale_mapping[${locale}]`, index);
160
- }
161
- formData.append('format_options[key_index]', keyIndex);
162
- formData.append('format_options[comment_index]', commentIndex);
163
- formData.append('format_options[tag_column]', tagColumn);
164
- formData.append('format_options[enable_pluralization]', 'false');
165
- log('Uploading translations');
166
- const result = await callPhrase(`uploads`, {
167
- method: 'POST',
168
- body: formData
169
- });
170
- trace('Upload result:\n', result);
171
- if (result && 'id' in result) {
172
- log('Upload ID:', result.id, '\n');
173
- log('Successfully Uploaded\n');
174
- } else {
175
- log(`Error uploading: ${result === null || result === void 0 ? void 0 : result.message}\n`);
176
- log('Response:', result);
177
- 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
+ }
178
192
  }
179
193
  return {
180
- uploadId: result.id
194
+ devLanguageUploadId
181
195
  };
182
196
  }
183
197
  async function deleteUnusedKeys(uploadId, branch) {
@@ -323,13 +337,13 @@ async function push({
323
337
  }
324
338
  }
325
339
  const {
326
- uploadId
340
+ devLanguageUploadId
327
341
  } = await pushTranslations(phraseTranslations, {
328
342
  devLanguage: config.devLanguage,
329
343
  branch
330
344
  });
331
345
  if (deleteUnusedKeys$1) {
332
- await deleteUnusedKeys(uploadId, branch);
346
+ await deleteUnusedKeys(devLanguageUploadId, branch);
333
347
  }
334
348
  }
335
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,45 +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
- for (const [locale, index] of Object.entries(localeMapping)) {
159
- formData.append(`locale_mapping[${locale}]`, index);
160
- }
161
- formData.append('format_options[key_index]', keyIndex);
162
- formData.append('format_options[comment_index]', commentIndex);
163
- formData.append('format_options[tag_column]', tagColumn);
164
- formData.append('format_options[enable_pluralization]', 'false');
165
- log('Uploading translations');
166
- const result = await callPhrase(`uploads`, {
167
- method: 'POST',
168
- body: formData
169
- });
170
- trace('Upload result:\n', result);
171
- if (result && 'id' in result) {
172
- log('Upload ID:', result.id, '\n');
173
- log('Successfully Uploaded\n');
174
- } else {
175
- log(`Error uploading: ${result === null || result === void 0 ? void 0 : result.message}\n`);
176
- log('Response:', result);
177
- 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
+ }
178
192
  }
179
193
  return {
180
- uploadId: result.id
194
+ devLanguageUploadId
181
195
  };
182
196
  }
183
197
  async function deleteUnusedKeys(uploadId, branch) {
@@ -323,13 +337,13 @@ async function push({
323
337
  }
324
338
  }
325
339
  const {
326
- uploadId
340
+ devLanguageUploadId
327
341
  } = await pushTranslations(phraseTranslations, {
328
342
  devLanguage: config.devLanguage,
329
343
  branch
330
344
  });
331
345
  if (deleteUnusedKeys$1) {
332
- await deleteUnusedKeys(uploadId, branch);
346
+ await deleteUnusedKeys(devLanguageUploadId, branch);
333
347
  }
334
348
  }
335
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,45 +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
- for (const [locale, index] of Object.entries(localeMapping)) {
147
- formData.append(`locale_mapping[${locale}]`, index);
148
- }
149
- formData.append('format_options[key_index]', keyIndex);
150
- formData.append('format_options[comment_index]', commentIndex);
151
- formData.append('format_options[tag_column]', tagColumn);
152
- formData.append('format_options[enable_pluralization]', 'false');
153
- log('Uploading translations');
154
- const result = await callPhrase(`uploads`, {
155
- method: 'POST',
156
- body: formData
157
- });
158
- trace('Upload result:\n', result);
159
- if (result && 'id' in result) {
160
- log('Upload ID:', result.id, '\n');
161
- log('Successfully Uploaded\n');
162
- } else {
163
- log(`Error uploading: ${result === null || result === void 0 ? void 0 : result.message}\n`);
164
- log('Response:', result);
165
- 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
+ }
166
180
  }
167
181
  return {
168
- uploadId: result.id
182
+ devLanguageUploadId
169
183
  };
170
184
  }
171
185
  async function deleteUnusedKeys(uploadId, branch) {
@@ -311,13 +325,13 @@ async function push({
311
325
  }
312
326
  }
313
327
  const {
314
- uploadId
328
+ devLanguageUploadId
315
329
  } = await pushTranslations(phraseTranslations, {
316
330
  devLanguage: config.devLanguage,
317
331
  branch
318
332
  });
319
333
  if (deleteUnusedKeys$1) {
320
- await deleteUnusedKeys(uploadId, branch);
334
+ await deleteUnusedKeys(devLanguageUploadId, branch);
321
335
  }
322
336
  }
323
337
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vocab/phrase",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "main": "dist/vocab-phrase.cjs.js",
5
5
  "module": "dist/vocab-phrase.esm.js",
6
6
  "author": "SEEK",