Internacionalização em PHP: criar aplicações multilíngues robustas com Intl e ICU

Guia prático para separar textos e código, escolher locales e gerir catálogos, plurais, números, moedas e datas com PHP Intl.

Internacionalização em PHP: criar aplicações multilíngues robustas com Intl e ICU

Tornar uma aplicação PHP multilíngue não significa apenas trocar algumas frases por um array. Um sistema fiável separa o conteúdo da lógica, escolhe idioma e região de forma previsível, formata corretamente quantidades, moedas e datas e mantém um idioma alternativo quando falta uma tradução.

Internacionalização e localização

A internacionalização prepara o software para vários idiomas e convenções culturais; a localização fornece textos e formatos para um público específico. O código deve usar chaves estáveis como checkout.total, enquanto os catálogos contêm as traduções. Uma correção editorial não deve exigir alteração do código.

Ativar Intl e definir locales

A extensão intl expõe as funções ICU em PHP. Em produção, verifique extension_loaded('intl') e a versão ICU disponível. Use identificadores explícitos como pt-PT. Não dependa do padrão do servidor. Uma lista permitida impede valores não suportados e caminhos manipulados.

<?php
$supported = ['it-IT', 'en-GB', 'de-DE', 'fr-FR', 'es-ES', 'pt-PT'];
$requested = $_GET['lang'] ?? 'it-IT';
$locale = in_array($requested, $supported, true) ? $requested : 'it-IT';

$catalogue = require __DIR__ . '/lang/' . $locale . '.php';

function trans(string $key, array $vars = []): string {
    global $catalogue, $locale;
    $pattern = $catalogue[$key] ?? $key;
    $formatted = MessageFormatter::formatMessage($locale, $pattern, $vars);
    return $formatted === false ? $pattern : $formatted;
}

Os catálogos podem ser ficheiros PHP ou JSON, ou dados de um serviço. Devem ficar fora das pastas públicas, ser validados no deployment e partilhar um conjunto mínimo de chaves. A estratégia de fallback deve ser centralizada.

Mensagens dinâmicas e plurais

Concatenar fragmentos impõe a mesma ordem de palavras a todos os idiomas. MessageFormatter usa padrões ICU para que cada tradução controle ordem, regras de plural e formatos incorporados. Passe valores estruturados e registe erros da API Intl.

Números, moedas e datas

Guarde dados neutros: montantes em unidades mínimas ou num formato decimal seguro, datas em UTC e moedas como códigos ISO. A apresentação é aplicada apenas na saída. NumberFormatter adapta separadores e símbolos, mas não converte taxas de câmbio. IntlDateFormatter aplica idioma, calendário e um fuso horário explícito.

<?php
$price = new NumberFormatter($locale, NumberFormatter::CURRENCY);
echo $price->formatCurrency(1299.90, 'EUR');

$date = new IntlDateFormatter(
    $locale,
    IntlDateFormatter::LONG,
    IntlDateFormatter::SHORT,
    'Europe/Rome'
);
echo $date->format(new DateTimeImmutable('2026-11-06 10:30:00'));

Escolher o idioma

Uma prioridade prática é preferência guardada, definição de sessão validada, cookie assinado, Accept-Language e fallback da aplicação. O cabeçalho do navegador é uma indicação, não um segmento seguro de caminho. Guarde o locale canónico e gere URLs localizados coerentes.

HTML, segurança e SEO

Faça escaping dos valores no momento da renderização conforme o contexto HTML, atributo ou JavaScript. Traduções não são HTML confiável por padrão. Defina o atributo lang, publique ligações hreflang e mantenha um mapa estável para slugs traduzidos.

Testes e manutenção

Automatize verificações de JSON válido, chaves ausentes, placeholders incompatíveis e textos não traduzidos. Teste zero, um e muitos elementos e também uma língua com palavras longas. Fixe o fuso horário nos testes e registe chaves ausentes sem as mostrar aos visitantes.

Conclusão

Uma arquitetura multilíngue sólida separa lógica e conteúdo e delega em ICU a formatação cultural. Com locales validados, catálogos versionados, fallbacks explícitos e testes automáticos, adicionar um idioma torna-se uma tarefa editorial controlada.

Partilhar

Qual é a sua reação?

Gosto Gosto 0
Não gosto Não gosto 0
Adoro Adoro 0
Divertido Divertido 0
Irritado Irritado 0
Triste Triste 0
Uau Uau 0