Documentación
localize.dev convierte el texto codificado en llamadas de traducción en bases de código React, Next.js, React Native, Vue, Nuxt, Svelte, Angular, Astro, Solid, Qwik, Lit, Ember, Flutter, Rails, Django, Laravel, Android, iOS y HTML estático, escribe los diccionarios de localización, configura la biblioteca i18n si no existe y puede abrir la pull request por ti. La traducción se ejecuta en el modelo alojado de localize.dev, por lo que no hay nada que configurar más allá de una clave API.
Inicio rápido
Necesitas Node.js 22 o posterior. Tu aplicación aún no necesita una biblioteca i18n; la primera ejecución configura una. Crea una clave API gratuita en el panel, luego elige tu framework:
React
Cualquier UI renderizada a través de un componente que pueda llamar a useTranslation(): React con Vite, Remix o Gatsby, renderizadores Electron y Tauri, y sistemas de diseño o paquetes de UI compartidos. Los componentes de clase obtienen t a través de withTranslation(), o <Translation> cuando no son la exportación predeterminada del archivo. Las oraciones alrededor de los enlaces permanecen completas con <Trans> (su propio enlace title incluido), se encuentra la copia en constantes, toasts y mensajes zod, y las fechas, números y precios siguen el idioma de la aplicación.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,fr
# Only if the run added packages to package.json
npm installGuía de React: qué cambios, con un antes y después real.
Next.js
Los componentes del servidor del App Router obtienen const { t } = await getTranslation() y componentes cliente useTranslation(), ambos en el idioma que eligió el servidor; el Pages Router funciona como React. Un proxy.ts da a cada página una URL por idioma con hreflang enlaces.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,fr
# Only if the run added packages to package.json
npm installGuía de Next.js: qué cambios, con un antes y después real.
React Native and Expo
React Native y Expo. accessibilityLabel y accessibilityHint también se traducen, y la configuración de i18n evita APIs solo del navegador.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,fr
# Only if the run added packages to package.json
npm installGuía de React Native and Expo: qué cambios, con un antes y después real.
Vue
Texto y {{ }} en <template> se convierten en {{ $t('key') }} y los atributos se convierten en :placeholder="$t('key')", con vue-i18n configurado en src/i18n.ts e instalado en main.ts. Mensajes mostrados desde <script setup> (alert, toasts, document.title) usan t() de useI18n, y n === 1 ? … : … se convierte en un plural de vue-i18n. Una existente createI18n configuración se deja como está. Una frase alrededor de un enlace o texto en negrita sigue siendo un solo mensaje a través de <i18n-t>, con los elementos como slots. Las constantes en <script setup> mostradas por la plantilla ({{ title }}, v-for="tab in tabs") se convierten en claves leídas a través de $t(). Las plantillas escritas en Pug (<template lang="pug">) obtienen lo mismo: h1 {{ $t('key') }}, texto piped y block, y input(:placeholder="$t('key')").
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,fr
# Only if the run added packages to package.json
npm installGuía de Vue: qué cambios, con un antes y después real.
Nuxt
Las páginas y componentes se reescriben como cualquier componente de Vue, y @nuxtjs/i18n se añade a nuxt.config, con una URL por idioma (/es/about) y hreflang enlaces desde useLocaleHead().
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,fr
# Only if the run added packages to package.json
npm installGuía de Nuxt: qué cambios, con un antes y después real.
Svelte and SvelteKit
El marcado se convierte en {$_('key')} con svelte-i18n, inicializado desde src/lib/i18n e importado en +layout (o main.ts sin SvelteKit). Atributos como title="Hello {name}" se convierten en un solo mensaje. En SvelteKit, un generado hooks.server renderiza cada página en el idioma del visitante (su elección guardada, luego Accept-Language), por lo que no hay un destello del idioma de origen.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,fr
# Only if the run added packages to package.json
npm installGuía de Svelte and SvelteKit: qué cambios, con un antes y después real.
Angular
Plantillas (.html e en línea template:) se convierten en {{ 'key' | translate }} con ngx-translate, atributos [placeholder]="'key' | translate" ([attr.aria-label] para aria), y cadenas en enlaces ('key' | translate). Flujo de control (@if, @for), *ngIf y plantillas en línea se entienden; los elementos marcados con los propios de Angular i18n se dejan a él. La configuración añade provideI18n() a app.config.ts (cada locale empaquetado, sin cargador HTTP) y TranslatePipe a cada componente independiente que lo necesite.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,fr
# Only if the run added packages to package.json
npm installGuía de Angular: qué cambios, con un antes y después real.
Astro
Texto y {expressions} en .astro los archivos se convierten en {t('key')}, atributos title={t('key')}, con t de un generado src/i18n módulo que lee el idioma de la URL. Cada página estática obtiene una copia por idioma (src/pages/es/about.astro), por lo que cada idioma es una página real e indexable, y los diseños establecen <html lang dir>. localizePath(path, lang) construye enlaces entre idiomas. Las islas React, Vue y Svelte (de @astrojs/react, /vue, /svelte) se localizan en la misma ejecución, cada una con su propia biblioteca configurada y siguiendo el idioma de la página.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,frGuía de Astro: qué cambios, con un antes y después real.
Solid
JSX como React, con useTranslation() de un generado src/i18n.ts: i18next detrás de una señal de idioma, por lo que el texto se actualiza en su lugar cuando cambia el idioma. Las oraciones alrededor de los enlaces permanecen como un solo mensaje, renderizado por rich(t('key'), { a: (c) => <a href="/terms">{c}</a> }) del mismo módulo.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,fr
# Only if the run added packages to package.json
npm installGuía de Solid: qué cambios, con un antes y después real.
Qwik
JSX en component$ obtiene const { t } = useTranslation() de un generado src/i18n.ts que lee el idioma de la URL (el de Qwik City useLocation), y cada ruta, incluidas las dinámicas, obtiene una copia por idioma en src/routes/es/. Las oraciones alrededor de los enlaces permanecen como un solo mensaje a través de rich() del mismo módulo.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,frGuía de Qwik: qué cambios, con un antes y después real.
Lit
Texto y ${expressions} en html`…` las plantillas se convierten en ${t('key')}, atributos placeholder=${t('key')}. Los componentes obtienen un I18nController para que se vuelvan a renderizar cuando setLanguage() cambia de idioma; las plantillas anidadas, los estilos y los comentarios se dejan solos.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,frGuía de Lit: qué cambios, con un antes y después real.
Ember
Las plantillas Glimmer (.hbs, y <template> en .gjs/.gts) se convierten en {{t "key" name=this.name}} con ember-intl, los atributos placeholder={{t "key"}}, las cadenas en {{if}} (t "key"), y {{if (eq n 1) "item" "items"}} en una oración un plural. Los mensajes van a translations/<locale>.json; una ruta de aplicación generada elige el idioma.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,fr
# Only if the run added packages to package.json
npm installGuía de Ember: qué cambios, con un antes y después real.
Flutter
Text('Hi $name') y argumentos como hintText: se convierten en AppLocalizations.of(context)!.hiName(name), con mensajes en lib/l10n/app_en.arb (claves camelCase, plurales ICU, metadatos de marcadores). const se elimina de los widgets que ahora contienen una búsqueda; las cadenas sin BuildContext en el ámbito se informan. La configuración añade flutter_localizations, generate: true, l10n.yaml, el MaterialApp delegados y la lista de idiomas de iOS.
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,frNo package.json necesario: npx ejecuta la CLI. Guía de Flutter: qué cambios, con un antes y después real.
Static HTML
El texto permanece en la página y obtiene un data-i18n="key" marcador (los atributos obtienen data-i18n-placeholder y similares). Un generado i18n.js carga los archivos de localización e intercambia el texto; añade <select data-i18n-switcher></select> para un menú de idioma. Una frase con elementos en línea (<strong>, enlaces) es un mensaje, reconstruido a partir de los propios elementos de la página. Las traducciones también se agrupan en i18n.js, así que las páginas abiertas desde el disco también funcionan. El texto de un motor de plantillas ({{ }}, {% %}, PHP) se deja intacto.
Los motores de búsqueda solo ven el texto de la página, así que configura "htmlPages": true y "siteUrl" en localize.config.json para escribir también cada página traducida a cada idioma (es/index.html), enlazado con hreflang.
npm install --save-dev localize-dev
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,frGuía de Static HTML: qué cambios, con un antes y después real.
Ruby on Rails
El texto en las vistas ERB se convierte en <%= t('key', name: @user.name) %>, con %{name} marcadores de posición en config/locales/<locale>.yml y plurales llamados con count:. available_locales y un switch_locale de acción se añaden.
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,frNo package.json necesario: npx ejecuta la CLI. Guía de Ruby on Rails: qué cambios, con un antes y después real.
Django
Las plantillas obtienen {% translate '…' %} y {% blocktranslate %}, las traducciones van a locale/<lang>/LC_MESSAGES/django.po, y la configuración obtiene LANGUAGES, LOCALE_PATHS y LocaleMiddleware.
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,frNo package.json necesario: npx ejecuta la CLI. Guía de Django: qué cambios, con un antes y después real.
Laravel
El texto de Blade se convierte en {{ __('Hi :name', ['name' => $user->name]) }} con lang/<locale>.json indexados por el texto, y un SetLocale el middleware elige el idioma (?locale=, una lang cookie, luego Accept-Language).
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,frNo package.json necesario: npx ejecuta la CLI. Guía de Laravel: qué cambios, con un antes y después real.
Android
android:text, hint y contentDescription en layouts y menús se convierten en @string/…, y Compose Text("Hi $name") dentro de @Composable funciones se convierte en stringResource(R.string.…, name). Ver código en Kotlin o Java (label.setText("Hi"), label.text = "Hi") se convierte en setText(R.string.…). Las cadenas van a res/values-<lang>/strings.xml con numeradas %1$s marcadores de posición, y locales_config.xml enumera los idiomas para Android 13+.
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,frNo package.json necesario: npx ejecuta la CLI. Guía de Android: qué cambios, con un antes y después real.
iOS
texto de SwiftUI (Text("Hi \(name)"), Button, .navigationTitle) permanece como está escrito, ya que SwiftUI lo busca en el propio Catálogo de Cadenas; las cadenas de UIKit (label.text = "Hi") se convierten en String(localized: "Hi"). Todo va en Localizable.xcstrings con cada idioma en el mismo archivo. Agrega el catálogo a tu destino de la aplicación en Xcode una vez.
# Save your API key on this machine
npx localize-dev login
# See what would change, without writing anything
npx localize-dev run --dry-run -l es,fr
# Rewrite the code and write the locale files
npx localize-dev run -l es,frNo package.json necesario: npx ejecuta la CLI. Guía de iOS: qué cambios, con un antes y después real.
¿Quieres echar un vistazo antes de registrarte? npx localize-dev scan enumera cada cadena que extraerá, y --offline genera claves sin traducir. Ninguno necesita una clave ni usa tu cuota. Una ejecución posterior en línea completa las traducciones faltantes sin tocar las claves existentes.
Bases de código compatibles
Cada framework obtiene su propio escáner y biblioteca de i18n. Lo que cambia en cada uno está bajo su nombre en la inicio rápido, y en su guía.
Monorepos: ejecute desde la raíz con --workspaces (o el de la Acción workspaces: true) para localizar cada aplicación, cada una con sus propios archivos de idioma. Las bibliotecas de componentes compartidas (paquetes sin dev o start script) también se traducen, en los idiomas de las aplicaciones que dependen de ellas, y sus mensajes se añaden a los archivos de idioma de esas aplicaciones, de modo que t() las llamadas se resuelven a través de la configuración propia de cada aplicación. Para localizar una sola app, indique a la Action working_directory: apps/web en su lugar: lee el localize.config.json, el código y los archivos de idioma de esa app, y la pull request los cambia en su sitio.
El framework se detecta desde package.json (o pubspec.yaml, o los archivos cuando no hay ninguno); establezca "framework" en localize.config.json para anularlo. Los diccionarios de React usan marcadores de posición i18next o ICU; Vue, Svelte y HTML usan {name}.
Archivos de idioma existentes
¿Ya tienes i18n configurado, en cualquier stack? localize-dev translate omite el código y rellena lo que falta en tus archivos de localización: claves sin traducción aún, en todos los idiomas que ya tienes, o en nuevos que nombres. Las traducciones existentes nunca se modifican, y no se detecta ningún framework, por lo que funciona para cualquier stack, iOS y Android nativos, Rails y Django incluidos.
# Fill in what's missing in the languages already there
npx localize-dev translate --dry-run
npx localize-dev translate
# Add languages (creates the files)
npx localize-dev translate -l de,ja,pt-BR
# Or as a pull request
npx localize-dev pr --translate| Formato | Archivos | Notas |
|---|---|---|
| JSON | locales/en.json, public/locales/en/*.json | i18next (con _one/_other para pluralidad), ICU (react-intl, next-intl, incluyendo coincidencias =0 y select), vue-i18n, ngx-translate, Transloco |
| YAML | config/locales/en.yml, devise.en.yml | Ruby on Rails, bajo la clave de idioma; mapeo de pluralidad (uno/otro) |
| gettext | locale/fr/LC_MESSAGES/django.po | Django, WordPress, PHP, Python. Las entradas vacías y ambiguas se completan; los slots de pluralidad siguen las formas plurales. Las nuevas lenguas se crean junto a una existente, con sus propias formas plurales. |
| Flutter | lib/l10n/app_en.arb | Mensajes ICU; las descripciones @key se convierten en contexto. gen-l10n detecta los nuevos archivos. |
| Android | res/values/strings.xml | <string> y <plurals>; translatable="false", <xliff:g> y escapes respetados. Escribe valores-es/, valores-pt-rBR/. |
| Apple | Localizable.xcstrings, en.lproj/*.strings | Catálogos de cadenas obtienen cada idioma en su lugar, incluyendo pluralidad; los archivos .strings reciben nuevas carpetas .lproj (añadir los idiomas en Xcode). |
| Extensiones del navegador | _locales/en/messages.json | Los placeholders se copian en cada idioma. |
Los marcadores de posición en la sintaxis propia de cada formato ({{name}}, %{name}, %1$s, %@, %(name)s, $NAME$) están protegidos: una traducción que pierde o añade uno, o reordena los no nombrados como %s, se descarta y se informa. Los plurales obtienen cada forma que el idioma de destino necesita (el ruso recibe one, few y many). Los comentarios y descripciones en los archivos se envían al modelo como contexto.
Copia editada: localize.lock.json mantiene una huella digital de cada mensaje de origen cuando se traduce. Cambie el inglés y el siguiente run, translate o la ejecución de la Acción lo traduce de nuevo en cada idioma; check falla en traducciones que quedan desactualizadas. Confirme el archivo.
En la Acción de GitHub, establezca mode: translate. Cada ejecución abre o actualiza una solicitud de extracción con lo que falte, por lo que las nuevas claves añadidas en inglés se traducen a medida que llegan.
Crowdin, Phrase, Lokalise, Transifex
¿Trabaja con traductores en un TMS? Envíe sus archivos de idioma de origen allí y recupere sus traducciones. Agregue el proyecto a localize.config.json (provider: crowdin, phrase, lokalise o transifex) y ponga el token de la API en CROWDIN_TOKEN, PHRASE_TOKEN, LOKALISE_TOKEN o TRANSIFEX_TOKEN (nunca en el archivo de configuración):
{
"tms": { "provider": "crowdin", "projectId": "123456" }
}# Upload source files (and, the first time, your existing translations)
npx localize-dev sync push --translations
# Download translations into your locale files
npx localize-dev sync pullJSON, YAML, ARB, Android, .strings y los archivos de extensión se sincronizan. Crowdin mantiene tus carpetas, Phrase mantiene cada archivo separado con una etiqueta, Lokalise almacena cada uno en su ruta con el idioma como %LANG_ISO%, y Transifex obtiene un recurso por archivo (projectId como o:acme:p:web). Los idiomas se emparejan con los códigos propios del proyecto (es → es-ES, pt-BR → pt_BR). Para Crowdin Enterprise o el centro de datos de Phrase en EE. UU., establezca "url" a su dirección API. Los archivos gettext y String Catalog se gestionan mejor con las integraciones propias del TMS. Un bucle común: ejecute localize-dev run o translate para traducciones automáticas, envíe, permita que los revisores editen, recupere.
comandos CLI
- localize-dev init
- Escribe un localize.config.json con todos los valores predeterminados explicados.
- localize-dev init --agent [--pre-commit]
- Configura agentes de codificación para traducir texto mientras lo escriben: el servidor MCP para Claude Code y Cursor, un hook post-edición para Claude Code, e instrucciones en AGENTS.md y una regla de Cursor. --pre-commit también verifica los archivos preparados antes de cada commit. Cómo funciona.
- localize-dev login [--api-key ldv_live_…]
- Guarda tu clave API para esta máquina. Sin
--api-keysolicita, o lee la clave desde stdin. - localize-dev whoami
- Muestra el espacio de trabajo, el plan y el uso de la clave actual.
- localize-dev logout
- Elimina la clave guardada de esta máquina.
- localize-dev scan [-d src] [-o extracted_strings.json]
- Enumera todas las cadenas que se extraerían, más las omitidas y por qué. No cambia nada; no se necesita clave.
- localize-dev run [--dry-run] [--offline] [--workspaces] [--files a.tsx… | --changed | --staged] [-l es,fr] [-d src] [--api-key …]
- El pase completo: extraer, nombrar claves, traducir, reescribir archivos, actualizar diccionarios y configurar la biblioteca i18n si la aplicación no tiene ninguna. Con
--workspaces, cada aplicación en un monorepo por turno. - localize-dev translate [--dry-run] [-l de,ja] [-s en] [--api-key …]
- Rellena las traducciones que faltan en los archivos de localización existentes, para cualquier pila. El código no se toca. Formatos.
- localize-dev check [--only strings|translations] [--files a.tsx… | --changed | --staged] [--json]
- Falla CI en copias codificadas, traducciones faltantes y traducciones desactualizadas con su fuente; reporta claves no utilizadas y, con un idioma de derecha a izquierda, estilos de izquierda/derecha. Detalles.
- localize-dev prune [--dry-run]
- Elimina claves a las que ningún código hace referencia del archivo de localización de cada idioma.
- localize-dev rtl [--fix]
- Enumera los estilos fijados a la izquierda o a la derecha;
--fixintercambia los seguros por los lógicos. De derecha a izquierda. - localize-dev content [--dry-run] [-l de,ja]
- Traduce documentos Markdown y MDX a una copia por idioma. Documentación y contenido.
- localize-dev sync push|pull [--translations] [-l de,ja]
- Envía archivos de localización de origen a Crowdin, Phrase, Lokalise o Transifex, o recupera sus traducciones. Configuración.
- localize-dev seo <url> [--limit 500] [--json]
- Comprueba lo que los motores de búsqueda ven de cada idioma en un sitio, en vivo o en una compilación local: el sitemap, los enlaces hreflang, <html lang>, la dirección canónica y og:locale. Sale con 1 cuando encuentra un problema, para que pueda ejecutarse en CI después de un despliegue Detalles.
- localize-dev pr [--translate] [--base main] [--repo owner/name] [--branch name] [--token …]
- Ejecuta el pass y abre (o actualiza) una solicitud de extracción en
localize-dev/<base>en lugar de escribir localmente. UsaGITHUB_TOKENcuando--tokense omite. Con--translate, la solicitud de extracción solo completa las traducciones faltantes.
Agentes de codificación
localize-dev mcp ejecuta un servidor MCP, para que un agente de codificación (Claude Code, Cursor, Codex, GitHub Copilot y otros) pueda verificar y localizar el repositorio en el que está trabajando. Lovable, Bolt, v0 y otros constructores que se ejecutan en el navegador se conectan al servidor alojado en https://uselocalize.dev/api/mcp con una clave API. La configuración de cada agente está en la página MCP. Para que el agente traduzca texto mientras lo escribe, ejecute esto en la carpeta de la aplicación:
npx localize-dev init --agent # MCP server, Claude Code hook, AGENTS.md, Cursor rule
npx localize-dev init --agent --pre-commit # also check staged files before each commitEscribe estos archivos:
.mcp.jsony.cursor/mcp.json: el servidor MCP, para Claude Code y Cursor..claude/settings.json: un hook post-edición que ejecutanpx -y localize-dev hook. Cuando un archivo que Claude Code edita tiene texto que no está traducido, el hook enumera las líneas y el agente llama alocalizeen ese archivo antes de continuar.AGENTS.md, y unCLAUDE.mdque lo importa cuando no hay ninguno: cuándo llamar alocalizeycheck. Una regla de Cursor en.cursor/rules/localize.mdcdice lo mismo para sus archivos de UI.- Con
--pre-commit:check --stageden el hook de pre-commit de husky, o el propio de git.
En un monorepo, las instrucciones nombran la aplicación. Se conservan su configuración, servidores y texto existentes, y una segunda ejecución no cambia nada. Confirme los archivos para que el equipo y sus agentes los compartan. El hook solo lee el archivo, sin clave ni modelo, y tarda aproximadamente un segundo; LOCALIZE_DEV_HOOK=off lo pausa. Las cadenas que un agente traduce a través del servidor MCP se muestran como "Mientras se escribe" en la página de uso.
Configuración de i18n
Vue, Nuxt, Svelte y HTML estático están configurados como se describe en Bases de código compatibles. En React, los componentes reescritos llaman a useTranslation(), así que la aplicación necesita i18next en ejecución. Cuando no lo está, la ejecución (y la solicitud de extracción de la Acción) añade lo que falta:
i18nextyreact-i18nextenpackage.json. La Acción también actualiza tu archivo de bloqueo (npm, pnpm, Yarn o Bun); después de una ejecución local, ejecuta tu instalación.src/i18n.ts(o.js), que carga los archivos de localización y elige el idioma de una opción guardada, luego del navegador, luego de tu idioma de origen. Con más de tres idiomas de destino, solo se empaqueta el de origen y el resto se carga cuando se usa por primera vez ("lazyLocales"para elegir). En aplicaciones Remix sin v3_routeConfig, las páginas se hidratan en su<html lang>y cambian después de cargar.- Un
import './i18n'en tu archivo de entrada: el script enindex.html, de lo contrariosrc/main.*osrc/index.*. resolveJsonModuleentsconfig.json, para que los archivos de idioma puedan importarse.- Una importación en tu archivo de configuración de pruebas (Vitest
setupFiles, JestsetupFilesAfterEnv,src/setupTests), para que las pruebas que buscan texto aún lo encuentren. Vue obtiene vue-i18n instalado para@vue/test-utils. - Una línea en
.gitattributesque combina archivos de idioma clave por clave, para que dos ramas que añaden claves no entren en conflicto. Actívalo una vez por clon congit config merge.localize-dev.driver "npx localize-dev merge-locales %O %A %B %P"(las fusiones en GitHub no lo ejecutan). src/language-switcher.tsx, exportando<LanguageSwitcher />yuseLanguage()con los valores predeterminados de esta app, ylocalize-devcomo dependencia. Renderiza el conmutador donde las personas eligen un idioma, como en tu encabezado; no está colocado automáticamente. Opciones.
Si algún archivo ya inicializa i18next, nada de esto se añade y tu configuración se usa tal cual. El conmutador guarda la elección en localStorage y la restaura en la próxima visita; para cambiar desde tu propio código, llama a i18n.changeLanguage('es') y guarda lang de la misma manera. Los proyectos configurados por una versión anterior obtienen el conmutador en su próxima ejecución. En el enrutador de páginas de Next.js, la importación va en pages/_app.
Enrutador de aplicaciones Next.js
Archivos en app/ sin 'use client' son componentes del servidor, que no pueden usar hooks. Reciben const { t } = await getTranslation() en su lugar (el componente se convierte en async si no lo era), desde un módulo generado i18n.server módulo que selecciona el idioma desde una lang cookie, luego la del navegador Accept-Language. Los componentes cliente mantienen useTranslation(). El diseño raíz está envuelto en un módulo generado <I18nProvider> que entrega a los componentes cliente el mismo idioma, y <html lang> lo sigue. El conmutador generado establece lang cookie y actualiza, para que los componentes del servidor se vuelvan a renderizar en el nuevo idioma.
Selector de idioma
<LanguageSwitcher /> es un menú de los idiomas que tu aplicación incluye (tu idioma de origen y los idiomas de destino que configuraste), cada uno con su bandera y su propio nombre. Funciona con el teclado (flechas, Inicio/Fin, Intro, Escape, escribir un nombre) y lectores de pantalla, recuerda la elección y establece <html lang> y dir para idiomas de derecha a izquierda.
import { LanguageSwitcher, useLanguage } from './language-switcher';
<LanguageSwitcher /> // flag + native name
<LanguageSwitcher compact /> // just the flag
<LanguageSwitcher nameStyle="native-english" /> // Español · Spanish
<LanguageSwitcher languages={['en', 'es']} /> // choose and order the list
<LanguageSwitcher regions={{ en: 'GB', pt: 'BR' }} /> // which country's flag
<LanguageSwitcher renderFlag={(l) => <img src={`/flags/${l.code}.svg`} alt="" />} />
<LanguageSwitcher unstyled className="…" buttonClassName="…" menuClassName="…" optionClassName="…" />
// Anywhere else: the current language and the list
const { language, info, languages, setLanguage, isRTL } = useLanguage();
info.flag // "🇪🇸"
info.nativeName // "Español"Otras props: showFlag, align (start/end), side (top/bottom), label, disabled, renderButton, renderOption, persist (localStorage, cookie o none), storageKey y onChange. Los estilos integrados leen variables CSS, por lo que un tema o modo oscuro son unas pocas líneas: --ldv-bg, --ldv-fg, --ldv-border, --ldv-hover, --ldv-muted, --ldv-accent, --ldv-radius, --ldv-shadow. Las opciones seleccionadas y resaltadas llevan data-selected y data-active para tu propio CSS. Fuera de React, getLanguageInfo('pt-BR') devuelve los mismos nombres, bandera y dirección.
En el App Router de Next.js, el archivo generado guarda la elección en la lang cookie y se refresca, por lo que los componentes del servidor siguen. Las banderas emoji se muestran como dos letras en Windows; pasa renderFlag para imágenes allí.
Todos los demás frameworks reciben el mismo menú, generado para sus propios componentes y su estado, basado en <localize-language-switcher> (elemento personalizado de localize-dev/switcher): acepta las mismas opciones como atributos, emite language-change y se estiliza con las mismas variables --ldv-* o con ::part(button|menu|option|flag).
Vue src/language-switcher.ts <LanguageSwitcher />, useLanguage()
Nuxt components/LanguageSwitcher.ts auto-imported, with composables/useLanguage.ts
Svelte LanguageSwitcher.svelte the $language store from language.ts
Solid, Qwik src/language-switcher.tsx <LanguageSwitcher />, useLanguage()
Angular language-switcher.component.ts <app-language-switcher />, languageOf(translate)
Astro components/LanguageSwitcher.astro useLanguage(Astro.url) from i18n/language.ts
Lit src/language-switcher.ts <app-language-switcher>, useLanguage()
Ember components/language-switcher <LanguageSwitcher />, the language service
React Native language-switcher.tsx a native picker, useLanguage()
HTML <localize-language-switcher> from the CDN; i18n.js switches on language-change
Rails shared/_language_switcher.html.erb render "shared/language_switcher", current_language
Django language_switcher.html {% include %}, {{ language }} in every template
Laravel <x-language-switcher /> App\Support\Language::current()
Flutter lib/language_switcher.dart LanguageSwitcher(), language.of(context)
iOS LanguageSwitcher.swift LanguageSwitcher(), LanguageStore.shared, .appLanguage()
Android LanguageSwitcher.kt LanguageSwitcher(), showLanguagePicker(context)Claves de API
Las claves se ven como ldv_live_… y pertenecen a un espacio de trabajo; cada clave en un espacio de trabajo comparte su asignación mensual. La CLI busca una clave en este orden:
- el
--api-keyindicador - el
LOCALIZE_API_KEYvariable de entorno (úsala en CI) - la clave guardada por
localize-dev login, en~/.config/localize-dev/credentials.json(legible solo por ti)
Solo almacenamos un hash de cada clave, por lo que el secreto se muestra una vez, al crearlo. Revoca una clave desde el panel y dejará de funcionar inmediatamente.
Configuración
Todo es opcional. Coloca las sobrescrituras en localize.config.json en la raíz del proyecto; los flags de CLI prevalecen sobre el archivo.
| Campo | Predeterminado | Descripción |
|---|---|---|
| srcDir | "src" | Directorio a escanear. |
| framework | detected | react, react-native, vue, svelte o html. Detectado desde package.json y luego desde los archivos. |
| include / ignore | by framework / tests, stories, .d.ts | Patrones globales relativ a srcDir: *.{tsx,jsx}, *.vue, *.svelte o *.html. |
| sourceLocale | "en" | Idioma del texto codificado de forma fija. |
| targetLocales | ["es", "fr"] | Idiomas a traducir. |
| localesPath | "locales/{locale}.json" | Ubicación del diccionario, p.ej. public/locales/{locale}/common.json. |
| attributes | placeholder, alt, title, aria-label, label, tooltip | Atributos tratados como texto de la interfaz. React Native añade accessibilityLabel y accessibilityHint. |
| importSource | "react-i18next" | React: desde dónde se importa useTranslation, p.ej. next-i18next. |
| interpolation | by framework | i18next escribe {{name}} (React); ICU escribe {name} (Svelte, HTML); Vue escribe {name} con caracteres especiales escapados por vue-i18n. |
| htmlPages | false | HTML estático: también escribe cada página traducida por idioma (es/index.html), para motores de búsqueda. |
| siteUrl | none | La dirección del sitio, p.ej. https://example.com. Necesario para enlaces hreflang entre versiones de idioma. |
| localizeFormats | true | Haz que fechas, números y precios codificados en un solo idioma sigan el idioma de la app. |
| currency | "USD" | Qué significa un $ sin más antes de una cantidad cuando los precios están localizados, p.ej. "CAD". |
| lazyLocales | más de 3 idiomas | React: empaqueta solo el idioma de origen y carga los demás cuando se usan por primera vez. |
| content | none | Documentos Markdown y MDX para contenido de localize-dev: { "include": ["docs/**/*.md"], "output": "{dir}/{name}.{locale}{ext}" }. |
Acción de GitHub
La acción ejecuta la misma pasada en CI y abre una solicitud de extracción contra la rama que la activó. Las re-ejecuciones actualizan la misma rama y PR. Antes de la primera ejecución, guarda tu clave API en el repositorio:
- 1
Copia tu clave de API
Empieza conldv_live_y solo se muestra una vez. ¿Lo perdiste? Crea uno nuevo en la Claves API página. - 2
Abre los secretos de Actions del repositorio
En GitHub, abre tu repositorio y ve a Configuración → Secretos y variables → Acciones, luego haz clic en Secreto de repositorio nuevo. Necesitas acceso de administrador al repositorio para ver Configuración. - 3
Añade el secreto
Nombre:LOCALIZEDEV_API_KEYSecreto: pegue su clave, sin espacios ni saltos de línea. Luego haga clic en Agregar secreto. GitHub oculta el valor a partir de ese momento; para cambiarlo, actualice el secreto. - 4
Sin la GitHub App de localize.dev: permite que la Action abra solicitudes de extracción
En Configuración → Acciones → General, bajo Permisos de flujo de trabajo, marca Permitir que GitHub Actions cree y apruebe solicitudes de extracción y haz clic Guardar. Sin esto, la ejecución traduce todo pero falla al abrir la solicitud de extracción. Si la opción está deshabilitada, un propietario de la organización debe habilitarla primero en Configuración → Acciones → General.
Luego confirma el flujo de trabajo:
name: Localize
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize]
workflow_dispatch: # "Run workflow" button in the Actions tab
permissions:
contents: write # push the localize-dev/<branch> branch
pull-requests: write # open or update the localization PR
# One run per branch at a time; a newer push supersedes the running one.
concurrency:
group: localize-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
jobs:
localize:
runs-on: ubuntu-latest
timeout-minutes: 60
# Skip localize.dev's own branches, and fork PRs (their token is read-only).
if: >-
!startsWith(github.head_ref || github.ref_name, 'localize-dev/') &&
(github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
steps:
- name: Checkout
uses: actions/checkout@v5
with:
# On PRs, scan the branch itself rather than the merge commit.
ref: ${{ github.head_ref || github.ref_name }}
- name: Localize
uses: ufortstephen/autolocalize-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
api_key: ${{ secrets.LOCALIZEDEV_API_KEY }}
target_locales: 'es,fr,de'
# src_dir: 'src' # default: your framework's (src, app/views, resources/views, lib…)
# locales_path: 'public/locales/{locale}/common.json' # default: your framework's
# working_directory: 'apps/web' # monorepo: localize just this appOtros insumos: src_dir, locales_path, base_branch, api_url, offline (sin clave necesaria), workspaces (cada app en un monorepo), working_directory (una app de un monorepo), tms_pull / tms_push (con tms_token: traer traducciones revisadas a la solicitud de extracción, subir archivos fuente desde la rama predeterminada), mode: translate (solo completar archivos de idioma existentes). Resultados: pr_url, strings_count.
Cada ejecución informa cuando termina: la página del proyecto en el panel muestra las ejecuciones recientes con su solicitud de extracción, cadenas reemplazadas, traducciones por idioma y el error si falló.
Vista previa de la solicitud de extracción
¿Quieres verlo en tu propio código antes de configurar algo? Conecta el repositorio en el panel y elige Abrir una vista previa de solicitud de extracción en su página. localize.dev lee la rama predeterminada, localiza hasta 200 cadenas en el primer idioma del proyecto en el servidor y abre una solicitud de extracción desde localize-dev/preview. No se necesita flujo de trabajo, clave API ni checkout; los cadenas cuentan para tu plan, y las traducciones aparecen en la pestaña Revisar como cualquier ejecución. Ejecutarlo nuevamente actualiza la misma solicitud de extracción.
En un monorepo, cada app se localiza por turno hasta usar las 200 cadenas. Los archivos en Git LFS y submódulos no están en el archivo que proporciona GitHub, por lo que se dejan fuera, y un repositorio muy grande solo se lee parcialmente; la solicitud de extracción lo indica. La acción de GitHub no tiene límite.
Verificación CI
localize-dev check fallo (código de salida 1) cuando el texto aún está codificado, falta traducción en un idioma, o las traducciones están desactualizadas porque su inglés cambió desde (desde localize.lock.json), y enumera cada una. También informa las claves que el código no usa (elíminalas con localize-dev prune), texto en hojas de estilo (content: "New"), mensajes que muestran un valor almacenado tal cual (Status: {{status}} muestra "paid") y, cuando un idioma de destino va de derecha a izquierda, estilos fijados a la izquierda o a la derecha, y next/font fuentes a las que les faltan letras de un idioma de destino; esas no fallan la comprobación. Una clave que usa el código y que el archivo de idioma de origen no tiene sí falla, ya que la gente vería la clave en sí. Solo lee archivos: sin clave API, nada enviado. En GitHub Actions, cada problema también es una anotación en la diferencia de la solicitud de extracción.
npx localize-dev check # both
npx localize-dev check --only strings # hardcoded copy only
npx localize-dev check --only translations # missing translations only
npx localize-dev check --json
npx localize-dev check --staged # files staged for the next commit (pre-commit hook)
npx localize-dev check --changed # files changed since the last commit, and new onesCon --files, --changed o --staged, check solo mira esos archivos: copias codificadas y claves que faltan en el archivo de locale de origen. Omite las comprobaciones de todo el proyecto, por lo que se ejecuta en aproximadamente un segundo, lo suficientemente rápido para un hook de pre-commit o un hook post-edición de un agente. run toma las mismas opciones.
O en un flujo de trabajo que se ejecuta en solicitudes de extracción, con la Acción:
on: pull_request
jobs:
i18n:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ufortstephen/autolocalize-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
mode: checkPseudolocalización
Antes de pagar por una traducción individual, comprueba dónde se rompe tu diseño. --pseudo escribe un en-XA idioma: cada mensaje acentuado, aproximadamente un 35% más largo (como el alemán o el finés) y entre corchetes, con marcadores de posición y etiquetas conservados exactamente, para que la aplicación se ejecute como lo haría con una traducción real. Cambia a él y busca botones recortados, tarjetas desbordadas y cualquier cosa sin corchetes: esa copia todavía está codificada.
npx localize-dev run --pseudo # en-XA: [Šáṽé çĥáñĝéš one two]
npx localize-dev run --pseudo rtl # ar-XB: right to left
npx localize-dev translate --pseudo # from existing locale files, code untouchedSin modelo ni clave: no utiliza tu asignación. Tus idiomas reales permanecen como están. La zona de juegos también lo tiene, como el en-XA idioma.
Fechas, números y dinero
En aplicaciones React, React Native, Electron, Tauri, Solid, Vue y Svelte, también se reescriben fechas, números y precios codificados de forma rígida a una configuración regional, para que sigan el idioma de la aplicación:
date.toLocaleDateString('en-US', …)ynew Intl.NumberFormat('en-US')toman el idioma de la aplicación en su lugar (y lo mismo ocurre con las llamadas sin idioma, que usan el del navegador).`$${price}`y<span>${price}</span>se convierten en formato de moneda, por lo que$1,234.50se lee1.234,50 $en alemán.€,£,¥,₹,₦,CA$,A$y otros símbolos se mapean a su moneda; un simple$es USD a menos que"currency"enlocalize.config.jsondiga lo contrario.- En las plantillas y scripts de Vue, el idioma proviene de vue-i18n (
$i18n.locale); en Svelte, de svelte-i18n$locale.
Fechas de date-fns (format(d, 'MMM d, yyyy')), dayjs y moment se convierten en Intl.DateTimeFormat con las mismas partes; los tiempos relativos (formatDistance, fromNow) se enumeran para que cambies a Intl.RelativeTimeFormat. localeCompare y mayúsculas o minúsculas mostradas en JSX usan el idioma de la aplicación (i turca). Las listas también siguen el idioma: {tags.join(', ')} en JSX y un `${xs.slice(0, -1).join(', ')} and ${xs[xs.length - 1]}` se convierten en Intl.ListFormat, así que el japonés obtiene 、 y el español su propio "y". Las solicitudes de extracción enumeran cada cambio. Desactívalo con "localizeFormats": false en localize.config.json. Las aplicaciones de Next.js App Router se dejan como están por ahora, ya que sus componentes cliente obtienen el idioma a través de un proveedor.
Una URL por idioma
Los motores de búsqueda indexan cada idioma cuando tiene su propia URL. En las aplicaciones de Next.js App Router, el generado proxy.ts (middleware.ts antes de Next 16) sirve /es/about con el /about página en español, sin mover tus archivos, y <LanguageAlternates /> en el layout raíz añade hreflang enlaces entre las versiones. Las URL sin prefijo siguen siguiendo la lang cookie y el navegador, y el menú de idioma se mueve entre URL con prefijo.
Las aplicaciones Nuxt obtienen @nuxtjs/i18n's prefix_except_default URLs con useLocaleHead() en app.vue; establecer "siteUrl" para enlaces absolutos. Los sitios estáticos obtienen lo mismo de htmlPages. Una app con su propio proxy o middleware la mantiene: la ejecución explica las dos cabeceras (x-localize-lang, x-localize-path) para establecer allí.
Los títulos y descripciones de página también siguen. Next.js export const metadata se convierte en un generateMetadata que usa el traductor de la solicitud (el de una plantilla de título %s mantenido), y uno existente generateMetadata obtiene t. En aplicaciones de una sola página (Vite React, Vue, Svelte, Angular, Solid), index.html's <title> y la descripción son traducidos y establecidos por el módulo generado cuando cambia el idioma; el archivo los mantiene como están escritos para la primera carga.
Para los motores de búsqueda, el diseño raíz también obtiene una dirección canónica y og:locale para la URL de cada idioma, desde el generado i18n-seo.ts. app/sitemap.ts enumera cada página con una dirección fija (sin rutas [slug], áreas de inicio de sesión o carpetas privadas) en cada idioma, con alternativas hreflang. Un robots.ts apunta a él. Ambos se escriben solo cuando la aplicación no tiene ninguno de los dos, y puede editarlos. Establezca "siteUrl" para que el sitemap tenga direcciones completas. Cuando no está configurada, la dirección proviene de un archivo CNAME o de la página de inicio en package.json, y en Vercel, Netlify, Render o Railway de la dirección que el host le da a la compilación.
Los diseños de Astro obtienen un componente I18nHead en su head, con los mismos enlaces y og:locale. SvelteKit 2.3 y posteriores sirven cada idioma en su propia dirección a través de un hook de reenvío en src/hooks.ts, por lo que las rutas no necesitan una carpeta [lang], y hooks.server agrega los enlaces a cada página. Ambos obtienen un sitemap.xml creado a partir de la carpeta de páginas o rutas, por lo que las nuevas páginas se enumeran sin ejecutar localize nuevamente, y un robots.txt cuando la aplicación no tiene ninguno.
Las aplicaciones de Qwik City obtienen un componente LanguageHead en root.tsx con los mismos enlaces, y las mismas rutas de sitemap y robots.
Las aplicaciones de React Router (modo framework) obtienen cada ruta de nuevo en cada idioma, por lo que /es/about es la página acerca de en español. El archivo de rutas pasa sus rutas a través de withLanguageRoutes desde app/i18n-routes.ts, y la raíz renderiza cada página en el idioma de su dirección, con los mismos enlaces. Los enlaces sin idioma conservan el idioma de la página, y las rutas sitemap.xml y robots.txt se agregan cuando la aplicación no tiene ninguna. Con más de tres idiomas, los que no están en el paquete se cargan en el cargador de la ruta, por lo que el servidor también los renderiza.
Las aplicaciones Remix 2 obtienen lo mismo cuando v3_routeConfig está activado en vite.config y las rutas están en app/routes.ts (configuración de ruta de Remix). Sin él, la ejecución dice qué cambiar.
Los sitios estáticos con htmlPages y siteUrl también obtienen un sitemap.xml que enumera cada página en cada idioma, y un robots.txt cuando no tienen ninguno.
El idioma del visitante se compara exactamente, por idioma, o con una variante regional que la aplicación ofrece: un navegador configurado en pt-PT obtiene el pt-BR.
Para ver lo que ven los motores de búsqueda, apunte localize-dev seo al sitio. Funciona en cualquier sitio, configurado por localize.dev o no.
npx localize-dev seo https://example.com # the live site
npx localize-dev seo http://localhost:3000 # a local build, before you deployLee robots.txt y el sitemap, luego carga cada página y las páginas que nombran sus enlaces hreflang. Informa sobre páginas que no cargan o redirigen, enlaces hreflang sin la dirección completa o sin x-default, un idioma cuya página no enlaza de vuelta, un <html lang> u og:locale que no coincide con el idioma de la página y un enlace canónico que apunta a otro lugar. Las direcciones en otro origen (siteUrl, cuando compruebas una compilación local) se cargan desde la dirección que proporcionas.
Revisando traducciones
Las traducciones automáticas de las ejecuciones de GitHub Action y las solicitudes de extracción de la CLI (pr, pr --translate) aparecen en el Revisar pestaña, origen y traducción uno al lado del otro, filtrable por idioma. Aprueba uno por uno o todos a la vez, o edita uno: una edición debe mantener los marcadores de posición del origen y reemplaza la entrada de memoria de traducción del espacio de trabajo, por lo que cada ejecución posterior usa la corrección. Los mensajes plurales muestran cada forma que el idioma necesita (el ruso one, few, many…) y se editan forma por forma.
Aplicar cambios a la pull request confirma tus cambios en la pull request de localización abierta de la ejecución de la que provienen, en sus archivos de localización JSON, a través de la GitHub App. Los cambios que no se pueden colocar (otros formatos de archivo o una pull request fusionada) llegan a la siguiente ejecución a través de la memoria de traducción.
Cada traducción mantiene un hilo de notas para el siguiente revisor, y muestra quién lo aprobó o editó y cuándo. Cuando la misma corrección sigue apareciendo, la pestaña sugiere un término del glosario: una palabra de origen que siempre debe traducirse de cierta manera (checkout → pago), o un nombre que los revisores siguen restaurando y que debe permanecer sin traducir. Un clic lo agrega al glosario del proyecto, que cada ejecución sigue.
Asignar un revisor por idioma de los miembros del espacio de trabajo. Cuando una ejecución trae nuevas traducciones en su idioma, reciben un correo electrónico por la ejecución con un enlace a la pestaña. Cada fila enlaza al archivo fuente del que proviene en GitHub. El modelo marca las traducciones de las que no está seguro (una palabra ambigua, un modismo, una suposición formal o informal) con su razón, y la pestaña se abre en esas, debajo de Necesita revisión; Aprobar el resto las deja para una persona. En el código muestra las líneas alrededor de donde se usa, leídas de la solicitud de extracción del run, para que la copia se pueda verificar donde se muestra.
Glosario
Cada proyecto tiene un glosario en su página de panel: términos que nunca deben traducirse (nombres de marca y producto), traducciones preferidas para su vocabulario y una nota de estilo como "informal; use du en alemán". Se aplica a cada solicitud de las ejecuciones de GitHub Action y CLI del proyecto. Las traducciones que cambian un término que nunca se traduce se rechazan; las traducciones preferidas y la nota de estilo guían al modelo.
Planes y límites
| Plan | Cadenas / mes | Idiomas |
|---|---|---|
| Free | 1000 | 3 |
| Pro | Ilimitado | 5 |
| Team | Ilimitado | Ilimitado |
Una cadena cuenta una vez sin importar en cuántos idiomas se traduzca. Las asignaciones se ejecutan en períodos de 30 días: desde el día en que se creó su espacio de trabajo o desde su fecha de facturación en un plan de pago. El panel muestra cuándo se restablece el suyo. El límite de idiomas cuenta cada idioma al que se ha traducido en los últimos 30 días, en todos sus espacios de trabajo y proyectos. Si una ejecución superara la asignación o el límite de idioma, se detiene antes de escribir nada, explica por qué y sale con el código 2, para que la CI falle en lugar de confirmar una traducción a medias.
Idiomas
localize.dev traduce a cualquier idioma que conozca el CLDR de Unicode, más de 600, escrito como código BCP 47: un idioma (es, ja, sw), con un sistema de escritura o una región cuando importa (zh-Hant, sr-Latn, pt-BR, es-419). No hay una lista entre la que elegir: define sourceLocale y targetLocales en localize.config.json, o pasa --locales.
Un código que no nombra ningún idioma se rechaza antes de traducir nada, indicando lo que probablemente querías: jp → ja, cn → zh. Se acepta cualquier código válido, incluidos los alias como en-UK (que se lee como en-GB) y los de uso privado. La CLI, la GitHub Action, el panel y la API lo comprueban igual.
- A cuántos idiomas puede traducir una ejecución depende de tu plan. Un texto cuenta una vez, a cuantos idiomas vaya.
- Las traducciones son más sólidas en los idiomas más usados. Para idiomas con menos texto en internet, pide a un hablante nativo que revise el pull request y añade un glosario con los términos propios de tu producto.
- Todo idioma cuya escritura va de derecha a izquierda (árabe, hebreo, persa, urdu, kurdo, pastún, siríaco, n’ko y otros) recibe
dir="rtl"y las comprobaciones de estilos izquierda/derecha. También cuenta un código que indica su escritura:pa-Arab. - Los plurales siguen las formas propias de cada idioma (one, few, many…) del CLDR, así el polaco, el árabe o el galés tienen todas las que necesitan.
- Los pseudoidiomas
en-XA(con acentos y más largo) yar-XB(de derecha a izquierda) no necesitan modelo ni clave.
Plurales y texto enriquecido
Una elección dependiente de la cantidad, como {n} {n === 1 ? 'file' : 'files'} left se convierte en un mensaje (también n > 1 ? …, rules.select(n) === 'one' ? … y ayudantes como plural(n, 'file', 'files')), reescrito a t('files.left', { count: n }). Cada idioma recibe exactamente las formas que necesita (español tres, polaco cuatro, árabe seis), escritas como files.left_one, files.left_few... para i18next o un mensaje plural ICU, y i18next elige el correcto en tiempo de ejecución.
Una frase con dos recuentos, {files} {files === 1 ? 'file' : 'files'} in {folders} {folders === 1 ? 'folder' : 'folders'}, se convierte en un mensaje por frase contada ({{count}} file / {{count}} files) colocada en una sola frase, {{files}} in {{folders}}, para que cada recuento obtenga sus propias formas y los traductores aún puedan reordenarlas. Los ordinales de ayudantes como ordinal(place) o {n}{ordinalSuffix(n)} se convierten en plúrales ordinales de i18next (t('rank.place', { count: place, ordinal: true })), con las propias formas ordinales de cada idioma: Inglés 1st/2nd/3rd/4th, Francés 1re/2e, Español 1.º.
Lo mismo funciona más allá de React: los mensajes ICU (Svelte, Ember) obtienen un selectordinal, vue-i18n obtiene key_ordinal_one, y en Vue, Svelte, Astro, Lit, Ember, Flutter y Rails cada frase contada se convierte en una llamada plural propia dentro de la frase. Intl.PluralRules... claves seleccionadas por
Texto alrededor de elementos en línea simples, como Read the <a href="/docs">docs</a> first, se convierte en un mensaje (Read the <a>docs</a> first) renderizado con <Trans>, para que los traductores puedan mover el enlace. El elemento conserva sus props. Se rechazan las traducciones que pierden o renombran una etiqueta.
Frameworks sin un <Trans> obtienen lo mismo, con el texto propio del elemento como un mensaje propio: Vue a través de <i18n-t> con slots, Svelte a través de un generado <I18nT> (snippets en Svelte 5, un slot en 3 y 4), Angular a través de un generado <i18n-t> con ng-template slots (un NgModule antes de Angular 14), Ember a través de un generado <I18nT>, Solid y Qwik a través de rich(). En Rails, un link_to dentro de una oración se interpola en un _html mensaje, por lo que su marcado se mantiene.
Lo que se traduce
- Texto JSX, con texto y expresiones simples fusionadas en un mensaje:
Hi {user.name}!→Hi {name}! - Atributos en la lista permitida (placeholder, alt, title, aria-label, aria-description, aria-valuetext, aria-roledescription, label, tooltip; configurable), y el SVG
<title>y<desc> - Cadenas y literales de plantilla renderizado en JSX, incluyendo ambas ramas de
a ? 'X' : 'Y'y el lado derecho de&& - Copiar en constantes que los componentes leen (
const NAV = [{ label: 'Home' }]conNAV.map((n) => n.label)): las cadenas se convierten en claves y cada lectura se convierte ent(n.label) - Cadenas unidas (
'Hi ' + name + '!') como un solo mensaje, y mensajes pasados a los establecedores de estado, toasts,alerty validación zod o yup (z.string().min(1, 'Required')) - Props de componentes que contienen texto (
<EmptyState heading="No orders yet" />, de Vueempty-text="…"), tablas de búsqueda leídas por clave (STATUS_LABELS[order.status]), funciones auxiliares cuyos resultados se renderizan, y copias importadas desde un módulo simple (nav.ts), cuyas cadenas se convierten en claves allí cuando cada componente que las importa puede ser rastreado - Oraciones con género (
gender === 'female' ? 'She…' : 'He…') como un mensaje con una variante por género, para que cada idioma las formule a su manera - Plantillas de Vue y Svelte (Vue en HTML o Pug): texto,
{{ }}y{ }expresiones, atributos (incluyendotitle="Hi {name}"), y las cadenas que una expresión renderiza, como{{ saving ? 'Saving…' : 'Save' }} - Scripts de Vue y Svelte: mensajes que se muestran, pasados a
alert,confirm, notificaciones emergentes y alertas, o asignadas adocument.title, y constantes que muestra la plantilla (const tabs = [{ label: 'Home' }]con{{ tab.label }}): las cadenas se convierten en claves y la plantilla las lee a través de$t()o$_() - HTML estático: texto del elemento, oraciones alrededor de elementos en línea como un mensaje, y los mismos atributos. El texto de un motor de plantillas o PHP se deja solo y se informa.
Nunca traducido: URLs y rutas, colores, UUIDs, unidades CSS, correos electrónicos, nombres de archivos, identificadores en snake_case o kebab-case, solo símbolos, y cualquier cosa dentro <code>, <pre>, <Trans>, translate="no" o data-i18n-ignore.
Cada traducción se verifica antes de ser escrita: una que añade, elimina o renombra una {placeholder} es rechazada. Las traducciones existentes en tus diccionarios nunca se sobrescriben.
De derecha a izquierda
El árabe, hebreo, persa y urdu se leen de derecha a izquierda, por lo que ml-4 o margin-left acaba en el lado equivocado. Cuando el idioma objetivo es de derecha a izquierda, check las listas de estilos anclados a la izquierda o derecha, y localize-dev rtl --fix intercambia los estilos por equivalentes lógicos que se ven iguales en inglés:
- Tailwind:
ml-/mr-→ms-/me-,pl-/pr-→ps-/pe-,text-left→text-start, esquinas redondeadas y bordes, con variantes comomd:se mantienen. - CSS:
margin-left→margin-inline-start,padding-right→padding-inline-end,text-align: left→start, bordes y radios de esquina.
left-/right- las posiciones y flotadores solo se informan, ya que suelen ser trucos de centrado. Verifique el resultado en ar-XB con localize-dev run --pseudo rtl.
Documentación y contenido
La documentación, las entradas de blog y las páginas legales se traducen como documentos completos. localize-dev content traduce archivos Markdown y MDX en una copia por idioma: se traducen prosa, encabezados, elementos de lista, celdas de tabla y títulos y descripciones del front-matter; los bloques de código, código en línea, URLs de enlaces, importaciones MDX, componentes y expresiones permanecen exactamente igual. Si una traducción pierde alguno de estos, se mantiene en inglés y se reporta.
{
"targetLocales": ["es", "fr"],
"content": {
"include": ["docs/**/*.md", "blog/**/*.mdx"],
"output": "{dir}/{name}.{locale}{ext}"
}
}La salida predeterminada se encuentra junto a cada archivo (intro.es.md) como esperan Nextra, Fumadocs y Hugo. Para Docusaurus use "i18n/{locale}/docusaurus-plugin-content-docs/current/{path}". Los documentos sin cambios desde que se crearon sus copias son omitidos (sus huellas dactilares están en localize.lock.json), por lo que solo los editados se traducen nuevamente.
Privacidad y datos
- Solo se envían las cadenas extraídas a la API, junto con su ruta de archivo y componente como contexto. Nunca se envían archivos completos.
- Los escaneos y ejecuciones offline nunca abandonan tu máquina.
- La CLI sobrescribe los archivos localmente; la acción de GitHub realiza commits desde su propio ejecutor con su propio token.
- Las claves API se almacenan como hashes; el secreto se muestra solo una vez.
Limitaciones
- El texto enriquecido admite elementos en línea anidados hasta tres niveles (el texto en negrita dentro de un enlace se convierte en un mensaje anidado). El enlace propio
title, escrito a mano o establecido desde el código, permanece dentro del componente de la oración en React. - Los plurales se reconocen a partir de opciones de dos cadenas según el número (
===/!==1,>1,<2,Intl.PluralRules) y ayudantes de plurales con un número y ambas formas. Cada framework extrae plurales según su propia sintaxis (Django'spluralize, Laravel'sStr::plural, Kotlin'sif … else) y escribe su propio formato (<plurals>, variaciones del catálogo de cadenas,msgid_plural,trans_choice; Angular, que no tiene ninguno, elige la clave con un generadopluralFormpipe). Una frase con varios recuentos obtiene un plural por recuento en todas partes excepto en Django (cuyoblocktranslatetoma uno) y iOS; los ordinales funcionan en los frameworks de JavaScript y Angular, no en Flutter, Rails, Django, Laravel, Android o iOS, cuyas bibliotecas i18n no tienen formas ordinales. En iOS, un plural necesita su número en el texto ("\(n) items"), que es lo que varía el Catálogo de Cadenas. - Los componentes de clase se traducen: a través de
withTranslation()cuando la clase es la exportación predeterminada del archivo, de lo contrario conrender()ejecutándose dentro de<Translation>. Los constructores, miembros estáticos y manejadores de eventos usan el i18nextt, por lo que el texto que almacena un constructor sigue el idioma en el montaje. - En scripts de Vue y Svelte, la copia extraída es lo que se muestra claramente:
alert,confirm, toasts y notificaciones,document.title, y constantes que muestra la plantilla (una cadena,ref('…'), los valores de un objeto o una listalabel/titlecampos, pasados a componentes hijos traducidos), y lo quecomputed(), funciones,$:y$derivedretorno. Una constante de cadena que el propio script utiliza conserva su texto, ya que el script puede compararla o enviarla. En Svelte 4, el texto que devuelve una función se actualiza en el siguiente renderizado del componente después de un cambio de idioma. - Las plantillas de Vue en Pug se traducen,
#[…]etiquetas en línea (tres de profundidad) y#{}valores incluidos. Las plantillas en otros preprocesadores (raros fuera de Pug) se omiten y se informan. - La copia fuera de componentes (emails, texto SVG, mensajes construidos en el servidor) no se extrae; los documentos Markdown y MDX se traducen completos con
localize-dev content. - La solicitud de vista previa lee los archivos de la rama predeterminada; los archivos Git LFS y los submódulos se dejan fuera.