From 4810a67e2e7a772e8a6545bdc586aac5e28cc5df Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Fri, 9 Apr 2021 00:46:10 +0800 Subject: [PATCH 1/8] Remove unused translation strings --- Translations/translations_def.js | 25 ------------------------- source/Core/Inc/Translation.h | 9 +-------- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/Translations/translations_def.js b/Translations/translations_def.js index b4b01eb8..2bbdb9d0 100644 --- a/Translations/translations_def.js +++ b/Translations/translations_def.js @@ -1,9 +1,6 @@ var def = { "messages": [ - { - "id": "SettingsCalibrationDone" - }, { "id": "SettingsCalibrationWarning" }, @@ -23,15 +20,6 @@ var def = "maxLen": 11, "note": "Preferably end with a space" }, - { - "id": "WarningTipTempString", - "maxLen": 12, - "note": "Preferably end with a space" - }, - { - "id": "BadTipString", - "maxLen": 8 - }, { "id": "SleepingSimpleString", "maxLen": 4 @@ -40,14 +28,6 @@ var def = "id": "SleepingAdvancedString", "maxLen": 16 }, - { - "id": "WarningSimpleString", - "maxLen": 4 - }, - { - "id": "WarningAdvancedString", - "maxLen": 16 - }, { "id": "SleepingTipAdvancedString", "maxLen": 6 @@ -80,11 +60,6 @@ var def = { "id": "OffString", "maxLen": 3 - }, - { - "id": "YourGainMessage", - "maxLen": 8, - "default": "Your Gain" } ], "messagesWarn": [ diff --git a/source/Core/Inc/Translation.h b/source/Core/Inc/Translation.h index 69c96a34..2fc8c23b 100644 --- a/source/Core/Inc/Translation.h +++ b/source/Core/Inc/Translation.h @@ -16,26 +16,20 @@ extern const char *SettingsShortNames[]; extern const char *SettingsDescriptions[]; extern const char *SettingsMenuEntries[]; -extern const char *SettingsCalibrationDone; extern const char *SettingsCalibrationWarning; extern const char *SettingsResetWarning; extern const char *UVLOWarningString; extern const char *UndervoltageString; extern const char *InputVoltageString; -extern const char *WarningTipTempString; -extern const char *BadTipString; extern const char *SleepingSimpleString; extern const char *SleepingAdvancedString; -extern const char *WarningSimpleString; -extern const char *WarningAdvancedString; extern const char *SleepingTipAdvancedString; extern const char *IdleTipString; extern const char *IdleSetString; extern const char *TipDisconnectedString; extern const char *SolderingAdvancedPowerPrompt; extern const char *OffString; -extern const char *YourGainMessage; extern const char *ResetOKMessage; extern const char *SettingsResetMessage; @@ -65,8 +59,7 @@ extern const char *SettingOffChar; extern const char *SettingFastChar; extern const char *SettingMediumChar; extern const char *SettingSlowChar; -extern const char *TipModelStrings[]; -extern const char *DebugMenu[]; + extern const char *SymbolPlus; extern const char *SymbolMinus; extern const char *SymbolSpace; From 09a58f6f4834d7680fd80855d11521ce65e5f664 Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Tue, 6 Apr 2021 17:24:57 +0800 Subject: [PATCH 2/8] Use settings desc by indexing instead of direct pointer --- source/Core/Inc/Translation.h | 2 +- source/Core/Inc/gui.hpp | 4 +++- source/Core/Src/gui.cpp | 26 +++++++++++++------------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/source/Core/Inc/Translation.h b/source/Core/Inc/Translation.h index 2fc8c23b..46cdaed2 100644 --- a/source/Core/Inc/Translation.h +++ b/source/Core/Inc/Translation.h @@ -110,6 +110,6 @@ enum class SettingsItemIndex : uint8_t { constexpr uint8_t settings_item_index(const SettingsItemIndex i) { return static_cast(i); } // Use a constexpr function for type-checking. -#define SETTINGS_DESC(i) (SettingsDescriptions[settings_item_index(i)]) +#define SETTINGS_DESC(i) (settings_item_index(i) + 1) #endif /* TRANSLATION_H_ */ diff --git a/source/Core/Inc/gui.hpp b/source/Core/Inc/gui.hpp index 45e9f288..7180253d 100644 --- a/source/Core/Inc/gui.hpp +++ b/source/Core/Inc/gui.hpp @@ -21,7 +21,9 @@ // Struct for holding the function pointers and descriptions typedef struct { - const char *description; + // The settings description index, please use the `SETTINGS_DESC` macro with + // the `SettingsItemIndex` enum. Use 0 for no description. + uint8_t description; // return true if increment reached the maximum value bool (*const incrementHandler)(void); bool (*const draw)(void); diff --git a/source/Core/Src/gui.cpp b/source/Core/Src/gui.cpp index 8c907521..9e3a184a 100644 --- a/source/Core/Src/gui.cpp +++ b/source/Core/Src/gui.cpp @@ -139,12 +139,12 @@ const menuitem rootSettingsMenu[]{ * Advanced Menu * Exit */ - {nullptr, settings_enterPowerMenu, settings_displayPowerMenu}, /*Power*/ - {nullptr, settings_enterSolderingMenu, settings_displaySolderingMenu}, /*Soldering*/ - {nullptr, settings_enterPowerSavingMenu, settings_displayPowerSavingMenu}, /*Sleep Options Menu*/ - {nullptr, settings_enterUIMenu, settings_displayUIMenu}, /*UI Menu*/ - {nullptr, settings_enterAdvancedMenu, settings_displayAdvancedMenu}, /*Advanced Menu*/ - {nullptr, nullptr, nullptr} // end of menu marker. DO NOT REMOVE + {0, settings_enterPowerMenu, settings_displayPowerMenu}, /*Power*/ + {0, settings_enterSolderingMenu, settings_displaySolderingMenu}, /*Soldering*/ + {0, settings_enterPowerSavingMenu, settings_displayPowerSavingMenu}, /*Sleep Options Menu*/ + {0, settings_enterUIMenu, settings_displayUIMenu}, /*UI Menu*/ + {0, settings_enterAdvancedMenu, settings_displayAdvancedMenu}, /*Advanced Menu*/ + {0, nullptr, nullptr} // end of menu marker. DO NOT REMOVE }; const menuitem powerMenu[] = { @@ -158,7 +158,7 @@ const menuitem powerMenu[] = { #ifdef POW_QC {SETTINGS_DESC(SettingsItemIndex::QCMaxVoltage), settings_setQCInputV, settings_displayQCInputV}, /*Voltage input*/ #endif - {nullptr, nullptr, nullptr} // end of menu marker. DO NOT REMOVE + {0, nullptr, nullptr} // end of menu marker. DO NOT REMOVE }; const menuitem solderingMenu[] = { /* @@ -173,7 +173,7 @@ const menuitem solderingMenu[] = { {SETTINGS_DESC(SettingsItemIndex::TempChangeShortStep), settings_setTempChangeShortStep, settings_displayTempChangeShortStep}, /*Temp change short step*/ {SETTINGS_DESC(SettingsItemIndex::TempChangeLongStep), settings_setTempChangeLongStep, settings_displayTempChangeLongStep}, /*Temp change long step*/ {SETTINGS_DESC(SettingsItemIndex::LockingMode), settings_setLockingMode, settings_displayLockingMode}, /*Locking Mode*/ - {nullptr, nullptr, nullptr} // end of menu marker. DO NOT REMOVE + {0, nullptr, nullptr} // end of menu marker. DO NOT REMOVE }; const menuitem UIMenu[] = { /* @@ -192,7 +192,7 @@ const menuitem UIMenu[] = { {SETTINGS_DESC(SettingsItemIndex::ReverseButtonTempChange), settings_setReverseButtonTempChangeEnabled, settings_displayReverseButtonTempChangeEnabled}, /* Reverse Temp change buttons + - */ {SETTINGS_DESC(SettingsItemIndex::AnimSpeed), settings_setAnimationSpeed, settings_displayAnimationSpeed}, /*Animation Speed adjustment */ {SETTINGS_DESC(SettingsItemIndex::AnimLoop), settings_setAnimationLoop, settings_displayAnimationLoop}, /*Animation Loop switch */ - {nullptr, nullptr, nullptr} // end of menu marker. DO NOT REMOVE + {0, nullptr, nullptr} // end of menu marker. DO NOT REMOVE }; const menuitem PowerSavingMenu[] = { /* @@ -208,7 +208,7 @@ const menuitem PowerSavingMenu[] = { #ifdef HALL_SENSOR {SETTINGS_DESC(SettingsItemIndex::HallEffSensitivity), settings_setHallEffect, settings_displayHallEffect}, /* HallEffect Sensitivity*/ #endif - {nullptr, nullptr, nullptr} // end of menu marker. DO NOT REMOVE + {0, nullptr, nullptr} // end of menu marker. DO NOT REMOVE }; const menuitem advancedMenu[] = { @@ -234,7 +234,7 @@ const menuitem advancedMenu[] = { {SETTINGS_DESC(SettingsItemIndex::PowerPulsePower), settings_setPowerPulse, settings_displayPowerPulse}, /*Power Pulse adjustment */ {SETTINGS_DESC(SettingsItemIndex::PowerPulseWait), settings_setPowerPulseWait, settings_displayPowerPulseWait}, /*Power Pulse Wait adjustment*/ {SETTINGS_DESC(SettingsItemIndex::PowerPulseDuration), settings_setPowerPulseDuration, settings_displayPowerPulseDuration}, /*Power Pulse Duration adjustment*/ - {nullptr, nullptr, nullptr} // end of menu marker. DO NOT REMOVE + {0, nullptr, nullptr} // end of menu marker. DO NOT REMOVE }; /** @@ -1110,7 +1110,7 @@ void gui_Menu(const menuitem *menu) { OLED::setCursor(0, 0); // If the user has hesitated for >=3 seconds, show the long text // Otherwise "draw" the option - if ((xTaskGetTickCount() - lastButtonTime < (TICKS_SECOND * 3)) || menu[currentScreen].description == nullptr) { + if ((xTaskGetTickCount() - lastButtonTime < (TICKS_SECOND * 3)) || menu[currentScreen].description == 0) { lcdRefresh = true; OLED::clearScreen(); if (menu[currentScreen].draw()) { @@ -1128,7 +1128,7 @@ void gui_Menu(const menuitem *menu) { // Draw description if (descriptionStart == 0) descriptionStart = xTaskGetTickCount(); - const char *description = menu[currentScreen].description; + const char *description = SettingsDescriptions[menu[currentScreen].description - 1]; // lower the value - higher the speed int16_t descriptionWidth = FONT_12_WIDTH * (str_display_len(description) + 7); int16_t descriptionOffset = ((xTaskGetTickCount() - descriptionStart) / (systemSettings.descriptionScrollSpeed == 1 ? (TICKS_100MS / 10) : (TICKS_100MS / 5))); From 82620c685da582fbdfcb6a17f71dc2285c260989 Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Fri, 9 Apr 2021 14:45:33 +0800 Subject: [PATCH 3/8] Change translation strs to be stored in one block --- Translations/make_translation.py | 183 +++++++++++++++++++----------- source/Core/Inc/Translation.h | 88 +++++++------- source/Core/Src/Translation.cpp | 3 + source/Core/Src/gui.cpp | 68 +++++------ source/Core/Threads/GUIThread.cpp | 36 +++--- source/Makefile | 2 +- 6 files changed, 220 insertions(+), 160 deletions(-) create mode 100644 source/Core/Src/Translation.cpp diff --git a/Translations/make_translation.py b/Translations/make_translation.py index 66cf642c..295c9712 100755 --- a/Translations/make_translation.py +++ b/Translations/make_translation.py @@ -12,6 +12,7 @@ from datetime import datetime from itertools import chain from pathlib import Path from typing import Dict, List, TextIO, Tuple, Union +from dataclasses import dataclass from bdflib import reader as bdfreader from bdflib.model import Font, Glyph @@ -377,6 +378,16 @@ def convert_string(symbol_conversion_table: Dict[str, str], text: str) -> str: return output_string +def escape(string: str) -> str: + return json.dumps(string, ensure_ascii=False) + + +@dataclass +class TranslationItem: + info: str + str_index: int + + def write_language(lang: dict, defs: dict, f: TextIO) -> None: language_code: str = lang["languageCode"] logging.info(f"Generating block for {language_code}") @@ -394,28 +405,26 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: f.write(font_table_text) f.write(f"\n// ---- {lang_name} ----\n\n") - # ----- Writing SettingsDescriptions + str_table: List[str] = [] + str_group_messages: List[TranslationItem] = [] + str_group_messageswarn: List[TranslationItem] = [] + str_group_characters: List[TranslationItem] = [] + str_group_settingdesc: List[TranslationItem] = [] + str_group_settingshortnames: List[TranslationItem] = [] + str_group_settingmenuentries: List[TranslationItem] = [] + str_group_settingmenuentriesdesc: List[TranslationItem] = [] + + # ----- Reading SettingsDescriptions obj = lang["menuOptions"] - f.write("const char* SettingsDescriptions[] = {\n") - max_len = 25 - index = 0 - for mod in defs["menuOptions"]: + for index, mod in enumerate(defs["menuOptions"]): eid = mod["id"] - if "feature" in mod: - f.write(f"#ifdef {mod['feature']}\n") - f.write(f" /* [{index:02d}] {eid.ljust(max_len)[:max_len]} */ ") - f.write( - f"\"{convert_string(symbol_conversion_table, obj[eid]['desc'])}\",//{obj[eid]['desc']} \n" + str_group_settingdesc.append( + TranslationItem(f"[{index:02d}] {eid}", len(str_table)) ) + str_table.append(obj[eid]["desc"]) - if "feature" in mod: - f.write("#endif\n") - index += 1 - - f.write("};\n\n") - - # ----- Writing Message strings + # ----- Reading Message strings obj = lang["messages"] @@ -426,11 +435,8 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: source_text = mod["default"] if eid in obj: source_text = obj[eid] - translated_text = convert_string(symbol_conversion_table, source_text) - source_text = source_text.replace("\n", "_") - f.write(f'const char* {eid} = "{translated_text}";//{source_text} \n') - - f.write("\n") + str_group_messages.append(TranslationItem(eid, len(str_table))) + str_table.append(source_text) obj = lang["messagesWarn"] @@ -443,22 +449,17 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: source_text = obj[eid][0] + "\n" + obj[eid][1] else: source_text = "\n" + obj[eid] - translated_text = convert_string(symbol_conversion_table, source_text) - source_text = source_text.replace("\n", "_") - f.write(f'const char* {eid} = "{translated_text}";//{source_text} \n') + str_group_messageswarn.append(TranslationItem(eid, len(str_table))) + str_table.append(source_text) - f.write("\n") - - # ----- Writing Characters + # ----- Reading Characters obj = lang["characters"] for mod in defs["characters"]: eid: str = mod["id"] - f.write( - f'const char* {eid} = "{convert_string(symbol_conversion_table, obj[eid])}";//{obj[eid]} \n' - ) - f.write("\n") + str_group_characters.append(TranslationItem(eid, len(str_table))) + str_table.append(obj[eid]) # Write out firmware constant options constants = get_constants() @@ -475,13 +476,10 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: f.write(f'\t "{convert_string(symbol_conversion_table, c)}",//{c} \n') f.write("};\n\n") - # ----- Writing SettingsDescriptions + # ----- Reading SettingsDescriptions obj = lang["menuOptions"] - f.write("const char* SettingsShortNames[] = {\n") - max_len = 25 - index = 0 - for mod in defs["menuOptions"]: + for index, mod in enumerate(defs["menuOptions"]): eid = mod["id"] if isinstance(obj[eid]["text2"], list): if not obj[eid]["text2"][1]: @@ -490,25 +488,15 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: source_text = obj[eid]["text2"][0] + "\n" + obj[eid]["text2"][1] else: source_text = "\n" + obj[eid]["text2"] - if "feature" in mod: - f.write(f"#ifdef {mod['feature']}\n") - f.write(f" /* [{index:02d}] {eid.ljust(max_len)[:max_len]} */ ") - f.write( - f'{{ "{convert_string(symbol_conversion_table, source_text)}" }},//{obj[eid]["text2"]} \n' + str_group_settingshortnames.append( + TranslationItem(f"[{index:02d}] {eid}", len(str_table)) ) + str_table.append(source_text) - if "feature" in mod: - f.write("#endif\n") - index += 1 - - f.write("};\n\n") - - # ----- Writing Menu Groups + # ----- Reading Menu Groups obj = lang["menuGroups"] - f.write(f"const char* SettingsMenuEntries[{len(obj)}] = {{\n") - max_len = 25 - for mod in defs["menuGroups"]: + for index, mod in enumerate(defs["menuGroups"]): eid = mod["id"] if isinstance(obj[eid]["text2"], list): if not obj[eid]["text2"][1]: @@ -517,26 +505,91 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: source_text = obj[eid]["text2"][0] + "\n" + obj[eid]["text2"][1] else: source_text = "\n" + obj[eid]["text2"] - f.write(f" /* {eid.ljust(max_len)[:max_len]} */ ") - f.write( - f'"{convert_string(symbol_conversion_table, source_text)}",//{obj[eid]["text2"]} \n' + str_group_settingmenuentries.append( + TranslationItem(f"[{index:02d}] {eid}", len(str_table)) ) + str_table.append(source_text) - f.write("};\n\n") - - # ----- Writing Menu Groups Descriptions + # ----- Reading Menu Groups Descriptions obj = lang["menuGroups"] - f.write(f"const char* SettingsMenuEntriesDescriptions[{(len(obj))}] = {{\n") - max_len = 25 - for mod in defs["menuGroups"]: + for index, mod in enumerate(defs["menuGroups"]): eid = mod["id"] - f.write(f" /* {eid.ljust(max_len)[:max_len]} */ ") - f.write( - f"\"{convert_string(symbol_conversion_table, (obj[eid]['desc']))}\",//{obj[eid]['desc']} \n" + str_group_settingmenuentriesdesc.append( + TranslationItem(f"[{index:02d}] {eid}", len(str_table)) ) + str_table.append(obj[eid]["desc"]) + + f.write("\n") + + # TODO: De-duplicate the strings in str_table. + + # ----- Write the string table: + str_offsets = [] + offset = 0 + write_null = False + f.write("const char TranslationStrings[] = {\n") + for i, source_str in enumerate(str_table): + if write_null: + f.write(' "\\0"\n') + write_null = True + # Find what items use this string + is_used = False + for group, pre_info in [ + (str_group_messages, "messages"), + (str_group_messageswarn, "messagesWarn"), + (str_group_characters, "characters"), + (str_group_settingdesc, "SettingsDescriptions"), + (str_group_settingshortnames, "SettingsShortNames"), + (str_group_settingmenuentries, "SettingsMenuEntries"), + (str_group_settingmenuentriesdesc, "SettingsMenuEntriesDescriptions"), + ]: + for item in group: + if item.str_index == i: + is_used = True + f.write(f" // - {pre_info} {item.info}\n") + if not is_used: + str_offsets.append(-1) + write_null = False + continue + f.write(f" // {offset: >4}: {escape(source_str)}\n") + converted_str = convert_string(symbol_conversion_table, source_str) + f.write(f' "{converted_str}"') + str_offsets.append(offset) + # Sanity check: Each "char" in `converted_str` should be in format + # `\xFF`, so the length should be divisible by 4. + assert len(converted_str) % 4 == 0 + # Add the length and the null terminator + offset += len(converted_str) // 4 + 1 + f.write("\n};\n\n") + + def get_offset(idx: int) -> int: + assert str_offsets[idx] >= 0 + return str_offsets[idx] + + # ----- Write the messages string indices: + for group in [str_group_messages, str_group_messageswarn, str_group_characters]: + for item in group: + f.write( + f"const uint16_t {item.info} = {get_offset(item.str_index)}; // {escape(str_table[item.str_index])}\n" + ) + f.write("\n") + + # ----- Write the settings index tables: + for group, name in [ + (str_group_settingdesc, "SettingsDescriptions"), + (str_group_settingshortnames, "SettingsShortNames"), + (str_group_settingmenuentries, "SettingsMenuEntries"), + (str_group_settingmenuentriesdesc, "SettingsMenuEntriesDescriptions"), + ]: + max_len = 30 + f.write(f"const uint16_t {name}[] = {{\n") + for item in group: + f.write( + f" /* {item.info.ljust(max_len)[:max_len]} */ {get_offset(item.str_index)}, // {escape(str_table[item.str_index])}\n" + ) + f.write(f"}}; // {name}\n\n") - f.write("};\n\n") f.write( f"const bool HasFahrenheit = {('true' if lang.get('tempUnitFahrenheit', True) else 'false')};\n" ) diff --git a/source/Core/Inc/Translation.h b/source/Core/Inc/Translation.h index 46cdaed2..456ad026 100644 --- a/source/Core/Inc/Translation.h +++ b/source/Core/Inc/Translation.h @@ -12,53 +12,55 @@ extern const uint8_t USER_FONT_12[]; extern const uint8_t USER_FONT_6x8[]; extern const bool HasFahrenheit; -extern const char *SettingsShortNames[]; -extern const char *SettingsDescriptions[]; -extern const char *SettingsMenuEntries[]; +extern const char TranslationStrings[]; -extern const char *SettingsCalibrationWarning; -extern const char *SettingsResetWarning; -extern const char *UVLOWarningString; -extern const char *UndervoltageString; -extern const char *InputVoltageString; +extern const uint16_t SettingsShortNames[]; +extern const uint16_t SettingsDescriptions[]; +extern const uint16_t SettingsMenuEntries[]; -extern const char *SleepingSimpleString; -extern const char *SleepingAdvancedString; -extern const char *SleepingTipAdvancedString; -extern const char *IdleTipString; -extern const char *IdleSetString; -extern const char *TipDisconnectedString; -extern const char *SolderingAdvancedPowerPrompt; -extern const char *OffString; +extern const uint16_t SettingsCalibrationWarning; +extern const uint16_t SettingsResetWarning; +extern const uint16_t UVLOWarningString; +extern const uint16_t UndervoltageString; +extern const uint16_t InputVoltageString; -extern const char *ResetOKMessage; -extern const char *SettingsResetMessage; -extern const char *NoAccelerometerMessage; -extern const char *NoPowerDeliveryMessage; -extern const char *LockingKeysString; -extern const char *UnlockingKeysString; -extern const char *WarningKeysLockedString; +extern const uint16_t SleepingSimpleString; +extern const uint16_t SleepingAdvancedString; +extern const uint16_t SleepingTipAdvancedString; +extern const uint16_t IdleTipString; +extern const uint16_t IdleSetString; +extern const uint16_t TipDisconnectedString; +extern const uint16_t SolderingAdvancedPowerPrompt; +extern const uint16_t OffString; -extern const char *SettingRightChar; -extern const char *SettingLeftChar; -extern const char *SettingAutoChar; -extern const char *SettingStartSolderingChar; -extern const char *SettingStartSleepChar; -extern const char *SettingStartSleepOffChar; -extern const char *SettingStartNoneChar; -extern const char *SettingSensitivityOff; -extern const char *SettingSensitivityLow; -extern const char *SettingSensitivityMedium; -extern const char *SettingSensitivityHigh; -extern const char *SettingLockDisableChar; -extern const char *SettingLockBoostChar; -extern const char *SettingLockFullChar; -extern const char *SettingNAChar; +extern const uint16_t ResetOKMessage; +extern const uint16_t SettingsResetMessage; +extern const uint16_t NoAccelerometerMessage; +extern const uint16_t NoPowerDeliveryMessage; +extern const uint16_t LockingKeysString; +extern const uint16_t UnlockingKeysString; +extern const uint16_t WarningKeysLockedString; -extern const char *SettingOffChar; -extern const char *SettingFastChar; -extern const char *SettingMediumChar; -extern const char *SettingSlowChar; +extern const uint16_t SettingRightChar; +extern const uint16_t SettingLeftChar; +extern const uint16_t SettingAutoChar; +extern const uint16_t SettingStartSolderingChar; +extern const uint16_t SettingStartSleepChar; +extern const uint16_t SettingStartSleepOffChar; +extern const uint16_t SettingStartNoneChar; +extern const uint16_t SettingSensitivityOff; +extern const uint16_t SettingSensitivityLow; +extern const uint16_t SettingSensitivityMedium; +extern const uint16_t SettingSensitivityHigh; +extern const uint16_t SettingLockDisableChar; +extern const uint16_t SettingLockBoostChar; +extern const uint16_t SettingLockFullChar; +extern const uint16_t SettingNAChar; + +extern const uint16_t SettingOffChar; +extern const uint16_t SettingFastChar; +extern const uint16_t SettingMediumChar; +extern const uint16_t SettingSlowChar; extern const char *SymbolPlus; extern const char *SymbolMinus; @@ -112,4 +114,6 @@ constexpr uint8_t settings_item_index(const SettingsItemIndex i) { return static // Use a constexpr function for type-checking. #define SETTINGS_DESC(i) (settings_item_index(i) + 1) +const char *translatedString(uint16_t index); + #endif /* TRANSLATION_H_ */ diff --git a/source/Core/Src/Translation.cpp b/source/Core/Src/Translation.cpp new file mode 100644 index 00000000..e4720f47 --- /dev/null +++ b/source/Core/Src/Translation.cpp @@ -0,0 +1,3 @@ +#include "Translation.h" + +const char *translatedString(uint16_t offset) { return TranslationStrings + offset; } diff --git a/source/Core/Src/gui.cpp b/source/Core/Src/gui.cpp index 9e3a184a..67589d57 100644 --- a/source/Core/Src/gui.cpp +++ b/source/Core/Src/gui.cpp @@ -247,7 +247,7 @@ const menuitem advancedMenu[] = { static void printShortDescription(SettingsItemIndex settingsItemIndex, uint16_t cursorCharPosition) { // print short description (default single line, explicit double line) uint8_t shortDescIndex = static_cast(settingsItemIndex); - OLED::printWholeScreen(SettingsShortNames[shortDescIndex]); + OLED::printWholeScreen(translatedString(SettingsShortNames[shortDescIndex])); // prepare cursor for value // make room for scroll indicator @@ -362,7 +362,7 @@ static bool settings_displayInputMinVRange(void) { OLED::printNumber(systemSettings.minVoltageCells % 10, 1, FontStyle::LARGE); } else { printShortDescription(SettingsItemIndex::MinVolCell, 5); - OLED::print(SettingNAChar, FontStyle::LARGE); + OLED::print(translatedString(SettingNAChar), FontStyle::LARGE); } return false; } @@ -437,7 +437,7 @@ static bool settings_setSleepTime(void) { static bool settings_displaySleepTime(void) { printShortDescription(SettingsItemIndex::SleepTimeout, 5); if (systemSettings.SleepTime == 0) { - OLED::print(OffString, FontStyle::LARGE); + OLED::print(translatedString(OffString), FontStyle::LARGE); } else if (systemSettings.SleepTime < 6) { OLED::printNumber(systemSettings.SleepTime * 10, 2, FontStyle::LARGE); OLED::print(SymbolSeconds, FontStyle::LARGE); @@ -461,7 +461,7 @@ static bool settings_setShutdownTime(void) { static bool settings_displayShutdownTime(void) { printShortDescription(SettingsItemIndex::ShutdownTimeout, 5); if (systemSettings.ShutdownTime == 0) { - OLED::print(OffString, FontStyle::LARGE); + OLED::print(translatedString(OffString), FontStyle::LARGE); } else { OLED::printNumber(systemSettings.ShutdownTime, 2, FontStyle::LARGE); OLED::print(SymbolMinutes, FontStyle::LARGE); @@ -546,7 +546,7 @@ static bool settings_setPowerLimit(void) { static bool settings_displayPowerLimit(void) { printShortDescription(SettingsItemIndex::PowerLimit, 5); if (systemSettings.powerLimit == 0) { - OLED::print(OffString, FontStyle::LARGE); + OLED::print(translatedString(OffString), FontStyle::LARGE); } else { OLED::printNumber(systemSettings.powerLimit, 2, FontStyle::LARGE); OLED::print(SymbolWatts, FontStyle::LARGE); @@ -564,7 +564,7 @@ static bool settings_setScrollSpeed(void) { static bool settings_displayScrollSpeed(void) { printShortDescription(SettingsItemIndex::ScrollingSpeed, 7); - OLED::print((systemSettings.descriptionScrollSpeed) ? SettingFastChar : SettingSlowChar, FontStyle::LARGE); + OLED::print(translatedString((systemSettings.descriptionScrollSpeed) ? SettingFastChar : SettingSlowChar), FontStyle::LARGE); return false; } @@ -592,16 +592,16 @@ static bool settings_displayDisplayRotation(void) { switch (systemSettings.OrientationMode) { case 0: - OLED::print(SettingRightChar, FontStyle::LARGE); + OLED::print(translatedString(SettingRightChar), FontStyle::LARGE); break; case 1: - OLED::print(SettingLeftChar, FontStyle::LARGE); + OLED::print(translatedString(SettingLeftChar), FontStyle::LARGE); break; case 2: - OLED::print(SettingAutoChar, FontStyle::LARGE); + OLED::print(translatedString(SettingAutoChar), FontStyle::LARGE); break; default: - OLED::print(SettingRightChar, FontStyle::LARGE); + OLED::print(translatedString(SettingRightChar), FontStyle::LARGE); break; } return false; @@ -637,7 +637,7 @@ static bool settings_displayBoostTemp(void) { if (systemSettings.BoostTemp) { OLED::printNumber(systemSettings.BoostTemp, 3, FontStyle::LARGE); } else { - OLED::print(OffString, FontStyle::LARGE); + OLED::print(translatedString(OffString), FontStyle::LARGE); } return false; } @@ -653,19 +653,19 @@ static bool settings_displayAutomaticStartMode(void) { switch (systemSettings.autoStartMode) { case 0: - OLED::print(SettingStartNoneChar, FontStyle::LARGE); + OLED::print(translatedString(SettingStartNoneChar), FontStyle::LARGE); break; case 1: - OLED::print(SettingStartSolderingChar, FontStyle::LARGE); + OLED::print(translatedString(SettingStartSolderingChar), FontStyle::LARGE); break; case 2: - OLED::print(SettingStartSleepChar, FontStyle::LARGE); + OLED::print(translatedString(SettingStartSleepChar), FontStyle::LARGE); break; case 3: - OLED::print(SettingStartSleepOffChar, FontStyle::LARGE); + OLED::print(translatedString(SettingStartSleepOffChar), FontStyle::LARGE); break; default: - OLED::print(SettingStartNoneChar, FontStyle::LARGE); + OLED::print(translatedString(SettingStartNoneChar), FontStyle::LARGE); break; } return false; @@ -682,16 +682,16 @@ static bool settings_displayLockingMode(void) { switch (systemSettings.lockingMode) { case 0: - OLED::print(SettingLockDisableChar, FontStyle::LARGE); + OLED::print(translatedString(SettingLockDisableChar), FontStyle::LARGE); break; case 1: - OLED::print(SettingLockBoostChar, FontStyle::LARGE); + OLED::print(translatedString(SettingLockBoostChar), FontStyle::LARGE); break; case 2: - OLED::print(SettingLockFullChar, FontStyle::LARGE); + OLED::print(translatedString(SettingLockFullChar), FontStyle::LARGE); break; default: - OLED::print(SettingLockDisableChar, FontStyle::LARGE); + OLED::print(translatedString(SettingLockDisableChar), FontStyle::LARGE); break; } return false; @@ -709,9 +709,9 @@ static bool settings_displayCoolingBlinkEnabled(void) { } static bool settings_setResetSettings(void) { - if (userConfirmation(SettingsResetWarning)) { + if (userConfirmation(translatedString(SettingsResetWarning))) { resetSettings(); - warnUser(ResetOKMessage, 2 * TICKS_SECOND); + warnUser(translatedString(ResetOKMessage), 2 * TICKS_SECOND); } return false; } @@ -754,7 +754,7 @@ static void setTipOffset() { // If not only do single point tuning as per usual static bool settings_setCalibrate(void) { - if (userConfirmation(SettingsCalibrationWarning)) { + if (userConfirmation(translatedString(SettingsCalibrationWarning))) { // User confirmed // So we now perform the actual calculation setTipOffset(); @@ -881,7 +881,7 @@ static bool settings_displayPowerPulse(void) { OLED::print(SymbolDot, FontStyle::LARGE); OLED::printNumber(systemSettings.KeepAwakePulse % 10, 1, FontStyle::LARGE); } else { - OLED::print(OffString, FontStyle::LARGE); + OLED::print(translatedString(OffString), FontStyle::LARGE); } return false; } @@ -907,16 +907,16 @@ static bool settings_displayAnimationSpeed(void) { printShortDescription(SettingsItemIndex::AnimSpeed, 7); switch (systemSettings.animationSpeed) { case settingOffSpeed_t::SLOW: - OLED::print(SettingSlowChar, FontStyle::LARGE); + OLED::print(translatedString(SettingSlowChar), FontStyle::LARGE); break; case settingOffSpeed_t::MEDIUM: - OLED::print(SettingMediumChar, FontStyle::LARGE); + OLED::print(translatedString(SettingMediumChar), FontStyle::LARGE); break; case settingOffSpeed_t::FAST: - OLED::print(SettingFastChar, FontStyle::LARGE); + OLED::print(translatedString(SettingFastChar), FontStyle::LARGE); break; default: - OLED::print(SettingOffChar, FontStyle::LARGE); + OLED::print(translatedString(SettingOffChar), FontStyle::LARGE); break; } return false; @@ -967,17 +967,17 @@ static bool settings_displayHallEffect(void) { printShortDescription(SettingsItemIndex::HallEffSensitivity, 7); switch (systemSettings.hallEffectSensitivity) { case 1: - OLED::print(SettingSensitivityLow, FontStyle::LARGE); + OLED::print(translatedString(SettingSensitivityLow), FontStyle::LARGE); break; case 2: - OLED::print(SettingSensitivityMedium, FontStyle::LARGE); + OLED::print(translatedString(SettingSensitivityMedium), FontStyle::LARGE); break; case 3: - OLED::print(SettingSensitivityHigh, FontStyle::LARGE); + OLED::print(translatedString(SettingSensitivityHigh), FontStyle::LARGE); break; case 0: default: - OLED::print(SettingSensitivityOff, FontStyle::LARGE); + OLED::print(translatedString(SettingSensitivityOff), FontStyle::LARGE); break; } return false; @@ -996,7 +996,7 @@ static bool animOpenState = false; static void displayMenu(size_t index) { // Call into the menu // Draw title - OLED::printWholeScreen(SettingsMenuEntries[index]); + OLED::printWholeScreen(translatedString(SettingsMenuEntries[index])); // Draw symbol // 16 pixel wide image // 2 pixel wide scrolling indicator @@ -1128,7 +1128,7 @@ void gui_Menu(const menuitem *menu) { // Draw description if (descriptionStart == 0) descriptionStart = xTaskGetTickCount(); - const char *description = SettingsDescriptions[menu[currentScreen].description - 1]; + const char *description = translatedString(SettingsDescriptions[menu[currentScreen].description - 1]); // lower the value - higher the speed int16_t descriptionWidth = FONT_12_WIDTH * (str_display_len(description) + 7); int16_t descriptionOffset = ((xTaskGetTickCount() - descriptionStart) / (systemSettings.descriptionScrollSpeed == 1 ? (TICKS_100MS / 10) : (TICKS_100MS / 5))); diff --git a/source/Core/Threads/GUIThread.cpp b/source/Core/Threads/GUIThread.cpp index b39afb0b..42636786 100644 --- a/source/Core/Threads/GUIThread.cpp +++ b/source/Core/Threads/GUIThread.cpp @@ -107,13 +107,13 @@ static bool checkVoltageForExit() { OLED::clearScreen(); OLED::setCursor(0, 0); if (systemSettings.detailedSoldering) { - OLED::print(UndervoltageString, FontStyle::SMALL); + OLED::print(translatedString(UndervoltageString), FontStyle::SMALL); OLED::setCursor(0, 8); - OLED::print(InputVoltageString, FontStyle::SMALL); + OLED::print(translatedString(InputVoltageString), FontStyle::SMALL); printVoltage(); OLED::print(SymbolVolts, FontStyle::SMALL); } else { - OLED::print(UVLOWarningString, FontStyle::LARGE); + OLED::print(translatedString(UVLOWarningString), FontStyle::LARGE); } OLED::refresh(); @@ -326,9 +326,9 @@ static int gui_SolderingSleepingMode(bool stayOff, bool autoStarted) { OLED::clearScreen(); OLED::setCursor(0, 0); if (systemSettings.detailedSoldering) { - OLED::print(SleepingAdvancedString, FontStyle::SMALL); + OLED::print(translatedString(SleepingAdvancedString), FontStyle::SMALL); OLED::setCursor(0, 8); - OLED::print(SleepingTipAdvancedString, FontStyle::SMALL); + OLED::print(translatedString(SleepingTipAdvancedString), FontStyle::SMALL); OLED::printNumber(tipTemp, 3, FontStyle::SMALL); if (systemSettings.temperatureInF) OLED::print(SymbolDegF, FontStyle::SMALL); @@ -340,7 +340,7 @@ static int gui_SolderingSleepingMode(bool stayOff, bool autoStarted) { printVoltage(); OLED::print(SymbolVolts, FontStyle::SMALL); } else { - OLED::print(SleepingSimpleString, FontStyle::LARGE); + OLED::print(translatedString(SleepingSimpleString), FontStyle::LARGE); OLED::printNumber(tipTemp, 3, FontStyle::LARGE); if (systemSettings.temperatureInF) OLED::drawSymbol(0); @@ -462,7 +462,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) { case BUTTON_BOTH_LONG: // Unlock buttons buttonsLocked = false; - warnUser(UnlockingKeysString, TICKS_SECOND); + warnUser(translatedString(UnlockingKeysString), TICKS_SECOND); break; case BUTTON_F_LONG: // if boost mode is enabled turn it on @@ -476,7 +476,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) { case BUTTON_F_SHORT: case BUTTON_B_SHORT: // Do nothing and display a lock warming - warnUser(WarningKeysLockedString, TICKS_SECOND / 2); + warnUser(translatedString(WarningKeysLockedString), TICKS_SECOND / 2); break; default: break; @@ -511,7 +511,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) { if (systemSettings.lockingMode != 0) { // Lock buttons buttonsLocked = true; - warnUser(LockingKeysString, TICKS_SECOND); + warnUser(translatedString(LockingKeysString), TICKS_SECOND); } break; default: @@ -523,7 +523,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) { OLED::clearScreen(); // Draw in the screen details if (systemSettings.detailedSoldering) { - OLED::print(SolderingAdvancedPowerPrompt, FontStyle::SMALL); // Power: + OLED::print(translatedString(SolderingAdvancedPowerPrompt), FontStyle::SMALL); // Power: OLED::printNumber(x10WattHistory.average() / 10, 2, FontStyle::SMALL); OLED::print(SymbolDot, FontStyle::SMALL); OLED::printNumber(x10WattHistory.average() % 10, 1, FontStyle::SMALL); @@ -535,7 +535,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) { } OLED::setCursor(0, 8); - OLED::print(SleepingTipAdvancedString, FontStyle::SMALL); + OLED::print(translatedString(SleepingTipAdvancedString), FontStyle::SMALL); gui_drawTipTemp(true, FontStyle::SMALL); if (boostModeOn) { @@ -713,7 +713,7 @@ void showDebugMenu(void) { void showWarnings() { // Display alert if settings were reset if (settingsWereReset) { - warnUser(SettingsResetMessage, 10 * TICKS_SECOND); + warnUser(translatedString(SettingsResetMessage), 10 * TICKS_SECOND); } #ifndef NO_WARN_MISSING // We also want to alert if accel or pd is not detected / not responding @@ -727,7 +727,7 @@ void showWarnings() { if (systemSettings.accelMissingWarningCounter < 2) { systemSettings.accelMissingWarningCounter++; saveSettings(); - warnUser(NoAccelerometerMessage, 10 * TICKS_SECOND); + warnUser(translatedString(NoAccelerometerMessage), 10 * TICKS_SECOND); } } #ifdef POW_PD @@ -736,7 +736,7 @@ void showWarnings() { if (systemSettings.pdMissingWarningCounter < 2) { systemSettings.pdMissingWarningCounter++; saveSettings(); - warnUser(NoPowerDeliveryMessage, 10 * TICKS_SECOND); + warnUser(translatedString(NoPowerDeliveryMessage), 10 * TICKS_SECOND); } } #endif @@ -844,16 +844,16 @@ void startGUITask(void const *argument __unused) { OLED::setCursor(0, 0); if (systemSettings.detailedIDLE) { if (tipTemp > tipDisconnectedThres) { - OLED::print(TipDisconnectedString, FontStyle::SMALL); + OLED::print(translatedString(TipDisconnectedString), FontStyle::SMALL); } else { - OLED::print(IdleTipString, FontStyle::SMALL); + OLED::print(translatedString(IdleTipString), FontStyle::SMALL); gui_drawTipTemp(false, FontStyle::SMALL); - OLED::print(IdleSetString, FontStyle::SMALL); + OLED::print(translatedString(IdleSetString), FontStyle::SMALL); OLED::printNumber(systemSettings.SolderingTemp, 3, FontStyle::SMALL); } OLED::setCursor(0, 8); - OLED::print(InputVoltageString, FontStyle::SMALL); + OLED::print(translatedString(InputVoltageString), FontStyle::SMALL); printVoltage(); } else { diff --git a/source/Makefile b/source/Makefile index c0b2c43e..eb988648 100644 --- a/source/Makefile +++ b/source/Makefile @@ -322,7 +322,7 @@ Core/Gen/Translation.%.cpp: ../Translations/translation_%.json Makefile ../Trans @python3 ../Translations/make_translation.py -o $(PWD)/$@ $* clean : - rm -Rf $(SOURCE_CORE_DIR)/Translation.cpp Core/Gen + rm -Rf Core/Gen rm -Rf $(OUTPUT_DIR_BASE) rm -Rf $(HEXFILE_DIR) From 7d6d7d11c08c317b1b4dd7c130cc40cf197a24e0 Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Fri, 9 Apr 2021 17:16:03 +0800 Subject: [PATCH 4/8] Put translation str indices into a struct --- Translations/make_translation.py | 16 +++-- source/Core/Inc/Translation.h | 105 ++++++++++++++++-------------- source/Core/Src/gui.cpp | 68 +++++++++---------- source/Core/Threads/GUIThread.cpp | 36 +++++----- 4 files changed, 119 insertions(+), 106 deletions(-) diff --git a/Translations/make_translation.py b/Translations/make_translation.py index 295c9712..dcb8f7b1 100755 --- a/Translations/make_translation.py +++ b/Translations/make_translation.py @@ -567,11 +567,13 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: assert str_offsets[idx] >= 0 return str_offsets[idx] + f.write("static const TranslationIndexTable TranslationIndices = {\n") + # ----- Write the messages string indices: for group in [str_group_messages, str_group_messageswarn, str_group_characters]: for item in group: f.write( - f"const uint16_t {item.info} = {get_offset(item.str_index)}; // {escape(str_table[item.str_index])}\n" + f" .{item.info} = {get_offset(item.str_index)}, // {escape(str_table[item.str_index])}\n" ) f.write("\n") @@ -583,12 +585,15 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: (str_group_settingmenuentriesdesc, "SettingsMenuEntriesDescriptions"), ]: max_len = 30 - f.write(f"const uint16_t {name}[] = {{\n") + f.write(f" .{name} = {{\n") for item in group: f.write( - f" /* {item.info.ljust(max_len)[:max_len]} */ {get_offset(item.str_index)}, // {escape(str_table[item.str_index])}\n" + f" /* {item.info.ljust(max_len)[:max_len]} */ {get_offset(item.str_index)}, // {escape(str_table[item.str_index])}\n" ) - f.write(f"}}; // {name}\n\n") + f.write(f" }}, // {name}\n\n") + + f.write("}; // TranslationIndices\n\n") + f.write("const TranslationIndexTable *const Tr = &TranslationIndices;\n\n") f.write( f"const bool HasFahrenheit = {('true' if lang.get('tempUnitFahrenheit', True) else 'false')};\n" @@ -600,6 +605,9 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: f.write( f"static_assert(static_cast(SettingsItemIndex::{eid}) == {i});\n" ) + f.write( + f"static_assert(static_cast(SettingsItemIndex::NUM_ITEMS) == {len(defs['menuOptions'])});\n" + ) def read_version() -> str: diff --git a/source/Core/Inc/Translation.h b/source/Core/Inc/Translation.h index 456ad026..feada0fb 100644 --- a/source/Core/Inc/Translation.h +++ b/source/Core/Inc/Translation.h @@ -12,56 +12,6 @@ extern const uint8_t USER_FONT_12[]; extern const uint8_t USER_FONT_6x8[]; extern const bool HasFahrenheit; -extern const char TranslationStrings[]; - -extern const uint16_t SettingsShortNames[]; -extern const uint16_t SettingsDescriptions[]; -extern const uint16_t SettingsMenuEntries[]; - -extern const uint16_t SettingsCalibrationWarning; -extern const uint16_t SettingsResetWarning; -extern const uint16_t UVLOWarningString; -extern const uint16_t UndervoltageString; -extern const uint16_t InputVoltageString; - -extern const uint16_t SleepingSimpleString; -extern const uint16_t SleepingAdvancedString; -extern const uint16_t SleepingTipAdvancedString; -extern const uint16_t IdleTipString; -extern const uint16_t IdleSetString; -extern const uint16_t TipDisconnectedString; -extern const uint16_t SolderingAdvancedPowerPrompt; -extern const uint16_t OffString; - -extern const uint16_t ResetOKMessage; -extern const uint16_t SettingsResetMessage; -extern const uint16_t NoAccelerometerMessage; -extern const uint16_t NoPowerDeliveryMessage; -extern const uint16_t LockingKeysString; -extern const uint16_t UnlockingKeysString; -extern const uint16_t WarningKeysLockedString; - -extern const uint16_t SettingRightChar; -extern const uint16_t SettingLeftChar; -extern const uint16_t SettingAutoChar; -extern const uint16_t SettingStartSolderingChar; -extern const uint16_t SettingStartSleepChar; -extern const uint16_t SettingStartSleepOffChar; -extern const uint16_t SettingStartNoneChar; -extern const uint16_t SettingSensitivityOff; -extern const uint16_t SettingSensitivityLow; -extern const uint16_t SettingSensitivityMedium; -extern const uint16_t SettingSensitivityHigh; -extern const uint16_t SettingLockDisableChar; -extern const uint16_t SettingLockBoostChar; -extern const uint16_t SettingLockFullChar; -extern const uint16_t SettingNAChar; - -extern const uint16_t SettingOffChar; -extern const uint16_t SettingFastChar; -extern const uint16_t SettingMediumChar; -extern const uint16_t SettingSlowChar; - extern const char *SymbolPlus; extern const char *SymbolMinus; extern const char *SymbolSpace; @@ -108,8 +58,63 @@ enum class SettingsItemIndex : uint8_t { AnimSpeed, PowerPulseWait, PowerPulseDuration, + NUM_ITEMS, }; +extern const char TranslationStrings[]; + +struct TranslationIndexTable { + uint16_t SettingsCalibrationWarning; + uint16_t SettingsResetWarning; + uint16_t UVLOWarningString; + uint16_t UndervoltageString; + uint16_t InputVoltageString; + + uint16_t SleepingSimpleString; + uint16_t SleepingAdvancedString; + uint16_t SleepingTipAdvancedString; + uint16_t IdleTipString; + uint16_t IdleSetString; + uint16_t TipDisconnectedString; + uint16_t SolderingAdvancedPowerPrompt; + uint16_t OffString; + + uint16_t ResetOKMessage; + uint16_t SettingsResetMessage; + uint16_t NoAccelerometerMessage; + uint16_t NoPowerDeliveryMessage; + uint16_t LockingKeysString; + uint16_t UnlockingKeysString; + uint16_t WarningKeysLockedString; + + uint16_t SettingRightChar; + uint16_t SettingLeftChar; + uint16_t SettingAutoChar; + uint16_t SettingFastChar; + uint16_t SettingSlowChar; + uint16_t SettingMediumChar; + uint16_t SettingOffChar; + uint16_t SettingStartSolderingChar; + uint16_t SettingStartSleepChar; + uint16_t SettingStartSleepOffChar; + uint16_t SettingStartNoneChar; + uint16_t SettingSensitivityOff; + uint16_t SettingSensitivityLow; + uint16_t SettingSensitivityMedium; + uint16_t SettingSensitivityHigh; + uint16_t SettingLockDisableChar; + uint16_t SettingLockBoostChar; + uint16_t SettingLockFullChar; + uint16_t SettingNAChar; + + uint16_t SettingsDescriptions[static_cast(SettingsItemIndex::NUM_ITEMS)]; + uint16_t SettingsShortNames[static_cast(SettingsItemIndex::NUM_ITEMS)]; + uint16_t SettingsMenuEntries[5]; + uint16_t SettingsMenuEntriesDescriptions[5]; // unused +}; + +extern const TranslationIndexTable *const Tr; + constexpr uint8_t settings_item_index(const SettingsItemIndex i) { return static_cast(i); } // Use a constexpr function for type-checking. #define SETTINGS_DESC(i) (settings_item_index(i) + 1) diff --git a/source/Core/Src/gui.cpp b/source/Core/Src/gui.cpp index 67589d57..583b437c 100644 --- a/source/Core/Src/gui.cpp +++ b/source/Core/Src/gui.cpp @@ -247,7 +247,7 @@ const menuitem advancedMenu[] = { static void printShortDescription(SettingsItemIndex settingsItemIndex, uint16_t cursorCharPosition) { // print short description (default single line, explicit double line) uint8_t shortDescIndex = static_cast(settingsItemIndex); - OLED::printWholeScreen(translatedString(SettingsShortNames[shortDescIndex])); + OLED::printWholeScreen(translatedString(Tr->SettingsShortNames[shortDescIndex])); // prepare cursor for value // make room for scroll indicator @@ -362,7 +362,7 @@ static bool settings_displayInputMinVRange(void) { OLED::printNumber(systemSettings.minVoltageCells % 10, 1, FontStyle::LARGE); } else { printShortDescription(SettingsItemIndex::MinVolCell, 5); - OLED::print(translatedString(SettingNAChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingNAChar), FontStyle::LARGE); } return false; } @@ -437,7 +437,7 @@ static bool settings_setSleepTime(void) { static bool settings_displaySleepTime(void) { printShortDescription(SettingsItemIndex::SleepTimeout, 5); if (systemSettings.SleepTime == 0) { - OLED::print(translatedString(OffString), FontStyle::LARGE); + OLED::print(translatedString(Tr->OffString), FontStyle::LARGE); } else if (systemSettings.SleepTime < 6) { OLED::printNumber(systemSettings.SleepTime * 10, 2, FontStyle::LARGE); OLED::print(SymbolSeconds, FontStyle::LARGE); @@ -461,7 +461,7 @@ static bool settings_setShutdownTime(void) { static bool settings_displayShutdownTime(void) { printShortDescription(SettingsItemIndex::ShutdownTimeout, 5); if (systemSettings.ShutdownTime == 0) { - OLED::print(translatedString(OffString), FontStyle::LARGE); + OLED::print(translatedString(Tr->OffString), FontStyle::LARGE); } else { OLED::printNumber(systemSettings.ShutdownTime, 2, FontStyle::LARGE); OLED::print(SymbolMinutes, FontStyle::LARGE); @@ -546,7 +546,7 @@ static bool settings_setPowerLimit(void) { static bool settings_displayPowerLimit(void) { printShortDescription(SettingsItemIndex::PowerLimit, 5); if (systemSettings.powerLimit == 0) { - OLED::print(translatedString(OffString), FontStyle::LARGE); + OLED::print(translatedString(Tr->OffString), FontStyle::LARGE); } else { OLED::printNumber(systemSettings.powerLimit, 2, FontStyle::LARGE); OLED::print(SymbolWatts, FontStyle::LARGE); @@ -564,7 +564,7 @@ static bool settings_setScrollSpeed(void) { static bool settings_displayScrollSpeed(void) { printShortDescription(SettingsItemIndex::ScrollingSpeed, 7); - OLED::print(translatedString((systemSettings.descriptionScrollSpeed) ? SettingFastChar : SettingSlowChar), FontStyle::LARGE); + OLED::print(translatedString((systemSettings.descriptionScrollSpeed) ? Tr->SettingFastChar : Tr->SettingSlowChar), FontStyle::LARGE); return false; } @@ -592,16 +592,16 @@ static bool settings_displayDisplayRotation(void) { switch (systemSettings.OrientationMode) { case 0: - OLED::print(translatedString(SettingRightChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingRightChar), FontStyle::LARGE); break; case 1: - OLED::print(translatedString(SettingLeftChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingLeftChar), FontStyle::LARGE); break; case 2: - OLED::print(translatedString(SettingAutoChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingAutoChar), FontStyle::LARGE); break; default: - OLED::print(translatedString(SettingRightChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingRightChar), FontStyle::LARGE); break; } return false; @@ -637,7 +637,7 @@ static bool settings_displayBoostTemp(void) { if (systemSettings.BoostTemp) { OLED::printNumber(systemSettings.BoostTemp, 3, FontStyle::LARGE); } else { - OLED::print(translatedString(OffString), FontStyle::LARGE); + OLED::print(translatedString(Tr->OffString), FontStyle::LARGE); } return false; } @@ -653,19 +653,19 @@ static bool settings_displayAutomaticStartMode(void) { switch (systemSettings.autoStartMode) { case 0: - OLED::print(translatedString(SettingStartNoneChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingStartNoneChar), FontStyle::LARGE); break; case 1: - OLED::print(translatedString(SettingStartSolderingChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingStartSolderingChar), FontStyle::LARGE); break; case 2: - OLED::print(translatedString(SettingStartSleepChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingStartSleepChar), FontStyle::LARGE); break; case 3: - OLED::print(translatedString(SettingStartSleepOffChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingStartSleepOffChar), FontStyle::LARGE); break; default: - OLED::print(translatedString(SettingStartNoneChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingStartNoneChar), FontStyle::LARGE); break; } return false; @@ -682,16 +682,16 @@ static bool settings_displayLockingMode(void) { switch (systemSettings.lockingMode) { case 0: - OLED::print(translatedString(SettingLockDisableChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingLockDisableChar), FontStyle::LARGE); break; case 1: - OLED::print(translatedString(SettingLockBoostChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingLockBoostChar), FontStyle::LARGE); break; case 2: - OLED::print(translatedString(SettingLockFullChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingLockFullChar), FontStyle::LARGE); break; default: - OLED::print(translatedString(SettingLockDisableChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingLockDisableChar), FontStyle::LARGE); break; } return false; @@ -709,9 +709,9 @@ static bool settings_displayCoolingBlinkEnabled(void) { } static bool settings_setResetSettings(void) { - if (userConfirmation(translatedString(SettingsResetWarning))) { + if (userConfirmation(translatedString(Tr->SettingsResetWarning))) { resetSettings(); - warnUser(translatedString(ResetOKMessage), 2 * TICKS_SECOND); + warnUser(translatedString(Tr->ResetOKMessage), 2 * TICKS_SECOND); } return false; } @@ -754,7 +754,7 @@ static void setTipOffset() { // If not only do single point tuning as per usual static bool settings_setCalibrate(void) { - if (userConfirmation(translatedString(SettingsCalibrationWarning))) { + if (userConfirmation(translatedString(Tr->SettingsCalibrationWarning))) { // User confirmed // So we now perform the actual calculation setTipOffset(); @@ -881,7 +881,7 @@ static bool settings_displayPowerPulse(void) { OLED::print(SymbolDot, FontStyle::LARGE); OLED::printNumber(systemSettings.KeepAwakePulse % 10, 1, FontStyle::LARGE); } else { - OLED::print(translatedString(OffString), FontStyle::LARGE); + OLED::print(translatedString(Tr->OffString), FontStyle::LARGE); } return false; } @@ -907,16 +907,16 @@ static bool settings_displayAnimationSpeed(void) { printShortDescription(SettingsItemIndex::AnimSpeed, 7); switch (systemSettings.animationSpeed) { case settingOffSpeed_t::SLOW: - OLED::print(translatedString(SettingSlowChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingSlowChar), FontStyle::LARGE); break; case settingOffSpeed_t::MEDIUM: - OLED::print(translatedString(SettingMediumChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingMediumChar), FontStyle::LARGE); break; case settingOffSpeed_t::FAST: - OLED::print(translatedString(SettingFastChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingFastChar), FontStyle::LARGE); break; default: - OLED::print(translatedString(SettingOffChar), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingOffChar), FontStyle::LARGE); break; } return false; @@ -967,17 +967,17 @@ static bool settings_displayHallEffect(void) { printShortDescription(SettingsItemIndex::HallEffSensitivity, 7); switch (systemSettings.hallEffectSensitivity) { case 1: - OLED::print(translatedString(SettingSensitivityLow), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingSensitivityLow), FontStyle::LARGE); break; case 2: - OLED::print(translatedString(SettingSensitivityMedium), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingSensitivityMedium), FontStyle::LARGE); break; case 3: - OLED::print(translatedString(SettingSensitivityHigh), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingSensitivityHigh), FontStyle::LARGE); break; case 0: default: - OLED::print(translatedString(SettingSensitivityOff), FontStyle::LARGE); + OLED::print(translatedString(Tr->SettingSensitivityOff), FontStyle::LARGE); break; } return false; @@ -996,7 +996,7 @@ static bool animOpenState = false; static void displayMenu(size_t index) { // Call into the menu // Draw title - OLED::printWholeScreen(translatedString(SettingsMenuEntries[index])); + OLED::printWholeScreen(translatedString(Tr->SettingsMenuEntries[index])); // Draw symbol // 16 pixel wide image // 2 pixel wide scrolling indicator @@ -1128,7 +1128,7 @@ void gui_Menu(const menuitem *menu) { // Draw description if (descriptionStart == 0) descriptionStart = xTaskGetTickCount(); - const char *description = translatedString(SettingsDescriptions[menu[currentScreen].description - 1]); + const char *description = translatedString(Tr->SettingsDescriptions[menu[currentScreen].description - 1]); // lower the value - higher the speed int16_t descriptionWidth = FONT_12_WIDTH * (str_display_len(description) + 7); int16_t descriptionOffset = ((xTaskGetTickCount() - descriptionStart) / (systemSettings.descriptionScrollSpeed == 1 ? (TICKS_100MS / 10) : (TICKS_100MS / 5))); diff --git a/source/Core/Threads/GUIThread.cpp b/source/Core/Threads/GUIThread.cpp index 42636786..3c72b758 100644 --- a/source/Core/Threads/GUIThread.cpp +++ b/source/Core/Threads/GUIThread.cpp @@ -107,13 +107,13 @@ static bool checkVoltageForExit() { OLED::clearScreen(); OLED::setCursor(0, 0); if (systemSettings.detailedSoldering) { - OLED::print(translatedString(UndervoltageString), FontStyle::SMALL); + OLED::print(translatedString(Tr->UndervoltageString), FontStyle::SMALL); OLED::setCursor(0, 8); - OLED::print(translatedString(InputVoltageString), FontStyle::SMALL); + OLED::print(translatedString(Tr->InputVoltageString), FontStyle::SMALL); printVoltage(); OLED::print(SymbolVolts, FontStyle::SMALL); } else { - OLED::print(translatedString(UVLOWarningString), FontStyle::LARGE); + OLED::print(translatedString(Tr->UVLOWarningString), FontStyle::LARGE); } OLED::refresh(); @@ -326,9 +326,9 @@ static int gui_SolderingSleepingMode(bool stayOff, bool autoStarted) { OLED::clearScreen(); OLED::setCursor(0, 0); if (systemSettings.detailedSoldering) { - OLED::print(translatedString(SleepingAdvancedString), FontStyle::SMALL); + OLED::print(translatedString(Tr->SleepingAdvancedString), FontStyle::SMALL); OLED::setCursor(0, 8); - OLED::print(translatedString(SleepingTipAdvancedString), FontStyle::SMALL); + OLED::print(translatedString(Tr->SleepingTipAdvancedString), FontStyle::SMALL); OLED::printNumber(tipTemp, 3, FontStyle::SMALL); if (systemSettings.temperatureInF) OLED::print(SymbolDegF, FontStyle::SMALL); @@ -340,7 +340,7 @@ static int gui_SolderingSleepingMode(bool stayOff, bool autoStarted) { printVoltage(); OLED::print(SymbolVolts, FontStyle::SMALL); } else { - OLED::print(translatedString(SleepingSimpleString), FontStyle::LARGE); + OLED::print(translatedString(Tr->SleepingSimpleString), FontStyle::LARGE); OLED::printNumber(tipTemp, 3, FontStyle::LARGE); if (systemSettings.temperatureInF) OLED::drawSymbol(0); @@ -462,7 +462,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) { case BUTTON_BOTH_LONG: // Unlock buttons buttonsLocked = false; - warnUser(translatedString(UnlockingKeysString), TICKS_SECOND); + warnUser(translatedString(Tr->UnlockingKeysString), TICKS_SECOND); break; case BUTTON_F_LONG: // if boost mode is enabled turn it on @@ -476,7 +476,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) { case BUTTON_F_SHORT: case BUTTON_B_SHORT: // Do nothing and display a lock warming - warnUser(translatedString(WarningKeysLockedString), TICKS_SECOND / 2); + warnUser(translatedString(Tr->WarningKeysLockedString), TICKS_SECOND / 2); break; default: break; @@ -511,7 +511,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) { if (systemSettings.lockingMode != 0) { // Lock buttons buttonsLocked = true; - warnUser(translatedString(LockingKeysString), TICKS_SECOND); + warnUser(translatedString(Tr->LockingKeysString), TICKS_SECOND); } break; default: @@ -523,7 +523,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) { OLED::clearScreen(); // Draw in the screen details if (systemSettings.detailedSoldering) { - OLED::print(translatedString(SolderingAdvancedPowerPrompt), FontStyle::SMALL); // Power: + OLED::print(translatedString(Tr->SolderingAdvancedPowerPrompt), FontStyle::SMALL); // Power: OLED::printNumber(x10WattHistory.average() / 10, 2, FontStyle::SMALL); OLED::print(SymbolDot, FontStyle::SMALL); OLED::printNumber(x10WattHistory.average() % 10, 1, FontStyle::SMALL); @@ -535,7 +535,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) { } OLED::setCursor(0, 8); - OLED::print(translatedString(SleepingTipAdvancedString), FontStyle::SMALL); + OLED::print(translatedString(Tr->SleepingTipAdvancedString), FontStyle::SMALL); gui_drawTipTemp(true, FontStyle::SMALL); if (boostModeOn) { @@ -713,7 +713,7 @@ void showDebugMenu(void) { void showWarnings() { // Display alert if settings were reset if (settingsWereReset) { - warnUser(translatedString(SettingsResetMessage), 10 * TICKS_SECOND); + warnUser(translatedString(Tr->SettingsResetMessage), 10 * TICKS_SECOND); } #ifndef NO_WARN_MISSING // We also want to alert if accel or pd is not detected / not responding @@ -727,7 +727,7 @@ void showWarnings() { if (systemSettings.accelMissingWarningCounter < 2) { systemSettings.accelMissingWarningCounter++; saveSettings(); - warnUser(translatedString(NoAccelerometerMessage), 10 * TICKS_SECOND); + warnUser(translatedString(Tr->NoAccelerometerMessage), 10 * TICKS_SECOND); } } #ifdef POW_PD @@ -736,7 +736,7 @@ void showWarnings() { if (systemSettings.pdMissingWarningCounter < 2) { systemSettings.pdMissingWarningCounter++; saveSettings(); - warnUser(translatedString(NoPowerDeliveryMessage), 10 * TICKS_SECOND); + warnUser(translatedString(Tr->NoPowerDeliveryMessage), 10 * TICKS_SECOND); } } #endif @@ -844,16 +844,16 @@ void startGUITask(void const *argument __unused) { OLED::setCursor(0, 0); if (systemSettings.detailedIDLE) { if (tipTemp > tipDisconnectedThres) { - OLED::print(translatedString(TipDisconnectedString), FontStyle::SMALL); + OLED::print(translatedString(Tr->TipDisconnectedString), FontStyle::SMALL); } else { - OLED::print(translatedString(IdleTipString), FontStyle::SMALL); + OLED::print(translatedString(Tr->IdleTipString), FontStyle::SMALL); gui_drawTipTemp(false, FontStyle::SMALL); - OLED::print(translatedString(IdleSetString), FontStyle::SMALL); + OLED::print(translatedString(Tr->IdleSetString), FontStyle::SMALL); OLED::printNumber(systemSettings.SolderingTemp, 3, FontStyle::SMALL); } OLED::setCursor(0, 8); - OLED::print(translatedString(InputVoltageString), FontStyle::SMALL); + OLED::print(translatedString(Tr->InputVoltageString), FontStyle::SMALL); printVoltage(); } else { From 880920da96fb8bd5471d2ae5fc67f4a9adeb3acb Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Fri, 9 Apr 2021 22:17:46 +0800 Subject: [PATCH 5/8] Change TranslationStrings to pointer --- Translations/make_translation.py | 7 ++++--- source/Core/Inc/Translation.h | 3 +-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Translations/make_translation.py b/Translations/make_translation.py index dcb8f7b1..6e0b9366 100755 --- a/Translations/make_translation.py +++ b/Translations/make_translation.py @@ -528,7 +528,7 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: str_offsets = [] offset = 0 write_null = False - f.write("const char TranslationStrings[] = {\n") + f.write("const char TranslationStringsData[] = {\n") for i, source_str in enumerate(str_table): if write_null: f.write(' "\\0"\n') @@ -567,7 +567,7 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: assert str_offsets[idx] >= 0 return str_offsets[idx] - f.write("static const TranslationIndexTable TranslationIndices = {\n") + f.write("const TranslationIndexTable TranslationIndices = {\n") # ----- Write the messages string indices: for group in [str_group_messages, str_group_messageswarn, str_group_characters]: @@ -593,7 +593,8 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: f.write(f" }}, // {name}\n\n") f.write("}; // TranslationIndices\n\n") - f.write("const TranslationIndexTable *const Tr = &TranslationIndices;\n\n") + f.write("const TranslationIndexTable *const Tr = &TranslationIndices;\n") + f.write("const char *const TranslationStrings = TranslationStringsData;\n\n") f.write( f"const bool HasFahrenheit = {('true' if lang.get('tempUnitFahrenheit', True) else 'false')};\n" diff --git a/source/Core/Inc/Translation.h b/source/Core/Inc/Translation.h index feada0fb..67277906 100644 --- a/source/Core/Inc/Translation.h +++ b/source/Core/Inc/Translation.h @@ -61,8 +61,6 @@ enum class SettingsItemIndex : uint8_t { NUM_ITEMS, }; -extern const char TranslationStrings[]; - struct TranslationIndexTable { uint16_t SettingsCalibrationWarning; uint16_t SettingsResetWarning; @@ -114,6 +112,7 @@ struct TranslationIndexTable { }; extern const TranslationIndexTable *const Tr; +extern const char *const TranslationStrings; constexpr uint8_t settings_item_index(const SettingsItemIndex i) { return static_cast(i); } // Use a constexpr function for type-checking. From 4061a35b6f783ba28972aea7167591be44738fbb Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Fri, 9 Apr 2021 23:04:38 +0800 Subject: [PATCH 6/8] Refactor make_translation bytes escaping - Change font table to store bytes instead of escape sequences - Add function to convert bytes to escape sequences - Update tests --- Translations/make_translation.py | 46 +++++++++++++++++---------- Translations/make_translation_test.py | 30 ++++++++++------- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/Translations/make_translation.py b/Translations/make_translation.py index 6e0b9366..fefc2fe1 100755 --- a/Translations/make_translation.py +++ b/Translations/make_translation.py @@ -234,10 +234,9 @@ def get_cjk_glyph(sym: str) -> str: return s -def get_chars_from_font_index(index: int) -> str: +def get_bytes_from_font_index(index: int) -> bytes: """ - Converts the font table index into its corresponding string escape - sequence(s). + Converts the font table index into its corresponding bytes """ # We want to be able to use more than 254 symbols (excluding \x00 null @@ -273,7 +272,7 @@ def get_chars_from_font_index(index: int) -> str: if page > 0x0F: raise ValueError("page value out of range") if page == 0: - return f"\\x{index:02X}" + return bytes([index]) else: # Into extended range # Leader is 0xFz where z is the page number @@ -283,13 +282,17 @@ def get_chars_from_font_index(index: int) -> str: if leader > 0xFF or value > 0xFF: raise ValueError("value is out of range") - return f"\\x{leader:02X}\\x{value:02X}" + return bytes([leader, value]) -def get_font_map_and_table(text_list: List[str]) -> Tuple[str, Dict[str, str]]: +def bytes_to_escaped(b: bytes) -> str: + return "".join((f"\\x{i:02X}" for i in b)) + + +def get_font_map_and_table(text_list: List[str]) -> Tuple[str, Dict[str, bytes]]: # the text list is sorted # allocate out these in their order as number codes - symbol_map = {"\n": "\\x01"} + symbol_map: Dict[str, bytes] = {"\n": bytes([1])} index = 2 # start at 2, as 0= null terminator,1 = new line forced_first_symbols = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] @@ -311,7 +314,7 @@ def get_font_map_and_table(text_list: List[str]) -> Tuple[str, Dict[str, str]]: total_symbol_count = len(ordered_normal_sym_list) + len(ordered_cjk_sym_list) # \x00 is for NULL termination and \x01 is for newline, so the maximum # number of symbols allowed is as follow (see also the comments in - # `get_chars_from_font_index`): + # `get_bytes_from_font_index`): if total_symbol_count > (0x10 * 0xFF - 15) - 2: # 4063 logging.error( f"Error, too many used symbols for this version (total {total_symbol_count})" @@ -323,7 +326,7 @@ def get_font_map_and_table(text_list: List[str]) -> Tuple[str, Dict[str, str]]: for sym in chain(ordered_normal_sym_list, ordered_cjk_sym_list): if sym in symbol_map: raise ValueError("Symbol not found in symbol map") - symbol_map[sym] = get_chars_from_font_index(index) + symbol_map[sym] = get_bytes_from_font_index(index) index += 1 font_table_strings = [] @@ -333,12 +336,16 @@ def get_font_map_and_table(text_list: List[str]) -> Tuple[str, Dict[str, str]]: logging.error(f"Missing Large font element for {sym}") sys.exit(1) font_line: str = font_table[sym] - font_table_strings.append(f"{font_line}//{symbol_map[sym]} -> {sym}") + font_table_strings.append( + f"{font_line}//{bytes_to_escaped(symbol_map[sym])} -> {sym}" + ) if sym not in font_small_table: logging.error(f"Missing Small font element for {sym}") sys.exit(1) font_line: str = font_small_table[sym] - font_small_table_strings.append(f"{font_line}//{symbol_map[sym]} -> {sym}") + font_small_table_strings.append( + f"{font_line}//{bytes_to_escaped(symbol_map[sym])} -> {sym}" + ) for sym in ordered_cjk_sym_list: if sym in font_table: @@ -347,10 +354,12 @@ def get_font_map_and_table(text_list: List[str]) -> Tuple[str, Dict[str, str]]: if font_line is None: logging.error(f"Missing Large font element for {sym}") sys.exit(1) - font_table_strings.append(f"{font_line}//{symbol_map[sym]} -> {sym}") + font_table_strings.append( + f"{font_line}//{bytes_to_escaped(symbol_map[sym])} -> {sym}" + ) # No data to add to the small font table font_small_table_strings.append( - f"// {symbol_map[sym]} -> {sym}" + f"// {bytes_to_escaped(symbol_map[sym])} -> {sym}" ) output_table = "const uint8_t USER_FONT_12[] = {\n" @@ -366,9 +375,9 @@ def get_font_map_and_table(text_list: List[str]) -> Tuple[str, Dict[str, str]]: return output_table, symbol_map -def convert_string(symbol_conversion_table: Dict[str, str], text: str) -> str: - # convert all of the symbols from the string into escapes for their content - output_string = "" +def convert_string_bytes(symbol_conversion_table: Dict[str, bytes], text: str) -> bytes: + # convert all of the symbols from the string into bytes for their content + output_string = b"" for c in text.replace("\\r", "").replace("\\n", "\n"): if c not in symbol_conversion_table: logging.error(f"Missing font definition for {c}") @@ -378,6 +387,11 @@ def convert_string(symbol_conversion_table: Dict[str, str], text: str) -> str: return output_string +def convert_string(symbol_conversion_table: Dict[str, bytes], text: str) -> str: + # convert all of the symbols from the string into escapes for their content + return bytes_to_escaped(convert_string_bytes(symbol_conversion_table, text)) + + def escape(string: str) -> str: return json.dumps(string, ensure_ascii=False) diff --git a/Translations/make_translation_test.py b/Translations/make_translation_test.py index ea091fd7..39b6f83b 100644 --- a/Translations/make_translation_test.py +++ b/Translations/make_translation_test.py @@ -3,20 +3,26 @@ import unittest class TestMakeTranslation(unittest.TestCase): - def test_get_chars_from_font_index(self): - from make_translation import get_chars_from_font_index + def test_get_bytes_from_font_index(self): + from make_translation import get_bytes_from_font_index - self.assertEqual(get_chars_from_font_index(2), "\\x02") - self.assertEqual(get_chars_from_font_index(239), "\\xEF") - self.assertEqual(get_chars_from_font_index(240), "\\xF0") - self.assertEqual(get_chars_from_font_index(241), "\\xF1\\x01") - self.assertEqual(get_chars_from_font_index(495), "\\xF1\\xFF") - self.assertEqual(get_chars_from_font_index(496), "\\xF2\\x01") - self.assertEqual(get_chars_from_font_index(750), "\\xF2\\xFF") - self.assertEqual(get_chars_from_font_index(751), "\\xF3\\x01") - self.assertEqual(get_chars_from_font_index(0x10 * 0xFF - 15), "\\xFF\\xFF") + self.assertEqual(get_bytes_from_font_index(2), b"\x02") + self.assertEqual(get_bytes_from_font_index(239), b"\xEF") + self.assertEqual(get_bytes_from_font_index(240), b"\xF0") + self.assertEqual(get_bytes_from_font_index(241), b"\xF1\x01") + self.assertEqual(get_bytes_from_font_index(495), b"\xF1\xFF") + self.assertEqual(get_bytes_from_font_index(496), b"\xF2\x01") + self.assertEqual(get_bytes_from_font_index(750), b"\xF2\xFF") + self.assertEqual(get_bytes_from_font_index(751), b"\xF3\x01") + self.assertEqual(get_bytes_from_font_index(0x10 * 0xFF - 15), b"\xFF\xFF") with self.assertRaises(ValueError): - get_chars_from_font_index(0x10 * 0xFF - 14) + get_bytes_from_font_index(0x10 * 0xFF - 14) + + def test_bytes_to_escaped(self): + from make_translation import bytes_to_escaped + + self.assertEqual(bytes_to_escaped(b"\x00"), "\\x00") + self.assertEqual(bytes_to_escaped(b"\xF1\xAB"), "\\xF1\\xAB") if __name__ == "__main__": From b17e49f54f8faa2715b173b092a3eb7954ce173d Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Sat, 10 Apr 2021 00:44:48 +0800 Subject: [PATCH 7/8] Do suffix merging for translations The size savings are very negligible but I implemented it anyway. --- Translations/make_translation.py | 82 +++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/Translations/make_translation.py b/Translations/make_translation.py index fefc2fe1..d3f2f31a 100755 --- a/Translations/make_translation.py +++ b/Translations/make_translation.py @@ -11,7 +11,7 @@ import sys from datetime import datetime from itertools import chain from pathlib import Path -from typing import Dict, List, TextIO, Tuple, Union +from typing import Dict, List, Optional, TextIO, Tuple, Union from dataclasses import dataclass from bdflib import reader as bdfreader @@ -536,10 +536,38 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: f.write("\n") - # TODO: De-duplicate the strings in str_table. + @dataclass + class RemappedTranslationItem: + str_index: int + str_start_offset: int = 0 + + # ----- Perform suffix merging optimization: + # + # We sort the backward strings so that strings with the same suffix will + # be next to each other, e.g.: + # "ef\0", + # "cdef\0", + # "abcdef\0", + backward_sorted_table: List[Tuple[int, str, bytes]] = sorted( + ( + (i, s, bytes(reversed(convert_string_bytes(symbol_conversion_table, s)))) + for i, s in enumerate(str_table) + ), + key=lambda x: x[2], + ) + str_remapping: List[Optional[RemappedTranslationItem]] = [None] * len(str_table) + for i, (str_index, source_str, converted) in enumerate(backward_sorted_table[:-1]): + j = i + while backward_sorted_table[j + 1][2].startswith(converted): + j += 1 + if j != i: + str_remapping[str_index] = RemappedTranslationItem( + str_index=backward_sorted_table[j][0], + str_start_offset=len(backward_sorted_table[j][2]) - len(converted), + ) # ----- Write the string table: - str_offsets = [] + str_offsets = [-1] * len(str_table) offset = 0 write_null = False f.write("const char TranslationStringsData[] = {\n") @@ -547,29 +575,39 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: if write_null: f.write(' "\\0"\n') write_null = True - # Find what items use this string - is_used = False - for group, pre_info in [ - (str_group_messages, "messages"), - (str_group_messageswarn, "messagesWarn"), - (str_group_characters, "characters"), - (str_group_settingdesc, "SettingsDescriptions"), - (str_group_settingshortnames, "SettingsShortNames"), - (str_group_settingmenuentries, "SettingsMenuEntries"), - (str_group_settingmenuentriesdesc, "SettingsMenuEntriesDescriptions"), - ]: - for item in group: - if item.str_index == i: - is_used = True - f.write(f" // - {pre_info} {item.info}\n") - if not is_used: - str_offsets.append(-1) + if str_remapping[i] is not None: write_null = False continue - f.write(f" // {offset: >4}: {escape(source_str)}\n") + # Find what items use this string + str_used_by = [i] + [ + j for j, r in enumerate(str_remapping) if r and r.str_index == i + ] + for j in str_used_by: + for group, pre_info in [ + (str_group_messages, "messages"), + (str_group_messageswarn, "messagesWarn"), + (str_group_characters, "characters"), + (str_group_settingdesc, "SettingsDescriptions"), + (str_group_settingshortnames, "SettingsShortNames"), + (str_group_settingmenuentries, "SettingsMenuEntries"), + (str_group_settingmenuentriesdesc, "SettingsMenuEntriesDescriptions"), + ]: + for item in group: + if item.str_index == j: + f.write(f" // - {pre_info} {item.info}\n") + if j == i: + f.write(f" // {offset: >4}: {escape(source_str)}\n") + str_offsets[j] = offset + else: + remapped = str_remapping[j] + assert remapped is not None + f.write( + f" // {offset + remapped.str_start_offset: >4}: {escape(str_table[j])}\n" + ) + str_offsets[j] = offset + remapped.str_start_offset converted_str = convert_string(symbol_conversion_table, source_str) f.write(f' "{converted_str}"') - str_offsets.append(offset) + str_offsets[i] = offset # Sanity check: Each "char" in `converted_str` should be in format # `\xFF`, so the length should be divisible by 4. assert len(converted_str) % 4 == 0 From f86629657a37f5729c90d16f0994ae4bba736b86 Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Sat, 10 Apr 2021 02:24:25 +0800 Subject: [PATCH 8/8] Fix python type hints (Checked using mypy) --- Translations/make_translation.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Translations/make_translation.py b/Translations/make_translation.py index d3f2f31a..296fc9a3 100755 --- a/Translations/make_translation.py +++ b/Translations/make_translation.py @@ -79,7 +79,7 @@ def write_start(f: TextIO): f.write('#include "Translation.h"\n') -def get_constants() -> List[str]: +def get_constants() -> List[Tuple[str, str]]: # Extra constants that are used in the firmware that are shared across all languages return [ ("SymbolPlus", "+"), @@ -183,9 +183,10 @@ def get_letter_counts(defs: dict, lang: dict) -> List[str]: if line: for letter in line: symbol_counts[letter] = symbol_counts.get(letter, 0) + 1 - symbols_by_occurrence = sorted(symbol_counts.items(), key=lambda kv: (kv[1], kv[0])) # swap to Big -> little sort order - symbols_by_occurrence = [x[0] for x in symbols_by_occurrence] + symbols_by_occurrence = [ + x[0] for x in sorted(symbol_counts.items(), key=lambda kv: (kv[1], kv[0])) + ] symbols_by_occurrence.reverse() return symbols_by_occurrence @@ -342,7 +343,7 @@ def get_font_map_and_table(text_list: List[str]) -> Tuple[str, Dict[str, bytes]] if sym not in font_small_table: logging.error(f"Missing Small font element for {sym}") sys.exit(1) - font_line: str = font_small_table[sym] + font_line = font_small_table[sym] font_small_table_strings.append( f"{font_line}//{bytes_to_escaped(symbol_map[sym])} -> {sym}" ) @@ -428,6 +429,8 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: str_group_settingmenuentries: List[TranslationItem] = [] str_group_settingmenuentriesdesc: List[TranslationItem] = [] + eid: str + # ----- Reading SettingsDescriptions obj = lang["menuOptions"] @@ -471,7 +474,7 @@ def write_language(lang: dict, defs: dict, f: TextIO) -> None: obj = lang["characters"] for mod in defs["characters"]: - eid: str = mod["id"] + eid = mod["id"] str_group_characters.append(TranslationItem(eid, len(str_table))) str_table.append(obj[eid]) @@ -667,9 +670,9 @@ def read_version() -> str: with open(HERE.parent / "source" / "version.h") as version_file: for line in version_file: if re.findall(r"^.*(?<=(#define)).*(?<=(BUILD_VERSION))", line): - line = re.findall(r"\"(.+?)\"", line) - if line: - version = line[0] + matches = re.findall(r"\"(.+?)\"", line) + if matches: + version = matches[0] try: version += f".{subprocess.check_output(['git', 'rev-parse', '--short=7', 'HEAD']).strip().decode('ascii').upper()}" # --short=7: the shorted hash with 7 digits. Increase/decrease if needed!