scratch-blocks 2.1.19 → 2.1.21
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/AGENTS.md +20 -0
- package/CLAUDE.md +1 -0
- package/dist/main.mjs +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/renderer/renderer.d.ts.map +1 -1
- package/dist/types/src/scratch_msgs.d.ts +32 -0
- package/dist/types/src/scratch_msgs.d.ts.map +1 -0
- package/eslint.config.mjs +0 -1
- package/msg/json/en.json +6 -0
- package/package.json +17 -14
- package/scripts/validate-en-json.mjs +27 -0
- package/src/fields/scratch_field_variable.ts +2 -2
- package/src/index.ts +2 -2
- package/src/renderer/constants.ts +1 -1
- package/src/renderer/drawer.ts +1 -1
- package/src/renderer/renderer.ts +2 -1
- package/src/scratch_c_block_wrap.ts +3 -2
- package/src/scratch_comment_bubble.ts +1 -1
- package/src/scratch_connection_checker.ts +2 -1
- package/src/scratch_msgs.ts +70 -0
- package/tsconfig.json +1 -0
- package/types/scratch-l10n.d.ts +15 -0
- package/dist/types/msg/scratch_msgs.d.ts +0 -9
- package/dist/types/msg/scratch_msgs.d.ts.map +0 -1
- package/i18n/common.py +0 -234
- package/i18n/create_messages.py +0 -162
- package/i18n/create_scratch_msgs.js +0 -68
- package/i18n/dedup_json.py +0 -73
- package/i18n/js_to_json.js +0 -54
- package/i18n/js_to_json.py +0 -136
- package/i18n/json_to_js.js +0 -52
- package/i18n/json_to_js.py +0 -185
- package/i18n/sync_tx_translations.js +0 -110
- package/i18n/test_scratch_msgs.js +0 -90
- package/i18n/tests.py +0 -47
- package/i18n/xliff_to_json.py +0 -232
- package/msg/js/en.js +0 -293
- package/msg/messages.js +0 -356
- package/msg/scratch_msgs.js +0 -23058
|
@@ -43,7 +43,7 @@ import * as ScratchVariables from './variables';
|
|
|
43
43
|
export * from 'blockly/core';
|
|
44
44
|
export * from './block_reporting';
|
|
45
45
|
export * from './procedures';
|
|
46
|
-
export * from '
|
|
46
|
+
export * from './scratch_msgs';
|
|
47
47
|
export * from './constants';
|
|
48
48
|
export { glowStack };
|
|
49
49
|
export { scratchBlocksUtils };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,iBAAiB,CAAA;AACxB,OAAO,kBAAkB,CAAA;AACzB,OAAO,eAAe,CAAA;AACtB,OAAO,gBAAgB,CAAA;AACvB,OAAO,gBAAgB,CAAA;AACvB,OAAO,eAAe,CAAA;AACtB,OAAO,iBAAiB,CAAA;AACxB,OAAO,iBAAiB,CAAA;AACxB,OAAO,eAAe,CAAA;AACtB,OAAO,oBAAoB,CAAA;AAC3B,OAAO,qBAAqB,CAAA;AAC5B,OAAO,kBAAkB,CAAA;AACzB,OAAO,gBAAgB,CAAA;AACvB,OAAO,eAAe,CAAA;AACtB,OAAO,8BAA8B,CAAA;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,gBAAgB,MAAM,sBAAsB,CAAA;AACxD,OAAO,OAAO,CAAA;AACd,OAAO,sCAAsC,CAAA;AAC7C,OAAO,wCAAwC,CAAA;AAC/C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,oCAAoC,CAAA;AAC3C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,yCAAyC,CAAA;AAChD,OAAO,EAA6B,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAE3F,OAAO,EAAqB,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAQlE,OAAO,wBAAwB,CAAA;AAC/B,OAAO,EAAmB,SAAS,EAAE,MAAM,SAAS,CAAA;AAEpD,OAAO,yBAAyB,CAAA;AAChC,OAAO,qBAAqB,CAAA;AAE5B,OAAO,KAAK,kBAAkB,MAAM,wBAAwB,CAAA;AAC5D,OAAO,wBAAwB,CAAA;AAC/B,OAAO,wBAAwB,CAAA;AAC/B,OAAO,8BAA8B,CAAA;AAGrC,OAAO,mBAAmB,CAAA;AAC1B,OAAO,sCAAsC,CAAA;AAC7C,OAAO,wBAAwB,CAAA;AAC/B,OAAO,0BAA0B,CAAA;AAGjC,OAAO,KAAK,gBAAgB,MAAM,aAAa,CAAA;AAE/C,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA;AACjC,cAAc,cAAc,CAAA;AAC5B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,iBAAiB,CAAA;AACxB,OAAO,kBAAkB,CAAA;AACzB,OAAO,eAAe,CAAA;AACtB,OAAO,gBAAgB,CAAA;AACvB,OAAO,gBAAgB,CAAA;AACvB,OAAO,eAAe,CAAA;AACtB,OAAO,iBAAiB,CAAA;AACxB,OAAO,iBAAiB,CAAA;AACxB,OAAO,eAAe,CAAA;AACtB,OAAO,oBAAoB,CAAA;AAC3B,OAAO,qBAAqB,CAAA;AAC5B,OAAO,kBAAkB,CAAA;AACzB,OAAO,gBAAgB,CAAA;AACvB,OAAO,eAAe,CAAA;AACtB,OAAO,8BAA8B,CAAA;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,gBAAgB,MAAM,sBAAsB,CAAA;AACxD,OAAO,OAAO,CAAA;AACd,OAAO,sCAAsC,CAAA;AAC7C,OAAO,wCAAwC,CAAA;AAC/C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,oCAAoC,CAAA;AAC3C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,yCAAyC,CAAA;AAChD,OAAO,EAA6B,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAE3F,OAAO,EAAqB,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAQlE,OAAO,wBAAwB,CAAA;AAC/B,OAAO,EAAmB,SAAS,EAAE,MAAM,SAAS,CAAA;AAEpD,OAAO,yBAAyB,CAAA;AAChC,OAAO,qBAAqB,CAAA;AAE5B,OAAO,KAAK,kBAAkB,MAAM,wBAAwB,CAAA;AAC5D,OAAO,wBAAwB,CAAA;AAC/B,OAAO,wBAAwB,CAAA;AAC/B,OAAO,8BAA8B,CAAA;AAGrC,OAAO,mBAAmB,CAAA;AAC1B,OAAO,sCAAsC,CAAA;AAC7C,OAAO,wBAAwB,CAAA;AAC/B,OAAO,0BAA0B,CAAA;AAGjC,OAAO,KAAK,gBAAgB,MAAM,aAAa,CAAA;AAE/C,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA;AACjC,cAAc,cAAc,CAAA;AAC5B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,OAAO,EAAE,kBAAkB,EAAE,CAAA;AAC7B,OAAO,EAAE,yBAAyB,EAAE,CAAA;AACpC,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAC3B,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAC3B,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAClF,cAAc,OAAO,CAAA;AAErB,UAAU,oBAAqB,SAAQ,OAAO,CAAC,cAAc;IAC3D;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAA;CAClC;AASD,wBAAgB,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,oBAAoB,wBAkDvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../../src/renderer/renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE1C;;GAEG;AACH,qBAAa,eAAgB,SAAQ,OAAO,CAAC,KAAK,CAAC,QAAQ;IACzD;;;;OAIG;IACM,YAAY,IAAI,MAAM;IAI/B;;;;;;OAMG;IACM,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,cAAc,CAAC,UAAU,GAAG,MAAM;IAI9F;;;;OAIG;IACM,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,GAAG,UAAU;IAI7D;;;OAGG;IACM,cAAc,IAAI,gBAAgB;IAI3C;;;;;OAKG;IACM,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,UAAU;IAItF;;;;OAIG;IACM,yBAAyB,CAAC,UAAU,EAAE,OAAO,CAAC,kBAAkB,GAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../../src/renderer/renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE1C;;GAEG;AACH,qBAAa,eAAgB,SAAQ,OAAO,CAAC,KAAK,CAAC,QAAQ;IACzD;;;;OAIG;IACM,YAAY,IAAI,MAAM;IAI/B;;;;;;OAMG;IACM,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,cAAc,CAAC,UAAU,GAAG,MAAM;IAI9F;;;;OAIG;IACM,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,GAAG,UAAU;IAI7D;;;OAGG;IACM,cAAc,IAAI,gBAAgB;IAI3C;;;;;OAKG;IACM,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,UAAU;IAItF;;;;OAIG;IACM,yBAAyB,CAAC,UAAU,EAAE,OAAO,CAAC,kBAAkB,GAAG,OAAO;CAIpF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import en from '../msg/json/en.json';
|
|
2
|
+
type Messages = Record<string, string>;
|
|
3
|
+
/** A message key defined in this repository's English source. */
|
|
4
|
+
export type ScratchMessageKey = keyof typeof en;
|
|
5
|
+
/**
|
|
6
|
+
* Localized strings for Scratch blocks and workspace UI.
|
|
7
|
+
*
|
|
8
|
+
* English comes from this repository's `msg/json/en.json`, so new strings are usable before they are translated.
|
|
9
|
+
* Every other locale comes from scratch-l10n, which pulls reviewed translations from Transifex.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ScratchMsgs {
|
|
12
|
+
static currentLocale_: string;
|
|
13
|
+
static locales: Record<string, Messages>;
|
|
14
|
+
/**
|
|
15
|
+
* Apply a locale's messages to `Blockly.Msg`.
|
|
16
|
+
* @param locale A key of `ScratchMsgs.locales`, such as `'de'` or `'pt-br'`.
|
|
17
|
+
*/
|
|
18
|
+
static setLocale(locale: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Look up a message without changing the current locale.
|
|
21
|
+
* @param msgId The message key.
|
|
22
|
+
* @param defaultMsg Returned when the locale has no translation for `msgId`.
|
|
23
|
+
* @param useLocale The locale to use instead of the current one.
|
|
24
|
+
* @returns The translation, else `defaultMsg`, else the English message.
|
|
25
|
+
*/
|
|
26
|
+
static translate(msgId: ScratchMessageKey, defaultMsg?: string, useLocale?: string): string;
|
|
27
|
+
static translate(msgId: string, defaultMsg: string, useLocale?: string): string;
|
|
28
|
+
static translate(msgId: string, defaultMsg?: string, useLocale?: string): string | undefined;
|
|
29
|
+
private static getLocaleMessages;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=scratch_msgs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scratch_msgs.d.ts","sourceRoot":"","sources":["../../../src/scratch_msgs.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAEpC,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAEtC,iEAAiE;AACjE,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,EAAE,CAAA;AAY/C;;;;;GAKG;AACH,qBAAa,WAAW;IACtB,MAAM,CAAC,cAAc,SAAO;IAC5B,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAwB;IAEhE;;;OAGG;IACH,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAetC;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,iBAAiB,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAC3F,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAC/E,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK5F,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAGjC"}
|
package/eslint.config.mjs
CHANGED
package/msg/json/en.json
CHANGED
|
@@ -245,12 +245,18 @@
|
|
|
245
245
|
"DELETE_X_BLOCKS": "Delete %1 Blocks",
|
|
246
246
|
"DELETE_ALL_BLOCKS": "Delete all %1 blocks?",
|
|
247
247
|
"CLEAN_UP": "Clean up Blocks",
|
|
248
|
+
"COLLAPSE_BLOCK": "Collapse Block",
|
|
249
|
+
"EXPAND_BLOCK": "Expand Block",
|
|
250
|
+
"COLLAPSE_ALL": "Collapse Blocks",
|
|
251
|
+
"EXPAND_ALL": "Expand Blocks",
|
|
252
|
+
"COLLAPSED_WARNINGS_WARNING": "Collapsed blocks contain warnings.",
|
|
248
253
|
"HELP": "Help",
|
|
249
254
|
"UNDO": "Undo",
|
|
250
255
|
"REDO": "Redo",
|
|
251
256
|
"EDIT_PROCEDURE": "Edit",
|
|
252
257
|
"SHOW_PROCEDURE_DEFINITION": "Go to definition",
|
|
253
258
|
"WORKSPACE_COMMENT_DEFAULT_TEXT": "Say something...",
|
|
259
|
+
"WORKSPACE_ARIA_LABEL": "Code Area",
|
|
254
260
|
"COLOUR_HUE_LABEL": "Color",
|
|
255
261
|
"COLOUR_SATURATION_LABEL": "Saturation",
|
|
256
262
|
"COLOUR_BRIGHTNESS_LABEL": "Brightness",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scratch-blocks",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.21",
|
|
4
4
|
"description": "Scratch Blocks is a library for building creative computing interfaces.",
|
|
5
5
|
"author": "Massachusetts Institute of Technology",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "webpack --mode production",
|
|
23
23
|
"format": "prettier --write . && eslint --fix",
|
|
24
|
+
"i18n:push": "tx-push-src scratch-editor blocks msg/json/en.json",
|
|
25
|
+
"i18n:src": "node scripts/validate-en-json.mjs",
|
|
24
26
|
"prepare": "husky || true",
|
|
25
27
|
"start": "webpack serve --open --mode development",
|
|
26
28
|
"test": "vitest run",
|
|
@@ -36,24 +38,25 @@
|
|
|
36
38
|
"blockly": "^12.4.1"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
39
|
-
"@commitlint/cli": "20.5.
|
|
40
|
-
"@commitlint/config-conventional": "20.5.
|
|
41
|
-
"@vitest/browser": "4.1.
|
|
42
|
-
"@vitest/browser-playwright": "4.1.
|
|
43
|
-
"eslint": "9.39.
|
|
44
|
-
"eslint-config-scratch": "14.1.
|
|
41
|
+
"@commitlint/cli": "20.5.3",
|
|
42
|
+
"@commitlint/config-conventional": "20.5.3",
|
|
43
|
+
"@vitest/browser": "4.1.11",
|
|
44
|
+
"@vitest/browser-playwright": "4.1.11",
|
|
45
|
+
"eslint": "9.39.5",
|
|
46
|
+
"eslint-config-scratch": "14.1.81",
|
|
45
47
|
"husky": "9.1.7",
|
|
46
|
-
"playwright": "1.
|
|
47
|
-
"prettier": "3.8.
|
|
48
|
+
"playwright": "1.63.0",
|
|
49
|
+
"prettier": "3.8.5",
|
|
50
|
+
"scratch-l10n": "6.1.119",
|
|
48
51
|
"scratch-semantic-release-config": "4.0.1",
|
|
49
|
-
"semantic-release": "25.0.
|
|
52
|
+
"semantic-release": "25.0.9",
|
|
50
53
|
"source-map-loader": "5.0.0",
|
|
51
|
-
"ts-loader": "9.
|
|
54
|
+
"ts-loader": "9.6.2",
|
|
52
55
|
"typescript": "5.9.3",
|
|
53
|
-
"vitest": "4.1.
|
|
54
|
-
"webpack": "5.
|
|
56
|
+
"vitest": "4.1.11",
|
|
57
|
+
"webpack": "5.111.1",
|
|
55
58
|
"webpack-cli": "6.0.1",
|
|
56
|
-
"webpack-dev-server": "5.2.
|
|
59
|
+
"webpack-dev-server": "5.2.6"
|
|
57
60
|
},
|
|
58
61
|
"config": {
|
|
59
62
|
"commitizen": {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2026 Scratch Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* Checks msg/json/en.json, the English source pushed to Transifex, before it is pushed.
|
|
7
|
+
*/
|
|
8
|
+
import console from 'node:console'
|
|
9
|
+
import fs from 'node:fs'
|
|
10
|
+
import process from 'node:process'
|
|
11
|
+
import { URL, fileURLToPath } from 'node:url'
|
|
12
|
+
|
|
13
|
+
const file = process.argv[2] ?? fileURLToPath(new URL('../msg/json/en.json', import.meta.url))
|
|
14
|
+
|
|
15
|
+
const messages = JSON.parse(fs.readFileSync(file, 'utf8'))
|
|
16
|
+
const errors = []
|
|
17
|
+
for (const [key, value] of Object.entries(messages)) {
|
|
18
|
+
if (!/^[A-Z][A-Z0-9_]*$/.test(key)) errors.push(`${key}: key must be UPPER_SNAKE_CASE`)
|
|
19
|
+
if (typeof value !== 'string' || !value.trim()) errors.push(`${key}: value must be a non-empty string`)
|
|
20
|
+
else if (value.includes('\n')) errors.push(`${key}: value must not contain a newline`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (errors.length > 0) {
|
|
24
|
+
console.error(`${file}:\n ${errors.join('\n ')}`)
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
27
|
+
console.log(`${file}: ${Object.keys(messages).length} messages OK`)
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
* @author fraser@google.com (Neil Fraser)
|
|
22
22
|
*/
|
|
23
23
|
import * as Blockly from 'blockly/core'
|
|
24
|
-
import { ScratchMsgs } from '../../msg/scratch_msgs.js'
|
|
25
24
|
import * as Constants from '../constants'
|
|
25
|
+
import { ScratchMsgs } from '../scratch_msgs'
|
|
26
26
|
import type { ScratchVariableModel } from '../scratch_variable_model'
|
|
27
27
|
import { createVariable, renameVariable } from '../variables'
|
|
28
28
|
|
|
@@ -47,7 +47,7 @@ export class ScratchFieldVariable extends Blockly.FieldVariable {
|
|
|
47
47
|
// dropdownCreate returns MenuOption[] rather than Blockly.MenuGenerator's
|
|
48
48
|
// MenuOption[][] variant; the cast is needed to satisfy FieldVariable's
|
|
49
49
|
// menuGenerator_ type while the actual runtime shape is compatible.
|
|
50
|
-
this.menuGenerator_ = ScratchFieldVariable.dropdownCreate.bind(this)
|
|
50
|
+
this.menuGenerator_ = ScratchFieldVariable.dropdownCreate.bind(this)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
initModel() {
|
package/src/index.ts
CHANGED
|
@@ -63,7 +63,7 @@ import * as ScratchVariables from './variables'
|
|
|
63
63
|
export * from 'blockly/core'
|
|
64
64
|
export * from './block_reporting'
|
|
65
65
|
export * from './procedures'
|
|
66
|
-
export * from '
|
|
66
|
+
export * from './scratch_msgs'
|
|
67
67
|
export * from './constants'
|
|
68
68
|
export { glowStack }
|
|
69
69
|
export { scratchBlocksUtils }
|
|
@@ -159,7 +159,7 @@ export function isContentNodeFocused(): boolean {
|
|
|
159
159
|
return Blockly.getFocusManager().getFocusedNode() !== null
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
|
|
162
|
+
registerContinuousToolbox()
|
|
163
163
|
Blockly.Scrollbar.scrollbarThickness = Blockly.Touch.TOUCH_ENABLED ? 14 : 11
|
|
164
164
|
Blockly.FlyoutButton.TEXT_MARGIN_X = 40
|
|
165
165
|
Blockly.FlyoutButton.TEXT_MARGIN_Y = 10
|
|
@@ -52,7 +52,7 @@ export class ConstantProvider extends Blockly.zelos.ConstantProvider {
|
|
|
52
52
|
* @returns The shape object for the given connection.
|
|
53
53
|
*/
|
|
54
54
|
override shapeFor(connection: Blockly.RenderedConnection): ReturnType<Blockly.zelos.ConstantProvider['shapeFor']> {
|
|
55
|
-
const connectionType = connection.type
|
|
55
|
+
const connectionType: Blockly.ConnectionType = connection.type
|
|
56
56
|
let checks = connection.getCheck()
|
|
57
57
|
const hexagonal = this.HEXAGONAL
|
|
58
58
|
const rounded = this.ROUNDED
|
package/src/renderer/drawer.ts
CHANGED
|
@@ -64,7 +64,7 @@ export class Drawer extends Blockly.zelos.Drawer {
|
|
|
64
64
|
*/
|
|
65
65
|
override drawConnectionHighlightPath(measurable: Blockly.blockRendering.Connection) {
|
|
66
66
|
const conn = measurable.connectionModel
|
|
67
|
-
const connectionType = conn.type
|
|
67
|
+
const connectionType: Blockly.ConnectionType = conn.type
|
|
68
68
|
if (connectionType === Blockly.ConnectionType.INPUT_VALUE && measurable.isDynamicShape) {
|
|
69
69
|
const input = measurable as Blockly.blockRendering.InlineInput
|
|
70
70
|
const EXPAND_X = 0.5
|
package/src/renderer/renderer.ts
CHANGED
|
@@ -65,7 +65,8 @@ export class ScratchRenderer extends Blockly.zelos.Renderer {
|
|
|
65
65
|
* @returns True if we should highlight the connection.
|
|
66
66
|
*/
|
|
67
67
|
override shouldHighlightConnection(connection: Blockly.RenderedConnection): boolean {
|
|
68
|
-
|
|
68
|
+
const connectionType: Blockly.ConnectionType = connection.type
|
|
69
|
+
return connectionType === Blockly.ConnectionType.INPUT_VALUE
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
|
|
@@ -28,7 +28,8 @@ Blockly.Connection.getConnectionForOrphanedConnection = function (
|
|
|
28
28
|
// Apply the wrapping logic when the orphaned connection is a statement
|
|
29
29
|
// connection (PREVIOUS_STATEMENT). Value connections (OUTPUT_VALUE) are
|
|
30
30
|
// already handled by the original implementation.
|
|
31
|
-
|
|
31
|
+
const orphanType: Blockly.ConnectionType = orphanConnection.type
|
|
32
|
+
if (orphanType === Blockly.ConnectionType.PREVIOUS_STATEMENT) {
|
|
32
33
|
const checker = orphanConnection.getConnectionChecker()
|
|
33
34
|
for (const input of startBlock.inputList) {
|
|
34
35
|
const conn = input.connection
|
|
@@ -87,7 +88,7 @@ Reflect.set(
|
|
|
87
88
|
if (markerPreviousConnection?.isConnected() && !markerNextConnection?.isConnected()) {
|
|
88
89
|
for (const input of marker.inputList) {
|
|
89
90
|
const conn = input.connection
|
|
90
|
-
const connType = conn?.type
|
|
91
|
+
const connType = conn?.type
|
|
91
92
|
if (connType !== Blockly.ConnectionType.NEXT_STATEMENT || !conn?.isConnected()) {
|
|
92
93
|
continue
|
|
93
94
|
}
|
|
@@ -69,7 +69,7 @@ export class ScratchCommentBubble
|
|
|
69
69
|
if (gesture) {
|
|
70
70
|
// ScratchCommentBubble implements IBubble structurally but TypeScript
|
|
71
71
|
// cannot verify it because IBubble.drag has a different signature here.
|
|
72
|
-
gesture.handleBubbleStart(e, this
|
|
72
|
+
gesture.handleBubbleStart(e, this)
|
|
73
73
|
Blockly.common.setSelected(this)
|
|
74
74
|
}
|
|
75
75
|
}
|
|
@@ -50,8 +50,9 @@ class ScratchConnectionChecker extends Blockly.ConnectionChecker {
|
|
|
50
50
|
// getConnectionForOrphanedConnection patch routes displaced blocks into
|
|
51
51
|
// statement inputs, so we allow the connection when a suitable statement
|
|
52
52
|
// input exists on the dragging block.
|
|
53
|
+
const bType: Blockly.ConnectionType = b.type
|
|
53
54
|
if (
|
|
54
|
-
|
|
55
|
+
bType === Blockly.ConnectionType.NEXT_STATEMENT &&
|
|
55
56
|
b.isConnected() &&
|
|
56
57
|
!(a.getSourceBlock() as Blockly.Block).nextConnection
|
|
57
58
|
) {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Scratch Foundation
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import * as Blockly from 'blockly/core'
|
|
6
|
+
import blocksMsgs from 'scratch-l10n/locales/blocks-msgs.js'
|
|
7
|
+
import en from '../msg/json/en.json'
|
|
8
|
+
|
|
9
|
+
type Messages = Record<string, string>
|
|
10
|
+
|
|
11
|
+
/** A message key defined in this repository's English source. */
|
|
12
|
+
export type ScratchMessageKey = keyof typeof en
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Blockly core message keys that read the same text as a Scratch message, mapped to that Scratch key. Transifex
|
|
16
|
+
* holds the translation under the Scratch key.
|
|
17
|
+
*/
|
|
18
|
+
const BLOCKLY_ALIASES: Record<string, ScratchMessageKey> = {
|
|
19
|
+
// The Duplicate items in the block and workspace comment context menus.
|
|
20
|
+
DUPLICATE_BLOCK: 'DUPLICATE',
|
|
21
|
+
DUPLICATE_COMMENT: 'DUPLICATE',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Localized strings for Scratch blocks and workspace UI.
|
|
26
|
+
*
|
|
27
|
+
* English comes from this repository's `msg/json/en.json`, so new strings are usable before they are translated.
|
|
28
|
+
* Every other locale comes from scratch-l10n, which pulls reviewed translations from Transifex.
|
|
29
|
+
*/
|
|
30
|
+
export class ScratchMsgs {
|
|
31
|
+
static currentLocale_ = 'en'
|
|
32
|
+
static locales: Record<string, Messages> = { ...blocksMsgs, en }
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Apply a locale's messages to `Blockly.Msg`.
|
|
36
|
+
* @param locale A key of `ScratchMsgs.locales`, such as `'de'` or `'pt-br'`.
|
|
37
|
+
*/
|
|
38
|
+
static setLocale(locale: string): void {
|
|
39
|
+
const messages = this.getLocaleMessages(locale)
|
|
40
|
+
if (!messages) {
|
|
41
|
+
console.warn('Ignoring unrecognized locale: ' + locale)
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
this.currentLocale_ = locale
|
|
45
|
+
// Apply English first so any key this locale lacks falls back to English instead of keeping the previous
|
|
46
|
+
// locale's text.
|
|
47
|
+
Object.assign(Blockly.Msg, this.locales.en, messages)
|
|
48
|
+
for (const [blocklyKey, scratchKey] of Object.entries(BLOCKLY_ALIASES)) {
|
|
49
|
+
Blockly.Msg[blocklyKey] = Blockly.Msg[scratchKey]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Look up a message without changing the current locale.
|
|
55
|
+
* @param msgId The message key.
|
|
56
|
+
* @param defaultMsg Returned when the locale has no translation for `msgId`.
|
|
57
|
+
* @param useLocale The locale to use instead of the current one.
|
|
58
|
+
* @returns The translation, else `defaultMsg`, else the English message.
|
|
59
|
+
*/
|
|
60
|
+
static translate(msgId: ScratchMessageKey, defaultMsg?: string, useLocale?: string): string
|
|
61
|
+
static translate(msgId: string, defaultMsg: string, useLocale?: string): string
|
|
62
|
+
static translate(msgId: string, defaultMsg?: string, useLocale?: string): string | undefined
|
|
63
|
+
static translate(msgId: string, defaultMsg?: string, useLocale?: string): string | undefined {
|
|
64
|
+
return this.getLocaleMessages(useLocale ?? this.currentLocale_)?.[msgId] ?? defaultMsg ?? this.locales.en[msgId]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private static getLocaleMessages(locale: string): Messages | undefined {
|
|
68
|
+
return Object.prototype.hasOwnProperty.call(this.locales, locale) ? this.locales[locale] : undefined
|
|
69
|
+
}
|
|
70
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Scratch Foundation
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
declare module 'scratch-l10n' {
|
|
6
|
+
/** The locales Scratch supports, keyed by locale code. */
|
|
7
|
+
const locales: Record<string, { name: string }>
|
|
8
|
+
export default locales
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare module 'scratch-l10n/locales/blocks-msgs.js' {
|
|
12
|
+
/** Reviewed block translations from Transifex, keyed by locale, then by message key. */
|
|
13
|
+
const blocksMsgs: Record<string, Record<string, string>>
|
|
14
|
+
export default blocksMsgs
|
|
15
|
+
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export class ScratchMsgs {
|
|
2
|
-
static currentLocale_: string;
|
|
3
|
-
static setLocale(locale: any): void;
|
|
4
|
-
static translate(msgId: any, defaultMsg: any, useLocale: any): any;
|
|
5
|
-
}
|
|
6
|
-
export namespace ScratchMsgs {
|
|
7
|
-
let locales: typeof locales;
|
|
8
|
-
}
|
|
9
|
-
//# sourceMappingURL=scratch_msgs.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scratch_msgs.d.ts","sourceRoot":"","sources":["../../../msg/scratch_msgs.js"],"names":[],"mappings":"AAEA;IACE,8BAA4B;IAG5B,oCAQC;IAED,mEAUC;CACF"}
|
package/i18n/common.py
DELETED
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/python
|
|
2
|
-
|
|
3
|
-
# Code shared by translation conversion scripts.
|
|
4
|
-
#
|
|
5
|
-
# Copyright 2013 Google Inc.
|
|
6
|
-
# https://developers.google.com/blockly/
|
|
7
|
-
#
|
|
8
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
9
|
-
# you may not use this file except in compliance with the License.
|
|
10
|
-
# You may obtain a copy of the License at
|
|
11
|
-
#
|
|
12
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
13
|
-
#
|
|
14
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
15
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
-
# See the License for the specific language governing permissions and
|
|
18
|
-
# limitations under the License.
|
|
19
|
-
|
|
20
|
-
import codecs
|
|
21
|
-
import json
|
|
22
|
-
import os
|
|
23
|
-
from datetime import datetime
|
|
24
|
-
|
|
25
|
-
class InputError(Exception):
|
|
26
|
-
"""Exception raised for errors in the input.
|
|
27
|
-
|
|
28
|
-
Attributes:
|
|
29
|
-
location -- where error occurred
|
|
30
|
-
msg -- explanation of the error
|
|
31
|
-
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
def __init__(self, location, msg):
|
|
35
|
-
Exception.__init__(self, '{0}: {1}'.format(location, msg))
|
|
36
|
-
self.location = location
|
|
37
|
-
self.msg = msg
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def read_json_file(filename):
|
|
41
|
-
"""Read a JSON file as UTF-8 into a dictionary, discarding @metadata.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
filename: The filename, which must end ".json".
|
|
45
|
-
|
|
46
|
-
Returns:
|
|
47
|
-
The dictionary.
|
|
48
|
-
|
|
49
|
-
Raises:
|
|
50
|
-
InputError: The filename did not end with ".json" or an error occurred
|
|
51
|
-
while opening or reading the file.
|
|
52
|
-
"""
|
|
53
|
-
if not filename.endswith('.json'):
|
|
54
|
-
raise InputError(filename, 'filenames must end with ".json"')
|
|
55
|
-
try:
|
|
56
|
-
# Read in file.
|
|
57
|
-
with codecs.open(filename, 'r', 'utf-8') as infile:
|
|
58
|
-
defs = json.load(infile)
|
|
59
|
-
if '@metadata' in defs:
|
|
60
|
-
del defs['@metadata']
|
|
61
|
-
return defs
|
|
62
|
-
except ValueError as e:
|
|
63
|
-
print('Error reading ' + filename)
|
|
64
|
-
raise InputError(filename, str(e))
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def _create_qqq_file(output_dir):
|
|
68
|
-
"""Creates a qqq.json file with message documentation for translatewiki.net.
|
|
69
|
-
|
|
70
|
-
The file consists of key-value pairs, where the keys are message ids and
|
|
71
|
-
the values are descriptions for the translators of the messages.
|
|
72
|
-
What documentation exists for the format can be found at:
|
|
73
|
-
http://translatewiki.net/wiki/Translating:Localisation_for_developers#Message_documentation
|
|
74
|
-
|
|
75
|
-
The file should be closed by _close_qqq_file().
|
|
76
|
-
|
|
77
|
-
Parameters:
|
|
78
|
-
output_dir: The output directory.
|
|
79
|
-
|
|
80
|
-
Returns:
|
|
81
|
-
A pointer to a file to which a left brace and newline have been written.
|
|
82
|
-
|
|
83
|
-
Raises:
|
|
84
|
-
IOError: An error occurred while opening or writing the file.
|
|
85
|
-
"""
|
|
86
|
-
qqq_file_name = os.path.join(os.curdir, output_dir, 'qqq.json')
|
|
87
|
-
qqq_file = codecs.open(qqq_file_name, 'w', 'utf-8')
|
|
88
|
-
print('Created file: ' + qqq_file_name)
|
|
89
|
-
qqq_file.write('{\n')
|
|
90
|
-
return qqq_file
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def _close_qqq_file(qqq_file):
|
|
94
|
-
"""Closes a qqq.json file created and opened by _create_qqq_file().
|
|
95
|
-
|
|
96
|
-
This writes the final newlines and right brace.
|
|
97
|
-
|
|
98
|
-
Args:
|
|
99
|
-
qqq_file: A file created by _create_qqq_file().
|
|
100
|
-
|
|
101
|
-
Raises:
|
|
102
|
-
IOError: An error occurred while writing to or closing the file.
|
|
103
|
-
"""
|
|
104
|
-
qqq_file.write('\n}\n')
|
|
105
|
-
qqq_file.close()
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def _create_lang_file(author, lang, output_dir):
|
|
109
|
-
"""Creates a <lang>.json file for translatewiki.net.
|
|
110
|
-
|
|
111
|
-
The file consists of metadata, followed by key-value pairs, where the keys
|
|
112
|
-
are message ids and the values are the messages in the language specified
|
|
113
|
-
by the corresponding command-line argument. The file should be closed by
|
|
114
|
-
_close_lang_file().
|
|
115
|
-
|
|
116
|
-
Args:
|
|
117
|
-
author: Name and email address of contact for translators.
|
|
118
|
-
lang: ISO 639-1 source language code.
|
|
119
|
-
output_dir: Relative directory for output files.
|
|
120
|
-
|
|
121
|
-
Returns:
|
|
122
|
-
A pointer to a file to which the metadata has been written.
|
|
123
|
-
|
|
124
|
-
Raises:
|
|
125
|
-
IOError: An error occurred while opening or writing the file.
|
|
126
|
-
"""
|
|
127
|
-
lang_file_name = os.path.join(os.curdir, output_dir, lang + '.json')
|
|
128
|
-
lang_file = codecs.open(lang_file_name, 'w', 'utf-8')
|
|
129
|
-
print('Created file: ' + lang_file_name)
|
|
130
|
-
# string.format doesn't like printing braces, so break up our writes.
|
|
131
|
-
lang_file.write('{\n\t"@metadata": {')
|
|
132
|
-
lang_file.write("""
|
|
133
|
-
\t\t"author": "{0}",
|
|
134
|
-
\t\t"lastupdated": "{1}",
|
|
135
|
-
\t\t"locale": "{2}",
|
|
136
|
-
\t\t"messagedocumentation" : "qqq"
|
|
137
|
-
""".format(author, str(datetime.now()), lang))
|
|
138
|
-
lang_file.write('\t},\n')
|
|
139
|
-
return lang_file
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def _close_lang_file(lang_file):
|
|
143
|
-
"""Closes a <lang>.json file created with _create_lang_file().
|
|
144
|
-
|
|
145
|
-
This also writes the terminating left brace and newline.
|
|
146
|
-
|
|
147
|
-
Args:
|
|
148
|
-
lang_file: A file opened with _create_lang_file().
|
|
149
|
-
|
|
150
|
-
Raises:
|
|
151
|
-
IOError: An error occurred while writing to or closing the file.
|
|
152
|
-
"""
|
|
153
|
-
lang_file.write('\n}\n')
|
|
154
|
-
lang_file.close()
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def _create_key_file(output_dir):
|
|
158
|
-
"""Creates a keys.json file mapping Closure keys to Blockly keys.
|
|
159
|
-
|
|
160
|
-
Args:
|
|
161
|
-
output_dir: Relative directory for output files.
|
|
162
|
-
|
|
163
|
-
Raises:
|
|
164
|
-
IOError: An error occurred while creating the file.
|
|
165
|
-
"""
|
|
166
|
-
key_file_name = os.path.join(os.curdir, output_dir, 'keys.json')
|
|
167
|
-
key_file = open(key_file_name, 'w')
|
|
168
|
-
key_file.write('{\n')
|
|
169
|
-
print('Created file: ' + key_file_name)
|
|
170
|
-
return key_file
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
def _close_key_file(key_file):
|
|
174
|
-
"""Closes a key file created and opened with _create_key_file().
|
|
175
|
-
|
|
176
|
-
Args:
|
|
177
|
-
key_file: A file created by _create_key_file().
|
|
178
|
-
|
|
179
|
-
Raises:
|
|
180
|
-
IOError: An error occurred while writing to or closing the file.
|
|
181
|
-
"""
|
|
182
|
-
key_file.write('\n}\n')
|
|
183
|
-
key_file.close()
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
def write_files(author, lang, output_dir, units, write_key_file):
|
|
187
|
-
"""Writes the output files for the given units.
|
|
188
|
-
|
|
189
|
-
There are three possible output files:
|
|
190
|
-
* lang_file: JSON file mapping meanings (e.g., Maze.turnLeft) to the
|
|
191
|
-
English text. The base name of the language file is specified by the
|
|
192
|
-
"lang" command-line argument.
|
|
193
|
-
* key_file: JSON file mapping meanings to Soy-generated keys (long hash
|
|
194
|
-
codes). This is only output if the parameter write_key_file is True.
|
|
195
|
-
* qqq_file: JSON file mapping meanings to descriptions.
|
|
196
|
-
|
|
197
|
-
Args:
|
|
198
|
-
author: Name and email address of contact for translators.
|
|
199
|
-
lang: ISO 639-1 source language code.
|
|
200
|
-
output_dir: Relative directory for output files.
|
|
201
|
-
units: A list of dictionaries with entries for 'meaning', 'source',
|
|
202
|
-
'description', and 'keys' (the last only if write_key_file is true),
|
|
203
|
-
in the order desired in the output files.
|
|
204
|
-
write_key_file: Whether to output a keys.json file.
|
|
205
|
-
|
|
206
|
-
Raises:
|
|
207
|
-
IOError: An error occurs opening, writing to, or closing a file.
|
|
208
|
-
KeyError: An expected key is missing from units.
|
|
209
|
-
"""
|
|
210
|
-
lang_file = _create_lang_file(author, lang, output_dir)
|
|
211
|
-
qqq_file = _create_qqq_file(output_dir)
|
|
212
|
-
if write_key_file:
|
|
213
|
-
key_file = _create_key_file(output_dir)
|
|
214
|
-
first_entry = True
|
|
215
|
-
for unit in units:
|
|
216
|
-
if not first_entry:
|
|
217
|
-
lang_file.write(',\n')
|
|
218
|
-
if write_key_file:
|
|
219
|
-
key_file.write(',\n')
|
|
220
|
-
qqq_file.write(',\n')
|
|
221
|
-
lang_file.write(u'\t"{0}": "{1}"'.format(
|
|
222
|
-
unit['meaning'],
|
|
223
|
-
unit['source'].replace('"', "'")))
|
|
224
|
-
if write_key_file:
|
|
225
|
-
key_file.write('"{0}": "{1}"'.format(unit['meaning'], unit['key']))
|
|
226
|
-
qqq_file.write(u'\t"{0}": "{1}"'.format(
|
|
227
|
-
unit['meaning'],
|
|
228
|
-
unit['description'].replace('"', "'").replace(
|
|
229
|
-
'{lb}', '{').replace('{rb}', '}')))
|
|
230
|
-
first_entry = False
|
|
231
|
-
_close_lang_file(lang_file)
|
|
232
|
-
if write_key_file:
|
|
233
|
-
_close_key_file(key_file)
|
|
234
|
-
_close_qqq_file(qqq_file)
|