pxt-core 11.3.6 → 11.3.7
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/built/cli.d.ts +5 -0
- package/built/cli.js +145 -1
- package/built/pxt.d.ts +5 -0
- package/built/pxt.js +146 -2
- package/built/pxtlib.d.ts +1 -1
- package/built/pxtlib.js +1 -1
- package/built/target.js +1 -1
- package/built/tests/blocksrunner.js +12 -4
- package/built/tests/blockssetup.js +12 -4
- package/built/web/main.js +2 -2
- package/built/web/pxtasseteditor.js +1 -1
- package/built/web/pxtembed.js +1 -1
- package/built/web/runnerembed.js +1 -1
- package/package.json +1 -1
package/built/cli.d.ts
CHANGED
|
@@ -44,6 +44,11 @@ export declare function staticpkgAsync(parsed: commandParser.ParsedCommand): Pro
|
|
|
44
44
|
export declare function cleanAsync(parsed?: commandParser.ParsedCommand): Promise<void>;
|
|
45
45
|
export declare function cleanGenAsync(parsed: commandParser.ParsedCommand): Promise<void>;
|
|
46
46
|
export declare function npmInstallNativeAsync(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Checks for syntax errors in a translated block strings file by comparing against a baseline.
|
|
49
|
+
* Optionally prints the results to console or sends to a file, if an output file is specified.
|
|
50
|
+
*/
|
|
51
|
+
export declare function validateTranslatedBlocks(parsed?: commandParser.ParsedCommand): Promise<void>;
|
|
47
52
|
export declare function buildJResSpritesAsync(parsed: commandParser.ParsedCommand): Promise<void>;
|
|
48
53
|
export declare function buildJResAsync(parsed: commandParser.ParsedCommand): Promise<void>;
|
|
49
54
|
export declare function buildAsync(parsed: commandParser.ParsedCommand): Promise<void>;
|
package/built/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-for-in-array */
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.mainCli = exports.getCodeSnippets = exports.getSnippets = exports.hex2uf2Async = exports.hexdumpAsync = exports.extractAsync = exports.testAsync = exports.runAsync = exports.deployAsync = exports.consoleAsync = exports.gendocsAsync = exports.buildShareSimJsAsync = exports.buildAsync = exports.buildJResAsync = exports.buildJResSpritesAsync = exports.npmInstallNativeAsync = exports.cleanGenAsync = exports.cleanAsync = exports.staticpkgAsync = exports.formatAsync = exports.downloadDiscourseTagAsync = exports.validateAndFixPkgConfig = exports.downloadPlaylistsAsync = exports.exportCppAsync = exports.timeAsync = exports.augmnetDocsAsync = exports.serviceAsync = exports.initAsync = exports.addAsync = exports.installAsync = exports.serveAsync = exports.internalBuildTargetAsync = exports.buildTargetAsync = exports.ghpPushAsync = exports.uploadTargetRefsAsync = exports.uploadTargetReleaseAsync = exports.yesNoAsync = exports.queryAsync = exports.apiAsync = exports.pokeRepoAsync = exports.globalConfig = void 0;
|
|
4
|
+
exports.mainCli = exports.getCodeSnippets = exports.getSnippets = exports.hex2uf2Async = exports.hexdumpAsync = exports.extractAsync = exports.testAsync = exports.runAsync = exports.deployAsync = exports.consoleAsync = exports.gendocsAsync = exports.buildShareSimJsAsync = exports.buildAsync = exports.buildJResAsync = exports.buildJResSpritesAsync = exports.validateTranslatedBlocks = exports.npmInstallNativeAsync = exports.cleanGenAsync = exports.cleanAsync = exports.staticpkgAsync = exports.formatAsync = exports.downloadDiscourseTagAsync = exports.validateAndFixPkgConfig = exports.downloadPlaylistsAsync = exports.exportCppAsync = exports.timeAsync = exports.augmnetDocsAsync = exports.serviceAsync = exports.initAsync = exports.addAsync = exports.installAsync = exports.serveAsync = exports.internalBuildTargetAsync = exports.buildTargetAsync = exports.ghpPushAsync = exports.uploadTargetRefsAsync = exports.uploadTargetReleaseAsync = exports.yesNoAsync = exports.queryAsync = exports.apiAsync = exports.pokeRepoAsync = exports.globalConfig = void 0;
|
|
5
5
|
/// <reference path="../built/pxtlib.d.ts"/>
|
|
6
6
|
/// <reference path="../built/pxtcompiler.d.ts"/>
|
|
7
7
|
/// <reference path="../built/pxtpy.d.ts"/>
|
|
@@ -4509,6 +4509,143 @@ function npmInstallNativeAsync() {
|
|
|
4509
4509
|
return nextAsync();
|
|
4510
4510
|
}
|
|
4511
4511
|
exports.npmInstallNativeAsync = npmInstallNativeAsync;
|
|
4512
|
+
/**
|
|
4513
|
+
* Checks for syntax errors in a single block string by comparing against a baseline string for the same block.
|
|
4514
|
+
*/
|
|
4515
|
+
function validateBlockString(original, toValidate) {
|
|
4516
|
+
var _a, _b, _c;
|
|
4517
|
+
function getResponse(result, message) {
|
|
4518
|
+
return {
|
|
4519
|
+
result,
|
|
4520
|
+
message,
|
|
4521
|
+
original,
|
|
4522
|
+
validate: toValidate
|
|
4523
|
+
};
|
|
4524
|
+
}
|
|
4525
|
+
// Check for empty strings. Both empty is fine. One empty and not the other, fail.
|
|
4526
|
+
if (!original && !toValidate) {
|
|
4527
|
+
return getResponse(true, "Empty strings");
|
|
4528
|
+
}
|
|
4529
|
+
else if (!original || !toValidate) {
|
|
4530
|
+
return getResponse(false, "Mis-match empty and non-empty strings.");
|
|
4531
|
+
}
|
|
4532
|
+
// Split block strings by the optional parameter separator "||" and parse each section separately.
|
|
4533
|
+
const originalParts = original.split("||");
|
|
4534
|
+
const toValidateParts = toValidate.split("||");
|
|
4535
|
+
if (originalParts.length !== toValidateParts.length) {
|
|
4536
|
+
return getResponse(false, "Block string has non-matching number of segments.");
|
|
4537
|
+
}
|
|
4538
|
+
for (let i = 0; i < originalParts.length; i++) {
|
|
4539
|
+
const originalParsed = pxtc.parseBlockDefinition(originalParts[i]);
|
|
4540
|
+
const toValidateParsed = pxtc.parseBlockDefinition(toValidateParts[i]);
|
|
4541
|
+
// Check if parameter count changed
|
|
4542
|
+
if (((_a = originalParsed.parameters) === null || _a === void 0 ? void 0 : _a.length) != ((_b = toValidateParsed.parameters) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
4543
|
+
return getResponse(false, "Block string has non-matching number of parameters.");
|
|
4544
|
+
}
|
|
4545
|
+
// Check if anything has been translated when it should not have been.
|
|
4546
|
+
for (let p = 0; p < ((_c = toValidateParsed.parameters) === null || _c === void 0 ? void 0 : _c.length); p++) {
|
|
4547
|
+
// For ref ($) params, order does not matter. For non-ref (%) params, it does.
|
|
4548
|
+
const toValidateParam = toValidateParsed.parameters[p];
|
|
4549
|
+
let matchParam;
|
|
4550
|
+
if (toValidateParam.ref) {
|
|
4551
|
+
matchParam = originalParsed.parameters.find(op => op.ref && op.name === toValidateParam.name);
|
|
4552
|
+
if (!matchParam) {
|
|
4553
|
+
return getResponse(false, "Block string has non-matching parameters.");
|
|
4554
|
+
}
|
|
4555
|
+
}
|
|
4556
|
+
else {
|
|
4557
|
+
matchParam = originalParsed.parameters[p];
|
|
4558
|
+
if (matchParam.ref || toValidateParam.name !== matchParam.name) {
|
|
4559
|
+
return getResponse(false, "Block string has non-matching ordered parameters.");
|
|
4560
|
+
}
|
|
4561
|
+
}
|
|
4562
|
+
if (toValidateParam.shadowBlockId !== matchParam.shadowBlockId) {
|
|
4563
|
+
return getResponse(false, "Block string has non-matching shadow block IDs.");
|
|
4564
|
+
}
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
// Passed all checks
|
|
4568
|
+
return getResponse(true);
|
|
4569
|
+
}
|
|
4570
|
+
/**
|
|
4571
|
+
* Checks for syntax errors in a translated block strings file by comparing against a baseline.
|
|
4572
|
+
* Optionally prints the results to console or sends to a file, if an output file is specified.
|
|
4573
|
+
*/
|
|
4574
|
+
function validateTranslatedBlocks(parsed) {
|
|
4575
|
+
const originalFilePath = parsed.args[0];
|
|
4576
|
+
const translatedFilePath = parsed.args[1];
|
|
4577
|
+
const outputFilePath = parsed.args[2]; // Optional
|
|
4578
|
+
if (!originalFilePath || !translatedFilePath) {
|
|
4579
|
+
U.userError("Missing required arguments: originalFilePath, translatedFilePath");
|
|
4580
|
+
}
|
|
4581
|
+
if (!fs.existsSync(originalFilePath)) {
|
|
4582
|
+
U.userError(`File ${originalFilePath} not found`);
|
|
4583
|
+
}
|
|
4584
|
+
if (!fs.existsSync(translatedFilePath)) {
|
|
4585
|
+
U.userError(`File ${translatedFilePath} not found`);
|
|
4586
|
+
}
|
|
4587
|
+
/**
|
|
4588
|
+
* Takes a key string from a translations file and returns the type of content it refers to (a block, a category, etc...)
|
|
4589
|
+
* Matches pxtc.gendocs key construction
|
|
4590
|
+
*/
|
|
4591
|
+
function getKeyType(key) {
|
|
4592
|
+
if (key.startsWith("{id:category}"))
|
|
4593
|
+
return "category";
|
|
4594
|
+
if (key.startsWith("{id:subcategory}"))
|
|
4595
|
+
return "subcategory";
|
|
4596
|
+
if (key.startsWith("{id:group}"))
|
|
4597
|
+
return "group";
|
|
4598
|
+
if (key.endsWith("|block"))
|
|
4599
|
+
return "block";
|
|
4600
|
+
return "unknown";
|
|
4601
|
+
}
|
|
4602
|
+
const originalMap = JSON.parse(fs.readFileSync(originalFilePath, 'utf8'));
|
|
4603
|
+
const translationMap = JSON.parse(fs.readFileSync(translatedFilePath, 'utf8'));
|
|
4604
|
+
const translationKeys = Object.keys(translationMap);
|
|
4605
|
+
const results = {};
|
|
4606
|
+
for (const translationKey of translationKeys) {
|
|
4607
|
+
if (!(translationKey in originalMap)) {
|
|
4608
|
+
results[translationKey] = { result: false, message: `Original string not found for key: ${translationKey}` };
|
|
4609
|
+
continue;
|
|
4610
|
+
}
|
|
4611
|
+
const keyType = getKeyType(translationKey);
|
|
4612
|
+
const translationString = translationMap[translationKey];
|
|
4613
|
+
const originalString = originalMap[translationKey];
|
|
4614
|
+
switch (keyType) {
|
|
4615
|
+
case "block": {
|
|
4616
|
+
const validation = validateBlockString(originalString, translationString);
|
|
4617
|
+
results[translationKey] = validation;
|
|
4618
|
+
break;
|
|
4619
|
+
}
|
|
4620
|
+
case "category":
|
|
4621
|
+
case "subcategory":
|
|
4622
|
+
case "group":
|
|
4623
|
+
case "unknown":
|
|
4624
|
+
default: {
|
|
4625
|
+
results[translationKey] = {
|
|
4626
|
+
result: true,
|
|
4627
|
+
message: `No validation performed for key type: ${keyType}`,
|
|
4628
|
+
original: originalString,
|
|
4629
|
+
validate: translationString
|
|
4630
|
+
};
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
}
|
|
4634
|
+
if (outputFilePath) {
|
|
4635
|
+
// Create directories for output file, if needed.
|
|
4636
|
+
const outputDir = path.dirname(outputFilePath);
|
|
4637
|
+
if (!fs.existsSync(outputDir)) {
|
|
4638
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
4639
|
+
}
|
|
4640
|
+
fs.writeFileSync(outputFilePath, JSON.stringify(results, null, 2));
|
|
4641
|
+
pxt.log(`Results written to ${outputFilePath}`);
|
|
4642
|
+
}
|
|
4643
|
+
else {
|
|
4644
|
+
pxt.log(JSON.stringify(results, null, 2));
|
|
4645
|
+
}
|
|
4646
|
+
return Promise.resolve();
|
|
4647
|
+
}
|
|
4648
|
+
exports.validateTranslatedBlocks = validateTranslatedBlocks;
|
|
4512
4649
|
function buildJResSpritesAsync(parsed) {
|
|
4513
4650
|
ensurePkgDir();
|
|
4514
4651
|
return loadPkgAsync()
|
|
@@ -6632,6 +6769,13 @@ ${pxt.crowdin.KEY_VARIABLE} - crowdin key
|
|
|
6632
6769
|
help: "Validate and attempt to fix common pxt.json issues",
|
|
6633
6770
|
}, validateAndFixPkgConfig);
|
|
6634
6771
|
advancedCommand("buildshims", "Regenerate shims.d.ts, enums.d.ts", buildShimsAsync);
|
|
6772
|
+
p.defineCommand({
|
|
6773
|
+
name: "validatetranslatedblocks",
|
|
6774
|
+
aliases: ["vtb"],
|
|
6775
|
+
help: "Validate a file of translated block strings against a baseline",
|
|
6776
|
+
advanced: true,
|
|
6777
|
+
argString: "<original-file> <translated-file> <output-file>"
|
|
6778
|
+
}, validateTranslatedBlocks);
|
|
6635
6779
|
function simpleCmd(name, help, callback, argString, onlineHelp) {
|
|
6636
6780
|
p.defineCommand({ name, help, onlineHelp, argString }, callback);
|
|
6637
6781
|
}
|
package/built/pxt.d.ts
CHANGED
|
@@ -44,6 +44,11 @@ export declare function staticpkgAsync(parsed: commandParser.ParsedCommand): Pro
|
|
|
44
44
|
export declare function cleanAsync(parsed?: commandParser.ParsedCommand): Promise<void>;
|
|
45
45
|
export declare function cleanGenAsync(parsed: commandParser.ParsedCommand): Promise<void>;
|
|
46
46
|
export declare function npmInstallNativeAsync(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Checks for syntax errors in a translated block strings file by comparing against a baseline.
|
|
49
|
+
* Optionally prints the results to console or sends to a file, if an output file is specified.
|
|
50
|
+
*/
|
|
51
|
+
export declare function validateTranslatedBlocks(parsed?: commandParser.ParsedCommand): Promise<void>;
|
|
47
52
|
export declare function buildJResSpritesAsync(parsed: commandParser.ParsedCommand): Promise<void>;
|
|
48
53
|
export declare function buildJResAsync(parsed: commandParser.ParsedCommand): Promise<void>;
|
|
49
54
|
export declare function buildAsync(parsed: commandParser.ParsedCommand): Promise<void>;
|
package/built/pxt.js
CHANGED
|
@@ -113979,7 +113979,7 @@ var pxt;
|
|
|
113979
113979
|
files[this.id + "/" + pxt.CONFIG_NAME] = this.readFile(pxt.CONFIG_NAME);
|
|
113980
113980
|
}
|
|
113981
113981
|
/**
|
|
113982
|
-
* Returns localized strings qName -> translation
|
|
113982
|
+
* Returns localized strings qName (+ some additional identification data) -> translation
|
|
113983
113983
|
*/
|
|
113984
113984
|
packageLocalizationStringsAsync(lang) {
|
|
113985
113985
|
const targetId = pxt.appTarget.id;
|
|
@@ -161051,7 +161051,7 @@ var pxsim;
|
|
|
161051
161051
|
"use strict";
|
|
161052
161052
|
/* eslint-disable @typescript-eslint/no-for-in-array */
|
|
161053
161053
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
161054
|
-
exports.mainCli = exports.getCodeSnippets = exports.getSnippets = exports.hex2uf2Async = exports.hexdumpAsync = exports.extractAsync = exports.testAsync = exports.runAsync = exports.deployAsync = exports.consoleAsync = exports.gendocsAsync = exports.buildShareSimJsAsync = exports.buildAsync = exports.buildJResAsync = exports.buildJResSpritesAsync = exports.npmInstallNativeAsync = exports.cleanGenAsync = exports.cleanAsync = exports.staticpkgAsync = exports.formatAsync = exports.downloadDiscourseTagAsync = exports.validateAndFixPkgConfig = exports.downloadPlaylistsAsync = exports.exportCppAsync = exports.timeAsync = exports.augmnetDocsAsync = exports.serviceAsync = exports.initAsync = exports.addAsync = exports.installAsync = exports.serveAsync = exports.internalBuildTargetAsync = exports.buildTargetAsync = exports.ghpPushAsync = exports.uploadTargetRefsAsync = exports.uploadTargetReleaseAsync = exports.yesNoAsync = exports.queryAsync = exports.apiAsync = exports.pokeRepoAsync = exports.globalConfig = void 0;
|
|
161054
|
+
exports.mainCli = exports.getCodeSnippets = exports.getSnippets = exports.hex2uf2Async = exports.hexdumpAsync = exports.extractAsync = exports.testAsync = exports.runAsync = exports.deployAsync = exports.consoleAsync = exports.gendocsAsync = exports.buildShareSimJsAsync = exports.buildAsync = exports.buildJResAsync = exports.buildJResSpritesAsync = exports.validateTranslatedBlocks = exports.npmInstallNativeAsync = exports.cleanGenAsync = exports.cleanAsync = exports.staticpkgAsync = exports.formatAsync = exports.downloadDiscourseTagAsync = exports.validateAndFixPkgConfig = exports.downloadPlaylistsAsync = exports.exportCppAsync = exports.timeAsync = exports.augmnetDocsAsync = exports.serviceAsync = exports.initAsync = exports.addAsync = exports.installAsync = exports.serveAsync = exports.internalBuildTargetAsync = exports.buildTargetAsync = exports.ghpPushAsync = exports.uploadTargetRefsAsync = exports.uploadTargetReleaseAsync = exports.yesNoAsync = exports.queryAsync = exports.apiAsync = exports.pokeRepoAsync = exports.globalConfig = void 0;
|
|
161055
161055
|
/// <reference path="../built/pxtlib.d.ts"/>
|
|
161056
161056
|
/// <reference path="../built/pxtcompiler.d.ts"/>
|
|
161057
161057
|
/// <reference path="../built/pxtpy.d.ts"/>
|
|
@@ -165559,6 +165559,143 @@ function npmInstallNativeAsync() {
|
|
|
165559
165559
|
return nextAsync();
|
|
165560
165560
|
}
|
|
165561
165561
|
exports.npmInstallNativeAsync = npmInstallNativeAsync;
|
|
165562
|
+
/**
|
|
165563
|
+
* Checks for syntax errors in a single block string by comparing against a baseline string for the same block.
|
|
165564
|
+
*/
|
|
165565
|
+
function validateBlockString(original, toValidate) {
|
|
165566
|
+
var _a, _b, _c;
|
|
165567
|
+
function getResponse(result, message) {
|
|
165568
|
+
return {
|
|
165569
|
+
result,
|
|
165570
|
+
message,
|
|
165571
|
+
original,
|
|
165572
|
+
validate: toValidate
|
|
165573
|
+
};
|
|
165574
|
+
}
|
|
165575
|
+
// Check for empty strings. Both empty is fine. One empty and not the other, fail.
|
|
165576
|
+
if (!original && !toValidate) {
|
|
165577
|
+
return getResponse(true, "Empty strings");
|
|
165578
|
+
}
|
|
165579
|
+
else if (!original || !toValidate) {
|
|
165580
|
+
return getResponse(false, "Mis-match empty and non-empty strings.");
|
|
165581
|
+
}
|
|
165582
|
+
// Split block strings by the optional parameter separator "||" and parse each section separately.
|
|
165583
|
+
const originalParts = original.split("||");
|
|
165584
|
+
const toValidateParts = toValidate.split("||");
|
|
165585
|
+
if (originalParts.length !== toValidateParts.length) {
|
|
165586
|
+
return getResponse(false, "Block string has non-matching number of segments.");
|
|
165587
|
+
}
|
|
165588
|
+
for (let i = 0; i < originalParts.length; i++) {
|
|
165589
|
+
const originalParsed = pxtc.parseBlockDefinition(originalParts[i]);
|
|
165590
|
+
const toValidateParsed = pxtc.parseBlockDefinition(toValidateParts[i]);
|
|
165591
|
+
// Check if parameter count changed
|
|
165592
|
+
if (((_a = originalParsed.parameters) === null || _a === void 0 ? void 0 : _a.length) != ((_b = toValidateParsed.parameters) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
165593
|
+
return getResponse(false, "Block string has non-matching number of parameters.");
|
|
165594
|
+
}
|
|
165595
|
+
// Check if anything has been translated when it should not have been.
|
|
165596
|
+
for (let p = 0; p < ((_c = toValidateParsed.parameters) === null || _c === void 0 ? void 0 : _c.length); p++) {
|
|
165597
|
+
// For ref ($) params, order does not matter. For non-ref (%) params, it does.
|
|
165598
|
+
const toValidateParam = toValidateParsed.parameters[p];
|
|
165599
|
+
let matchParam;
|
|
165600
|
+
if (toValidateParam.ref) {
|
|
165601
|
+
matchParam = originalParsed.parameters.find(op => op.ref && op.name === toValidateParam.name);
|
|
165602
|
+
if (!matchParam) {
|
|
165603
|
+
return getResponse(false, "Block string has non-matching parameters.");
|
|
165604
|
+
}
|
|
165605
|
+
}
|
|
165606
|
+
else {
|
|
165607
|
+
matchParam = originalParsed.parameters[p];
|
|
165608
|
+
if (matchParam.ref || toValidateParam.name !== matchParam.name) {
|
|
165609
|
+
return getResponse(false, "Block string has non-matching ordered parameters.");
|
|
165610
|
+
}
|
|
165611
|
+
}
|
|
165612
|
+
if (toValidateParam.shadowBlockId !== matchParam.shadowBlockId) {
|
|
165613
|
+
return getResponse(false, "Block string has non-matching shadow block IDs.");
|
|
165614
|
+
}
|
|
165615
|
+
}
|
|
165616
|
+
}
|
|
165617
|
+
// Passed all checks
|
|
165618
|
+
return getResponse(true);
|
|
165619
|
+
}
|
|
165620
|
+
/**
|
|
165621
|
+
* Checks for syntax errors in a translated block strings file by comparing against a baseline.
|
|
165622
|
+
* Optionally prints the results to console or sends to a file, if an output file is specified.
|
|
165623
|
+
*/
|
|
165624
|
+
function validateTranslatedBlocks(parsed) {
|
|
165625
|
+
const originalFilePath = parsed.args[0];
|
|
165626
|
+
const translatedFilePath = parsed.args[1];
|
|
165627
|
+
const outputFilePath = parsed.args[2]; // Optional
|
|
165628
|
+
if (!originalFilePath || !translatedFilePath) {
|
|
165629
|
+
U.userError("Missing required arguments: originalFilePath, translatedFilePath");
|
|
165630
|
+
}
|
|
165631
|
+
if (!fs.existsSync(originalFilePath)) {
|
|
165632
|
+
U.userError(`File ${originalFilePath} not found`);
|
|
165633
|
+
}
|
|
165634
|
+
if (!fs.existsSync(translatedFilePath)) {
|
|
165635
|
+
U.userError(`File ${translatedFilePath} not found`);
|
|
165636
|
+
}
|
|
165637
|
+
/**
|
|
165638
|
+
* Takes a key string from a translations file and returns the type of content it refers to (a block, a category, etc...)
|
|
165639
|
+
* Matches pxtc.gendocs key construction
|
|
165640
|
+
*/
|
|
165641
|
+
function getKeyType(key) {
|
|
165642
|
+
if (key.startsWith("{id:category}"))
|
|
165643
|
+
return "category";
|
|
165644
|
+
if (key.startsWith("{id:subcategory}"))
|
|
165645
|
+
return "subcategory";
|
|
165646
|
+
if (key.startsWith("{id:group}"))
|
|
165647
|
+
return "group";
|
|
165648
|
+
if (key.endsWith("|block"))
|
|
165649
|
+
return "block";
|
|
165650
|
+
return "unknown";
|
|
165651
|
+
}
|
|
165652
|
+
const originalMap = JSON.parse(fs.readFileSync(originalFilePath, 'utf8'));
|
|
165653
|
+
const translationMap = JSON.parse(fs.readFileSync(translatedFilePath, 'utf8'));
|
|
165654
|
+
const translationKeys = Object.keys(translationMap);
|
|
165655
|
+
const results = {};
|
|
165656
|
+
for (const translationKey of translationKeys) {
|
|
165657
|
+
if (!(translationKey in originalMap)) {
|
|
165658
|
+
results[translationKey] = { result: false, message: `Original string not found for key: ${translationKey}` };
|
|
165659
|
+
continue;
|
|
165660
|
+
}
|
|
165661
|
+
const keyType = getKeyType(translationKey);
|
|
165662
|
+
const translationString = translationMap[translationKey];
|
|
165663
|
+
const originalString = originalMap[translationKey];
|
|
165664
|
+
switch (keyType) {
|
|
165665
|
+
case "block": {
|
|
165666
|
+
const validation = validateBlockString(originalString, translationString);
|
|
165667
|
+
results[translationKey] = validation;
|
|
165668
|
+
break;
|
|
165669
|
+
}
|
|
165670
|
+
case "category":
|
|
165671
|
+
case "subcategory":
|
|
165672
|
+
case "group":
|
|
165673
|
+
case "unknown":
|
|
165674
|
+
default: {
|
|
165675
|
+
results[translationKey] = {
|
|
165676
|
+
result: true,
|
|
165677
|
+
message: `No validation performed for key type: ${keyType}`,
|
|
165678
|
+
original: originalString,
|
|
165679
|
+
validate: translationString
|
|
165680
|
+
};
|
|
165681
|
+
}
|
|
165682
|
+
}
|
|
165683
|
+
}
|
|
165684
|
+
if (outputFilePath) {
|
|
165685
|
+
// Create directories for output file, if needed.
|
|
165686
|
+
const outputDir = path.dirname(outputFilePath);
|
|
165687
|
+
if (!fs.existsSync(outputDir)) {
|
|
165688
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
165689
|
+
}
|
|
165690
|
+
fs.writeFileSync(outputFilePath, JSON.stringify(results, null, 2));
|
|
165691
|
+
pxt.log(`Results written to ${outputFilePath}`);
|
|
165692
|
+
}
|
|
165693
|
+
else {
|
|
165694
|
+
pxt.log(JSON.stringify(results, null, 2));
|
|
165695
|
+
}
|
|
165696
|
+
return Promise.resolve();
|
|
165697
|
+
}
|
|
165698
|
+
exports.validateTranslatedBlocks = validateTranslatedBlocks;
|
|
165562
165699
|
function buildJResSpritesAsync(parsed) {
|
|
165563
165700
|
ensurePkgDir();
|
|
165564
165701
|
return loadPkgAsync()
|
|
@@ -167682,6 +167819,13 @@ ${pxt.crowdin.KEY_VARIABLE} - crowdin key
|
|
|
167682
167819
|
help: "Validate and attempt to fix common pxt.json issues",
|
|
167683
167820
|
}, validateAndFixPkgConfig);
|
|
167684
167821
|
advancedCommand("buildshims", "Regenerate shims.d.ts, enums.d.ts", buildShimsAsync);
|
|
167822
|
+
p.defineCommand({
|
|
167823
|
+
name: "validatetranslatedblocks",
|
|
167824
|
+
aliases: ["vtb"],
|
|
167825
|
+
help: "Validate a file of translated block strings against a baseline",
|
|
167826
|
+
advanced: true,
|
|
167827
|
+
argString: "<original-file> <translated-file> <output-file>"
|
|
167828
|
+
}, validateTranslatedBlocks);
|
|
167685
167829
|
function simpleCmd(name, help, callback, argString, onlineHelp) {
|
|
167686
167830
|
p.defineCommand({ name, help, onlineHelp, argString }, callback);
|
|
167687
167831
|
}
|
package/built/pxtlib.d.ts
CHANGED
|
@@ -1973,7 +1973,7 @@ declare namespace pxt {
|
|
|
1973
1973
|
getFiles(): string[];
|
|
1974
1974
|
addSnapshot(files: Map<string>, exts?: string[]): void;
|
|
1975
1975
|
/**
|
|
1976
|
-
* Returns localized strings qName -> translation
|
|
1976
|
+
* Returns localized strings qName (+ some additional identification data) -> translation
|
|
1977
1977
|
*/
|
|
1978
1978
|
packageLocalizationStringsAsync(lang: string): Promise<Map<string>>;
|
|
1979
1979
|
bundledStringsForFile(lang: string, filename: string): Map<string>;
|
package/built/pxtlib.js
CHANGED
|
@@ -16293,7 +16293,7 @@ var pxt;
|
|
|
16293
16293
|
files[this.id + "/" + pxt.CONFIG_NAME] = this.readFile(pxt.CONFIG_NAME);
|
|
16294
16294
|
}
|
|
16295
16295
|
/**
|
|
16296
|
-
* Returns localized strings qName -> translation
|
|
16296
|
+
* Returns localized strings qName (+ some additional identification data) -> translation
|
|
16297
16297
|
*/
|
|
16298
16298
|
packageLocalizationStringsAsync(lang) {
|
|
16299
16299
|
const targetId = pxt.appTarget.id;
|