Skip to content

Commit 4cacde4

Browse files
authored
Merge pull request #163 from carlosperate/lang
Change how Ardublockly block strings are stored and build
2 parents 6edff27 + c733502 commit 4cacde4

21 files changed

+1026
-848
lines changed

blockly/build.py

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ def _rebuild(self, srcs, dests):
391391
else:
392392
print("Error checking file creation times: " + e)
393393

394-
def run(self):
394+
def generate_blockly(self):
395395
# The files msg/json/{en,qqq,synonyms}.json depend on msg/messages.js.
396396
if self._rebuild([os.path.join("msg", "messages.js")],
397397
[os.path.join("msg", "json", f) for f in
@@ -424,7 +424,8 @@ def run(self):
424424
"--quiet"]
425425
json_files = glob.glob(os.path.join("msg", "json", "*.json"))
426426
json_files = [file for file in json_files if not
427-
(file.endswith(("keys.json", "synonyms.json", "qqq.json")))]
427+
(file.endswith(("keys.json", "synonyms.json", "qqq.json",
428+
"_ardublockly.json")))]
428429
cmd.extend(json_files)
429430
subprocess.check_call(cmd)
430431
except (subprocess.CalledProcessError, OSError) as e:
@@ -440,6 +441,62 @@ def run(self):
440441
else:
441442
print("FAILED to create " + f)
442443

444+
def generate_ardublockly(self):
445+
"""
446+
Recreates the msg/json/{en,qqq,synonyms}_ardublockly.json files if older
447+
than msg/messages_ardublockly.js.
448+
Then attaches the {lang}_ardublockly.json strings into the {lang}.js files.
449+
"""
450+
# The files msg/json/{en,qqq,synonyms}.json depend on msg/messages.js.
451+
if self._rebuild([os.path.join("msg", "messages_ardublockly.js")],
452+
[os.path.join("msg", "json", f) for f in
453+
["en_ardublockly.json",
454+
"qqq_ardublockly.json",
455+
"synonyms_ardublockly.json"]]):
456+
try:
457+
subprocess.check_call([
458+
"python",
459+
os.path.join("i18n", "js_to_json.py"),
460+
"--author", "carlosperate",
461+
"--input_file", "msg/messages_ardublockly.js",
462+
"--output_dir", "msg/json/",
463+
"--ardublockly",
464+
"--quiet"])
465+
except (subprocess.CalledProcessError, OSError) as e:
466+
print("Error running i18n/js_to_json.py for Ardublockly pass: ", e)
467+
sys.exit(1)
468+
469+
try:
470+
# Use create_messages.py to attach _ardublockly.json strings to .js files
471+
cmd = [
472+
"python",
473+
os.path.join("i18n", "create_messages.py"),
474+
"--source_lang_file", os.path.join("msg","json",
475+
"en_ardublockly.json"),
476+
"--source_synonym_file", os.path.join("msg", "json",
477+
"synonyms_ardublockly.json"),
478+
"--output_dir", os.path.join("msg", "js"),
479+
"--ardublockly",
480+
"--quiet"]
481+
json_files = glob.glob(os.path.join("msg", "json", "*.json"))
482+
json_files = [file for file in json_files if not
483+
(file.endswith(("keys.json", "synonyms.json", "qqq.json",
484+
"_ardublockly.json")))]
485+
cmd.extend(json_files)
486+
subprocess.check_call(cmd)
487+
except (subprocess.CalledProcessError, OSError) as e:
488+
print("Error running i18n/create_messages.py for Ardublockly pass: ", e)
489+
sys.exit(1)
490+
491+
def run(self):
492+
"""
493+
Runs the thread to generate the Blockly JavaScript string files and append
494+
the Ardublockly strings at the end as well.
495+
"""
496+
self.generate_blockly()
497+
# Ardublockly appends it's strings at the end of blockly output
498+
self.generate_ardublockly()
499+
443500

444501
if __name__ == "__main__":
445502
try:

blockly/i18n/common.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def read_json_file(filename):
6464
raise InputError(filename, str(e))
6565

6666

