فهرست منبع

Merge pull request #2221 from DRracer/translations-doc

Doc. of the lang. translation process + code docs
DRracer 5 سال پیش
والد
کامیت
a2703510ac
3فایلهای تغییر یافته به همراه669 افزوده شده و 151 حذف شده
  1. 360 122
      Firmware/ultralcd.cpp
  2. 57 29
      lang/lang-import.sh
  3. 252 0
      lang/translations.md

+ 360 - 122
Firmware/ultralcd.cpp

@@ -1,4 +1,7 @@
 //! @file
+//! @date Aug 28, 2019
+//! @author mkbel
+//! @brief LCD
 
 #include "temperature.h"
 #include "ultralcd.h"
@@ -857,18 +860,23 @@ void lcdui_print_status_line(void)
 			lcd_print(' ');
 }
 
+//! @brief Show Status Screen
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |N 000/000D  Z000.0  |
+//! |B 000/000D  F100%   |
+//! |USB100% T0  t--:--  |
+//! |Status line.........|
+//! ----------------------
+//! N - nozzle temp symbol	LCD_STR_THERMOMETER
+//! D - Degree sysmbol		LCD_STR_DEGREE
+//! B - bed temp symbol 	LCD_STR_BEDTEMP
+//! F - feedrate symbol 	LCD_STR_FEEDRATE
+//! t - clock symbol 		LCD_STR_THERMOMETER
+//! @endcode
 void lcdui_print_status_screen(void)
 {
-//|01234567890123456789|
-//|N 000/000D  Z000.0  |
-//|B 000/000D  F100%   |
-//|USB100% T0  t--:--  |
-//|Status line.........|
-//----------------------
-//N - nozzle temp symbol LCD_STR_THERMOMETER
-//B - bed temp symbol LCD_STR_BEDTEMP
-//F - feedrate symbol LCD_STR_FEEDRATE
-//t - clock symbol LCD_STR_THERMOMETER
 
     lcd_set_cursor(0, 0); //line 0
 
@@ -1692,22 +1700,27 @@ static void pgmtext_with_colon(const char *ipgmLabel, char *dst, uint8_t dstSize
     dst[dstSize-1] = '\0';      // terminate the string properly
 }
 
+//! @brief Show Extruder Info
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |Nozzle FAN: 0000 RPM|	FAN c=10 r=1  SPEED c=3 r=1
+//! |Print FAN:  0000 RPM|	FAN c=10 r=1  SPEED c=3 r=1
+//! |Fil. Xd:000 Yd:000  |	Fil. c=4 r=1
+//! |Int:  000 Shut: 000 |	Int: c=4 r=1  Shut: c=4 r=1
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 void lcd_menu_extruder_info()                     // NOT static due to using inside "Marlin_main" module ("manage_inactivity()")
 {
-//|01234567890123456789|
-//|Nozzle FAN:      RPM|
-//|Print FAN:       RPM|
-//|Fil. Xd:    Yd:     |
-//|Int:      Shut:     |
-//----------------------
 
     // Display Nozzle fan RPM
     lcd_timeoutToStatus.stop(); //infinite timeout
     lcd_home();
     static const size_t maxChars = 12;
     char nozzle[maxChars], print[maxChars];
-    pgmtext_with_colon(_i("Nozzle FAN"), nozzle, maxChars);
-    pgmtext_with_colon(_i("Print FAN"), print, maxChars);
+    pgmtext_with_colon(_i("Nozzle FAN"), nozzle, maxChars);  ////c=10 r=1
+    pgmtext_with_colon(_i("Print FAN"), print, maxChars);  ////c=10 r=1
     lcd_printf_P(_N("%s %4d RPM\n" "%s %4d RPM\n"), nozzle, 60*fan_speed[0], print, 60*fan_speed[1] ); 
 
 #ifdef PAT9125
@@ -1728,8 +1741,9 @@ void lcd_menu_extruder_info()                     // NOT static due to using ins
 			if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal))
 				pat9125_update();
 			lcd_printf_P(_N(
-				"Fil. Xd:%3d Yd:%3d\n"
-				"Int: %3d  Shut: %3d"
+				"Fil. Xd:%3d Yd:%3d\n" ////c=4 r=1
+				"Int: %3d  " ////c=4 r=1
+				"Shut: %3d"  ////c=4 r=1
 			),
 				pat9125_x, pat9125_y,
 				pat9125_b, pat9125_s
@@ -1741,125 +1755,183 @@ void lcd_menu_extruder_info()                     // NOT static due to using ins
     menu_back_if_clicked();
 }
 
+//! @brief Show Fails Statistics MMU
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! | Main               |	c=18 r=1
+//! | Last print         |	c=18 r=1
+//! | Total              |	c=18 r=1
+//! |                    |
+//! ----------------------
+//! @endcode
 static void lcd_menu_fails_stats_mmu()
 {
 	MENU_BEGIN();
 	MENU_ITEM_BACK_P(_T(MSG_MAIN));
-	MENU_ITEM_SUBMENU_P(_i("Last print"), lcd_menu_fails_stats_mmu_print);
-	MENU_ITEM_SUBMENU_P(_i("Total"), lcd_menu_fails_stats_mmu_total);
+	MENU_ITEM_SUBMENU_P(_i("Last print"), lcd_menu_fails_stats_mmu_print); ////c=18 r=1
+	MENU_ITEM_SUBMENU_P(_i("Total"), lcd_menu_fails_stats_mmu_total); ////c=18 r=1
 	MENU_END();
 }
 
