boost::locale::translate und umlaute



  • Hallo

    In meinem Projekt verwende ich gnu gettext in verbindung mit boost::locale::translate.
    Nun habe ich allerdings das Problem dass meine Umlaute nicht richtig dargestellt werden.

    Und habe keine Ahnung woran das liegt.

    Zur Information

    Plattform: Win32
    Character Set: Multi Byte

    Code:

    shared_ptr<boost::locale::generator> _localeGenerator;
    
    void InitLocale()
    {
        if( _localeGenerator) return;
         _localeGenerator = make_shared<boost::locale::generator>();
        std::filsystem::path path =  "C:/Projekte/MyProject/locale";
    
        _localeGenerator->add_messages_path(path.string());
        _localeGenerator->add_messages_domain("MyProject");
        const auto baselocale = _localeGenerator->generate("");
    
        locale::global(baselocale);
    }
    
    void main()
    {
        InitLocale();
        auto message =  boost::locale::translate("message with special characters");
    }
    


  • Versuch doch mal wstring.



  • Wie sind die texte codiert? Unicode (Da UTF-8, UTF-16) oder ANSI?



  • du meinst so.

    auto message =  boost::locale::translate<wchar_t>("message with special characters");
    

    Ja das geht. Danke. Aber das bringt mir im Code dann noch einige andere Probleme.

    zum beispiel das hier

    throw runtime_error(message)
    


  • @firefly sagte in boost::locale::translate und umlaute:

    Wie sind die texte codiert? Unicode (Da UTF-8, UTF-16) oder ANSI?

    In .po File ist "charset=UTF-8" eingestellt



  • Wie stellst du die texte dar?
    Denn die API unter windows kennt an vielen stellen kein UTF-8 sondern nur UTF-18 (wchar_t als datentyp für strings)



  • @firefly sagte in boost::locale::translate und umlaute:

    Wie stellst du die texte dar?

    Wird mit SendMessage aus WinUser.h an eine andere Applikation (MFC mit CString) gesendet

    @firefly sagte in boost::locale::translate und umlaute:

    UTF-18 (wchar_t als datentyp für strings)

    Du meinst UTF-16?



  • @booster sagte in boost::locale::translate und umlaute:

    Wird mit SendMessage aus WinUser.h an eine andere Applikation (MFC mit CString) gesendet

    Dann würde ich SendMessageW verwenden und L"texttexttext" Literale (die auf Windows UTF-16 sind).

    Wenn du Texte aus einem File lesen willst, dann kommt es darauf an wie dieses kodiert ist. Auf Windows kannst du aber auf jeden Fall MultiByteToWideChar verwenden um 8-Bit kodierte Strings nach UTF-16 zu konvertieren. Du musst dabei natürlich die passende 8-Bit CodePage mitgeben - eben abhängig davon was für ein Encoding das File verwendet. (Bzw. was für ein Encoding du von gettext zurückbekommst, aber ich nehme an dass das 1:1 dem entspricht was im File drinnen steht.)



  • @booster sagte in boost::locale::translate und umlaute:

    @firefly sagte in boost::locale::translate und umlaute:

    Wie stellst du die texte dar?

    Wird mit SendMessage aus WinUser.h an eine andere Applikation (MFC mit CString) gesendet

    @firefly sagte in boost::locale::translate und umlaute:

    UTF-18 (wchar_t als datentyp für strings)

    Du meinst UTF-16?

    Ja stimmt ist ein vertipper 🙂



  • @hustbaer sagte in boost::locale::translate und umlaute:

    Dann würde ich SendMessageW verwenden und L"texttexttext" Literale (die auf Windows UTF-16 sind).

    Das war doch jetzt gar nicht die Frage. Habe ich ja nur geschreiben weil firefly gefragt hat wo ich das darstelle.

    @hustbaer sagte in boost::locale::translate und umlaute:

    Wenn du Texte aus einem File lesen willst, dann kommt es darauf an wie dieses kodiert ist. Auf Windows kannst du aber auf jeden Fall MultiByteToWideChar verwenden um 8-Bit kodierte Strings nach UTF-16 zu konvertieren.

    Bin eigentlich dran die Microsoft Erweiterungen zu vermeiden. Es sollte aber auch kein Problem sein das File auf UTF-16 umzustellen

    Eigentlich sollte ich im Programm auf Unicode Character Set umstellen. Das hat aber hinreichende Änderungen in meinem Programm zur Folge.



  • @booster sagte in boost::locale::translate und umlaute:

    @hustbaer sagte in boost::locale::translate und umlaute:

    Dann würde ich SendMessageW verwenden und L"texttexttext" Literale (die auf Windows UTF-16 sind).

    Das war doch jetzt gar nicht die Frage. Habe ich ja nur geschreiben weil firefly gefragt hat wo ich das darstelle.

    Doch, da du eine Frage über ein Darstellungsproblem gestellt hast. Und da ist es wichtig zu wissen wo die Darstellung erfolgt und wie die Daten da hin kommen.
    @booster:

    Nun habe ich allerdings das Problem dass meine Umlaute nicht richtig dargestellt werden.

    Und SendMessage (bei Multi Byte Character Set ist es SendMessageA) kann nur mit ASCII/ANSI zeichen umgehen.
    Bzw. der Empfänger der Nachricht wird den String als ASCII/ANSI kodiert ansehen und nicht als Unicode.
    Ist die Empfänger Applikation (MFC mit CString) auch auf Multi Byte Character set eingestellt? Wenn ja, dann ist CString = CStringA und kann kein Unicode. Sonder du musst CStringW (CString ist ein CStringW, wenn Character Set = UNICODE) verwenden.

    Wenn beide Applikationen "Multi Byte" sein müssen, dann musst du den Uncode String in die lokale codepage (ANSI codepage) umwandeln und dann mit SendMessageA an die andere Applikation senden.



  • Danke für deine Erläuterung.

    Ich glaube ich habe noch nicht genau verstanden was die Umstellung von MultiByte auf Unicode im Visual Studio bewirkt.

    Wenn ich auf Unicode Umstelle werden die Funktionen mit dem zusatz W verwendet anstatt mit dem Zusatz A.
    Also widestring statt Ansi. Ist das korrekt?

    was ist mit meinen strings. Muss ich nun alles als wstring kennzeichnen?



  • @booster sagte in boost::locale::translate und umlaute:

    Danke für deine Erläuterung.

    Ich glaube ich habe noch nicht genau verstanden was die Umstellung von MultiByte auf Unicode im Visual Studio bewirkt.

    Wenn ich auf Unicode Umstelle werden die Funktionen mit dem zusatz W verwendet anstatt mit dem Zusatz A.
    Also widestring statt Ansi. Ist das korrekt?

    Wenn du die Funktionen ohne A/W zusatz verwendest, dann wird bei MultiByte die A variante und bei Unicode die W variante verwendet. Die Funktionen ohne diesen Zusatz (z.b. SendMessage) sind nur Aliase (als macro definiert) für die A/W varianten (z.b. SendMessageA/SendMessageW)

    was ist mit meinen strings. Muss ich nun alles als wstring kennzeichnen?
    Meinst du hartcodierte Strings? Ja die müssen bei UNICODE als "wstring" gekennzeichnet werden. Es gibt ein Macro mit der Bezeichnung TEXT (https://docs.microsoft.com/en-us/windows/desktop/api/winnt/nf-winnt-text), welche das ganze passend handhabt.

    Eingelesene strings müssen nach UTF-16 konvertiert (bevor diese an z.b. SendMessageW übergeben werden können) werden (via MultiByteToWideChar), falls diese nicht schon als UTF-16 eingelesen werden.



  • @firefly sagte in boost::locale::translate und umlaute:

    Wenn du die Funktionen ohne A/W zusatz verwendest, dann wird bei MultiByte die A variante und bei Unicode die W variante verwendet. Die Funktionen ohne diesen Zusatz (z.b. SendMessage) sind nur Aliase (als macro definiert) für die A/W varianten (z.b. SendMessageA/SendMessageW)

    Ja das meinte ich. Das war ja meine Frage. Ist das alles was passiert wenn ich von Multibyte auf Unicode umstelle?

    Also der datentyp std::string bassiert weiterhin auf char. Bei CString von microsoft ist das anders.



  • muss ich nun im ganzen Code auf wstring umstellen?



  • @booster sagte in boost::locale::translate und umlaute:

    Ja das meinte ich. Das war ja meine Frage. Ist das alles was passiert wenn ich von Multibyte auf Unicode umstelle?

    Probiers doch einmal aus. Intern in der WinApi wird ohnehin alles nach UTF-16 codiert. Wahrscheinlich wirst du mit Fehlermeldungen zugeschüttet werden.
    Prinzipiell ist es immer eine gute Idee (wenn nicht sofort alles auf UNICODE gesetzt wird) eine Konfiguration auf MultiByte, die andere auf UNICODE zu stellen (bspw. Debug->UNICODE, Release->MultiByte).

    Alles was std::string ist und irgendwie mit der WinApi zu tun hat, sollte ebenfalls angepasst sein:

    typedef std::basic_string<TCHAR> tstring;
    

    Bei großen Projekten bedeutet die Umstellung leider ziemlich viel Arbeit, da immer geschaut werden muss, ob die Unterscheidung notwendig und nicht fehlerhaft ist. Ein find and replace in allen Dateien funktioniert nicht.



  • Ja ich werde mit Fehlermeldungen zugeschüttet. Darum die Frage kann ich nicht bei Multibyte Character Set bleiben. Und trotzdem Umlaute verwenden.
    Wieso heißt das überhaupt Multibyte. Multibyte heißt doch mehrere Bytes verwenden um ein Zeichen zu codieren.

    @yahendrik sagte in boost::locale::translate und umlaute:

    Alles was std::string ist und irgendwie mit der WinApi zu tun hat, sollte ebenfalls angepasst sein:
    typedef std::basic_string<TCHAR> tstring;

    std::string ist doch ein typedef auf std::basic_string<char> also wird es ja nicht angepasst.



  • @booster Da steht TCHAR, nicht char.



  • @yahendrik sagte in boost::locale::translate und umlaute:

    Da steht TCHAR, nicht char.

    Ja das habe ich schon gesehen. Und da steht auch tstring.
    Aber im Satz vor dem typedef sagst du std::string

    Also std::string wird nicht angepasst da std::string<char>
    und tstring wird nach deiner definition angepasst. Aber das verwende ich ja nirgends.



  • Beispiel:
    Vorher

    std::string s="Windowtext";
    SetWindowText(wnd, s.c_str());
    

    ->

    tstring s=TEXT("WindowText");
    SetWindowText(wnd, s.c_str());
    

    Wenn UNICODE definiert ist, wird SetWindowTextW mit wstring::c_str() aufgerufen, sonst SetWindowTextA mit string::c_str().