scratch-l10n 5.0.231 → 5.0.232

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.
Files changed (43) hide show
  1. package/.editorconfig +9 -0
  2. package/.github/PULL_REQUEST_TEMPLATE.md +53 -46
  3. package/.github/workflows/ci-cd.yml +5 -5
  4. package/.github/workflows/commitlint.yml +1 -1
  5. package/.github/workflows/daily-help-update.yml +4 -4
  6. package/.github/workflows/daily-tx-pull.yml +4 -4
  7. package/.github/workflows/signature-assistant.yml +3 -3
  8. package/.prettierignore +11 -0
  9. package/CHANGELOG.md +7 -0
  10. package/README.md +12 -12
  11. package/commitlint.config.js +3 -3
  12. package/dist/l10n.js +224 -232
  13. package/dist/l10n.js.map +1 -1
  14. package/dist/localeData.js +223 -232
  15. package/dist/localeData.js.map +1 -1
  16. package/dist/supportedLocales.js +123 -130
  17. package/dist/supportedLocales.js.map +1 -1
  18. package/eslint.config.mjs +13 -0
  19. package/lib/batch.js +10 -12
  20. package/lib/progress-logger.mjs +33 -33
  21. package/lib/transifex.js +145 -144
  22. package/lib/validate.mjs +32 -31
  23. package/package.json +7 -8
  24. package/prettier.config.mjs +3 -0
  25. package/release.config.js +13 -13
  26. package/renovate.json5 +3 -5
  27. package/scripts/build-data.mjs +33 -49
  28. package/scripts/build-i18n-src.js +29 -28
  29. package/scripts/freshdesk-api.js +129 -144
  30. package/scripts/help-utils.js +129 -139
  31. package/scripts/tx-pull-editor.mjs +54 -51
  32. package/scripts/tx-pull-help-articles.js +14 -14
  33. package/scripts/tx-pull-help-names.js +14 -14
  34. package/scripts/tx-pull-locale-articles.js +19 -19
  35. package/scripts/tx-pull-www.mjs +79 -76
  36. package/scripts/tx-push-help.mjs +87 -96
  37. package/scripts/tx-push-src.js +65 -65
  38. package/scripts/validate-extension-inputs.mjs +65 -68
  39. package/scripts/validate-translations.mjs +33 -29
  40. package/scripts/validate-www.mjs +45 -43
  41. package/src/index.mjs +4 -3
  42. package/src/locale-data.mjs +148 -150
  43. package/src/supported-locales.mjs +124 -131
package/lib/transifex.js CHANGED
@@ -1,29 +1,29 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * @fileoverview
4
+ * @file
5
5
  * Utilities for interfacing with Transifex API 3.
6
6
  */
7
7
 
8
- const transifexApi = require('@transifex/api').transifexApi;
9
- const download = require('download');
8
+ const transifexApi = require('@transifex/api').transifexApi
9
+ const download = require('download')
10
10
 
11
11
  /**
12
12
  * @import {Collection, JsonApiResource} from '@transifex/api';
13
13
  */
14
14
 
15
- const ORG_NAME = 'llk';
16
- const SOURCE_LOCALE = 'en';
15
+ const ORG_NAME = 'llk'
16
+ const SOURCE_LOCALE = 'en'
17
17
 
18
18
  try {
19
- transifexApi.setup({
20
- auth: process.env.TX_TOKEN
21
- });
19
+ transifexApi.setup({
20
+ auth: process.env.TX_TOKEN,
21
+ })
22
22
  } catch (err) {
23
- if (!process.env.TX_TOKEN) {
24
- throw new Error('TX_TOKEN is not defined.');
25
- }
26
- throw err;
23
+ if (!process.env.TX_TOKEN) {
24
+ throw new Error('TX_TOKEN is not defined.')
25
+ }
26
+ throw err
27
27
  }
28
28
 
29
29
  /*
@@ -46,13 +46,13 @@ try {
46
46
  * @returns {Promise<JsonApiResource[]>} An array of all resources in the collection.
47
47
  */
