Internacionalização com o Qt

A internacionalização de uma aplicação é o processo de tornar a aplicação utilizável para pessoas de países diferentes do seu. Em alguns casos a internacionalização é simples, por exemplo, tornar uma aplicação dos EUA acessível para usuários Australianos ou Britânicos pode requerer apenas algumas correções de grafia. Mas fazer uma aplicação dos EUA acessível para usuários Japoneses, ou uma aplicação Coreana acessível para usuários Alemães, irá requerer que o software opere não apenas com idiomas diferentes, mas use técnicas de entrada de dados, codificações de caracteres e convenções de apresentação diferentes.

Passo a passo

Escrever um software internacionalizado com o Qt é um processo suave e incremental. Seu software pode torna-se internacionalizado com os seguintes estágios:

Use QString para todos os textos visíveis ao usuário


Como QString usa a codificação Unicode internamente, todos os idiomas do planeta podem ser processados de forma transparente usando operações de processamento de texto familiares. Além disso, como todas as funções do Qt que exibem texto ao usuário usam uma QtString como parâmetro, não há nenhuma conversão de char* para QtString.
As Strings que estão no espaço do programador (como nomes de QObject e textos de formatos de arquivos) não precisam usar QString; o tradicional char* ou a classe QCString será suficiente.
Você praticamente não notará que está usando o Unicode; QString, e QChar são nada mais do que versões mais simples do const char* bruto e do char tradicional do C.
 

Use tr() para todos os textos literais

Em qualquer lugar que seu programa use "quoted text" para texto que será mostrado ao usuário, certifique que ele será processado pela função  QApplication::translate(). Essencialmente tudo que é necessário para conseguir isso é usar QObject::tr(). Por exemplo, assumindo que LoginWidget seja uma sub-classe de QWidget:
 

    LoginWidget::LoginWidget()
    {
        QLabel *label = new QLabel( tr("Password:"), this );
        ...
    }

Isso cobre 99% das strings visíveis ao usuário que você precisará escrever.
Se o texto não for uma função membro de uma sub-classe QObject, use ou a função tr() de uma classe apropriada, ou a função QApplication::translate() diretamente:
 

    void some_global_function( LoginWidget *logwid )
    {
        QLabel *label = new QLabel(
                LoginWidget::tr("Password:"), logwid );
    }
    void same_global_function( LoginWidget *logwid )
    {
        QLabel *label = new QLabel(
                qApp->translate("LoginWidget", "Password:"),
                logwid );
    }

Se você precisar ter texto traduzível completamente fora de uma função, existem duas macros que lhe ajudarão: QT_TR_NOOP() e QT_TRANSLATE_NOOP(). Elas meramente marcam o  texto para extração pelo utilitário lupdate descrito abaixo. Os macros expandem-se no texto apenas (sem o contexto).
Exemplo do QT_TR_NOOP():

    QString FriendlyConversation::greeting( int greet_type )
    {
        static const char* greeting_strings[] = {
            QT_TR_NOOP( "Hello" ),
            QT_TR_NOOP( "Goodbye" )
        };
        return tr( greeting_strings[greet_type] );
    }

Examplo do QT_TRANSLATE_NOOP():

    static const char* greeting_strings[] = {
        QT_TRANSLATE_NOOP( "FriendlyConversation", "Hello" ),
        QT_TRANSLATE_NOOP( "FriendlyConversation", "Goodbye" )
    };
    QString FriendlyConversation::greeting( int greet_type )
    {
        return tr( greeting_strings[greet_type] );
    }
    QString global_greeting( int greet_type )
    {
        return qApp->translate( "FriendlyConversation",
                                greeting_strings[greet_type] );
    }

Se você não desativar a conversão automática de const char* para QString pela compilação de seu software com a macro QT_NO_CAST_ASCII definida, você estará sujeito a pegar qualquer string que esteja faltando. Veja QString::fromLatin1() para mais informações. Desativar  a conversão torna a programação pesada.
Se o idioma fonte de sua aplicação usar caracteres fora do Latin-1, você pode achar QObject::trUtf8() mais conveniente que QObject::tr(), já que tr() depende  de QApplication::defaultCodec(), o que a torna mais frágil do que QObject::trUtf8().

