build.shPF-build.sh with a parameter -c 1 to keep lang build files after compilinglang folderconfig.sh
Arduino main folder: NG message change in config.sh export ARDUINO=C:/arduino-1.8.5 to export ARDUINO=<Path to your Arduino IDE folder>
-example: export ARDUINO=D:/Github/Prusa-Firmware/PF-build-env-1.0.6/windows-64lang-build.sh en to create english lang_en.tmp, lang_en.dat and lang_en.bin filesfw-build.sh IGNORE_MISSING_TEXT=1 to IGNORE_MISSING_TEXT=0 so it stops with error and generates not_used<variant>.txt and not_tran<variant>.txtfw-build.sh
not_tran<variant>.txt should be reviewed and added as these are potential missing translationsnot_tran<variant>.txt as lang_add.txt
spaces as the scripts doesn't handle these well at this moment.lang-add.sh lang_add.txt to add the missing translations to lang_en.txt and lang_en_??.txtnot_used<variant>.txt should only contain messages that aren't used in this variant like MK2.5/S vs MK3/Sfw-clean.sh to cleanup firmware related filesnot_used<variant>.txt and not_tran<variant>.txtlang-clean.sh to cleanup language related fileslang-export.sh all to create PO files for translation these are stored in /lang/po folder
/lang/po/new andValidatein POEdit as it shows you errors and the missing translations / most likely the newly added at the top./lang/po/new folder so store the received files theselang-import.sh <language code (iso639-1)> for each newly translated language
PF-build.sh -v all -n 1 -c 1 to compile for all variants filesnot_tran<variant>.txt that need attentionfw-clean.sh to cleanup firmware related fileslang-clean.sh to cleanup language related filesfw-build.sh back to IGNORE_MISSING_TEXT=1build.sh, PF-build.sh or how you normally do it.There are 2 modes of operation. If LANG_MODE==0, only one language is being used (the default compilation approach from plain Arduino IDE).
The reset of this explanation is devoted to LANG_MODE==1:
language.h:
// section .loc_sec (originally .progmem0) will be used for localized translated strings
#define PROGMEM_I2 __attribute__((section(".loc_sec")))
// section .loc_pri (originally .progmem1) will be used for localized strings in english
#define PROGMEM_I1 __attribute__((section(".loc_pri")))
// section .noloc (originally progmem2) will be used for not localized strings in english
#define PROGMEM_N1 __attribute__((section(".noloc")))
#define _I(s) (__extension__({static const char __c[] PROGMEM_I1 = "\xff\xff" s; &__c[0];}))
#define ISTR(s) "\xff\xff" s
#define _i(s) lang_get_translation(_I(s))
#define _T(s) lang_get_translation(s)
That explains the macros:
_i expands into lang_get_translation((__extension__({static const char __c[] PROGMEM_I1 = "\xff\xff" s; &__c[0];}))) . Note the two 0xff's in the beginning of the string. _i allows for declaring a string directly in-place of C++ code, no string table is used. The downside of this approach is obvious - the compiler is not able/willing to merge duplicate strings into one._T expands into lang_get_translation(s) without the two 0xff's at the beginning. Must be used in conjunction with MSG tables in messages.h. Allows to declare a string only once and use many times._N means not-translated. These strings reside in a different segment of memory.The two 0xff's are somehow magically replaced by real string ID's where the translations are available (still don't know where).
const char* lang_get_translation(const char* s){
if (lang_selected == 0) return s + 2; //primary language selected, return orig. str.
if (lang_table == 0) return s + 2; //sec. lang table not found, return orig. str.
uint16_t ui = pgm_read_word(((uint16_t*)s)); //read string id
if (ui == 0xffff) return s + 2; //translation not found, return orig. str.
ui = pgm_read_word(((uint16_t*)(((char*)lang_table + 16 + ui*2)))); //read relative offset
if (pgm_read_byte(((uint8_t*)((char*)lang_table + ui))) == 0) //read first character
return s + 2;//zero length string == not translated, return orig. str.
return (const char*)((char*)lang_table + ui); //return calculated pointer
}
lang_en.txt#MSG_CRASH_DET_ONLY_IN_NORMAL c=20 r=4
"Crash detection can\x0abe turned on only in\x0aNormal mode"
lang_en_*.txt#MSG_CRASH_DET_ONLY_IN_NORMAL c=20 r=4
"Crash detection can\x0abe turned on only in\x0aNormal mode"
"Crash detekce muze\x0abyt zapnuta pouze v\x0aNormal modu"
not_tran.txtA simple list of strings that are not translated yet.
not_used.txtA list os strings not currently used in this variant of the firmware or are obsolete. Example: There are MK2.5 specific messages that aren't used when you compile a MK3 variant and vice versa. So be careful and double check the code if this message is obsolete or just not used due to the chosen variant.
config.shARDUINO. If not found/empty, a default C:/arduino-1.8.5 is used.CONFIG_OK=1 when all good, otherwise sets CONFIG_OK=0fw-build.shJoins firmware HEX and language binaries into one file.
fw-clean.shlang-add.shAdds new messages into the dictionary regardless of whether there have been any older versions.
lang-build.shGenerates lang_xx.bin (language binary files) for the whole firmware build.
Arguments:
$1 : language code (en, cz, de, es, fr, it, pl) or allallInput: lang_en.txt or lang_en_xx.txt
Output: lang_xx.bin
Temporary files: lang_xx.tmp and lang_xx.dat
Description of the process:
The script first runs lang-check.py $1 and removes empty lines and comments (and non-translated texts) into lang_$1.tmp.
The tmp file now contains all translated texts (some of them empty, i.e. "").
The tmp file is then transformed into lang_$1.dat, which is a simple dump of all texts together, each terminated with a \x00.
Format of the bin file:
A5 5AB4 4Ben converted into ne, i.e. characters swapped. Only cz is changed into sc (old cs ISO code).\x00The signature is composed of 2B number of strings and 2B checksum in lang_en.bin. Signature in lang_en.bin is zero.
lang-check.sh and lang-check.pyBoth do the same, only lang-check.py is newer, i.e. lang-check.sh is not used anymore. lang-check.py makes a binary comparison between what's in the dictionary and what's in the binary.
lang-clean.shRemoves all language output files from lang folder. That means deleting:
lang-export.shExports PO (gettext) for external translators.
lang-import.shImport from PO.
Arguments:
$1 : language code (en, cz, de, es, fr, it, pl)Input files: <language code>.po files like de.po, es.po, etc.
Input folder: ´/lang/po/new´
Output files:
Output foler: ´/lang/po/new´
Needed improvements to scripts:
all argumentreplace in <language> translations to all known special characters the LCD display with Japanese ROM cannot displaylang_en_<language code>.txt to folder /lang<language code>_filtered.po, <language code>_new.po and nonasci.txtprogmem.shExamine content of progmem sections (default is progmem1).
Input:
Outputs:
Description of process:
\x0atextaddr.shCompiles progmem1.var and lang_en.txt files to textaddr.txt file (mapping of progmem addresses to text identifiers).
Description of process:
Input:
Output:
update_lang.sh