scratch-l10n 5.0.308 → 6.0.0
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/CHANGELOG.md +57 -0
- package/README.md +6 -0
- package/dist/l10n.js +3 -0
- package/dist/l10n.js.map +1 -1
- package/dist/localeData.js +3 -0
- package/dist/localeData.js.map +1 -1
- package/dist/supportedLocales.js +3 -0
- package/dist/supportedLocales.js.map +1 -1
- package/package.json +24 -22
- package/scripts/{build-data.mjs → build-data.mts} +15 -6
- package/scripts/{build-i18n-src.js → build-i18n-src.mts} +16 -11
- package/scripts/lib/concurrent.mts +37 -0
- package/scripts/lib/freshdesk-api.mts +322 -0
- package/scripts/lib/help-utils.mts +221 -0
- package/{lib/progress-logger.mjs → scripts/lib/progress-logger.mts} +10 -5
- package/scripts/lib/transifex-formats.mts +53 -0
- package/scripts/lib/transifex-objects.mts +143 -0
- package/scripts/lib/transifex.mts +284 -0
- package/scripts/lib/validate.mts +107 -0
- package/scripts/tsconfig.json +20 -0
- package/scripts/tx-pull-editor.mts +74 -0
- package/scripts/{tx-pull-help-articles.js → tx-pull-help-articles.mts} +5 -13
- package/scripts/{tx-pull-help-names.js → tx-pull-help-names.mts} +5 -13
- package/scripts/{tx-pull-locale-articles.js → tx-pull-locale-articles.mts} +5 -13
- package/scripts/{tx-pull-www.mjs → tx-pull-www.mts} +16 -29
- package/scripts/{tx-push-help.mjs → tx-push-help.mts} +39 -37
- package/scripts/{tx-push-src.js → tx-push-src.mts} +13 -20
- package/scripts/update-translations.sh +2 -2
- package/scripts/{validate-extension-inputs.mjs → validate-extension-inputs.mts} +20 -10
- package/scripts/{validate-translations.mjs → validate-translations.mts} +7 -12
- package/scripts/{validate-www.mjs → validate-www.mts} +15 -13
- package/src/supported-locales.mjs +3 -0
- package/www/scratch-website.about-l10njson/nn.json +1 -1
- package/www/scratch-website.splash-l10njson/mi.json +2 -2
- package/www/scratch-website.teacher-faq-l10njson/cy.json +1 -1
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -75
- package/.github/workflows/ci-cd.yml +0 -55
- package/.github/workflows/commitlint.yml +0 -12
- package/.github/workflows/daily-help-update.yml +0 -40
- package/.github/workflows/daily-tx-pull.yml +0 -54
- package/.github/workflows/signature-assistant.yml +0 -31
- package/lib/batch.js +0 -15
- package/lib/transifex.js +0 -242
- package/lib/validate.mjs +0 -48
- package/scripts/freshdesk-api.js +0 -149
- package/scripts/help-utils.js +0 -190
- package/scripts/tx-pull-editor.mjs +0 -83
@@ -1,10 +1,11 @@
|
|
1
|
-
#!/usr/bin/env
|
1
|
+
#!/usr/bin/env tsx
|
2
2
|
/**
|
3
3
|
* @file
|
4
4
|
* Script get Knowledge base articles from Freshdesk and push them to transifex.
|
5
5
|
*/
|
6
|
-
import {
|
7
|
-
import
|
6
|
+
import FreshdeskApi, { FreshdeskArticleStatus, FreshdeskCategory, FreshdeskFolder } from './lib/freshdesk-api.mts'
|
7
|
+
import { TransifexStringsKeyValueJson, TransifexStringsStructuredJson } from './lib/transifex-formats.mts'
|
8
|
+
import { txPush, txCreateResource, JsonApiException } from './lib/transifex.mts'
|
8
9
|
|
9
10
|
const args = process.argv.slice(2)
|
10
11
|
|
@@ -26,65 +27,63 @@ if (!process.env.TX_TOKEN || !process.env.FRESHDESK_TOKEN || args.length > 0) {
|
|
26
27
|
const FD = new FreshdeskApi('https://mitscratch.freshdesk.com', process.env.FRESHDESK_TOKEN)
|
27
28
|
const TX_PROJECT = 'scratch-help'
|
28
29
|
|
29
|
-
const categoryNames = {}
|
30
|
-
const folderNames = {}
|
30
|
+
const categoryNames: TransifexStringsKeyValueJson = {}
|
31
|
+
const folderNames: TransifexStringsKeyValueJson = {}
|
31
32
|
|
32
33
|
/**
|
33
34
|
* Generate a transifex id from the name and id field of an objects. Remove spaces and '/'
|
34
35
|
* from the name and append '.<id>' Transifex ids (slugs) have a max length of 50. Use at most
|
35
36
|
* 30 characters of the name to allow for Freshdesk id, and a suffix like '_json'
|
36
|
-
* @param
|
37
|
-
* @returns
|
37
|
+
* @param item - data from Freshdesk that includes the name and id of a category or folder
|
38
|
+
* @returns generated transifex id
|
38
39
|
*/
|
39
|
-
const makeTxId = item => `${item.name.replace(/[ /]/g, '').slice(0, 30)}_${item.id}`
|
40
|
+
const makeTxId = (item: FreshdeskFolder) => `${item.name.replace(/[ /]/g, '').slice(0, 30)}_${item.id}`
|
40
41
|
|
41
|
-
const txPushResource = async (
|
42
|
+
const txPushResource = async (
|
43
|
+
name: string,
|
44
|
+
articles: TransifexStringsStructuredJson | TransifexStringsKeyValueJson,
|
45
|
+
type: string,
|
46
|
+
) => {
|
42
47
|
const resourceData = {
|
43
48
|
slug: name,
|
44
49
|
name: name,
|
45
|
-
|
50
|
+
i18nType: type,
|
46
51
|
priority: 0, // default to normal priority
|
47
52
|
content: articles,
|
48
53
|
}
|
49
54
|
|
50
55
|
try {
|
51
56
|
await txPush(TX_PROJECT, name, articles)
|
52
|
-
} catch (
|
57
|
+
} catch (errUnknown) {
|
58
|
+
const err = errUnknown as JsonApiException
|
53
59
|
if (err.statusCode !== 404) {
|
54
|
-
|
55
|
-
process.stdout.write(`Transifex Error ${err.response.statusCode.toString()}: ${err.response.body}\n`)
|
56
|
-
process.exitCode = 1
|
57
|
-
return
|
60
|
+
throw err
|
58
61
|
}
|
59
62
|
|
60
63
|
// file not found - create it, but also give message
|
61
64
|
process.stdout.write(`Transifex Resource not found, creating: ${name}\n`)
|
62
|
-
|
63
|
-
await txCreateResource(TX_PROJECT, resourceData)
|
64
|
-
}
|
65
|
+
await txCreateResource(TX_PROJECT, resourceData)
|
65
66
|
}
|
66
67
|
}
|
67
68
|
|
68
69
|
/**
|
69
70
|
* get a flattened list of folders associated with the specified categories
|
70
|
-
* @param
|
71
|
-
* @returns
|
71
|
+
* @param categories - array of categories the folders belong to
|
72
|
+
* @returns flattened list of folders from all requested categories
|
72
73
|
*/
|
73
|
-
const getFolders = async categories => {
|
74
|
+
const getFolders = async (categories: FreshdeskCategory[]) => {
|
74
75
|
const categoryFolders = await Promise.all(categories.map(category => FD.listFolders(category)))
|
75
|
-
return [].concat(...categoryFolders)
|
76
|
+
return ([] as FreshdeskCategory[]).concat(...categoryFolders)
|
76
77
|
}
|
77
78
|
|
78
|
-
const PUBLISHED = 2 // in Freshdesk, draft status = 1, and published = 2
|
79
|
-
|
80
79
|
/**
|
81
80
|
* Save articles in a particular folder
|
82
|
-
* @param
|
81
|
+
* @param folder - The folder object
|
83
82
|
*/
|
84
|
-
const saveArticles = async folder => {
|
85
|
-
await FD.listArticles(folder).then(json => {
|
86
|
-
const txArticles = json.reduce((strings, current) => {
|
87
|
-
if (current.status ===
|
83
|
+
const saveArticles = async (folder: FreshdeskFolder) => {
|
84
|
+
await FD.listArticles(folder).then(async json => {
|
85
|
+
const txArticles = json.reduce((strings: TransifexStringsStructuredJson, current) => {
|
86
|
+
if (current.status === FreshdeskArticleStatus.published) {
|
88
87
|
strings[`${current.id}`] = {
|
89
88
|
title: {
|
90
89
|
string: current.title,
|
@@ -93,27 +92,28 @@ const saveArticles = async folder => {
|
|
93
92
|
string: current.description,
|
94
93
|
},
|
95
94
|
}
|
96
|
-
if (current.tags
|
95
|
+
if (current.tags?.length) {
|
97
96
|
strings[`${current.id}`].tags = { string: current.tags.toString() }
|
98
97
|
}
|
99
98
|
}
|
100
99
|
return strings
|
101
100
|
}, {})
|
102
101
|
process.stdout.write(`Push ${folder.name} articles to Transifex\n`)
|
103
|
-
txPushResource(`${makeTxId(folder)}_json`, txArticles, 'STRUCTURED_JSON')
|
102
|
+
await txPushResource(`${makeTxId(folder)}_json`, txArticles, 'STRUCTURED_JSON')
|
104
103
|
})
|
105
104
|
}
|
106
105
|
|
107
106
|
/**
|
108
|
-
* @param
|
107
|
+
* @param folders - Array of folders containing articles to be saved
|
109
108
|
*/
|
110
|
-
const saveArticleFolders = async folders => {
|
109
|
+
const saveArticleFolders = async (folders: FreshdeskCategory[]) => {
|
111
110
|
await Promise.all(folders.map(folder => saveArticles(folder)))
|
112
111
|
}
|
113
112
|
|
114
113
|
const syncSources = async () => {
|
115
114
|
await FD.listCategories()
|
116
115
|
.then(json => {
|
116
|
+
console.dir(json)
|
117
117
|
// save category names for translation
|
118
118
|
for (const cat of json.values()) {
|
119
119
|
categoryNames[`${makeTxId(cat)}`] = cat.name
|
@@ -121,16 +121,18 @@ const syncSources = async () => {
|
|
121
121
|
return json
|
122
122
|
})
|
123
123
|
.then(getFolders)
|
124
|
-
.then(data => {
|
124
|
+
.then(async data => {
|
125
125
|
data.forEach(item => {
|
126
126
|
folderNames[`${makeTxId(item)}`] = item.name
|
127
127
|
})
|
128
128
|
process.stdout.write('Push category and folder names to Transifex\n')
|
129
|
-
|
130
|
-
|
129
|
+
await Promise.all([
|
130
|
+
txPushResource('categoryNames_json', categoryNames, 'KEYVALUEJSON'),
|
131
|
+
txPushResource('folderNames_json', folderNames, 'KEYVALUEJSON'),
|
132
|
+
])
|
131
133
|
return data
|
132
134
|
})
|
133
135
|
.then(saveArticleFolders)
|
134
136
|
}
|
135
137
|
|
136
|
-
syncSources()
|
138
|
+
await syncSources()
|
@@ -1,5 +1,4 @@
|
|
1
|
-
#!/usr/bin/env
|
2
|
-
|
1
|
+
#!/usr/bin/env tsx
|
3
2
|
/**
|
4
3
|
* @file
|
5
4
|
* Script to upload a source en.json file to a particular transifex project resource.
|
@@ -7,10 +6,10 @@
|
|
7
6
|
* the person running the script has the the TX_TOKEN environment variable set to an api
|
8
7
|
* token that has developer access.
|
9
8
|
*/
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
import fs from 'fs'
|
10
|
+
import path from 'path'
|
11
|
+
import { TransifexStrings } from './lib/transifex-formats.mts'
|
12
|
+
import { txPush, txCreateResource, JsonApiException } from './lib/transifex.mts'
|
14
13
|
|
15
14
|
const args = process.argv.slice(2)
|
16
15
|
|
@@ -34,11 +33,10 @@ if (args.length < 3 || !process.env.TX_TOKEN) {
|
|
34
33
|
const PROJECT = args[0]
|
35
34
|
const RESOURCE = args[1]
|
36
35
|
|
37
|
-
|
38
|
-
en = JSON.parse(en)
|
36
|
+
const en = JSON.parse(fs.readFileSync(path.resolve(args[2]), 'utf8')) as TransifexStrings<unknown>
|
39
37
|
|
40
38
|
// get the correct resource file type based on transifex project/repo and resource
|
41
|
-
const getResourceType = (project, resource) => {
|
39
|
+
const getResourceType = (project: string, resource: string) => {
|
42
40
|
if (project === 'scratch-website') {
|
43
41
|
// all the resources are KEYVALUEJSON
|
44
42
|
return 'KEYVALUEJSON'
|
@@ -66,21 +64,18 @@ const getResourceType = (project, resource) => {
|
|
66
64
|
// all the resources are Chrome format json files
|
67
65
|
return 'CHROME'
|
68
66
|
}
|
69
|
-
|
70
|
-
|
71
|
-
process.exit(1)
|
67
|
+
|
68
|
+
throw new Error(`Error - Unknown resource type for:\n Project: ${project}, resource: ${resource}\n`)
|
72
69
|
}
|
73
70
|
|
74
71
|
// update Transifex with English source
|
75
72
|
const pushSource = async function () {
|
76
73
|
try {
|
77
74
|
await txPush(PROJECT, RESOURCE, en)
|
78
|
-
} catch (
|
75
|
+
} catch (errUnknown) {
|
76
|
+
const err = errUnknown as JsonApiException
|
79
77
|
if (err.statusCode !== 404) {
|
80
|
-
|
81
|
-
process.stdout.write(`Transifex Error ${err.response.statusCode.toString()}: ${err.response.body}\n`)
|
82
|
-
process.exitCode = 1
|
83
|
-
return
|
78
|
+
throw err
|
84
79
|
}
|
85
80
|
// file not found - create it, but also give message
|
86
81
|
process.stdout.write(`Transifex Resource not found, creating: ${RESOURCE}\n`)
|
@@ -92,9 +87,7 @@ const pushSource = async function () {
|
|
92
87
|
content: en,
|
93
88
|
}
|
94
89
|
await txCreateResource(PROJECT, resourceData)
|
95
|
-
// eslint-disable-next-line require-atomic-updates -- I promise that `process` won't change across `await`
|
96
|
-
process.exitCode = 0
|
97
90
|
}
|
98
91
|
}
|
99
92
|
|
100
|
-
pushSource()
|
93
|
+
await pushSource()
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/bin/bash
|
1
|
+
#!/usr/bin/env bash
|
2
2
|
|
3
3
|
# script for syncing translations from transifex and comitting the changes.
|
4
4
|
|
@@ -7,7 +7,7 @@ set -ev
|
|
7
7
|
|
8
8
|
npm run pull:editor
|
9
9
|
npm run pull:www
|
10
|
-
npm run test
|
10
|
+
npm run test
|
11
11
|
|
12
12
|
# commit any updates and push. Build and release should happen on the push not here.
|
13
13
|
git add .
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/bin/env
|
1
|
+
#!/usr/bin/env tsx
|
2
2
|
/**
|
3
3
|
* @file
|
4
4
|
* Script to validate extension block input placeholders
|
@@ -8,10 +8,12 @@ import async from 'async'
|
|
8
8
|
import fs from 'fs'
|
9
9
|
import path from 'path'
|
10
10
|
import locales from '../src/supported-locales.mjs'
|
11
|
+
import { TransifexStringsKeyValueJson } from './lib/transifex-formats.mts'
|
11
12
|
|
12
13
|
// Globals
|
13
14
|
const JSON_DIR = path.join(process.cwd(), '/editor/extensions')
|
14
|
-
|
15
|
+
|
16
|
+
const source = JSON.parse(fs.readFileSync(`${JSON_DIR}/en.json`, 'utf8')) as TransifexStringsKeyValueJson
|
15
17
|
|
16
18
|
// Matches everything inside brackets, and the brackets themselves.
|
17
19
|
// e.g. matches '[MOTOR_ID]', '[POWER]' from 'altera a potência de [MOTOR_ID] para [POWER]'
|
@@ -19,7 +21,11 @@ const blockInputRegex = /\[.+?\]/g
|
|
19
21
|
|
20
22
|
let numTotalErrors = 0
|
21
23
|
|
22
|
-
|
24
|
+
/**
|
25
|
+
* @param translationData - the translation data to validate
|
26
|
+
* @param locale - validate extension inputs for this locale
|
27
|
+
*/
|
28
|
+
const validateExtensionInputs = (translationData: TransifexStringsKeyValueJson, locale: string) => {
|
23
29
|
let numLocaleErrors = 0
|
24
30
|
for (const block of Object.keys(translationData)) {
|
25
31
|
const englishBlockInputs = source[block].match(blockInputRegex)
|
@@ -29,7 +35,7 @@ const validateExtensionInputs = (translationData, locale) => {
|
|
29
35
|
// If null (meaning no matches), that means that English block inputs exist but translated ones don't.
|
30
36
|
// Coerce it to an empty array so that the assertion below fails, instead of getting the less-helpful error
|
31
37
|
// that we can't call Array.includes on null.
|
32
|
-
const translatedBlockInputs = translationData[block].match(blockInputRegex)
|
38
|
+
const translatedBlockInputs: string[] = translationData[block].match(blockInputRegex) ?? []
|
33
39
|
|
34
40
|
for (const input of englishBlockInputs) {
|
35
41
|
// Currently there are enough errors here that it would be tedious to fix an error, rerun this tool
|
@@ -43,7 +49,7 @@ const validateExtensionInputs = (translationData, locale) => {
|
|
43
49
|
)
|
44
50
|
} catch (err) {
|
45
51
|
numLocaleErrors++
|
46
|
-
console.error(err.message + '\n')
|
52
|
+
console.error((err as Error).message + '\n')
|
47
53
|
}
|
48
54
|
}
|
49
55
|
}
|
@@ -54,16 +60,20 @@ const validateExtensionInputs = (translationData, locale) => {
|
|
54
60
|
}
|
55
61
|
}
|
56
62
|
|
57
|
-
|
58
|
-
|
63
|
+
/**
|
64
|
+
* @param locale - the Transifex ID of the locale
|
65
|
+
* @param callback - completion callback
|
66
|
+
*/
|
67
|
+
const validate = (locale: string, callback: async.ErrorCallback<Error>) => {
|
68
|
+
fs.readFile(`${JSON_DIR}/${locale}.json`, 'utf8', (err, data) => {
|
59
69
|
if (err) callback(err)
|
60
70
|
// let this throw an error if invalid json
|
61
|
-
|
71
|
+
const parsedData = JSON.parse(data) as TransifexStringsKeyValueJson
|
62
72
|
|
63
73
|
try {
|
64
|
-
validateExtensionInputs(
|
74
|
+
validateExtensionInputs(parsedData, locale)
|
65
75
|
} catch (error) {
|
66
|
-
console.error(error.message + '\n')
|
76
|
+
console.error((error as Error).message + '\n')
|
67
77
|
}
|
68
78
|
|
69
79
|
callback()
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/bin/env
|
1
|
+
#!/usr/bin/env tsx
|
2
2
|
/**
|
3
3
|
* @file
|
4
4
|
* Script to validate the translation json
|
@@ -6,13 +6,8 @@
|
|
6
6
|
import async from 'async'
|
7
7
|
import fs from 'fs'
|
8
8
|
import path from 'path'
|
9
|
-
import { validateTranslations } from '../lib/validate.mjs'
|
10
9
|
import locales from '../src/supported-locales.mjs'
|
11
|
-
|
12
|
-
/**
|
13
|
-
* @file
|
14
|
-
* Script to validate the translation json
|
15
|
-
*/
|
10
|
+
import { TransifexEditorStrings, validateTranslations } from './lib/validate.mts'
|
16
11
|
|
17
12
|
const args = process.argv.slice(2)
|
18
13
|
const usage = `
|
@@ -29,16 +24,16 @@ if (args.length < 1) {
|
|
29
24
|
// Globals
|
30
25
|
const JSON_DIR = path.resolve(args[0])
|
31
26
|
|
32
|
-
const source = JSON.parse(fs.readFileSync(`${JSON_DIR}/en.json
|
27
|
+
const source = JSON.parse(fs.readFileSync(`${JSON_DIR}/en.json`, 'utf8')) as TransifexEditorStrings
|
33
28
|
|
34
|
-
const validate = (locale, callback) => {
|
35
|
-
fs.readFile(`${JSON_DIR}/${locale}.json`, (err, data) => {
|
29
|
+
const validate = (locale: string, callback: async.ErrorCallback) => {
|
30
|
+
fs.readFile(`${JSON_DIR}/${locale}.json`, 'utf8', (err, data) => {
|
36
31
|
if (err) callback(err)
|
37
32
|
// let this throw an error if invalid json
|
38
|
-
|
33
|
+
const strings = JSON.parse(data) as TransifexEditorStrings
|
39
34
|
const translations = {
|
40
35
|
locale: locale,
|
41
|
-
translations:
|
36
|
+
translations: strings,
|
42
37
|
}
|
43
38
|
validateTranslations(translations, source)
|
44
39
|
})
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/bin/env
|
1
|
+
#!/usr/bin/env tsx
|
2
2
|
/**
|
3
3
|
* @file
|
4
4
|
* Script to validate the www translation json
|
@@ -7,13 +7,9 @@ import async from 'async'
|
|
7
7
|
import fs from 'fs'
|
8
8
|
import glob from 'glob'
|
9
9
|
import path from 'path'
|
10
|
-
import { validateTranslations } from '../lib/validate.mjs'
|
11
10
|
import locales from '../src/supported-locales.mjs'
|
12
|
-
|
13
|
-
|
14
|
-
* @file
|
15
|
-
* Script to validate the www translation json
|
16
|
-
*/
|
11
|
+
import { TransifexStringsKeyValueJson, TransifexStrings } from './lib/transifex-formats.mts'
|
12
|
+
import { validateTranslations } from './lib/validate.mts'
|
17
13
|
|
18
14
|
const args = process.argv.slice(2)
|
19
15
|
const usage = `
|
@@ -30,21 +26,27 @@ if (args.length < 1) {
|
|
30
26
|
const WWW_DIR = path.resolve(args[0])
|
31
27
|
const RESOURCES = glob.sync(`${path.resolve(WWW_DIR)}/*`)
|
32
28
|
|
33
|
-
|
34
|
-
|
29
|
+
interface LocaleData {
|
30
|
+
locale: string
|
31
|
+
localeFileName: string
|
32
|
+
sourceData: TransifexStrings<string>
|
33
|
+
}
|
34
|
+
|
35
|
+
const validate = (localeData: LocaleData, callback: async.ErrorCallback) => {
|
36
|
+
fs.readFile(localeData.localeFileName, 'utf8', (err, data) => {
|
35
37
|
if (err) callback(err)
|
36
38
|
// let this throw an error if invalid json
|
37
|
-
|
39
|
+
const strings = JSON.parse(data) as TransifexStringsKeyValueJson
|
38
40
|
const translations = {
|
39
41
|
locale: localeData.locale,
|
40
|
-
translations:
|
42
|
+
translations: strings,
|
41
43
|
}
|
42
44
|
validateTranslations(translations, localeData.sourceData)
|
43
45
|
})
|
44
46
|
}
|
45
47
|
|
46
|
-
const validateResource = (resource, callback) => {
|
47
|
-
const source = JSON.parse(fs.readFileSync(`${resource}/en.json
|
48
|
+
const validateResource = (resource: string, callback: async.ErrorCallback) => {
|
49
|
+
const source = JSON.parse(fs.readFileSync(`${resource}/en.json`, 'utf8')) as TransifexStringsKeyValueJson
|
48
50
|
const allLocales = Object.keys(locales).map(loc => ({
|
49
51
|
locale: loc,
|
50
52
|
localeFileName: `${resource}/${loc}.json`,
|
@@ -11,7 +11,7 @@
|
|
11
11
|
"splash.communityLoving": "Ko ngā Mea e Arohaina ana e te Hapori",
|
12
12
|
"messages.becomeCuratorText": "I eke a {username} hei kairauhī mō {studio}",
|
13
13
|
"messages.becomeManagerText": "I tokona ake a {username} hei kaiwhakahaere mō {studio}",
|
14
|
-
"messages.favoriteText": "
|
14
|
+
"messages.favoriteText": "Nā {profileLink} i kaingākau ki tō kaupapa {projectLink}",
|
15
15
|
"messages.followProfileText": "Kei te whai a {profileLink} i a {followeeLink} ināianei",
|
16
16
|
"messages.followStudioText": "Kei te whai a {profileLink} i a {studioLink} ināianei",
|
17
17
|
"messages.loveText": "He ngākaunui a {profileLink} ki te {projectLink}",
|
@@ -56,4 +56,4 @@
|
|
56
56
|
"featurebanner.highContrast.comingSoon": "COMING SOON: Color Contrast in Scratch!",
|
57
57
|
"featurebanner.highContrast.forumTitle": "Block Color Settings and Site Updates",
|
58
58
|
"featurebanner.highContrast.learnMore": "Ako ake"
|
59
|
-
}
|
59
|
+
}
|
@@ -69,4 +69,4 @@
|
|
69
69
|
"teacherfaq.commBlockGamesTitle": "A allaf rwystro fy nysgwyr rhag chwarae gemau ar Scratch?",
|
70
70
|
"teacherfaq.commBlockGamesBody1": "Nid ydym yn dileu projectau sy'n gemau, neu wedi'u hysbrydoli gan gemau fideo poblogaidd oni bai eu bod yn cynnwys elfennau eraill a fyddai'n amhriodol i blant. Credwn fod plant yn dysgu orau wrth weithio ar brojectau am bethau yn eu bywyd y maent yn angerddol amdanynt; un o'r pethau maen nhw'n aml yn angerddol amdanynt yw gemau.",
|
71
71
|
"teacherfaq.commBlockGamesBody2": "Os ydych chi'n ymwybodol o unrhyw brojectau penodol sy'n cynnwys elfennau amhriodol, cliciwch y botwm 'Adrodd' sy'n ymddangos ar dudalen y project fel y gallwn gymryd camau priodol."
|
72
|
-
}
|
72
|
+
}
|
@@ -1,75 +0,0 @@
|
|
1
|
-
### Resolves
|
2
|
-
|
3
|
-
- Resolves #
|
4
|
-
|
5
|
-
### Proposed Changes
|
6
|
-
|
7
|
-
_Describe what this Pull Request does_
|
8
|
-
|
9
|
-
## Checklist for updating translations
|
10
|
-
|
11
|
-
There are two situations in which we create manual PRs to update translations:
|
12
|
-
|
13
|
-
1. We don't want to wait for Travis's automatic weekly update; or,
|
14
|
-
2. We need to add a language that has become ready
|
15
|
-
|
16
|
-
### 1. Updating translations manually
|
17
|
-
|
18
|
-
- [ ] Pull editor translations from Transifex with `> npm run pull:editor`
|
19
|
-
- [ ] Pull www translations from Transifex with `> npm run pull:www`
|
20
|
-
- [ ] Test the result with `> npm run test`
|
21
|
-
- [ ] Confirm that you see changes to files like `editor/<resource>/<lang code>.json`
|
22
|
-
|
23
|
-
### Adding a language
|
24
|
-
|
25
|
-
- [ ] Edit `src/supported-locales.mjs`:
|
26
|
-
|
27
|
-
- [ ] Add entry for the language in the `locales` const
|
28
|
-
- [ ] Check if language is right-to-left. If so:
|
29
|
-
- Add entry in `rtlLocales`
|
30
|
-
|
31
|
-
- [ ] Check if the new language uses a country code
|
32
|
-
|
33
|
-
- Check [https://www.transifex.com/explore/languages](https://www.transifex.com/explore/languages). If the language has a country code:
|
34
|
-
- [ ] Edit `src/supported-locales.mjs`:
|
35
|
-
- Add new entry to `localeMap`. Format is `'<W3C HTML browser locale string>': '<Transifex ICU locale string>'`
|
36
|
-
- [ ] Edit `.tx/config`:
|
37
|
-
- Add to the `lang_map` list. Format is `<Transifex ICU locale string>:<W3C HTML browser locale string>`
|
38
|
-
- NOTE: we are moving away from using the `tx` cli; `.tx/config` will eventually be deprecated
|
39
|
-
|
40
|
-
- [ ] Edit `src/index.js`:
|
41
|
-
|
42
|
-
- [ ] Add 'import' line
|
43
|
-
- [ ] Add entry in `localeData` array
|
44
|
-
|
45
|
-
- [ ] Check if locale is in `react-intl`
|
46
|
-
|
47
|
-
- Look in [https://unpkg.com/react-intl/locale-data/](https://unpkg.com/react-intl/locale-data/)
|
48
|
-
- If not in `react-intl`:
|
49
|
-
- [ ] Edit `src/supported-locales.mjs`:
|
50
|
-
- In `customLocales`, add entry with parent set to a `react-intl` locale
|
51
|
-
- [ ] Edit `src/index.js`:
|
52
|
-
- In `localeData`, add entry for parent locale
|
53
|
-
|
54
|
-
- [ ] Update translations per the "Updating translations" section above
|
55
|
-
- [ ] Confirm that we see changes to:
|
56
|
-
|
57
|
-
- [ ] `src/supported-locales.mjs`
|
58
|
-
- [ ] `src/index.js`
|
59
|
-
- [ ] `.tx/config` (if language needed a new locale)
|
60
|
-
- [ ] Multiple files like `editor/<resource>/<lang code>.json`
|
61
|
-
|
62
|
-
- [ ] Bump minor version number in `package.json`
|
63
|
-
|
64
|
-
- [ ] **Add language po files to scratchr2_translations**
|
65
|
-
|
66
|
-
- manually update `scratchr2_translations/legacy` with `tx pull -l <locale>` and check in changes
|
67
|
-
|
68
|
-
- [ ] **Add language to scratchr2 settings**
|
69
|
-
- manually update `settings/base.py` with the new language
|
70
|
-
|
71
|
-
#### After scratch-l10n update is published:
|
72
|
-
|
73
|
-
- [ ] **Update scratch-blocks dependency**
|
74
|
-
- [ ] in `package.json`, update the version of the scratch-l10n dependency to the version number you used above
|
75
|
-
- [ ] pull translations so that a new `Blockly.ScratchMsgs.locales["<LOCALE CODE>"]` is added to `msg/scratch_msgs.js`
|
@@ -1,55 +0,0 @@
|
|
1
|
-
name: CI/CD
|
2
|
-
|
3
|
-
on:
|
4
|
-
push: # Runs whenever a commit is pushed to the repository
|
5
|
-
workflow_call: # Allows another workflow to call this one
|
6
|
-
workflow_dispatch: # Allows you to run this workflow manually from the Actions tab
|
7
|
-
workflow_run: # Allows you to run this workflow when another workflow is run
|
8
|
-
types: [completed]
|
9
|
-
workflows:
|
10
|
-
- 'Daily TX Pull'
|
11
|
-
- 'Daily Help Update'
|
12
|
-
|
13
|
-
concurrency:
|
14
|
-
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
|
15
|
-
cancel-in-progress: true
|
16
|
-
|
17
|
-
permissions:
|
18
|
-
contents: write # publish a GitHub release
|
19
|
-
pages: write # deploy to GitHub Pages
|
20
|
-
issues: write # comment on released issues
|
21
|
-
pull-requests: write # comment on released pull requests
|
22
|
-
|
23
|
-
jobs:
|
24
|
-
build-and-deploy:
|
25
|
-
runs-on: ubuntu-latest
|
26
|
-
steps:
|
27
|
-
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
28
|
-
|
29
|
-
- uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # v3
|
30
|
-
with:
|
31
|
-
cache: 'npm'
|
32
|
-
node-version-file: '.nvmrc'
|
33
|
-
|
34
|
-
- name: Info
|
35
|
-
run: |
|
36
|
-
cat <<EOF
|
37
|
-
Node version: $(node --version)
|
38
|
-
NPM version: $(npm --version)
|
39
|
-
GitHub ref: ${{ github.ref }}
|
40
|
-
GitHub head ref: ${{ github.head_ref }}
|
41
|
-
EOF
|
42
|
-
|
43
|
-
- name: Install dependencies
|
44
|
-
run: npm ci
|
45
|
-
|
46
|
-
- name: Setup & Test
|
47
|
-
run: |
|
48
|
-
mkdir -p ./test/results
|
49
|
-
npm test
|
50
|
-
|
51
|
-
- name: Run semantic-release
|
52
|
-
env:
|
53
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
54
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
55
|
-
run: npx --no -- semantic-release
|
@@ -1,12 +0,0 @@
|
|
1
|
-
name: Lint commit messages
|
2
|
-
on: [pull_request]
|
3
|
-
|
4
|
-
concurrency:
|
5
|
-
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.sha }}'
|
6
|
-
|
7
|
-
jobs:
|
8
|
-
commitlint:
|
9
|
-
runs-on: ubuntu-latest
|
10
|
-
steps:
|
11
|
-
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
12
|
-
- uses: wagoid/commitlint-github-action@5ce82f5d814d4010519d15f0552aec4f17a1e1fe # v5
|
@@ -1,40 +0,0 @@
|
|
1
|
-
name: Daily Help Update
|
2
|
-
|
3
|
-
on:
|
4
|
-
workflow_dispatch: # Allows you to run this workflow manually from the Actions tab
|
5
|
-
schedule:
|
6
|
-
# daily-help-update (e.g., daily at 5 AM UTC)
|
7
|
-
- cron: '0 5 * * *'
|
8
|
-
|
9
|
-
concurrency:
|
10
|
-
group: '${{ github.workflow }}'
|
11
|
-
cancel-in-progress: true
|
12
|
-
|
13
|
-
permissions:
|
14
|
-
contents: write # publish a GitHub release
|
15
|
-
pages: write # deploy to GitHub Pages
|
16
|
-
issues: write # comment on released issues
|
17
|
-
pull-requests: write # comment on released pull requests
|
18
|
-
|
19
|
-
jobs:
|
20
|
-
daily-help-update:
|
21
|
-
runs-on: ubuntu-latest
|
22
|
-
|
23
|
-
steps:
|
24
|
-
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
25
|
-
- uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # v3
|
26
|
-
with:
|
27
|
-
cache: 'npm'
|
28
|
-
node-version-file: '.nvmrc'
|
29
|
-
|
30
|
-
- name: Install dependencies
|
31
|
-
run: |
|
32
|
-
npm ci
|
33
|
-
npx browserslist@latest --update-db
|
34
|
-
|
35
|
-
- name: Sync help
|
36
|
-
env:
|
37
|
-
# Organization-wide secrets
|
38
|
-
FRESHDESK_TOKEN: ${{ secrets.FRESHDESK_TOKEN }}
|
39
|
-
TX_TOKEN: ${{ secrets.TX_TOKEN }}
|
40
|
-
run: npm run sync:help
|