67-
def _create_qqq_file(output_dir):
67+
def _create_qqq_file(output_dir, ardublockly=False):
6868
"""Creates a qqq.json file with message documentation for translatewiki.net.
6969
7070
The file consists of key-value pairs, where the keys are message ids and
@@ -83,7 +83,8 @@ def _create_qqq_file(output_dir):
8383
Raises:
8484
IOError: An error occurred while opening or writing the file.
8585
"""
86-
qqq_file_name = os.path.join(os.curdir, output_dir, 'qqq.json')
86+
qqq_file_name = 'qqq_ardublockly.json' if ardublockly else 'qqq.json'
87+
qqq_file_name = os.path.join(os.curdir, output_dir, qqq_file_name)
8788
qqq_file = codecs.open(qqq_file_name, 'w', 'utf-8')
8889
print 'Created file: ' + qqq_file_name
8990
qqq_file.write('{\n')
@@ -105,7 +106,7 @@ def _close_qqq_file(qqq_file):
105106
qqq_file.close()
106107

107108

108-
def _create_lang_file(author, lang, output_dir):
109+
def _create_lang_file(author, lang, output_dir, ardublockly=False):
109110
"""Creates a <lang>.json file for translatewiki.net.
110111
111112
The file consists of metadata, followed by key-value pairs, where the keys
@@ -124,7 +125,8 @@ def _create_lang_file(author, lang, output_dir):
124125
Raises:
125126
IOError: An error occurred while opening or writing the file.
126127
"""
127-
lang_file_name = os.path.join(os.curdir, output_dir, lang + '.json')
128+
lang_file_name = lang + ('_ardublockly.json' if ardublockly else '.json')
129+
lang_file_name = os.path.join(os.curdir, output_dir, lang_file_name)
128130
lang_file = codecs.open(lang_file_name, 'w', 'utf-8')
129131
print 'Created file: ' + lang_file_name
130132
# string.format doesn't like printing braces, so break up our writes.
@@ -232,3 +234,27 @@ def write_files(author, lang, output_dir, units, write_key_file):
232234
if write_key_file:
233235
_close_key_file(key_file)
234236
_close_qqq_file(qqq_file)
237+
238+
239+
def write_files_ardublockly(author, lang, output_dir, units):
240+
"""
241+
Same as write_files, but does not include the key_files and generates
242+
lang_ardublockly.json and qqq_ardublockly.json instead.
243+
"""
244+
lang_file = _create_lang_file(author, lang, output_dir, ardublockly=True)
245+
qqq_file = _create_qqq_file(output_dir, ardublockly=True)
246+
first_entry = True
247+
for unit in units:
248+
if not first_entry:
249+
lang_file.write(',\n')
250+
qqq_file.write(',\n')
251+
lang_file.write(u'\t"{0}": "{1}"'.format(
252+
unit['meaning'],
253+
unit['source'].replace('"', "'")))
254+
qqq_file.write(u'\t"{0}": "{1}"'.format(
255+
unit['meaning'],
256+
unit['description'].replace('"', "'").replace(
257+
'{lb}', '{').replace('{rb}', '}')))
258+
first_entry = False
259+
_close_lang_file(lang_file)
260+
_close_qqq_file(qqq_file)

blockly/i18n/create_messages.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ def main():
5555
help='relative path to input keys file')
5656
parser.add_argument('--quiet', action='store_true', default=False,
5757
help='do not write anything to standard output')
58+
parser.add_argument('--ardublockly', action='store_true', default=False,
59+
help='Attach Ardublockly strings to lang js files')
5860
parser.add_argument('files', nargs='+', help='input files')
5961
args = parser.parse_args()
6062
if not args.output_dir.endswith(os.path.sep):
@@ -80,10 +82,18 @@ def main():
8082

8183
# Create each output file.
8284
for arg_file in args.files:
83-
(_, filename) = os.path.split(arg_file)
85+
(dir_, filename) = os.path.split(arg_file)
8486
target_lang = filename[:filename.index('.')]
8587
if target_lang not in ('qqq', 'keys', 'synonyms'):
86-
target_defs = read_json_file(os.path.join(os.curdir, arg_file))
88+
if args.ardublockly:
89+
# For Ardublockly pass search for {lang}_ardublockly.json target file
90+
target_defs = {}
91+
ardu_json = os.path.join(dir_, target_lang + '_ardublockly.json')
92+
if os.path.isfile(ardu_json):
93+
target_defs = read_json_file(os.path.join(os.curdir, ardu_json))
94+
print(u'Processed Ardublockly translation: {0}'.format(ardu_json))
95+
else:
96+
target_defs = read_json_file(os.path.join(os.curdir, arg_file))
8797

