Manually maintaining localization files and inventing arbitrary keys for every button or title is a big bottleneck for developers.
With Lingui, you don’t need to write JSON keys manually. Lingui leverages compilation macros to extract text directly from your UI code, while the Crowdin CLI automates the cloud synchronization and translation loop.
In this guide, you will learn how to configure a fully automated CLI-driven localization pipeline: from extracting new strings in your terminal to pushing them for translation without leaving your codebase.
If you want to look at the bigger picture first, explore our i18n guide. If you are new to Lingui, check out our full Lingui i18n setup guide first.
Step 1: How to extract i18n keys using Lingui CLI
Lingui parses the AST (Abstract Syntax Tree) of your JavaScript or TypeScript files, captures text wrapped in macros, and updates your localization source files automatically.
1. Install dependencies
First, install the Lingui CLI tool, macros, and Crowdin CLI as development dependencies.
Depending on your project setup and choice of package manager (npm, yarn, pnpm, or bun), the installation command may vary. For full environment-specific instructions, refer to the official Lingui installation guide.
2. Configure lingui.config.js
Create a lingui.config.js file in the root of your project to define where your source files are located and where the translations should go.
We use Lingui’s default PO (Gettext) format instead of raw JSON. PO files are industry standard for localization because they natively store code context and developer notes. Since PO is the default, we can omit the format property entirely.
import { defineConfig } from "@lingui/cli";
export default defineConfig({ sourceLocale: "en", locales: ["en", "es", "de"], // Define your source and target languages catalogs: [ { path: "src/locales/{locale}/messages", // Where translation catalogs (.po) will be saved include: ["src"], // Folder to scan for code exclude: ["**/node_modules/**"] } ]});Add a shorthand script to your package.json to trigger the extraction process. We include the --clean flag to ensure that any obsolete strings removed from the codebase are automatically pruned from your translation files:
"scripts": { "i18n:extract": "lingui extract --clean" }3. Wrap UI code and extract
Now, whenever you write UI components, wrap your user-facing strings using the <Trans> macro. Make sure your functional component logic is correctly encapsulated.
We use implicit IDs, meaning we do not hardcode manual id attributes. Lingui automatically uses the English source text as the key. For short, ambiguous words (like “Close” or “Run”), never mix styles by adding an explicit ID. Instead, provide a comment attribute. Lingui will extract this comment into the PO file, giving translators full clarity in Crowdin without cluttering your codebase with arbitrary keys.
import { Trans, Plural } from "@lingui/react/macro";
export function Dashboard({ userCount }: { userCount: number }) { return ( <div> <h1> <Trans comment="Main welcome heading on user dashboard"> Welcome back to your dashboard </Trans> </h1>
<button> <Trans comment="Close button for the dashboard modal"> Close </Trans> </button>
{/* Plural macro handles dynamic numeric rules seamlessly */} <p> <Plural value={userCount} one="# active user online" other="# active users online" /> </p> </div> );}Run the extraction command in your terminal:
npm run i18n:extractWhat happens next:
Lingui automatically scans your components, finds the new strings ("Welcome back to your dashboard", "View reports"), and adds them into your source file at src/locales/en/messages.po. It also initializes empty structural records in your target locale paths (src/locales/es/messages.po, etc.) so that they are ready to be mapped.
Step 2: How to configure the Crowdin CLI to automate translation
Extracting strings locally into PO catalogs solves the developer bottleneck of tracking raw UI text. But it introduces a new question: How do these strings actually get translated into multiple languages without manual copy-pasting?
Leaving raw localization files in a Git repository and waiting for engineers to manually fill them out slows down development. This is where Crowdin can help as an automated bridge between your local codebase and translation engines. Once your strings are uploaded, Crowdin triggers automated auto-translation rules — using AI (OpenAI, Gemini, Anthropic, etc.) or machine translation (like DeepL or Google Translate).
Because we are using the PO format, Lingui automatically injects code references and developer comments into the source file. Crowdin leverages this metadata context to ensure that terms like “Close” or “Run” are translated correctly based on where they appear.
Create the crowdin.yml configuration file
To fully automate this hand-off and fetch translations directly via the terminal, create a crowdin.yml configuration file in your project root:
project_id: "123456" # Replace with your actual Crowdin Project IDapi_token_env: "CROWDIN_PERSONAL_TOKEN" # Set this in your local .env or CI secretsbase_path: "."files: - source: /src/locales/en/messages.json translation: /src/locales/%two_letters_code%/messages.jsonStep 3: Production pipeline automation
To bring it all together into a production-ready workflow, let’s update your package.json scripts. This combines extraction, uploads, downloads, and the required runtime compilation step into clean developer pipelines:
"scripts": { "i18n:extract": "lingui extract --clean", "i18n:push": "lingui extract --clean && npx crowdin upload sources", "i18n:pull": "npx crowdin download && lingui compile"}Now, your entire cloud translation cycle is reduced to just two native terminal commands:
1. Upload newly extracted keys to Crowdin
npm run i18n:pushThis pulls the completed translations from Crowdin and drops them right into your /src/locales/{locale}/messages.po paths. It then calls lingui compile, which transforms your raw .po files into highly optimized, minified raw JavaScript artifacts that your production application actually reads at runtime.
GitHub Actions CI/CD Automation
To ensure new strings are pushed to Crowdin automatically without manual developer intervention, add a .github/workflows/i18n-sync.yml file to your codebase:
name: Continuous Localization Sync
on: push: branches: - main
jobs: sync-translations: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v4
- name: Setup Node.js uses: actions/setup-node@v4 with: node-node-version: "20" cache: "npm"
- name: Install Dependencies run: npm ci
- name: Extract Strings run: npm run i18n:extract
- name: Push to Crowdin uses: crowdin/github-action@v2 with: upload_sources: true download_translations: false env: CROWDIN_PROJECT_ID: "123456" CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}By utilizing the official crowdin/github-action, you don’t have to worry about global vs local CLI setups in your build environment. It will safely pick up your crowdin.yml configuration and securely use the CROWDIN_PERSONAL_TOKEN stored in your GitHub Repository Secrets.
CLI Automation Summary
By combining these tools, your continuous localization loop looks like this:
- Write Code: Wrap UI text into
<Trans comment="...">Your text</Trans>using implicit IDs. For dynamic numeric strings, always leverage the<Plural />macro. - Extract: Run
npm run i18n:extractto automatically scan components, catch new strings, prune old ones using the--cleanflag, and update the local .po source catalog. - Sync: Run
npm run i18n:push(or let GitHub Actions handle it on push to main) to make the fresh content accessible for translators or automated AI translation rules inside Crowdin. - Deploy: Run
npm run i18n:pullbefore bundling your application to fetch fresh multi-language support from Crowdin and compile it into optimized production artifacts.
Useful links
If you are looking to advance your localization architecture and dive into automated AI-driven engineering workflows, check out these specialized resources:
- How to Localize JavaScript and React Apps with Lingui (Our step-by-step setup guide for beginners)
- Automating i18n Context with AI Agents (How to use AI to automatically extract and generate developer comments from your code layout)
- Crowdin AI for Developers: Advanced Translation Automation (A practical guide on how developers can leverage Crowdin’s built-in AI features)
- The Ultimate JavaScript Localization Guide (A deep dive into managing i18n architectures across the broader vanilla JS and Node.js ecosystems)
- Case Study: How Holafly uses a custom AI skill and Crowdin to localize 5x faster (Real-world performance insights on building custom AI agent for localization)
Also, watch this 5-minute demo showing a React website plugged into a real localization pipeline using Lingui and Crowdin.
Localize your product with Crowdin
FAQ
How does Lingui extract strings without manual keys?
Unlike traditional i18n frameworks that require developers to invent unique, arbitrary keys for every string, Lingui uses compilation macros. It parses the Abstract Syntax Tree (AST) of your JavaScript or TypeScript files and captures the actual text wrapped inside components like <Trans>. Then, it automatically generates an internal ID based on the text and its context, completely eliminating the need for manual key mapping.
Can I bring my own LLM API keys to use OpenAI or Gemini in Crowdin?
Yes, absolutely. Crowdin features a strict “Bring Your Own API Key” (BYOK) model. You can securely input your own API credentials directly into your Crowdin account settings. This ensures you maintain full control over your data privacy, compliance agreements, and direct-to-provider API costs with zero hidden platform surcharges.
Why should I use api_token_env instead of hardcoding my token in crowdin.yml?
Hardcoding your personal access tokens or API credentials directly into crowdin.yml poses a severe security risk if your codebase is pushed to public or shared repositories. Using api_token_env instructs the Crowdin CLI to look for an environment variable (e.g., CROWDIN_PERSONAL_TOKEN) injected safely via local .env files or CI/CD platform secrets.
