Avançar para a área de conteúdo

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Todas as informações enviadas são seguras.

  • Fechar [x]

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Todas as informações enviadas são seguras.

  • Fechar [x]

O que há de novo em Unicode em PHP V5.3?

Suporte de i18N e Unicode

Jirka Kosek, Freelance XML consultant, Consultant
Photo of Jirka Kosek
Jirka Kosek é consultor autônomo de XML e professor na University of Economics em Praga. Ele tem mais de 10 anos de experiência em fornecer consultoria e treinamento em XML e é um integrante ativo em diversos órgãos de padronização, incluindo OASIS (DocBook TC e RELAX NG TC), W3C (XSL WG e ITS WG) e ISO/IEC JTC1/SC34. Jirka é autor de diversos livros e artigos sobre tecnologias da Web. Em seu tempo livre, ele contribui com código no projeto de software livre de folhas de estilo do DocBook XSL. Confira seu mais recente trabalho e ideias no seu blog.

Resumo:  PHP é uma linguagem popular, mas ainda carece de suporte adequado a Unicode. Entretanto, a V5.3 lançada recentemente adiciona uma nova biblioteca de internacionalização criada sobre a famosa biblioteca ICU. Com essa nova biblioteca, agora é possível intercalar, ordenar e formatar números e datas adequadamente para muitos códigos de idioma. Saiba como usar essa nova biblioteca para internacionalizar adequadamente aplicativos, bem como para superar problemas comuns do Unicode.

Data:  26/Mar/2010
Nível:  Intermediário
Atividade:  2437 visualizações
Comentários:  


A Web é uma plataforma ideal para desenvolver aplicativos e serviços com alcance mundial. Para criar um aplicativo que tenha verdadeiro apelo global, é necessário adaptá-lo ao processo e exibir dados em diversos idiomas e sistemas de escrita.

Acrônimos usados frequentemente

  • HTML: Hypertext Markup Language
  • HTTP: Hypertext Transfer Protocol
  • IETF: Internet Engineering Task Force
  • UI: User interface
  • XML: Extensible Markup Language

Um aplicativo é adaptado para outro idioma em diversas fases, a primeira das quais é a chamada internacionalização, frequentemente abreviada como i18n. O objetivo da internacionalização é garantir que os usuários possam utilizar seu idioma e notações no aplicativo, incluindo caracteres especiais para entrada e exibição de dados, exibindo números e datas no formato adequado e classificando listas de acordo com as regras específicas do idioma.

A abordagem mais avançada também inclui localização (abreviada como l10n). Durante a localização, o aplicativo é adaptado para dar suporte a hábitos culturais, linguísticos e locais específicos. Esse processo envolve tradução para o idioma local; a configuração adequada de formatos de datas, números e moedas; regras de classificação; etc.

Este artigo apresenta os novos recursos do PHP V5.3 que aperfeiçoam sua habilidade de criar aplicativos internacionalizados em PHP. O artigo não lida com o problema da localização em geral — especialmente com tradução; essa tarefa é mais bem abordada por bibliotecas PHP adicionais, como gettext do GNU (consulte Recursos).

Suporte a Unicode em PHP

Um aplicativo adequadamente internacionalizado deve ser capaz de processar dados escritos em diferentes sistemas de escrita. Inglês e outros idiomas usados na Europa Ocidental são baseados no sistema de script latino e usam somente caracteres latinos — algumas vezes com acentos adicionados (sinais diacríticos). Conforme avançamos para o oriente, encontramos os alfabetos cirílicos, os sistemas hebraico e árabe no Oriente Médio e diversos alfabetos indianos. Então há o chinês, o japonês e uma dúzia de outros sistemas de script orientais. A maioria dos sistemas de caracteres usados mais ou menos comumente estão inclusos no conjunto de caracteres Unicode (consulte Recursos para obter mais informações).

