From ac3df2759c00ef47148125dffd5c416e0c920518 Mon Sep 17 00:00:00 2001 From: Andrew n marshall Date: Wed, 11 Jan 2017 15:47:56 -0800 Subject: [PATCH] PR #818: Adding support for string table lookups in dropdown field labels Adding support for string table lookups in dropdown field labels specified in JSON. Adds Blockly.utils.replaceMessageReferences() method to handle string replacement without interpolation tokens. Effectively uses the same old code, now moved into tokenizeInterpolation_(), which takes a parseInterpolationTokens option. Replaces the direct JavaScript references (not pure JSON, and thus not portable). Demonstrating this behavior in the logic_boolean dropdown. --- blocks/logic.js | 4 ++-- core/field_dropdown.js | 11 ++++++++++- core/utils.js | 38 +++++++++++++++++++++++++++++++++++--- tests/jsunit/utils_test.js | 28 ++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/blocks/logic.js b/blocks/logic.js index 376deec92..9e0b1ae3a 100644 --- a/blocks/logic.js +++ b/blocks/logic.js @@ -445,8 +445,8 @@ Blockly.Blocks['logic_boolean'] = { "type": "field_dropdown", "name": "BOOL", "options": [ - [Blockly.Msg.LOGIC_BOOLEAN_TRUE, "TRUE"], - [Blockly.Msg.LOGIC_BOOLEAN_FALSE, "FALSE"] + ["%{bky_logic_boolean_true}", "TRUE"], + ["%{bky_logic_boolean_false}", "FALSE"] ] } ], diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 70ac3b9f4..fd081e7ef 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -241,9 +241,18 @@ Blockly.FieldDropdown.prototype.trimOptions_ = function() { this.prefixField = null; this.suffixField = null; var options = this.menuGenerator_; - if (!goog.isArray(options) || options.length < 2) { + if (!goog.isArray(options)) { return; } + // Replace message strings. + for (var i = 0; i < options.length; i++) { + var rawText = options[i][0]; + var localizedText = Blockly.utils.replaceMessageReferences(rawText); + options[i][0] = localizedText; + } + if (options.length < 2) { + return; // Nothing to trim. + } var strings = []; for (var i = 0; i < options.length; i++) { var text = options[i][0]; diff --git a/core/utils.js b/core/utils.js index 32e171962..9ec03b84b 100644 --- a/core/utils.js +++ b/core/utils.js @@ -392,11 +392,43 @@ Blockly.utils.commonWordSuffix = function(array, opt_shortest) { /** * Parse a string with any number of interpolation tokens (%1, %2, ...). - * '%' characters may be self-escaped (%%). - * @param {string} message Text containing interpolation tokens. + * It will also replace string table references (e.g., %{bky_my_msg} and + * %{BKY_MY_MSG} will both be replaced with the value in + * Blockly.Msg['MY_MSG']). Percentage sign characters '%' may be self-escaped + * (e.g., '%%'). + * @param {string} message Text which might contain string table references and + * interpolation tokens. * @return {!Array.} Array of strings and numbers. */ Blockly.utils.tokenizeInterpolation = function(message) { + return Blockly.utils.tokenizeInterpolation_(message, true); +} + +/** + * Replaces string table references in a message string. For example, + * %{bky_my_msg} and %{BKY_MY_MSG} will both be replaced with the value in + * Blockly.Msg['MY_MSG']. + * @param {string} message Text which might contain string table references. + * @return {!string} String with message references replaced. + */ +Blockly.utils.replaceMessageReferences = function(message) { + var interpolatedResult = Blockly.utils.tokenizeInterpolation_(message, false); + // When parseInterpolationTokens == false, interpolatedResult should be at + // most length 1. + return interpolatedResult.length ? interpolatedResult[0] : ""; +} + +/** + * Internal implemention of the message reference and interpolation token + * parsing used by tokenizeInterpolation() and replaceMessageReferences(). + * @param {string} message Text which might contain string table references and + * interpolation tokens. + * @param {boolean} parseInterpolationTokens Option to parse numeric + * interpolation tokens (%1, %2, ...) when true. + * @return {!Array.} Array of strings and numbers. + * @private + */ +Blockly.utils.tokenizeInterpolation_ = function(message, parseInterpolationTokens) { var tokens = []; var chars = message.split(''); chars.push(''); // End marker. @@ -425,7 +457,7 @@ Blockly.utils.tokenizeInterpolation = function(message) { if (c == '%') { buffer.push(c); // Escaped %: %% state = 0; - } else if ('0' <= c && c <= '9') { + } else if (parseInterpolationTokens && '0' <= c && c <= '9') { state = 2; number = c; var text = buffer.join(''); diff --git a/tests/jsunit/utils_test.js b/tests/jsunit/utils_test.js index 5aaa2cc78..31ccfc187 100644 --- a/tests/jsunit/utils_test.js +++ b/tests/jsunit/utils_test.js @@ -188,3 +188,31 @@ function test_tokenizeInterpolation() { tokens = Blockly.utils.tokenizeInterpolation('before %{unclosed'); assertArrayEquals('String table reference, with parameter', ['before %{unclosed'], tokens); } + +function test_replaceMessageReferences() { + Blockly.Msg = Blockly.Msg || {}; + Blockly.Msg.STRING_REF = 'test string'; + + var resultString = Blockly.utils.replaceMessageReferences(''); + assertEquals('Empty string produces empty string', '', resultString); + + resultString = Blockly.utils.replaceMessageReferences('%{bky_string_ref}'); + assertEquals('Message ref dereferenced.', 'test string', resultString); + resultString = Blockly.utils.replaceMessageReferences('before %{bky_string_ref} after'); + assertEquals('Message ref dereferenced.', 'before test string after', resultString); + + resultString = Blockly.utils.replaceMessageReferences('%1'); + assertEquals('Interpolation tokens ignored.', '%1', resultString); + resultString = Blockly.utils.replaceMessageReferences('%1 %2'); + assertEquals('Interpolation tokens ignored.', '%1 %2', resultString); + resultString = Blockly.utils.replaceMessageReferences('before %1 after'); + assertEquals('Interpolation tokens ignored.', 'before %1 after', resultString); + + resultString = Blockly.utils.replaceMessageReferences('%%'); + assertEquals('Escaped %', '%', resultString); + resultString = Blockly.utils.replaceMessageReferences('%%{bky_string_ref}'); + assertEquals('Escaped %', '%{bky_string_ref}', resultString); + + resultString = Blockly.utils.replaceMessageReferences('%a'); + assertEquals('Unrecognized % escape code treated as literal', '%a', resultString); +}