Files
SnapOtter/apps/docs/es/guide/translations.md
T
SnapOtterandGitHub 4963ab3bbd feat(docs-i18n): translate all documentation into 20 languages
All 181 docs markdown files translated into 20 languages (apps/docs/<locale>/**). Companion to the i18n code PR; admin-merged because the file count exceeds GitHub's per-PR CI trigger limit. Validated by pnpm i18n:check (all surfaces, 0 stale/missing) and a clean all-locale docs build.
2026-07-11 13:52:47 +08:00

11 KiB

description, i18n_source_hash, i18n_provenance, i18n_output_hash
description i18n_source_hash i18n_provenance i18n_output_hash
21 idiomas admitidos y cómo crear o mejorar traducciones para SnapOtter usando el sistema i18n reforzado con TypeScript. 55837d9fdaef human 4dffadc0da66

Guía de traducción

SnapOtter incluye 21 idiomas de fábrica. El sistema i18n usa un runtime propio y ligero, con integridad de locales reforzada por TypeScript y división dinámica del código.

Idiomas admitidos

Code Language Native Name Direction
en Inglés English LTR
zh-CN Chino (simplificado) 简体中文 LTR
zh-TW Chino (tradicional) 繁體中文 LTR
ja Japonés 日本語 LTR
ko Coreano 한국어 LTR
es Español Español LTR
fr Francés Français LTR
it Italiano Italiano LTR
pt-BR Portugués (Brasil) Português (Brasil) LTR
de Alemán Deutsch LTR
nl Neerlandés Nederlands LTR
sv Sueco Svenska LTR
ru Ruso Русский LTR
pl Polaco Polski LTR
uk Ucraniano Українська LTR
ar Árabe العربية RTL
tr Turco Türkçe LTR
hi Hindi हिन्दी LTR
vi Vietnamita Tiếng Việt LTR
id Indonesio Bahasa Indonesia LTR
th Tailandés ไทย LTR

Cómo funciona la detección de idioma

SnapOtter usa un orden de resolución de tres niveles:

  1. Preferencia del usuario: almacenada en localStorage("snapotter-locale") y sincronizada con los ajustes del usuario cuando ha iniciado sesión
  2. Detección automática del navegador: recorre el array navigator.languages con coincidencia de prefijos BCP 47
  3. Predeterminado de la instancia: la variable de entorno DEFAULT_LOCALE del administrador (obtenida de GET /api/v1/config/locale)
  4. Respaldo en inglés: siempre disponible

Los usuarios pueden cambiar el idioma desde:

  • El selector del globo terráqueo del pie de página (escritorio, siempre visible)
  • El selector de idioma de la página de inicio de sesión (previo a la autenticación)
  • La sección Ajustes > General (preferencia por usuario)
  • El menú desplegable de idioma de la barra lateral móvil
  • La sección Ajustes > Sistema, que fija el idioma predeterminado de toda la instancia (solo administradores)

Cómo funcionan las traducciones

Todas las cadenas de la interfaz viven en packages/shared/src/i18n/. El archivo de referencia es en.ts, que exporta un objeto tipado con todas las cadenas que usa la aplicación (~1500 claves). Los demás idiomas son archivos independientes (por ejemplo, de.ts, fr.ts) que exportan la misma forma.

El tipo TranslationKeys usa DeepStringRecord para aceptar cualquier valor de cadena a la vez que refuerza la estructura de claves. TypeScript detecta las claves que falten en cualquier archivo de traducción en tiempo de compilación.

En tiempo de ejecución solo se carga el locale activo mediante import() dinámico, lo que mantiene pequeño el bundle principal.

Uso de traducciones en los componentes

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>
  );
}

Contribuir con una traducción

Recibimos con gusto PRs de traducción directamente. Puedes mejorar un locale existente o añadir uno nuevo.

Para informar de una traducción incorrecta sin enviar código, abre un GitHub Issue con el idioma, la cadena incorrecta y la corrección sugerida.

::: tip Los PRs de traducción no requieren aprobación previa. Haz un fork del repositorio, realiza tus cambios y abre un PR. Consulta la Guía de contribución para conocer el proceso completo de PR y el requisito del CLA. :::

Cómo crear o actualizar una traducción

1. Fork y clonado

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

2. Copiar el archivo de referencia (solo para un idioma nuevo)

Omite este paso si estás mejorando una traducción existente.

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

3. Traducir las cadenas

Abre tu nuevo archivo y traduce cada valor de cadena. Mantén exactamente igual la estructura del objeto y las claves.

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

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

Reglas:

  • No traduzcas las claves del objeto, solo los valores de cadena
  • Mantén as const al final
  • Importa TranslationKeys desde ./en.js y tipa tu exportación
  • Mantén los marcadores {variable} exactamente como están
  • Los arrays (rotatingPhrases, progressMessages) deben tener el mismo número de entradas
  • No traduzcas: SnapOtter, JPEG, PNG, WebP, EXIF, API y otros términos técnicos

4. Registrar el locale (solo para un idioma nuevo)

Añade tu locale a SUPPORTED_LOCALES en packages/shared/src/i18n/index.ts:

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

5. Verificar

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

6. Enviar

Abre un PR contra main con un título como feat(i18n): add Swedish translation o fix(i18n): correct German typos. El bot del CLA te pedirá que firmes en tu primera contribución.

Añadir nuevas claves de traducción

Al añadir una nueva función que necesita cadenas nuevas en la interfaz:

  1. Añade primero las nuevas claves a en.ts (el archivo de referencia)
  2. Ejecuta pnpm typecheck: cada archivo de locale fallará si le falta la nueva clave
  3. Añade la nueva clave a todos los archivos de locale (usa el inglés como respaldo temporal)

Configuración

Establece el idioma predeterminado de la instancia mediante una variable de entorno:

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

Referencia de archivos

File Purpose
packages/shared/src/i18n/en.ts Cadenas en inglés (locale de referencia, ~1500 claves)
packages/shared/src/i18n/index.ts SUPPORTED_LOCALES, loadTranslations(), exportaciones de tipos
packages/shared/src/i18n/<locale>.ts Archivos de traducción por idioma
apps/web/src/contexts/i18n-context.tsx I18nProvider, hook useTranslation()
apps/web/src/lib/format.ts Helpers format(), plural(), formatFileSize()
apps/api/src/routes/config.ts Endpoint público GET /api/v1/config/locale

Traducir el sitio web, la documentación y la referencia de la API

El soporte de 21 idiomas descrito arriba cubre la aplicación. El sitio web público (snapotter.com), este sitio de documentación y la referencia de la API REST también se traducen a los 21 idiomas, mediante una canalización independiente controlada por hash que reutiliza los mismos nombres y descripciones de herramientas de packages/shared/src/i18n, de modo que la terminología se mantenga coherente en todas partes.

Traducción automática de forma predeterminada

Cada página que no está en inglés del sitio web y de la documentación se traduce automáticamente en la primera pasada (por una sesión de Claude Code, no por un servicio de terceros) y lleva un banner pequeño y descartable que así lo indica, con un enlace de vuelta aquí. Es intencional: así se publican los 21 idiomas de forma rápida y honesta, y luego se invita a la comunidad a refinar las páginas más importantes. La traducción automática transmite el significado; la revisión humana hace que se lea con naturalidad.

Cómo decide la canalización qué traducir

Cada unidad traducible del texto original en inglés se somete a hash, y ese hash se almacena junto a su traducción. En cada ejecución, la canalización:

  • traduce cualquier unidad que todavía no tenga traducción,
  • omite cualquier unidad cuyo hash almacenado siga coincidiendo con el texto original en inglés,
  • vuelve a traducir una unidad automática cuando su texto original en inglés cambia,
  • y marca una unidad refinada por un humano como stale (necesita revisión) cuando su texto original en inglés cambia, en lugar de sobrescribir tu trabajo.

Refinar una traducción del sitio web mediante un PR

Mejoras una traducción del sitio web, de la documentación o de la referencia de la API igual que mejoras un locale de la aplicación: editando el archivo generado y abriendo un PR.

  1. Encuentra la traducción generada para tu idioma:
    • cadenas de la interfaz del sitio web: apps/landing/src/i18n/<locale>.json
    • una página de documentación: apps/docs/<locale>/**.md
    • la referencia de la API: apps/api/src/openapi.<locale>.yaml
  2. Edita el texto. Mantén el código, los enlaces, {placeholders} y cualquier marcador ⸤I18N…⸥ exactamente como están; el validador de la canalización rechaza una traducción que los omita o reordene.
  3. Abre un PR. Editar una unidad cambia su procedencia de machine a human, de modo que la canalización nunca la sobrescribirá en una ejecución posterior. Si el texto original en inglés cambia después, tu unidad se marca como stale para revisión en lugar de reemplazarse en silencio.

Para informar de una traducción incorrecta sin enviar código, abre un GitHub Issue con la URL de la página, el idioma, el texto incorrecto y tu corrección sugerida.

::: tip Los mantenedores ejecutan la canalización de traducción; no necesitas una clave de API para contribuir. Solo edita el archivo generado y abre un PR. Consulta scripts/i18n/README.md para saber cómo se ejecuta la canalización. :::