48
48
  const collectAll = async function (collection) {
49
- await collection.fetch(); // fetch the first page if it hasn't already been fetched
50
- const collected = [];
51
- for await (const item of collection.all()) {
52
- collected.push(item);
53
- }
54
- return collected;
55
- };
49
+ await collection.fetch() // fetch the first page if it hasn't already been fetched
50
+ const collected = []
51
+ for await (const item of collection.all()) {
52
+ collected.push(item)
53
+ }
54
+ return collected
55
+ }
56
56
 
57
57
  /**
58
58
  * Creates a download event for a specific project, resource, and locale.
@@ -64,34 +64,34 @@ const collectAll = async function (collection) {
64
64
  * @returns {Promise<string>} - URL to download the resource
65
65
  */
66
66
  const getResourceLocation = async function (projectSlug, resourceSlug, localeCode, mode = 'default') {
67
- const resource = {
68
- data: {
69
- id: `o:${ORG_NAME}:p:${projectSlug}:r:${resourceSlug}`,
70
- type: 'resources'
71
- }
72
- };
73
-
74
- // if locale is English, create a download event of the source file
75
- if (localeCode === SOURCE_LOCALE) {
76
- return await transifexApi.ResourceStringsAsyncDownload.download({
77
- resource
78
- });
79
- }
80
-
81
- const language = {
82
- data: {
83
- id: `l:${localeCode}`,
84
- type: 'languages'
85
- }
86
- };
87
-
88
- // if locale is not English, create a download event of the translation file
89
- return await transifexApi.ResourceTranslationsAsyncDownload.download({
90
- mode,
91
- resource,
92
- language
93
- });
94
- };
67
+ const resource = {
68
+ data: {
69
+ id: `o:${ORG_NAME}:p:${projectSlug}:r:${resourceSlug}`,
70
+ type: 'resources',
71
+ },
72
+ }
73
+
74
+ // if locale is English, create a download event of the source file
75
+ if (localeCode === SOURCE_LOCALE) {
76
+ return await transifexApi.ResourceStringsAsyncDownload.download({
77
+ resource,
78
+ })
79
+ }
80
+
81
+ const language = {
82
+ data: {
83
+ id: `l:${localeCode}`,
84
+ type: 'languages',
85
+ },
86
+ }
87
+
88
+ // if locale is not English, create a download event of the translation file
89
+ return await transifexApi.ResourceTranslationsAsyncDownload.download({
90
+ mode,
91
+ resource,
92
+ language,
93
+ })
94
+ }
95
95
 
96
96
  /**
97
97
  * Pulls a translation json from transifex, for a specific project, resource, and locale.
@@ -103,67 +103,68 @@ const getResourceLocation = async function (projectSlug, resourceSlug, localeCod
103
103
  * strings, if the local is the source language)
104
104
  */
105
105
  const txPull = async function (project, resource, locale, mode = 'default') {
106
- let buffer;
107
- try {
108
- const url = await getResourceLocation(project, resource, locale, mode);
109
- for (let i = 0; i < 5; i++) {
110
- if (i > 0) {
111
- console.log(`Retrying txPull download after ${i} failed attempt(s)`);
112
- }
113
- try {
114
- buffer = await download(url); // might throw(?)
115
- break;
116
- } catch (e) {
117
- console.error(e, {project, resource, locale, buffer});
118
- }
119
- }
120
- if (!buffer) {
121
- throw Error(`txPull download failed after 5 retries: ${url}`);
122
- }
123
- buffer = buffer.toString();
124
- return JSON.parse(buffer);
125
- } catch (e) {
126
- e.cause = {
127
- project,
128
- resource,
129
- locale,
130
- buffer
131
- };
132
- throw e;
106
+ let buffer
107
+ try {
108
+ const url = await getResourceLocation(project, resource, locale, mode)
109
+ for (let i = 0; i < 5; i++) {
110
+ if (i > 0) {
111
+ console.log(`Retrying txPull download after ${i} failed attempt(s)`)
112
+ }
113
+ try {
114
+ buffer = await download(url) // might throw(?)
115
+ break
116
+ } catch (e) {
117
+ console.error(e, { project, resource, locale, buffer })
118
+ }
119
+ }
120
+ if (!buffer) {
121
+ throw Error(`txPull download failed after 5 retries: ${url}`)
133
122
  }
134
- };
123
+ buffer = buffer.toString()
124
+ return JSON.parse(buffer)
125
+ } catch (e) {
126
+ e.cause = {
127
+ project,
128
+ resource,
129
+ locale,
130
+ buffer,
131
+ }
132
+ throw e
133
+ }
134
+ }
135
135
 
