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);
}
