localize.dev

Documentazione

localize.dev trasforma il testo hardcoded in chiamate di traduzione in codebase React, Next.js, React Native, Vue, Nuxt, Svelte, Angular, Astro, Solid, Qwik, Lit, Ember, Flutter, Rails, Django, Laravel, Android, iOS e HTML statici, scrive i dizionari locali, imposta la libreria i18n se non ce n'è una e può aprire la pull request per te. La traduzione viene eseguita sul modello ospitato di localize.dev, quindi non c'è nulla da configurare oltre a una chiave API.

Guida rapida

È necessario Node.js 22 o versioni successive. La tua app non necessita ancora di una libreria i18n; la prima esecuzione ne imposta una. Crea una chiave API gratuita nella dashboard, quindi scegli il tuo framework:

React

Qualsiasi UI resa tramite un componente che può chiamare useTranslation(): React con Vite, Remix o Gatsby, renderizzatori Electron e Tauri, e sistemi di design o pacchetti UI condivisi. Le componenti di classe ottengono t attraverso withTranslation(), oppure <Translation> quando non sono l'esportazione predefinita del file. Le frasi intorno ai link rimangono complete con <Trans> (il proprio link title inclusi), il testo nelle costanti, nelle notifiche e nei messaggi di validazione di Zod viene trovato, e le date, i numeri e i prezzi seguono la lingua dell'app.

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 install

guida React: cosa cambia, con un esempio reale prima e dopo.

Next.js

Componenti server di App Router ottengono const { t } = await getTranslation() e componenti client useTranslation(), entrambi nella lingua scelta dal server; il Pages Router funziona come React. Un file generato proxy.ts assegna a ogni pagina un URL per lingua tramite hreflang link.

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 install

guida Next.js: cosa cambia, con un esempio reale prima e dopo.

React Native and Expo

React Native ed Expo. accessibilityLabel e accessibilityHint vengono tradotti anche, e la configurazione i18n evita API specifiche del browser.

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 install

guida React Native and Expo: cosa cambia, con un esempio reale prima e dopo.

Vue

Testo e {{ }} in <template> diventano {{ $t('key') }} e gli attributi diventano :placeholder="$t('key')", con vue-i18n configurato in src/i18n.ts e installato in main.ts. Messaggi mostrati da <script setup> (alert, toast, document.title) usa t() da useI18n, e n === 1 ? … : … diventa un plurale di vue-i18n. Una configurazione esistente createI18n viene lasciata così com'è. Una frase attorno a un link o a testo in grassetto rimane un unico messaggio attraverso <i18n-t>, con gli elementi come slot. Le costanti in <script setup> mostrati dal template ({{ title }}, v-for="tab in tabs") diventano chiavi lette tramite $t(). Template scritti in Pug (<template lang="pug">) ottieni lo stesso: h1 {{ $t('key') }}, piped e testo bloccato, e 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 install

guida Vue: cosa cambia, con un esempio reale prima e dopo.

Nuxt

Le pagine e i componenti vengono riscritti come qualsiasi componente Vue, e @nuxtjs/i18n viene aggiunto a nuxt.config, con un URL per lingua (/es/about) e hreflang link da 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 install

guida Nuxt: cosa cambia, con un esempio reale prima e dopo.

Svelte and SvelteKit

Il markup diventa {$_('key')} con svelte-i18n, inizializzato da src/lib/i18n e importato in +layout (o main.ts senza SvelteKit). Attributi come title="Hello {name}" diventano un unico messaggio. In SvelteKit, un generato hooks.server renderizza ogni pagina nella lingua del visitatore (la sua scelta salvata, poi Accept-Language), così non c'è alcun flash della lingua sorgente.

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 install

guida Svelte and SvelteKit: cosa cambia, con un esempio reale prima e dopo.

Angular

Modelli (.html e inline template:) diventano {{ 'key' | translate }} con ngx-translate, attributi [placeholder]="'key' | translate" ([attr.aria-label] per aria), e stringhe nei binding ('key' | translate). Flusso di controllo (@if, @for), *ngIf e template inline sono compresi; gli elementi contrassegnati con il proprio i18n sono lasciati a esso. La configurazione aggiunge provideI18n() a app.config.ts (ogni locale incluso, nessun loader HTTP) e TranslatePipe a ogni componente standalone che ne ha bisogno.

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 install

guida Angular: cosa cambia, con un esempio reale prima e dopo.

Astro

Testo e {expressions} in .astro i file diventano {t('key')}, attributi title={t('key')}, con t da un generato src/i18n modulo che legge la lingua dall'URL. Ogni pagina statica ottiene una copia per lingua (src/pages/es/about.astro), quindi ogni lingua è una pagina reale e indicizzabile, e i layout impostano <html lang dir>. localizePath(path, lang) costruisce collegamenti tra le lingue. Le isole React, Vue e Svelte (da @astrojs/react, /vue, /svelte) sono localizzate nella stessa esecuzione, ognuna con la propria libreria configurata e seguendo la lingua della pagina.

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

guida Astro: cosa cambia, con un esempio reale prima e dopo.

Solid

JSX come React, con useTranslation() da un generato src/i18n.ts: i18next dietro un segnale linguistico, quindi il testo si aggiorna sul posto quando la lingua cambia. Le frasi attorno ai link rimangono un unico messaggio, renderizzato da rich(t('key'), { a: (c) => <a href="/terms">{c}</a> }) dallo stesso modulo.

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 install

guida Solid: cosa cambia, con un esempio reale prima e dopo.

Qwik

JSX in component$ ottiene const { t } = useTranslation() da un generato src/i18n.ts che legge la lingua dall'URL (di Qwik City useLocation), e ogni route, anche quelle dinamiche, ottiene una copia per lingua sotto src/routes/es/. Le frasi attorno ai link rimangono un unico messaggio tramite rich() dallo stesso modulo.

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

guida Qwik: cosa cambia, con un esempio reale prima e dopo.

Lit

Testo e ${expressions} in html`…` i template diventano ${t('key')}, attributi placeholder=${t('key')}. I componenti ricevono un I18nController così si ri-rendono quando setLanguage() cambia lingua; le template annidate, gli stili e i commenti rimangono intatti.

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

guida Lit: cosa cambia, con un esempio reale prima e dopo.

Ember

Modelli Glimmer (.hbs, e <template> in .gjs/.gts) diventano {{t "key" name=this.name}} con ember-intl, attributi placeholder={{t "key"}}, stringhe in {{if}} (t "key"), e {{if (eq n 1) "item" "items"}} in una frase un plurale. I messaggi vanno a translations/<locale>.json; una rotta applicativa generata sceglie la lingua.

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 install

guida Ember: cosa cambia, con un esempio reale prima e dopo.

Flutter

