v0.1CLI, GitHub Action and Cloud are live

Ship your app in every language.

Your web, mobile and desktop apps, translated in one run. Localize.dev finds every hardcoded string, translates it into the languages you choose, and opens a pull request that's ready to review.

$npx localize-dev run
import { useTranslation } from 'react-i18next';

export function Inbox({ user, unread }) {
  const { t } = useTranslation();
  return (
    <section>
      <h1>{t('inbox.welcome_heading', { name: user.name })}</h1>
      <p>{t('inbox.unread_summary', { unread })}</p>
      <input placeholder={t('inbox.search_placeholder')} />
      <button>{unread ? t('inbox.mark_all_read') : t('inbox.refresh')}</button>
    </section>
  );
}

Works with the stack you already use

  • React
  • Next.js
  • Remix
  • Vite
  • React Native
  • Expo
  • Electron
  • Tauri
  • Astro
  • react-i18next
  • next-i18next
  • ICU
  • GitHub Actions

How it works

From hardcoded copy to a localized pull request

Four deterministic steps, with the model only where judgment helps: naming keys and translating. Scroll to follow one component through all four.

01 / 04

Scan the AST

Every .tsx and .jsx file is parsed. JSX text, user-facing attributes and rendered template literals are extracted. URLs, class names and code samples are skipped.

src/checkout/Summary.tsx
4<aside className="summary">class · ignored
5 <h2>Order summary</h2>
6 <p>Hi {user.name}, you have {count} items</p>
7 <input placeholder="Discount code" />
8 <button>Place order</button>
9 <Link href="/cart/edit">Edit cart</Link>URL · ignored
10</aside>

5

strings found

2

ignored by rule

1

component

Works where you build

One engine for web, mobile and desktop

Websites, iOS and Android apps, desktop apps and the component libraries they share. If the interface is built with JSX or TSX, Localize.dev can translate it.

01 / 04

Web apps

React · Next.js · Remix · Vite · Gatsby · Astro islands

acmegoods.com/en

Free shipping on orders over $50

Acme Goods2
The weekend editPieces for slow mornings and long trips.Shop now
Canvas Weekender
New arrivalsView all
Studio Headphones
Studio Headphones$189
Essential Tee
Essential Tee$32
Parlour Palm
Parlour Palm$38
Minimal Watch
Minimal Watch$149

Vue and Svelte single-file components are next on the roadmap.

Why Localize.dev

Five manual steps, done in one run

The work you repeat every release, done in a single pass and reviewed like any other code change.

  1. Find

    Usually:Grep the codebase for strings, file by file

    Now:Every string found on the AST, including attributes, ternaries and template literals

  2. Name

    Usually:Invent a key for each one and hope it stays consistent

    Now:Semantic keys from component context; identical copy reuses its key

  3. Translate

    Usually:Export a spreadsheet, wait on translators, paste it all back

    Now:Every target language translated in one pass

  4. Verify

    Usually:Discover the broken {placeholder} in production

    Now:Placeholders checked before anything is written

  5. Ship

    Usually:Do it all again next release

    Now:A pull request on every push, so new copy never ships untranslated

5 handoffsthe usual way

1 pull requestwith Localize.dev

Try it on your code

How the engine works

Rules do the rewriting. The model only names keys and translates.

Minimal diffs

Edits are spliced in at exact AST offsets. Formatting and import order stay as they were, so reviewers see only the lines that changed.

- <button>Place order</button>
+ <button>{t('checkout.place_order')}</button>
<a href="/terms">…

Whole sentences

Text and expressions merge into one message, so translators see the full sentence instead of fragments.

Hi {name}, you have {count} items

Skips what it can’t change safely

Class components and module-level helpers can't call hooks, so those strings are reported, not guessed at. Next.js server components get an awaited translator instead.

Idempotent

Run it on every push. Wrapped strings are left alone and identical copy reuses its existing key.

Nothing to host

Translation runs on the hosted Localize.dev model on every plan. You don’t need GPUs, prompts or provider keys. An API key is enough.

From your terminal

See every change before it happens

Run it locally first. --dry-run prints each replacement and every skipped string with the reason, so nothing surprises you in review.

