English | 简体中文
Xloca Core is a pure Rust, cross-platform toolkit for Apple localization
formats. It provides the xloca command-line tool and the xloca_core Rust
library for reading, validating, converting, merging, exporting, inspecting,
and editing String Catalog resources.
- Features
- Installation
- Quick start
- Input conventions and safety
- Command overview
- Command reference
- Exit status
- Rust library
- Development
- Strict
.xcstringsparsing from files or byte slices. - Duplicate JSON property detection before a document is built.
- Preservation of entry order, unknown JSON fields, and future schema data.
- Typed recursive access to
stringUnit, variations, and substitutions. - XML and binary plist
.stringsdictsupport on macOS, Linux, and Windows. - Conversion of plural, device, width, nested, and positional substitution rules into multi-locale String Catalogs.
- CI lint output in text, JSON, SARIF, and GitHub Actions formats.
- Coverage reports in text, JSON, CSV, and Markdown.
- Catalog merging with configurable conflict and missing-key strategies.
.stringsand.stringsdictexport in text, XML, or binary form.- Catalog editing, diffing, pseudo-localization, and project scanning.
- Atomic file replacement for generated Catalog and resource files.
For a published release, install the CLI directly from crates.io:
cargo install xloca-coreThe package name is xloca-core; the installed executable is named xloca.
xloca --version
xloca --helpTo use the library in another Rust project:
cargo add xloca-coreThen import it with the Rust crate name xloca_core:
use xloca_core::CatalogParser;Requirements:
- Rust 1.88 or newer.
- Cargo from the same Rust toolchain.
Build and install locally:
cargo build --release
cargo install --path .The release binary is also available at target/release/xloca on Unix-like
systems and target/release/xloca.exe on Windows.
Inspect a Catalog:
xloca inspect Localizable.xcstringsConvert localized .stringsdict resources:
xloca convert-stringsdict Resources \
--table Localizable \
--source-language en \
--output Localizable.xcstringsLint it in CI:
xloca lint Localizable.xcstrings --format sarif --deny-warningsExport legacy resources:
xloca export Localizable.xcstrings \
--output Resources \
--table Localizable- String Catalog:
.xcstrings - Legacy strings table:
.strings - Legacy variation dictionary:
.stringsdict
Catalogs and text .strings files must be UTF-8. .stringsdict input may be an
XML or binary property list.
For legacy files, the locale is inferred from an ancestor directory named
<locale>.lproj, for example en.lproj, fr.lproj, or zh-Hans.lproj.
--localeoverrides inference for all applicable inputs.Base.lprojdoes not produce aBaselocale; the source language is used as the fallback where supported.- Locale matching inside a Catalog is case-insensitive.
The table name is the input file stem: Localizable.strings belongs to the
Localizable table and Errors.stringsdict belongs to Errors.
- Directory conversion or merge fails when it discovers multiple tables unless
--tableselects one. - Explicitly listed merge files may have different names because that choice is considered intentional.
- Modified Catalogs are fully validated before replacement.
- Generated files use temporary files in the destination directory and are atomically persisted.
- Merge and scan generation exclude their own output file, so an output located inside an input tree is safe to regenerate.
- Export locale and table names must be safe single path components.
- Export synchronizes the selected table and resource kinds and removes stale files for locales that no longer contain matching entries.
| Command | Purpose |
|---|---|
inspect |
Parse, validate, and summarize a String Catalog. |
convert-stringsdict |
Convert one or more .stringsdict inputs into a Catalog. |
lint |
Run structural, translation, placeholder, and Xcode compatibility checks. |
merge |
Merge Catalogs and legacy localization resources. |
export |
Export a Catalog to .strings and .stringsdict. |
stats |
Report translation coverage and state totals. |
set-state |
Set stringUnit.state recursively for one locale. |
rename-key |
Rename a Catalog key. |
remove-locale |
Remove a locale from every entry. |
set-comment |
Set or replace an entry comment. |
diff |
Compare Catalog content, states, placeholders, and root metadata. |
pseudo |
Generate an accented or RTL pseudo-localized locale. |
scan |
Discover resources, conflicts, project locales, and generate Catalogs. |
Global options:
| Option | Description |
|---|---|
-h, --help |
Show general or subcommand help. |
-V, --version |
Show the installed version. |
xloca inspect [OPTIONS] <CATALOG>
| Argument or option | Required/default | Description |
|---|---|---|
<CATALOG> |
Required | .xcstrings file to parse and validate. |
--format <FORMAT> |
text |
text for humans or json for programmatic callers. |
The summary includes the canonical file path, source language, schema version,
string count, discovered locales, and whether the Catalog is editable. The
command fails when parsing or structural validation reports an error. JSON
output also includes has_document and structured diagnostics so callers can
distinguish an unreadable Catalog from one that can be opened read-only.
xloca convert-stringsdict [OPTIONS] --output <OUTPUT> \
--source-language <SOURCE_LANGUAGE> <INPUTS>...
| Argument or option | Required/default | Description |
|---|---|---|
<INPUTS>... |
Required | .stringsdict files or directories scanned recursively. |
-o, --output <OUTPUT> |
Required | Destination .xcstrings file. |
-s, --source-language <LANG> |
Required | Catalog development/source language. |
-l, --locale <LOCALE> |
Inferred | Override the locale for every input file. |
--table <TABLE> |
Auto | Select one table from directory inputs. |
--catalog-version <VERSION> |
1.0 |
Schema version written to the generated Catalog. |
Conversion rejects malformed inputs, duplicate plist keys, unsupported rules, unreferenced rules, and ambiguous structures instead of silently dropping data. The generated Catalog is validated before the output is replaced.
Examples:
xloca convert-stringsdict en.lproj/Localizable.stringsdict \
--source-language en \
--output Localizable.xcstrings
xloca convert-stringsdict Resources \
--table Localizable \
--source-language en \
--output Localizable.xcstringsxloca lint [OPTIONS] <CATALOG>
| Argument or option | Required/default | Description |
|---|---|---|
<CATALOG> |
Required | Catalog to check. |
--format <FORMAT> |
text |
text, json, sarif, or github. |
--fix |
Off | Apply deterministic safe fixes before reporting. |
--source-language <LANG> |
None | Add a source language when missing; used with --fix. |
--sort |
Off | Sort Catalog keys; requires --fix. |
-l, --locale <LOCALE> |
Catalog locales | Require a locale even when it is absent from all entries. Repeatable. |
--deny-warnings |
Off | Return a failure status when warnings are present. |
Checks include missing and empty translations, review/stale states, invalid states, printf signature mismatches, substitutions, locale spelling collisions, plural categories, variation ordering, and unsupported Xcode structures.
Safe fixes can normalize locale spelling, add required fields, normalize known states, remove empty localization objects, and sort keys. Fixes are validated before the Catalog is written.
xloca lint Localizable.xcstrings
xloca lint Localizable.xcstrings --format github --deny-warnings
xloca lint Localizable.xcstrings --fix --source-language en --sortxloca merge [OPTIONS] --output <OUTPUT> <INPUTS>...
| Argument or option | Required/default | Description |
|---|---|---|
<INPUTS>... |
Required | Catalog, .strings, .stringsdict, or directory inputs. |
-o, --output <OUTPUT> |
Required | Destination String Catalog. |
-s, --source-language <LANG> |
Inferred/en fallback |
Output source language and fallback locale for legacy files. |
-l, --locale <LOCALE> |
Inferred | Override locale inference for legacy inputs. |
--table <TABLE> |
Auto | Select one table from directory inputs. |
--conflict <MODE> |
keep-existing |
error, keep-existing, overwrite, or prefer-translated. |
--missing <MODE> |
keep |
keep, remove, or mark-stale for keys only in the first input. |
Conflict modes:
| Mode | Behavior |
|---|---|
error |
Stop at the first unequal value for the same key/locale/field. |
keep-existing |
Keep the value already present in the merge base. |
overwrite |
Replace existing values with incoming values. |
prefer-translated |
Replace only when incoming localization content is complete and translated while existing content is not. |
The first expanded input is the merge base. Directory entries are sorted for deterministic results. The output path is excluded from recursive discovery.
xloca merge Base.xcstrings Feature.xcstrings fr.lproj/Localizable.strings \
--source-language en \
--conflict prefer-translated \
--output Localizable.xcstrings
xloca merge Resources \
--table Localizable \
--source-language en \
--output Resources/Localizable.xcstringsxloca export [OPTIONS] --output <OUTPUT> <CATALOG>
| Argument or option | Required/default | Description |
|---|---|---|
<CATALOG> |
Required | Source String Catalog. |
-o, --output <OUTPUT> |
Required | Directory that receives <locale>.lproj folders. |
--table <TABLE> |
Catalog file stem | Output filename without an extension. |
-l, --locale <LOCALE> |
All Catalog locales | Export only the selected locale. Repeatable. |
--kind <KIND> |
all |
strings, stringsdict, or all. |
--serialization <MODE> |
text |
text, xml, or binary. |
Serialization behavior:
| Mode | .strings |
.stringsdict |
|---|---|---|
text |
OpenStep strings syntax | XML plist |
xml |
XML plist dictionary | XML plist |
binary |
Binary plist dictionary | Binary plist |
Direct strings are written to .strings; plural, device, width, and
substitution resources are written to .stringsdict. When applicable, a
fallback direct string is also emitted. Unsupported legacy shapes cause the
command to fail before planned files are written.
xloca export Localizable.xcstrings \
--output Resources \
--table Localizable \
--kind all \
--serialization textxloca stats [OPTIONS] <CATALOG>
| Argument or option | Required/default | Description |
|---|---|---|
<CATALOG> |
Required | Catalog to summarize. |
--format <FORMAT> |
text |
text, json, csv, or markdown. |
-l, --locale <LOCALE> |
All locales | Include only selected locales. Repeatable. |
--minimum <PERCENT> |
None | Fail if any selected locale is below 0 through 100. |
The report includes total, present, completed, missing, pending, review, stale, direct, variation, plural, device, width, substitution, and coverage values. Implicit source-language keys count as complete source content.
xloca stats Localizable.xcstrings --format markdown --minimum 95All editing commands validate the complete Catalog before atomically replacing the input file.
xloca set-state --locale <LOCALE> --state <STATE> [--key <KEY>] <CATALOG>
| Argument or option | Required/default | Description |
|---|---|---|
<CATALOG> |
Required | Catalog to modify. |
--locale <LOCALE> |
Required | Locale whose nested stringUnit values are updated. |
--state <STATE> |
Required | New non-empty state. Common values: translated, needs_review, new, stale. |
--key <KEY> |
All keys | Restrict the change to one Catalog key. |
xloca rename-key <CATALOG> <OLD_KEY> <NEW_KEY>
The command preserves entry order and content and fails if <NEW_KEY> already
exists.
xloca remove-locale <CATALOG> <LOCALE>
Locale matching is case-insensitive. Every matching localization is removed.
xloca set-comment <CATALOG> <KEY> <COMMENT>
The key must already exist. Quote comments containing whitespace in the shell.
xloca diff [OPTIONS] <OLD> <NEW>
| Argument or option | Required/default | Description |
|---|---|---|
<OLD> |
Required | Baseline Catalog. |
<NEW> |
Required | Catalog to compare. |
--format <FORMAT> |
text |
text, json, or markdown. |
--check |
Off | Return a failure status when any difference exists. |
Diff output covers added, removed, and modified keys; locale changes; entry
fields; translation values; states; placeholder-sensitive changes; and root
metadata such as sourceLanguage, version, and unknown future fields.
xloca diff Old.xcstrings New.xcstrings --format json --checkxloca pseudo [OPTIONS] --locale <LOCALE> <CATALOG>
| Argument or option | Required/default | Description |
|---|---|---|
<CATALOG> |
Required | Source Catalog. |
-l, --locale <LOCALE> |
Required | Target pseudo locale, commonly en-XA or ar-XB. |
-o, --output <OUTPUT> |
Input Catalog | Destination Catalog; omission edits in place. |
--source-locale <LOCALE> |
Catalog source language | Locale to clone before transformation. |
--overwrite |
Off | Replace existing target localizations. |
--rtl |
Off | Wrap output with RTL override markers. Automatically enabled for ar-XB. |
--expansion <PERCENT> |
30 |
Append expansion padding; accepted range is 0 through 300. |
Printf placeholders, escaped percent tokens, and Catalog substitution markers are preserved while visible text is accented and expanded.
xloca pseudo Localizable.xcstrings \
--locale en-XA \
--output Pseudo.xcstrings
xloca pseudo Localizable.xcstrings --locale ar-XB --rtlxloca scan [OPTIONS] <PATHS>...
| Argument or option | Required/default | Description |
|---|---|---|
<PATHS>... |
Required | Project files or resource trees to scan recursively. |
--format <FORMAT> |
text |
text or json. |
--catalog-output <DIR> |
None | Generate one merged .xcstrings file per discovered table. |
--source-language <LANG> |
Required with output | Source language for generated Catalogs. |
--fail-on-conflicts |
Off | Return a failure status when duplicate resource groups are found. |
The scanner discovers .xcstrings, .strings, and .stringsdict resources;
groups them by kind, table, and locale; reports duplicates; reads Xcode
knownRegions; reads Swift package defaultLocalization; and reports declared
locales without resources.
Generated output files are excluded on subsequent runs, even when the output directory is inside a scanned tree.
xloca scan . --format json --fail-on-conflicts
xloca scan . \
--catalog-output Generated \
--source-language en| Code | Meaning |
|---|---|
0 |
Command completed successfully. |
2 |
Invalid arguments, parsing/validation failure, I/O failure, lint failure, diff --check difference, coverage threshold failure, or requested conflict failure. |
Machine-readable reports are written to standard output. Diagnostics and final error summaries are written to standard error.
Add the dependency:
cargo add xloca-coreParse a Catalog:
use xloca_core::CatalogParser;
fn main() {
let result = CatalogParser::default().parse_path("Localizable.xcstrings");
for diagnostic in &result.diagnostics {
eprintln!("{diagnostic}");
}
if let Some(document) = result.document {
println!("{} strings", document.strings.len());
println!("locales: {}", document.locales.join(", "));
}
}Main library entry points:
CatalogParser::parse_path/CatalogParser::parse_bytesStringsdictConverter::convertlint_catalog/fix_catalogmerge_catalogs/merge_catalogs_filteredexport_catalogcatalog_stats/diff_catalogsgenerate_pseudoscan_project/generate_catalogs_from_scanwrite_json_atomic
Diagnostics include a stable code, severity, source, JSON/plist pointer, message, and optional line/column information.
Run the complete local verification suite:
cargo test --all-targets
cargo test --doc
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --all -- --checkBuild optimized artifacts:
cargo build --releaseMIT