Skip to content

i18n

Anhanga never hardcodes labels. All user-facing text is resolved through a translate function following a key convention.

Key Conventions

Key PatternExampleUsed For
{domain}.fields.{field}person.fields.nameField labels
{domain}.fields.{field}[{state}]person.fields.name[error]Field label with visual state
{domain}.groups.{group}person.groups.basicGroup labels
common.actions.{action}common.actions.createAction labels (shared)

Translate Contract

The translate function has a simple signature:

typescript
type TranslateContract = (key: string) => string

Pass it to hooks:

typescript
const form = useDataForm({
  schema: PersonSchema.provide(),
  scope: Scope.add,
  translate: (key) => i18n.t(key),
  // ...
})

Resolution Helpers

All framework packages provide the same helper functions for label resolution:

typescript
import { resolveFieldLabel, resolveGroupLabel, resolveActionLabel } from '@anhanga/react' // or '@anhanga/vue' or '@anhanga/svelte'

resolveFieldLabel(t, 'person', 'name', '')
// → t('person.fields.name')

resolveFieldLabel(t, 'person', 'name', 'error')
// → t('person.fields.name[error]')

resolveGroupLabel(t, 'person', 'basic')
// → t('person.groups.basic')

resolveActionLabel(t, 'person', 'create')
// → tries t('person.actions.create'), falls back to t('common.actions.create')

Example Translation File

Translations are typically defined as TypeScript objects (see @anhanga/demo for a complete example):

typescript
export const ptBR = {
  common: {
    actions: {
      add: "Adicionar",
      create: "Criar",
      update: "Atualizar",
      cancel: "Cancelar",
      destroy: "Excluir",
      "create.success": "Registro criado com sucesso",
      "update.success": "Registro atualizado com sucesso",
      "destroy.confirm": "Deseja realmente excluir este registro?",
      "destroy.success": "Registro excluído com sucesso",
    },
    table: {
      columns: "Colunas",
      previous: "Anterior",
      next: "Próximo",
      page: "Página {{page}} de {{total}}",
      empty: "Nenhum registro encontrado",
    },
    dialog: { confirm: "Confirmar", cancel: "Cancelar" },
  },
  validation: {
    required: "Campo obrigatório",
    minLength: "Mínimo de {{value}} caracteres",
    maxLength: "Máximo de {{value}} caracteres",
    min: "Valor mínimo é {{value}}",
    max: "Valor máximo é {{value}}",
  },
  person: {
    fields: {
      id: "ID",
      name: "Nome",
      email: "E-mail",
      phone: "Telefone",
      birthDate: "Data de Nascimento",
      active: "Ativo",
      street: "Rua",
      city: "Cidade",
    },
    groups: {
      basic: "Informações Básicas",
      address: "Endereço",
    },
  },
}

Field States

Fields can have visual states (set via the schema proxy). When a state is active, the label key includes the state:

typescript
schema.name.state = 'error'
// Label resolves from: person.fields.name[error]

Define allowed states on a field:

typescript
text().states('error', 'warning', 'new')

Released under the MIT License.