mirror of
https://github.com/google/blockly.git
synced 2026-01-08 17:40:09 +01:00
String reference in JSON string messages (#741)
* Adds message references to message string interpolation, in the form of %{BKY_STRING}.
* Re-adding CONTROLS_IFELSE block using the new syntax, referencing to CONTROL_IF equivalents.
This commit is contained in:
committed by
GitHub
parent
f6aef459fc
commit
e5d25bb686
@@ -265,6 +265,48 @@ Blockly.Blocks['controls_if_else'] = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['controls_ifelse'] = {
|
||||||
|
/**
|
||||||
|
* If/else block that does not use a mutator.
|
||||||
|
*/
|
||||||
|
init: function() {
|
||||||
|
this.jsonInit({
|
||||||
|
"message0": "%{BKY_CONTROLS_IF_MSG_IF} %1",
|
||||||
|
"args0": [
|
||||||
|
{
|
||||||
|
"type": "input_value",
|
||||||
|
"name": "IF0",
|
||||||
|
"check": "Boolean",
|
||||||
|
"align": "RIGHT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1",
|
||||||
|
"args1": [
|
||||||
|
{
|
||||||
|
"type": "input_statement",
|
||||||
|
"name": "DO0",
|
||||||
|
"check": "Boolean",
|
||||||
|
"align": "RIGHT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"message2": "%{BKY_CONTROLS_IF_MSG_ELSE} %1",
|
||||||
|
"args2": [
|
||||||
|
{
|
||||||
|
"type": "input_statement",
|
||||||
|
"name": "ELSE",
|
||||||
|
"check": "Boolean",
|
||||||
|
"align": "RIGHT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"previousStatement": null,
|
||||||
|
"nextStatement": null,
|
||||||
|
"colour": Blockly.Blocks.logic.HUE,
|
||||||
|
"tooltip": Blockly.Msg.CONTROLS_IF_TOOLTIP_2,
|
||||||
|
"helpUrl": Blockly.Msg.CONTROLS_IF_HELPURL
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Blockly.Blocks['logic_compare'] = {
|
Blockly.Blocks['logic_compare'] = {
|
||||||
/**
|
/**
|
||||||
* Block for comparison operator.
|
* Block for comparison operator.
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ Blockly.utils.tokenizeInterpolation = function(message) {
|
|||||||
// 0 - Base case.
|
// 0 - Base case.
|
||||||
// 1 - % found.
|
// 1 - % found.
|
||||||
// 2 - Digit found.
|
// 2 - Digit found.
|
||||||
|
// 3 - Message ref found
|
||||||
var state = 0;
|
var state = 0;
|
||||||
var buffer = [];
|
var buffer = [];
|
||||||
var number = null;
|
var number = null;
|
||||||
@@ -330,6 +331,11 @@ Blockly.utils.tokenizeInterpolation = function(message) {
|
|||||||
var c = chars[i];
|
var c = chars[i];
|
||||||
if (state == 0) {
|
if (state == 0) {
|
||||||
if (c == '%') {
|
if (c == '%') {
|
||||||
|
var text = buffer.join('');
|
||||||
|
if (text) {
|
||||||
|
tokens.push(text);
|
||||||
|
}
|
||||||
|
buffer.length = 0;
|
||||||
state = 1; // Start escape.
|
state = 1; // Start escape.
|
||||||
} else {
|
} else {
|
||||||
buffer.push(c); // Regular char.
|
buffer.push(c); // Regular char.
|
||||||
@@ -346,8 +352,10 @@ Blockly.utils.tokenizeInterpolation = function(message) {
|
|||||||
tokens.push(text);
|
tokens.push(text);
|
||||||
}
|
}
|
||||||
buffer.length = 0;
|
buffer.length = 0;
|
||||||
|
} else if (c == '{') {
|
||||||
|
state = 3;
|
||||||
} else {
|
} else {
|
||||||
buffer.push('%', c); // Not an escape: %a
|
buffer.push('%', c); // Not recognized. Return as literal.
|
||||||
state = 0;
|
state = 0;
|
||||||
}
|
}
|
||||||
} else if (state == 2) {
|
} else if (state == 2) {
|
||||||
@@ -358,13 +366,70 @@ Blockly.utils.tokenizeInterpolation = function(message) {
|
|||||||
i--; // Parse this char again.
|
i--; // Parse this char again.
|
||||||
state = 0;
|
state = 0;
|
||||||
}
|
}
|
||||||
|
} else if (state == 3) { // String table reference
|
||||||
|
if (c == '') {
|
||||||
|
// Premature end before closing '}'
|
||||||
|
buffer.splice(0, 0, '%{'); // Re-insert leading delimiter
|
||||||
|
i--; // Parse this char again.
|
||||||
|
state = 0; // and parse as string literal.
|
||||||
|
} else if (c != '}') {
|
||||||
|
buffer.push(c);
|
||||||
|
} else {
|
||||||
|
var rawKey = buffer.join('');
|
||||||
|
if (/[a-zA-Z][a-zA-Z0-9_]*/.test(rawKey)) { // Strict matching
|
||||||
|
// Found a valid string key. Attempt case insensitive match.
|
||||||
|
var keyUpper = rawKey.toUpperCase();
|
||||||
|
|
||||||
|
// BKY_ is the prefix used to namespace the strings used in Blockly
|
||||||
|
// core files and the predefined blocks in ../blocks/. These strings
|
||||||
|
// are defined in ../msgs/ files.
|
||||||
|
var bklyKey = goog.string.startsWith(keyUpper, 'BKY_') ?
|
||||||
|
keyUpper.substring(4) : null;
|
||||||
|
if (bklyKey && bklyKey in Blockly.Msg) {
|
||||||
|
var rawValue = Blockly.Msg[bklyKey];
|
||||||
|
var subTokens = Blockly.utils.tokenizeInterpolation(rawValue);
|
||||||
|
tokens = tokens.concat(subTokens);
|
||||||
|
} else {
|
||||||
|
// No entry found in the string table. Pass reference as string.
|
||||||
|
tokens.push('%{' + rawKey + '}');
|
||||||
|
}
|
||||||
|
buffer.length = 0; // Clear the array
|
||||||
|
state = 0;
|
||||||
|
} else {
|
||||||
|
tokens.push('%{' + rawKey + '}');
|
||||||
|
buffer.length = 0;
|
||||||
|
state = 0; // and parse as string literal.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var text = buffer.join('');
|
var text = buffer.join('');
|
||||||
if (text) {
|
if (text) {
|
||||||
tokens.push(text);
|
tokens.push(text);
|
||||||
}
|
}
|
||||||
return tokens;
|
|
||||||
|
// Merge adjacent text tokens into a single string.
|
||||||
|
var mergedTokens = [];
|
||||||
|
buffer.length = 0;
|
||||||
|
for (var i = 0; i < tokens.length; ++i) {
|
||||||
|
if (typeof tokens[i] == 'string') {
|
||||||
|
buffer.push(tokens[i]);
|
||||||
|
} else {
|
||||||
|
text = buffer.join('');
|
||||||
|
if (text) {
|
||||||
|
mergedTokens.push(text);
|
||||||
|
}
|
||||||
|
buffer.length = 0;
|
||||||
|
mergedTokens.push(tokens[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text = buffer.join('');
|
||||||
|
if (text) {
|
||||||
|
mergedTokens.push(text);
|
||||||
|
}
|
||||||
|
buffer.length = 0;
|
||||||
|
|
||||||
|
return mergedTokens;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ Blockly.Dart['controls_if'] = function(block) {
|
|||||||
return code + '\n';
|
return code + '\n';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Blockly.Dart['controls_ifelse'] = Blockly.Dart['controls_if'];
|
||||||
|
|
||||||
Blockly.Dart['logic_compare'] = function(block) {
|
Blockly.Dart['logic_compare'] = function(block) {
|
||||||
// Comparison operator.
|
// Comparison operator.
|
||||||
var OPERATORS = {
|
var OPERATORS = {
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ Blockly.JavaScript['controls_if'] = function(block) {
|
|||||||
return code + '\n';
|
return code + '\n';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Blockly.JavaScript['controls_ifelse'] = Blockly.JavaScript['controls_if'];
|
||||||
|
|
||||||
Blockly.JavaScript['logic_compare'] = function(block) {
|
Blockly.JavaScript['logic_compare'] = function(block) {
|
||||||
// Comparison operator.
|
// Comparison operator.
|
||||||
var OPERATORS = {
|
var OPERATORS = {
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ Blockly.Lua['controls_if'] = function(block) {
|
|||||||
return code + 'end\n';
|
return code + 'end\n';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Blockly.Lua['controls_ifelse'] = Blockly.Lua['controls_if'];
|
||||||
|
|
||||||
Blockly.Lua['logic_compare'] = function(block) {
|
Blockly.Lua['logic_compare'] = function(block) {
|
||||||
// Comparison operator.
|
// Comparison operator.
|
||||||
var OPERATORS = {
|
var OPERATORS = {
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ Blockly.PHP['controls_if'] = function(block) {
|
|||||||
return code + '\n';
|
return code + '\n';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Blockly.PHP['controls_ifelse'] = Blockly.PHP['controls_if'];
|
||||||
|
|
||||||
Blockly.PHP['logic_compare'] = function(block) {
|
Blockly.PHP['logic_compare'] = function(block) {
|
||||||
// Comparison operator.
|
// Comparison operator.
|
||||||
var OPERATORS = {
|
var OPERATORS = {
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ Blockly.Python['controls_if'] = function(block) {
|
|||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Blockly.Python['controls_ifelse'] = Blockly.Python['controls_if'];
|
||||||
|
|
||||||
Blockly.Python['logic_compare'] = function(block) {
|
Blockly.Python['logic_compare'] = function(block) {
|
||||||
// Comparison operator.
|
// Comparison operator.
|
||||||
var OPERATORS = {
|
var OPERATORS = {
|
||||||
|
|||||||
@@ -115,16 +115,66 @@ function test_commonWordSuffix() {
|
|||||||
function test_tokenizeInterpolation() {
|
function test_tokenizeInterpolation() {
|
||||||
var tokens = Blockly.utils.tokenizeInterpolation('');
|
var tokens = Blockly.utils.tokenizeInterpolation('');
|
||||||
assertArrayEquals('Null interpolation', [], tokens);
|
assertArrayEquals('Null interpolation', [], tokens);
|
||||||
|
|
||||||
tokens = Blockly.utils.tokenizeInterpolation('Hello');
|
tokens = Blockly.utils.tokenizeInterpolation('Hello');
|
||||||
assertArrayEquals('No interpolation', ['Hello'], tokens);
|
assertArrayEquals('No interpolation', ['Hello'], tokens);
|
||||||
|
|
||||||
tokens = Blockly.utils.tokenizeInterpolation('Hello%World');
|
tokens = Blockly.utils.tokenizeInterpolation('Hello%World');
|
||||||
assertArrayEquals('Unescaped %.', ['Hello%World'], tokens);
|
assertArrayEquals('Unescaped %.', ['Hello%World'], tokens);
|
||||||
|
|
||||||
tokens = Blockly.utils.tokenizeInterpolation('Hello%%World');
|
tokens = Blockly.utils.tokenizeInterpolation('Hello%%World');
|
||||||
assertArrayEquals('Escaped %.', ['Hello%World'], tokens);
|
assertArrayEquals('Escaped %.', ['Hello%World'], tokens);
|
||||||
|
|
||||||
tokens = Blockly.utils.tokenizeInterpolation('Hello %1 World');
|
tokens = Blockly.utils.tokenizeInterpolation('Hello %1 World');
|
||||||
assertArrayEquals('Interpolation.', ['Hello ', 1, ' World'], tokens);
|
assertArrayEquals('Interpolation.', ['Hello ', 1, ' World'], tokens);
|
||||||
|
|
||||||
tokens = Blockly.utils.tokenizeInterpolation('%123Hello%456World%789');
|
tokens = Blockly.utils.tokenizeInterpolation('%123Hello%456World%789');
|
||||||
assertArrayEquals('Interpolations.', [123, 'Hello', 456, 'World', 789], tokens);
|
assertArrayEquals('Interpolations.', [123, 'Hello', 456, 'World', 789], tokens);
|
||||||
|
|
||||||
tokens = Blockly.utils.tokenizeInterpolation('%%%x%%0%00%01%');
|
tokens = Blockly.utils.tokenizeInterpolation('%%%x%%0%00%01%');
|
||||||
assertArrayEquals('Torture interpolations.', ['%%x%0', 0, 1, '%'], tokens);
|
assertArrayEquals('Torture interpolations.', ['%%x%0', 0, 1, '%'], tokens);
|
||||||
|
|
||||||
|
Blockly.Msg = Blockly.Msg || {};
|
||||||
|
|
||||||
|
Blockly.Msg.STRING_REF = 'test string';
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('%{bky_string_ref}');
|
||||||
|
assertArrayEquals('String table reference, lowercase', ['test string'], tokens);
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('%{BKY_STRING_REF}');
|
||||||
|
assertArrayEquals('String table reference, uppercase', ['test string'], tokens);
|
||||||
|
|
||||||
|
Blockly.Msg.WITH_PARAM = 'before %1 after';
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('%{bky_with_param}');
|
||||||
|
assertArrayEquals('String table reference, with parameter', ['before ', 1, ' after'], tokens);
|
||||||
|
|
||||||
|
Blockly.Msg.RECURSE = 'before %{bky_string_ref} after';
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('%{bky_recurse}');
|
||||||
|
assertArrayEquals('String table reference, with subreference', ['before test string after'], tokens);
|
||||||
|
|
||||||
|
// Error cases...
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('%{bky_undefined}');
|
||||||
|
assertArrayEquals('Undefined string table reference', ['%{bky_undefined}'], tokens);
|
||||||
|
|
||||||
|
Blockly.Msg['1'] = 'Will not match';
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('before %{1} after');
|
||||||
|
assertArrayEquals('Invalid initial digit in string table reference', ['before %{1} after'], tokens);
|
||||||
|
|
||||||
|
Blockly.Msg['TWO WORDS'] = 'Will not match';
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('before %{two words} after');
|
||||||
|
assertArrayEquals('Invalid character in string table reference: space', ['before %{two words} after'], tokens);
|
||||||
|
|
||||||
|
Blockly.Msg['TWO-WORDS'] = 'Will not match';
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('before %{two-words} after');
|
||||||
|
assertArrayEquals('Invalid character in string table reference: dash', ['before %{two-words} after'], tokens);
|
||||||
|
|
||||||
|
Blockly.Msg['TWO.WORDS'] = 'Will not match';
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('before %{two.words} after');
|
||||||
|
assertArrayEquals('Invalid character in string table reference: period', ['before %{two.words} after'], tokens);
|
||||||
|
|
||||||
|
Blockly.Msg['AB&C'] = 'Will not match';
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('before %{ab&c} after');
|
||||||
|
assertArrayEquals('Invalid character in string table reference: &', ['before %{ab&c} after'], tokens);
|
||||||
|
|
||||||
|
Blockly.Msg['UNCLOSED'] = 'Will not match';
|
||||||
|
tokens = Blockly.utils.tokenizeInterpolation('before %{unclosed');
|
||||||
|
assertArrayEquals('String table reference, with parameter', ['before %{unclosed'], tokens);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ h1 {
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<xml id="toolbox-simple" style="display: none">
|
<xml id="toolbox-simple" style="display: none">
|
||||||
<block type="controls_if"></block>
|
<block type="controls_ifelse"></block>
|
||||||
<block type="logic_compare"></block>
|
<block type="logic_compare"></block>
|
||||||
<!-- <block type="control_repeat"></block> -->
|
<!-- <block type="control_repeat"></block> -->
|
||||||
<block type="logic_operation"></block>
|
<block type="logic_operation"></block>
|
||||||
|
|||||||
Reference in New Issue
Block a user