+//! @brief Show Last Print Failures Statistics MMU
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |Last print failures |	c=20 r=1
+//! | MMU fails:      000|	c=14 r=1
+//! | MMU load fails: 000|	c=14 r=1
+//! |                    |
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_fails_stats_mmu_print()
 {
-//01234567890123456789
-//Last print failures
-// MMU fails  000
-// MMU load fails  000
-//
-//////////////////////
-    lcd_timeoutToStatus.stop(); //infinite timeout
+	lcd_timeoutToStatus.stop(); //infinite timeout
     uint8_t fails = eeprom_read_byte((uint8_t*)EEPROM_MMU_FAIL);
     uint16_t load_fails = eeprom_read_byte((uint8_t*)EEPROM_MMU_LOAD_FAIL);
     lcd_home();
-    lcd_printf_P(PSTR("%S\n" " %-16.16S%-3d\n" " %-16.16S%-3d"), _i("Last print failures"), _i("MMU fails"), fails, _i("MMU load fails"), load_fails);
+    lcd_printf_P(PSTR("%S\n" " %-16.16S%-3d\n" " %-16.16S%-3d"), 
+        _i("Last print failures"), ////c=20 r=1
+        _i("MMU fails"), fails, ////c=14 r=1
+        _i("MMU load fails"), load_fails); ////c=14 r=1
     menu_back_if_clicked_fb();
 }
 
+//! @brief Show Total Failures Statistics MMU
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |Total failures      |	c=20 r=1
+//! | MMU fails:      000|	c=14 r=1
+//! | MMU load fails: 000|	c=14 r=1
+//! | MMU power fails:000|	c=14 r=1
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_fails_stats_mmu_total()
 {
-//01234567890123456789
-//Last print failures
-// MMU fails  000
-// MMU load fails  000
-//
-//////////////////////
-    mmu_command(MmuCmd::S3);
-    lcd_timeoutToStatus.stop(); //infinite timeout
+	mmu_command(MmuCmd::S3);
+	lcd_timeoutToStatus.stop(); //infinite timeout
     uint8_t fails = eeprom_read_byte((uint8_t*)EEPROM_MMU_FAIL_TOT);
     uint16_t load_fails = eeprom_read_byte((uint8_t*)EEPROM_MMU_LOAD_FAIL_TOT);
     lcd_home();
-    lcd_printf_P(PSTR("%S\n" " %-16.16S%-3d\n" " %-16.16S%-3d\n" " %-16.16S%-3d"), _i("Total failures"), _i("MMU fails"), fails, _i("MMU load fails"), load_fails, _i("MMU power fails"), mmu_power_failures);
+    lcd_printf_P(PSTR("%S\n" " %-16.16S%-3d\n" " %-16.16S%-3d\n" " %-16.16S%-3d"), 
+        _i("Total failures"), ////c=20 r=1
+        _i("MMU fails"), fails, ////c=14 r=1
+        _i("MMU load fails"), load_fails, ////c=14 r=1
+        _i("MMU power fails"), mmu_power_failures); ////c=14 r=1
     menu_back_if_clicked_fb();
 }
 
 #if defined(TMC2130) && defined(FILAMENT_SENSOR)
 static const char failStatsFmt[] PROGMEM = "%S\n" " %-16.16S%-3d\n" " %-16.16S%-3d\n" " %-7.7SX %-3d  Y %-3d";
+
+//! @brief Show Total Failures Statistics MMU
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |Total failures      |	c=20 r=1
+//! | Power failures: 000|	c=14 r=1
+//! | Filam. runouts: 000|	c=14 r=1
+//! | Crash   X:000 Y:000|	c=7 r=1
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_fails_stats_total()
 {
-//01234567890123456789
-//Total failures
-// Power failures  000
-// Filam. runouts  000
-// Crash  X 000  Y 000
-//////////////////////
-    lcd_timeoutToStatus.stop(); //infinite timeout
+	lcd_timeoutToStatus.stop(); //infinite timeout
     uint16_t power = eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT);
     uint16_t filam = eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT);
     uint16_t crashX = eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT);
     uint16_t crashY = eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT);
     lcd_home();
-    lcd_printf_P(failStatsFmt, _i("Total failures"), _i("Power failures"), power, _i("Filam. runouts"), filam, _i("Crash"), crashX, crashY);
+    lcd_printf_P(failStatsFmt, 
+        _i("Total failures"),   ////c=20 r=1
+        _i("Power failures"), power,   ////c=14 r=1
+        _i("Filam. runouts"), filam,   ////c=14 r=1
+        _i("Crash"), crashX, crashY);  ////c=7 r=1
     menu_back_if_clicked_fb();
 }
 
+//! @brief Show Last Print Failures Statistics
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |Last print failures |	c=20 r=1
+//! | Power failures: 000|	c=14 r=1
+//! | Filam. runouts: 000|	c=14 r=1
+//! | Crash   X:000 Y:000|	c=7 r=1
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_fails_stats_print()
 {
-//01234567890123456789
-//Last print failures
-// Power failures  000
-// Filam. runouts  000
-// Crash  X 000  Y 000
-//////////////////////
-    lcd_timeoutToStatus.stop(); //infinite timeout
+	lcd_timeoutToStatus.stop(); //infinite timeout
     uint8_t power = eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT);
     uint8_t filam = eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT);
     uint8_t crashX = eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_X);
     uint8_t crashY = eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_Y);
     lcd_home();
-    lcd_printf_P(failStatsFmt, _i("Last print failures"), _i("Power failures"), power, _i("Filam. runouts"), filam, _i("Crash"), crashX, crashY);
+    lcd_printf_P(failStatsFmt,
+        _i("Last print failures"),  ////c=20 r=1
+        _i("Power failures"), power,  ////c=14 r=1
+        _i("Filam. runouts"), filam,  ////c=14 r=1
+        _i("Crash"), crashX, crashY);  ////c=7 r=1
     menu_back_if_clicked_fb();
 }
 
