@vocab/phrase 0.0.0-phrase-pull-dev-language-202281412540 → 0.0.0-rate-limit-seconds-20230314015727

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.
@@ -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,14 +16,50 @@ 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
+ // Ensure languages are ordered for locale mapping
23
+ const orderedLanguages = [devLanguage, ...altLanguages];
24
+ const devLanguageTranslations = translations[devLanguage];
25
+ const csv = Object.entries(devLanguageTranslations).map(([key, {
26
+ message,
27
+ description,
28
+ tags
29
+ }]) => {
30
+ const altTranslationMessages = altLanguages.map(language => {
31
+ 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;
33
+ });
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
+ });
40
+
41
+ // Column indices start at 1
42
+ const localeMapping = Object.fromEntries(orderedLanguages.map((language, index) => [language, index + 1]));
43
+ const keyIndex = orderedLanguages.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 */
18
56
  function _callPhrase(path, options = {}) {
19
57
  const phraseApiToken = process.env.PHRASE_API_TOKEN;
20
-
21
58
  if (!phraseApiToken) {
22
59
  throw new Error('Missing PHRASE_API_TOKEN');
23
60
  }
24
-
25
- return fetch(path, { ...options,
61
+ return fetch(path, {
62
+ ...options,
26
63
  headers: {
27
64
  Authorization: `token ${phraseApiToken}`,
28
65
  // Provide identification via User Agent as requested in https://developers.phrase.com/api/#overview--identification-via-user-agent
@@ -31,30 +68,26 @@ function _callPhrase(path, options = {}) {
31
68
  }
32
69
  }).then(async response => {
33
70
  console.log(`${path}: ${response.status} - ${response.statusText}`);
34
- 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})`);
35
- console.log('\nLink:', response.headers.get('Link'), '\n'); // Print All Headers:
71
+ const secondsUntilLimitReset = Math.ceil(Number.parseFloat(response.headers.get('X-Rate-Limit-Reset') || '0') - Date.now() / 1000);
72
+ console.log(`Rate Limit: ${response.headers.get('X-Rate-Limit-Remaining')} of ${response.headers.get('X-Rate-Limit-Limit')} remaining. (${secondsUntilLimitReset} seconds remaining})`);
73
+ trace('\nLink:', response.headers.get('Link'), '\n');
74
+ // Print All Headers:
36
75
  // console.log(Array.from(r.headers.entries()));
37
76
 
38
77
  try {
39
78
  var _response$headers$get;
40
-
41
79
  const result = await response.json();
42
- console.log(`Internal Result (Length: ${result.length})\n`);
43
-
80
+ trace(`Internal Result (Length: ${result.length})\n`);
44
81
  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')) {
45
82
  var _response$headers$get2, _response$headers$get3;
46
-
47
83
  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 : [];
48
-
49
84
  if (!nextPageUrl) {
50
- throw new Error('Cant parse next page URL');
85
+ throw new Error("Can't parse next page URL");
51
86
  }
52
-
53
- console.log('Results recieved with next page: ', nextPageUrl);
87
+ console.log('Results received with next page: ', nextPageUrl);
54
88
  const nextPageResult = await _callPhrase(nextPageUrl, options);
55
89
  return [...result, ...nextPageResult];
56
90
  }
57
-
58
91
  return result;
59
92
  } catch (e) {
60
93
  console.error('Unable to parse response as JSON', e);
@@ -62,19 +95,15 @@ function _callPhrase(path, options = {}) {
62
95
  }
63
96
  });
64
97
  }
65
-
66
98
  async function callPhrase(relativePath, options = {}) {
67
99
  const projectId = process.env.PHRASE_PROJECT_ID;
68
-
69
100
  if (!projectId) {
70
101
  throw new Error('Missing PHRASE_PROJECT_ID');
71
102
  }
72
-
73
103
  return _callPhrase(`https://api.phrase.com/v2/projects/${projectId}/${relativePath}`, options).then(result => {
74
104
  if (Array.isArray(result)) {
75
105
  console.log('Result length:', result.length);
76
106
  }
77
-
78
107
  return result;
79
108
  }).catch(error => {
80
109
  console.error(`Error calling phrase for ${relativePath}:`, error);
@@ -84,36 +113,76 @@ async function callPhrase(relativePath, options = {}) {
84
113
  async function pullAllTranslations(branch) {
85
114
  const phraseResult = await callPhrase(`translations?branch=${branch}&per_page=100`);
86
115
  const translations = {};
87
-
88
116
  for (const r of phraseResult) {
89
117
  if (!translations[r.locale.code]) {
90
118
  translations[r.locale.code] = {};
91
119
  }
92
-
93
120
  translations[r.locale.code][r.key.name] = {
94
121
  message: r.content
95
122
  };
96
123
  }
97
-
98
124
  return translations;
99
125
  }
100
- async function pushTranslationsByLocale(contents, locale, branch) {
126
+ async function pushTranslations(translationsByLanguage, {
127
+ devLanguage,
128
+ branch
129
+ }) {
101
130
  const formData = new FormData();
102
- const fileContents = Buffer.from(JSON.stringify(contents));
131
+ const {
132
+ csvString,
133
+ localeMapping,
134
+ keyIndex,
135
+ commentIndex,
136
+ tagColumn
137
+ } = translationsToCsv(translationsByLanguage, devLanguage);
138
+ const fileContents = Buffer.from(csvString);
103
139
  formData.append('file', fileContents, {
104
- contentType: 'application/json',
105
- filename: `${locale}.json`
140
+ contentType: 'text/csv',
141
+ filename: 'translations.csv'
106
142
  });
107
- formData.append('file_format', 'json');
108
- formData.append('locale_id', locale);
143
+ formData.append('file_format', 'csv');
109
144
  formData.append('branch', branch);
110
145
  formData.append('update_translations', 'true');
111
- trace('Starting to upload:', locale);
112
- await callPhrase(`uploads`, {
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`, {
113
155
  method: 'POST',
114
156
  body: formData
115
157
  });
116
- log('Successfully Uploaded:', locale, '\n');
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');
166
+ }
167
+ return {
168
+ uploadId: result.id
169
+ };
170
+ }
171
+ async function deleteUnusedKeys(uploadId, branch) {
172
+ const query = `unmentioned_in_upload:${uploadId}`;
173
+ const {
174
+ records_affected
175
+ } = await callPhrase('keys', {
176
+ method: 'DELETE',
177
+ headers: {
178
+ 'Content-Type': 'application/json'
179
+ },
180
+ body: JSON.stringify({
181
+ branch,
182
+ q: query
183
+ })
184
+ });
185
+ log('Successfully deleted', records_affected, 'unused keys from branch', branch);
117
186
  }
118
187
  async function ensureBranch(branch) {
119
188
  await callPhrase(`branches`, {
@@ -125,7 +194,7 @@ async function ensureBranch(branch) {
125
194
  name: branch
126
195
  })
127
196
  });
128
- trace('Created branch:', branch);
197
+ log('Created branch:', branch);
129
198
  }
130
199
 
131
200
  async function pull({
@@ -137,62 +206,55 @@ async function pull({
137
206
  const allPhraseTranslations = await pullAllTranslations(branch);
138
207
  trace(`Pulling translations from Phrase for languages ${config.devLanguage} and ${alternativeLanguages.join(', ')}`);
139
208
  const phraseLanguages = Object.keys(allPhraseTranslations);
140
- const phraseLanguagesWithTranslations = phraseLanguages.filter(language => {
141
- const phraseTranslationsForLanguage = allPhraseTranslations[language];
142
- return Object.keys(phraseTranslationsForLanguage).length > 0;
143
- });
144
- trace(`Found Phrase translations for languages ${phraseLanguagesWithTranslations.join(', ')}`);
145
-
146
- if (!phraseLanguagesWithTranslations.includes(config.devLanguage)) {
147
- throw new Error(`Phrase did not return any translations for dev language "${config.devLanguage}".\nEnsure you have configured your Phrase project for your dev language, and have pushed your translations.`);
209
+ trace(`Found Phrase translations for languages ${phraseLanguages.join(', ')}`);
210
+ if (!phraseLanguages.includes(config.devLanguage)) {
211
+ 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.`);
148
212
  }
149
-
150
213
  const allVocabTranslations = await loadAllTranslations({
151
214
  fallbacks: 'none',
152
- includeNodeModules: false
215
+ includeNodeModules: false,
216
+ withTags: true
153
217
  }, config);
154
-
155
218
  for (const loadedTranslation of allVocabTranslations) {
156
219
  const devTranslations = loadedTranslation.languages[config.devLanguage];
157
-
158
220
  if (!devTranslations) {
159
221
  throw new Error('No dev language translations loaded');
160
222
  }
161
-
162
- const defaultValues = { ...devTranslations
223
+ const defaultValues = {
224
+ ...devTranslations
163
225
  };
164
226
  const localKeys = Object.keys(defaultValues);
165
-
166
227
  for (const key of localKeys) {
167
- defaultValues[key] = { ...defaultValues[key],
228
+ defaultValues[key] = {
229
+ ...defaultValues[key],
168
230
  ...allPhraseTranslations[config.devLanguage][getUniqueKey(key, loadedTranslation.namespace)]
169
231
  };
170
232
  }
171
233
 
234
+ // Only write a `_meta` field if necessary
235
+ if (Object.keys(loadedTranslation.metadata).length > 0) {
236
+ defaultValues._meta = loadedTranslation.metadata;
237
+ }
172
238
  await writeFile(loadedTranslation.filePath, `${JSON.stringify(defaultValues, null, 2)}\n`);
173
-
174
239
  for (const alternativeLanguage of alternativeLanguages) {
175
240
  if (alternativeLanguage in allPhraseTranslations) {
176
- const altTranslations = { ...loadedTranslation.languages[alternativeLanguage]
241
+ const altTranslations = {
242
+ ...loadedTranslation.languages[alternativeLanguage]
177
243
  };
178
244
  const phraseAltTranslations = allPhraseTranslations[alternativeLanguage];
179
-
180
245
  for (const key of localKeys) {
181
246
  var _phraseAltTranslation;
182
-
183
247
  const phraseKey = getUniqueKey(key, loadedTranslation.namespace);
184
248
  const phraseTranslationMessage = (_phraseAltTranslation = phraseAltTranslations[phraseKey]) === null || _phraseAltTranslation === void 0 ? void 0 : _phraseAltTranslation.message;
185
-
186
249
  if (!phraseTranslationMessage) {
187
250
  trace(`Missing translation. No translation for key ${key} in phrase as ${phraseKey} in language ${alternativeLanguage}.`);
188
251
  continue;
189
252
  }
190
-
191
- altTranslations[key] = { ...altTranslations[key],
253
+ altTranslations[key] = {
254
+ ...altTranslations[key],
192
255
  message: phraseTranslationMessage
193
256
  };
194
257
  }
195
-
196
258
  const altTranslationFilePath = getAltLanguageFilePath(loadedTranslation.filePath, alternativeLanguage);
197
259
  await mkdir(path.dirname(altTranslationFilePath), {
198
260
  recursive: true
@@ -204,44 +266,58 @@ async function pull({
204
266
  }
205
267
 
206
268
  /**
207
- * Uploading to the Phrase API for each language. Adding a unique namespace to each key using file path they key came from
269
+ * Uploads translations to the Phrase API for each language.
270
+ * A unique namespace is appended to each key using the file path the key came from.
208
271
  */
209
272
  async function push({
210
- branch
273
+ branch,
274
+ deleteUnusedKeys: deleteUnusedKeys$1
211
275
  }, config) {
212
276
  const allLanguageTranslations = await loadAllTranslations({
213
277
  fallbacks: 'none',
214
- includeNodeModules: false
278
+ includeNodeModules: false,
279
+ withTags: true
215
280
  }, config);
216
281
  trace(`Pushing translations to branch ${branch}`);
217
282
  const allLanguages = config.languages.map(v => v.name);
218
283
  await ensureBranch(branch);
219
284
  trace(`Pushing translations to phrase for languages ${allLanguages.join(', ')}`);
220
285
  const phraseTranslations = {};
221
-
222
286
  for (const loadedTranslation of allLanguageTranslations) {
223
287
  for (const language of allLanguages) {
224
288
  const localTranslations = loadedTranslation.languages[language];
225
-
226
289
  if (!localTranslations) {
227
290
  continue;
228
291
  }
229
-
230
292
  if (!phraseTranslations[language]) {
231
293
  phraseTranslations[language] = {};
232
294
  }
233
-
295
+ const {
296
+ metadata: {
297
+ tags: sharedTags = []
298
+ }
299
+ } = loadedTranslation;
234
300
  for (const localKey of Object.keys(localTranslations)) {
235
301
  const phraseKey = getUniqueKey(localKey, loadedTranslation.namespace);
236
- phraseTranslations[language][phraseKey] = localTranslations[localKey];
302
+ const {
303
+ tags = [],
304
+ ...localTranslation
305
+ } = localTranslations[localKey];
306
+ if (language === config.devLanguage) {
307
+ localTranslation.tags = [...tags, ...sharedTags];
308
+ }
309
+ phraseTranslations[language][phraseKey] = localTranslation;
237
310
  }
238
311
  }
239
312
  }
240
-
241
- for (const language of allLanguages) {
242
- if (phraseTranslations[language]) {
243
- await pushTranslationsByLocale(phraseTranslations[language], language, branch);
244
- }
313
+ const {
314
+ uploadId
315
+ } = await pushTranslations(phraseTranslations, {
316
+ devLanguage: config.devLanguage,
317
+ branch
318
+ });
319
+ if (deleteUnusedKeys$1) {
320
+ await deleteUnusedKeys(uploadId, branch);
245
321
  }
246
322
  }
247
323
 
package/package.json CHANGED
@@ -1,19 +1,24 @@
1
1
  {
2
2
  "name": "@vocab/phrase",
3
- "version": "0.0.0-phrase-pull-dev-language-202281412540",
3
+ "version": "0.0.0-rate-limit-seconds-20230314015727",
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": "^1.0.0",
9
+ "@vocab/core": "^1.2.0",
10
+ "@vocab/types": "^1.1.2",
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
17
  "devDependencies": {
18
+ "@types/debug": "^4.1.5",
17
19
  "@types/node-fetch": "^2.5.7"
18
- }
19
- }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ]
24
+ }
package/CHANGELOG.md DELETED
@@ -1,128 +0,0 @@
1
- # @vocab/phrase
2
-
3
- ## 0.0.0-phrase-pull-dev-language-202281412540
4
-
5
- ### Patch Changes
6
-
7
- - [`ac206c8`](https://github.com/seek-oss/vocab/commit/ac206c8ba997551d960f0b72474568c1850f9561) [#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
8
-
9
- ## 1.0.1
10
-
11
- ### Patch Changes
12
-
13
- - [`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
14
-
15
- ## 1.0.0
16
-
17
- ### Major Changes
18
-
19
- - [`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
20
-
21
- Release Vocab as v1.0.0 to signify a stable API and support future [semver versioning](https://semver.org/) releases.
22
-
23
- 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.
24
-
25
- ### Patch Changes
26
-
27
- - Updated dependencies [[`0074382`](https://github.com/seek-oss/vocab/commit/007438273ef70f5d5ded45777933651ad8df36f6), [`3031054`](https://github.com/seek-oss/vocab/commit/303105440851db6126f0606e1607745b27dd981c)]:
28
- - @vocab/core@1.0.0
29
- - @vocab/types@1.0.0
30
-
31
- ## 0.0.11
32
-
33
- ### Patch Changes
34
-
35
- - Updated dependencies [[`5b1fdc0`](https://github.com/seek-oss/vocab/commit/5b1fdc019522b12e7ef94b2fec57b54a9310d41c)]:
36
- - @vocab/core@0.0.11
37
- - @vocab/types@0.0.9
38
-
39
- ## 0.0.10
40
-
41
- ### Patch Changes
42
-
43
- - Updated dependencies [[`7c96a14`](https://github.com/seek-oss/vocab/commit/7c96a142f602132d38c1df1a47a1f4657dc5c94c)]:
44
- - @vocab/core@0.0.10
45
-
46
- ## 0.0.9
47
-
48
- ### Patch Changes
49
-
50
- - Updated dependencies [[`3034bd3`](https://github.com/seek-oss/vocab/commit/3034bd3de610a9d1f3bfbd8caefa27064dee2710), [`c110745`](https://github.com/seek-oss/vocab/commit/c110745b79df1a8ade6b1d8a49e798b04a7b95e1)]:
51
- - @vocab/core@0.0.9
52
-
53
- ## 0.0.8
54
-
55
- ### Patch Changes
56
-
57
- - Updated dependencies [[`f2fca67`](https://github.com/seek-oss/vocab/commit/f2fca679c66ae65405a0aa24f0a0e472026aad0d)]:
58
- - @vocab/core@0.0.8
59
- - @vocab/types@0.0.8
60
-
61
- ## 0.0.7
62
-
63
- ### Patch Changes
64
-
65
- - [`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
66
-
67
- - 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)]:
68
- - @vocab/core@0.0.7
69
- - @vocab/types@0.0.7
70
-
71
- ## 0.0.6
72
-
73
- ### Patch Changes
74
-
75
- - [`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
76
-
77
- * [`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
78
-
79
- * Updated dependencies [[`80a46c0`](https://github.com/seek-oss/vocab/commit/80a46c01a55408675f5822c3618519f80136c3ab), [`80a46c0`](https://github.com/seek-oss/vocab/commit/80a46c01a55408675f5822c3618519f80136c3ab)]:
80
- - @vocab/core@0.0.6
81
- - @vocab/types@0.0.6
82
-
83
- ## 0.0.5
84
-
85
- ### Patch Changes
86
-
87
- - Updated dependencies [[`371ed16`](https://github.com/seek-oss/vocab/commit/371ed16a232a04dab13afa7e2b352dfb6724eea4), [`c222d68`](https://github.com/seek-oss/vocab/commit/c222d68a3c0c24723a338eccb959798881f6a118)]:
88
- - @vocab/core@0.0.5
89
-
90
- ## 0.0.4
91
-
92
- ### Patch Changes
93
-
94
- - [`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`.
95
-
96
- The new `vocab compile` step replaces `vocab generate-types` in creating a fully functional **translations.ts** file.
97
-
98
- 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.
99
-
100
- 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.
101
-
102
- See the [documentation](https://github.com/seek-oss/vocab) for further usage details.
103
-
104
- * [`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
105
-
106
- * Updated dependencies [[`5f5c581`](https://github.com/seek-oss/vocab/commit/5f5c581a65bff28729ee19e1ec0bdea488a9d6c2), [`02f943c`](https://github.com/seek-oss/vocab/commit/02f943ca892913b41f9e4720a72400777cf14b3d)]:
107
- - @vocab/core@0.0.4
108
- - @vocab/types@0.0.5
109
-
110
- ## 0.0.3
111
-
112
- ### Patch Changes
113
-
114
- - [`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
115
-
116
- * [`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
117
-
118
- * 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)]:
119
- - @vocab/core@0.0.3
120
- - @vocab/types@0.0.4
121
-
122
- ## 0.0.2
123
-
124
- ### Patch Changes
125
-
126
- - Updated dependencies [[`4710f34`](https://github.com/seek-oss/vocab/commit/4710f341f2827643e3eff69ef7e26d44ec6e8a2b), [`4710f34`](https://github.com/seek-oss/vocab/commit/4710f341f2827643e3eff69ef7e26d44ec6e8a2b)]:
127
- - @vocab/types@0.0.3
128
- - @vocab/core@0.0.2
package/src/file.ts DELETED
@@ -1,4 +0,0 @@
1
- import { promises as fs } from 'fs';
2
-
3
- export const mkdir = fs.mkdir;
4
- export const writeFile = fs.writeFile;
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export { pull } from './pull-translations';
2
- export { push } from './push-translations';
package/src/logger.ts DELETED
@@ -1,9 +0,0 @@
1
- import chalk from 'chalk';
2
- import debug from 'debug';
3
-
4
- export const trace = debug(`vocab:phrase`);
5
-
6
- export const log = (...params: unknown[]) => {
7
- // eslint-disable-next-line no-console
8
- console.log(chalk.yellow('Vocab'), ...params);
9
- };