136
136
  /**
137
137
  * Given a project, returns a list of the slugs of all resources in the project
138
138
  * @param {string} project - project slug (for example, "scratch-website")
139
- * @returns {Promise<array>} - array of strings, slugs identifying each resource in the project
139
+ * @returns {Promise<Array>} - array of strings, slugs identifying each resource in the project
140
140
  */
141
141
  const txResources = async function (project) {
142
- const resources = transifexApi.Resource.filter({
143
- project: `o:${ORG_NAME}:p:${project}`
144
- });
145
-
146
- const resourcesData = await collectAll(resources);
147
-
148
- const slugs = resourcesData.map(r =>
149
- // r.id is a longer id string, like "o:llk:p:scratch-website:r:about-l10njson"
150
- // We just want the slug that comes after ":r:" ("about-l10njson")
151
- r.id.split(':r:')[1]
152
- );
153
- return slugs;
154
- };
142
+ const resources = transifexApi.Resource.filter({
143
+ project: `o:${ORG_NAME}:p:${project}`,
144
+ })
145
+
146
+ const resourcesData = await collectAll(resources)
147
+
148
+ const slugs = resourcesData.map(
149
+ r =>
150
+ // r.id is a longer id string, like "o:llk:p:scratch-website:r:about-l10njson"
151
+ // We just want the slug that comes after ":r:" ("about-l10njson")
152
+ r.id.split(':r:')[1],
153
+ )
154
+ return slugs
155
+ }
155
156
 
156
157
  /**
157
158
  * @param {string} project - project slug (for example)
158
159
  * @returns {Promise<JsonApiResource[]>} - array of resource objects
159
160
  */
160
161
  const txResourcesObjects = async function (project) {
161
- const resources = transifexApi.Resource.filter({
162
- project: `o:${ORG_NAME}:p:${project}`
163
- });
162
+ const resources = transifexApi.Resource.filter({
163
+ project: `o:${ORG_NAME}:p:${project}`,
164
+ })
164
165
 
165
- return collectAll(resources);
166
- };
166
+ return collectAll(resources)
167
+ }
167
168
 
168
169
  /**
169
170
  * Gets available languages for a project
@@ -171,15 +172,15 @@ const txResourcesObjects = async function (project) {
171
172
  * @returns {Promise<string[]>} - list of language codes
172
173
  */
173
174
  const txAvailableLanguages = async function (slug) {
174
- const project = await transifexApi.Project.get({
175
- organization: `o:${ORG_NAME}`,
176
- slug: slug
177
- });
178
-
179
- const languages = await project.fetch('languages');
180
- const languagesData = await collectAll(languages);
181
- return languagesData.map(l => l.attributes.code);
182
- };
175
+ const project = await transifexApi.Project.get({
176
+ organization: `o:${ORG_NAME}`,
177
+ slug: slug,
178
+ })
179
+
180
+ const languages = await project.fetch('languages')
181
+ const languagesData = await collectAll(languages)
182
+ return languagesData.map(l => l.attributes.code)
183
+ }
183
184
 
184
185
  /**
185
186
  * Uploads English source strings to a resource in transifex
@@ -188,54 +189,54 @@ const txAvailableLanguages = async function (slug) {
188
189
  * @param {object} sourceStrings - json of source strings
189
190
  */
