localize.dev

Documentación / iOS

Localización de iOS y macOS con Catálogos de Cadenas, automatizada

Busca texto codificado en SwiftUI y UIKit, tradúcelo a Localizable.xcstrings para cada idioma y envuelve las cadenas de UIKit con String(localized:), en un solo comando o solicitud de extracción.

Cómo funciona

SwiftUI busca el texto de Text("…"), Button, Label, TextField, .navigationTitle y otras vistas directamente en el Catálogo de Cadenas, para que el código permanezca igual. UIKit maneja cadenas simples, por lo que label.text = "…", setTitle("…", for:) y los títulos de alertas se convierten en String(localized: "…").

Un número con su palabra, "\(n) \(n == 1 ? "item" : "items")", se convierte en "\(n) items": el catálogo varía %lld items según la cantidad, con las formas plurales de cada idioma.

Cada cadena se coloca en Localizable.xcstrings, indexada por su texto como lo escribe Xcode (Welcome back, %@!), con la traducción de cada idioma en el mismo archivo y placeholders numerados (%1$@, %2$lld) cuando hay más de uno. Text(verbatim:), nombres de imágenes y comentarios permanecen sin cambios.

Antes y después

La salida real del motor para este archivo. En una ejecución real, el modelo alojado nombra las claves a partir del contexto.

Shop/CartView.swift · antes
import SwiftUI

struct CartView: View {
    let name: String
    var body: some View {
        VStack {
            Text("Welcome back, \(name)!")
            Button("Checkout") {}
        }
        .navigationTitle("Your cart")
    }
}

final class LoginController: UIViewController {
    let label = UILabel()
    override func viewDidLoad() {
        label.text = "Sign in to continue"
    }
}
Shop/CartView.swift · después
import SwiftUI

struct CartView: View {
    let name: String
    var body: some View {
        VStack {
            Text("Welcome back, \(name)!")
            Button("Checkout") {}
        }
        .navigationTitle("Your cart")
    }
}

final class LoginController: UIViewController {
    let label = UILabel()
    override func viewDidLoad() {
        label.text = String(localized: "Sign in to continue")
    }
}
locales/en.json
{
  "sourceLanguage" : "en",
  "strings" : {
    "Checkout" : {

    },
    "Sign in to continue" : {

    },
    "Welcome back, %@!" : {

    },
    "Your cart" : {

    }
  },
  "version" : "1.0"
}

Lo que añade la configuración

La primera ejecución configura Catálogos de Cadenas (Localizable.xcstrings) si el proyecto aún no lo tiene:

  • Localizable.xcstrings, encontrado en cualquier lugar del proyecto o creado en la raíz: agréguelo una vez a la meta del proyecto en Xcode.

Ejecutarlo

La CLI necesita Node.js 22 o posterior, nada más: npx lo ejecuta sin añadir un package.json al proyecto. ¿No tienes Node en tu máquina? La GitHub Action de abajo la ejecuta por ti.

npx localize-dev login

# Preview, then write the changes
npx localize-dev run --dry-run -l es,fr,de
npx localize-dev run -l es,fr,de

# Or open a pull request instead
npx localize-dev pr -l es,fr,de

O añade la GitHub Action y obtén una pull request en cada push. Pruébalo primero en tu propio código en el playground.