Zend Framework: Localização (L10n ou Localization) com Zend_Locale

O processo de localização de um software refere-se a adaptação do software, para suportar as diferenças culturais dos diversos lugares do mundo.

Tenha em mente que um lugar (locale) é identificado por sua linguagem e seu território. Por exemplo, existem vários países que tem o português como sua linguagem oficial, porém, o português usado no Brasil é diferente do português usado em Portugal. A identificação de um locale é definida por uma abreviatura que representa a linguagem um underscore _ e a abreviatura do território (país) da cultura determinada. Exemplo: pt_BR, en_US, etc.

É importante saber quando e porquê localizar um software?

Responda as perguntas abaixo:

  • Seu software poderá ser acessado por pessoas de vários países/línguas?
  • Seu software poderá lidar com dados de vários países/línguas?

Se ao menos uma resposta para as perguntas acima for sim, então, é recomendado que planeje localizar seu software.

O problema

Vamos expor a impressão de uma simples frase:

A batata custa R$1.000,00 se você comprar 500Kg em uma feira em 2Km do centro da cidade, até o dia 29/12/2009.

Utilizando o Zend Framework, mas sem os recursos de localization dele, poderíamos colocar esse código no nosso controller:

<?php
class IndexController extends Zend_Controller_Action {
    public function indexAction () 
    {
        $this->view->valor = 1000.00;
        $this->view->distancia = 2;
        $this->view->data = '29/12/2009';
        $this->view->peso = 500;
    }
}

E na view poderíamos escrever o seguinte:

<h1>Localiza&ccedil;&atilde;o</h1>
<p>
<?php echo 'A batata custa R$' . number_format($this->valor, 2, ',', '.') 
           . ' se você comprar ' . $this->peso . 'Kg em uma feira em ' 
           . $this->distancia . 'Km do ' . 'centro da cidade, até o dia ' 
           . $this->data . '.'; ?>
</p>

Se você executar o projeto, obterá a frase como mostrada anteriormente.

O problema é, ela não será entendida por uma pessoa residente nos EUA que não entenda português. Não só pelo fato das palavras estarem em português, mas também porque o sistema de numeração é diferente.

E como resolver? Há diversas formas. Algumas utilizam arquivos de configuração, outros, fazem arquivos diferentes para cada linguagem.

Aqui vou demonstrar como usar um componente do Zend Framework.

A solução com Zend_Locale

No Zend Framework existe um conjunto de classes Zend_Locale* que trata as diferenças culturais de cada local. Essas classes não fazem a tradução em si, mas possibilitam, que outros componentes possam utilizá-lo para implementar as diferenças em particular.

O Zend_Locale é simples de utilizar. Você pode deixá-lo que ele defina automaticamente o locale:

$locale = new Zend_Locale();

Ou você pode indicar um:

$locale = new Zend_Locale('pt_BR');

Quando instanciado o objeto sem nenhum parâmetro, a classe tenta identificar o locale pela a informação fornecida pelo browser do usuário. Ou você pode especificar o locale a ser utilizado. Ainda, você pode especificar que o framework use o locale configurado no servidor, utilizando:

$locale = new Zend_Locale(Zend_Locale::ENVIRONMENT);

Após instanciado, para fazer uso de suas funcionalidades, você deve passar o objeto que acabou de criar para os objetos que implementam as diferenças. Isso as vezes é um pouco custoso. Uma alternativa é adicionar o Zend_Locale no objeto Zend_Registry:

Zend_Registry::set('Zend_Locale', $locale);

Assim, os objetos que já existem no framework podem ter acesso ao objeto de localização automaticamente.

Adaptando valores de moeda

Para os valores de moeda, você pode usar o Zend_Currency. Vamos alterar a nossa view para isso:

<h1>Localiza&ccedil;&atilde;o</h1>
<p>
<?php
    $currency = new Zend_Currency();
    echo 'A batata custa ' . $currency->toCurrency($this->valor) 
         . ' se você comprar ' . $this->peso . 'Kg em uma feira em ' 
         . $this->distancia . 'Km do ' . 'centro da cidade, até o dia ' 
         . $this->data . '.'; ?>
</p>

Dependendo da sua configuração, o valor R$1.000,00 irá aparecer se o seu navegador informou seu locale como pt_BR ou $1,000.00 se o seu locale for en_US. Para você testar a facilidade de adaptação, você pode mudar indicar locales diferentes na hora de instanciar o Zend_Locale.

Adaptando medidas de peso

As medidas de peso podem ser convertidas utilizando a classe Zend_Measure_Weight. Por exemplo, para converter o valor acima para libras podemos fazer a seguinte alteração na view:

<h1>Localiza&ccedil;&atilde;o</h1>
<p>
<?php
    $currency = new Zend_Currency();
    $peso = new Zend_Measure_Weight($this->peso, 'KILOGRAM');
    echo 'A batata custa ' . $currency->toCurrency($this->valor) 
         . ' se você comprar ' . $peso->convertTo('POUND') . ' em uma feira em ' 
         . $this->distancia . 'Km do ' . 'centro da cidade, até o dia ' 
         . $this->data . '.'; ?>
</p>

Adaptando as medidas de distâncias

As medidas de distâncias aproveitam do mesmo recurso, utilizando a classe Zend_Measure_Length, podemos por exemplo, converter uma medida de kilômetros para metros. Veja a nossa view adaptada:

<h1>Localiza&ccedil;&atilde;o</h1>
<p>
<?php
    $currency = new Zend_Currency();
    $peso = new Zend_Measure_Weight($this->peso, 'KILOGRAM');
    $distancia = new Zend_Measure_Length($this->distancia, Zend_Measure_Length::KILOMETER);
    echo 'A batata custa ' . $currency->toCurrency($this->valor) 
         . ' se você comprar ' . $peso->convertTo('POUND') . ' em uma feira em ' 
         . $distancia->convertTo(Zend_Measure_Length::METER) 
         . ' do centro da cidade, até o dia '
         . $this->data . '.'; ?>
</p>

Adaptando datas

Para lidar com datas utiliza-se o objeto Zend_Date. Você pode passar a data no momento de instanciar, ou depois utilizando o método set. Veja um exemplo da view utilizando o Zend_Date:

<h1>Localiza&ccedil;&atilde;o</h1>
<p>
<?php
    $currency = new Zend_Currency();
    $peso = new Zend_Measure_Weight($this->peso, 'KILOGRAM');
    $data = new Zend_Date($this->data);
    echo 'A batata custa ' . $currency->toCurrency($this->valor) 
         . ' se você comprar ' . $peso->convertTo('POUND') . ' em uma feira em ' 
         . $this->distancia . 'Km do ' . 'centro da cidade, até o dia ' 
         . $data . '.'; ?>
</p>

Veja que dependendo do locale escolhido o formato da data será alterado.

Conclusão

Aqui expliquei um pouco como utilizar as ferramentas de localização que o Zend Framework proporciona. Mas há muito mais que pode ser utilizado, para tal, recomendo a leitura para esses itens da documentação:

http://framework.zend.com/manual/en/zend.currency.html
http://framework.zend.com/manual/en/zend.date.html
http://framework.zend.com/manual/en/zend.locale.html
http://framework.zend.com/manual/en/zend.measure.html

Ainda, outro processo que anda em conjunto com a Localização é a tradução das palavras. A tradução no Zend é bastante versátil, porém, tem algumas falhas, que será um texto para um próximo artigo.

Apenas adiantando, a tradução pode ser realizada com o Zend_Translate.