Esta página foi traduzida automaticamente. Encontrou um erro?Ajude a melhorá-la.
Skip to content

Guia de tradução ​

O SnapOtter já vem com 21 idiomas prontos para uso. O sistema de i18n usa um runtime próprio e leve, com completude de locale garantida pelo TypeScript e code-splitting dinâmico.

Idiomas suportados ​

CodeLanguageNative NameDirection
enInglêsEnglishLTR
zh-CNChinês (Simplificado)简体中文LTR
zh-TWChinês (Tradicional)繁體中文LTR
jaJaponês日本語LTR
koCoreano한국어LTR
esEspanholEspañolLTR
frFrancêsFrançaisLTR
itItalianoItalianoLTR
pt-BRPortuguês (Brasil)Português (Brasil)LTR
deAlemãoDeutschLTR
nlHolandêsNederlandsLTR
svSuecoSvenskaLTR
ruRussoРусскийLTR
plPolonêsPolskiLTR
ukUcranianoУкраїнськаLTR
arÁrabeالعربيةRTL
trTurcoTürkçeLTR
hiHíndiहिन्दीLTR
viVietnamitaTiếng ViệtLTR
idIndonésioBahasa IndonesiaLTR
thTailandêsไทยLTR

Como funciona a detecção de idioma ​

O SnapOtter usa uma ordem de resolução em três camadas:

  1. Preferência do usuário - armazenada em localStorage("snapotter-locale") e sincronizada com as configurações do usuário quando autenticado
  2. Detecção automática do navegador - percorre o array navigator.languages com correspondência de prefixo BCP 47
  3. Padrão da instância - a variável de ambiente DEFAULT_LOCALE do administrador (obtida de GET /api/v1/config/locale)
  4. Fallback para inglês - sempre disponível

Os usuários podem alterar o idioma a partir de:

  • O seletor Globo no rodapé (desktop, sempre visível)
  • O seletor de idioma da página de login (pré-autenticação)
  • A seção Configurações > Geral (preferência por usuário)
  • O menu suspenso de idioma da barra lateral móvel
  • A seção Configurações > Sistema define o padrão para toda a instância (somente administrador)

Como funcionam as traduções ​

Todas as strings da interface ficam em packages/shared/src/i18n/. O arquivo de referência é en.ts, que exporta um objeto tipado com todas as strings que o app usa (~1500 chaves). Os demais idiomas são arquivos separados (por exemplo, de.ts, fr.ts) que exportam a mesma estrutura.

O tipo TranslationKeys usa DeepStringRecord para aceitar qualquer valor de string enquanto impõe a estrutura das chaves. O TypeScript detecta chaves faltantes em qualquer arquivo de tradução em tempo de compilação.

Apenas o locale ativo é carregado em runtime via import() dinâmico, mantendo o bundle principal pequeno.

Usando traduções em componentes ​

tsx
import { useTranslation } from "@/contexts/i18n-context";
import { format, plural } from "@/lib/format";

function MyComponent() {
  const { t, locale, setLocale } = useTranslation();
  
  return (
    <div>
      <h1>{t.common.settings}</h1>
      <p>{format(t.settings.people.deleteConfirm, { username: "admin" })}</p>
      <p>{plural(count, t.automate.fileCount, t.automate.fileCountPlural)}</p>
    </div>
  );
}

Contribuindo com uma tradução ​

Aceitamos PRs de tradução diretamente. Você pode aprimorar um locale existente ou adicionar um novo.

Para relatar uma tradução incorreta sem enviar código, abra uma GitHub Issue com o idioma, a string incorreta e a correção sugerida.

TIP

PRs de tradução não exigem aprovação prévia. Faça um fork do repositório, faça suas alterações e abra um PR. Consulte o Guia de Contribuição para o processo completo de PR e o requisito de CLA.

Como criar ou atualizar uma tradução ​

1. Faça o fork e clone ​

bash
git clone https://github.com/<your-username>/snapotter.git
cd snapotter
pnpm install

2. Copie o arquivo de referência (apenas novo idioma) ​

Pule esta etapa se você estiver aprimorando uma tradução existente.

bash
cp packages/shared/src/i18n/en.ts packages/shared/src/i18n/XX.ts

3. Traduza as strings ​

Abra seu novo arquivo e traduza cada valor de string. Mantenha a estrutura do objeto e as chaves exatamente iguais.

ts
import type { TranslationKeys } from "./en.js";

export const xx: TranslationKeys = {
  common: {
    upload: "Your translation here",
    // ... translate all entries
  },
  // ... translate all sections
} as const;

Regras:

  • Não traduza as chaves do objeto, apenas os valores de string
  • Mantenha as const no final
  • Importe TranslationKeys de ./en.js e tipe sua exportação
  • Mantenha os placeholders {variable} exatamente como estão
  • Os arrays (rotatingPhrases, progressMessages) devem ter o mesmo número de entradas
  • Não traduza: SnapOtter, JPEG, PNG, WebP, EXIF, API e outros termos técnicos

