See the code in action on Tinkercad
/* This is my quick and dirty Tutorial/Demo of a "i18n Multi-Lingual 'array'" By using this method you can create easily customizable Multi-ligual sketches Created by Alain Martel */ #include <avr/pgmspace.h> //Used to store "constant variables" in program space (in this case for messages displayed on LCD) //Multi-Lingual display Start #define ArrayCount(array) ((sizeof array / sizeof array[0]) - 1) // For myArray[X][Y] // X = (ArrayCount(menu2)); // Y = (ArrayCount(menu2[0])); //Languages to include: #define ENGLISH #define FRENCH //Comment out any of these defines to exclude a language from the array //#define SPANISH //Uncomment to include in the array #define PORTUGUES #define GERMAN //Set Default Language This section can be removed, I use it as a "safety" because I have unique settings in ENGLISH defines #ifndef ENGLISH //This ensures the default language is set #define ENGLISH #endif //Used to demonstrate changing the available menu items #define CONFIGURATION //Commenting this will remove "Settings" from the array //Start putting Strings into Program Memory #ifdef ENGLISH //Only required if your SET DEFAULT LANGUAGE SETTING is not ENGLISH const static char langEN [] PROGMEM = "English"; const static char menu1en1[] PROGMEM = "Language"; const static char menu1en2[] PROGMEM = "Game 1"; const static char menu1en3[] PROGMEM = "Game 2"; const static char menu1en4[] PROGMEM = "Game 3"; const static char menu1en5[] PROGMEM = "Game 4"; const static char menu1en6[] PROGMEM = "Game 5"; #ifdef CONFIGURATION const static char menu1en7[] PROGMEM = "Settings"; #define ENGLISH_M1 { langEN, menu1en1, menu1en2, menu1en3, menu1en4, menu1en5, menu1en6, menu1en7 }, //The following line is only required in the default language #define M1_Elements 8 //This will set the number of elements in the array #else #define ENGLISH_M1 { langEN, menu1en1, menu1en2, menu1en3, menu1en4, menu1en5, menu1en6 }, //The following line is only required in the default language #define M1_Elements 7 //One less element in the array "Settings" is unavailable #endif #endif #ifdef FRENCH const static char langFR [] PROGMEM = "Francais"; const static char menu1fr1[] PROGMEM = "Langue"; const static char menu1fr2[] PROGMEM = "Jeux 1"; const static char menu1fr3[] PROGMEM = "Jeux 2"; const static char menu1fr4[] PROGMEM = "Jeux 3"; const static char menu1fr5[] PROGMEM = "Jeux 4"; const static char menu1fr6[] PROGMEM = "Jeux 5"; #ifdef CONFIGURATION const static char menu1fr7[] PROGMEM = "Parametres"; #define FRENCH_M1 { langFR, menu1fr1, menu1fr2, menu1fr3, menu1fr4, menu1fr5, menu1fr6, menu1fr7 }, #else #define FRENCH_M1 { langFR, menu1fr1, menu1fr2, menu1fr3, menu1fr4, menu1fr5, menu1fr6 }, #endif #endif #ifdef SPANISH const static char langES [] PROGMEM = "Espanol"; const static char menu1es1[] PROGMEM = "Idioma"; const static char menu1es2[] PROGMEM = "Juego 1"; const static char menu1es3[] PROGMEM = "Juego 2"; const static char menu1es4[] PROGMEM = "Juego 3"; const static char menu1es5[] PROGMEM = "Juego 4"; const static char menu1es6[] PROGMEM = "Juego 5"; #ifdef CONFIGURATION const static char menu1es7[] PROGMEM = "Ajustes"; #define SPANISH_M1 { langES, menu1es1, menu1es2, menu1es3, menu1es4, menu1es5, menu1es6, menu1es7 }, #else #define SPANISH_M1 { langES, menu1es1, menu1es2, menu1es3, menu1es4, menu1es5, menu1es6 }, #endif #endif #ifdef PORTUGUES const static char langPT [] PROGMEM = "Portugues"; const static char menu1pt1[] PROGMEM = "Lingua"; const static char menu1pt2[] PROGMEM = "Jogo 1"; const static char menu1pt3[] PROGMEM = "Jogo 2"; const static char menu1pt4[] PROGMEM = "Jogo 3"; const static char menu1pt5[] PROGMEM = "Jogo 4"; const static char menu1pt6[] PROGMEM = "Jogo 5"; #ifdef CONFIGURATION const static char menu1pt7[] PROGMEM = "Definicoes"; #define PORTUGUES_M1 { langPT, menu1pt1, menu1pt2, menu1pt3, menu1pt4, menu1pt5, menu1pt6, menu1pt7 }, #else #define PORTUGUES_M1 { langPT, menu1pt1, menu1pt2, menu1pt3, menu1pt4, menu1pt5, menu1pt6 }, #endif #endif #ifdef GERMAN const static char langDE [] PROGMEM = "Deutsche"; const static char menu1de1[] PROGMEM = "Sprache"; const static char menu1de2[] PROGMEM = "Spiel 1"; const static char menu1de3[] PROGMEM = "Spiel 2"; const static char menu1de4[] PROGMEM = "Spiel 3"; const static char menu1de5[] PROGMEM = "Spiel 4"; const static char menu1de6[] PROGMEM = "Spiel 5"; #ifdef CONFIGURATION const static char menu1de7[] PROGMEM = "Einstellungen"; #define GERMAN_M1 { langDE, menu1de1, menu1de2, menu1de3, menu1de4, menu1de5, menu1de6, menu1de7 }, #else #define GERMAN_M1 { langDE, menu1de1, menu1de2, menu1de3, menu1de4, menu1de5, menu1de6 }, #endif #endif //End putting Strings into Program Memory //This was the easiest way I found to count the number of Languages selected //Start Count const static char* const langMenu [] PROGMEM = { langEN, #ifdef FRENCH langFR, #endif #ifdef SPANISH langES, #endif #ifdef PORTUGUES langPT, #endif #ifdef GERMAN langDE, #endif }; const uint8_t numLang = ArrayCount(langMenu); //((sizeof(langMenu) / sizeof(langMenu[0])) - 1); const uint8_t numLangElements = numLang + 1; //End Count const static char* const menu1[numLangElements][M1_Elements] PROGMEM = { ENGLISH_M1 //Places the defined ENGLISH_M1 array here #ifdef FRENCH //If othe Languages have been defined they will be added to the array FRENCH_M1 #endif #ifdef SPANISH SPANISH_M1 #endif #ifdef PORTUGUES PORTUGUES_M1 #endif #ifdef GERMAN GERMAN_M1 #endif }; char charBuffer[17]; //Required to read from program memory into a buffer for processing uint8_t lang = 0; //Multi-Lingual display End #include <LiquidCrystal.h> LiquidCrystal lcd(12, 11, 5, 4, 3, 2); void setup() { lcd.begin(16, 2); lcd.print(F("Enabled ")); lcd.print(numLangElements); lcd.print(F(" Langs")); lcd.setCursor(0, 1); lcd.print(freeRam()); delay(5000); lcd.clear(); } void loop() { for (lang; lang <= numLang; lang++) { for (int i = 0; i<= M1_Elements - 1; i++) { lcd.setCursor(0, 0); printProgStr ((const char *) pgm_read_word(&(menu1[lang][i]))); //Copies string from program and prints directly to LCD lcd.setCursor(0, 1); lcd.print(F("menu1[")); lcd.print(lang); lcd.print(F("][")); lcd.print(i); lcd.print(F("]")); delay(1000); lcd.clear(); } } } int freeRam () { //From https://playground.arduino.cc/Code/AvailableMemory/ extern int __heap_start, *__brkval; int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); } // Print a string from Program Memory directly to save RAM void printProgStr(const char * str) { char singleCharBuffer; if(!str) return; while((singleCharBuffer = pgm_read_byte(str++))) lcd.print (singleCharBuffer); }