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.
- package/.editorconfig +9 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +53 -46
- package/.github/workflows/ci-cd.yml +5 -5
- package/.github/workflows/commitlint.yml +1 -1
- package/.github/workflows/daily-help-update.yml +4 -4
- package/.github/workflows/daily-tx-pull.yml +4 -4
- package/.github/workflows/signature-assistant.yml +3 -3
- package/.prettierignore +11 -0
- package/CHANGELOG.md +7 -0
- package/README.md +12 -12
- package/commitlint.config.js +3 -3
- package/dist/l10n.js +224 -232
- package/dist/l10n.js.map +1 -1
- package/dist/localeData.js +223 -232
- package/dist/localeData.js.map +1 -1
- package/dist/supportedLocales.js +123 -130
- package/dist/supportedLocales.js.map +1 -1
- package/eslint.config.mjs +13 -0
- package/lib/batch.js +10 -12
- package/lib/progress-logger.mjs +33 -33
- package/lib/transifex.js +145 -144
- package/lib/validate.mjs +32 -31
- package/package.json +7 -8
- package/prettier.config.mjs +3 -0
- package/release.config.js +13 -13
- package/renovate.json5 +3 -5
- package/scripts/build-data.mjs +33 -49
- package/scripts/build-i18n-src.js +29 -28
- package/scripts/freshdesk-api.js +129 -144
- package/scripts/help-utils.js +129 -139
- package/scripts/tx-pull-editor.mjs +54 -51
- package/scripts/tx-pull-help-articles.js +14 -14
- package/scripts/tx-pull-help-names.js +14 -14
- package/scripts/tx-pull-locale-articles.js +19 -19
- package/scripts/tx-pull-www.mjs +79 -76
- package/scripts/tx-push-help.mjs +87 -96
- package/scripts/tx-push-src.js +65 -65
- package/scripts/validate-extension-inputs.mjs +65 -68
- package/scripts/validate-translations.mjs +33 -29
- package/scripts/validate-www.mjs +45 -43
- package/src/index.mjs +4 -3
- package/src/locale-data.mjs +148 -150
- 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
|
-
* @
|
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
|
-
|
20
|
-
|
21
|
-
|
19
|
+
transifexApi.setup({
|
20
|
+
auth: process.env.TX_TOKEN,
|
21
|
+
})
|
22
22
|
} catch (err) {
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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<
|
139
|
+
* @returns {Promise<Array>} - array of strings, slugs identifying each resource in the project
|
140
140
|
*/
|
141
141
|
const txResources = async function (project) {
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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
|
-
|
162
|
-
|
163
|
-
|
162
|
+
const resources = transifexApi.Resource.filter({
|
163
|
+
project: `o:${ORG_NAME}:p:${project}`,
|
164
|
+
})
|
164
165
|
|
165
|
-
|
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
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
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
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
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 -
|
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
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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.
|
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
|
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": "
|
71
|
-
"eslint-config-scratch": "
|
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",
|
package/release.config.js
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
module.exports = {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
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
|
}
|
package/scripts/build-data.mjs
CHANGED
@@ -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
|
43
|
-
import mkdirp from 'mkdirp'
|
44
|
-
import
|
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
|
-
|
46
|
+
const MSGS_DIR = './locales/'
|
47
|
+
mkdirp.sync(MSGS_DIR)
|
48
|
+
const missingLocales = []
|
50
49
|
|
51
|
-
const combineJson =
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
67
|
-
|
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
|
-
|
77
|
-
|
78
|
-
components.forEach(
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
-
|
91
|
-
|
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
|
-
|
99
|
-
|
82
|
+
process.stdout.write('missing locales:\n' + missingLocales.toString())
|
83
|
+
process.exit(1)
|
100
84
|
}
|