Entretanto, os caracteres Unicode são apenas abstrações. Sistemas de computador precisam codificar caracteres Unicode quando armazenados na memória ou em disco ou quando transferidos pela rede. Diversas codificações são usadas para Unicode: as duas mais populares são UTF-8 e UTF-16. Ambientes de desenvolvimento modernos como a tecnologia Java™ e o Microsoft® .NET Framework usam Unicode e possuem tipos de dados para caracteres e sequências de caracteres Unicode. Trabalhar com texto que usa caracteres Unicode é, então, completamente transparente para os desenvolvedores. É responsabilidade das funções da biblioteca lidar corretamente com todas as entradas e saídas (UI, formulários HTML, o banco de dados, XML) e, se necessário, transformá-las para codificação interna usada para a representação de sequências de caracteres Unicode.

Infelizmente, a linguagem PHP ainda carece de suporte Unicode adequado. Embora desenvolvedores de PHP central estejam pensando sobre adicionar suporte Unicode ao PHP desde 2001, nem sequer PHP V5.3 o inclui. Entretanto, esse suporte está planejado para o próximo importante release — PHP V6.


Superando o suporte Unicode ausente em PHP

A falta de suporte Unicode em PHP é desagradável, mas há soluções alternativas que permitem desenvolver aplicativos internacionalizados adequados mesmo em PHP. O primeiro problema que precisa ser solucionado é a representação adequada de dados Unicode. PHP usa as chamadas cadeias binárias de caracteres — em PHP, uma cadeia de caracteres não é uma sequência de caracteres Unicode, mas uma sequência de bytes. É possível armazenar internamente todas as sequências de caracteres em codificação UTF-8 e certificar-se de que todas as entradas e saídas do script sejam adequadamente codificadas e decodificadas.

Em teoria, é possível usar outras codificações além de UTF-8, mas UTF-8 cria menos problema que os outros sistemas. Muitas bibliotecas PHP já esperam que sequências de caracteres sejam codificadas em UTF-8, incluindo todas as funções que funcionam com XML e a recentemente adicionada biblioteca intl. Para trabalhar de maneira mais tranquila com sequências de caracteres codificadas em UTF-8, é melhor codificar caracteres em UTF-8 e enviar saída de scripts em UTF-8.

Ainda assim, transformar tudo em UTF-8 não resolve nada. Se você codificar um caractere latino com um acento ou caractere não latino em UTF-8, obterá dois, três ou quatro bytes, o que confunde as funções de cadeia de caracteres do PHP que calculam o comprimento da sequência de caracteres ou trabalham com subsequências de caracteres. A Listagem 1 demonstra esse problema.


Listagem 1. Problemas relacionados a suporte inadequado a Unicode em PHP
<?php

Header("Content-type: text/plain;charset=utf-8");
 
$text["en"] = "The Hitchhiker's Guide to the Galaxy";
$text["es"] = "Guía del autoestopista galáctico";
$text["cs"] = "Stopařův průvodce po Galaxii";
$text["ru"] = "Путеводитель хитч-хайкера по Галактике";
$text["ja"] = "銀河ヒッチハイク・ガイド";

foreach($text as $lang => $t)
{
 echo $lang, ": ", $t, " (", strlen($t), " vs. ", mb_strlen($t, "utf-8"), ")\n";
}
?>

A saída dessa listagem é mostrada na Figura 1.


Figura 1. Funções de cadeia de caracteres PHP simples retornam resultados inadequados para texto codificado em UTF-8
Image shows output from plain PHP string functions

Como se pode ver, o comprimento das sequências de caracteres escritas em diversos sistemas de escrita é calculado incorretamente. Somente para texto contendo letras do alfabeto latino um resultado correto é retornado. Nesse caso, é possível solucionar o problema usando funções da biblioteca mbstring (consulte Recursos). Assim, para obter o comprimento correto da cadeia de caracteres codificada em UTF-8, é necessário usar mb_strlen(string, "utf-8"), em vez de somente strlen(string).

Configurando seu editor

O código na Listagem 1 é codificado em UTF-8, então é necessário configurar adequadamente seu editor para usar essa codificação antes de carregar o arquivo. De modo similar, defina a codificação para a saída para UTF-8 usando o cabeçalho HTTP correspondente. Caso contrário, seu navegador exibirá uma saída corrompida.

Quando seus scripts estão processando dados em UTF-8, você está pronto para adicionar mais recursos de internacionalização com a biblioteca intl.

Instalando a biblioteca intl

