C++ Lokalisierung



  • Hallo,

    ich möchte in meiner Anwendung mehrere Sprachen (Deutsch, Englisch etc.) unterstützen. Wie könnte ich das am einfachsten machen (ohne externe Lib)? Also dass in der deutschen Version in der Anwendung steht "Wie geht es dir?" und in der englischen "How are you"?



  • Localizer33 schrieb:

    Hallo,

    ich möchte in meiner Anwendung mehrere Sprachen (Deutsch, Englisch etc.) unterstützen. Wie könnte ich das am einfachsten machen (ohne externe Lib)? Also dass in der deutschen Version in der Anwendung steht "Wie geht es dir?" und in der englischen "How are you"?

    Phrases.hxx

    #include <vector>
    
    std::vector<std::string> const PHRASES =
    {
    #ifdef EN
          "Hello World!",
          "How are you doing?"
    #elif defined DE
          "Hallo Welt!",
          "Wie geht's dir?"
    #endif
    };
    
    enum PHRASE_INDEX
    {
          Greeting,
          HowAreYou //denk dir bessere Bezeichner aus :D
    };
    

    Main.cxx

    #include <iostream>
    #define DE
    
    #include "Phrases.hxx"
    
    int main()
    {
          std::cout << PHRASES[HowAreYou] << '\n';
    }
    

    Oder: Etwas schönes aus dem hause trolltech und in Qt enthalten 😃



  • Was auch geht: Damit muss die Sprache nicht zur Compilezeit bekannt sein:

    #include <iostream>
    #include <vector>
    
    std::vector<std::vector<std::string>> const Phrases =
    {
          {//EN
                "Hello World!",
                "How are you doing?"
          },
          {//DE
                "Hallo Welt!",
                "Wie geht's dir?"
          }
    };
    
    enum LanguageIndex
    {
          ENG,
          GER
    };
    
    enum PhraseIndex
    {
          Greeting,
          Question1 //denk dir bessere Bezeichner aus :D
    };
    
    int main()
    {
          std::cout << Phrases[GER][Question1] << '\n';
    }
    


  • Hackers Lösungen finde ich beide nicht so toll, da hier unnötigerweise Speicher angefordert wird. Wie wäre es mit sowas?

    enum language { en = 0, de = 1, };
    enum text { greeting = 0, how_are_you_question = 1, };
    
    char const* const strings[][] =
    {
        { "Hello, World!", "How are you?"    },
        { "Hallo, Welt!",  "Wie geht's dir?" }
    };
    

    Dann machste dir noch ne Funktion get_text:

    char const* get_text(language lang, text tx)
    {
        return strings[lang][tx];
    }
    

    Und dann kannste dir die Begrüßung in englischer Sprache holen über:

    get_text(language::en, text::greeting);
    


  • Kellerautomat schrieb:

    Hackers Lösungen finde ich beide nicht so toll, da hier unnötigerweise Speicher angefordert wird. Wie wäre es mit sowas?

    enum language { en = 0, de = 1, };
    enum text { greeting = 0, how_are_you_question = 1, };
    
    char const* const strings[][] =
    {
        { "Hello, World!", "How are you?"    },
        { "Hallo, Welt!",  "Wie geht's dir?" }
    };
    

    Dann machste dir noch ne Funktion get_text:

    char const* get_text(language lang, text tx)
    {
        return strings[lang][tx];
    }
    

    Und dann kannste dir die Begrüßung in englischer Sprache holen über:

    get_text(language::en, text::greeting);
    

    Jetzt versuche ich mal klugzuscheißern. 😃 🤡

    Das ist ungefähr genau das meinige, nur ohne den vector und den Strings aber mit einem C-Style Array und C-Style Strings - die gar nicht das essentielle waren. Ist das denn nicht schon premature optimization? erwischt :p
    Wieso eine Funktion? Auch wenn sie höchstwahrscheinlich geinlined wird (oder zumindest RVO angewandt wird), ist sie unnötig da man gleich die Enumeratoren als Indizen nutzen kann. (Außer du findest es so schöner, das ist natürlich ein Punkt)
    Die Initialisierung des Arrays ist syntaktisch falsch, da du nur die Größe der ersten Dimension automatisch deduzieren lassen kannst.

    Außerdem kann er auch den Qt Linguist verwenden...der macht es halt professionell (da man bei unser beider Lösungen selbst den Fehler machen kann, etwas falsch zu übersetzen (auch wenn viele Übersetzungsprogramme noch an ihrer Grammatik arbeiten müssen 😉 )).



  • Hacker schrieb:

    Das ist ungefähr genau das meinige, nur ohne den vector und den Strings aber mit einem C-Style Array und C-Style Strings - die gar nicht das essentielle waren. Ist das denn nicht schon premature optimization? erwischt :p

    Eigentlich nicht, weil mit den Strings überhaupt nichts angestellt wird.

    Wieso eine Funktion? Auch wenn sie höchstwahrscheinlich geinlined wird (oder zumindest RVO angewandt wird), ist sie unnötig da man gleich die Enumeratoren als Indizen nutzen kann. (Außer du findest es so schöner, das ist natürlich ein Punkt)

    In einem halben Jahr fällt dir auf, dass deine Übersetzungstabelle viel zu unübersichtlich geworden ist oder ein professioneller Übersetzer die Übersetzungen erstellen soll, ohne im Quellcode rumzupfuschen. Dann willst du deine Übersetzungen in einer Datenbank oder einer Konfigurationsdatei oder sonstwo haben. Wenn das Lookup in einer Funktion gekapselt wurde, ist das überhaupt kein Problem. Bei deiner Lösung muss man den halben Quellcode ändern oder komische Spielchen mit Proxys treiben.

    Edit: Denk außerdem an solche Dinge wie beliebig viele Platzhalter in Phrasen.



  • Michael E. schrieb:

    Wieso eine Funktion? Auch wenn sie höchstwahrscheinlich geinlined wird (oder zumindest RVO angewandt wird), ist sie unnötig da man gleich die Enumeratoren als Indizen nutzen kann. (Außer du findest es so schöner, das ist natürlich ein Punkt)

    In einem halben Jahr fällt dir auf, dass deine Übersetzungstabelle viel zu unübersichtlich geworden ist oder ein professioneller Übersetzer die Übersetzungen erstellen soll, ohne im Quellcode rumzupfuschen. Dann willst du deine Übersetzungen in einer Datenbank oder einer Konfigurationsdatei oder sonstwo haben. Wenn das Lookup in einer Funktion gekapselt wurde, ist das überhaupt kein Problem. Bei deiner Lösung muss man den halben Quellcode ändern oder komische Spielchen mit Proxys treiben.

    Edit: Denk außerdem an solche Dinge wie beliebig viele Platzhalter in Phrasen.

    Du könntest dann das Array wegschmeißen, eine Klasse mit demselben Namen Definieren und für die dann geschickt den Indizoperator überladen 🕶 , aber gut - das ist natürlich lächerlich viel Aufwand. Kapseln klingt gut.

    Edit: Obige Idee fällt unter "komische Spielchen mit Proxys", richtig?



  • Hacker schrieb:

    Edit: Obige Idee fällt unter "komische Spielchen mit Proxys", richtig?

    Ja.



  • Mit ein wenig Abstraktion und in C**++**:

    #include <array>
    #include <string>
    #include <istream>
    #include <iostream>
    
    namespace example
    {
    	struct Language
    	{
    		enum TextId
    		{
    			HelloWorld,
    			//...
    
    			Count_,
    		};
    
    		typedef std::array<std::string, Count_> Texts;
    
    		Texts texts;
    	};
    
    	static bool loadLanguage(std::istream &file, Language &language)
    	{
    		for (auto i = begin(language.texts); i != end(language.texts); ++i)
    		{
    			getline(file, *i);
    		}
    		return file.good();
    	}
    
    	static void printHelloWorld(std::ostream &out, const Language &lang)
    	{
    		out << lang.texts[Language::HelloWorld] << "\n";
    	}
    }
    
    int main()
    {
    	using namespace example;
    
    	const Language builtinGerman =
    	{{{
    		"Hallo, Welt", //HelloWorld
    	}}};
    
    	printHelloWorld(std::cout, builtinGerman);
    }
    

Anmelden zum Antworten