Seu app Lovable pode estar totalmente traduzido e ainda exibir "5 элемент" ou mostrar um preço como "1,234.50" para um usuário alemão. A causa é uma lógica de plural e de formatação escrita para o inglês e esquecida nos seus componentes. O globalize.now é uma infraestrutura de localização com IA que mantém suas strings em catálogos versionados, e a correção abaixo coloca as regras de plural dentro desses catálogos, e não no seu código.

Por que os plurais quebram quando o Lovable traduz meu app?

Porque a regra de plural fica no componente, e não na tradução. Um padrão gerado com frequência é assim:

<p>{count} {count === 1 ? "item" : "items"} in your cart</p>

Essa linha deixa a gramática do inglês fixa no código. Um tradutor pode mudar as palavras, mas não o teste === 1, e a ordem das palavras também fica travada, com o número sempre em primeiro lugar. O inglês tem duas formas. O russo tem quatro, então "1 элемент", "2 элемента", "5 элементов" e "1,5 элемента" exigem terminações diferentes.

Se você configurou o roteamento primeiro (veja como tornar um app Lovable multilíngue), os plurais são o próximo bug que os usuários notam, porque nada quebra. A frase simplesmente sai errada.

Passo 1: Como escrever um plural que os tradutores possam alterar?

Use uma mensagem de plural ICU, para que a regra passe para a tradução. Com o Lingui, tanto o componente Plural quanto a macro plural geram uma.

import { Plural } from "@lingui/react/macro";

<p>
  <Plural value={count} one="# item in your cart" other="# items in your cart" />
</p>

Para strings fora do JSX, use a macro do pacote core:

import { plural } from "@lingui/core/macro";

const label = plural(count, { one: "# file", other: "# files" });

# é substituído pelo número. Segundo a documentação do Lingui, você escreve apenas as formas que o seu idioma de origem exige, e other é obrigatório. Correspondências exatas como _0="Your cart is empty" tratam o caso zero em inglês sem um ramo separado.

As stacks padrão do Lovable diferem na configuração, mas não nessa API, então o mesmo componente funciona nos projetos Vite SPA e TanStack Start.

Como fica o catálogo depois que os plurais são extraídos?

Uma mensagem por string, em sintaxe ICU padrão, armazenada como arquivo PO no seu repositório. O tradutor, humano ou IA, fornece as formas que o idioma dele exige.

msgid "{count, plural, one {# item in your cart} other {# items in your cart}}"
msgstr "{count, plural, one {# товар в корзине} few {# товара в корзине} many {# товаров в корзине} other {# товара в корзине}}"

A forma other do russo cobre frações como 1,5, e é por isso que ela coincide com o genitivo singular. Como o catálogo é um arquivo versionado, você revisa mudanças de plural em um pull request, como qualquer outro código. Para entender a sintaxe em si, veja o que é o ICU MessageFormat.

Quais idiomas precisam de mais do que one e other?

O Unicode CLDR define seis categorias de plural: zero, one, two, few, many e other. Cada idioma usa um subconjunto, e other é obrigatório em todos.

IdiomaCategorias usadas
Japonês, chinêsother
Inglêsone, other
Russoone, few, many, other
Árabezero, one, two, few, many, other

A especificação do CLDR lista o galês como um idioma que também usa as seis categorias. Você não precisa decorar isso. Você precisa de um formato de catálogo que permita a cada idioma preencher as próprias formas, e o PO com mensagens ICU faz isso.

Como evitar que o Lovable volte a escrever plurais com ternários?

Coloque a regra onde o Lovable lê as instruções. O Lovable regenera componentes quando você pede novas funcionalidades, e uma funcionalidade nova escrita sem a regra traz o ternário de volta.

Adicione isto ao seu Knowledge ou ao AGENTS.md:

Never hand-build plurals or number formats. Use the Lingui Plural component
or plural() macro for every count. Use Intl with the active locale for every
date, number and price.

A skill lovable-i18n escreve regras desse tipo para você. Como ela faz isso está em o que a skill de i18n do Lovable faz. Depois da próxima funcionalidade gerada, procure no diff por === 1 e !== 1 para confirmar que a regra foi respeitada.

Passo 2: Como formatar datas e moeda por locale?

Use Intl com o locale ativo. O objeto i18n do Lingui também oferece i18n.date() e i18n.number(), mas chamar Intl diretamente com i18n.locale mantém as opções de formatação visíveis no seu próprio código.

import { useLingui } from "@lingui/react";

export function Price({ amount, currency }: { amount: number; currency: string }) {
  const { i18n } = useLingui();
  return (
    <span>
      {new Intl.NumberFormat(i18n.locale, { style: "currency", currency }).format(amount)}
    </span>
  );
}

export function OrderDate({ date }: { date: Date }) {
  const { i18n } = useLingui();
  return <time>{new Intl.DateTimeFormat(i18n.locale, { dateStyle: "long" }).format(date)}</time>;
}

Os mesmos 1234,5 euros são renderizados como uma string diferente em cada locale, com separadores e posição de símbolo próprios. A formatação nunca converte dinheiro. Um preço armazenado em euros continua em euros em todos os idiomas, então mantenha o código da moeda ao lado de cada preço no seu banco de dados.

Passo 3: Como testar todas as categorias de plural antes de publicar?

Pergunte ao navegador em qual categoria um número se enquadra e depois verifique se cada uma tem uma forma.

const ru = new Intl.PluralRules("ru");
[1, 2, 5, 21, 1.5].map((n) => ru.select(n));
// ["one", "few", "many", "one", "other"]

const ar = new Intl.PluralRules("ar");
[0, 1, 2, 3, 11, 100].map((n) => ar.select(n));
// ["zero", "one", "two", "few", "many", "other"]

Adicione um teste por idioma publicado: renderize o componente com um número de cada categoria e verifique que nenhum cai em uma forma ausente. Depois, leia as páginas em russo e em árabe no navegador pelo menos uma vez. Um few ausente em um catálogo aparece como a terminação errada, não como um erro.

O que muda se eu usava um widget de runtime antes?

Widgets de runtime traduzem o texto já renderizado depois do carregamento, então não enxergam uma regra de plural no seu código. Esse é um dos motivos pelos quais mover as traduções para o repositório importa. O Lovalingo encerrou as atividades em 31/08/2026; o guia de migração e a página de comparação explicam o que muda quando os catálogos ficam no seu repositório.

Com o globalize.now, você conecta o repositório uma vez e a base de código é convertida no app. Depois disso, as tarefas de push traduzem as novas unidades do catálogo e o resultado chega como um pull request. O Lovable sincroniza a partir do GitHub, então as formas de plural chegam ao seu app como qualquer outra mudança. A configuração está na página de integração com o Lovable, e o fluxo sem painel está em como localizar um app Lovable sem painel.

O globalize.now transforma textos fixos do app em arquivos de locale prontos para tradução e os mantém atualizados a cada novo lançamento.

Experimente o globalize.now grátis