Text('Hi $name') e argomenti come hintText: diventano AppLocalizations.of(context)!.hiName(name), con messaggi in lib/l10n/app_en.arb (chiavi camelCase, plurali ICU, metadati dei segnaposto). const viene rimosso dai widget che ora contengono un lookup; stringhe senza BuildContext nell'ambito vengono segnalate. La configurazione aggiunge flutter_localizations, generate: true, l10n.yaml, il MaterialApp delegati e l'elenco delle lingue 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,fr

No package.json necessario: npx esegue il CLI. guida Flutter: cosa cambia, con un esempio reale prima e dopo.

Static HTML

Il testo rimane nella pagina e ottiene un data-i18n="key" marcatore (gli attributi ottengono data-i18n-placeholder e simili). Un generato i18n.js carica i file delle lingue e sostituisce il testo; aggiungi <select data-i18n-switcher></select> per un menu delle lingue. Una frase con elementi inline (<strong>, collegamenti) è un messaggio, ricostruito dagli elementi della pagina stessa. Le traduzioni sono anche raggruppate in i18n.js, quindi anche le pagine aperte da disco funzionano. Il testo da un motore di template ({{ }}, {% %}, PHP) rimane invariato.

I motori di ricerca vedono solo il testo nella pagina, quindi imposta "htmlPages": true e "siteUrl" in localize.config.json per scrivere anche ogni pagina tradotta in ogni lingua (es/index.html), collegato 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,fr

guida Static HTML: cosa cambia, con un esempio reale prima e dopo.

Ruby on Rails

Il testo nelle viste ERB diventa <%= t('key', name: @user.name) %>, con %{name} placeholder in config/locales/<locale>.yml e plural chiamati con count:. available_locales e un switch_locale azione-intorno vengono aggiunti.

# 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

No package.json necessario: npx esegue il CLI. guida Ruby on Rails: cosa cambia, con un esempio reale prima e dopo.

Django

I template ottengono {% translate '…' %} e {% blocktranslate %}, le traduzioni vanno in locale/<lang>/LC_MESSAGES/django.po, e le impostazioni ottengono LANGUAGES, LOCALE_PATHS e 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,fr

No package.json necessario: npx esegue il CLI. guida Django: cosa cambia, con un esempio reale prima e dopo.

Laravel

