El CLI de Lingo.dev traduce los recursos de strings de Android (strings.xml) a través de un motor de localización configurado. Con el formato android, el CLI entiende de forma nativa los elementos <resources>, <string>, <string-array> y <plurals>, conserva la estructura del XML y genera las categorías de plural correctas para cada idioma de destino.
Esta guía te lleva de punta a punta por la localización de una app de Android: configurar el CLI, traducir localmente y automatizar en CI para que las traducciones se publiquen con cada push.
Repositorio de ejemplo
Clona o haz fork de lingodotdev/android-app-localization-example para seguir el paso a paso. El repositorio incluye un proyecto de Android funcional con recursos de strings, una configuración de Lingo.dev CLI y traducciones ya confirmadas para cada idioma de destino.
Cómo funciona la localización en Android#
Android usa una convención de directorios de recursos en la que cada idioma tiene su propio directorio values-[locale]/. El sistema carga el archivo strings.xml correcto en tiempo de ejecución según el idioma configurado en el dispositivo.
app/src/main/res/
values/ # Default (source) strings
strings.xml
values-es/ # Spanish
strings.xml
values-fr/ # French
strings.xml
values-ja/ # Japanese
strings.xmlUn archivo strings.xml típico contiene tres tipos de elementos:
<resources>
<!-- Simple strings -->
<string name="app_name">My App</string>
<string name="welcome_message">Welcome back!</string>
<!-- String arrays -->
<string-array name="planets">
<item>Mercury</item>
<item>Venus</item>
<item>Earth</item>
</string-array>
<!-- Plurals -->
<plurals name="items_count">
<item quantity="one">%d item</item>
<item quantity="other">%d items</item>
</plurals>
</resources>El CLI analiza los tres tipos de elementos, traduce su contenido mediante el motor de localización y escribe archivos por idioma en los directorios values-[locale]/ correspondientes.
Requisitos previos#
Crea un motor de localización
Cada ejecución de CLI envía el contenido a través de un motor de localización, la configuración que define qué modelo de LLM, glosario, voz de marca y reglas se aplican. Crea uno en el panel de Lingo.dev.
Verifica Node.js
El CLI requiere Node.js 22 o superior:
node -vInstala el CLI
Instala el CLI globalmente para exponer el comando lingo:
npm install -g @lingo.dev/cliInicia sesión
Autentícate con una contraseña de un solo uso:
lingo loginPara CI, usa una API key: pasa --api-key o configura LINGO_API_KEY.
Configura tu proyecto Android
Tu proyecto necesita un archivo strings.xml predeterminado en app/src/main/res/values/. Android Studio crea este archivo al iniciar un proyecto nuevo. Consulta la guía de localización de Android para configurar los directorios de recursos.
Configura el CLI#
Ejecuta lingo init en la raíz de tu proyecto para crear .lingo/config.json con tus idiomas de origen y destino, además de los patrones de archivos; luego ejecuta lingo link para vincular tu organización y motor. El resultado se verá así:
{
"orgId": "org_...",
"engineId": "eng_...",
"sourceLocale": "en",
"targetLocales": ["es", "fr", "de", "ja"],
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android"
}
]
}El patrón apunta a tu directorio de recursos predeterminado: el values/ sin calificador, justo donde Android espera encontrar las strings de origen. No lleva ningún código de idioma, ni lo necesita.
Por qué `format` se define explícitamente
El CLI detecta automáticamente la mayoría de los formatos a partir de la extensión del archivo, pero .xml es ambiguo, así que los archivos de recursos de Android necesitan un "format": "android" explícito en la entrada de files.
Varios archivos de recursos
Si tu proyecto reparte las strings en varios archivos (por ejemplo, strings.xml y arrays.xml), agrega una entrada en files para cada uno:
{
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android"
},
{
"pattern": "app/src/main/res/values/arrays.xml",
"format": "android"
}
]
}Haz commit de .lingo/config.json en tu repositorio.
Directorios de idioma y calificadores#
Android guarda el idioma predeterminado en un directorio values/ sin calificador, así que la ruta de origen no incluye ningún código de idioma. La CLI lo reconoce: trata values/ sin calificador como el idioma de origen y agrega el calificador de destino para cada uno de los demás idiomas.
| Idioma | Directorio de recursos |
|---|---|
en (origen) | values/ |
es | values-es/ |
pt-BR | values-pt-rBR/ |
zh-Hans | values-b+zh+Hans/ |
Aquí conviene entender los idiomas regionales y con escritura, porque un calificador de recursos no es una etiqueta BCP 47 sin más. Android acepta dos formas: la variante heredada idioma-región (values-pt-rBR/) y una variante BCP 47 con el prefijo b+ (values-b+pt+BR/, API 24 en adelante). Un directorio llamado values-pt-BR/ se ignora por completo: las strings existirían, pero nunca se cargarían.
Al configurar "format": "android", la CLI genera por ti la forma correcta: la variante heredada siempre que pueda representar el idioma, y b+ para escrituras, idiomas de tres letras y regiones numéricas.
Actualización desde una configuración anterior
Las versiones anteriores de la CLI exigían que el idioma apareciera en la ruta de origen, y esta guía antes recomendaba un symlink values-en -> values para enlazar ambas convenciones. Desde @lingo.dev/cli 1.12.0 eso ya no hace falta: apunta el patrón a values/strings.xml y elimina el symlink.
Traduce en local#
Ejecuta el CLI. En la primera ejecución, o cada vez que agregues un nuevo idioma de destino, usa --backfill-missing para traducir todas las strings existentes:
lingo push --backfill-missingEl CLI lee tu archivo fuente strings.xml, identifica las entradas sin traducir usando el estado de ejecución, traduce el delta a través de tu motor de localización y escribe los resultados en los directorios de destino values-[locale]/. Abre cualquier archivo de destino para ver las strings traducidas.
En las ejecuciones siguientes, lingo push traduce solo lo que cambió:
lingo pushPara limitar una ejecución a archivos específicos, pasa un glob. Los patrones se comparan con las rutas de origen, así que delimita por el archivo de origen en lugar del de destino:
lingo push "app/src/main/res/values/strings.xml"Para traer a tu árbol de trabajo traducciones generadas en otro lugar (por ejemplo, en CI), ejecuta lingo pull.
Plurales#
Android usa elementos <plurals> con cadenas de cantidad de CLDR (zero, one, two, few, many, other) para manejar las formas plurales. Cada idioma requiere categorías de plural distintas: el inglés necesita dos (one y other), el ruso necesita cuatro y el árabe necesita seis.
El CLI conserva la estructura de <plurals> durante la traducción y genera las entradas de cantidad correctas para cada idioma de destino. Una entrada de origen con dos categorías:
<plurals name="messages_count">
<item quantity="one">%d new message</item>
<item quantity="other">%d new messages</item>
</plurals>Genera las categorías correctas para cada idioma de destino. El motor de localización sabe qué reglas de plural de CLDR se aplican a cada idioma y genera únicamente las categorías que ese idioma necesita.
Bloqueo de claves#
Algunos valores de texto deben mantenerse idénticos en todos los idiomas: nombres de marca, endpoints de API o patrones de formato. Usa el bloqueo de claves para copiar estos valores sin traducirlos:
{
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android",
"lockedKeys": ["app_name", "api_base_url"]
}
]
}Las claves bloqueadas se copian desde el origen a todos los archivos de destino sin pasar por el flujo de traducción.
Automatiza en CI#
La forma recomendada de mantener las traducciones al día es la app de GitHub de Lingo.dev. Se ejecuta del lado del servidor, lee tus archivos versionados .lingo/config.json y engineId, y abre actualizaciones de traducción automáticamente, sin runner, sin secretos almacenados y sin que tengas que gestionar lockfiles. Instálala y conéctala a tu repositorio para traducir con cada push.
Si prefieres ejecutar el CLI dentro de tu propio pipeline, agrega un flujo de trabajo que instale el CLI y ejecute lingo push:
name: Translate
on:
push:
branches: [main]
permissions:
contents: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm install -g @lingo.dev/cli
- run: lingo push --backfill-missing
env:
LINGO_API_KEY: ${{ secrets.LINGO_API_KEY }}Guarda tu API key como LINGO_API_KEY en Settings > Secrets and variables > Actions de tu repositorio de GitHub y luego haz commit de los archivos de destino actualizados (o abre un pull request) como paso siguiente.
Verifica antes de desplegar#
Usa lingo check como puerta de despliegue para asegurarte de que no lleguen strings sin traducir a producción. El comando devuelve un estado distinto de cero si alguna entrada necesita traducción:
lingo checkAgrégalo como un paso de CI independiente antes de tu compilación:
- name: Verify translations
run: lingo check
env:
LINGO_API_KEY: ${{ secrets.LINGO_API_KEY }}