boost::locale::translate und umlaute



  • @yahendrik

    Ja das war klar. Aber das wollte ich gar nicht wissen.

    Egal. Nochmals zu dem was nun noch nicht klar ist:

    • 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. Dann bräuchte ich doch kein Unicode?

    Bei Wikipedia steht übrigens:
    Die wichtigsten Vertreter von MBCS sind: UTF-8, UTF-16, UTF-7, Shift-JIS, Big5 und GB2312. ??

    Dachte UTF-16 wäre Unicode!



  • Ist es.

    Multibyte kann auch single-byte sein. wchar_t ist laut der msdn unicode also zwei bytes.

    Was du willst sind wide characters, also wstring. Und wenn die standard Exception-Klassen keine überladungen dafür implementieren kannst du auch einfach eine eigene klasse schreiben.



  • wo liegt jetzt der Unterschied zwischen Multibyte und Unicode

    Multibyte sind mehrere Bytes
    Unicode sind auch mehrere Bytes.

    Und wieso will ich wstring?

    Wenn ich einen std::string anlege und darin umlaute speicher werden die auch angezeigt im Visual Studio debugger.


  • Administrator

    Vielleicht müsste man hier klarstellen, dass du von der Multibyte Einstellung in Visual Studio redest? Weil Visual Studio meint damit die Multi Byte Character Sets (MBCS) von Windows. Das sind Windows spezifische 1 bis 2 Byte pro Zeichen Enkodierungen. Windows selbst betrachtet dies als Legacy und empfiehlt heutzutage Unicode zu verwenden.

    MBCS ist eben Windows spezifisch, kann bis zu zwei Bytes pro Zeichen verwenden. Es ist dann aber weiterhin nötig ein Character Set zu verwenden. Du hast MBCS für westeuropäisch, koreanisch, japanisch, usw. Und die sind nicht zueinander kompatibel. Es war eine temporäre Übergangslösung, um Sprachen zu ermöglichen, welche mehr als 255 Zeichen benötigen.

    Unicode dagegen hat ein Character Set. Unicode. Fertig. Unicode unterstützt aber mehrere Möglichkeiten, wie man es enkodiert. UTF-16 verwendet 2 oder 4 Bytes pro Zeichen. UTF-8 hat 1 bis 4 (?) Bytes pro Zeichen. Windows empfiehlt heutzutage UTF-16 zu verwenden. Da UTF-16 mindestens 2 Bytes benötigt, verwendet man dafür unter Windows wchar_t und somit std::wstring.

    Ist das einigermassen verständlich?



  • Die Unterschiede werden in Unicode and MBCS sowie Unicode and Multibyte Character Set (MBCS) Support beschrieben.

    Lies aber auch mal VisualStudio: MultiByte vs Unicode.

    Die Definition in Wikipedia bzgl. MBCS und DBCS entspricht also (strenggenommen) nicht dem, was MS unter "MBCS" versteht (1 oder 2 Bytes per Zeichen, daher char als Basis für TCHAR), also der älteren Definition wie in Double Byte Character Set erwähnt.

    Und bei "UNICODE" wird UTF-16 aktiviert (daher wchar_t).



  • @Dravere

    Hi danke für deine Erklärung. Das hilf mir schon etwas weiter.

    Aber weiterhin unklar:

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

    Windows empfiehlt heutzutage UTF-16 zu verwenden. Da UTF-16 mindestens 2 Bytes benötigt, verwendet man dafür unter Windows wchar_t und somit std::wstring.

    Überall wir zur Verwendung von Unicode geraten. So auch die Einstellung wenn ich ein neues Projekt in Visual Studio anlege.
    Und wenn Unicode dann auch wchar_t bzw wstring verwenden.

    Nur egal wo ist std::string immer noch überall standard.
    Sei es bei Beispielen im Internet, bei irgendwelchem Bibliotheken die ich mir von github ziehe. Und sogar in der std::exception wird string verwendet.

    Es ist allso extrem schwierig sein Programm auf wstring umzustellen.



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

    Es ist allso extrem schwierig sein Programm auf wstring umzustellen.

    Ich würde bei plattform-agnostischen Projekten eher dazu tendieren bei UTF-8 zu bleiben und an den Schnittstellen zu Windows nach UTF-16 zu konvertieren - wo das ist, siehst du ja dann an den Fehlermeldungen, wenn du auf die Windows-Funktionen mit dem W-Suffix umstellst. Besonders wenn du schon solche Bibliotheken wie GNU Gettext verwendest macht das Sinn. Bei den meisten nicht-windows-spezifischen Bibliotheken ist ohnehin eher UTF-8 verbreitet, wenn man mal z.B. von ICU absieht.

    Da du allerdings auch MFC und CString erwähnst, ist nicht ganz klar, ob es sich bei dir nicht doch um ein reines Windows-Projekt handelt. Wenn du mehr WinAPI-Calls als Aufrufe anderer Bibliotheken hast, dann ist der wchar-Weg vielleicht doch nicht verkehrt.

    Konvertierten wirst du so oder so müssen, fragt sich nur an welcher Schnittstelle - WinAPI oder Gettext und andere Libs.
    Choose your poison 😉


  • Administrator

    @booster Weil ausserhalb von Windows verwenden sehr viele (alle?) UTF-8. Viele der englischen Beispiele sind zudem äussert einfach in UTF-8 zu erklären, da keine Sonderzeichen vorkommen. Damit entspricht ein Byte noch einem Zeichen. So kann man die ganze Komplexität von Unicode und Textenkodierung am Anfang auslassen.

    Ob du nun UTF-16 und std::wstring oder UTF-8 und std::string verwendest, kommt, wie Finnegan sagt, sehr auf deine Anwendung an. Wenn du sowieso auf Windows unterwegs bist, die MFC und WinAPI einsetzt, dann geh mit UTF-16 und std::wstring. Ansonsten prüfe, ob du entweder mit UTF-8 oder mit einer sich dynamisch anpassenden Konfiguration gehst, welche automatisch je nach Plattform zwischen UTF-8 und UTF-16 umschaltet.



  • @Dravere

    Also ich passe die Anwendung gerade an und habe auf MFC komplett verzichtet. WinApi wird an einigen Stellen noch verwendet.
    Die Applikation die die Meldungen darstellt ist momentan noch in MFC programmiert wird in Zukunft aber geändert.

    Ich würde am liebsten auf UTF-8 bleiben. Meine Anwendung hat bisher ja auch mit den Umlauten funktioniert.
    Das liegt wohl jetzt nur daran dass gettext bzw boost::locale::translate das falsch codiert.

    wobei ich wieder bei meiner Ausgangsfrage wäre 🙂



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

    Ich würde am liebsten auf UTF-8 bleiben. Meine Anwendung hat bisher ja auch mit den Umlauten funktioniert.
    Das liegt wohl jetzt nur daran dass gettext bzw boost::locale::translate das falsch codiert.

    An Umlauten würde ich das nicht unbedingt festmachen. Es ist gut möglich, dass deine Quellcode-Dateien wie auch die char*-basierte Textausgabe der WinAPI-Funktionen z.B. die Windows-1252-Codepage verwenden. Das ist eine erweitere ASCII 1-Byte-Zeichenkodierung, die in den höheren Bytes zusätzlich Sonderzeichen westeuropäischer Sprachen wie eben auch Umlaute enthält. Auf Systemen mit einem anderen Default-Zeichensatz würde dein "funktioniert" dann sehr schnell relativiert.

    Wie sind denn deine Quellcode-Dateien in Visual Studio codiert? Für durchgängiges UTF-8 würde ich da die Einstellung Unicode (UTF-8 without signature) - Codepage 65001 empfehlen (siehe auch hier).



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

    @Dravere

    Also ich passe die Anwendung gerade an und habe auf MFC komplett verzichtet. WinApi wird an einigen Stellen noch verwendet.
    Die Applikation die die Meldungen darstellt ist momentan noch in MFC programmiert wird in Zukunft aber geändert.

    Ich würde am liebsten auf UTF-8 bleiben. Meine Anwendung hat bisher ja auch mit den Umlauten funktioniert.
    Das liegt wohl jetzt nur daran dass gettext bzw boost::locale::translate das falsch codiert.

    wobei ich wieder bei meiner Ausgangsfrage wäre 🙂

    Sicher das gettext/boost::locale::translate das problem ist? Und wie kommst du darauf?
    Wenn die gettext files utf-8 codiert sind, dann lies mal eine Übersetzung mit umlauten als std::string ein. Und dann schau dir mal die "byte" werte der einzelnen chars an (z.b. in hexadezimaler Darstellung).
    Wenn kein kodierungsfehler auftritt müssten an den stellen für die Umlaute folgende 2 byte folgen auftauchen:
    Ä (0xc3 0x84)
    Ö (0xc3 0x96)
    Ü (0xc3 0x9c)
    ä (0xc3 0xa4)
    ö (0xc3 0xb6)
    ü (0xc3 0xbc)

    Aber prüf vor diesem Test ob die gettext files auch wirklich in UTF-8 kodiert sind (z.b. mit notepad++). Ein "charset=UTF-8"" im .po file reicht nicht.
    Mit welchen tool wurden die .po files erstellt?

    Das Problem ist unter winows kann z.b. die "console" initial nichts mit UTF-8 anfangen und dadurch ist eine simple ausgabe zur überprüfung nicht möglich,
    AFAIK hat der debugger von VisualStudio das gleiche Problem



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

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

    Ich würde am liebsten auf UTF-8 bleiben. Meine Anwendung hat bisher ja auch mit den Umlauten funktioniert.
    Das liegt wohl jetzt nur daran dass gettext bzw boost::locale::translate das falsch codiert.

    An Umlauten würde ich das nicht unbedingt festmachen. Es ist gut möglich, dass deine Quellcode-Dateien wie auch die char*-basierte Textausgabe der WinAPI-Funktionen z.B. die Windows-1252-Codepage verwenden. Das ist eine erweitere ASCII 1-Byte-Zeichenkodierung, die in den höheren Bytes zusätzlich Sonderzeichen westeuropäischer Sprachen wie eben auch Umlaute enthält. Auf Systemen mit einem anderen Default-Zeichensatz würde dein "funktioniert" dann sehr schnell relativiert.

    Wie sind denn deine Quellcode-Dateien in Visual Studio codiert? Für durchgängiges UTF-8 würde ich da die Einstellung Unicode (UTF-8 without signature) - Codepage 65001 empfehlen (siehe auch hier).

    Ist nur relevant, wenn im quellcode selbst non ascii zeichen vorkommen. Da für die Übersetzung gettext (via boost::locale:translate) verwendet wird sollte es in diesem Falle kein Problem sein



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

    Sicher das gettext/boost::locale::translate das problem ist? Und wie kommst du darauf?

    Wenn ich std::string = "ÜÄÖ"; schreibe sehe ich im debugger als auch in meiner Ausgabe "ÜÄÖ"
    mein string hat in dem Fall 6 Bytes

    Ü = 0xdc
    Ö = 0xd6
    Ä = 0xc4

    ü = 0xfc
    ö = 0xf6
    ä = 0xe4

    wenn ich std::string = boost::locale::translate("Umlaute"); schreibe erhalte ich im debugger als auch in der Ausgabe irgenwelche Sonderzeichen.
    mein string hat dann 12 bytes und die von dir gezeigten werte.

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

    Aber prüf vor diesem Test ob die gettext files auch wirklich in UTF-8 kodiert sind (z.b. mit notepad++). Ein "charset=UTF-8"" im .po file reicht nicht.
    Mit welchen tool wurden die .po files erstellt?

    Die .po Files wurden mit PoEdit erstellt. Die Files sind auf UTF-8 eingestellt. Kontrolliert mit Visual Studio Code.



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

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

    Sicher das gettext/boost::locale::translate das problem ist? Und wie kommst du darauf?

    Wenn ich std::string = "ÜÄÖ"; schreibe sehe ich im debugger als auch in meiner Ausgabe "ÜÄÖ"
    mein string hat in dem Fall 6 Bytes

    Ü = 0xdc
    Ö = 0xd6
    Ä = 0xc4

    ü = 0xfc
    ö = 0xf6
    ä = 0xe4

    Dann sind die Zeichen nicht in UTF-8 codiert. Sie post von @Finnegan

    wenn ich std::string = boost::locale::translate("Umlaute"); schreibe erhalte ich im debugger als auch in der Ausgabe irgenwelche Sonderzeichen.
    mein string hat dann 12 bytes und die von dir gezeigten werte.

    Ok gut, dann macht boost locale alles richtig und auch die po files sind in UTF-8 kodiert.
    Das du nur komische zeichen im Debugger und in der Ausgabe siehst liegt daran, dass der Debugger und die Ausgabe unter Windows bei default kein UTF-8 kann.
    Hierfür muss dann vorher das ganze nach UTF-16 umkodiert werden damit es unter Windows funktioniert.

    Für ein Test consolen programm siehe folgenden hinweis aus der boost locale dokumentation bezüglich UTF-8 und windows:
    https://www.boost.org/doc/libs/1_50_0/libs/locale/doc/html/running_examples_under_windows.html

    Hier eine gute Beschreibung wenn man intern in C++ UTF-8 für strings verwenden möchte und die Probleme unter windows und mögliche Lösungen:

    http://www.nubaria.com/en/blog/?p=289

    Wenn es ein reines windows projekt ist, dann wäre es günstiger alle strings in UTF-16 zu verwenden, dann gibt es keine Darstellungsprobleme unter windows.



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

    Ist nur relevant, wenn im quellcode selbst non ascii zeichen vorkommen. Da für die Übersetzung gettext (via boost::locale:translate) verwendet wird sollte es in diesem Falle kein Problem sein

    Das stimmt zwar, allerdings sprach ich von durchgängigem UTF-8, was in jedem Fall zu empfehlen ist, wenn man sich schon für UTF-8 entscheidet. Man spart sich unter Umständen eine Menge Ärger, wenn man sicherstellt, dass auch die im Quellcode definierten Strings die selbe Codierung verwenden - auch wenn man separate Übersetzungs-Dateien verwendet können durchaus auch mal Sonderzeichen im Code auftauchen - z.B. für sprachunabhängige Symbole ("✓" verwende ich z.B. schonmal ganz gerne um erfolgreich abgeschlossene Aktionen zu markieren).

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

    wenn ich std::string = boost::locale::translate("Umlaute"); schreibe erhalte ich im debugger als auch in der Ausgabe irgenwelche Sonderzeichen.

    Der VS-Debugger scheint das UTF-8 nicht automatisch zu erkennen, auch nicht wenn die Quellcode-Datei selbst als UTF-8 gespeichert wurde. Für Watch-Variablen gibt es aber sog. Format Specifier mit dem man dem Debugger u.a. verklickern kann, dass er den std::string oder auch einen char* interpretieren soll. Zumindest in VS2017 funktioniert das recht gut:

    std::string s = "äöüシ✓";
    

    Wenn man hier eine Watch-Variable mit dem s8-Specifier anlegt, also mit nem Namen s,s8, dann wird dort der String im Debugger exakt so wie im Code angegeben dargestellt (Quellcode-Datei als UTF-8 without signature gespeichert). Leider nur für Watch-Variablen, nicht für Autos, Locals oder im Tooltip des Variablennamens im Quellcode (Vielleicht gibt es ja irgendwo einen projektbezogenen Default-Specifier, das wäre fein, aber dazu habe ich leider nichts finden können).



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

    Wenn es ein reines windows projekt ist, dann wäre es günstiger alle strings in UTF-16 zu verwenden, dann gibt es keine Darstellungsprobleme unter windows.

    Und wie mache ich das.

    Mein .po file UTF-16 codieren ??

    Der Quellcode selber ist Windows 1252 codiert. Das sagt mir der Visual Studio code. Das muss ich auch auf UTF-16 umstellen?
    Wo geht das im Visual Studio?



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

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

    Wenn es ein reines windows projekt ist, dann wäre es günstiger alle strings in UTF-16 zu verwenden, dann gibt es keine Darstellungsprobleme unter windows.

    Und wie mache ich das.

    Mein .po file UTF-16 codieren ??

    Wäre eine möglichkeit, die andere, die ich mir vorstellen kann ist dass boost::locale::translatestd::wstring() die konvertierung von UTF-8 nach UTF-16 selbst vornimmt.

    Der Quellcode selber ist Windows 1252 codiert. Das sagt mir der Visual Studio code. Das muss ich auch auf UTF-16 umstellen?
    Wo geht das im Visual Studio?

    In dem du einfach einen string literal statt "string" so schreibst L"string", dann wird das string literal automatisch vom compiler als wide char (unter windows ist es dann UTF-16) interpretiert.

    Zusätzlich musst da dabei deine Projekte von MultiByte CharacterSet auf Unicode umgestellt werden, damit auch die ganzen WinAPI funktionen (ohne A/W Zusatz) Unicode verwenden.

    Intern UTF-8 zu verwenden wäre die Portablere variante, da die meisten non Windows system UTF-8 verwenden.
    Nur halt mit den schon beschriebenen Problemen unter Windows/Visual Studio



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

    Mein .po file UTF-16 codieren ??

    Der Quellcode selber ist Windows 1252 codiert. Das sagt mir der Visual Studio code. Das muss ich auch auf UTF-16 umstellen?
    Wo geht das im Visual Studio?

    Hast du nicht vor eine Weile noch sowas hier geschrieben?

    Also ich passe die Anwendung gerade an und habe auf MFC komplett verzichtet. WinApi wird an einigen Stellen noch verwendet. [...]
    Ich würde am liebsten auf UTF-8 bleiben.

    Ich denke das wichtigste ist erstmal dass du dir klar wirst, welche Codierung du eigentlich verwenden willst und dann bei dieser bleibst und sie konsequent durchziehst. Den halben Code ändern und sich dann wieder umentscheiden wird die Probleme mit den falschen Zeichen wohl eher verstärken 😉



  • 🙂 Du hast recht Finnegan

    Also nochmals zusammengefasst.
    Ich versuche nicht auf Microsoft Erweiterungen zu setzen. Also auf MFC zu verzichten.
    Nichts desto trotz bleibt die Anwendung auf Windows.

    Ich würde am liebsten auf UTF-8 bleiben.

    Nun ja, damit wollte ich eigentlich nur sagen dass ich nicht auf Unicode bzw widestring umstellen möchte.

    Verstehe ich das richtig.

    • Für UTF-8 benötige ich 2 Bytes um meine Zeichen darzustellen. Das ist das was mir gettext liefert.
    • Wenn ich einen string direkt im code anlege wird mir ein zeichen als 1 byte abgelegt. Was ich nicht ganz verstehe. Es ist doch Multibyte Character Set eingestellt. Also wie ich hier jetzt gelernt habe mehrere bytes um 1 Character dar zu stellen.

    Also was ich nicht verstehe.
    Was passiert in dem Fall wenn ich einen std::string direkt im Code setze. Wieso wird dann ein einzelnes Zeichen nur als 1 Byte dargestellt.
    Das ist ja dann nicht mehr UTF-8. UTF-16 kann es ja auch nicht sein. Dazu bräuchte ich ja ein wstring?



  • Wenn du im Code UTF-8 Literale erzeugen wilst, dann schreib u8"literal string". Wenn dann der Compiler das Encoding des Source-Files kennt, dann kann er daraus UTF-8 Literals erzeugen. Egal ob das Encoding des Source-Files jetzt UTF-8 ist oder etwas anderes.

    Aber Achtung: es kann sein dass du beim Switch auf C++20 dann ein paar Sachen anpassen musst. Gibt nämlich ein Proposal dass u8 Literale nicht mehr char sondern char8_t sein sollen. Was dann ein neuer Typ ist, was dann bedeutet dass man entsprechend casten oder kopieren muss, oder halt std::u8string statt std::string verwenden.


Anmelden zum Antworten