190
191
  const txPush = async function (project, resource, sourceStrings) {
191
- const resourceObj = {
192
- data: {
193
- id: `o:${ORG_NAME}:p:${project}:r:${resource}`,
194
- type: 'resources'
195
- }
196
- };
197
-
198
- await transifexApi.ResourceStringsAsyncUpload.upload({
199
- resource: resourceObj,
200
- content: JSON.stringify(sourceStrings)
201
- });
202
- };
192
+ const resourceObj = {
193
+ data: {
194
+ id: `o:${ORG_NAME}:p:${project}:r:${resource}`,
195
+ type: 'resources',
196
+ },
197
+ }
198
+
199
+ await transifexApi.ResourceStringsAsyncUpload.upload({
200
+ resource: resourceObj,
201
+ content: JSON.stringify(sourceStrings),
202
+ })
203
+ }
203
204
 
204
205
  /**
205
206
  * Creates a new resource, and then uploads source strings to it if they are provided
206
207
  * @param {string} project - project slug (for example, "scratch-editor")
207
208
  * @param {object} resource - object of resource information
208
209
  * @param {string} resource.slug - resource slug (for example, "blocks")
209
- * @param {string} resource.name - resource name
210
+ * @param {string} resource.name - human-readable name for the resource
210
211
  * @param {string} resource.i18nType - i18n format id
211
212
  * @param {object} resource.sourceStrings - json object of source strings
212
213
  */
213
- const txCreateResource = async function (project, {slug, name, i18nType, sourceStrings}) {
214
- const i18nFormat = {
215
- data: {
216
- id: i18nType || 'KEYVALUEJSON',
217
- type: 'i18n_formats'
218
- }
219
- };
220
-
221
- const projectObj = {
222
- data: {
223
- id: `o:${ORG_NAME}:p:${project}`,
224
- type: 'projects'
225
- }
226
- };
227
-
228
- await transifexApi.Resource.create({
229
- attributes: {slug: slug, name: name},
230
- relationships: {
231
- i18n_format: i18nFormat,
232
- project: projectObj
233
- }
234
- });
235
-
236
- if (sourceStrings) {
237
- await txPush(project, slug, sourceStrings);
238
- }
239
- };
214
+ const txCreateResource = async function (project, { slug, name, i18nType, sourceStrings }) {
215
+ const i18nFormat = {
216
+ data: {
217
+ id: i18nType || 'KEYVALUEJSON',
218
+ type: 'i18n_formats',
219
+ },
220
+ }
221
+
222
+ const projectObj = {
223
+ data: {
224
+ id: `o:${ORG_NAME}:p:${project}`,
225
+ type: 'projects',
226
+ },
227
+ }
228
+
229
+ await transifexApi.Resource.create({
230
+ attributes: { slug: slug, name: name },
231
+ relationships: {
232
+ i18n_format: i18nFormat,
233
+ project: projectObj,
234
+ },
235
+ })
236
+
237
+ if (sourceStrings) {
238
+ await txPush(project, slug, sourceStrings)
239
+ }
240
+ }
240
241
 
241
- module.exports = {txPull, txPush, txResources, txResourcesObjects, txCreateResource, txAvailableLanguages};
242
+ module.exports = { txPull, txPush, txResources, txResourcesObjects, txCreateResource, txAvailableLanguages }
package/lib/validate.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import assert from 'assert';
2
- import parse from 'format-message-parse';
1
+ import assert from 'assert'
2
+ import parse from 'format-message-parse'
3
3
 
4
4
  // filter placeholders out of a message
5
5
  // parse('a message with a {value} and {count, plural, one {one} other {more}}.')
@@ -11,37 +11,38 @@ import parse from 'format-message-parse';
11
11
  // '.'
12
12
  // ]
13
13
  // placeholders are always an array, so filter for array elements to find the placeholders