Il testo Blade diventa {{ __('Hi :name', ['name' => $user->name]) }} con lang/<locale>.json indicizzato per testo, e un SetLocale middleware sceglie la lingua (?locale=, un lang cookie, poi 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,fr

No package.json necessario: npx esegue il CLI. guida Laravel: cosa cambia, con un esempio reale prima e dopo.

Android

android:text, hint e contentDescription in layout e menu diventano @string/…, e Compose Text("Hi $name") all'interno @Composable le funzioni diventano stringResource(R.string.…, name). Visualizza il codice in Kotlin o Java (label.setText("Hi"), label.text = "Hi") diventa setText(R.string.…). Le stringhe vanno a res/values-<lang>/strings.xml con numerati %1$s segnaposto, e locales_config.xml elenca le lingue per 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,fr

No package.json necessario: npx esegue il CLI. guida Android: cosa cambia, con un esempio reale prima e dopo.

iOS

testo SwiftUI (Text("Hi \(name)"), Button, .navigationTitle) rimangono così come sono scritte, poiché SwiftUI le cerca nel Catalogo Stringhe stesso; le stringhe UIKit (label.text = "Hi") diventano String(localized: "Hi"). Tutto va in Localizable.xcstrings con ogni lingua nello stesso file. Aggiungi il catalogo al tuo target dell'app in Xcode una volta.

# 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

No package.json necessario: npx esegue il CLI. guida iOS: cosa cambia, con un esempio reale prima e dopo.

Vuoi dare un'occhiata prima di registrarti? npx localize-dev scan elenca ogni stringa che estrarrebbe, e --offline genera chiavi senza tradurre. Nessuno dei due richiede una chiave né utilizza la tua quota. Un'esecuzione online successiva riempie le traduzioni mancanti senza toccare le chiavi esistenti.

Codebase supportate

Ogni framework ottiene il proprio scanner e la propria libreria i18n. Ciò che cambia in ciascuno si trova sotto il suo nome nella guida rapida, e nella sua guida.

Monorepo: esegui dalla root con --workspaces (o l'Action workspaces: true) per localizzare ogni app, ognuna con i propri file di localizzazione. Librerie di componenti condivise (pacchetti senza dev o start script) vengono tradotte anche, nelle lingue delle app che dipendono da esse, e i loro messaggi vengono aggiunti ai file di localizzazione di tali app, quindi la libreria t() le chiamate si risolvono attraverso la configurazione di ciascuna app. Per localizzare una sola app, fornisci l'Azione working_directory: apps/web invece: legge l'app specifica localize.config.json, codice e file di localizzazione, e la pull request li modifica sul posto.

Il framework viene rilevato da package.json (o pubspec.yaml, o i file quando non c'è nessuno dei due); imposta "framework" in localize.config.json per sovrascriverlo. I dizionari React usano i segnaposto i18next o ICU; Vue, Svelte e HTML usano lo stile ICU {name}.

File di localizzazione esistenti

Hai già configurato l'i18n, in qualsiasi stack? localize-dev translate salta il codice e compila ciò che manca nei tuoi file di localizzazione: chiavi senza traduzione, in ogni lingua già presente o in nuove lingue da te nominate. Le traduzioni esistenti non vengono mai modificate e nessun framework viene rilevato, quindi funziona per qualsiasi stack, inclusi iOS e Android nativi, Rails e Django.

# 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
FormatoFileNote
JSONlocales/en.json, public/locales/en/*.jsoni18next (con _one/_other per plural), ICU (react-intl, next-intl, inclusi =0 e select), vue-i18n, ngx-translate, Transloco
YAMLconfig/locales/en.yml, devise.en.ymlRails, sotto la chiave della lingua; mappatura dei plurali one/other
gettextlocale/fr/LC_MESSAGES/django.poDjango, WordPress, PHP, Python. Voci vuote e fuzzy vengono compilate; le posizioni plurali seguono Plural-Forms. Nuove lingue vengono create accanto a una esistente, con le proprie Plural-Forms.
Flutterlib/l10n/app_en.arbMessaggi ICU; le descrizioni @key diventano contesto. gen-l10n rileva i nuovi file.
Androidres/values/strings.xml<string> e <plurals>; translatable="false", <xliff:g> e le escape rispettate. Scrive valori-es/, valori-pt-rBR/.
AppleLocalizable.xcstrings, en.lproj/*.stringsI cataloghi di stringhe includono ogni lingua, con i plurali; i file .strings ottengono nuove cartelle .lproj (aggiungi le lingue in Xcode).
Estensioni del browser_locales/en/messages.jsonI placeholder vengono copiati in ogni lingua.

I segnaposto nella sintassi specifica di ogni formato ({{name}}, %{name}, %1$s, %@, %(name)s, $NAME$) sono protetti: una traduzione che ne perde o aggiunge uno, o riordina quelli senza nome come %s, viene scartata e segnalata. I plurali ottengono ogni forma necessaria alla lingua di destinazione (il russo ottiene one, few e many). Commenti e descrizioni nei file vanno al modello come contesto.

Copia modificata: localize.lock.json mantiene un'impronta digitale di ogni messaggio sorgente quando viene tradotto. Cambia l'inglese e il prossimo run, translate o l'esecuzione dell'azione lo traduce di nuovo in ogni lingua; check fallisce sulle traduzioni lasciate obsolete. Esegui il commit del file.

Nell'azione di GitHub, imposta mode: translate. Ogni esecuzione apre o aggiorna una pull request con ciò che manca, quindi le nuove chiavi aggiunte in inglese vengono tradotte non appena arrivano.

Crowdin, Phrase, Lokalise, Transifex

Lavori con traduttori in un TMS? Invia lì i tuoi file della locale sorgente ed estrai le loro traduzioni. Aggiungi il progetto a localize.config.json (provider: crowdin, phrase, lokalise o transifex) e inserisci il token API in CROWDIN_TOKEN, PHRASE_TOKEN, LOKALISE_TOKEN o TRANSIFEX_TOKEN (mai nel file di configurazione):

localize.config.json
{
  "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 pull

JSON, YAML, ARB, Android, .strings e i file di estensione vengono sincronizzati. Crowdin conserva le tue cartelle, Phrase mantiene ogni file separato con un tag, Lokalise archivia ciascuno sotto il suo percorso con la lingua come %LANG_ISO%, e Transifex ottiene una risorsa per file (projectId come o:acme:p:web). Le lingue vengono abbinate ai codici del progetto stesso (es → es-ES, pt-BR → pt_BR). Per Crowdin Enterprise o il data center USA di Phrase, imposta "url" al suo indirizzo API. I file gettext e String Catalog sono meglio gestiti dalle integrazioni del TMS. Un ciclo comune: esegui localize-dev run o translate per traduzioni automatiche, push, lascia che i revisori modifichino, pull.

Comandi CLI

localize-dev init
Scrive un localize.config.json con tutte le impostazioni predefinite specificate.
localize-dev init --agent [--pre-commit]
Imposta agenti di codifica per tradurre il testo mentre lo scrivono: il server MCP per Claude Code e Cursor, un hook post-modifica per Claude Code e istruzioni in AGENTS.md e una regola Cursor. --pre-commit controlla anche i file preparati prima di ogni commit. Come funziona.
localize-dev login [--api-key ldv_live_…]
Salva la tua chiave API per questa macchina. Senza --api-key richiede, oppure legge la chiave da stdin.
localize-dev whoami
Mostra l'area di lavoro, il piano e l'utilizzo per la chiave corrente.
localize-dev logout
Rimuove la chiave salvata da questa macchina.
localize-dev scan [-d src] [-o extracted_strings.json]
Elenca ogni stringa che verrebbe estratta, più quelle saltate e il motivo. Non modifica nulla; non è necessaria alcuna chiave.
localize-dev run [--dry-run] [--offline] [--workspaces] [--files a.tsx… | --changed | --staged] [-l es,fr] [-d src] [--api-key …]
Il passaggio completo: estrai, nomina le chiavi, traduci, riscrivi i file, aggiorna i dizionari e configura la libreria i18n se l'app non ne ha. Con --workspaces, ogni app in un monorepo a sua volta.
localize-dev translate [--dry-run] [-l de,ja] [-s en] [--api-key …]
Riempie le traduzioni mancanti nei file di localizzazione esistenti, per qualsiasi stack. Il codice non viene modificato. Formati.
localize-dev check [--only strings|translations] [--files a.tsx… | --changed | --staged] [--json]
Blocca la CI per testo hardcoded, traduzioni mancanti e traduzioni non aggiornate rispetto alla sorgente; segnala chiavi inutilizzate e, con una lingua da destra a sinistra, stili left/right. Dettagli.
localize-dev prune [--dry-run]
Rimuove le chiavi a cui nessun codice fa riferimento da ogni file di localizzazione di ogni lingua.
localize-dev rtl [--fix]
Elenca gli stili ancorati a sinistra o a destra; --fix sostituisce quelli sicuri con quelli logici. Da destra a sinistra.
localize-dev content [--dry-run] [-l de,ja]
Traduce documenti Markdown e MDX in una copia per lingua. Documenti e contenuti.
localize-dev sync push|pull [--translations] [-l de,ja]
Invia i file della locale sorgente a Crowdin, Phrase, Lokalise o Transifex, o recupera le loro traduzioni. Configurazione.
localize-dev seo <url> [--limit 500] [--json]
Controlla cosa vedono i motori di ricerca di ogni lingua su un sito, live o in una build locale: la sitemap, i link hreflang, <html lang>, l'indirizzo canonico e og:locale. Esce con 1 quando trova un problema, in modo che possa essere eseguito in CI dopo un deploy Dettagli.
localize-dev pr [--translate] [--base main] [--repo owner/name] [--branch name] [--token …]
Esegue il passaggio e apre (o aggiorna) una pull request su localize-dev/<base> invece di scrivere localmente. Usa GITHUB_TOKEN quando --token viene omesso. Con --translate, la pull request compila solo le traduzioni mancanti.

Agenti di codifica

localize-dev mcp esegue un server MCP, in modo che un agente di codifica (Claude Code, Cursor, Codex, GitHub Copilot e altri) possa controllare e localizzare il repository su cui sta lavorando. Lovable, Bolt, v0 e altri builder che vengono eseguiti nel browser si connettono al server ospitato su https://uselocalize.dev/api/mcp con una chiave API. La configurazione per ogni agente si trova sulla pagina MCP. Per far tradurre testo all'agente mentre lo scrive, esegui questo nella cartella dell'app:

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 commit

Scrive questi file:

  • .mcp.json e .cursor/mcp.json: il server MCP, per Claude Code e Cursor.
  • .claude/settings.json: un hook post-modifica che esegue npx -y localize-dev hook. Quando un file modificato da Claude Code contiene testo non tradotto, l'hook elenca le righe e l'agente chiama localize su quel file prima di procedere.
  • AGENTS.md, e un CLAUDE.md che lo importa quando non ce n'è nessuno: quando chiamare localize e check. Una regola Cursor in .cursor/rules/localize.mdc dice la stessa cosa per i tuoi file UI.
  • Con --pre-commit: check --staged nell'hook di pre-commit di husky, o quello di git.

In un monorepo, le istruzioni nominano l'app. Le tue impostazioni, i server e il testo esistenti vengono mantenuti e una seconda esecuzione non cambia nulla. Esegui il commit dei file in modo che il team e i loro agenti li condividano. L'hook legge solo il file, senza chiave o modello, e richiede circa un secondo; LOCALIZE_DEV_HOOK=off lo mette in pausa. Le stringhe che un agente traduce tramite il server MCP vengono visualizzate come "Durante la scrittura" nella pagina di utilizzo.

impostazione i18n

Vue, Nuxt, Svelte e HTML statico sono configurati come descritto in Codebase supportate. In React, i componenti riscritti chiamano useTranslation(), quindi l'app necessita di i18next in esecuzione. Quando non lo è, l'esecuzione (e la pull request dell'Action) aggiunge ciò che manca:

  • i18next e react-i18next in package.json. L'Action aggiorna anche il tuo lockfile (npm, pnpm, Yarn o Bun); dopo un'esecuzione locale, esegui la tua installazione.
  • src/i18n.ts (o .js), che carica i file di localizzazione e sceglie la lingua da una preferenza salvata, poi dal browser, poi dalla tua locale sorgente. Con più di tre lingue di destinazione solo la sorgente viene inclusa nel bundle e le altre vengono caricate al primo utilizzo ("lazyLocales" da scegliere). Nelle app Remix senza v3_routeConfig, le pagine si idratano nel loro <html lang> e cambiano dopo il caricamento.
  • Un import './i18n' nel tuo file di ingresso: lo script in index.html, altrimenti src/main.* o src/index.*.
  • resolveJsonModule in tsconfig.json, in modo che i file di localizzazione possano essere importati.
  • Un'importazione di esso nel file di configurazione dei test (Vitest setupFiles, Jest setupFilesAfterEnv, src/setupTests) in modo che i test che cercano testo lo trovino ancora. Vue riceve vue-i18n installato per @vue/test-utils.
  • Una riga in .gitattributes che unisce i file di localizzazione chiave per chiave, in modo che due ramificazioni che aggiungono chiavi non entrino in conflitto. Attivalo una volta per clone con git config merge.localize-dev.driver "npx localize-dev merge-locales %O %A %B %P" (le fusioni su GitHub stesso non lo eseguono).
  • src/language-switcher.tsx, esportando <LanguageSwitcher /> e useLanguage() con le impostazioni predefinite di questa app, e localize-dev come dipendenza. Renderizza lo switcher dove le persone selezionano una lingua, come nel tuo header; non è posizionato automaticamente. Opzioni.

Se un file esiste già che inizializza i18next, nulla viene aggiunto e la configurazione attuale viene utilizzata come tale. Il commutatore salva la scelta in localStorage e la ripristina alla visita successiva; per commutare dalla tua codifica, chiama i18n.changeLanguage('es') e salva lang allo stesso modo. I progetti configurati da una versione precedente riceveranno il commutatore al loro prossimo avvio. Nel Next.js Pages Router l'importazione va inserita in pages/_app.

Next.js App Router

File sotto app/ senza 'use client' sono componenti server, che non possono utilizzare gli hooks. Ricevono const { t } = await getTranslation() al posto loro (il componente diventa async se non lo era), da un componente generato i18n.server modulo che seleziona la lingua da un lang cookie, poi del browser Accept-Language. I component client mantengono useTranslation(). La disposizione principale è avvolta in una generata <I18nProvider> che fornisce ai component client la stessa lingua e <html lang> la segue. Il commutatore generato imposta lang cookie e aggiorna, quindi i component server si rigenerano nella nuova lingua.

Cambia lingua

<LanguageSwitcher /> è un menu delle lingue supportate dall'app (la lingua di origine e quelle di destinazione configurate), ognuna con la propria bandiera e nome. Funziona con la tastiera (freccie, Home/End, Invio, Esc, digitando un nome), i lettori schermo e ricorda la scelta, impostando <html lang> e dir per le lingue da destra a sinistra.

Header.tsx
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"

Altre proprietà: showFlag, align (start/end), side (top/bottom), label, disabled, renderButton, renderOption, persist (localStorage, cookie o none), storageKey e onChange. Le stilistiche integrate leggono le variabili CSS, quindi un tema o modalità scura richiede solo poche righe: --ldv-bg, --ldv-fg, --ldv-border, --ldv-hover, --ldv-muted, --ldv-accent, --ldv-radius, --ldv-shadow. Le opzioni selezionate e evidenziate includono data-selected e data-active per il tuo CSS personalizzato. Fuori da React, getLanguageInfo('pt-BR') restituisce gli stessi nomi, bandiera e direzione.

Nel Next.js App Router il file generato salva la scelta nel lang cookie e aggiorna, quindi i componenti server seguono. Le bandiere emoji appaiono come due lettere su Windows; passa renderFlag per le immagini lì.

Ogni altro framework riceve lo stesso menu, generato per i suoi componenti e stato, sulla <localize-language-switcher> elemento personalizzato da localize-dev/switcher: accetta le stesse opzioni come gli attributi, emette l'evento language-change e viene stilizzato con le stesse variabili --ldv-* o ::part(button|menu|option|flag).

Cosa genera la configurazione
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)

Chiavi API

Le chiavi sembrano ldv_live_… e appartengono a uno spazio di lavoro; ogni chiave in uno spazio di lavoro condivide il suo limite mensile. Il CLI cerca una chiave in questo ordine:

  1. il --api-key bandiera
  2. il LOCALIZE_API_KEY variabile di ambiente (usa questa nel CI)
  3. la chiave salvata da localize-dev login, in ~/.config/localize-dev/credentials.json (visibile solo da te)

Viene memorizzato solo l'hash di ogni chiave dal nostro lato, quindi un segreto viene mostrato una sola volta, al momento della creazione. Revoca una chiave dalla dashboard e smetterà di funzionare immediatamente.

Configurazione

Tutto è opzionale. Inserisci le sovrascritture in localize.config.json alla radice del progetto; le flag CLI prevalgono sul file.

CampoPredefinitoDescrizione
srcDir"src"Cartella da scandire.
frameworkdetectedreact, react-native, vue, svelte o html. Rilevato da package.json, poi dai file.
include / ignoreby framework / tests, stories, .d.tsGlobs relativi a srcDir: *.{tsx,jsx}, *.vue, *.svelte o *.html.
sourceLocale"en"Lingua del testo hardcoded.
targetLocales["es", "fr"]Lingue in cui tradurre.
localesPath"locales/{locale}.json"Posizione del dizionario, es. public/locales/{locale}/common.json.
attributesplaceholder, alt, title, aria-label, label, tooltipAttributi trattati come testo dell'interfaccia utente. React Native aggiunge accessibilityLabel e accessibilityHint.
importSource"react-i18next"React: da dove viene importato useTranslation, es. next-i18next.
interpolationby frameworki18next scrive {{name}} (React); icu scrive {name} (Svelte, HTML); vue scrive {name} con i caratteri speciali di vue-i18n sottoposti a escape.
htmlPagesfalseHTML statico: scrivi anche ogni pagina tradotta per lingua (es/index.html), per i motori di ricerca.
siteUrlnoneL'indirizzo del sito, es. https://example.com. Necessario per i link hreflang tra le versioni linguistiche.
localizeFormatstrueFai in modo che date, numeri e prezzi codificati in un'unica localizzazione seguano la lingua dell'app.
currency"USD"Cosa rappresenta un $ isolato prima di un importo quando i prezzi sono localizzati, ad es. "CAD".
lazyLocalespiù di 3 lingueReact: impacchetta solo la lingua di origine e carica le altre al primo utilizzo.
contentnoneDocumenti Markdown e MDX per contenuti localize-dev: { "include": ["docs/**/*.md"], "output": "{dir}/{name}.{locale}{ext}" }.

GitHub Action

L'azione esegue lo stesso pass in CI e apre una pull request contro il branch che l'ha attivata. Le ri-esecuzioni aggiornano lo stesso branch e PR. Prima della prima esecuzione, salva la tua chiave API nel repository:

  1. 1

    Copia la tua chiave API

    Inizia con ldv_live_ e viene mostrato solo una volta. L'hai perso? Creane uno nuovo sulla Chiavi API pagina.
  2. 2

    Apri i segreti delle Azioni del repository

    Su GitHub, apri il tuo repository e vai a Impostazioni → Segreti e variabili → Azioni, poi clicca su Nuovo segreto del repository. Hai bisogno di accesso amministrativo al repository per visualizzare le Impostazioni.
  3. 3

    Aggiungi il segreto

    Nome: LOCALIZEDEV_API_KEYSegreto: incolla la tua chiave, senza spazi o interruzioni di riga. Poi clicca su Aggiungi segreto. GitHub nasconde il valore da quel momento in poi; per modificarla, aggiorna il segreto.
  4. 4

    Senza l'app GitHub localize.dev: consenti all'azione di aprire pull request

    In Impostazioni → Azioni → Sezione generale, sotto Permessi del workflow, spunta Consenti a GitHub Actions di creare e approvare le richieste pull e clicca Salva. Senza questa opzione, l'esecuzione traduce tutto ma fallisce quando apre la richiesta pull. Se l'opzione è grigia, un proprietario dell'organizzazione deve abilitarla prima nelle impostazioni dell'organizzazione → Azioni → Generale.

Quindi committa il workflow:

.github/workflows/localize.yml
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 app

Altri input: src_dir, locales_path, base_branch, api_url, offline (nessuna chiave necessaria), workspaces (ogni app in un monorepo), working_directory (un'app di un monorepo), tms_pull / tms_push (con tms_token: porta le traduzioni revisionate nella pull request, carica i file sorgente dal branch predefinito), mode: translate (compila solo file di localizzazione esistenti). Output: pr_url, strings_count.

Ogni esecuzione segnala al termine: la pagina del progetto nella dashboard elenca le esecuzioni recenti con la loro pull request, le stringhe sostituite, le traduzioni per lingua e l'errore in caso di fallimento.

Anteprima pull request

Vuoi vederlo sul tuo codice prima di configurare qualsiasi cosa? Collega il repository nella dashboard e scegli Apri una pull request di anteprima sulla sua pagina. localize.dev legge il branch predefinito, localizza fino a 200 stringhe nella prima lingua del progetto sul server e apre una pull request da localize-dev/preview. Non sono necessari workflow, API key o checkout; le stringhe contano per il tuo piano e le traduzioni appaiono nella scheda Revisione come quelle di qualsiasi esecuzione. Eseguendola di nuovo si aggiorna la stessa pull request.

In un monorepo, ogni app viene localizzata a turno finché non vengono utilizzate le 200 stringhe. I file in Git LFS e i submodule non sono nell'archivio fornito da GitHub, quindi vengono esclusi, e un repository molto grande viene letto solo in parte; la pull request lo indica. La GitHub Action non ha limiti.

Controllo CI

localize-dev check fallisce (codice di uscita 1) quando il testo è ancora hardcoded, manca la traduzione di una lingua o le traduzioni sono obsolete perché il loro inglese è cambiato da (da localize.lock.json), e ne elenca ognuno. Segnala anche le chiavi che nessun codice utilizza (rimuovile con localize-dev prune), testo nei fogli di stile (content: "New"), messaggi che mostrano un valore memorizzato così com'è (Status: {{status}} ), e quando una lingua di destinazione è da destra a sinistra, stili ancorati a sinistra o a destra, e next/font i font non hanno le lettere di una lingua di destinazione; questi non fanno fallire il controllo. Una chiave usata dal codice che manca nel file della lingua sorgente lo fa fallire, poiché le persone vedrebbero la chiave stessa. Legge solo file: nessuna chiave API, nulla inviato. Su GitHub Actions ogni problema è anche un'annotazione sul diff della pull request.

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 ones

Con --files, --changed o --staged, check esamina solo quei file: testo hardcoded e chiavi mancanti dal file locale di origine. Salta i controlli sull'intero progetto, quindi viene eseguito in circa un secondo, abbastanza velocemente per un hook di pre-commit o un hook post-modifica di un agente. run accetta le stesse opzioni.

Oppure in un workflow che viene eseguito sulle pull request, con l'Action:

.github/workflows/i18n-check.yml
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: check

Pseudo-localizzazione

Prima di pagare per una singola traduzione, vedi dove si rompe il tuo layout. --pseudo scrive una en-XA lingua: ogni messaggio accentato, circa il 35% più lungo (come il tedesco o il finlandese) e tra parentesi, con segnaposto e tag mantenuti esattamente, in modo che l'app venga eseguita come farebbe con una traduzione reale. Passa a questa e cerca pulsanti tagliati, card che traboccano e qualsiasi cosa senza parentesi: quel testo è ancora codificato in modo fisso.

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 untouched

Nessun modello e nessuna chiave: non utilizza il tuo credito. Le tue lingue reali rimangono invariate. Anche il playground la include, come la en-XA lingua.

Date, numeri e denaro

Nelle app React, React Native, Electron, Tauri, Solid, Vue e Svelte, riscrive anche date, numeri e prezzi codificati in modo fisso in una locale, in modo che seguano la lingua dell'app:

  • date.toLocaleDateString('en-US', …) e new Intl.NumberFormat('en-US') adottano invece la lingua dell'app (e così fanno le chiamate senza locale, che usano quelle del browser).
  • `$${price}` e <span>${price}</span> diventano un formato valuta, quindi $1,234.50 si legge 1.234,50 $ in tedesco. €, £, ¥, ₹, ₦, CA$, A$ e altri simboli vengono mappati alla loro valuta; un semplice $ è USD a meno che "currency" in localize.config.json non dica diversamente.
  • Nei template e negli script Vue la lingua proviene da vue-i18n ($i18n.locale); in Svelte, da di svelte-i18n $locale.

Date da date-fns (format(d, 'MMM d, yyyy')), dayjs e moment diventano Intl.DateTimeFormat con le stesse parti; i tempi relativi (formatDistance, fromNow) sono elencati per passare a Intl.RelativeTimeFormat. localeCompare e maiuscole o minuscole mostrate in JSX usano la lingua dell'app (i turca). Anche le liste seguono la lingua: {tags.join(', ')} in JSX e un `${xs.slice(0, -1).join(', ')} and ${xs[xs.length - 1]}` diventano Intl.ListFormat, così il giapponese ottiene 、 e lo spagnolo la sua "y". Le pull request elencano ogni modifica. Disattivalo con "localizeFormats": false in localize.config.json. Le app Next.js App Router per ora vengono lasciate così come sono, poiché i loro componenti client ottengono la lingua tramite un provider.

Un URL per lingua

I motori di ricerca indicizzano ogni lingua quando ha un proprio URL. Nelle app Next.js App Router, il generato proxy.ts (middleware.ts prima di Next 16) serve /es/about con il /about pagina in spagnolo, senza spostare i tuoi file, e <LanguageAlternates /> nel layout principale aggiunge hreflang link tra le versioni. Gli URL senza prefisso continuano a seguire il lang cookie e il browser, e il menu della lingua si sposta tra gli URL con prefisso.

Le app Nuxt ottengono @nuxtjs/i18n's prefix_except_default URL con useLocaleHead() in app.vue; imposta "siteUrl" per link assoluti. I siti statici ottengono lo stesso da htmlPages. Un'app con un proprio proxy o middleware la mantiene: l'esecuzione spiega le due intestazioni (x-localize-lang, x-localize-path) da impostare lì.

Anche titoli e descrizioni delle pagine seguono. Next.js export const metadata diventa un generateMetadata che utilizza il traduttore della richiesta (di un modello di titolo %s mantenuto), e un esistente generateMetadata ottiene t. Nelle app a pagina singola (Vite React, Vue, Svelte, Angular, Solid), index.html's <title> e la descrizione vengono tradotte e impostate dal modulo generato al cambio di lingua; il file le mantiene come scritte per il primo rendering.

Per i motori di ricerca, il layout principale ottiene anche un indirizzo canonico e og:locale per l'URL di ogni lingua, dal generato i18n-seo.ts. app/sitemap.ts elenca ogni pagina con un indirizzo fisso (nessun percorso [slug], aree di accesso o cartelle private) in ogni lingua, con alternative hreflang. Un robots.ts punta ad esso. Entrambi vengono scritti solo quando l'app non ha nessuno dei due e puoi modificarli. Imposta "siteUrl" in modo che la sitemap abbia indirizzi completi. Quando non è impostato, l'indirizzo proviene da un file CNAME o dalla homepage in package.json, e su Vercel, Netlify, Render o Railway dall'indirizzo che l'host fornisce alla build.

I layout di Astro ottengono un componente I18nHead nella loro head, con gli stessi link e og:locale. SvelteKit 2.3 e versioni successive servono ogni lingua al proprio indirizzo tramite un hook di reindirizzamento in src/hooks.ts, quindi i percorsi non necessitano di una cartella [lang] e hooks.server aggiunge i collegamenti a ciascuna pagina. Entrambi ottengono un sitemap.xml creato dalla cartella delle pagine o dei percorsi, in modo che le nuove pagine vengano elencate senza eseguire localize di nuovo, e un robots.txt quando l'app non ne ha nessuno.

Le app Qwik City ottengono un componente LanguageHead in root.tsx con gli stessi collegamenti e le stesse route sitemap e robots.

Le app React Router (modalità framework) ottengono ogni route di nuovo sotto ogni lingua, quindi /es/about è la pagina about in spagnolo. Il file routes passa le sue route tramite withLanguageRoutes da app/i18n-routes.ts, e la root renderizza ogni pagina nella lingua del suo indirizzo, con gli stessi link. I link senza lingua mantengono la lingua della pagina, e le route sitemap.xml e robots.txt vengono aggiunte quando l'app non ne ha nessuna. Con più di tre lingue, quelle non presenti nel bundle vengono caricate nel loader della route, in modo che anche il server le renda.

Le app Remix 2 ottengono lo stesso quando v3_routeConfig è attivo in vite.config e le route sono in app/routes.ts (configurazione della route di Remix). Senza di essa, l'esecuzione indica cosa cambiare.

I siti statici con htmlPages e siteUrl ottengono anche una sitemap.xml che elenca ogni pagina in ogni lingua e un robots.txt quando non ne hanno.

La lingua del visitatore viene abbinata esattamente, per lingua o a una variante regionale offerta dall'app: un browser impostato su pt-PT riceve l' pt-BR.

Per vedere cosa vedono i motori di ricerca, punta localize-dev seo sul sito. Funziona su qualsiasi sito, configurato da localize.dev o meno.

npx localize-dev seo https://example.com     # the live site
npx localize-dev seo http://localhost:3000   # a local build, before you deploy

Legge robots.txt e la sitemap, quindi carica ogni pagina e le pagine nominate dai suoi link hreflang. Segnala le pagine che non si caricano o reindirizzano, i link hreflang senza l'indirizzo completo o senza x-default, una lingua la cui pagina non rimanda indietro, un <html lang> o og:locale che non corrisponde alla lingua della pagina e un link canonico che punta altrove. Gli indirizzi su un'altra origine (siteUrl, quando controlli una build locale) vengono caricati dall'indirizzo fornito.

Revisione delle traduzioni

Le traduzioni automatiche dalle esecuzioni di GitHub Action e dalle richieste di pull CLI (pr, pr --translate) appaiono sulla Revisione scheda, sorgente e traduzione affiancate, filtrabili per lingua. Approvate una per una o tutte insieme, oppure modificate una: una modifica deve mantenere i segnaposto del sorgente e sostituisce la voce della memoria di traduzione dell'area di lavoro, quindi ogni esecuzione successiva utilizza la correzione. I messaggi plurali mostrano ogni forma necessaria alla lingua (il russo one, few, many...) e vengono modificate forma per forma.

Applica le modifiche alla pull request esegue il commit delle tue modifiche alla pull request di localizzazione aperta da cui provengono, nei suoi file di locale JSON, tramite l'app GitHub. Le modifiche che non possono essere inserite (altri formati di file o una pull request unita) raggiungono la prossima esecuzione tramite la memoria di traduzione.

Ogni traduzione mantiene un thread di note per il prossimo revisore, e mostra chi l'ha approvata o modificata e quando. Quando la stessa correzione continua a presentarsi, la scheda suggerisce un termine del glossario: una parola di origine che dovrebbe sempre tradursi in un certo modo (checkout → pago), o un nome che i revisori continuano a ripristinare e che dovrebbe rimanere non tradotto. Un clic lo aggiunge al glossario del progetto, che ogni esecuzione segue.

Assegna un revisore per lingua dai membri dell'area di lavoro. Quando un'esecuzione porta nuove traduzioni nella loro lingua, ricevono un'email per l'esecuzione con un link alla scheda. Ogni riga si collega al file di origine da cui proviene su GitHub. Il modello segnala le traduzioni di cui non è sicuro (una parola ambigua, un idioma, un'ipotesi formale o informale) con il suo motivo, e la scheda si apre su quelle, sotto Richiede un'occhiata; Approva il resto, lasciali a una persona. Nel codice mostra le righe intorno a dove viene utilizzato, letto dalla pull request dell'esecuzione, in modo che il testo possa essere controllato dove viene visualizzato.

Glossario

Ogni progetto ha un glossario sulla sua pagina dashboard: termini che non devono mai essere tradotti (nomi di marchi e prodotti), traduzioni preferite per il tuo vocabolario e una nota di stile come "informale; usa il tu in tedesco". Si applica a ogni richiesta dall'azione GitHub del progetto e dalle esecuzioni della CLI. Le traduzioni che modificano un termine da non tradurre vengono rifiutate; le traduzioni preferite e la nota di stile guidano il modello.

Piani e limiti

PianoStringhe / meseLingue
Free10003
ProIllimitato5
TeamIllimitatoIllimitato

Una stringa conta una sola volta, indipendentemente da quante lingue viene tradotta. I limiti sono validi per periodi di 30 giorni: dal giorno in cui è stato creato il tuo spazio di lavoro, o dalla data di fatturazione su un piano a pagamento. La dashboard mostra quando il tuo si resetta. Il limite di lingue conta ogni lingua in cui è stata tradotta negli ultimi 30 giorni, in tutti i tuoi spazi di lavoro e progetti. Se una traduzione superasse il limite o il limite di lingue, si interrompe prima di scrivere qualsiasi cosa, spiega il motivo ed esce con codice 2, in modo che la CI fallisca invece di committare una traduzione parziale.

Lingue

localize.dev traduce in qualsiasi lingua conosciuta dal CLDR Unicode, più di 600, scritte come codice BCP 47: una lingua (es, ja, sw), con uno script o una regione quando conta (zh-Hant, sr-Latn, pt-BR, es-419). Non c'è un elenco tra cui scegliere: imposta sourceLocale e targetLocales in localize.config.json, o passa --locales.

Un codice che non nomina alcuna lingua viene rifiutato prima che venga tradotto qualsiasi cosa, con ciò che probabilmente era inteso: jp → ja, cn → zh. Ogni codice valido viene accettato, inclusi alias come en-UK (letto come en-GB) e codici per uso privato. La CLI, l'azione GitHub, la dashboard e l'API controllano nello stesso modo.

  • Quante lingue una traduzione può gestire dipende dal tuo piano. Una stringa conta una sola volta, indipendentemente da quante lingue viene tradotta.
  • Le traduzioni sono più accurate nelle lingue più diffuse. Per le lingue con meno testo online, fai rivedere la pull request da un madrelingua e aggiungi un glossario per i termini specifici del tuo prodotto.
  • Ogni lingua il cui script scorre da destra a sinistra (arabo, ebraico, persiano, urdu, curdo, pashto, siriaco, N’Ko e altri) riceve dir="rtl" e i controlli di stile sinistra/destra. Anche un codice che nomina il suo script conta: pa-Arab.
  • I plurali seguono le forme proprie di ogni lingua (one, few, many...) dal CLDR, quindi polacco, arabo e gallese ottengono tutte le forme di cui hanno bisogno.
  • Le pseudo-localizzazioni en-XA (accentate e più lunghe) e ar-XB (da destra a sinistra) non necessitano di modello né di chiave.

Plurali e testo formattato

Una scelta dipendente dalla quantità come {n} {n === 1 ? 'file' : 'files'} left diventa un messaggio (anche n > 1 ? …, rules.select(n) === 'one' ? … e helper come plural(n, 'file', 'files')), riscritto per t('files.left', { count: n }). Ogni lingua ottiene esattamente le forme di cui ha bisogno (spagnolo tre, polacco quattro, arabo sei), scritte come files.left_one, files.left_few… per i18next o un messaggio plurale ICU, e i18next sceglie quello giusto al runtime.

Una frase con due conteggi, {files} {files === 1 ? 'file' : 'files'} in {folders} {folders === 1 ? 'folder' : 'folders'}, diventa un messaggio per frase contata ({{count}} file / {{count}} files) inserito in una frase, {{files}} in {{folders}}, così ogni conteggio ottiene le proprie forme e i traduttori possono comunque riordinarle. Gli ordinali da helper come ordinal(place) o {n}{ordinalSuffix(n)} diventare plurali ordinali di i18next (t('rank.place', { count: place, ordinal: true })), con le forme ordinali proprie di ogni lingua: inglese 1st/2nd/3rd/4th, francese 1re/2e, spagnolo 1.º.

Lo stesso funziona oltre React: i messaggi ICU (Svelte, Ember) ottengono un selectordinal, vue-i18n ottiene key_ordinal_one… chiavi scelte da Intl.PluralRules, e in Vue, Svelte, Astro, Lit, Ember, Flutter e Rails ogni frase numerata diventa una chiamata plurale all'interno della frase.

Testo intorno a elementi inline semplici, come Read the <a href="/docs">docs</a> first, diventa un messaggio (Read the <a>docs</a> first) reso con <Trans>, così i traduttori possono spostare il link. L'elemento mantiene le sue proprietà. Le traduzioni che perdono o rinominano un tag vengono rifiutate.

Framework senza un <Trans> ottengono lo stesso, con il testo dell'elemento stesso come messaggio proprio: Vue tramite <i18n-t> con slot, Svelte tramite un generato <I18nT> (snippet in Svelte 5, uno slot in 3 e 4), Angular tramite un generato <i18n-t> con ng-template slot (un NgModule prima di Angular 14), Ember tramite un generato <I18nT>, Solid e Qwik tramite rich(). In Rails, un link_to all'interno di una frase viene interpolato in un _html messaggio, in modo che il suo markup venga mantenuto.

Cosa viene tradotto

  • Testo JSX, con testo ed espressioni semplici unite in un messaggio: Hi {user.name}! → Hi {name}!
  • Attributi nell'elenco consentito (placeholder, alt, title, aria-label, aria-description, aria-valuetext, aria-roledescription, label, tooltip; configurabile), e in un SVG <title> e <desc>
  • Stringhe e template literal renderizzato in JSX, comprese entrambe le ramificazioni di a ? 'X' : 'Y' e il lato destro di &&
  • Copia nei costanti che i componenti leggono (const NAV = [{ label: 'Home' }] con NAV.map((n) => n.label)) le string diventano chiavi e ogni lettura diventa t(n.label)
  • Stringhe unite ('Hi ' + name + '!') come un unico messaggio, e messaggi passati a impostatori di stato, notifiche, alert e validazione con zod o yup (z.string().min(1, 'Required'))
  • Prop delle componenti che contengono testo (<EmptyState heading="No orders yet" />, di Vue empty-text="…") tabelle di ricerca lette per chiave (STATUS_LABELS[order.status]) funzioni ausiliarie i cui risultati vengono visualizzati, e testo importato da un modulo semplice (nav.ts) le cui stringhe diventano chiavi lì quando ogni componente che lo importa può essere seguita
  • Frasi con genere grammaticale (gender === 'female' ? 'She…' : 'He…') come messaggi con varianti per genere, quindi ogni lingua li esprime a modo suo
  • Modelli Vue e Svelte (Vue in HTML o Pug): testo, {{ }} e { } espressioni, attributi (compresi title="Hi {name}") e le stringhe che un'espressione rende, come {{ saving ? 'Saving…' : 'Save' }}
  • Script Vue e Svelte: messaggi visualizzati, passati a alert, confirm, toast e notifiche, oppure assegnati a document.title, e costanti mostrate dal template (const tabs = [{ label: 'Home' }] con {{ tab.label }}) le stringhe diventano chiavi e il template le legge tramite $t() o $_()
  • HTML statico: testo degli elementi, frasi intorno agli elementi inline come un unico messaggio, e gli stessi attributi. Il testo da motori di template o PHP viene lasciato invariato e segnalato.

Non tradotto: URL e percorsi, colori, UUID, unità CSS, email, nomi di file, identificatori in snake_case o kebab-case, testo composto solo da simboli e tutto ciò che è contenuto all'interno <code>, <pre>, <Trans>, translate="no" o data-i18n-ignore.

Ogni traduzione viene controllata prima di essere scritta: quella che aggiunge, elimina o rinomina un {placeholder} viene respinta. Le traduzioni esistenti nei tuoi dizionari non vengono mai sovrascritte.

Da destra a sinistra

L'arabo, l'ebraico, il persiano e l'urdu si leggono da destra a sinistra, quindi ml-4 o margin-left finisce dalla parte sbagliata. Quando una lingua di destinazione è da destra a sinistra, check le liste di stili ancorati a sinistra o destra, e localize-dev rtl --fix scambia quelli con un equivalente logico che appare uguale in inglese:

  • Tailwind: ml-/mr- → ms-/me-, pl-/pr- → ps-/pe-, text-left → text-startspigoli arrotondati e bordi, con varianti come md: rimasto.
  • CSS: margin-left → margin-inline-start, padding-right → padding-inline-end, text-align: left → start, bordi e raggi di curvatura.

left-/right- posizioni e galleggiamenti vengono riportati solo perché sono spesso trucchi per il centratura. Verifica il risultato in ar-XB con localize-dev run --pseudo rtl.

Documenti e contenuti

La documentazione, i post del blog e le pagine legali vengono tradotti come documenti interi. localize-dev content traduce i file Markdown e MDX in una copia per lingua: il testo, i titoli, gli elementi delle liste, le celle delle tabelle e i titoli e le descrizioni dei front-matter vengono tradotti; i blocchi di codice, il codice inline, gli URL dei link, le importazioni MDX, i componenti e le espressioni rimangono esattamente come scritti. Un passaggio la cui traduzione perde uno di questi elementi viene mantenuto in inglese e segnalato.

localize.config.json
{
  "targetLocales": ["es", "fr"],
  "content": {
    "include": ["docs/**/*.md", "blog/**/*.mdx"],
    "output": "{dir}/{name}.{locale}{ext}"
  }
}

L’output predefinito si trova accanto a ciascun file (intro.es.md), come previsto da Nextra, Fumadocs e Hugo. Per Docusaurus usa "i18n/{locale}/docusaurus-plugin-content-docs/current/{path}". I documenti non modificati dal momento della creazione delle copie vengono saltati (le loro impronte digitali sono in localize.lock.json), quindi solo quelle modificate vengono ritradotte.

Privacy e dati

  • Solo le stringhe estratte vengono inviate all'API, con il loro percorso file e componente come contesto. I file interi non vengono mai inviati.
  • Scansioni ed esecuzioni offline non lasciano mai la tua macchina.
  • La CLI riscrive i file localmente; la GitHub Action esegue il commit dal tuo runner con il tuo token.
  • Le chiavi API sono archiviate come hash; il segreto viene mostrato solo una volta.

Limitazioni

  • Il testo formattato accetta elementi inline annidati fino a tre livelli (il testo in grassetto all'interno di un link diventa un messaggio annidato). Il proprio link title, scritto o impostato dal codice, rimane all'interno del componente della frase in React.
  • I plurali vengono riconosciuti da scelte tra due stringhe in base a un conteggio (===/!== 1, > 1, < 2, Intl.PluralRules) e helper di pluralizzazione con un conteggio e entrambe le forme. Ogni framework estrae le plurali nel proprio idioma (Django's pluralize, Laravel's Str::plural, Kotlin's if … else) e scrive il proprio formato (<plurals>, variazioni del catalogo stringhe, msgid_plural, trans_choice; Angular, che non ne ha, sceglie la chiave con un generato pluralForm pipe). Una frase con diversi conteggi ottiene un plurale per conteggio ovunque tranne Django (il cui blocktranslate ne prende uno) e iOS; gli ordinali funzionano nei framework JavaScript e Angular, non in Flutter, Rails, Django, Laravel, Android o iOS, le cui librerie i18n non hanno forme ordinali. Su iOS, un plurale necessita il suo numero nel testo ("\(n) items"), che è ciò da cui varia il catalogo stringhe.
  • I componenti di classe sono tradotti: tramite withTranslation() quando la classe è l'exportazione predefinita del file, altrimenti con render() eseguito all'interno <Translation>. I costruttori, i membri statici e i gestori di eventi utilizzano i18next t, quindi il testo memorizzato da un costruttore segue la lingua al momento del montaggio.
  • Nei script di Vue e Svelte, il testo estratto è ciò che viene chiaramente visualizzato: alert, confirm, le notifiche e le toast, document.title, e le costanti mostrate dal template (una stringa, ref('…'), di un oggetto o di una lista, label/title campi, passati ai componenti figli tradotti), e ciò che computed(), funzioni, $: e $derived ritorno. Una costante di stringa utilizzata dallo script stesso mantiene il suo testo, poiché lo script può confrontarlo o inviarlo. In Svelte 4, il testo che una funzione restituisce viene aggiornato sul render successivo del componente dopo un cambio di lingua.
  • I modelli Vue in Pug vengono tradotti, #[…] tag inline (fino a tre livelli di profondità) e #{} valori inclusi. I modelli di altri preprocessori (rari fuori da Pug) vengono saltati e segnalati.
  • Copiare fuori dai componenti (email, testo SVG, messaggi costruiti sul server) non viene estratto; i documenti Markdown e MDX vengono tradotti interamente con localize-dev content.
  • La richiesta pull per la preview legge i file della branch predefinita; i file Git LFS e i sottomoduli vengono esclusi.