scratch-l10n 5.0.309 → 6.0.1

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 (47) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +6 -0
  3. package/dist/l10n.js +3 -0
  4. package/dist/l10n.js.map +1 -1
  5. package/dist/localeData.js +3 -0
  6. package/dist/localeData.js.map +1 -1
  7. package/dist/supportedLocales.js +3 -0
  8. package/dist/supportedLocales.js.map +1 -1
  9. package/package.json +23 -21
  10. package/scripts/{build-data.mjs → build-data.mts} +15 -6
  11. package/scripts/{build-i18n-src.js → build-i18n-src.mts} +16 -11
  12. package/scripts/lib/concurrent.mts +37 -0
  13. package/scripts/lib/freshdesk-api.mts +322 -0
  14. package/scripts/lib/help-utils.mts +221 -0
  15. package/{lib/progress-logger.mjs → scripts/lib/progress-logger.mts} +10 -5
  16. package/scripts/lib/transifex-formats.mts +53 -0
  17. package/scripts/lib/transifex-objects.mts +143 -0
  18. package/scripts/lib/transifex.mts +284 -0
  19. package/scripts/lib/validate.mts +107 -0
  20. package/scripts/tsconfig.json +20 -0
  21. package/scripts/tx-pull-editor.mts +74 -0
  22. package/scripts/{tx-pull-help-articles.js → tx-pull-help-articles.mts} +5 -13
  23. package/scripts/{tx-pull-help-names.js → tx-pull-help-names.mts} +5 -13
  24. package/scripts/{tx-pull-locale-articles.js → tx-pull-locale-articles.mts} +5 -13
  25. package/scripts/{tx-pull-www.mjs → tx-pull-www.mts} +16 -29
  26. package/scripts/{tx-push-help.mjs → tx-push-help.mts} +39 -37
  27. package/scripts/{tx-push-src.js → tx-push-src.mts} +13 -20
  28. package/scripts/update-translations.sh +2 -2
  29. package/scripts/{validate-extension-inputs.mjs → validate-extension-inputs.mts} +20 -10
  30. package/scripts/{validate-translations.mjs → validate-translations.mts} +7 -12
  31. package/scripts/{validate-www.mjs → validate-www.mts} +15 -13
  32. package/src/supported-locales.mjs +3 -0
  33. package/www/scratch-website.about-l10njson/nn.json +1 -1
  34. package/www/scratch-website.splash-l10njson/mi.json +2 -2
  35. package/www/scratch-website.teacher-faq-l10njson/cy.json +1 -1
  36. package/.github/PULL_REQUEST_TEMPLATE.md +0 -75
  37. package/.github/workflows/ci-cd.yml +0 -55
  38. package/.github/workflows/commitlint.yml +0 -12
  39. package/.github/workflows/daily-help-update.yml +0 -40
  40. package/.github/workflows/daily-tx-pull.yml +0 -54
  41. package/.github/workflows/signature-assistant.yml +0 -31
  42. package/lib/batch.js +0 -15
  43. package/lib/transifex.js +0 -242
  44. package/lib/validate.mjs +0 -48
  45. package/scripts/freshdesk-api.js +0 -149
  46. package/scripts/help-utils.js +0 -190
  47. package/scripts/tx-pull-editor.mjs +0 -83
@@ -1,10 +1,11 @@
1
- #!/usr/bin/env node
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 { txPush, txCreateResource } from '../lib/transifex.js'
7
- import FreshdeskApi from './freshdesk-api.js'
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 {object} item data from Freshdesk that includes the name and id of a category or folder
37
- * @returns {string} generated transifex id
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 (name, articles, type) => {
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
- i18n_type: type,
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 (err) {
57
+ } catch (errUnknown) {
58
+ const err = errUnknown as JsonApiException
53
59
  if (err.statusCode !== 404) {
54
- process.stdout.write(`Transifex Error: ${err.message}\n`)
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
- if (err.statusCode === 404) {
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 {object[]} categories array of categories the folders belong to
71
- * @returns {Promise<object[]>} flattened list of folders from all requested categories
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 {object} folder The folder object
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 === PUBLISHED) {
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.length > 0) {
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 {object[]} folders Array of folders containing articles to be saved
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
- txPushResource('categoryNames_json', categoryNames, 'KEYVALUEJSON')
130
- txPushResource('folderNames_json', folderNames, 'KEYVALUEJSON')
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 node
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
- const fs = require('fs')
12
- const path = require('path')
13
- const { txPush, txCreateResource } = require('../lib/transifex.js')
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
- let en = fs.readFileSync(path.resolve(args[2]))
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
- process.stdout.write(`Error - Unknown resource type for:\n`)
70
- process.stdout.write(` Project: ${project}, resource: ${resource}\n`)
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 (err) {
75
+ } catch (errUnknown) {
76
+ const err = errUnknown as JsonApiException
79
77
  if (err.statusCode !== 404) {
80
- process.stdout.write(`Transifex Error: ${err.message}\n`)
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 node
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
- const source = JSON.parse(fs.readFileSync(`${JSON_DIR}/en.json`))
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
- const validateExtensionInputs = (translationData, locale) => {
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
- const validate = (locale, callback) => {
58
- fs.readFile(`${JSON_DIR}/${locale}.json`, (err, data) => {
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
- data = JSON.parse(data)
71
+ const parsedData = JSON.parse(data) as TransifexStringsKeyValueJson
62
72
 
63
73
  try {
64
- validateExtensionInputs(data, locale)
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 node
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
- data = JSON.parse(data)
33
+ const strings = JSON.parse(data) as TransifexEditorStrings
39
34
  const translations = {
40
35
  locale: locale,
41
- translations: data,
36
+ translations: strings,
42
37
  }
43
38
  validateTranslations(translations, source)
44
39
  })
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
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
- const validate = (localeData, callback) => {
34
- fs.readFile(localeData.localeFileName, (err, data) => {
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
- data = JSON.parse(data)
39
+ const strings = JSON.parse(data) as TransifexStringsKeyValueJson
38
40
  const translations = {
39
41
  locale: localeData.locale,
40
- translations: data,
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`,
@@ -120,6 +120,9 @@ const customLocales = {
120
120
  },
121
121
  }
122
122
 
123
+ /**
124
+ * @type {Record<string,string>}
125
+ */
123
126
  const localeMap = {
124
127
  'aa-dj': 'aa_DJ',
125
128
  'es-419': 'es_419',
@@ -38,4 +38,4 @@
38
38
  "about.donorsLinkText": "donors",
39
39
  "about.donateLinkText": "her",
40
40
  "about.donateButton": "Gje pengegåve"
41
- }
41
+ }
@@ -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": "I tohua e {profileLink} he pai te {profileLink}",
14
+ "messages.favoriteText": " {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