-/**
- * @brief Open fail statistics menu
- *
- * This version of function is used, when there is filament sensor,
- * power failure and crash detection.
- * There are Last print and Total menu items.
- */
+//! @brief Open fail statistics menu
+//! 
+//! This version of function is used, when there is filament sensor,
+//! power failure and crash detection.
+//! There are Last print and Total menu items.
+//! 
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! | Main               |	c=18 r=1
+//! | Last print         |	c=18 r=1
+//! | Total              |	c=18 r=1
+//! |                    |
+//! ----------------------
+//! @endcode
+
 static void lcd_menu_fails_stats()
 {
 	MENU_BEGIN();
 	MENU_ITEM_BACK_P(_T(MSG_MAIN));
-	MENU_ITEM_SUBMENU_P(_i("Last print"), lcd_menu_fails_stats_print);
-	MENU_ITEM_SUBMENU_P(_i("Total"), lcd_menu_fails_stats_total);
+	MENU_ITEM_SUBMENU_P(_i("Last print"), lcd_menu_fails_stats_print);  ////c=18 r=1
+	MENU_ITEM_SUBMENU_P(_i("Total"), lcd_menu_fails_stats_total);  ////c=18 r=1
 	MENU_END();
 }
 
 #elif defined(FILAMENT_SENSOR)
-/**
- * @brief Print last print and total filament run outs
- *
- * This version of function is used, when there is filament sensor,
- * but no other sensors (e.g. power failure, crash detection).
- *
- * Example screen:
- * @code
- * 01234567890123456789
- * Last print failures
- *  Filam. runouts  0
- * Total failures
- *  Filam. runouts  5
- * @endcode
- */
+//! 
+//! @brief Print last print and total filament run outs
+//! 
+//! This version of function is used, when there is filament sensor,
+//! but no other sensors (e.g. power failure, crash detection).
+//! 
+//! Example screen:
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |Last print failures |	c=20 r=1
+//! | Filam. runouts: 000|	c=14 r=1
+//! |Total failures      |	c=20 r=1
+//! | Filam. runouts: 000|	c=14 r=1
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_fails_stats()
 {
 	lcd_timeoutToStatus.stop(); //infinite timeout
     uint8_t filamentLast = eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT);
     uint16_t filamentTotal = eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT);
 	lcd_home();
-    lcd_printf_P(PSTR("Last print failures\n" " Filam. runouts  %-3d\n" "Total failures\n" " Filam. runouts  %-3d"), filamentLast, filamentTotal);
+    lcd_printf_P(PSTR("Last print failures\n"  ////c=20 r=1 
+        " Filam. runouts  %-3d\n"   ////c=14 r=1
+        "Total failures\n"  ////c=20 r=1
+        " Filam. runouts  %-3d"), filamentLast, filamentTotal);  ////c=14 r=1
     menu_back_if_clicked();
 }
 #else
@@ -1880,11 +1952,25 @@ extern char* __malloc_heap_start;
 extern char* __malloc_heap_end;
 #endif //DEBUG_STACK_MONITOR
 
