# Internacionalização (i18n)

> LocaleFormats cuida da formatação; a tradução de texto é manual — onde o framework ajuda e onde não.

Source: https://crossfly.dev/pt/docs/best-practices/internacionalizacao — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Internacionalização (i18n)

A divisão é clara: **formatação é automática** (`LocaleFormats`), **tradução de texto é manual**
(você). Saber onde fica cada uma evita procurar por uma API que não existe.

## Formatação automática — `LocaleFormats`
`LocaleFormats` (em `dev.crossfly.util`) concentra os separadores e formatos sensíveis ao locale, e é
respeitado por `DatePicker`/`TimePicker`/máscara de moeda **automaticamente**:
| Campo | Tipo | Controla |
|---|---|---|
| `dateFormat` | `UIConstants.DateFormat` | ordem da data (DMY/MDY/YMD) |
| `dateSeparator` | `char` | separador de data (`/`, `-`, `.`) |
| `timeSeparator` | `char` | separador de hora (`:`) |
| `is24Hour` | `boolean` | 12h vs 24h |
| `decimalSeparator` | `char` | decimal (`,` ou `.`) |
| `thousandsSeparator` | `char` | milhar |
| `weekStart` | `byte` | primeiro dia da semana |

```java
LocaleFormats.decimalSeparator = ',';
LocaleFormats.thousandsSeparator = '.';
LocaleFormats.is24Hour = true;
// a partir daqui, a máscara de moeda e os pickers já formatam no padrão pt-BR
```

## Tradução de texto — manual
**Não há catálogo de strings embutido.** Externalize seus textos (um `Map`/enum próprio) e troque
conforme o idioma:
```java
enum Idioma { PT, EN }
static Idioma idioma = Idioma.PT;
static final Map<String, Map<Idioma,String>> T = Map.of(
   "salvar", Map.of(Idioma.PT, "Salvar", Idioma.EN, "Save"),
   "cancelar", Map.of(Idioma.PT, "Cancelar", Idioma.EN, "Cancel")
);
static String t(String chave) { return T.get(chave).get(idioma); }

// uso:
new Button(t("salvar"));
```
Nomes de meses/dias e rótulos dos pickers são **campos públicos** que você reatribui para localizar.

## Por que o layout já ajuda
Layouts por **fração/`Relative`** toleram textos de comprimentos diferentes entre idiomas ("Salvar" vs
"Enregistrer") sem quebrar — outro ganho de não usar larguras fixas.

## Boas práticas
- Configure `LocaleFormats` **uma vez** no bootstrap conforme o locale do usuário.
- Externalize **todo** texto visível desde o início (retrofitar depois é caro).
- Teste os idiomas mais "largos" para garantir que o layout comporta.

## Erros comuns
- Procurar um sistema de strings/`R.string` embutido — não existe; faça o seu.
- Hardcode de `/` na data em vez de usar `LocaleFormats.dateSeparator`.

## Veja também
- [DatePicker](/docs/ui/widgets/datepicker) · [Máscaras e teclados](/docs/ui/forms-and-input/masks-and-keyboards)