8898
# Verify that keys are 'ascii'
8999
bad_keys = [key for key in target_defs if not string_is_ascii(key)]
@@ -99,19 +109,23 @@ def main():
99109
format(key, arg_file))
100110
target_defs[key] = _NEWLINE_PATTERN.sub(' ', value)
101111

112+
# Prepare differences from parsing lang.json and lang_ardublockly.json
113+
if args.ardublockly:
114+
file_write_mode = 'a'
115+
start_str = '\n\n// Ardublockly strings\n'
116+
else:
117+
file_write_mode = 'w'
118+
start_str = ("// This file was automatically generated. "
119+
"Do not modify.\n\n"
120+
"'use strict';\n\n"
121+
"goog.provide('Blockly.Msg.{0}');\n\n"
122+
"goog.require('Blockly.Msg');\n\n").format(
123+
target_lang.replace('-', '.'))
124+
102125
# Output file.
103126
outname = os.path.join(os.curdir, args.output_dir, target_lang + '.js')
104-
with codecs.open(outname, 'w', 'utf-8') as outfile:
105-
outfile.write(
106-
"""// This file was automatically generated. Do not modify.
107-
108-
'use strict';
109-
110-
goog.provide('Blockly.Msg.{0}');
111-
112-
goog.require('Blockly.Msg');
113-
114-
""".format(target_lang.replace('-', '.')))
127+
with codecs.open(outname, file_write_mode, 'utf-8') as outfile:
128+
outfile.write(start_str)
115129
# For each key in the source language file, output the target value
116130
# if present; otherwise, output the source language value with a
117131
# warning comment.

blockly/i18n/js_to_json.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@
4545
import json
4646
import os
4747
import re
48-
from common import write_files
48+
from common import write_files, write_files_ardublockly
4949

5050

51-
_INPUT_DEF_PATTERN = re.compile("""Blockly.Msg.(\w*)\s*=\s*'([^']*)';?$""")
51+
#_INPUT_DEF_PATTERN = re.compile("""Blockly.Msg.(\w*)\s*=\s*'([^']*)';?$""")
52+
_INPUT_DEF_PATTERN = re.compile("""Blockly.Msg.(\w*)\s*=\s*'([^']*)';[\r\n]+$""")
5253

5354
_INPUT_SYN_PATTERN = re.compile(
5455
"""Blockly.Msg.(\w*)\s*=\s*Blockly.Msg.(\w*);""")
@@ -68,6 +69,8 @@ def main():
6869
help='input file')
6970
parser.add_argument('--quiet', action='store_true', default=False,
7071
help='only display warnings, not routine info')
72+
parser.add_argument('--ardublockly', action='store_true', default=False,
73+
help='Create files for Ardublockly messages')
7174
args = parser.parse_args()
7275
if (not args.output_dir.endswith(os.path.sep)):
7376
args.output_dir += os.path.sep
@@ -105,7 +108,10 @@ def main():
105108
infile.close()
106109

107110
# Create <lang_file>.json, keys.json, and qqq.json.
108-
write_files(args.author, args.lang, args.output_dir, results, False)
111+
if args.ardublockly:
112+
write_files_ardublockly(args.author, args.lang, args.output_dir, results)
113+
else:
114+
write_files(args.author, args.lang, args.output_dir, results, False)
109115

110116
# Create synonyms.json.
111117
synonym_file_name = os.path.join(os.curdir, args.output_dir, 'synonyms.json')

blockly/msg/json/en.json