A biblioteca intl é um wrapper de PHP da famosa biblioteca International Components for Unicode (ICU) (consulte Recursos). Muitos aplicativos usam ICU para implementar suporte Unicode e de localização adequado.

A biblioteca intl é uma parte padrão do PHP desde a V5.3. Se você possui o PHP V5.3 ou posterior, a biblioteca deve estar disponível para uso. Para versões mais antigas do PHP, ainda é possível usar a biblioteca através de uma extensão PECL.


Trabalhando com códigos do idioma

A combinação de idioma, região, sistema de escrita e outros parâmetros que controlam a localização é conhecida como código do idioma. O código do idioma normalmente é identificado por um tag de idioma como definido em IETF Best Current Practices (BCP) 47 (consulte Resources para obter mais informações). Por exemplo, inglês será identificado pela tag simples en. Alguns idiomas historicamente evoluíram em diferentes regiões e hoje possuem diferenças significativas. Para lidar com essa situação, é possível anexar um identificador de país após o identificador de idioma. Por exemplo, pt_PT identifica português como usado em Portugal, enquanto pt_BR denota o português como usado no Brasil. O BCP 47 oferece um controle muito mais refinado, mas para fins de brevidade, este artigo não fornece mais detalhes sobre identificadores de códigos do idioma.

Todas as funções e métodos intl que reconhecem o código do idioma aceitam um tag de idioma como o identificar do código do idioma. Ainda, a biblioteca intl fornece uma interface dupla — funcional e orientada a objeto. É possível escolher a interface adequada dependendo do seu estilo de codificação PHP. Por exemplo, há uma função/um método que retorna o nome do idioma para um código do idioma no idioma escolhido. Usando a notação funcional, é possível chamar o código usando o seguinte:

// return name of language used for "en" locale in French (fr)
echo locale_get_display_language("en", "fr"); // Anglais

Se você prefere a abordagem orientada a objeto, é possível usar o método estático correspondente:

// return name of language used for "en" locale in French (fr)
echo Locale::getDisplayLanguage("en", "fr"); // Anglais

A classe Locale fornecida na biblioteca intl define métodos de utilitário úteis. Alguns exemplos são fornecidos na Listagem 2.


Listagem 2. Uso dos métodos na classe Locale
<?php
Header("Content-type: text/plain; charset=utf-8");
 
// display name of Portuguese as used in Brazil in different languages
echo Locale::getDisplayName("pt_BR", "en"), "\n";
echo Locale::getDisplayName("pt_BR", "de"), "\n";
echo Locale::getDisplayName("pt_BR", "ru"), "\n";
echo Locale::getDisplayName("pt_BR", "ja"), "\n";
 
// return preferred locale set in user's browser
echo "Preferred locale from browser: ", 
     Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);
?>

O script produz o nome do idioma (Português) e o nome do país (Brasil) em diversos códigos do idioma diferentes. Ainda, o método acceptFromHttp(), que pode ser usado para ler o código do idioma preferido que um usuário definiu, é mostrado. A Figura 2 mostra a saída dessa listagem.


Figura 2. Saída do código da Listagem 2
Image shows Locale class output


Formatar números

Em um primeiro relance, formatar números pode parecer uma tarefa fácil. Mas quando é preciso lidar com todos os detalhes entediantes — os diferentes separadores e agrupadores de decimais usados em diferentes idiomas, por exemplo— você gostará de poder usar o intl para fazer isso por você. Além de formatação de números e moedas, o intl lida com tarefas mais sofisticadas, como escrever números corretamente —novamente, não apenas para o inglês, mas para muitos códigos do idioma suportados.

Formatação está disponível como funções, iniciando com o prefixo numfmt_, ou como métodos, como na classe NumberFormatter. Os exemplos neste artigo usam o estilo orientado a objeto, mas é possível obter os mesmos resultados usando uma abordagem funcional.

Antes de formatar, é preciso criar uma nova instância do NumberFormatter. É preciso fornecer um identificador de código do idioma e um estilo de formatador como parâmetros para o método de construção. É possível especificar o estilo usando diversas constantes predefinidas, como NumberFormatter::DECIMAL (formato decimal), NumberFormatter::CURRENCY (formato de moeda), NumberFormatter::SCIENTIFIC (formato científico) e NumberFormatter::SPELLOUT (o número será escrito corretamente). Por exemplo:

$fmt = new NumberFormatter("en", NumberFormatter::SPELLOUT);

Em um formatador recentemente criado, é possível salvar diversos métodos. Os mais úteis provavelmente são format() para formatar números e formatCurrency() para formatar quantias. O último método aceita um código de moeda como um segundo parâmetro. O uso dos métodos é mostrado na Listagem 3.


Listagem 3. Uso dos métodos na classe FormatNumber
<?php
Header("Content-type: text/plain; charset=utf-8");
 
// Locale-aware number formatting
$fmt = new NumberFormatter("en", NumberFormatter::DECIMAL);
echo $fmt->format(19841984.123456), "\n";
 
// Spelling out numbers in English
$fmt = new NumberFormatter("en", NumberFormatter::SPELLOUT);
echo $fmt->format(1984), "\n";
 
// Spelling out numbers in Russian
$fmt = new NumberFormatter("ru", NumberFormatter::SPELLOUT);
echo $fmt->format(1984), "\n";
 
// Formatting Euro and Czech crowns in German
$fmt = new NumberFormatter("de", NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(123456.789, "EUR"), "\n";
echo $fmt->formatCurrency(123456.789, "CZK"), "\n";
 
// Formatting Euro and Czech crowns in Czech
$fmt = new NumberFormatter("cs", NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(123456.789, "EUR"), "\n";
echo $fmt->formatCurrency(123456.789, "CZK"), "\n";

?>

Como a saída na Figura 3 mostra, separadores decimais e agrupamento adequado são usados ao formatar o número decimal. Se você conhece os idiomas inglês e russo, é possível verificar se o número está escrito corretamente. E, por fim, é possível ver que alguns códigos de moedas como EUR estão formatados como , enquanto outros estão presentes em formas localizadas — por exemplo, a Coroa Tcheca (CZK) está escrita em tcheco como .


Figura 3. Saída do script da Listagem 3
Image shows FormatNumber class output


Ordenação

Em muitos aplicativos, os dados podem ser classificados antes de serem exibidos. Mas regras de ordenação para idiomas que não o inglês podem ser complexas. Caracteres com acentos normalmente são tratados de uma maneira especial; alguns idiomas tratam sequências selecionadas de dois caracteres como uma letra para classificar (por exemplo, ch em tcheco e espanhol tradicional). Felizmente, a biblioteca intl fornece a classe Collator (e funções de sombra com nomes iniciando com collator_), que você pode usar para comparar e classificar sequências de caracteres com relação ao seu código do idioma selecionado.

Antes de comparar ou classificar, é preciso criar o novo intercalador e especificar um código do idioma para ele: $coll = new Collator("en_US");.

Agora á possível chamar diversos métodos no objeto criado. Por exemplo, o método compare() compara duas sequências de caracteres; os métodos sort() e asort() classificam arrays ou arrays associativas de maneira semelhante às funções de array do PHP correspondentes. O código na Listagem 4 mostra como é possível classificar uma array de palavras em tcheco baseadas de maneira diferente no código do idioma usado para o intercalador.


Listagem 4. Ordenando com diferentes códigos do idioma
<?php

Header("Content-type: text/plain; charset=utf-8");
 
// words to sort
$words = array("čočka", "čekanka", "cena", "chalupa",
               "ťululum", "dálnopis", "tyfus", "traktor");
 
// sort using built-in PHP sort function
sort($words);
echo "Words sorted using built-in sort function:\n";
var_export($words);

// sort according to English rules
$coll = new Collator("en_US");
$coll->sort($words);
echo "\n\nWords sorted according to English rules:\n";
var_export($words);

// sort according to Czech rules
$coll = new Collator("cs");
$coll->sort($words);
echo "\n\nWords sorted according to Czech rules:\n";
var_export($words);

?>

Se você classificar palavras usando a função integrada sort() do PHP, as palavras iniciando com letras acentuadas estão no final, porque o PHP compara sequências de caracteres como valores binários e não trata letras acentuadas de uma maneira especial. Entretanto, se você classificar as mesmas palavras usando um intercalador criado para inglês, as palavras são classificadas como se os acentos fossem ignorados — comportamento desejado se você possui algumas poucas palavras estrangeiras em um texto em inglês. No final, um intercalador tcheco é usado. Como se pode ver, regras estranhas agora são aplicadas: alguns caracteres acentuados são tratados como não acentuados (por exemplo, ť), alguns são tratados como caracteres separados (por exemplo, c e č) e ch é tratado como um caractere especial. A Figura 4 mostra o resultado do código na Listagem 4.


Figura 4. Saída do script da Listagem 4
Image showing output of the previous script


Tópicos avançados

Unicode e internacionalização é um amplo tópico, mas você deve conhecer pelo menos mais um elemento importante. Por motivos históricos, Unicode permite representações alternativas dos mesmos caracteres. Por exemplo, á pode ser escrito tanto como um caractere pré-composto á com o ponto de código Unicode U+00E1 quanto como uma sequência decomposta da letra a (U+0061) combinada com o acento ´ (U+0301). Para fins de comparação e classificação, essas duas representações devem ser consideradas iguais.

Para solucionar isso, a biblioteca intl fornece a classe Normalizer. Essa classe, por sua vez, fornece o método normalize(), que pode ser usado para converter uma cadeia de caracteres em uma forma normalizada composta ou decomposta. Seu aplicativo deve transformar de maneira consistente todas as sequências de caracteres em uma ou outra forma antes de realizar comparações.

echo Normalizer::normalize("a´, Normalizer::FORM_C); // á 
echo Normalizer::normalize("á", Normalizer::FORM_D);      // a´


Conclusão

Este breve artigo apresentou a funcionalidade mais importante e útil que a biblioteca intl fornece. Essa biblioteca tornou-se uma parte padrão do PHP V5.3. A biblioteca oferece muito mais funcionalidade que este artigo poderia abordar—por exemplo, formatação de data e análise de valores armazenados em formatos localizados. Para mais informações, consulte o manual do PHP em PHP.



Download

DescriçãoNomeTamanhoMétodo de download
Source code for this articlephp-unicode_source.zip4KBHTTP

Informações sobre métodos de download


Recursos

Aprender

Obter produtos e tecnologias

Discutir

Sobre o autor

Photo of Jirka Kosek

Jirka Kosek é consultor autônomo de XML e professor na University of Economics em Praga. Ele tem mais de 10 anos de experiência em fornecer consultoria e treinamento em XML e é um integrante ativo em diversos órgãos de padronização, incluindo OASIS (DocBook TC e RELAX NG TC), W3C (XSL WG e ITS WG) e ISO/IEC JTC1/SC34. Jirka é autor de diversos livros e artigos sobre tecnologias da Web. Em seu tempo livre, ele contribui com código no projeto de software livre de folhas de estilo do DocBook XSL. Confira seu mais recente trabalho e ideias no seu blog.

Ajuda para Relatar Abuso

Relatar abuso

Obrigado. Esta entrada foi sinalizada para atenção do moderador.


Ajuda para Relatar Abuso

Relatar abuso

Falha no envio do Relatório de abuso. Tente novamente mais tarde.


developerWorks: Registre-se


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Selecione seu nome de exibição

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

(Deve possuir de 3 a 31 caracteres.)


Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Classificar este artigo

Comentários

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre
ArticleID=477923
ArticleTitle=O que há de novo em Unicode em PHP V5.3?
publish-date=03262010
author1-email=jirka@kosek.cz
author1-email-cc=

Conheça a IBM da sua cidade

Virtual Branch Office Brasil

A IBM está mais perto do que você imagina!


Tags

Help
Use o campo de pesquisa para encontrar todos os tipos de conteúdo no My developerWorks com essa tag.

Use a barra de rolagem para ver mais ou menos tags.

Tags populares mostra as principais tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Minhas tags mostra suas tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Use o campo de pesquisa para localizar todos os tipos de conteúdo no Meu developerWorks com essa tag. Tags populares mostra as tags principais para essa zona de conteúdo particular (por exemplo, tecnologia Java, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere). Minhas tags mostra as suas tags para essa zona de conteúdo em particular (por exemplo, tecnologia Java, Linux, WebSphere).