Create language file

I need suggestions on creating a language file for my project. My project is multi language and i want to output all texts in the selected language.

I was thinking about creating a language.h file with some sort of object for all outputs per language but i don't know exactly what the best approach is.

Is it better to create a language.h file with all language variables or multiple files (like en.h, nl.h etc)?
I would like to have a global setting (selectedLanguage), and with that value i can select the text in the right language.

do you plan to be able to switch language at run time or is this a compile time choice?

At runtime, so i need a file with all the languages (won't be many), and if a different language is selected i will use the other selected language

localisation can be complex where word orders or variable positions don't work the same way depending on the language. (currency symbol location ➜ 5€ versus $5 for example or Friday, August 31st versus Vendredi 31 août, ...)

so more than the text, it might impact the way things get printed out

how sophisticated does it need to be? what type or arduino do you plan to run this on? (memory footprint can become large)

I am programming on an ESP32

I think i need something like this pseudocode:

[en]:
  monday = 'Monday';
  tuesday = 'Tuesday';
  ...
  no_connection = 'No connection';
[nl]
  monday = 'Maandag';
  tuesday = 'Dinsdag';
  ...
  no_connection = 'Geen verbinding';

It won't be a lot of text, just some day names and error messages
I can create different classes (class per language) but than i don't know what the easiest way is to select the right language. Preferably i would set a language at some point, and the variable is taken from the right object or class

Perhaps this is a starting point.

char const* const english[] {"hello", "world"};
char const* const german[] {"hallo", "Welt"};


void greet(char const* const* const language) {
  Serial.print(language[0]);
  Serial.print(' ');
  Serial.println(language[1]);
}

void setup() {
  Serial.begin(9600);

  greet(english);
  greet(german);
}

void loop() {}

To save memory, you could have a look at the PROGMEM utility.

Thanks, but i don't like the fact that i cannot use a key (string instead of an index) to get the value. I am sure at some point i will get a mess with selecting the right key and none of the texts are right.

of just have the chosen language a global variable and always use the array indirection whenever you want to print and may be an enum list that matches the array's order to make the code more readable

enum {HELLO, WORLD,};

char const* const english[] {"hello", "world"};
char const* const german[] {"hallo", "Welt"};

char const* const*  language = english;

void greet() {
  Serial.print(language[HELLO]);
  Serial.print(' ');
  Serial.println(language[WORLD]);
}

void setup() {
  Serial.begin(9600);
  greet();
  language = german;
  greet();
}

void loop() {}

I was about to suggest something similar:

char const* const english[] {"monday", "tuesday"};
char const* const german[] {"Montag", "Dienstag"};

enum Weekday {mon, tue};


void printDay(char const* const* const language, Weekday const day) {
  Serial.println(language[day]);
}

void setup() {
  Serial.begin(9600);

  printDay(english, mon);
  printDay(german, tue);
}

void loop() {}

Thank you, i will try if i can do it like this.

What is the purpose of char const* const ...?
or
char const* const* language = ...

I mean the char with double const

This creates a constant array of constant C strings. It disallows assignment to elements of this array, e.g.,

char const* w {"OI"};
english[0] = w;  // error: assignment of read-only location 'english[0]'

Thank you!

I am trying to create a Language class but i get a compiler error.

This is my language file:

#ifndef LANGUAGE_H
#define LANGUAGE_H

#include <Arduino.h>

class Language
{
    public:
        enum translationKeys {
            monday,
            tuesday,
            wednesday,
            thursday,
            friday,
            saturday,
            sunday
        };
        
        char const* const en[] {
            "Monday",
            "Tuesday",
            "Wednesday",
            "Thursday",
            "Friday",
            "Saturday",
            "Sunday"
        };
        char const* const nl[] {
            "Maandag",
            "Dinsdag",
            "Woensdag",
            "Donderdag",
            "Vrijdag",
            "Zaterdag",
            "Zondag"
        };
        char const* const* language;
        
        String translate(translationKeys const translationKey) {
            return language[translationKey];
        }
    
};

#endif

This is my main.cpp:

#include "language.h"

Language                    language;

void setup() {
    language.language = language.nl;

}

This is the error:


In file included from src/main.cpp:4:
src/language.h:27:9: error: flexible array member 'Language::en' not at end of 'class Language'
         };
         ^
src/language.h:27:9: error: initializer for flexible array member 'const char* const Language::en []'
src/language.h:36:9: error: initializer for flexible array member 'const char* const Language::nl []'
         };
         ^

What am i doing wrong?

Flexible array members (i.e., arrays with no specified size) are not allowed inside of structs or classes in C++.

Try to change this to:

char const* const en[7] {

Thank you, i was just testing this and it works. Is there also a way to define the enum translationKeys automatically?

Something like:

static const int numberOfTranslationKeys     = sizeof(translationKeys);

char const* const en[numberOfTranslationKeys] {
...
}

You could use enum promotion to your advantage. E.g.,

enum translationKeys {
  monday,
  // ...          
  sunday,
  size
};

char const* const en[size] {
  // ...

Perfect, thank you!

you don't need the size to define the array, the compiler will calculate it

see in this code, I did not have to specify I had 2 entries


what's the question exactly ?

would you want something to magically generate the enum keywords based on the array? (really hard may be impossible esp. if you have long text and not just words in the array ➜ probably better to maintain the words in XML on the side and have a pre-processor phase generating a .h for you from all your languages )

Sorry, i only meant the length of the enum translationKeys, but i have it.
Thanks for all the help

good - have fun