llll  
ll  
TU WSTAW TEKST

Kodowanie Unicode w bibliotece Qt 2.*

Ci, którzy zaczynają programować w Qt będą zaskoczeni widokiem znaków zapytania, jakie pojawiły się w napisanych przez nich aplikacjach. Załóżmy, że w naszym komputerze jest zainstalowany Linux (dowolna dystrybucja), KDE 2.*, Qt 2.* i pakiet kde-i18n-pl, dzięki któremu KDE jest spolonizowane. Poniżej umieszczono kod żródłowy programu pr1 :

1   #include <qapplication.h>
2   #include <qlabel.h>
3
4   int main( int argc, char** argv )
5   {
6     QApplication app( argc, argv ) ;
7     QLabel* l = new QLabel( "Gżegżółka", 0 ) ;
8     l->show() ;
9     app.setMainWidget( l ) ;
10    return app.exec() ;
11  }
  

Kompilujemy go :

    g++ -o pr1 -I$QTDIR/include -L$QTDIR/lib -lqt pr1.cpp  
  

Po pomyślnym skompilowaniu, uruchamiamy program :

Rozmiar: 2156 bajtów

W tekście programu użyto polskich liter ale po jego skompilowaniu i uruchomieniu pojawiły się znaki zapytania. W bibliotece Qt (począwszy od jej wersji 2.0) obiekty klasy QString przechowują napisy kodowane metodą Unicode, gdzie każdy znak jest reprezentowany przez "dwubajtową" liczbę. W takim obiekcie przechowywana jest także długość tego napisu. Widgety często wyświetlają napisy, które są im przekazywane jako obiekty QString. Na przykład deklaracja konstruktora widgetu QLabel wygląda następująco:

  QLabel( const QString & text, QWidget * parent, 
           const char * name=0, WFlags f=0 )
  
W wierszu nr 7 wywołuje się konstruktor klasy QLabel i jego pierwszym argumentem jest obiekt typu char*. QLabel nie ma konstruktora, który jako argument może przyjąć zmienną typu char*. Aby wywołanie konstruktora się powiodło, kompilator musi dokonać niejawnej konwersji typu. W tym celu tworzy obiekt chwilowy QString a używa do tego następującego konstruktora konwertującego:
    QString( const char * str )
  
Cytat z dokumentacji Qt:
    ...This is a cast constructor, but it is perfectly safe: 
	converting a Latin1 const char* to QString preserves all 
	the information...
  
Jest to moment, w którym napis jest uszkadzany bo zakłada się, że jest on kodowany w standardzie ISO 8859-1 (Latin1), a faktycznie jest kodowany metodą Latin2 (ISO 8859-2). Dekodowanie jest poprawne w przypadku znaków G, e, g, ó, k, a. Ich kody, w ISO8859-1 i w ISO8859-2, są takie same. Kod litery "ż" z ISO 8859-2 reprezentuje, w ISO 8859-1, znak o innym wyglądzie. Podobnie jest ze znakiem "ł".

Przy uruchamianiu programu napisy są ponownie kodowane ale tym razem z Unicode do standardu ISO 8859-2 (zgodnie z wartością przechowywaną w zmiennej środowiska LANG). Niestety, w zbiorze znaków, kodowanych metodą ISO 8859-2, nie ma znaków (179 i 191) kodowanych metodą ISO 8859-1. W takim przypadku, w miejsce nie znalezionych liter, Qt - standardowo - wstawia znak zapytania.

Aby program poprawnie wyświetlał polskie litery, należy go nieco zmodyfikować:


    1   #include <qapplication.h>
    2   #include <qlabel.h>
    3   #include <qstring.h>
    4
    5   int main( int argc, char** argv )
    6   {
    7     QApplication app( argc, argv ) ;
    8     QString str = QString::fromLocal8Bit( "Gżegżółka" ) ;
    9     QLabel* l = new QLabel( str, 0 ) ;
   10     l->show() ;
   11     app.setMainWidget( l ) ;
   12     return app.exec() ;
   13   }
  
Dodano nowy wiersz o numerze 8, w którym wywołuje się statyczną metodę klasy QString, poprawnie dekodującą napis z ISO 8859-2 do Unicode. Kodowanie napisu zostanie określone na podstawie zmiennej środowiska LANG. Metoda fromLocal8Bit dokonuje konwersji kodowania napisów z tradycyjnego 8-bitowego do kodowania Unicode.

Po skompilowaniu drugiego programu o nazwie pr2 i uruchomieniu, otrzymuje się:

Rozmiar: 2193 bajtów

Jak widać problem został rozwiązany ale, mimo wszystko, nie jest to rozwiązanie optymalne. Zmiana napisu wyświetlanego w widgecie QLabel wymaga ponownej kompilacji programu. Ponowna kompilacja będzie również potrzebna, gdy z naszego programu zechcą skorzystać użytkownicy posługujący się innym językiem niż polski. Przy pisaniu programów powinno przyjąć się zasadę, że w tekście programu, napisy są w języku angielskim a ich tłumaczenia znajdują się w oddzielnym pliku po. Qt ma specjalną klasę zajmująca się tłumaczeniem napisów. Odpowiednikiem i18n jest (w Qt) tr (ang.translate) - statyczna metoda w klasie QObject, którą można użyć tak jak poniżej :

QLabel* l = new QLabel( QObject::tr("This is an english text"), 0 ) ;
  
Producent biblioteki Qt oferuje specjalne narzędzia do wyszukiwania ,w programie żródłowym, napisów przeznaczonych do tłumaczenia, zamieniający plik .*po w plik *.mo, itd. - findtr, msg2qm, mergetr, Linquist. Odpowiednio przygotowany plik wczytuje się do obiektu klasy QTranslator (za pomocą metody load). Taki obiekt należy jeszcze zarejestrować: QApplication::installTranslator. Od tego momentu, aplikacja powinna pokazywać przetłumaczone napisy.

Autor: Jerzy Skalski
Data 21.03.2001

[ DO GÓRY ]

 
ll
 
 
   
  kde.com.pl