I have been trying to figure out a memory efficient way of selecting languages (at compile-time) creating multi dimentional arrays, that can then be used to dynamically set the displayed language at run time.
The reason for this is to create multi-lingual sketches that are easy to modify by adding/removing the languages that are available. Once compiled the created array will allow the end user to dynamically choose the language that is going to be displayed or transmitted.
Good news I have a working sketch ![]()
You can try it out at the following link on TinkerCAD:
Tinkercad "Compile-time-dynamic-multi-lingual-array"
The code is below:
#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
#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
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);
strcpy_P(charBuffer, (char*) pgm_read_word(&(menu1[lang][i]))); //Copies string from program memory into buffer
lcd.print(charBuffer); //Prints the buffer
lcd.setCursor(0, 1);
lcd.print(F("menu1["));
lcd.print(lang);
lcd.print(F("]["));
lcd.print(i);
lcd.print(F("]"));
delay(1000);
lcd.clear();
}
}
}
Does anyone have an idea as to how I would go about making a library out of this?
The intent is to be able to setup each language lookup table in separate headers and remove some of the leg work by automating the process and making it easier for people to integrate into thier sketches.