formatjs_cli 1.1.20

Command-line interface for FormatJS - A Rust-based CLI for internationalization
Documentation

formatjs_cli

A high-performance Rust-based command-line interface for FormatJS internationalization tools.

Overview

formatjs_cli is a high-performance Rust implementation of core FormatJS CLI workflows, providing fast tools for working with ICU MessageFormat messages in your internationalization workflow.

Why Use the Native CLI?

The native Rust CLI offers significant advantages over the Node.js-based @formatjs/cli:

  • Faster Performance: 20.90x faster in the checked-in extraction benchmark, with parallel parsing for large compile and verify workloads
  • Zero Node.js Runtime Dependency: Single binary with no Node.js runtime required for supported features
  • Lower Memory Usage: Minimal memory footprint compared to Node.js
  • Instant Startup: No Node.js initialization overhead
  • Easy Distribution: Standalone binaries for CI/CD pipelines
  • CI/CD Friendly: Fast, reliable, and cache-friendly

Benchmark results (processing 1,000 generated files with 9,406 messages):

  • Pure TypeScript Node.js CLI: ~8.5 seconds
  • Hybrid Node.js/native CLI: 744.86 ms, 12,628 messages/second
  • Rust CLI: 35.65 ms, 263,876 messages/second
  • Speedup vs hybrid CLI: 20.90x

Catalog benchmark results (20,000 generated messages, Apple Silicon, 2026-05-25; includes process startup and JSON I/O):

Workflow Before After Improvement
compile --ast 180.9 ms 121.1 ms 33.1% lower latency
verify --structural-equality 373.3 ms 228.8 ms 38.7% lower latency

The native CLI aims to match @formatjs/cli for supported workflows. Some Node-specific behavior is intentionally not available in the standalone Rust binary, including loading arbitrary JavaScript formatter files with --format.

Threading

The native CLI parallelizes per-file and per-message work with Rayon. Extraction uses per-file parallelism, while AST compilation and structural verification can also parse individual messages in parallel. By default, Rayon uses the number of available logical CPU cores. Set RAYON_NUM_THREADS to cap worker threads in CPU-constrained environments:

RAYON_NUM_THREADS=4 formatjs extract "src/**/*.tsx" --out-file messages.json

Features

  • Extract: Extract messages from JavaScript and TypeScript source files
  • Compile: Compile messages for production use with optional minification
  • Verify: Validate message files and check for missing/extra keys
  • Compile-Folder: Batch compile all translation files in a folder

Quick Start

# Install from Cargo
cargo install formatjs_cli

# Extract messages from your source code
formatjs extract "src/**/*.tsx" --out-file messages.json

# Compile translations for production
formatjs compile "translations/*.json" --out-file compiled.json --ast

# Verify translations are complete
formatjs verify "translations/*.json" --source-locale en --missing-keys

Installation

Cargo

Install the published crate with Cargo:

cargo install formatjs_cli

Cargo installs the command as formatjs in ~/.cargo/bin:

formatjs --help
formatjs --version

If formatjs is not found, add Cargo's bin directory to your PATH:

export PATH="$HOME/.cargo/bin:$PATH"

For local development from this repository:

cargo install --path crates/formatjs_cli
formatjs --help

You can also run without installing:

cargo run -p formatjs_cli -- --help
cargo run -p formatjs_cli -- extract "src/**/*.tsx"

Pre-Built Binaries

Download pre-built native binaries from the GitHub Releases page.

Available binaries:

  • formatjs_cli-darwin-arm64 - macOS Apple Silicon
  • formatjs_cli-linux-arm64 - Linux ARM64
  • formatjs_cli-linux-x64 - Linux x86_64
  • formatjs_cli-win32-x64.exe - Windows x64

Installation steps:

  1. Download the appropriate binary for your platform:

    # macOS Apple Silicon
    curl -L https://github.com/formatjs/formatjs/releases/download/<version>/formatjs_cli-darwin-arm64 -o formatjs
    
    # Linux x86_64
    curl -L https://github.com/formatjs/formatjs/releases/download/<version>/formatjs_cli-linux-x64 -o formatjs
    
    # Linux ARM64
    curl -L https://github.com/formatjs/formatjs/releases/download/<version>/formatjs_cli-linux-arm64 -o formatjs
    
    # Windows x64
    curl.exe -L https://github.com/formatjs/formatjs/releases/download/<version>/formatjs_cli-win32-x64.exe -o formatjs.exe
    
  2. On macOS or Linux, make it executable:

    chmod +x formatjs
    
  3. On macOS or Linux, optionally move it to your PATH:

    sudo mv formatjs /usr/local/bin/
    
  4. Verify installation:

    formatjs --version
    

Using Bazel

Build the CLI using Bazel for host platform:

bazel build //crates/formatjs_cli:formatjs

Run directly with Bazel:

bazel run //crates/formatjs_cli:formatjs -- --help

Cross-Platform Release Builds

Build the release binaries for Darwin ARM64, Linux x64, Linux ARM64, and Windows x64:

bazel build --compilation_mode=opt \
  //crates/formatjs_cli:release_binary_darwin_arm64 \
  //crates/formatjs_cli:release_binary_linux_x64 \
  //crates/formatjs_cli:release_binary_linux_arm64 \
  //crates/formatjs_cli:release_binary_windows_x64_gnullvm

Use bazel cquery --output=files <target> to locate each binary:

bazel cquery --output=files //crates/formatjs_cli:release_binary_darwin_arm64
bazel cquery --output=files //crates/formatjs_cli:release_binary_linux_x64
bazel cquery --output=files //crates/formatjs_cli:release_binary_linux_arm64
bazel cquery --output=files //crates/formatjs_cli:release_binary_windows_x64_gnullvm

Local Cargo Build

Build and install from the local checkout using Cargo:

cd crates/formatjs_cli
cargo build --release
cargo install --path .

The built binary is target/release/formatjs.

Usage

Extract Command

Extract string messages from React components that use react-intl:

formatjs extract "src/**/*.tsx" --out-file messages.json

Full example with options:

formatjs extract "src/**/*.{js,ts,tsx}" \
  --out-file extracted.json \
  --id-interpolation-pattern '[sha512:contenthash:base64:6]' \
  --additional-function-names t,__ \
  --flatten \
  --extract-source-location

Options:

  • [FILES]... - File glob patterns to extract from (e.g., src/**/*.tsx)
  • --format <FORMATTER> - Built-in formatter controlling JSON output shape (default, simple, transifex, smartling, lokalise, or crowdin)
  • --in-file <PATH> - File containing list of files to extract (one per line)
  • --out-file <PATH> - Target file for aggregated .json output
  • --id-interpolation-pattern <PATTERN> - Pattern to auto-generate message IDs (default: [sha512:contenthash:base64:6])
  • --extract-source-location - Extract metadata about message location in source
  • --additional-component-names <NAMES> - Additional component names to extract from (comma-separated)
  • --additional-function-names <NAMES> - Additional function names to extract from (comma-separated)
  • --ignore <PATTERNS> - Glob patterns to exclude
  • --throws - Throw exception when failing to process any file
  • --pragma <PRAGMA> - Parse custom pragma for file metadata (e.g., @intl-meta)
  • --preserve-whitespace - Preserve whitespace and newlines
  • --flatten - Hoist selectors and flatten sentences

Compile Command

Compile extracted translation files into react-intl consumable JSON:

formatjs compile "lang/*.json" --out-file compiled.json

Full example with options:

formatjs compile "lang/*.json" \
  --out-file compiled.json \
  --ast

Options:

  • [TRANSLATION_FILES]... - Glob patterns for translation files (e.g., foo/**/en.json)
  • --format <FORMATTER> - Built-in formatter that converts input to Record<string, string> (default, simple, transifex, smartling, lokalise, or crowdin)
  • --out-file <PATH> - Output file path (prints to stdout if not provided)
  • --ast - Compile to AST instead of strings
  • --skip-errors - Continue compiling after errors (excludes keys with errors)
  • --pseudo-locale <LOCALE> - Generate pseudo-locale AST output; requires --ast
    • Values: xx-LS, xx-AC, xx-HA, en-XA, en-XB
  • --ignore-tag - Treat HTML/XML tags as string literals

Compile-Folder Command

Batch compile all translation JSON files in a folder:

formatjs compile-folder lang/ dist/lang/

Full example with options:

formatjs compile-folder lang/ dist/lang/ --ast

Options:

  • <FOLDER> - Source directory containing translation JSON files
  • <OUT_FOLDER> - Output directory for compiled files
  • --format <FORMATTER> - Built-in formatter (default, simple, transifex, smartling, lokalise, or crowdin)
  • --ast - Compile to AST

Verify Command

Run checks on translation files to validate correctness:

formatjs verify "lang/*.json" --source-locale en --missing-keys

Full example with all checks:

formatjs verify "lang/*.json" \
  --source-locale en \
  --missing-keys \
  --extra-keys \
  --structural-equality

Options:

  • [TRANSLATION_FILES]... - Glob patterns for translation files
  • --source-locale <LOCALE> - Required for checks to work (e.g., en)
  • --ignore <PATTERNS> - Glob patterns to ignore
  • --missing-keys - Check for missing keys in target locales
  • --extra-keys - Check for extra keys not in source locale
  • --structural-equality - Check structural equality of messages

Compatibility Notes

formatjs_cli is intended to match @formatjs/cli where the Rust implementation supports the same feature. Known differences include:

  • --format accepts built-in formatter names only. The Node.js CLI can also load custom JavaScript formatter files.
  • Extraction currently targets JavaScript and TypeScript source files. Framework template extraction for Vue, Svelte, Handlebars, Glimmer, GTS, and GJS is handled by the Node.js CLI.

Development

Running Tests

Using Bazel:

bazel test //crates/formatjs_cli:formatjs_cli_test

Using Cargo:

cargo test

Project Structure

crates/formatjs_cli/
├── Cargo.toml          # Cargo package manifest
├── BUILD.bazel         # Bazel build configuration
├── README.md           # This file
└── src/
    └── main.rs         # Main CLI implementation

Dependencies

  • clap: Command-line argument parsing
  • anyhow: Error handling
  • serde & serde_json: JSON serialization
  • formatjs_icu_messageformat_parser: ICU MessageFormat parsing
  • formatjs_icu_skeleton_parser: ICU skeleton parsing

Performance

This Rust implementation provides significant performance improvements over the Node.js-based CLI, especially for:

  • Large codebases: 10-100x faster extraction and compilation
  • Batch processing: Parallel file and message processing for large catalogs
  • CI/CD pipelines: Faster builds and deployments
  • Memory efficiency: Lower memory usage for large message catalogs

See the benchmarks for detailed performance comparisons.

Contributing

Contributions are welcome! Please see the main FormatJS repository for contribution guidelines.

License

MIT

Related Packages