Use QKeySequence() para valores das teclas de atalho

Os valores das teclas de atalho como Ctrl-Q ou Alt-F precisam ser traduzidos também. Se você codificar diretamente CTRL+Key_Q para “Quit” em sua aplicação, os tradutores não serão capazes de sobrecarrega-la. A forma correta de fazer isso é:
 

    QPopupMenu *file = new QPopupMenu( this );
    file->insertItem( tr("&Quit"), this, SLOT(quit()),
                      QKeySequence(tr("Ctrl+Q", "File|Quit")) );

 

Use QString::arg() para argumentos simples

O estilo printf() de inserção de argumentos em strings é frequentemente uma escolhe pobre para texto internacionalizado, por algumas vezes ser necessários alterar a ordem dos argumentos para a tradução. Mesmo assim, as funções QString::arg() oferecem um meio simples para substituir argumentos:

    void FileCopier::showProgress( int done, int total,
                                   const QString& current_file )
    {
        label.setText( tr("%1 of %2 files copied.\nCopying: %3")
                        .arg(done)
                        .arg(total)
                        .arg(current_file) );
    }

 

Produza as traduções

Uma vez que você tenha usado tr() em toda a aplicação, pode começar a produzir as traduções dos textos visíveis ao usuário de seu programa.
O manual do Qt Linguist fornece mais informações sobre as ferramentas de tradução do Qt, Qt Linguistlupdate e lrelease.
A tradução de uma aplicação é um processo de três passos:

  1. Executar lupdate para extrair os textos traduzíveis do código C++ da aplicação, resultando em um arquivo de mensagens para os tradutores (um arquivo *.ts). O utilitário reconhece tanto as construções tr() quanto as macros descritas acima e produz os arquivos *.ts (normalmente um por idioma).
  2. Fornecer traduções para os textos originais no arquivo *.ts, usando o Qt Linguist. Já que os arquivos *.ts estão em formato XML, você pode editá-los a mão.
  3. Executar lrelease para obter um arquivo de mensagem mais leve (um arquivo *.qm) a partir do arquivo *.ts, adequado apenas para o uso final. Você pode enxergar os arquivos *.ts como os arquivos fontes e os arquivos *.qm como os objetos. O tradutor edita os arquivos *.ts, mas os usuários de sua aplicação precisam apenas dos arquivos *.qm. Os dois tipos de arquivos são independentes de plataforma e de locale.

Tipicamente, você repetirá esses passos para cada versão de sua aplicação. O utilitário lupdate faz o melhor que pode para reutilizar as traduções das versões anteriores.
Antes de executar lupdate, você deve preparar um arquivo de projeto. Abaixo segue um exemplo desse arquivo (arquivo com extensão *.pro):
 

    HEADERS         = funnydialog.h \
                      wackywidget.h
    SOURCES         = funnydialog.cpp \
                      main.cpp \
                      wackywidget.cpp
    FORMS           = fancybox.ui
    TRANSLATIONS    = superapp_dk.ts \
                      superapp_fi.ts \
                      superapp_no.ts \
                      superapp_se.ts