14
- const placeholders = message => (
15
- // this will throw an error if the message is not valid ICU
16
- // single quote (as in French l'année) messes up the parse and is not
17
- // relevant for this check, so strip them out
18
- parse(message.replace(/'/g, '')).filter(item => Array.isArray(item))
19
- );
14
+ const placeholders = message =>
15
+ // this will throw an error if the message is not valid ICU
16
+ // single quote (as in French l'année) messes up the parse and is not
17
+ // relevant for this check, so strip them out
18
+ parse(message.replace(/'/g, '')).filter(item => Array.isArray(item))
20
19
 
21
20
  const validMessage = (message, source) => {
22
- const transPlaceholders = placeholders(message.toString());
23
- const srcPlaceholders = placeholders(source.toString());
24
- // different number of placeholders
25
- if (transPlaceholders.length !== srcPlaceholders.length) {
26
- return false;
27
- }
28
- // TODO: Add checking to make sure placeholders in source have not been translated
29
- // TODO: Add validation of scratch-blocks placeholders
30
- return true;
31
- };
21
+ const transPlaceholders = placeholders(message.toString())
22
+ const srcPlaceholders = placeholders(source.toString())
23
+ // different number of placeholders
24
+ if (transPlaceholders.length !== srcPlaceholders.length) {
25
+ return false
26
+ }
27
+ // TODO: Add checking to make sure placeholders in source have not been translated
28
+ // TODO: Add validation of scratch-blocks placeholders
29
+ return true
30
+ }
32
31
 
33
32
  const validateTranslations = (translation, source) => {
34
- const locale = translation.locale;
35
- const translations = translation.translations;
36
- const transKeys = Object.keys(translations);
37
- const sourceKeys = Object.keys(source);
38
- assert.strictEqual(transKeys.length, sourceKeys.length, `locale ${locale} has a different number of message keys`);
39
- transKeys.map(item => assert(sourceKeys.includes(item), `locale ${locale} has key ${item} not in the source`));
40
- sourceKeys.map(item => assert(transKeys.includes(item), `locale ${locale} is missing key ${item}`));
41
- sourceKeys.map(item => assert(
42
- validMessage(translations[item], source[item]),
43
- `locale ${locale}: "${translations[item]}" is not a valid translation for "${source[item]}"`)
44
- );
45
- };
33
+ const locale = translation.locale
34
+ const translations = translation.translations
35
+ const transKeys = Object.keys(translations)
36
+ const sourceKeys = Object.keys(source)
37
+ assert.strictEqual(transKeys.length, sourceKeys.length, `locale ${locale} has a different number of message keys`)
38
+ transKeys.map(item => assert(sourceKeys.includes(item), `locale ${locale} has key ${item} not in the source`))
39
+ sourceKeys.map(item => assert(transKeys.includes(item), `locale ${locale} is missing key ${item}`))
40
+ sourceKeys.map(item =>
41
+ assert(
42
+ validMessage(translations[item], source[item]),
43
+ `locale ${locale}: "${translations[item]}" is not a valid translation for "${source[item]}"`,
44
+ ),
45
+ )
46
+ }
46
47
 
47
- export {validateTranslations, validMessage};
48
+ export { validateTranslations, validMessage }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scratch-l10n",
3
- "version": "5.0.231",
3
+ "version": "5.0.232",
4
4
  "description": "Localization for the Scratch 3.0 components",
5
5
  "main": "./dist/l10n.js",
6
6
  "browser": "./src/index.mjs",
@@ -12,8 +12,9 @@
12
12
  "build": "npm run clean && npm run build:data && webpack --progress --colors --bail",
13
13
  "build:data": "node scripts/build-data.mjs",
14
14
  "clean": "rimraf ./dist ./locales && mkdirp dist locales",
15
+ "format": "prettier --write . && eslint --fix",
15
16
  "lint": "npm run lint:js && npm run lint:json",
16
- "lint:js": "eslint . --ext .js,.mjs,.cjs",
17
+ "lint:js": "eslint && prettier --check .",
17
18
  "lint:json": "jshint -e .json www editor/blocks editor/extensions editor/interface editor/paint-editor",
18
19
  "prepare": "husky install",
19
20
  "pull:blocks": "node scripts/tx-pull-editor.mjs scratch-editor blocks ./editor/blocks/",
@@ -54,7 +55,6 @@
54
55
  "devDependencies": {
55
56
  "@babel/cli": "7.27.1",
56
57
  "@babel/core": "7.27.1",
57
- "@babel/eslint-parser": "7.27.1",
58
58
  "@babel/node": "7.27.1",
59
59
  "@babel/plugin-proposal-object-rest-spread": "7.20.7",
60
60
  "@babel/plugin-syntax-dynamic-import": "7.8.3",
@@ -64,16 +64,14 @@
64
64
  "@commitlint/cli": "18.6.1",
65
65
  "@commitlint/config-conventional": "18.6.3",
66
66
  "async": "3.2.6",
67
- "babel-eslint": "10.1.0",
68
67
  "babel-loader": "8.4.1",
69
68
  "babel-plugin-react-intl": "3.5.1",
70
- "eslint": "8.57.1",
71
- "eslint-config-scratch": "9.0.9",
72
- "eslint-plugin-import": "2.31.0",
73
- "eslint-plugin-react": "7.37.5",
69
+ "eslint": "9.26.0",
70
+ "eslint-config-scratch": "11.0.1",
74
71
  "format-message-cli": "6.2.4",
75
72
  "format-message-parse": "6.2.4",
76
73
  "glob": "7.2.3",
74
+ "globals": "16.0.0",
77
75
  "husky": "8.0.3",
78
76
  "jshint": "2.13.6",
79
77
  "json": "^9.0.6",
@@ -83,6 +81,7 @@
83
81
  "node-fetch": "2.7.0",
84
82
  "p-limit": "2.3.0",
85
83
  "p-queue": "3.2.0",
84
+ "prettier": "3.5.3",
86
85
  "rimraf": "2.7.1",
87
86
  "scratch-semantic-release-config": "3.0.0",
88
87
  "semantic-release": "19.0.5",
@@ -0,0 +1,3 @@
1
+ import { prettierConfigScratch } from 'eslint-config-scratch'
2
+
3
+ export default prettierConfigScratch.recommended
package/release.config.js CHANGED
@@ -1,14 +1,14 @@
1
1
  module.exports = {
2
- extends: 'scratch-semantic-release-config',
3
- branches: [
4
- {
5
- name: 'master'
6
- // default channel
7
- },
8
- {
9
- name: 'hotfix/*',
10
- channel: 'hotfix',
11
- prerelease: 'hotfix'
12
- }
13
- ]
14
- };
2
+ extends: 'scratch-semantic-release-config',
3
+ branches: [
4
+ {
5
+ name: 'master',
6
+ // default channel
7
+ },
8
+ {
9
+ name: 'hotfix/*',
10
+ channel: 'hotfix',
11
+ prerelease: 'hotfix',
12
+ },
13
+ ],
14
+ }
package/renovate.json5 CHANGED
@@ -1,7 +1,5 @@
1
1
  {
2
- "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
- "extends": [
4
- "github>scratchfoundation/scratch-renovate-config:js-lib-bundled"
5
- ],
6
- "baseBranches": ["master"]
2
+ $schema: 'https://docs.renovatebot.com/renovate-schema.json',
3
+ extends: ['github>scratchfoundation/scratch-renovate-config:js-lib-bundled'],
4
+ baseBranches: ['master'],
7
5
  }
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
-
3
2
  /*
4
3
  Generates locales/<component>-msgs.js for each component (gui, etc) from the
5
4
  current translation files for each language for that component
@@ -38,63 +37,48 @@ NOTE: blocks messages are plain key-value JSON files
38
37
 
39
38
  Missing locales are ignored, react-intl will use the default messages for them.
40
39
  */
41
- import * as fs from 'fs';
42
- import * as path from 'path';
43
- import mkdirp from 'mkdirp';
44
- import defaultsDeep from 'lodash.defaultsdeep';
45
- import locales from '../src/supported-locales.mjs';
40
+ import * as fs from 'fs'
41
+ import defaultsDeep from 'lodash.defaultsdeep'
42
+ import mkdirp from 'mkdirp'
43
+ import * as path from 'path'
44
+ import locales from '../src/supported-locales.mjs'
46
45
 
47
- const MSGS_DIR = './locales/';
48
- mkdirp.sync(MSGS_DIR);
49
- let missingLocales = [];
46
+ const MSGS_DIR = './locales/'
47
+ mkdirp.sync(MSGS_DIR)
48
+ const missingLocales = []
50
49
 
51
- const combineJson = (component) => {
52
- return Object.keys(locales).reduce((collection, lang) => {
53
- try {
54
- let langData = JSON.parse(
55
- fs.readFileSync(path.resolve('editor', component, lang + '.json'), 'utf8')
56
- );
57
- collection[lang] = langData;
58
- } catch (e) {
59
- missingLocales.push(component + ':' + lang + '\n');
60
- }
61
- return collection;
62
- }, {});
63
- };
50
+ const combineJson = component =>
51
+ Object.keys(locales).reduce((collection, lang) => {
52
+ try {
53
+ const langData = JSON.parse(fs.readFileSync(path.resolve('editor', component, lang + '.json'), 'utf8'))
54
+ collection[lang] = langData
55
+ } catch {
56
+ missingLocales.push(component + ':' + lang + '\n')
57
+ }
58
+ return collection
59
+ }, {})
64
60
 
65
61
  // generate the blocks messages: files are plain key-value JSON
66
- let blocksMessages = combineJson('blocks');
67
- let blockData =
68
- '// GENERATED FILE:\n' +
69
- 'export default ' +
70
- JSON.stringify(blocksMessages, null, 2) +
71
- ';\n';
62
+ const blocksMessages = combineJson('blocks')
63
+ const blockData = '// GENERATED FILE:\n' + 'export default ' + JSON.stringify(blocksMessages, null, 2) + ';\n'
72
64
 
73
- fs.writeFileSync(MSGS_DIR + 'blocks-msgs.js', blockData);
65
+ fs.writeFileSync(MSGS_DIR + 'blocks-msgs.js', blockData)
74
66
 
75
67
  // generate messages for gui components - all files are plain key-value JSON
76
- let components = ['interface', 'extensions', 'paint-editor'];
77
- let editorMsgs = {};
78
- components.forEach((component) => {
79
- let messages = combineJson(component);
80
- let data =
81
- '// GENERATED FILE:\n' +
82
- 'export default ' +
83
- JSON.stringify(messages, null, 2) +
84
- ';\n';
85
- fs.writeFileSync(MSGS_DIR + component + '-msgs.js', data);
86
- defaultsDeep(editorMsgs, messages);
87
- });
68
+ const components = ['interface', 'extensions', 'paint-editor']
69
+ const editorMsgs = {}
70
+ components.forEach(component => {
71
+ const messages = combineJson(component)
72
+ const data = '// GENERATED FILE:\n' + 'export default ' + JSON.stringify(messages, null, 2) + ';\n'
73
+ fs.writeFileSync(MSGS_DIR + component + '-msgs.js', data)
74
+ defaultsDeep(editorMsgs, messages)
75
+ })
88
76
 
89
77
  // generate combined editor-msgs file
90
- let editorData =
91
- '// GENERATED FILE:\n' +
92
- 'export default ' +
93
- JSON.stringify(editorMsgs, null, 2) +
94
- ';\n';
95
- fs.writeFileSync(MSGS_DIR + 'editor-msgs.js', editorData);
78
+ const editorData = '// GENERATED FILE:\n' + 'export default ' + JSON.stringify(editorMsgs, null, 2) + ';\n'
79
+ fs.writeFileSync(MSGS_DIR + 'editor-msgs.js', editorData)
96
80
 
97
81
  if (missingLocales.length > 0) {
98
- process.stdout.write('missing locales:\n' + missingLocales.toString());
99
- process.exit(1);
82
+ process.stdout.write('missing locales:\n' + missingLocales.toString())
83
+ process.exit(1)
100
84
  }