Internacionalizar uma aplicação PHP não consiste apenas em traduzir botões e mensagens. Uma aplicação preparada para vários idiomas ou mercados deve separar idioma, formatos regionais, fuso horário, moeda, conteúdo e políticas de negócio. Se essas camadas se misturarem, cada expansão pode se tornar uma bifurcação funcional difícil de testar e manter.
O que muda ao operar em vários idiomas e mercados

O idioma determina como um texto é expresso. A configuração regional, ou locale, define convenções de apresentação, como o separador decimal, a ordem das datas ou o agrupamento de milhares. Um locale pode incluir uma região, como es-ES ou fr-CA, mas essa região não deve substituir o mercado, a entidade legal, a residência, a política comercial nem o país de operação.
Também é conveniente distinguir contextos que costumam vir juntos, mas não significam a mesma coisa:
- Fuso horário: interpreta horários, prazos, agendas e fechamentos operacionais.
- Moeda: identifica o valor de uma transação ou lista de preços; não é inferida a partir do idioma.
- Organização ou entidade legal: pode determinar impostos, permissões, faturamento ou retenção de dados.
- Mercado: pode condicionar catálogo, logística, métodos de pagamento ou canais disponíveis.
- Preferências do usuário: idioma, locale e fuso horário escolhidos, que podem diferir da configuração corporativa.
Uma pessoa pode usar a interface em inglês, trabalhar em um fuso horário europeu e administrar uma organização que fatura em outra moeda. Reduzir essa realidade a uma única variável locale cria decisões implícitas.
O erro caro: transformar o idioma em regra de negócio
Um mau sinal aparece quando o código toma decisões de domínio a partir do idioma da interface: if ($locale === 'es'). Esse condicional pode começar exibindo um rótulo diferente e terminar aplicando impostos, ocultando um método de pagamento ou alterando uma aprovação.
A pergunta correta é: “que dado ou política explica essa variação?”. Se ela depende de uma entidade legal, essa entidade deve ser consultada. Se responde a uma política comercial, deve existir uma política identificável e versionável. Se afeta apenas a representação, pertence à fronteira de entrada ou saída.
O idioma traduz a experiência; não autoriza, calcula nem define por si só o comportamento do domínio.
O que deve permanecer no domínio
O domínio deve trabalhar com conceitos estáveis e valores canônicos. Um pedido precisa de quantidades, valores, linhas, estados e regras de cálculo; não precisa saber se um valor será exibido como 1,234.50 ou 1.234,50. Uma política de elegibilidade deve receber atributos explícitos, não ler a apresentação do usuário.
- Domínio: invariantes, estados, cálculos, autorizações de negócio, políticas e eventos.
- Aplicação: casos de uso, carregamento de contexto, coordenação e seleção de políticas.
- Adaptadores de entrada: formulários, cabeçalhos, APIs ou arquivos; validação e normalização.
- Adaptadores de saída: tradução, serialização e formatação de datas, valores e unidades.
Em PHP, evite que entidades e serviços centrais consultem diretamente sessão, cabeçalhos HTTP, variáveis de ambiente ou o locale global do processo. Essas dependências fazem com que o mesmo caso de uso se comporte de forma diferente conforme o canal ou o momento da execução.
Projetar um contexto explícito e limitado
Um ExecutionContext pode incluir identificador da organização, ator, locale de apresentação e fuso horário preferido. Cada campo deve ter semântica clara. A moeda de uma operação, porém, deve fazer parte do valor ou da política de preços aplicada, não de uma preferência global mutável.
Resolva o contexto na borda de cada canal. Uma requisição web pode usar uma preferência salva ou negociação controlada; uma API deve receber campos explícitos e documentados; um processo em fila deve persistir os identificadores necessários ao ser criado. Um trabalho assíncrono não deve supor que herdará sessão, usuário nem fuso horário.
Conteúdo traduzível e dados operacionais
Os textos de interface, templates de comunicação e conteúdo editorial têm um ciclo de vida diferente dos dados operacionais. Use chaves estáveis e semânticas, por exemplo billing.invoice.overdue, em vez do texto original. Assim, é possível alterar a redação sem quebrar código, testes ou integrações.
O conteúdo gerenciável requer publicação: uma tradução pode existir como rascunho, estar aprovada ou publicada. Defina o fallback: idioma solicitado, idioma base da organização e, se aplicável, uma ausência visível e controlada. Uma tradução alternativa pode ser aceitável para uma nota interna, mas não necessariamente para uma comunicação contratual.
Não duplique um registro operacional completo por idioma, a menos que o dado seja localizado. Um produto pode ter nome e descrição traduzíveis, enquanto identificador, peso, estado e regras de disponibilidade permanecem comuns. Se houver uma diferença comercial real, modele-a como variante ou política, não como tradução.
Datas, valores, unidades e arredondamentos
Armazene instantes temporais de forma inequívoca e mantenha o fuso horário quando o significado for local. “A reunião começa às 09:00” exige conhecer o fuso em que foi definida; “o evento ocorreu neste horário” requer um instante absoluto. As mudanças sazonais produzem horas inexistentes ou repetidas; portanto, a entrada deve ser validada e a resolução adotada deve ser registrada quando aplicável.
Para dinheiro, armazene uma quantidade inteira em unidades menores junto com o código da moeda, mas não suponha duas casas decimais. A escala ou expoente provém dos metadados da moeda aplicáveis à operação. Algumas moedas usam uma escala diferente de duas, e requisitos históricos ou de uma rede de pagamento podem exigir a preservação da escala efetiva ou de uma versão da regra usada.
final class Money {
public function __construct(
public readonly int $minorUnits,
public readonly string $currency,
public readonly int $scale
) {}
}
A escala permite interpretar corretamente as unidades menores, mas não substitui uma política de arredondamento. Defina o ponto de arredondamento, o modo aplicado e a regra de numerário quando existir, pois o arredondamento de caixa pode diferir do arredondamento contábil. Evite float, formatos localizados durante o cálculo e conversões implícitas.
A mesma diretriz serve para medidas: guarde a unidade original quando ela tiver significado operacional, normalize quando o cálculo exigir e converta apenas ao capturar ou apresentar. Um formulário deve indicar a unidade e os formatos permitidos; não deve adivinhar se 1,500 significa um e meio ou mil e quinhentos.
Arquitetura dos fluxos de entrada e saída
A separação de camadas deve ser visível em um fluxo completo e repetível:
- Capturar o contexto e o dado de entrada: obter organização, ator, canal, locale, fuso horário e o valor recebido.
- Validar o formato permitido: verificar campos obrigatórios, sintaxe, unidade, moeda, fuso horário e restrições do canal.
- Normalizar para valores canônicos: converter texto localizado em valores, datas, unidades e identificadores inequívocos.
- Executar o caso de uso de domínio: aplicar regras e políticas explícitas sobre valores canônicos.
- Traduzir e formatar a saída: escolher mensagens publicadas e representar valores para o destinatário ou contrato da API.
Uma API pode decidir aceitar apenas formatos canônicos, como datas com fuso explícito e valores estruturados. Um formulário destinado a pessoas pode aceitar formatos localizados, desde que seu parser seja explícito. Em ambos os casos, o domínio recebe a mesma representação estável.
Política configurável ou regra de negócio distinta
Uma variação costuma ser configurável se compartilha o processo e altera parâmetros declaráveis, como um limite, uma lista de feriados ou um método de cálculo definido por configuração. Essa configuração precisa de esquema, versão, responsável e testes.
A diferença revela uma regra distinta quando modifica invariantes, estados, responsabilidades, fontes de dados ou consequências legais. Nesse caso, escondê-la em opções cria uma configuração opaca. Modele uma política por meio de uma interface explícita ou de um fluxo separado se o processo for realmente diferente. O objetivo não é forçar uma abstração única, mas evitar duplicar toda a aplicação por uma diferença localizada.
Testes e lista de verificação

Os testes devem verificar cálculo e representação. Alterar o idioma ou locale não deve modificar um total, uma autorização ou uma política comercial, a menos que um requisito explícito o determine.
- Teste datas em mudanças de horário, com horas ambíguas e inexistentes.
- Inclua valores zero, negativos, escalas diferentes, arredondamento contábil e de caixa.
- Verifique entradas localizadas permitidas e a rejeição de formatos ambíguos.
- Verifique fallback, ausência de conteúdo publicado e variáveis interpoladas.
- Execute trabalhos assíncronos sem sessão, usando apenas o contexto persistido.
- Teste contratos de API com valores canônicos e metadados de formato quando forem necessários.
Antes de disponibilizar um idioma ou mercado, identifique o que realmente muda, separe suas fontes de verdade, revise regras monetárias e temporais e ative a disponibilidade gradualmente quando a operação exigir validação controlada. Essa disciplina permite expandir a aplicação sem transformar cada mercado em uma versão paralela do produto.



