Hi all,
while trying to write a multi-language sketch, I've putted together a class to simplify my code.
Here's what I've come up with.
(arduino 1.0)
The sketch:
// Arduino localization example.
#include <LiquidCrystal.h>
#include "ArduL10n.h"
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // lcd pins for nuelectronics lcd+keypad shield
const short LCD_ROWS = 2;
const short LCD_COLS = 16;
// localization object
ArduL10n l10n;
// print some (localized) strings
void printStrings() {
lcd.clear();
lcd.print(l10n.getString(l10n.STR_SELECTED_LANGUAGE));
lcd.setCursor(0, 1);
lcd.print(l10n.getString(l10n.STR_LANG));
lcd.print(" ");
lcd.print(l10n.getString(l10n.STR_WAIT));
}
void setup() {
lcd.begin(LCD_COLS, LCD_ROWS);
}
void loop() {
byte l = l10n.getCurrLang();
l++;
if (l >= l10n.NUM_LANGS) {
l = 0;
}
l10n.setCurrLang(l);
printStrings();
delay(1000);
}
ArduL10n.h:
#ifndef _ARDU_L10N
#define _ARDU_L10N
#include <Arduino.h>
// Localization for Arduino sketches.
// Author: tuxduino @ arduino.cc forum
// Date: 2012-11-12
// Version: 0.1
class ArduL10n {
public:
// --- start of user defined section --- //
// language identifiers
static const byte LANG_FIRST = 0; // alias for looping through all languages
static const byte LANG_ITA = 0;
static const byte LANG_ENG = 1;
// ...define more languages...
// don't forget to update LANG_LAST
static const byte LANG_LAST = 1; // alias for looping through all languages
static const byte NUM_LANGS = LANG_LAST + 1; // number of defined languages
static const byte DEFAULT_LANG = LANG_ITA;
// string identifiers
static const byte STR_FIRST = 0; // alias to loop through all the strings
static const byte STR_LANG = 0;
static const byte STR_SELECTED_LANGUAGE = 1;
static const byte STR_WAIT = 2;
// ...define more strings...
// don't forget to update STR_LAST
static const byte STR_LAST = 2; // alias to loop through all the strings
// --- end of user-defined section --- //
// specify one of the string ids above, and automatically get
// the translated string for the currently selected language
__FlashStringHelper* getString(byte stringId) const;
// get a specific translation, regardless of the currently
// selected language
__FlashStringHelper* getString(byte stringId, byte langId) const;
// get the currently selected language
byte getCurrLang() const;
// select a language
void setCurrLang(byte lang);
// constructor: specify the initially selected language
ArduL10n(byte lang = DEFAULT_LANG);
private:
// currently selected language
byte _currLang;
// lenght of the longest string (as in strlen)
static const byte MAX_STR_LEN = 16;
// array of localized strings
static const char strings[][NUM_LANGS][MAX_STR_LEN + 1];
};
#endif
ArduL10n.cpp:
#include "ArduL10n.h"
// Localization for Arduino sketches.
// Author: tuxduino @ arduino.cc forum
// Date: 2012-11-12
// Version: 0.1
// this is where the actual text goes.
// notice the + 1 after MAX_STR_LEN to make room for the null-byte string terminator.
const char ArduL10n::strings[][NUM_LANGS][MAX_STR_LEN + 1] PROGMEM = {
// LANG_ITA strings // LANG_ENG strings
// 012345678901235 , 0123456789012345 // string length guides to ensure we don't go beyond MAX_STR_LEN
{ "Italiano" , "English" },
{ "Lingua selez." , "Sel. language" },
{ "Attendi" , "Wait" },
// ...add more string couples...
// don't forget to add their string identifiers in ArduL10n.h too...
};
ArduL10n::ArduL10n(byte lang) {
if (lang < NUM_LANGS) {
_currLang = lang;
}
else {
_currLang = DEFAULT_LANG;
}
};
__FlashStringHelper* ArduL10n::getString(byte stringId) const {
return getString(stringId, getCurrLang());
}
__FlashStringHelper* ArduL10n::getString(byte stringId, byte langId) const {
if (stringId <= STR_LAST && langId <= LANG_LAST) {
return (__FlashStringHelper*)ArduL10n::strings[stringId][langId];
}
else {
return NULL;
}
}
byte ArduL10n::getCurrLang() const {
return _currLang;
}
void ArduL10n::setCurrLang(byte lang) {
if (lang < NUM_LANGS) {
_currLang = lang;
}
}
The translated strings are stored into progmem, to avoid wasting precious RAM.
Currently supports up to 256 string ids. This limit could be easily raised by changing byte with unsigned int.
To add a new string couple follow these steps:
- add the two(*) strings to the strings[] array at the top of the cpp file
- ensure their length is below MAX_STR_LEN, or increase that constant to make room for the longest string
- add the named constant for the string id: its value must be equal to the greatest string id so far + 1
- update the STR_LAST named constant
(*) or three, or four, etc., depending on the number of languages defined (NUM_LANGS)
I admit adding strings is not as straightforward as I'd like. But the sketch code is quite clean IMHO.
Any questions, comments or suggestions are welcome, of course.