localize-dev scanlocalize-dev run --dry-runlocalize-dev runlocalize-dev prlocalize-dev whoami
CLI reference
~/acme/storefront

$ npx localize-dev run -l es,fr,de

🔍 Scanning src/ (target locales: es, fr, de)

src/checkout/Summary.tsx

L6 Order summary → {t('checkout.order_summary_heading')}

L12 "Discount code" → {t('checkout.discount_code_placeholder')}

L15 Place order → {t('checkout.place_order_button')}

src/legacy/PromoBanner.tsx:9 skipped "Free shipping over $50": class component

✅ Localized 3 string(s) across 1 file(s) (3 new keys, 0 reused). 5 file(s) written.

$

Continuous localization

Every push stays localized

Add the GitHub Action and new copy never ships untranslated. Each run updates the same branch and pull request, so you never end up with a pile of PRs or conflicts between runs.

  • One commit with components and every locale file
  • Adds and initializes react-i18next if your app has no i18n yet
  • PR body lists each replacement and every skipped string
  • Every run is tracked on the project page in your dashboard
Set up the Action

Localize: 12 new strings in 4 locales

localize-dev/mainmain

esfrdeja Placeholders verified
.github/workflows/localize.yml
- uses: ufortstephen/autolocalize-action@v1
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    api_key: ${{ secrets.LOCALIZEDEV_API_KEY }}
    target_locales: es,fr,de,ja

Security & privacy

What leaves your machine

Only the strings being translated go to the API. Your source files stay on your machine or CI runner.

  • Strings, not source

    Only extracted strings are sent, with their file path for context. Whole files never leave your machine.

  • Local when you want

    Scans and offline runs happen on your machine with no API key and no network calls, and they don’t use your allowance.

  • Hashed API keys

    Only a hash of each key is stored. Secrets are shown once, and revoking one takes effect immediately.

  • All or nothing

    If a run would go over your plan, it stops before writing anything, so your code is never left half-rewritten.

Pricing

Start free. Upgrade when your copy grows.

Free

$0forever

Everything you need to localize a side project or try it on a real codebase.

  • 500 strings / month
  • Up to 3 target languages per run
  • CLI and GitHub Action
  • Offline mode and scans never use your allowance

Pro

Most popular

$29/month

For products shipping in several markets.

  • 20,000 strings / month
  • Up to 10 target languages per run
  • Pull requests on every push
  • Usage dashboard and multiple API keys
  • One extra workspace, sharing the plan

Team

$99/month

For product teams shipping in many markets.

  • Everything in Pro
  • Invite your team: shared projects, keys and usage
  • Unlimited workspaces, sharing the plan
  • 150,000 strings / month
  • Up to 50 target languages per run
  • Priority support

Compare plans in detail

FAQ

Questions teams ask first

Is it only for React web apps?+

No. It works on any JSX or TSX codebase: web apps on Next.js, Remix or Vite, mobile apps on React Native and Expo, desktop apps on Electron or Tauri, and shared component libraries. Vue and Svelte support is on the roadmap.

Does my code leave my machine?+

Only the strings being translated are sent to the Localize.dev API, with their file path as context. Whole files are never sent. Rewriting happens locally (or on your own CI runner), and scans and offline runs never touch the network.

Do I need to set up a model or GPUs?+

No. Translation runs on the hosted Localize.dev model on every plan, including Free. Create an API key, run localize-dev login, and you’re done.

Do I need i18next set up first?+

No. If your app doesn't use i18next yet, the pull request adds i18next and react-i18next (lockfile included), creates src/i18n.ts to load every locale file, and imports it from your entry file. Apps that already initialize i18next keep their own setup.

What if I already use i18next in part of the app?+

Existing t() calls are ignored, an existing const { t } = useTranslation() is reused, and keys already in en.json are reused when the text matches. It's safe to run on half-localized code.

Are machine translations good enough to ship?+

They are a strong first draft with correct placeholders and consistent keys. For regulated or brand-critical copy, have a native speaker review the PR. The locale file diff puts every translation in one place.

Paste a component. See it in three languages.

No account needed. The playground runs the same engine as the CLI.