+//! @brief Show Debug Information
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |RAM statistics      |	c=20 r=1
+//! | SP_min:        0000|	c=14 r=1
+//! | heap_start:    0000|	c=14 r=1
+//! | heap_end:      0000|	c=14 r=1
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_debug()
 {
 #ifdef DEBUG_STACK_MONITOR
 	lcd_home();
-	lcd_printf_P(PSTR("RAM statistics\n" " SP_min: 0x%04x\n" " heap_start: 0x%04x\n" " heap_end: 0x%04x"), SP_min, __malloc_heap_start, __malloc_heap_end);
+	lcd_printf_P(PSTR("RAM statistics\n"  ////c=20 r=1
+        " SP_min: 0x%04x\n"   ////c=14 r=1
+        " heap_start: 0x%04x\n"   ////c=14 r=1
+        " heap_end: 0x%04x"), SP_min, __malloc_heap_start, __malloc_heap_end);  ////c=14 r=1
 #endif //DEBUG_STACK_MONITOR
 
 	menu_back_if_clicked_fb();
@@ -1900,16 +1986,29 @@ static void lcd_menu_temperatures_line(const char *ipgmLabel, int value){
     pgmtext_with_colon(ipgmLabel, tmp, maxChars);
     lcd_printf_P(PSTR(" %s%3d\x01 \n"), tmp, value); // no need to add -14.14 to string alignment
 }
+
+//! @brief Show Temperatures
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! | Nozzle:        000D|	c=14 r=1
+//! | Bed:           000D|	c=14 r=1
+//! | Ambient:       000D|	c=14 r=1
+//! | PINDA:         000D|	c=14 r=1
+//! ----------------------
+//! D - Degree sysmbol		LCD_STR_DEGREE
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_temperatures()
 {
     lcd_timeoutToStatus.stop(); //infinite timeout
     lcd_home();
-    lcd_menu_temperatures_line( _T(MSG_NOZZLE), (int)current_temperature[0] );
-    lcd_menu_temperatures_line( _T(MSG_BED), (int)current_temperature_bed );
+    lcd_menu_temperatures_line( _T(MSG_NOZZLE), (int)current_temperature[0] ); ////c=14 r=1
+    lcd_menu_temperatures_line( _T(MSG_BED), (int)current_temperature_bed );  ////c=14 r=1
 #ifdef AMBIENT_THERMISTOR
-    lcd_menu_temperatures_line( _i("Ambient"), (int)current_temperature_ambient );
+    lcd_menu_temperatures_line( _i("Ambient"), (int)current_temperature_ambient );  ////c=14 r=1
 #endif
-    lcd_menu_temperatures_line( _i("PINDA"), (int)current_temperature_pinda );
+    lcd_menu_temperatures_line( _i("PINDA"), (int)current_temperature_pinda );  ////c=14 r=1
 
 
     menu_back_if_clicked();
@@ -1920,6 +2019,17 @@ static void lcd_menu_temperatures()
 #define VOLT_DIV_R2 2370
 #define VOLT_DIV_FAC ((float)VOLT_DIV_R2 / (VOLT_DIV_R2 + VOLT_DIV_R1))
 #define VOLT_DIV_REF 5
+//! @brief Show Voltages
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |                    |
+//! | PWR:         00.0V |	c=12 r=1
+//! | Bed:         00.0V |	c=12 r=1
+//! |                    |
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_voltages()
 {
 	lcd_timeoutToStatus.stop(); //infinite timeout
@@ -1932,6 +2042,17 @@ static void lcd_menu_voltages()
 #endif //defined VOLT_BED_PIN || defined VOLT_PWR_PIN
 
 #ifdef TMC2130
+//! @brief Show Belt Status
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! | Belt status        |	c=18 r=1
+//! |  X:            000 |
+//! |  Y:            000 |
+//! |                    |
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_belt_status()
 {
 	lcd_home();
@@ -1955,12 +2076,85 @@ static void lcd_menu_test_restore()
 }
 #endif //RESUME_DEBUG 
 
+//! @brief Show Preheat Menu
 static void lcd_preheat_menu()
 {
     eFilamentAction = FilamentAction::Preheat;
     mFilamentMenu();
 }
 
+//! @brief Show Support Menu
+//!
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! | Main               |
+//! | Firmware:          |	c=18 r=1
+//! |  3.7.2.-2363       |	c=16 r=1
+//! | prusa3d.com        |	MSG_PRUSA3D
+//! | forum.prusa3d.com  |	MSG_PRUSA3D_FORUM
+//! | howto.prusa3d.com  |	MSG_PRUSA3D_HOWTO
+//! | --------------     |	STR_SEPARATOR
+//! | 1_75mm_MK3         |	FILAMENT_SIZE
+//! | howto.prusa3d.com  |	ELECTRONICS
+//! | howto.prusa3d.com  |	NOZZLE_TYPE
+//! | --------------     |	STR_SEPARATOR
+//! | Date:              |	c=17 r=1
+//! | MMM DD YYYY        |	__DATE__
+//! | --------------     |	STR_SEPARATOR
+//! @endcode
+//! 
+//! If MMU is connected
+//! 
+//! 	@code{.unparsed}
+//! 	| MMU2 connected     |	c=18 r=1
+//! 	|  FW: 1.0.6-7064523 |
+//! 	@endcode
+//! 
+//! If MMU is not connected
+//! 
+//! 	@code{.unparsed}
+//! 	| MMU2       N/A     |	c=18 r=1
+//! 	@endcode
+//! 
+//! If Flash Air is connected
+//! 
+//! 	@code{.unparsed}
+//! 	| --------------     |	STR_SEPARATOR
+//! 	| FlashAir IP Addr:  |	c=18 r=1
+//! 	|  192.168.1.100     |
+//! 	@endcode
+//! 
+//! @code{.unparsed}
+//! | --------------     |	STR_SEPARATOR
+//! | XYZ cal. details   |	MSG_XYZ_DETAILS
+//! | Extruder info      |	MSG_INFO_EXTRUDER
+//! | XYZ cal. details   |	MSG_INFO_SENSORS
+//! @endcode
+//! 
+//! If TMC2130 defined
+//! 
+//! 	@code{.unparsed}
+//! 	| Belt status        |	MSG_MENU_BELT_STATUS
+//! @endcode
+//! 
+//! @code{.unparsed}
+//! | Temperatures       |	MSG_MENU_TEMPERATURES
+//! @endcode
+//! 
+//! If Voltage Bed and PWR Pin are defined
+//! 
+//! 	@code{.unparsed}
+//! 	| Voltages           |	MSG_MENU_VOLTAGES
+//! 	@endcode
+//! 
+//! 
+//! If DEBUG_BUILD is defined
+//! 
+//! 	@code{.unparsed}
+//! 	| Debug              |	c=18 r=1
+//! 	@endcode
+//! ----------------------
+//! @endcode
 static void lcd_support_menu()
 {
 	typedef struct
@@ -2022,8 +2216,8 @@ static void lcd_support_menu()
 	MENU_ITEM_BACK_P(STR_SEPARATOR);
 	if (mmu_enabled)
 	{
-		MENU_ITEM_BACK_P(_i("MMU2 connected"));
-		MENU_ITEM_BACK_P(PSTR(" FW:"));
+		MENU_ITEM_BACK_P(_i("MMU2 connected"));  ////c=18 r=1
+		MENU_ITEM_BACK_P(PSTR(" FW:"));  ////c=17 r=1
 		if (((menu_item - 1) == menu_line) && lcd_draw_update)
 		{
 		    lcd_set_cursor(6, menu_row);
@@ -2040,7 +2234,7 @@ static void lcd_support_menu()
   // Show the FlashAir IP address, if the card is available.
   if (_md->is_flash_air) {
       MENU_ITEM_BACK_P(STR_SEPARATOR);
-      MENU_ITEM_BACK_P(PSTR("FlashAir IP Addr:"));
+      MENU_ITEM_BACK_P(PSTR("FlashAir IP Addr:"));  //c=18 r=1
 ///!      MENU_ITEM(back_RAM, _md->ip_str, 0);
   }
 
@@ -2061,7 +2255,7 @@ static void lcd_support_menu()
 #endif //defined VOLT_BED_PIN || defined VOLT_PWR_PIN
 
 #ifdef DEBUG_BUILD
-  MENU_ITEM_SUBMENU_P(PSTR("Debug"), lcd_menu_debug);
+  MENU_ITEM_SUBMENU_P(PSTR("Debug"), lcd_menu_debug);////c=18 r=1
 #endif /* DEBUG_BUILD */
 
   #endif //MK1BP
@@ -2653,9 +2847,9 @@ if(0)
 //!
 //! @code{.unparsed}
 //! |01234567890123456789|
-//! |Filament used:      |
+//! |Filament used:      | c=18 r=1
 //! |         00.00m     |
-//! |Print time:         |
+//! |Print time:         | c=18 r=1
 //! |        00h 00m 00s |
 //! ----------------------
 //! @endcode
@@ -2664,12 +2858,13 @@ if(0)
 //!
 //! @code{.unparsed}
 //! |01234567890123456789|
-//! |Total filament :    |
+//! |Total filament :    | c=18 r=1
 //! |           000.00 m |
-//! |Total print time :  |
+//! |Total print time :  | c=18 r=1
 //! |     00d :00h :00 m |
 //! ----------------------
 //! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations. Translations missing for "d"days, "h"ours, "m"inutes", "s"seconds".
 void lcd_menu_statistics()
 {
 	if (IS_SD_PRINTING)
@@ -2686,7 +2881,9 @@ void lcd_menu_statistics()
 			"%17.2fm  \n"
 			"%S:\n"
 			"%2dh %02dm %02ds"
-		),_i("Filament used"), _met, _i("Print time"), _h, _m, _s);
+		    ),
+            _i("Filament used"), _met,  ////c=18 r=1
+            _i("Print time"), _h, _m, _s);  ////c=18 r=1
 		menu_back_if_clicked_fb();
 	}
 	else
@@ -2793,17 +2990,20 @@ static void lcd_move_e()
 }
 
 
-//@brief Show measured Y distance of front calibration points from Y_MIN_POS
-//If those points are detected too close to edge of reachable area, their confidence is lowered.
-//This functionality is applied more often for MK2 printers.
+//! @brief Show measured Y distance of front calibration points from Y_MIN_POS
+//! If those points are detected too close to edge of reachable area, their confidence is lowered.
+//! This functionality is applied more often for MK2 printers.
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |Y distance from min |	c=19 r=1
+//! | --------------     |	STR_SEPARATOR
+//! |Left:       00.00mm |	c=11 r=1
+//! |Right:      00.00mm |	c=11 r=1
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_xyz_y_min()
 {
-//|01234567890123456789|
-//|Y distance from min:|
-//|--------------------|
-//|Left:      N/A      |
-//|Right:     N/A      |
-//----------------------
 	float distanceMin[2];
     count_xyz_details(distanceMin);
 	lcd_home();
@@ -2813,15 +3013,15 @@ static void lcd_menu_xyz_y_min()
 	  "%S:\n"
 	  "%S:"
 	 ),
-	 _i("Y distance from min"),
+	 _i("Y distance from min"),  ////c=19 r=1
 	 separator,
-	 _i("Left"),
-	 _i("Right")
+	 _i("Left"),  ////c=11 r=1
+	 _i("Right")  ////c=11 r=1
 	);
 	for (uint8_t i = 0; i < 2; i++)
 	{
 		lcd_set_cursor(11,2+i);
-		if (distanceMin[i] >= 200) lcd_puts_P(_N("N/A"));
+		if (distanceMin[i] >= 200) lcd_puts_P(_N("N/A"));  ////c=3 r=1
 		else lcd_printf_P(_N("%6.2fmm"), distanceMin[i]);
 	}
     if (lcd_clicked())
