Expand description
Universal localization file toolkit for Rust.
Supports parsing, writing, and converting between Apple .strings, .xcstrings, Android strings.xml, and CSV files.
All conversion happens through the unified Resource model.
§Quick Start
use langcodec::{Codec, convert_auto};
// Convert between formats automatically
convert_auto("en.lproj/Localizable.strings", "strings.xml")?;
// Or work with the unified Resource model
let mut codec = Codec::new();
codec.read_file_by_extension("en.lproj/Localizable.strings", None)?;
codec.write_to_file()?;
// Or use the builder pattern for fluent construction
let codec = Codec::builder()
.add_file("en.lproj/Localizable.strings")?
.add_file("fr.lproj/Localizable.strings")?
.add_file("values-es/strings.xml")?
.read_file_by_extension("de.strings", Some("de".to_string()))?
.build();§Supported Formats
- Apple
.strings: Traditional iOS/macOS localization files - Apple
.xcstrings: Modern Xcode localization format with plural support - Android
strings.xml: Android resource files - CSV: Comma-separated values for simple key-value pairs
§Features
- ✨ Parse, write, convert, and merge multiple localization file formats
- 🦀 Idiomatic, modular, and ergonomic Rust API
- 📦 Designed for CLI tools, CI/CD pipelines, and library integration
- 🔄 Unified internal model (
Resource) for lossless format-agnostic processing - 📖 Well-documented, robust error handling and extensible codebase
§Examples
§Basic Format Conversion
use langcodec::convert_auto;
// Convert Apple .strings to Android XML
convert_auto("en.lproj/Localizable.strings", "values-en/strings.xml")?;
// Convert to CSV for analysis
convert_auto("Localizable.xcstrings", "translations.csv")?;§Working with Resources
use langcodec::{Codec, types::Entry};
// Load multiple files with the builder pattern
let codec = Codec::builder()
.add_file("en.lproj/Localizable.strings")?
.add_file("fr.lproj/Localizable.strings")?
.add_file("values-es/strings.xml")?
.build();
// Find specific translations
if let Some(en_resource) = codec.get_by_language("en") {
if let Some(entry) = en_resource.entries.iter().find(|e| e.id == "welcome") {
println!("Welcome message: {}", entry.value);
}
}§Modifying Translations
use langcodec::{Codec, types::{Translation, EntryStatus}};
let mut codec = Codec::builder()
.add_file("en.lproj/Localizable.strings")?
.add_file("fr.lproj/Localizable.strings")?
.build();
// Update an existing translation
codec.update_translation(
"welcome_message",
"en",
Translation::Singular("Hello, World!".to_string()),
Some(EntryStatus::Translated)
)?;
// Add a new translation
codec.add_entry(
"new_feature",
"en",
Translation::Singular("Check out our new feature!".to_string()),
Some("Promotional message for new feature".to_string()),
Some(EntryStatus::New)
)?;
// Copy a translation from one language to another
codec.copy_entry("welcome_message", "en", "fr", true)?;
// Find all translations for a key
for (resource, entry) in codec.find_entries("welcome_message") {
println!("{}: {}", resource.metadata.language, entry.value);
}
// Validate the codec
if let Err(validation_error) = codec.validate() {
eprintln!("Validation failed: {}", validation_error);
}§Batch Processing
use langcodec::Codec;
use std::path::Path;
let mut codec = Codec::new();
// Load all localization files in a directory
for entry in std::fs::read_dir("locales")? {
let path = entry?.path();
if path.extension().and_then(|s| s.to_str()) == Some("strings") {
codec.read_file_by_extension(&path, None)?;
}
}
// Write all resources back to their original formats
codec.write_to_file()?;Re-exports§
pub use crate::builder::CodecBuilder;pub use crate::codec::Codec;pub use crate::converter::convert;pub use crate::converter::convert_auto;pub use crate::converter::convert_auto_with_normalization;pub use crate::converter::convert_resources_to_format;pub use crate::converter::convert_with_normalization;pub use crate::converter::infer_format_from_extension;pub use crate::converter::infer_format_from_path;pub use crate::converter::infer_language_from_path;pub use crate::converter::merge_resources;pub use crate::error::Error;pub use crate::formats::FormatType;pub use crate::placeholder::extract_placeholders;pub use crate::placeholder::normalize_placeholders;pub use crate::placeholder::signature;pub use crate::plural_rules::PluralValidationReport;pub use crate::plural_rules::autofix_fill_missing_from_other_resource;pub use crate::plural_rules::collect_resource_plural_issues;pub use crate::plural_rules::required_categories_for_str;pub use crate::plural_rules::validate_resource_plurals;pub use crate::types::ConflictStrategy;pub use crate::types::Entry;pub use crate::types::EntryStatus;pub use crate::types::Metadata;pub use crate::types::Plural;pub use crate::types::PluralCategory;pub use crate::types::Resource;pub use crate::types::Translation;
Modules§
- builder
- codec
- converter
- Format conversion utilities for langcodec.
- error
- All error types for the langcodec crate.
- formats
- All supported localization file formats for langcodec.
- placeholder
- Placeholder parsing, normalization and validation utilities.
- plural_
rules - traits
- Traits for format-agnostic parsing and serialization in langcodec.
- types
- Core, format-agnostic types for langcodec. Parsers decode into these; encoders serialize these.