Quando você executar lupdate ou lrelease, você precisa fornecer o nome do arquivo do projeto como argumento na linha de comando.
Nesse exemplo, quatro linguagens exóticas são suportadas: Dinamarquês, Finlandês, Norueguês Sueco. Se você usar qmake (ou tmake), você normalmente não precisará de um arquivo extra para o lupdate; seu arquivo de projeto do qmake funcionará bem uma vez que você tenha adicionado as entradas TRANSLATIONS.
Em sua aplicação, você precisa usar QTranslator::load() para carregar os arquivos de tradução apropriados para o idioma do usuário, e instala-los usando QApplication::installTranslator().
Se você estiver usando as ferramentas antigas do Qt (findtr, msg2qm and mergetr), você pode usar qm2ts para converter os seus arquivos *.qm antigos.
Os utilitários linguistlupdate e lrelease estão instalados no diretório $QTDIR/bin. Clique em Help | Manual no Qt Linguist para acessar o manual do usuário; ele contém um tutorial introdutório a essas ferramentas.
Enquanto  esses utilitários oferecem uma maneira conveniente de criar arquivo *.qm, qualquer sistema onde se possa escrever esses arquivos é suficiente. Você pode criar uma aplicação que adicione traduções em um QTranslator com QTranslator::insert() e depois gere um arquivo *qm com QTranslator::save(). Dessa forma as traduções podem vir de qualquer fonte de sua escolha.
O próprio Qt contém cerca de 400 strings que precisarão ser traduzidas nos idiomas alvo. Você encontrará arquivos de traduções para Francês e Alemão no diretório $QTDIR/translations assim como um modelo para a tradução em outros idiomas.
Tipicamente, a função main() de sua aplicação deve parecer com isso:

    int main( int argc, char **argv )
    {
        QApplication app( argc, argv );
        // translation file for Qt
        QTranslator qt( 0 );
        qt.load( QString( "qt_" ) + QTextCodec::locale(), "." );
        app.installTranslator( &qt );
        // translation file for application strings
        QTranslator myapp( 0 );
        myapp.load( QString( "myapp_" ) + QTextCodec::locale(), "." );
        app.installTranslator( &myapp );
        ...
        return app.exec();
    }

 

Suporte para codificações

A classe QTextCodec  e as instalações de QTextStream tornam fácil suportar várias codificações de entrada e saída dos dados do usuário. Quando uma aplicação é iniciada, a localização da máquina determinará a codificação de 8 bits usada quando for lidar com dados de 8 bits – como no caso de seleção de fontes, exibição de texto, entrada/saída de texto de 8 bits e entrada de caracteres.
A aplicação pode ocasionalmente precisar de outras codificações além da padrão de 8 bits. Por exemplo, uma aplicação em um idioma Cyrillic KOI8-R (o padrão na Rússia) precisaria de uma saída em Cyrillic na codificação ISO 8859-5. O código para isso deve ser:

    QString string = ...; // some Unicode text
    QTextCodec* codec = QTextCodec::codecForName( "ISO 8859-5" );
    QCString encoded_string = codec->fromUnicode( string );
    ...; // use encoded_string in 8-bit operations

Para converter de Unicode para a codificação local em 8 bits, um atalho está disponível: o método local8Bit() de QString retorna cada dado de 8 bits. Outro atalho útil é o método utf8(), que retorna o texto na codificação UTF-8 – o interessante nisso é que preserva perfeitamente a informação em Unicode enquanto parece com US-ASCII plano se o texto em Unicode for inteiramente US-ASCII.
Para a conversão inversa, existem as funções QString::fromUtf8() e QString::fromLocal8Bit(), ou o código geral, demonstrado por essa conversão de ISO 8859-5 Cyrillic para Unicode.

    QCString encoded_string = ...; // Some ISO 8859-5 encoded text.
    QTextCodec* codec = QTextCodec::codecForName("ISO 8859-5");
    QString string = codec->toUnicode(encoded_string);
    ...; // Use string in all of Qt's QString operations.

Idealmente a Entrada/Saída Unicode deve ser usada pois isso maximiza a portabilidade de documentos entre usuários pelo mundo, mas na realidade é útil suportar todas as codificações que seus usuários precisarão para processar documentos existentes. EM geral, o Unicode (UTF16 ou UTF8) é melhor para informações transferidas entre pessoas arbitrárias, enquanto que para um idioma ou grupo nacional, um padrão local é frequentemente mais apropriado. A codificação mais importante a ser suportada é a retornada por QTextCodec::codecForLocale(), pois essa é a codificação que o usuário mais precisará para se comunicar com outras pessoas e aplicações (esse é o codec usado por local8Bit() ).
Como muitos sistemas Unix não possuem suporte embutido para conversão entre codificações de 8 bits locais e o Unicode, pode ser necessário escrever sua própria subclasse de QTextCodec. Dependendo da urgência, pode ser útil contatar o suporte técnico da Trolltech ou perguntar na lista de discussão qt-interest se alguém já está trabalhando no suporte a codificação desejada. Uma medida intermediária útil pode ser usar a função QTextCodec::loadCharmapFile() para construir um codec direcionado aos dados, apesar dessa abordagem vir com alguns perdas relacionadas a memória e velocidade, especialmente com bibliotecas de carregamento dinâmico.

