From 989db4912469e9e8a6bc35c667d3b9edab4867ef Mon Sep 17 00:00:00 2001 From: Embin <113154360+NotEmbin@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:35:53 -0700 Subject: [PATCH 1/5] Create embintranslation.js --- static/extensions/Embin/embintranslation.js | 278 ++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 static/extensions/Embin/embintranslation.js diff --git a/static/extensions/Embin/embintranslation.js b/static/extensions/Embin/embintranslation.js new file mode 100644 index 000000000..8c0b6658a --- /dev/null +++ b/static/extensions/Embin/embintranslation.js @@ -0,0 +1,278 @@ +// Name: Translation Keys +// ID: embintranslation +// Description: Use translation keys in your projects for multi-language support +// By: Embin +// License: MIT + +(function (Scratch) { + 'use strict'; + + if (!Scratch.extensions.unsandboxed) { + throw new Error('"Translation Keys" must run unsandboxed'); + } + + const embin_translation_keys_version = 'v1.1.1'; + const Cast = Scratch.Cast; + let selected_lang = navigator.language || navigator.userLanguage; + let current_lang_data = {}; + let languages = {}; + languages[selected_lang] = {}; + if (selected_lang != "en-US") languages["en-US"] = {}; + + class EmbinTranslation { + getInfo() { + return { + id: 'embintranslation', + name: 'Translation Keys', + color1: '#00565b', + color2: '#00494d', + color3: '#00f4ff', + blocks: [ + { + opcode: 'get_user_language', + blockType: Scratch.BlockType.REPORTER, + text: 'user language code', + disableMonitor: false + }, + { + opcode: 'get_selected_language', + blockType: Scratch.BlockType.REPORTER, + text: 'current selected language', + disableMonitor: false + }, + '---', + { + opcode: 'get_translation_json', + blockType: Scratch.BlockType.REPORTER, + text: 'get current translation data as json', + disableMonitor: true + }, + { + opcode: 'get_all_translation_json', + blockType: Scratch.BlockType.REPORTER, + text: 'get all translation data as json', + disableMonitor: true + }, + { + opcode: 'set_translation_json', + blockType: Scratch.BlockType.COMMAND, + text: 'set current translation data to json [json]', + arguments: { + json: { + type: Scratch.ArgumentType.STRING, + defaultValue: '{"block.stone":"Stone","block.air":"Air %s dud"}' + } + } + }, + { + opcode: 'set_lang_translation_json', + blockType: Scratch.BlockType.COMMAND, + text: 'set translation data of language [lang] to json [json]', + arguments: { + lang: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'en-US' + }, + json: { + type: Scratch.ArgumentType.STRING, + defaultValue: '{"block.stone":"Stone","block.air":"Air %s dud"}' + } + } + }, + { + opcode: 'set_current_language', + blockType: Scratch.BlockType.COMMAND, + text: 'set current language to [lang]', + arguments: { + lang: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'en-US' + } + } + }, + { + opcode: 'clear_translations', + blockType: Scratch.BlockType.COMMAND, + text: 'clear current translation data' + }, + { + opcode: 'clear_all_translations', + blockType: Scratch.BlockType.COMMAND, + text: 'clear all translations' + }, + '---', + { + opcode: 'get_translation', + blockType: Scratch.BlockType.REPORTER, + text: 'get translation [translation_key]', + disableMonitor: true, + arguments: { + translation_key: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'block.stone' + } + } + }, + { + opcode: 'get_translation_with_data', + blockType: Scratch.BlockType.REPORTER, + text: 'get translation [translation_key] with data [data]', + disableMonitor: true, + arguments: { + translation_key: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'block.air' + }, + data: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'soap' + } + } + }, + '---', + { + opcode: 'add_translation', + blockType: Scratch.BlockType.COMMAND, + text: 'add translation key [key] with value [value] to current lang', + arguments: { + key: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'block.stone' + }, + value: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'Stone' + } + } + }, + { + opcode: 'remove_translation', + blockType: Scratch.BlockType.COMMAND, + text: 'remove translation key [key] from current lang', + arguments: { + key: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'block.stone' + } + } + }, + ] + }; + } + + return_version (args) { + return embin_translation_keys_version; + } + + get_user_language (args) { + return navigator.language || navigator.userLanguage; + } + + get_translation (args) { + let key = Cast.toString(args.translation_key); + if (Object.keys(current_lang_data).includes(key)) return String(current_lang_data[key]); + if (Object.keys(current_lang_data).includes("missingtranslation")) return this.get_translation_with_data({translation_key: "missingtranslation", data: key}); + return key; + } + + get_translation_with_data (args) { + let string = this.get_translation(args); + let datas; + let is_data_string = false; + try { + datas = JSON.parse(args.data); + if (!Array.isArray(datas)) throw new Error("not array"); + } catch { + datas = Cast.toString(args.data); + is_data_string = true; + } + if (is_data_string) { + //if (datas === "") return string; + if (string.includes("%1$s")) return string.replaceAll("%1$s", datas); + return string.replaceAll("%s", datas); + } else { + let mutated_string = string; + for (let i = 0; i < datas.length; i++) { + let indexed_replace_key = "%" + String(i + 1) + "$s"; + let thing = datas[i]; + if (mutated_string.includes(indexed_replace_key)) { + mutated_string = mutated_string.replaceAll(indexed_replace_key, String(thing)); + } else { + mutated_string = mutated_string.replace("%s", String(thing)); + } + } + return mutated_string; + } + } + + get_translation_json (args) { + return JSON.stringify(current_lang_data); + } + + add_translation (args) { + current_lang_data[Cast.toString(args.key)] = Cast.toString(args.value); + if (!Object.hasOwn(languages, selected_lang)) languages[selected_lang] = {}; + languages[selected_lang][Cast.toString(args.key)] = Cast.toString(args.value); + } + + set_translation_json (args) { + let new_json = JSON.parse(args.json); + if (!Array.isArray(new_json)) { + current_lang_data = new_json; + languages[selected_lang] = current_lang_data; + } + } + + + serialize () { + return { embintranslation: { current_lang_data: current_lang_data, languages: languages } }; + } + + deserialize (data) { + if (data.embintranslation !== undefined) { + current_lang_data = data.embintranslation.current_lang_data; + languages = data.embintranslation.languages; + } + } + + + remove_translation (args) { + delete current_lang_data[Cast.toString(args.key)]; + delete languages[selected_lang][Cast.toString(args.key)]; + } + + clear_translations (args) { + current_lang_data = {}; + languages[selected_lang] = {}; + } + + get_selected_language (args) { + return selected_lang; + } + + clear_all_translations (args) { + languages = {}; + current_lang_data = {}; + } + + set_current_language (args) { + selected_lang = Cast.toString(args.lang); + if (!Object.hasOwn(languages, selected_lang)) languages[selected_lang] = {}; + current_lang_data = languages[selected_lang]; + } + + get_all_translation_json (args) { + return JSON.stringify(languages); + } + + set_lang_translation_json (args) { + let new_json = JSON.parse(args.json); + if (!Array.isArray(new_json)) { + languages[Cast.toString(args.lang)] = new_json; + if (selected_lang == Cast.toString(args.lang)) current_lang_data = new_json; + } + } + + } // end of blocks code + Scratch.extensions.register(new EmbinTranslation()); +})(Scratch); From 3d58dc84bbc34baa15148cb8caecf50653c31c85 Mon Sep 17 00:00:00 2001 From: Embin <113154360+NotEmbin@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:38:03 -0700 Subject: [PATCH 2/5] Add files via upload --- static/images/embintranslation.png | Bin 0 -> 23144 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 static/images/embintranslation.png diff --git a/static/images/embintranslation.png b/static/images/embintranslation.png new file mode 100644 index 0000000000000000000000000000000000000000..384edb44db7289171c6e32bc219fc35d850ed13b GIT binary patch literal 23144 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 literal 0 HcmV?d00001 From 96555004c165bc499bc2434eba215a3b3689a223 Mon Sep 17 00:00:00 2001 From: Embin <113154360+NotEmbin@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:39:03 -0700 Subject: [PATCH 3/5] Rename static/images/embintranslation.png to static/images/Embin/embintranslation.png --- static/images/{ => Embin}/embintranslation.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename static/images/{ => Embin}/embintranslation.png (100%) diff --git a/static/images/embintranslation.png b/static/images/Embin/embintranslation.png similarity index 100% rename from static/images/embintranslation.png rename to static/images/Embin/embintranslation.png From a29c15dcdc9866286af90edd5ba8287785d7835d Mon Sep 17 00:00:00 2001 From: Embin <113154360+NotEmbin@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:46:21 -0700 Subject: [PATCH 4/5] Update extensions.js --- src/lib/extensions.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index b50a99058..4426d5f29 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -187,6 +187,15 @@ export default [ isGitHub: true, notes: "Gallery banner by Dillon", }, + { + name: "Translation Keys", + description: "Use translation keys in your projects for multi-language support", + code: "Embin/embintranslation.js", + banner: "Embin/embintranslation.png", + creator: "NotEmbin", + isGitHub: true, + creatorAlias: "Embin", + }, { name: "Yet Another String Extension", description: "A small collection of utilty blocks intended to make managing strings much, much easier.", From 0c7e53366be12b43f1b124594576548af38274a9 Mon Sep 17 00:00:00 2001 From: Embin <113154360+NotEmbin@users.noreply.github.com> Date: Mon, 6 Oct 2025 13:38:20 -0700 Subject: [PATCH 5/5] v1.1.2 - Replace {} with Object.create(null); --- static/extensions/Embin/embintranslation.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/static/extensions/Embin/embintranslation.js b/static/extensions/Embin/embintranslation.js index 8c0b6658a..6648d824c 100644 --- a/static/extensions/Embin/embintranslation.js +++ b/static/extensions/Embin/embintranslation.js @@ -11,13 +11,13 @@ throw new Error('"Translation Keys" must run unsandboxed'); } - const embin_translation_keys_version = 'v1.1.1'; + const embin_translation_keys_version = 'v1.1.2'; const Cast = Scratch.Cast; let selected_lang = navigator.language || navigator.userLanguage; - let current_lang_data = {}; - let languages = {}; - languages[selected_lang] = {}; - if (selected_lang != "en-US") languages["en-US"] = {}; + let current_lang_data = Object.create(null); + let languages = Object.create(null); + languages[selected_lang] = Object.create(null); + if (selected_lang != "en-US") languages["en-US"] = Object.create(null); class EmbinTranslation { getInfo() { @@ -242,8 +242,8 @@ } clear_translations (args) { - current_lang_data = {}; - languages[selected_lang] = {}; + current_lang_data = Object.create(null); + languages[selected_lang] = Object.create(null); } get_selected_language (args) { @@ -251,13 +251,13 @@ } clear_all_translations (args) { - languages = {}; - current_lang_data = {}; + languages = Object.create(null); + current_lang_data = Object.create(null); } set_current_language (args) { selected_lang = Cast.toString(args.lang); - if (!Object.hasOwn(languages, selected_lang)) languages[selected_lang] = {}; + if (!Object.hasOwn(languages, selected_lang)) languages[selected_lang] = Object.create(null); current_lang_data = languages[selected_lang]; }