@@ -2834,14 +3034,20 @@ float _deg(float rad)
 	return rad * 180 / M_PI;
 }
 
+//! @brief Show Measured XYZ Skew
+//! 
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |Measured skew: 0.00D|	c=13 r=1
+//! | --------------     |	STR_SEPARATOR
+//! |Slight skew:   0.12D|	c=13 r=1  c=4 r=1
+//! |Severe skew:   0.25D|	c=13 r=1  c=4 r=1
+//! ----------------------
+//! D - Degree sysmbol		LCD_STR_DEGREE
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_xyz_skew()
 {
-//|01234567890123456789|
-//|Measured skew:  N/A |
-//|--------------------|
-//|Slight skew:   0.12d|
-//|Severe skew:   0.25d|
-//----------------------
     float angleDiff = eeprom_read_float((float*)(EEPROM_XYZ_CAL_SKEW));
 	lcd_home();
 	lcd_printf_P(_N(
@@ -2850,10 +3056,10 @@ static void lcd_menu_xyz_skew()
 	  "%-15.15S%3.2f\x01\n"
 	  "%-15.15S%3.2f\x01"
 	 ),
-	 _i("Measured skew"),
+	 _i("Measured skew"),  ////c=13 r=1
 	 separator,
-	 _i("Slight skew:"), _deg(bed_skew_angle_mild),
-	 _i("Severe skew:"), _deg(bed_skew_angle_extreme)
+	 _i("Slight skew:"), _deg(bed_skew_angle_mild),  ////c=13 r=1  c=4 r=1
+	 _i("Severe skew:"), _deg(bed_skew_angle_extreme)  ////c=13 r=1  c=4 r=1
 	);
 	if (angleDiff < 100){
 		lcd_set_cursor(15,0);
@@ -2866,16 +3072,24 @@ static void lcd_menu_xyz_skew()
     if (lcd_clicked())
         menu_goto(lcd_menu_xyz_offset, 0, true, true);
 }
-/**
- * @brief Show measured bed offset from expected position
- */
+//! @brief Show measured bed offset from expected position
+//! 
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |[0;0] point offset  |	c=20 r=1
+//! | --------------     |	STR_SEPARATOR
+//! |X:          000.00mm|	c=10 r=1
+//! |Y:          000.00mm|	c=10 r=1
+//! ----------------------
+//! @endcode
+//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
 static void lcd_menu_xyz_offset()
 {
     lcd_set_cursor(0,0);
     lcd_puts_P(_i("[0;0] point offset"));////MSG_MEASURED_OFFSET
     lcd_puts_at_P(0, 1, separator);
-    lcd_puts_at_P(0, 2, PSTR("X"));
-    lcd_puts_at_P(0, 3, PSTR("Y"));
+    lcd_puts_at_P(0, 2, PSTR("X"));  ////c=10 r=1
+    lcd_puts_at_P(0, 3, PSTR("Y"));  ////c=10 r=1
 
     float vec_x[2];
     float vec_y[2];
@@ -3034,6 +3248,18 @@ void lcd_adjust_bed_reset(void)
 	_md->status = 0;
 }
 
+//! @brief Show Bed level correct
+//! 
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! |Settings:           |	MSG_SETTINGS
+//! |Left side [um]:     |	MSG_BED_CORRECTION_LEFT
+//! |Right side[um]:     |	MSG_BED_CORRECTION_RIGHT
+//! |Front side[um]:     |	MSG_BED_CORRECTION_FRONT
+//! |Rear side [um]:     |	MSG_BED_CORRECTION_REAR
+//! |Reset               |	MSG_BED_CORRECTION_RESET
+//! ----------------------
+//! @endcode
 void lcd_adjust_bed(void)
 {
 	_menu_data_adjust_bed_t* _md = (_menu_data_adjust_bed_t*)&(menu_data[0]);
@@ -3071,6 +3297,16 @@ void lcd_adjust_bed(void)
     MENU_END();
 }
 
+//! @brief Show PID Extruder
+//! 
+//! @code{.unparsed}
+//! |01234567890123456789|
+//! | Set temperature:   |	MSG_SET_TEMPERATURE
+//! |                    |
+//! | 210                |
+//! |                    |
+//! ----------------------
+//! @endcode
 void pid_extruder()
 {
 	lcd_clear();
@@ -4540,7 +4776,9 @@ void lcd_v2_calibration()
 {
 	if (mmu_enabled)
 	{
-	    const uint8_t filament = choose_menu_P(_i("Select PLA filament:"),_T(MSG_FILAMENT),_i("Cancel")); ////c=20 r=1  ////c=19 r=1
+	    const uint8_t filament = choose_menu_P(
+            _i("Select PLA filament:"), ////c=20 r=1
+            _T(MSG_FILAMENT),_i("Cancel"));  ////c=19 r=1
 	    if (filament < 5)
 	    {
 	        lcd_commands_step = 20 + filament;

+ 57 - 29
lang/lang-import.sh

@@ -4,7 +4,19 @@
 #  for importing translated xx.po
 
 LNG=$1
-if [ -z "$LNG" ]; then exit -1; fi
+# if no arguments, 'all' is selected (all po and also pot will be generated)
+if [ -z "$LNG" ]; then LNG=all; fi
+
+# if 'all' is selected, script will generate all po files and also pot file
+if [ "$LNG" = "all" ]; then
+ ./lang-import.sh cz
+ ./lang-import.sh de
+ ./lang-import.sh es
+ ./lang-import.sh fr
+ ./lang-import.sh it
+ ./lang-import.sh pl
+ exit 0
+fi
 
 # language code (iso639-1) is equal to LNG
 LNGISO=$LNG
@@ -28,43 +40,51 @@ sed -i 's/ \\n/ /g;s/\\n/ /g' $LNG'_filtered.po'
 
 #replace in czech translation
 if [ "$LNG" = "cz" ]; then
- #replace 'ž' with 'z'
+ #replace 'ž' with 'z'
  sed -i 's/\xc5\xbe/z/g' $LNG'_filtered.po'
- #replace 'ì' with 'e'
+ #replace 'ì' with 'e'
  sed -i 's/\xc4\x9b/e/g' $LNG'_filtered.po'
- #replace 'í' with 'i'
+ #replace 'í' with 'i'
  sed -i 's/\xc3\xad/i/g' $LNG'_filtered.po'
- #replace 'ø' with 'r'
+ #replace 'ø' with 'r'
  sed -i 's/\xc5\x99/r/g' $LNG'_filtered.po'
- #replace 'è' with 'c'
+ #replace 'è' with 'c'
  sed -i 's/\xc4\x8d/c/g' $LNG'_filtered.po'
- #replace 'á' with 'a'
+ #replace 'á' with 'a'
  sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
- #replace 'é' with 'e'
+ #replace 'é' with 'e'
  sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
 fi
 
-#replace in german translation
+#replace in german translation https://en.wikipedia.org/wiki/German_orthography
 if [ "$LNG" = "de" ]; then
- #replace 'ä' with 'ae'
+ #replace 'ä' with 'ae'
  sed -i 's/\xc3\xa4/ae/g' $LNG'_filtered.po'
- #replace 'ü' with 'ue'
+ #replace 'Ä' with 'Ae'
+ sed -i 's/\xc3\x84/Ae/g' $LNG'_filtered.po'
+ #replace 'ü' with 'ue'
  sed -i 's/\xc3\xbc/ue/g' $LNG'_filtered.po'
- #replace 'ö' with 'oe'
+ #replace 'Ü' with 'Ue'
+ sed -i 's/\xc3\x9c/Ue/g' $LNG'_filtered.po'
+ #replace 'ö' with 'oe'
  sed -i 's/\xc3\xb6/oe/g' $LNG'_filtered.po'
+ #replace 'Ö' with 'Oe'
+ sed -i 's/\xc3\x96/Oe/g' $LNG'_filtered.po'
+ #replace 'ß' with 'ss'
+ sed -i 's/\xc3\x9f/ss/g' $LNG'_filtered.po'
 fi
 
 #replace in spain translation
 if [ "$LNG" = "es" ]; then
- #replace 'á' with 'a'
+ #replace 'á' with 'a'
  sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
- #replace '?' with '?'
+ #replace '¿' with '?'
  sed -i 's/\xc2\xbf/?/g' $LNG'_filtered.po'
- #replace 'ó' with 'o'
+ #replace 'ó' with 'o'
  sed -i 's/\xc3\xb3/o/g' $LNG'_filtered.po'
- #replace 'é' with 'e'
+ #replace 'é' with 'e'
  sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
- #replace 'í' with 'i'
+ #replace 'í' with 'i'
  sed -i 's/\xc3\xad/i/g' $LNG'_filtered.po'
  #replace '!' with '!'
  sed -i 's/\xc2\xa1/!/g' $LNG'_filtered.po'
@@ -72,31 +92,39 @@ if [ "$LNG" = "es" ]; then
  sed -i 's/\xc3\xb1/n/g' $LNG'_filtered.po'
 fi
 
-#replace in french translation
+#replace in french translation https://en.wikipedia.org/wiki/French_orthography
 if [ "$LNG" = "fr" ]; then
- #replace 'é' with 'e'
+ #replace 'á' with 'a' (right)
+ sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
+ #replace '�' with 'A' (right)
+ sed -i 's/\xc3\x81/A/g' $LNG'_filtered.po'
+ #replace 'à' with 'a' (left)
+ sed -i 's/\xc3\xa0/a/g' $LNG'_filtered.po'
+ #replace 'À' with 'A' (left)
+ sed -i 's/\xc3\x80/A/g' $LNG'_filtered.po'
+ #replace 'é' with 'e' (right)
  sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
- #replace 'É' with 'E'
+ #replace 'É' with 'E' (right)
  sed -i 's/\xc3\x89/E/g' $LNG'_filtered.po'
- #replace 'é' with 'e' (left)
+ #replace 'è' with 'e' (left)
  sed -i 's/\xc3\xa8/e/g' $LNG'_filtered.po'
- #replace 'á' with 'a' (left)
- sed -i 's/\xc3\xa0/a/g' $LNG'_filtered.po'
+ #replace 'È' with 'E' (left)
+ sed -i 's/\xc3\x88/E/g' $LNG'_filtered.po'
 fi
 
 #replace in italian translation
 if [ "$LNG" = "it" ]; then
- #replace 'é' with 'e' (left)
+ #replace 'é' with 'e' (left)
  sed -i 's/\xc3\xa8/e/g' $LNG'_filtered.po'
- #replace 'á' with 'a' (left)
+ #replace 'á' with 'a' (left)
  sed -i 's/\xc3\xa0/a/g' $LNG'_filtered.po'
- #replace 'ó' with 'o' (left)
+ #replace 'ó' with 'o' (left)
  sed -i 's/\xc3\xb2/o/g' $LNG'_filtered.po'
- #replace 'ú' with 'u' (left)
+ #replace 'ú' with 'u' (left)
  sed -i 's/\xc3\xb9/u/g' $LNG'_filtered.po'
- #replace 'é' with 'e'
+ #replace 'é' with 'e'
  sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
- #replace 'É' with 'E' (left)
+ #replace 'É' with 'E' (left)
  sed -i 's/\xc3\x88/E/g' $LNG'_filtered.po'
 fi
 

+ 252 - 0
lang/translations.md

@@ -0,0 +1,252 @@
+# Translations
+
+## Workflow
+
+- Build firmware
+  - using `build.sh`
+  - using `PF-build.sh` with a `break` before `# build languages`
+- change to `lang` folder
+- check if lang scripts being able to run with `config.sh`
+  - if you get `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-64`
+- run `lang-build.sh en` to create english `lang_en.tmp`, `lang_en.dat` and `lang_en.bin` files
+- change in `fw-build.sh` `IGNORE_MISSING_TEXT=1` to `IGNORE_MISSING_TEXT=0` so it stops with error and generates `not_used.txt` and `not_tran.txt`
+- run modified `fw-build.sh`
+  - `not_tran.txt` should be reviewed and added as these are potential missing translations
+    - copy `not_tran.txt` as `lang_add.txt` 
+	  - check if there are things you don't want to translate or must be modifed
+	  - als check that the strings do not start with `spaces` as the scripts doesn't handle these well at this moment.
+	  - run `lang-add.sh lang_add.txt` to add the missing translations to `lang_en.txt` and `lang_en_??.txt`
+  - `not_used.txt` should only contain mesages that aren't used in this variant like MK2.5 vs MK3
+- run `fw-clean.sh` to cleanup firmware related files
+- delete `not_used.txt` and `not_tran.txt`
+- run `lang-clean.sh` to cleanup language related files
+- run `lang-export.sh all` to create PO files for translation these are stored in `/lang/po` folder
+  - Send them to translators and reviewers or
+  - copy these to `/lang/po/new` and 
+  - translate these with POEdit the newly added messages
+    - easiest way is to choose `Validate`in POEdit as it shows you `errors` and the `missing transalations` / most likely the newly added at the top.
+- The new translated files are expected in `/lang/po/new` folder so store the received files these
+- run `lang-import.sh <language code (iso639-1)>` for each newly translated language
+  - script improvement to import "all" and other things would be great.
+- Double check if something is missing or faulty
+  - run `lang-build.sh` to to create `lang_en.tmp/.dat/.bin` and `lang_en_??.tmp/.dat/.bin` files
+  - run `fw-build.sh` and check if there are still some messages in `not_tran.txt` that need attention
+- After approval
+  - run `fw-clean.sh` to cleanup firmware related files
+  - run `lang-clean.sh` to cleanup language related files
+  - change in `fw-build.sh` back to `IGNORE_MISSING_TEXT=1`
+  - remove `break` from `PF-build.sh` script if that has been modified
+  - build your firmware with `build.sh`, `PF-build.sh` or how you normally do it.
+  - Check/Test firmware on printer
+
+## Code / usage
+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`:
+```C++
+// section .loc_sec (originaly .progmem0) will be used for localized translated strings
+#define PROGMEM_I2 __attribute__((section(".loc_sec")))
+// section .loc_pri (originaly .progmem1) will be used for localized strings in english
+#define PROGMEM_I1 __attribute__((section(".loc_pri")))
+// section .noloc (originaly 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 inplace of C++ code, no string table is used. The downside of this approach is obvious - the compiler is not able/willing to merge duplicit 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).
+```C++
+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
+}
+```
+
+## Files
+
+### `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"
+```
+1. a comment - usually a MSG define with number of characters (c) and rows (r)
+2. English text
+3. translated text
+
+### `not_tran.txt`
+A simple list of strings that are not translated yet.
+
+### `not_used.txt`
+A 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 carefull and double check the code if this message is obsolete or just not used due to the chosen variant.
+
+## Scripts
+
+### `config.sh`
+- Checks setup and sets auxiliary env vars used in many other scripts. 
+- Looks for env var `ARDUINO`. If not found/empty, a default `C:/arduino-1.8.5` is used.
+- Sets env var `CONFIG_OK=1` when all good, otherwise sets `CONFIG_OK=0`
+
+### `fw-build.sh`
+Joins firmware HEX and language binaries into one file.
+
+### `fw-clean.sh`
+
+### `lang-add.sh`
+Adds new messages into the dictionary regardless of whether there have been any older versions.
+
+### `lang-build.sh`
+Generates lang_xx.bin (language binary files) for the whole firmware build.
+
+Arguments:
+- `$1` : language code (`en`, `cz`, `de`, `es`, `fr`, `it`, `pl`) or `all`
+- empty/no arguments defaults to `all`
+
+Input: `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:
+- 00-01: `A5 5A`
+- 02-03: `B4 4B`
+- 04-05: 2B size
+- 06-07: 2B number of strings
+- 08-09: 2B checksum
+- 0A-0B: 2B lang code hex data: basically `en` converted into `ne`, i.e. characters swapped. Only `cz` is changed into `sc` (old `cs` ISO code).
+- 0C-0D: 2B signature low
+- 0E-0F: 2B signature high
+- 10-(10 + 2*number of strings): table of string offsets from the beginning of this file
+- after the table there are the strings themselves, each terminated with `\x00`
+
+The 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.py`
+Both 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.sh`
+Removes all language output files from lang folder. That means deleting:
+-  if [ "$1" = "en" ]; then
+  rm_if_exists lang_$1.tmp
+ else
+  rm_if_exists lang_$1.tmp
+  rm_if_exists lang_en_$1.tmp
+  rm_if_exists lang_en_$1.dif
+  rm_if_exists lang_$1.ofs
+  rm_if_exists lang_$1.txt
+ fi
+ rm_if_exists lang_$1_check.dif
+ rm_if_exists lang_$1.bin
+ rm_if_exists lang_$1.dat
+ rm_if_exists lang_$1_1.tmp
+ rm_if_exists lang_$1_2.tmp
+
+### `lang-export.sh`
+Exports PO (gettext) for external translators.
+
+### `lang-import.sh`
+Import from PO.
+
+Arguments:
+- `$1` : language code (`en`, `cz`, `de`, `es`, `fr`, `it`, `pl`)
+- empty/no arguments quits the script
+
+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 improments to scrpit:
+ - add `all` argument
+ - update `replace in <language> translations` to all known special characters the LCD display with Japanese ROM cannot display
+ - move `lang_en_<language code>.txt` to folder `/lang`
+ - cleanup `<language code>_filtered.po`, `<language code>_new.po` and `nonasci.txt`
+
+### `progmem.sh`
+
+Examine content of progmem sections (default is progmem1).
+
+Input:
+- $OUTDIR/Firmware.ino.elf
+- $OUTDIR/sketch/*.o (all object files)
+
+Outputs:
+- text.sym     - formated symbol listing of section '.text'
+- $PROGMEM.sym - formated symbol listing of section '.progmemX'
+- $PROGMEM.lss - disassembly listing file
+- $PROGMEM.hex - variables - hex
+- $PROGMEM.chr - variables - char escape
+- $PROGMEM.var - variables - strings
+- $PROGMEM.txt - text data only (not used)
+
+Description of process:
+- check input files
+- remove output files
+- list symbol table of section '.text' from output elf file to text.sym (sorted by address)
+- calculate start and stop address of section '.$PROGMEM'
+- dump $PROGMEM data in hex format, cut disassembly (keep hex data only) into $PROGMEM.lss
+- convert $PROGMEM.lss to $PROGMEM.hex:
+ - replace empty lines with '|' (variables separated by empty lines)
+ - remove address from multiline variables (keep address at first variable line only)
+ - remove '<' and '>:', remove whitespace at end of lines
+ - remove line-endings, replace separator with '\n' (join hex data lines - each line will contain single variable)
+- convert $PROGMEM.hex to $PROGMEM.chr (prepare string data for character check and conversion)
+ - replace first space with tab
+ - replace second and third space with tab and space
+ - replace all remaining spaces with '\x'
+ - replace all tabs with spaces
+- convert $PROGMEM.chr to $PROGMEM.var (convert data to text) - a set of special characters is escaped here including `\x0a`
+
+
+### `textaddr.sh`
+
+Compiles `progmem1.var` and `lang_en.txt` files to `textaddr.txt` file (mapping of progmem addreses to text idenifiers).
+
+Description of process:
+- check if input files exists
+- create sorted list of strings from progmem1.var and lang_en.txt
+- lines from progmem1.var will contain addres (8 chars) and english text
+- lines from lang_en.txt will contain linenumber and english text
+- after sort this will generate pairs of lines (line from progmem1 first)
+- result of sort is compiled with simple script and stored into file textaddr.txt
+
+Input:
+- progmem1.var
+- lang_en.txt
+
+Output:
+- textaddr.txt
+
+
+
+update_lang.sh