4. Registre o locale (apenas novo idioma) ​

Adicione seu locale a SUPPORTED_LOCALES em packages/shared/src/i18n/index.ts:

ts
{ code: "xx", name: "Language Name", nativeName: "Native Name", dir: "ltr" },

5. Verifique ​

bash
pnpm typecheck    # catches missing or mistyped keys
pnpm lint         # formatting check
pnpm dev          # manually verify strings appear correctly

6. Envie ​

Abra um PR contra main com um título como feat(i18n): add Swedish translation ou fix(i18n): correct German typos. O bot do CLA pedirá que você assine na sua primeira contribuição.

Adicionando novas chaves de tradução ​

Ao adicionar um novo recurso que precise de novas strings de interface:

  1. Adicione as novas chaves a en.ts primeiro (o arquivo de referência)
  2. Execute pnpm typecheck - cada arquivo de locale falhará se estiver sem a nova chave
  3. Adicione a nova chave a todos os arquivos de locale (use o inglês como fallback temporário)

Configuração ​

Defina o idioma padrão da instância por meio de variável de ambiente:

yaml
DEFAULT_LOCALE: "de"  # German as the default for all new users

Referência de arquivos ​

FilePurpose
packages/shared/src/i18n/en.tsStrings em inglês (locale de referência, ~1500 chaves)
packages/shared/src/i18n/index.tsSUPPORTED_LOCALES, loadTranslations(), exportações de tipos
packages/shared/src/i18n/<locale>.tsArquivos de tradução por idioma
apps/web/src/contexts/i18n-context.tsxI18nProvider, hook useTranslation()
apps/web/src/lib/format.tsHelpers format(), plural(), formatFileSize()
apps/api/src/routes/config.tsEndpoint público GET /api/v1/config/locale

Traduzindo o site, a documentação e a referência da API ​

O suporte a 21 idiomas descrito acima cobre o app. O site público (snapotter.com), este site de documentação e a referência da API REST também são traduzidos para todos os 21 idiomas, por um pipeline separado protegido por hash que reutiliza os mesmos nomes e descrições de ferramentas de packages/shared/src/i18n, de modo que a terminologia permaneça consistente em toda parte.

Traduzido por máquina por padrão ​

Toda página que não seja em inglês no site e na documentação é traduzida por máquina na primeira passagem (por uma sessão do Claude Code, não por um serviço de terceiros) e traz um pequeno banner dispensável dizendo isso, com um link de volta para cá. Isso é deliberado: entrega todos os 21 idiomas com rapidez e honestidade e, então, convida a comunidade a refinar as páginas que mais importam. A tradução por máquina transmite o significado; a revisão humana faz o texto soar natural.

Como o pipeline decide o que traduzir ​

Cada unidade traduzível do texto-fonte em inglês é submetida a hash, e o hash é armazenado ao lado de sua tradução. A cada execução, o pipeline:

  • traduz qualquer unidade que ainda não tenha tradução,
  • pula qualquer unidade cujo hash armazenado ainda corresponda ao texto-fonte em inglês,
  • retraduz uma unidade de máquina quando seu texto-fonte em inglês muda,
  • e sinaliza uma unidade refinada por humano como stale (precisa de revisão) quando seu texto-fonte em inglês muda, em vez de sobrescrever seu trabalho.

Refinando uma tradução da web por PR ​

Você aprimora uma tradução do site, da documentação ou da referência da API da mesma forma que aprimora um locale do app: editando o arquivo gerado e abrindo um PR.

  1. Encontre a tradução gerada para o seu idioma:
    • strings de interface do site: apps/landing/src/i18n/<locale>.json
    • uma página da documentação: apps/docs/<locale>/**.md
    • a referência da API: apps/api/src/openapi.<locale>.yaml
  2. Edite o texto. Mantenha código, links, {placeholders} e quaisquer marcadores ⸤I18N…⸥ exatamente como estão; o validador do pipeline rejeita uma tradução que remova ou reordene esses elementos.
  3. Abra um PR. Editar uma unidade muda sua proveniência de machine para human, de modo que o pipeline nunca a sobrescreverá em uma execução posterior. Se o texto-fonte em inglês mudar depois, sua unidade é sinalizada como stale para revisão, em vez de ser substituída silenciosamente.

Para relatar uma tradução incorreta sem enviar código, abra uma GitHub Issue com a URL da página, o idioma, o texto incorreto e sua correção sugerida.

TIP

Os mantenedores executam o pipeline de tradução; você não precisa de uma chave de API para contribuir. Basta editar o arquivo gerado e abrir um PR. Consulte scripts/i18n/README.md para saber como o pipeline funciona.