boost::locale::translate und umlaute



  • @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().



  • @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).


Anmelden zum Antworten