Lines changed: 1 addition & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -370,123 +370,5 @@
370370
"PROCEDURES_CREATE_DO": "Create '%1'",
371371
"PROCEDURES_IFRETURN_TOOLTIP": "If a value is true, then return a second value.",
372372
"PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause",
373-
"PROCEDURES_IFRETURN_WARNING": "Warning: This block may be used only within a function definition.",
374-
"ARD_TYPE_CHAR": "Character",
375-
"ARD_TYPE_TEXT": "Text",
376-
"ARD_TYPE_BOOL": "Boolean",
377-
"ARD_TYPE_SHORT": "Short Number",
378-
"ARD_TYPE_NUMBER": "Number",
379-
"ARD_TYPE_LONG": "Large Number",
380-
"ARD_TYPE_DECIMAL": "Decimal",
381-
"ARD_TYPE_ARRAY": "Array",
382-
"ARD_TYPE_NULL": "Null",
383-
"ARD_TYPE_UNDEF": "Undefined",
384-
"ARD_TYPE_CHILDBLOCKMISSING": "ChildBlockMissing",
385-
"ARD_HIGH": "HIGH",
386-
"ARD_LOW": "LOW",
387-
"ARD_ANALOGREAD": "read analog pin#",
388-
"ARD_ANALOGREAD_TIP": "Return value between 0 and 1024",
389-
"ARD_ANALOGWRITE": "set analog pin#",
390-
"ARD_ANALOGWRITE_TIP": "Write analog value between 0 and 255 to a specific PWM Port",
391-
"ARD_HIGHLOW_TIP": "Set a pin state logic High or Low.",
392-
"ARD_DIGITALREAD": "read digital pin#",
393-
"ARD_DIGITALREAD_TIP": "Read digital value on a pin: HIGH or LOW",
394-
"ARD_DIGITALWRITE": "set digitial pin#",
395-
"ARD_WRITE_TO": "to",
396-
"ARD_DIGITALWRITE_TIP": "Write digital value HIGH or LOW to a specific Port",
397-
"ARD_BUILTIN_LED": "set built-in LED",
398-
"ARD_BUILTIN_LED_TIP": "Light on or off for the built-in LED of the Arduino",
399-
"ARD_DEFINE": "Define",
400-
"ARD_TONE_PIN": "Tone PIN#",
401-
"ARD_TONE_FREQ": "frequency",
402-
"ARD_TONE_PIN_TIP": "Generate audio tones on a pin",
403-
"ARD_NOTONE_PIN": "No tone PIN#",
404-
"ARD_NOTONE_PIN_TIP": "Stop generating a tone on a pin",
405-
"ARD_MAP": "Map",
406-
"ARD_MAP_VAL": "value to [0-",
407-
"ARD_MAP_TIP": "Re-maps a number from [0-1024] to another.",
408-
"ARD_FUN_RUN_SETUP": "Arduino run first:",
409-
"ARD_FUN_RUN_LOOP": "Arduino loop forever:",
410-
"ARD_FUN_RUN_TIP": "Defines the Arduino setup() and loop() functions.",
411-
"ARD_PIN_WARN1": "Pin %1 is needed for %2 as pin %3. Already used as %4.",
412-
"ARD_SERIAL_SETUP": "Setup",
413-
"ARD_SERIAL_SPEED": ": speed to",
414-
"ARD_SERIAL_BPS": "bps",
415-
"ARD_SERIAL_SETUP_TIP": "Selects the speed for a specific Serial peripheral",
416-
"ARD_SERIAL_PRINT": "print",
417-
"ARD_SERIAL_PRINT_NEWLINE": "add new line",
418-
"ARD_SERIAL_PRINT_TIP": "Prints data to the console/serial port as human-readable ASCII text.",
419-
"ARD_SERIAL_PRINT_WARN": "A setup block for %1 must be added to the workspace to use this block!",
420-
"ARD_SERVO_WRITE": "set SERVO from Pin",
421-
"ARD_SERVO_WRITE_TO": "to",
422-
"ARD_SERVO_WRITE_DEG_180": "Degrees (0~180)",
423-
"ARD_SERVO_WRITE_TIP": "Set a Servo to an specified angle",
424-
"ARD_SERVO_READ": "read SERVO from PIN#",
425-
"ARD_SERVO_READ_TIP": "Read a Servo angle",
426-
"ARD_SPI_SETUP": "Setup",
427-
"ARD_SPI_SETUP_CONF": "configuration:",
428-
"ARD_SPI_SETUP_SHIFT": "data shift",
429-
"ARD_SPI_SETUP_MSBFIRST": "MSBFIRST",
430-
"ARD_SPI_SETUP_LSBFIRST": "LSBFIRST",
431-
"ARD_SPI_SETUP_DIVIDE": "clock divide",
432-
"ARD_SPI_SETUP_MODE": "SPI mode (idle - edge)",
433-
"ARD_SPI_SETUP_MODE0": "0 (Low - Falling)",
434-
"ARD_SPI_SETUP_MODE1": "1 (Low - Rising)",
435-
"ARD_SPI_SETUP_MODE2": "2 (High - Falling)",
436-
"ARD_SPI_SETUP_MODE3": "3 (High - Rising)",
437-
"ARD_SPI_SETUP_TIP": "Configures the SPI peripheral.",
438-
"ARD_SPI_TRANS_NONE": "none",
439-
"ARD_SPI_TRANS_VAL": "transfer",
440-
"ARD_SPI_TRANS_SLAVE": "to slave pin",
441-
"ARD_SPI_TRANS_TIP": "Send a SPI message to an specified slave device.",
442-
"ARD_SPI_TRANS_WARN1": "A setup block for %1 must be added to the workspace to use this block!",
443-
"ARD_SPI_TRANS_WARN2": "Old pin value %1 is no longer available.",
444-
"ARD_SPI_TRANSRETURN_TIP": "Send a SPI message to an specified slave device and get data back.",
445-
"ARD_STEPPER_SETUP": "Setup stepper motor",
446-
"ARD_STEPPER_MOTOR": "stepper motor:",
447-
"ARD_STEPPER_DEFAULT_NAME": "MyStepper",
448-
"ARD_STEPPER_NUMBER_OF_PINS": "Number of pins",
449-
"ARD_STEPPER_TWO_PINS": "2",
450-
"ARD_STEPPER_FOUR_PINS": "4",
451-
"ARD_STEPPER_PIN1": "pin1#",
452-
"ARD_STEPPER_PIN2": "pin2#",
453-
"ARD_STEPPER_PIN3": "pin3#",
454-
"ARD_STEPPER_PIN4": "pin4#",
455-
"ARD_STEPPER_REVOLVS": "how many steps per revolution",
456-
"ARD_STEPPER_SPEED": "set speed (rpm) to",
457-
"ARD_STEPPER_SETUP_TIP": "Configures a stepper motor pinout and other settings.",
458-
"ARD_STEPPER_STEP": "move stepper",
459-
"ARD_STEPPER_STEPS": "steps",
460-
"ARD_STEPPER_STEP_TIP": "Turns the stepper motor a specific number of steps.",
461-
"ARD_STEPPER_COMPONENT": "stepper",
462-
"ARD_COMPONENT_WARN1": "A %1 configuration block with the same %2 name must be added to use this block!",
463-
"ARD_TIME_DELAY": "wait",
464-
"ARD_TIME_MS": "milliseconds",
465-
"ARD_TIME_DELAY_TIP": "Wait specific time in milliseconds",
466-
"ARD_TIME_DELAY_MICROS": "microseconds",
467-
"ARD_TIME_DELAY_MICRO_TIP": "Wait specific time in microseconds",
468-
"ARD_TIME_MILLIS": "current elapsed Time (milliseconds)",
469-
"ARD_TIME_MILLIS_TIP": "Returns the number of milliseconds since the Arduino board began running the current program. Has to be stored in a positive long integer",
470-
"ARD_TIME_MICROS": "current elapsed Time (microseconds)",
471-
"ARD_TIME_MICROS_TIP": "Returns the number of microseconds since the Arduino board began running the current program. Has to be stored in a positive long integer",
472-
"ARD_TIME_INF": "wait forever (end program)",
473-
"ARD_TIME_INF_TIP": "Wait indefinitely, stopping the program.",
474-
"ARD_VAR_AS": "as",
475-
"ARD_VAR_AS_TIP": "Sets a value to a specific type",
476-
"ARD_PULSEREAD": "Read",
477-
"ARD_PULSEON": "pulse on pin #",
478-
"ARD_PULSETIMEOUT": "timeout after",
479-
"ARD_PULSETIMEOUT_MS": "",
480-
"ARD_PULSE_TIP": "Measures the duration of a pulse on the selected pin.",
481-
"ARD_PULSETIMEOUT_TIP": "Measures the duration of a pulse on the selected pin, if it is within the timeout.",
482-
"ARD_SETTONE": "Set tone on pin #",
483-
"ARD_TONEFREQ": "at frequency",
484-
"ARD_TONE_TIP": "Sets tone on pin to specified frequency within range 31 - 65535",
485-
"ARD_TONE_WARNING": "Frequency must be in range 31 - 65535",
486-
"ARD_NOTONE": "Turn off tone on pin #",
487-
"ARD_NOTONE_TIP": "Turns the tone off on the selected pin",
488-
"NEW_INSTANCE": "New instance...",
489-
"RENAME_INSTANCE": "Rename instance...",
490-
"NEW_INSTANCE_TITLE": "New instance name:",
491-
"RENAME_INSTANCE_TITLE": "Rename all '%1' instances to:"
373+
"PROCEDURES_IFRETURN_WARNING": "Warning: This block may be used only within a function definition."
492374
}

0 commit comments

Comments
 (0)