Localize


A Localização é o processo de adaptação de convenções locais como exibição de data e hora. Tais localizações podem ser conseguidas usando strings tr() apropriadas, até mesmo palavras “mágicas”, como  o exemplo mostra de forma artificial:

    void Clock::setTime(const QTime& t)
    {
        if ( tr("AMPM") == "AMPM" ) {
            // 12-hour clock
        } else {
            // 24-hour clock
        }
    }

Localizar imagens não é recomendado. Escolha ícones que indiquem exatamente o que eles fazem, que sejam apropriadas a todas as localidades, ao invés de confiar em trocadilhos locais ou  metáforas esticadas.

Suporte do sistema


O suporte dos sistemas operacionais e sistemas de janelas ao Unicode ainda está nos estágios iniciais de desenvolvimento. O nível de suporte disponível nos sistemas básicos influencia o suporte que o Qt fornece a essa plataforma, mas aplicações escritas em Qt precisam geralmente se preocupar com essas limitações.

Unix/X11

  • Fontes orientadas a certos Locales e métodos de entrada. O Qt esconde essas fontes e fornece entrada e saída via Unicode.
  • Convenções de sistemas de arquivos tal como o UTF-8 estão em desenvolvimento em algumas variantes do Unix. Todas as funções relacionadas a acesso a arquivos do Qt permitem Unicode, mas convertem todos os nomes de arquivos para a codificação de 8 bits local, de acordo com a convenção do Unix.
  • E/S de arquivos padrão para a codificação de 8 bits padrão, como opções relacionadas ao Unicode em QTextStream.

Windows 95/98/NT

  • O QT fornece suporte completo ao Unicode, incluindo métodos de entrada, fontes, área de transferência, arrastar e soltar e nomes de arquivos.
  • E/S de arquivos padrão para Latin-1, com opções relacionadas ao Unicode em QTextStream. Note que alguns programas Windows não entendem arquivos de texto Unicode big-endian mesmo que essa seja a ordem descrita no padrão Unicode na ausência de protocolos de alto nível.
  • Ao contrário de programas escritos com o MFC ou plain winlib, os programas Qt são portáveis entre o Windows 95/98 e NT. Você não precisa de binários diferentes para suportar Unicode.

Nota sobre Locales no X11


Muitas distribuições Unix contém apenas suporte parcial para alguns locales. Por exemplo, se você possuir um diretório /usr/share/locale/ja_JP.EUC, isso não significa necessariamente que você poderá exibir texto em japonês; você precisa também das fontes JIS (ou fontes Unicode), e esse diretório precisa estar completo. Para melhores resultados, use os locales completos do distribuidor de seu sistema.

Classes Qt Relevantes


Essa classes são relevantes para internacionalizar aplicações Ot.

QEucJpCodec Conversion to and from EUC-JP character sets
QEucKrCodec Conversion to and from EUC-KR character sets
QGb18030Codec Conversion to and from the Chinese GB18030/GBK/GB2312 encoding
QGbkCodec Conversion to and from the Chinese GBK encoding
QHebrewCodec Conversion to and from visually ordered Hebrew
QJisCodec Conversion to and from JIS character sets
QSjisCodec Conversion to and from Shift-JIS
QTextCodec Conversion between text encodings
QTextDecoder State-based decoder
QTextEncoder State-based encoder
QTranslator Internationalization support for text output
QTranslatorMessage Translator message and its properties
QTsciiCodec Conversion to and from the Tamil TSCII encoding

Traduzido de http://www.kde.gr.jp/~ichi/qt/i18n.html