This document provides detailed information about all LRM commands, their options, and usage examples.
- Global Options
- Configuration File
- validate - Validate resource files
- stats - Display statistics
- view - View key details
- add - Add new keys
- update - Update existing keys
- delete - Delete keys
- merge-duplicates - Merge duplicate key occurrences
- export - Export to various formats
- import - Import from CSV
- edit - Interactive TUI editor
- add-language - Create new language file
- remove-language - Delete language file
- list-languages - List all languages
- backup - Backup and version management
- backup list - List backup versions
- backup create - Create manual backup
- backup restore - Restore from backup
- backup diff - Compare backup versions
- backup info - View backup metadata
- backup prune - Clean up old backups
- scan - Scan source code for key references
- translate - Automatic translation (documented below)
- config - Configuration management (documented below)
- chain - Execute multiple commands sequentially
- web - Start web server with REST API and browser UI
- cloud - Cloud synchronization commands (see CLOUD_SYNC.md)
All commands support these options:
-p, --path <PATH>- Path to Resources folder (default: current directory)--config-file <PATH>- Path to configuration file (optional)-h, --help- Show command help
LRM supports a configuration file to customize behavior and avoid repeating options.
Location:
- Auto-discovered:
lrm.jsonin the resource folder - Or specify explicitly with
--config-fileoption
Example lrm.json:
{
"DefaultLanguageCode": "en",
"Translation": {
"DefaultProvider": "google",
"MaxRetries": 3,
"TimeoutSeconds": 30
},
"Scanning": {
"ResourceClassNames": ["Resources", "Strings", "AppResources"],
"LocalizationMethods": ["GetString", "Translate", "L", "T"]
}
}Configuration Options:
| Option | Type | Description |
|---|---|---|
DefaultLanguageCode |
string | Language code to display for the default language (e.g., "en", "fr", "de"). If not set, displays "default". Only affects Table, Simple, and TUI display formats. Does not affect JSON/CSV exports or internal logic. |
Translation |
object | Translation provider configuration (see Translation section below) |
Scanning |
object | Code scanning configuration (see Scanning section below) |
Scanning Configuration:
Configure default behavior for the scan command:
| Option | Type | Description |
|---|---|---|
ResourceClassNames |
string[] | Resource class names to detect in code (e.g., ["Resources", "Strings"]). Default: ["Resources", "Strings", "AppResources"] |
LocalizationMethods |
string[] | Localization method names to detect (e.g., ["GetString", "T"]). Default: ["GetString", "GetLocalizedString", "Translate", "L", "T"] |
Priority System:
All configuration follows a consistent priority order:
- Command-line arguments (highest priority) - Override everything
- Configuration file (
lrm.json) - Project-wide defaults - Built-in defaults (lowest priority) - Fallback values
This allows you to:
- Set project-wide defaults in
lrm.json - Override per-command via CLI arguments
- Use sensible defaults when nothing is configured
Usage:
# Auto-discover lrm.json in resource folder
lrm validate --path ./Resources
# Use specific config file
lrm validate --config-file ./my-config.json --path ./ResourcesNote: Configuration is loaded automatically if lrm.json exists in the resource path. The --config-file option loads a specific configuration file instead.
LRM automatically detects and supports these localization file formats:
| Format | File Patterns | Use Case |
|---|---|---|
| .resx | *.resx, *.{culture}.resx |
.NET applications |
| JSON | strings.json, strings.{culture}.json |
Web applications, custom JSON |
| i18next | {culture}.json in flat structure |
React, Node.js with i18next |
| Android | res/values/strings.xml, res/values-{culture}/strings.xml |
Android apps |
| iOS | {culture}.lproj/Localizable.strings |
iOS/macOS apps |
| PO | locale/{culture}/LC_MESSAGES/*.po, *.po |
GNU gettext projects |
| XLIFF | *.xliff, *.xlf |
Translation interchange |
Format detection is automatic based on file structure and naming patterns. No explicit format flag is required.
See CONFIGURATION.md for format-specific configuration options (JSON, Android, iOS, PO, XLIFF).
Description: Validate resource files for issues including missing translations, duplicates, empty values, and extra keys.
Arguments: None
Options:
-p, --path <PATH>- Resource folder path-f, --format <FORMAT>- Output format:table(default),json, orsimple--placeholder-types <TYPES>- Placeholder types to validate (dotnet, printf, icu, template, all). Comma-separated. Default: dotnet--no-placeholder-validation- Disable placeholder validation--no-scan-code- Disable code scanning when duplicates are found--source-path <PATH>- Source code path to scan for duplicate key usage (defaults to parent of resource path)
What it checks:
- Missing keys in translation files
- Duplicate keys within files (case-insensitive per ResX specification)
- Empty values
- Extra keys not in default language
- Placeholder mismatches between source and translations
Duplicate Key Detection:
Resource key names are case-insensitive per the ResX specification. This means Save and save are considered duplicates by MSBuild and will cause build warnings. When duplicates are found, lrm automatically scans your source code to show which variant is actually used:
Duplicate Keys
┌──────────┬────────────────┐
│ Language │ Duplicate Keys │
├──────────┼────────────────┤
│ default │ Devices │
└──────────┴────────────────┘
Code Usage for Duplicate Keys:
• Variants in resources: Devices, devices
✓ "Devices" found in code: MonitoringDevices.razor:31
✗ "devices" not found in code
This helps you identify which variant to keep and which to remove.
Exit codes:
0- No issues found1- Validation issues detected
Examples:
# Validate current directory (table format by default)
lrm validate
# Validate specific path
lrm validate --path ../Resources
# Output as JSON (useful for CI/CD pipelines)
lrm validate --format json
# Output as simple text (no colors or formatting)
lrm validate --format simple
# Skip code scanning for duplicates
lrm validate --no-scan-code
# Specify custom source path for code scanning
lrm validate --source-path ./src
# Validate with all placeholder types
lrm validate --placeholder-types allOutput formats:
Table (default):
✓ All validations passed!
No issues found.
JSON:
{
"isValid": true,
"totalIssues": 0,
"missingKeys": {},
"extraKeys": {},
"duplicateKeys": {},
"duplicateKeyCodeUsages": {},
"emptyValues": {},
"placeholderMismatches": {}
}JSON with duplicates (showing code usage):
{
"isValid": false,
"totalIssues": 2,
"missingKeys": {},
"extraKeys": {},
"duplicateKeys": {
"default": ["devices", "Devices"]
},
"duplicateKeyCodeUsages": {
"devices": {
"normalizedKey": "devices",
"resourceVariants": ["devices", "Devices"],
"codeScanned": true,
"codeReferences": {
"devices": [
{ "file": "src/Services/DeviceService.cs", "line": 42 },
{ "file": "src/Views/MainView.cs", "line": 128 }
],
"Devices": []
},
"usedVariants": ["devices"],
"unusedVariants": ["Devices"]
}
},
"emptyValues": {},
"placeholderMismatches": {}
}Simple:
✓ All validations passed!
No issues found.
Description: Display translation statistics and coverage with charts and tables.
Arguments: None
Options:
-p, --path <PATH>- Resource folder path-f, --format <FORMAT>- Output format:table(default),json, orsimple
Information shown:
- Total keys per language
- Missing keys count
- Translation coverage percentage
- Visual progress bars (table format only)
- Per-language statistics table
- File sizes
Examples:
# Show stats for current directory (table format with charts)
lrm stats
# Show stats for specific path
lrm stats --path ./Resources
# Output as JSON (useful for programmatic analysis)
lrm stats --format json
# Output as simple text (no colors or charts)
lrm stats --format simpleOutput example:
Translation Statistics
Default Language: English (252 keys)
Language Coverage:
Ελληνικά (el) ████████████████████ 100% (252/252)
Summary Table:
┌────────────────┬────────┬──────────┬──────────┐
│ Language │ Keys │ Missing │ Coverage │
├────────────────┼────────┼──────────┼──────────┤
│ English │ 252 │ 0 │ 100% │
│ Ελληνικά (el) │ 252 │ 0 │ 100% │
└────────────────┴────────┴──────────┴──────────┘
Description: View details of a specific key or multiple keys matching a regex pattern across all languages.
Arguments:
<KEY>- The key or regex pattern to view (required)
Options:
-p, --path <PATH>- Resource folder path--config-file <PATH>- Path to configuration file-f, --format <FORMAT>- Output format:table(default),json, orsimple--regex- Treat KEY as a regular expression pattern--search-in|--scope <SCOPE>- Where to search:keys(default),values,both,comments, orall--case-sensitive- Make search case-sensitive (default is case-insensitive)--count- Show only the count of matching keys (no details)--status <STATUS>- Filter by translation status:empty,missing,untranslated,complete, orpartial--not <PATTERNS>- Exclude keys matching these patterns (comma-separated, supports wildcards)--show-comments- Include comments in output--limit <COUNT>- Maximum number of keys to display (default: 100, 0 for no limit)--no-limit- Show all matches without limit (same as --limit 0)--sort- Sort matched keys alphabetically--cultures <CODES>- Include only specific cultures (comma-separated, e.g.,en,fr,el,default)--exclude <CODES>- Exclude specific cultures (comma-separated)--keys-only- Output only key names without translations--no-translations- Alias for--keys-only
Modes:
- Exact match (default): View a single specific key
- Wildcard mode (automatic): Use
*and?for simple pattern matching - Regex mode (with --regex): View all keys matching a regex pattern
Examples:
Single Key (Exact Match):
# View key in table format (default)
lrm view SaveButton
# Include comments
lrm view SaveButton --show-comments
# Output as JSON
lrm view SaveButton --format json
# Simple format (one line per language)
lrm view SaveButton --format simpleWildcard Patterns (Automatic Detection):
# View all Error keys (App.* → App followed by anything)
lrm view "Error.*"
# View all keys ending with .Text
lrm view "*.Text"
# View all Button keys
lrm view "Button.*"
# View all keys (match everything)
lrm view "*"
# View numbered items with single digit (Item1, Item2, etc.)
lrm view "Item?"
# View keys with exactly 4 characters
lrm view "????"
# View all keys containing "Error" anywhere
lrm view "*Error*"
# Combine wildcards: keys starting with App and ending with Text
lrm view "App.*Text"
# Escape wildcards to match literal * or ?
lrm view "Special\*Key" # Matches literal asterisk
lrm view "Test\?Value" # Matches literal question mark
# With sorting and limit
lrm view "Button.*" --sort --limit 10Multiple Keys (Regex Pattern):
# View all Error keys
lrm view "Error\..*" --regex
# View all button keys with comments
lrm view "Button\..*" --regex --show-comments
# View numbered items (Item1, Item2, etc.)
lrm view "Item[0-9]+" --regex
# View all keys containing "Validation"
lrm view ".*Validation.*" --regex
# View with sorting
lrm view "Success\..*" --regex --sort
# View all matches (no limit)
lrm view ".*" --regex --no-limit
# Custom limit of 50 matches
lrm view ".*Label.*" --regex --limit 50
# JSON output for automation
lrm view "Error\..*" --regex --format jsonCulture Filtering:
# Show only English translations
lrm view "Error.*" --cultures en
# Show default and Greek only
lrm view "Button.*" --cultures default,el
# Show all except French
lrm view "Success.*" --exclude fr
# Show only French and Greek (exclude default)
lrm view "*" --cultures el,fr --limit 50
# Complex: include English and Greek, but exclude English
lrm view "Label.*" --cultures en,el --exclude en # Results in only elKeys-Only Output (for automation):
# Get only key names (explicit)
lrm view "Error.*" --keys-only
# Alternative syntax
lrm view "Api.*" --no-translations
# Auto keys-only: exclude all cultures
lrm view "Button.*" --exclude default,en,el,fr
# Keys-only with JSON for scripting
lrm view "Error.*" --keys-only --format json
# Output: {"matchCount": 3, "keys": [{"key": "Error.NotFound", "translations": {}}, ...]}
# Keys-only with simple format
lrm view "*" --keys-only --format simple --limit 10
# Output: Plain list of key namesDuplicate Key Handling:
The view command handles both case variants and true duplicates (same key appearing multiple times):
# When a key has duplicates, all occurrences are shown with [N] suffix
lrm view TestKey
# Output shows: TestKey [1], TestKey [2], etc.
# View a specific occurrence
lrm view "TestKey [2]"
# Case-insensitive search (default) finds all case variants
lrm view testkey
# Finds: TestKey, testkey, TESTKEY (all shown)
# Case-sensitive search matches exact casing only
lrm view testkey --case-sensitive
# Finds only: testkey
# Wildcards also show all occurrences
lrm view "Test*"
# Shows: TestKey [1], TestKey [2], testkey, TESTKEY, TestOther
# JSON output includes occurrence information
lrm view TestKey --format json
# Output includes: key, occurrence, totalOccurrences, displayKey fieldsDuplicate Handling in Output:
- Table format: Shows
Key [N]in the Key column when duplicates exist - JSON format: Includes
occurrence,totalOccurrences, anddisplayKeyfields - Simple format: Shows
--- Key [N] ---headers for each occurrence - Match count: Shows "N occurrence(s) of M key(s)" when duplicates are present
Search Scope:
Control where the pattern is searched using --search-in (or alias --scope):
# Search in key names only (default behavior)
lrm view "Error" --search-in keys
lrm view "Error.*" # Same - keys is default
# Search in translation values only
lrm view "Not Found" --search-in values
# Finds keys whose translations contain "Not Found"
# Find keys by French translation
lrm view "Introuvable" --search-in values --cultures fr
# Searches all languages' values, displays only French
# Search in both keys and values
lrm view "Cancel" --search-in both
# Returns key if EITHER key name OR any translation matches
# Search in comments only
lrm view "*deprecated*" --search-in comments
# Find all keys with "deprecated" in comments
# Search everywhere (keys, values, AND comments)
lrm view "password" --search-in all
# Find "password" in any location
# Combine with wildcards
lrm view "*error*" --search-in values
# Find all keys with values containing "error"
# Combine with regex
lrm view ".*[Ff]ound.*" --regex --search-in values
# Find keys with values matching regex pattern
# Find untranslated strings
lrm view "Save" --search-in values --cultures fr
# Shows keys where French translation equals "Save" (untranslated)
# Audit terminology
lrm view "contact support" --search-in values --format json
# Find all keys mentioning "contact support" in any language
# Find keys with specific context/comments
lrm view "*navigation*" --search-in comments
# Find keys with navigation-related comments
# Use alias --scope
lrm view "Button" --scope bothKey Points:
--search-in keys(default): Searches key names only (backward compatible)--search-in values: Searches translation values across ALL languages--search-in both: Matches if key OR any value matches--search-in comments: Searches comments across ALL languages--search-in all: Searches keys, values, AND comments everywhere--culturesaffects display, not search scope - all languages are still searched- Searches are case-insensitive by default - use
--case-sensitiveto enable exact case matching
Count-Only Mode:
Get just the count of matching keys without displaying details using --count:
# Count all Error keys
lrm view "Error.*" --count
# Output: Pattern: Error.* (wildcard)
# Found 15 matching key(s)
# Count with JSON output for automation
lrm view "Button.*" --count --format json
# Output: {"pattern":"Button.*","patternType":"wildcard","matchCount":8}
# Count complete translations
lrm view "*" --status complete --count
# Output: Found 42 matching key(s)
# Count with multiple filters
lrm view "*" --cultures fr --status untranslated --count
# Output: Found 12 matching key(s)Status Filtering:
Filter keys by their translation completeness using --status:
# Find keys with empty values in any language
lrm view "*" --status empty
# Shows keys where at least one language has empty/whitespace value
# Find keys missing from any language file
lrm view "*" --status missing
# Shows keys that don't exist in one or more language files
# Find untranslated keys (empty, missing, or same as default)
lrm view "*" --status untranslated
# Shows keys needing translation work
# Find fully translated keys
lrm view "*" --status complete
# Shows keys with non-empty values in all languages
# Find partially translated keys
lrm view "*" --status partial
# Shows keys with some but not all translations
# Combine with pattern matching
lrm view "Error.*" --status untranslated
# Find untranslated Error keys
# Check specific language
lrm view "*" --cultures fr --status untranslated
# Find keys untranslated in French only
# Export for translators
lrm view "*" --status partial --format json --limit 0
# Get all partially translated keys as JSON
# Count untranslated keys
lrm view "*" --status untranslated --count
# Quick summary of translation work neededStatus Types:
empty: Keys with empty/whitespace values in any languagemissing: Keys absent from any language fileuntranslated: Keys that are empty, missing, OR identical to default valuecomplete: Keys with non-empty translations in all languagespartial: Keys with some but not all translations
Note: When using --cultures with --status, the status check applies only to the filtered languages. For example, --cultures fr --status untranslated finds keys untranslated in French only, not all languages.
Inverse Matching (Exclusions):
Exclude keys matching specific patterns using --not:
# Exclude specific key
lrm view "Button.*" --not Button.Cancel
# Shows all Button keys except Cancel
# Exclude with wildcards
lrm view "*" --not "Test.*" --limit 50
# Show first 50 keys, excluding all Test keys
# Multiple exclusion patterns (comma-separated)
lrm view "*" --not "Button.*,Link.*,Icon.*"
# Exclude multiple namespaces
# Multiple exclusion patterns (multiple flags - recommended for shell safety)
lrm view "*" --not "Button.*" --not "Link.*" --not "Icon.*"
# Same as above, but cleaner syntax
# Combine with other filters
lrm view "*" --status untranslated --not "Debug.*" --not "Test.*"
# Find untranslated keys, excluding debug/test keys
# Complex filtering (multiple flags)
lrm view "App.*" --not "App.Internal.*" --not "App.Debug.*"
# Show App keys except internal and debug
# Complex filtering (comma-separated - needs quotes)
lrm view "App.*" --not "App.Internal.*,App.Debug.*"
# Same as above, comma-separated (must quote the whole string)
# Case-insensitive by default
lrm view "*" --not "BUTTON.*"
# Excludes button.*, Button.*, BUTTON.*, etc.
# Case-sensitive exclusion
lrm view "*" --not "Button.*" --case-sensitive
# Only excludes exact case matches
# Export filtered results
lrm view "*" --status partial --not "Test.*" --format json
# Get partially translated keys, excluding testsExclusion Patterns:
- Supports exact matches:
Button.Save - Supports wildcards:
Test.*,*.Debug,*temp* - Multiple patterns: Use multiple
--notflags (recommended) or comma-separated in quotes - Matches key names only (not values or comments)
- Case-insensitive by default, use
--case-sensitiveto change
Syntax Options:
# Option 1: Multiple flags (recommended - shell-safe)
lrm view "*" --not "Test.*" --not "Debug.*"
# Option 2: Comma-separated (must quote the entire value)
lrm view "*" --not "Test.*,Debug.*"
# Option 3: Mix both (all patterns are combined)
lrm view "*" --not "Test.*,Debug.*" --not "Temp.*"Extra Keys Warning:
The view command will warn you if filtered language files contain keys that don't exist in the default file:
lrm view "*" --cultures el
# ⚠ Warning: Some filtered languages contain keys not in default:
# • Ελληνικά (el): 1 extra key(s)
# Run 'lrm validate' to detect all inconsistenciesThis helps identify structural inconsistencies where translation files have extra keys that shouldn't exist. The default language file should always be the master list of keys. Use the validate command for a comprehensive analysis of all inconsistencies.
Wildcards vs Regex:
Wildcards are simpler and more intuitive for most users:
*matches zero or more characters (like.*in regex)?matches exactly one character (like.in regex)- Automatically detected - no flag needed
- Special regex chars are escaped automatically
Use explicit --regex when you need:
- Alternation:
(Error|Warning)\..* - Character classes:
Item[0-9]+ - Anchors:
^StartorEnd$ - Quantifiers:
Item[0-9]{2,4}
The tool automatically detects wildcards if the pattern contains * or ? but doesn't have regex-specific syntax like ^, $, [, (, +, or |.
Output formats:
All output formats use a consistent structure regardless of the number of matched keys. This ensures reliable parsing in automation scripts.
Table format:
Keys: 1
Matched 1 key(s)
┌───────────────────┬──────────────┬─────────────────┐
│ Key │ Language │ Value │
├───────────────────┼──────────────┼─────────────────┤
│ SaveButton │ English │ Save │
│ │ Greek │ Σώσει │
└───────────────────┴──────────────┴─────────────────┘
Showing 1 key(s) across 2 language(s)
Table format (with wildcard pattern):
Pattern: Error.* (wildcard)
Matched 3 key(s)
┌───────────────────┬──────────────┬─────────────────┐
│ Key │ Language │ Value │
├───────────────────┼──────────────┼─────────────────┤
│ Error.NotFound │ English │ Item not found │
│ │ Greek │ Δεν βρέθηκε │
├───────────────────┼──────────────┼─────────────────┤
│ Error.Validation │ English │ Invalid │
│ │ Greek │ Άκυρο │
├───────────────────┼──────────────┼─────────────────┤
│ Error.Unauthorized│ English │ Access denied │
│ │ Greek │ Απαγορεύεται │
└───────────────────┴──────────────┴─────────────────┘
Showing 3 key(s) across 2 language(s)
JSON format:
All JSON output uses the same structure with a keys array for consistency:
{
"pattern": null,
"patternType": null,
"matchCount": 1,
"keys": [
{
"key": "SaveButton",
"translations": {
"default": "Save",
"el": "Σώσει"
}
}
]
}JSON format (with regex pattern):
{
"pattern": "Error\\..*",
"patternType": "regex",
"matchCount": 3,
"keys": [
{
"key": "Error.NotFound",
"translations": {
"default": "Item not found",
"el": "Δεν βρέθηκε"
}
},
{
"key": "Error.Validation",
"translations": {
"default": "Invalid",
"el": "Άκυρο"
}
},
{
"key": "Error.Unauthorized",
"translations": {
"default": "Access denied",
"el": "Απαγορεύεται"
}
}
]
}Simple format:
Keys: 1
Matched 1 key(s)
--- SaveButton ---
English (default): Save
Greek: Σώσει
Simple format (with pattern):
Pattern: Error\..* (regex)
Matched 3 key(s)
--- Error.NotFound ---
English (default): Item not found
Greek: Δεν βρέθηκε
--- Error.Validation ---
English (default): Invalid
Greek: Άκυρο
--- Error.Unauthorized ---
English (default): Access denied
Greek: Απαγορεύεται
Safety Features:
- Regex timeout: 1-second limit prevents ReDoS attacks
- Default limit: Shows first 100 matches to avoid overwhelming output
- Invalid pattern detection: Clear error messages for malformed regex
- Backward compatible: Exact match by default, regex is opt-in
Use Cases:
- Namespace exploration: View all keys in a namespace (e.g.,
Error.*) - Pattern discovery: Find keys by pattern without knowing exact names
- Documentation: Generate translation reports for specific areas
- Validation: Check translations for entire feature groups
- CI/CD integration: Export specific key groups as JSON
Description: Add a new key to all languages. Can be used in interactive or non-interactive mode.
Arguments:
<KEY>- The key to add (required)
Options:
-p, --path <PATH>- Resource folder path-l, --lang <CODE:VALUE>- Language value (e.g.,default:"Save",el:"Σώσει") - can be used multiple times- Use
defaultfor the default language file (the one without a culture code)
- Use
-i, --interactive- Interactive mode (prompts for all language values)--ask-missing- Prompt for missing language values (by default, unspecified languages have empty values)--comment <COMMENT>- Add comment to the key--plural- Create a plural key with multiple forms (JSON backend only)--plural-form <FORM:VALUE>- Plural form value (can be used multiple times). Valid forms: zero, one, two, few, many, other--no-backup- Skip automatic backup creation
Examples:
# Interactive mode (recommended - prompts for proper values in each language)
lrm add NewKey -i
# With completion support - press Tab for suggestions
lrm add <Tab> # Suggests existing keys, common patterns
# Non-interactive with all values (good for automation)
lrm add NewKey --lang default:"Value" --lang el:"Τιμή"
# Add with comment
lrm add SaveButton -i --comment "Button label for save action"
# Add with placeholder for later manual editing
lrm add ErrorMessage --lang default:"ErrorMessage" --comment "TODO: Add actual error text"
# Quick add without backup
lrm add TestKey -l default:"Test" -l el:"Δοκιμή" --no-backup
# Add plural key (JSON backend only)
lrm add ItemCount --plural --plural-form one:"{0} item" --plural-form other:"{0} items"
# Add plural key interactively (prompts for plural forms per language)
lrm add ItemCount --plural -iInteractive mode workflow:
- Prompts for value in each language
- Shows preview of changes
- Creates backup (unless --no-backup)
- Saves changes to all .resx files
When to use interactive vs non-interactive:
- Interactive (
-i): Best for manual development when you know the proper text values - Non-interactive with values: Good for scripting when values are known
- Non-interactive with placeholders: For automation where manual review happens later (e.g., from code scan)
--lang default:"KeyName"), do NOT auto-translate immediately. Edit the .resx manually first, then translate. See Two Workflows for Handling Missing Keys for details.
Description: Update values for an existing key. Can modify one or all languages.
Arguments:
<KEY>- The key to update (required)
Options:
-p, --path <PATH>- Resource folder path-l, --lang <CODE:VALUE>- Language value (e.g.,default:"Save Changes",el:"Αποθήκευση") - can be used multiple times- Use
defaultfor the default language file (the one without a culture code)
- Use
--comment <COMMENT>- Update the comment--plural-form <FORM:VALUE>- Update plural form value (can be used multiple times). Valid forms: zero, one, two, few, many, other-i, --interactive- Interactive mode (prompts for each language)-y, --yes- Skip confirmation prompt--no-backup- Skip automatic backup creation
Examples:
# Update specific languages
lrm update SaveButton --lang default:"Save Changes" --lang el:"Αποθήκευση Αλλαγών"
# Interactive mode
lrm update SaveButton -i
# Quick update with auto-confirm
lrm update SaveButton -y --no-backup
# Update only comment
lrm update SaveButton --comment "Updated description"
# Update plural forms for an existing plural key
lrm update ItemCount --plural-form one:"{0} item selected" --plural-form other:"{0} items selected"Confirmation prompt:
Current values:
English: Save
Greek: Σώσει
New values:
English: Save Changes
Greek: Αποθήκευση Αλλαγών
Proceed with update? [y/N]:
Description: Delete a key from all language files. If duplicates are found, requires the --all-duplicates flag or use of the merge-duplicates command.
Arguments:
<KEY>- The key to delete (required)
Options:
-p, --path <PATH>- Resource folder path-y, --yes- Skip confirmation prompt--no-backup- Skip automatic backup creation--all-duplicates- Delete all occurrences of a duplicate key
Examples:
# Delete with confirmation
lrm delete OldKey
# Delete without confirmation
lrm delete OldKey -y
# Delete without backup
lrm delete OldKey -y --no-backup
# Delete all occurrences of a duplicate key
lrm delete DuplicateKey --all-duplicates -yHandling Duplicate Keys:
When a key appears multiple times in your resource files (duplicates), the delete command will error unless you use --all-duplicates flag or use the merge-duplicates command to consolidate them first:
# Attempting to delete a duplicate key without the flag
lrm delete DuplicateKey
# Output:
# ✗ Key 'DuplicateKey' has 2 occurrences.
# Use --all-duplicates to delete all occurrences, or use 'merge-duplicates' to consolidate them.
# Delete all occurrences at once
lrm delete DuplicateKey --all-duplicates
# Or consolidate duplicates first (recommended)
lrm merge-duplicates DuplicateKey
# Then delete the merged entry
lrm delete DuplicateKeyConfirmation prompt:
Key to delete: OldKey
┌───────────────┬─────────────────────┐
│ Language │ Value │
├───────────────┼─────────────────────┤
│ Default │ Clear Selection │
│ Ελληνικά (el) │ Καθαρισμός Επιλογής │
└───────────────┴─────────────────────┘
Delete key 'OldKey' from all languages? [y/N]:
Behavior:
- Deletes the key from all language files
- If duplicates exist, requires
--all-duplicatesflag to proceed (deletes all occurrences) - For selective duplicate handling, use
merge-duplicatescommand instead
Description: Merge duplicate occurrences of a key into a single entry by selecting which occurrence to keep for each language.
Arguments:
[KEY]- The key to merge (optional if using--all)
Options:
-p, --path <PATH>- Resource folder path--all- Merge all duplicate keys in the resource files--auto-first- Automatically select first occurrence from each language without prompting-y, --yes- Skip final confirmation prompt--no-backup- Skip automatic backup creation
Examples:
# Interactive mode - prompts for each language
lrm merge-duplicates DuplicateKey
# Auto mode - keeps first occurrence from each language
lrm merge-duplicates DuplicateKey --auto-first
# Merge all duplicate keys in the file (auto mode)
lrm merge-duplicates --all --auto-first
# Merge without backup or confirmation
lrm merge-duplicates DuplicateKey --auto-first -y --no-backupInteractive Mode:
When running in interactive mode (default), the command prompts you to select which occurrence to keep for each language:
Merging key: DuplicateKey
Ελληνικά (el) has 2 occurrences:
Which occurrence to keep for Ελληνικά (el)?
> [1] "Πρώτη εμφάνιση"
[2] "Δεύτερη εμφάνιση"
English (default) has 3 occurrences:
Which occurrence to keep for English (default)?
> [1] "First occurrence"
[2] "Second occurrence"
[3] "Third occurrence"
Preview of merged entry:
┌───────────────┬─────────────────────┐
│ Language │ Selected Value │
├───────────────┼─────────────────────┤
│ Default │ First occurrence │
│ Ελληνικά (el) │ Πρώτη εμφάνιση │
└───────────────┴─────────────────────┘
Apply merge for key 'DuplicateKey'? [Y/n]:
Auto Mode (--auto-first):
Automatically selects the first occurrence from each language file:
lrm merge-duplicates DuplicateKey --auto-first
# Output:
# ✓ Merged 'DuplicateKey' (kept first occurrence from each language)Case Variant Handling:
When duplicates include case variants (e.g., TestKey and testkey), the command detects them and allows you to choose which key name to standardize on:
Merging key: testkey
⚠ Found 2 case variants: TestKey, testkey
Which key name should be used after merge?
> TestKey
testkey
English (default) has 2 occurrences:
Which occurrence to keep for English (default)?
> [1] "First value" (testkey)
[2] "Second value"
Preview of merged entry: TestKey
...
Apply merge for key 'testkey' → 'TestKey'? [Y/n]:
In auto mode (--auto-first), the first occurrence's key name is used:
lrm merge-duplicates testkey --auto-first
# Output:
# ✓ Merged 'testkey' → 'TestKey' (kept first occurrence from each language)Batch Processing (--all):
Merge all duplicate keys at once:
lrm merge-duplicates --all --auto-first
# Output:
# Found 3 key(s) with duplicates
#
# ✓ Merged 'DuplicateKey1' (kept first occurrence from each language)
# ✓ Merged 'DuplicateKey2' (kept first occurrence from each language)
# ✓ Merged 'DuplicateKey3' (kept first occurrence from each language)
#
# ✓ Successfully merged 3 keysBehavior:
- Per-language selection: Each language can keep a different occurrence
- Comment preservation: Comments are kept atomically with their values
- Cross-file synchronization: If you select occurrence #2 for English, it removes occurrences #1 and #3
- Handles partial occurrences: If a language has fewer occurrences than others, it uses what's available
- Key name standardization: When case variants exist, all remaining entries are renamed to the selected key name
- Case-insensitive matching: Finds all case variants (TestKey, testkey, TESTKEY) automatically
- Error handling: If key doesn't exist or has no duplicates, shows appropriate error message
Error Cases:
# Key not found
lrm merge-duplicates NonExistentKey
# ✗ Key 'NonExistentKey' not found
# Key has no duplicates
lrm merge-duplicates UniqueKey
# ✗ Key 'UniqueKey' has only 1 occurrence, nothing to merge
# No duplicate keys when using --all
lrm merge-duplicates --all --auto-first
# No duplicate keys foundDescription: Export all translations to various formats (CSV, JSON, or simple text) for review or editing.
Arguments: None
Options:
-p, --path <PATH>- Resource folder path-f, --format <FORMAT>- Output format:table(CSV, default),json, orsimple-o, --output <FILE>- Output file path (default:resources.csvfor CSV,resources.jsonfor JSON,resources.txtfor simple)--include-status- Include validation status (shows if key has issues)
Examples:
# Export to CSV (default format)
lrm export
# Export to JSON format
lrm export --format json
# Export to simple text format
lrm export --format simple
# Export to custom file
lrm export -o translations.csv
# Export JSON with custom output file
lrm export --format json -o translations.json
# Include validation status
lrm export --include-statusOutput formats:
CSV (table format, default):
Key,English,Greek,Comment
SaveButton,Save,Σώσει,"Button label"
CancelButton,Cancel,Ακύρωση,""
JSON:
{
"languages": ["English", "Greek"],
"totalKeys": 2,
"entries": [
{
"key": "SaveButton",
"translations": {
"English": "Save",
"Greek": "Σώσει"
},
"comment": "Button label"
}
]
}Simple:
Resource Export
Languages: English, Greek
Total Keys: 2
================================================================================
Key: SaveButton
English: Save
Greek: Σώσει
Comment: Button label
Key: CancelButton
English: Cancel
Greek: Ακύρωση
Description: Import translations from a CSV file. Updates existing keys or adds new ones based on CSV content.
Arguments:
<FILE>- CSV file to import (required)
Options:
-p, --path <PATH>- Resource folder path--overwrite- Overwrite existing values (default: only update empty/missing values)--no-backup- Skip automatic backup creation
CSV Format Requirements:
- First row must be headers:
Key,Language1,Language2,... - Key column is required
- Language columns match your language codes
- Comments column is optional
Examples:
# Import (only fills missing values)
lrm import translations.csv
# Import and overwrite existing values
lrm import translations.csv --overwrite
# Import without backup
lrm import translations.csv --no-backupImport behavior:
- Without --overwrite: Only updates empty or missing values
- With --overwrite: Replaces all values from CSV
Description: Launch the interactive Terminal UI (TUI) editor for visual editing of all translations with advanced filtering and language management.
Arguments: None
Options:
-p, --path <PATH>- Resource folder path
Features:
- Side-by-side multi-language view
- Advanced search and filtering (wildcard, substring, regex)
- Smart wildcard detection (like CLI
viewcommand) - Search scope toggle (Keys+Values / Keys Only / Comments / All)
- Comment editing - Add/edit comments for each language
- Comment display toggle - Show comments below values with double-row layout
- Duplicate key handling - Shows duplicate keys as separate rows with [N] suffix (e.g., "ClearSelection [1]", "ClearSelection [2]")
- Language visibility controls
- Real-time filtering with debouncing (300ms)
- Extra keys detection and warnings
- Visual key editing with auto-translate button for specific occurrences
- 10 translation providers - Google, DeepL, LibreTranslate, Ollama, OpenAI, Claude, Azure OpenAI, Azure Translator, Lingva, MyMemory
- Translation context - Shows key name, source text, and comments when translating
- Automatic validation
- Unsaved changes tracking
- Keyboard-driven interface
Search and Filtering:
The TUI includes powerful filtering capabilities that mirror the CLI view command:
Filter Modes:
- Wildcard (default) - Automatically detects and handles wildcards (
*and?)- If pattern contains wildcards: uses wildcard matching
- If no wildcards: uses substring matching (contains)
- Regex - Full regular expression support with 1-second timeout (when checkbox is checked)
Search Scope:
- Keys+Values (default) - Search in both key names and translation values
- Keys Only - Search only in key names (useful for patterns like
Error.*) - Comments - Search only in comment fields across all languages
- All - Search in keys, values, AND comments together
Filter Controls:
Search: [___________] ☐ Case-sensitive [Keys+Values] ☐ Regex
Show languages: ☑ Default ☑ fr ☑ el [More...] ☐ Show Comments
Example Filters:
Error*- All keys starting with "Error" (wildcard mode, auto-detected)*Button- All keys ending with "Button" (wildcard mode, auto-detected)button- Keys or values containing "button" (substring mode)- Check "Regex" and type
^Api\..*- Keys matching regex pattern (regex mode)
Language Visibility:
Control which language columns are displayed:
Quick Toggle Checkboxes:
- First 3-4 languages shown as checkboxes below search controls
- Click to instantly show/hide language columns
- Changes are reflected immediately in the table
Full Language Dialog:
- Click "More..." button to open complete language selector
- Select/deselect all languages
- "Select All" and "Select None" quick actions
- Apply changes to rebuild table with selected languages
Extra Keys Detection:
The TUI automatically detects and warns about keys that exist in translation files but not in the default language file:
- Keys with warnings are marked with "⚠ " prefix in the key column
- Status bar shows:
⚠ Extra: N (lang1, lang2...) - These keys indicate structural inconsistencies
- Use
validatecommand for detailed analysis
Keyboard Shortcuts:
Navigation:
↑/↓- Navigate keysPgUp/PgDn- Page up/down
Key Management:
Enter- Edit selected key (includes comment fields and auto-translate button)Ctrl+N- Add new keyDel- Delete selected key
Translation:
Ctrl+T- Translate selected key (or auto-translate in edit dialog)F4- Translate all missing valuesF5- Configure translation providers
Language Management:
F2- Add new languageF3- Remove languageCtrl+L- Show language list
File Operations:
Ctrl+S- Save all changes (creates backup)F6- Run validationCtrl+Q- Quit editor
Help:
F1- Show help panel with all shortcuts
All keyboard shortcuts are displayed in the status bar at the bottom of the screen.
Examples:
# Launch editor for current directory
lrm edit
# Launch editor for specific path
lrm edit --path ../ResourcesTUI Interface:
┌─────────────────────────────────────────────────────────────┐
│ Localization Resource Manager - Interactive Editor │
├─────────────────────────────────────────────────────────────┤
│ File | Edit | Languages | Help │
├─────────────────────────────────────────────────────────────┤
│ Search: [___________] ☐ Case-sensitive [Keys+Values] ☐ Regex│
│ Show languages: ☑ Default ☑ fr ☑ el [More...] │
├────────────────┬──────────────┬───────────────┬─────────────┤
│ Key │ Default │ French │ Greek │
├────────────────┼──────────────┼───────────────┼─────────────┤
│ SaveButton │ Save │ Enregistrer │ Σώσει │
│ CancelButton │ Cancel │ Annuler │ Ακύρωση │
│ ⚠ ExtraKey │ │ Extra Value │ │
│ ... │ ... │ ... │ ... │
└────────────────┴──────────────┴───────────────┴─────────────┘
│ Keys: 256/260 | Languages: 3 | ⚠ Extra: 4 (fr,el) | F1=Help...│
└─────────────────────────────────────────────────────────────┘
Workflow Tips:
Finding Keys:
- Use wildcard filters to explore namespaces:
Error*,Button* - Wildcards are auto-detected - just type
*or?in your search - Toggle to "Keys Only" mode for pattern-based key searches
- Check "Regex" checkbox for complex patterns:
^(Error|Warning)\..*
Managing Translations:
- Hide languages you're not currently working on
- Focus on specific culture pairs (e.g., Default + French only)
- Extra key warnings help identify inconsistencies
Performance:
- Search input is debounced (300ms) for smooth typing
- Regex patterns have 1-second timeout to prevent hangs
- Filter results update in real-time as you type
Description: Create a new language resource file with culture-specific translations.
Arguments: None
Options:
-p, --path <PATH>- Resource folder path-c, --culture <CODE>- Culture code (e.g.,fr,fr-FR,de,el,ja) (required)--base-name <NAME>- Base resource file name (auto-detected if not specified)--copy-from <CODE>- Copy entries from specific language (default: copies from default language)--empty- Create empty language file with no entries--no-backup- Skip creating backups-y, --yes- Skip confirmation prompts
Culture Code Format:
- ISO 639-1 language codes:
en,fr,de,el,ja, etc. - Regional variants:
fr-FR,fr-CA,en-US,en-GB, etc.
Examples:
# Add French language (copies from default)
lrm add-language --culture fr
# Add French Canadian (copy from French)
lrm add-language -c fr-CA --copy-from fr
# Create empty German language file
lrm add-language -c de --empty
# Add language without confirmation
lrm add-language -c es -y
# Specify base name when multiple resource files exist
lrm add-language -c fr --base-name MyResourcesWorkflow:
- Validates culture code
- Discovers existing languages
- Auto-detects or validates base name
- Checks if language already exists
- Loads source language entries (default or specified)
- Creates backup of source file
- Creates new language file
- Copies entries if requested
Output example:
► Validating culture code 'fr'...
✓ Culture code valid: French
✓ Using base name: Resources
► Copying 252 entries from default language...
✓ Created: Resources.fr.resx
✓ Added French (fr) language
Tip: Use 'lrm update' or 'lrm edit' to add translations
Description: Delete a language resource file with safety checks and automatic backup.
Arguments: None
Options:
-p, --path <PATH>- Resource folder path-c, --culture <CODE>- Culture code to remove (required)--base-name <NAME>- Base resource file name (auto-detected if not specified)-y, --yes- Skip confirmation prompt--no-backup- Skip creating backups
Safety Features:
- Prevents deletion of default language file
- Shows preview of file to be deleted
- Requires confirmation (unless
-yflag used) - Creates timestamped backup before deletion
Examples:
# Remove French language (with confirmation)
lrm remove-language --culture fr
# Remove without confirmation
lrm remove-language -c fr -y
# Remove specific base name
lrm remove-language -c fr --base-name MyResources
# Remove without backup (not recommended)
lrm remove-language -c fr -y --no-backupConfirmation prompt example:
► Validating culture code 'fr'...
⚠ Warning: This will permanently delete the following file:
┌──────────┬────────────────────────────┐
│ Property │ Value │
├──────────┼────────────────────────────┤
│ File │ Resources.fr.resx │
│ Language │ French (fr) │
│ Entries │ 252 │
│ Path │ ./Resources/Resources.fr.resx │
└──────────┴────────────────────────────┘
Delete this language file? [y/N]:
Output example:
✓ Backup created: Resources.fr.20251109_172342.resx
✓ Deleted Resources.fr.resx
✓ Removed French (fr) language
Error cases:
- Cannot delete default language (no culture code in filename)
- Language file not found
- Invalid culture code
Description: List all available language files with statistics and coverage information.
Arguments: None
Options:
-p, --path <PATH>- Resource folder path--format <FORMAT>- Output format:table(default),simple, orjson
Information displayed:
- Base resource file name
- Language name and code
- File name
- Entry count
- Translation coverage percentage
Output Formats:
lrm list-languagesResource Files: Resources
┌───────────────┬─────────┬────────────────────┬─────────┬──────────┐
│ Language │ Code │ File │ Entries │ Coverage │
├───────────────┼─────────┼────────────────────┼─────────┼──────────┤
│ Default │ (default)│ Resources.resx │ 252 │ 100% ✓ │
│ Ελληνικά (el) │ el │ Resources.el.resx │ 252 │ 100% ✓ │
│ français (fr) │ fr │ Resources.fr.resx │ 248 │ 98% │
└───────────────┴─────────┴────────────────────┴─────────┴──────────┘
Total: 3 languages
lrm list-languages --format simpleResource Files: Resources
(default) Default 252 entries 100%
el Ελληνικά (el) 252 entries 100%
fr français (fr) 248 entries 98%
Total: 3 languages
lrm list-languages --format json[
{
"baseName": "Resources",
"language": "Default",
"code": "(default)",
"fileName": "Resources.resx",
"entries": 252,
"coverage": 100
},
{
"baseName": "Resources",
"language": "Ελληνικά (el)",
"code": "el",
"fileName": "Resources.el.resx",
"entries": 252,
"coverage": 100
},
{
"baseName": "Resources",
"language": "français (fr)",
"code": "fr",
"fileName": "Resources.fr.resx",
"entries": 248,
"coverage": 98
}
]Examples:
# List all languages (table format)
lrm list-languages
# JSON output for scripting
lrm list-languages --format json
# Simple format for quick overview
lrm list-languages --format simple
# List languages in specific path
lrm list-languages --path ./ResourcesUse cases:
- Quick overview of available translations
- Check translation coverage
- Export language list as JSON for automation
- Identify incomplete translations
Description: Backup and version management commands for resource files. LRM automatically creates backups before destructive operations (update, delete, import, translate, etc.) and provides comprehensive version control with diff comparison, selective restoration, and smart rotation policies.
All backups are stored in .lrm/backups/{FileName}/ with version history tracked in manifest.json.
📚 See docs/BACKUP.md for the complete backup system guide.
Description: Display all backup versions for a resource file with metadata.
Arguments: None
Options:
-p, --path <PATH>- Path to Resources folder (default: current directory)-f, --file <NAME>- Resource file name (default: auto-detect first .resx file)-d, --detailed- Show detailed information (operation, user, changes)--format <FORMAT>- Output format:table(default),json, orsimple
Examples:
# List all backups for default resource file
lrm backup list
# List backups for specific file
lrm backup list --file Resources.el.resx
# Show detailed information
lrm backup list --detailed
# JSON output for scripts
lrm backup list --format jsonExample Output:
Backup History: Resources.resx
┌─────────┬──────────────────────┬────────────────┬──────────────┬──────┬─────────┐
│ Version │ Timestamp │ Operation │ User │ Keys │ Changed │
├─────────┼──────────────────────┼────────────────┼──────────────┼──────┼─────────┤
│ v003 │ 2025-01-15 14:22:10 │ delete │ john │ 150 │ -1 │
│ v002 │ 2025-01-15 11:15:22 │ update │ john │ 151 │ 2 │
│ v001 │ 2025-01-15 10:30:45 │ import │ john │ 149 │ 149 │
└─────────┴──────────────────────┴────────────────┴──────────────┴──────┴─────────┘
Total: 3 backups
Description: Manually create a backup of a resource file. Useful before making manual edits or risky operations.
Arguments: None
Options:
-p, --path <PATH>- Path to Resources folder (default: current directory)-f, --file <NAME>- Resource file name (default: all .resx files)-o, --operation <LABEL>- Custom operation label for the backup (default: "manual")
Examples:
# Create backup with default label ("manual")
lrm backup create
# Create backup with custom label
lrm backup create --operation "before-major-refactor"
# Backup specific file
lrm backup create --file Resources.fr.resx --operation "before-translation"
# Backup all files before risky operation
lrm backup create --operation "before-v2-migration"Use Cases:
- Before editing
.resxfiles in Visual Studio - Before running custom scripts
- Before major refactoring
- Creating named checkpoints
Description: Restore a resource file from a backup version. Includes preview of changes and creates a safety backup before applying.
Arguments: None
Options:
-p, --path <PATH>- Path to Resources folder (default: current directory)-f, --file <NAME>- Resource file name (default: auto-detect first .resx file)-v, --version <N>- Backup version number to restore (required)-k, --keys <KEYS>- Comma-separated list of keys to restore (for selective restore)-y, --yes- Skip confirmation prompt--no-backup- Don't create backup before restoring (not recommended)
Examples:
# Restore to version 2 (with preview and confirmation)
lrm backup restore --version 2
# Restore specific file
lrm backup restore --version 2 --file Resources.el.resx
# Selective restore (only specific keys)
lrm backup restore --version 2 --keys Key1,Key2,Key3
# Skip confirmation prompt
lrm backup restore --version 2 --yes
# Restore without creating safety backup (dangerous!)
lrm backup restore --version 2 --no-backupWorkflow:
# 1. List available backups
lrm backup list
# 2. Preview what would change
lrm backup diff --version 2 --current
# 3. Restore the backup
lrm backup restore --version 2Safety Features:
- Shows preview of changes before restoring
- Creates automatic backup before applying restore (unless
--no-backup) - Validates backup file integrity (SHA256 hash)
- Requires confirmation (unless
--yes)
Description: Compare two backup versions or a backup with the current file to see what changed.
Arguments: None
Options:
-p, --path <PATH>- Path to Resources folder (default: current directory)-f, --file <NAME>- Resource file name (default: auto-detect first .resx file)-v, --version <N>- First version number (required unless--version-ais used)--current- Compare with current file state (use with-v)--version-a <N>- First version number (for version-to-version comparison)--version-b <N>- Second version number (for version-to-version comparison)-o, --output <FORMAT>- Output format:text(default),json, orhtml--include-unchanged- Include unchanged keys in output--save <PATH>- Save diff report to file
Examples:
# Compare backup v2 with current state
lrm backup diff --version 2 --current
# Compare two backup versions
lrm backup diff --version-a 1 --version-b 3
# JSON output for scripts
lrm backup diff --version 2 --current --output json
# HTML report for documentation
lrm backup diff --version 2 --current --output html --save diff-report.html
# Include unchanged keys
lrm backup diff --version 2 --current --include-unchangedExample Output:
Diff: v002 → Current (Resources.resx)
┌──────────┬──────────────┬─────────────────┬─────────────────┐
│ Key │ Type │ Old Value │ New Value │
├──────────┼──────────────┼─────────────────┼─────────────────┤
│ Key1 │ Modified │ "Old value" │ "New value" │
│ Key2 │ Deleted │ "Some value" │ │
│ Key3 │ Added │ │ "Added value" │
└──────────┴──────────────┴─────────────────┴─────────────────┘
Statistics:
Added: 1
Modified: 1
Deleted: 1
Total Changes: 3
Change Types:
- Added: Key exists in newer version but not in older
- Modified: Key value or comment changed
- Deleted: Key exists in older version but not in newer
- CommentChanged: Only the comment changed
- Unchanged: Key and value identical (only with
--include-unchanged)
Description: Display detailed metadata for a specific backup version.
Arguments: None
Options:
-p, --path <PATH>- Path to Resources folder (default: current directory)-f, --file <NAME>- Resource file name (default: auto-detect first .resx file)-v, --version <N>- Backup version number (required)--format <FORMAT>- Output format:table(default),json, orsimple
Examples:
# Show info for version 2
lrm backup info --version 2
# Show info for specific file
lrm backup info --version 2 --file Resources.el.resx
# JSON output
lrm backup info --version 2 --format jsonExample Output:
Backup Information: Resources.resx v002
┌─────────────┬───────────────────────┐
│ Property │ Value │
├─────────────┼───────────────────────┤
│ Version │ v002 │
│ Timestamp │ 2025-01-15 11:15:22 │
│ Operation │ update │
│ User │ john │
│ Key Count │ 151 │
│ Changed │ 2 keys │
│ Hash │ a1b2c3d4e5f6... │
│ File Size │ 15.2 KB │
│ File Path │ v002_2025-01-15T... │
└─────────────┴───────────────────────┘
Metadata Includes:
- Version number
- Creation timestamp
- Operation that triggered backup
- User who created it
- Number of keys in backup
- Number of keys changed from previous version
- SHA256 hash for integrity verification
- File size and path
Description: Remove old backups manually. The system automatically keeps up to 10 recent backup versions per file.
Arguments: None
Options:
-p, --path <PATH>- Path to Resources folder (default: current directory)-f, --file <NAME>- Resource file name (default: all .resx files)-y, --yes- Skip confirmation prompt--dry-run- Show what would be deleted without actually deleting
Examples:
# Prune old backups
lrm backup prune
# Prune specific file
lrm backup prune --file Resources.el.resx
# Dry run (preview what would be deleted)
lrm backup prune --dry-run
# Skip confirmation
lrm backup prune --yes
# Prune all files without confirmation
lrm backup prune --yesBehavior:
- The system automatically keeps up to 10 recent backup versions per file
- Older backups are automatically removed when the limit is exceeded
- Manual pruning can remove specific versions or all old backups
Safety:
- Never deletes all backups - at least one backup is always preserved
- Requires confirmation unless
--yes - Use
--dry-runto preview changes
LRM automatically creates backups before any destructive operation:
Auto-backup Triggers:
lrm update- Before updating key valueslrm delete- Before deleting keyslrm remove-lang- Before removing language filelrm import- Before importing datalrm translate- Before translating keyslrm merge-duplicates- Before merging duplicates
Note: lrm add-lang does NOT trigger backups because it creates a new file rather than modifying existing files.
Disabling Backups:
Use the --no-backup flag to skip backup creation for any command:
lrm update MyKey "value" --no-backup
lrm delete OldKey --no-backup
lrm import data.csv --no-backupBackups are stored in .lrm/backups/ with the following structure:
YourProject/
├── Resources/
│ ├── Resources.resx
│ ├── Resources.el.resx
│ └── Resources.fr.resx
└── .lrm/
└── backups/
├── Resources.resx/
│ ├── manifest.json # Version history metadata
│ ├── v001_2025-01-15T10-30-45.resx # First backup
│ ├── v002_2025-01-15T11-15-22.resx # Second backup
│ └── v003_2025-01-15T14-22-10.resx # Latest backup
├── Resources.el.resx/
│ ├── manifest.json
│ └── v001_2025-01-15T10-31-00.resx
└── Resources.fr.resx/
├── manifest.json
└── v001_2025-01-15T14-22-20.resx
Important:
- Add
.lrm/to your.gitignoreto avoid committing backups - Each file has independent version numbering
- Manifest file tracks metadata for all versions
- Backup files include timestamp in filename for easy identification
Access the Backup Manager in the interactive TUI by pressing F7:
Features:
- Browse all backup versions
- View metadata (timestamp, operation, user, changes)
- Compare any two versions with diff viewer
- Restore selected version with preview
- Delete individual backups
- Prune old backups with policy
Keyboard Shortcuts:
- F7 - Open Backup Manager
- ↑/↓ - Navigate backup list
- Enter - View selected backup
- D - Show diff with current
- R - Restore selected backup
- Del - Delete selected backup
- P - Prune old backups
- Esc - Close Backup Manager
Description: Scan source code for localization key references and detect unused or missing keys. Helps identify keys that exist in code but not in .resx files (missing) and keys in .resx files that are never used in code (unused).
Arguments: None
Options:
-p, --path <PATH>- Path to Resources folder (default: current directory)--source-path <PATH>- Path to source code directory to scan (default: parent directory of resource path)--file <PATH>- Scan a single file instead of the entire codebase--exclude <PATTERNS>- Comma-separated glob patterns to exclude from scan (e.g.,**/*.g.cs,**/bin/**,**/obj/**)--strict- Strict mode: only detect high-confidence static references, ignore dynamic patterns--show-unused- Show only unused keys (in .resx but not found in code)--show-missing- Show only missing keys (referenced in code but not in .resx)--show-references- Show detailed reference information for each key (top 20 by usage)--resource-classes <NAMES>- Resource class names to detect (comma-separated, default:Resources,Strings,AppResources)--localization-methods <NAMES>- Localization method names to detect (comma-separated, default:GetString,GetLocalizedString,Translate,L,T)-f, --format <FORMAT>- Output format:table(default),json, orsimple
Supported File Types:
- C# files (
.cs) - Razor files (
.cshtml,.razor) - XAML files (
.xaml)
Detection Patterns:
The scanner automatically detects localization key references using various patterns:
-
Property Access:
Resources.KeyName Strings.SaveButton AppResources.ErrorMessage
-
Indexer Access:
Localizer["KeyName"] _localizer["ErrorMessage"]
-
Method Calls:
GetString("KeyName") GetLocalizedString("ErrorMessage") Translate("ButtonLabel") L("Message") T("Title")
-
Razor Syntax:
@Localizer["KeyName"] @Resources.ErrorMessage
-
XAML Markup Extensions:
{x:Static res:Resources.KeyName} {x:Static local:Strings.ButtonText}
Configuration Priority:
The scanner uses a priority system for configuration:
- Command-line arguments (highest priority)
- Configuration file (
lrm.json- see Scanning section) - Built-in defaults (lowest priority)
This allows you to set project defaults in lrm.json and override them per-scan via CLI arguments.
Strict Mode:
When --strict is enabled, the scanner only detects high-confidence static references:
- Property access:
Resources.KeyName - String literals in method calls:
GetString("KeyName") - XAML static references
Dynamic patterns are ignored in strict mode:
- Variable-based access:
Resources[variableName] - String interpolation:
GetString($"{prefix}.{suffix}") - Computed keys
Use strict mode for CI/CD pipelines or when you want to avoid false positives.
Exit Codes:
0- No issues found (all keys accounted for)1- Issues detected (missing or unused keys found)
Examples:
Basic scan:
# Scan source code in parent directory
lrm scan
# Scan specific source directory
lrm scan --source-path ./MyApp
# Scan with specific resource path
lrm scan --path ./Resources --source-path ./srcSingle file scan:
# Scan a single file for resource key references
lrm scan --file ./Controllers/HomeController.cs
# Scan a single file with JSON output
lrm scan --file ./Views/Home/Index.cshtml --format json
# Useful for editor integrations and real-time validation
lrm scan --file ./Services/UserService.cs --format simpleFilter results:
# Show only unused keys
lrm scan --show-unused
# Show only missing keys
lrm scan --show-missing
# Show detailed reference information
lrm scan --show-referencesExclude patterns:
# Exclude generated files
lrm scan --exclude "**/*.g.cs,**/*.designer.cs"
# Exclude build outputs and test files
lrm scan --exclude "**/bin/**,**/obj/**,**/Tests/**"
# Multiple patterns
lrm scan --exclude "**/*.g.cs" --exclude "**/obj/**"Strict mode:
# Only high-confidence static references
lrm scan --strict
# Strict mode for CI/CD validation
lrm scan --strict --format jsonCustom resource classes and methods:
# Custom resource class names
lrm scan --resource-classes "MyResources,AppStrings,Labels"
# Custom localization methods
lrm scan --localization-methods "GetText,Localize,__"
# Both custom
lrm scan --resource-classes "MyResources" --localization-methods "GetText,T"Output formats:
# JSON output for automation
lrm scan --format json
# Simple text output
lrm scan --format simple
# Default table output (most detailed)
lrm scanOutput Examples:
Table format (default):
Scanning source: /home/user/MyApp/src
Resource path: /home/user/MyApp/Resources
✓ Scanned 145 files
Found 423 key references (156 unique keys)
⚠ 12 low-confidence references (dynamic keys)
╭─────────────────────────────────────────────────────────╮
│ Missing Keys (in code, not in .resx) │
├──────────────────────┬────────────┬─────────────────────┤
│ Key │ References │ Files │
├──────────────────────┼────────────┼─────────────────────┤
│ Error.NotAuthorized │ 3 │ AuthService.cs, ... │
│ Button.Refresh │ 1 │ MainWindow.xaml │
╰──────────────────────┴────────────┴─────────────────────╯
╭─────────────────────────────────────────────────────────╮
│ Unused Keys (in .resx, not in code) │
├──────────────────────┬───────────────────────────────────┤
│ Key │ Count │
├──────────────────────┼───────────────────────────────────┤
│ OldFeature.Title │ - │
│ Deprecated.Message │ - │
╰──────────────────────┴───────────────────────────────────╯
✗ Found 2 missing keys and 2 unused keys
JSON format:
{
"summary": {
"filesScanned": 145,
"totalReferences": 423,
"uniqueKeys": 156,
"missingKeys": 2,
"unusedKeys": 2,
"warnings": 12,
"hasIssues": true
},
"missingKeys": [
{
"key": "Error.NotAuthorized",
"referenceCount": 3,
"references": [
{
"file": "/home/user/MyApp/src/AuthService.cs",
"line": 42,
"pattern": "Resources.Error.NotAuthorized",
"confidence": "High",
"warning": null
}
]
}
],
"unusedKeys": [
"OldFeature.Title",
"Deprecated.Message"
]
}Simple format:
Scanned: 145 files
Found: 423 references (156 unique keys)
Warnings: 12
Missing Keys (2):
- Error.NotAuthorized (3 references)
- Button.Refresh (1 references)
Unused Keys (2):
- OldFeature.Title
- Deprecated.Message
Issues: 2 missing, 2 unused
Use Cases:
Code cleanup:
# Find unused keys to remove
lrm scan --show-unusedDetect missing translations:
# Find keys referenced in code but not in .resx
lrm scan --show-missingAudit key usage:
# See which keys are most frequently used
lrm scan --show-referencesCI/CD validation:
# Fail build if unused or missing keys exist
lrm scan --strict --format json || exit 1Project-specific scanning:
# Scan ASP.NET Core project with custom methods
lrm scan \
--source-path ./MyWebApp \
--resource-classes "Resources,SharedResources" \
--localization-methods "GetString,T" \
--exclude "**/Migrations/**,**/wwwroot/**"Configuration file integration:
Instead of repeating CLI arguments, define scanning defaults in lrm.json:
{
"Scanning": {
"ResourceClassNames": ["MyResources", "Strings", "Labels"],
"LocalizationMethods": ["GetText", "Localize", "L", "T"]
}
}Then simply run:
lrm scanSee the Configuration File section for more details.
Tips:
- Start with default settings to see all patterns, then use
--strictto reduce false positives - Use exclusion patterns to skip generated files, build outputs, and third-party code
- Run regularly as part of your development workflow to catch issues early
- Combine with validate command for complete resource file quality checks
- Use JSON output for integration with CI/CD pipelines and custom tooling
- Check warnings - dynamic patterns may indicate maintenance issues or legitimate use cases
When lrm scan --show-missing finds keys used in code but missing from .resx files, you have two distinct workflows to follow:
Best for: Manual development, ensuring proper source text from the start
# 1. Scan code to find missing keys
lrm scan --show-missing
# 2. Add each key interactively (prompts for text in each language)
lrm add MissingKeyName -i
# 3. Validate the additions
lrm validateWith completion support, press Tab to get command suggestions:
# Start typing and press Tab
lrm add <Tab>
# LRM suggests keys, commands, and optionsBest for: Batch processing, automation scenarios where manual review happens later
# 1. Scan code to find missing keys
lrm scan --format json > scan-results.json
# 2. Add keys with placeholder values (key name as value)
jq -r '.missingKeys[].key' scan-results.json | while read key; do
lrm add "$key" --lang default:"$key" --comment "TODO: Add proper text"
done
# 3. IMPORTANT: Edit the .resx file or use TUI to replace placeholders with real text
lrm edit # or manually edit .resx files
# 4. ONLY AFTER proper text is added, translate to other languages
lrm translate --only-missing
# 5. Validate
lrm validateBROKEN WORKFLOW (will produce incorrect translations):
# ❌ WRONG - This will translate "ErrorMessage" literally
lrm add ErrorMessage --lang default:"ErrorMessage"
lrm translate --only-missing # Translates placeholder as if it were real content!
# Result: French gets "MessageErreur" instead of actual error messageCORRECT WORKFLOW:
# ✅ RIGHT - Add placeholder, edit manually, then translate
lrm add ErrorMessage --lang default:"ErrorMessage" --comment "TODO: Add actual error message"
lrm edit # Replace "ErrorMessage" with "An error occurred"
lrm translate --only-missing # NOW safe to translateThe translate command sends the value from the default language .resx to the AI/translation service:
- If value =
"ErrorMessage"(placeholder), AI translates it literally →"MessageErreur"❌ - If value =
"An error occurred"(proper text), AI translates the actual message →"Une erreur s'est produite"✅
Rule of thumb: Only use lrm translate when the default language .resx file contains proper source text, not placeholder values.
| Scenario | Recommended Workflow |
|---|---|
| Adding 1-5 keys manually | Workflow A (interactive -i) |
| Adding many keys from scan | Workflow B (placeholders → edit → translate) |
| CI/CD automation | Workflow B (add placeholders, require manual review) |
| Dev adds key to code | Workflow A (immediately add with proper text) |
| Batch import from scan | Workflow B (placeholders, team reviews before translating) |
- LRM creates automatic backups before modifications (
.backupfiles) - Use
--no-backuponly when absolutely sure or in automated scripts - Backups are timestamped and stored in the same directory
- Run
lrm validatebefore commits - Add to CI/CD pipeline to catch issues early
- Use exit codes in scripts:
lrm validate || exit 1
- Use
editfor bulk changes (visual, intuitive) - Use
add/update/deletefor scripting and automation - Use
export→ edit in Excel →importfor translator workflows - Use
statsto track translation progress
# Export for translators
lrm export -o for_translation.csv
# Translators edit in Excel/Google Sheets
# Import completed translations
lrm import for_translation.csv --overwriteAutomatically translate resource keys using machine translation providers (Google, DeepL, LibreTranslate, Azure AI Translator), AI-powered translation (OpenAI, Claude, Azure OpenAI, Ollama), or free providers (Lingva, MyMemory).
lrm translate [KEY_PATTERN] [OPTIONS]KEY_PATTERN(optional): Key pattern with wildcard support- If omitted, translates all keys
- Examples:
Error*,Button_*,*.Text
| Option | Description |
|---|---|
--provider <PROVIDER> |
Translation provider: google, deepl, libretranslate, azuretranslator, openai, claude, azureopenai, ollama, lingva, mymemory (default: from config or google) |
--source-language <LANG> |
Source language code (e.g., en, fr, or default). Always defaults to default language file (auto-detect). Specify explicitly to use a specific culture file as source |
--target-languages <LANGS> |
Comma-separated target languages (e.g., fr,de,es). Default: all non-default languages |
--only-missing |
Only translate keys with missing or empty values (safe) |
--overwrite |
Allow overwriting existing translations when using KEY pattern |
--dry-run |
Preview translations without saving |
--no-cache |
Disable translation cache |
--batch-size <SIZE> |
Batch size for processing (default: 10) |
-p, --path <PATH> |
Path to Resources folder |
--config-file <PATH> |
Path to configuration file |
-f, --format <FORMAT> |
Output format: table, json, simple |
Translate only missing keys (recommended):
lrm translate --only-missingTranslate specific keys matching a pattern:
lrm translate "Error*"
lrm translate "Button_*"Translate only missing keys to specific languages:
lrm translate --only-missing --target-languages fr,de,esUse a specific provider:
lrm translate --only-missing --provider deepl
lrm translate --only-missing --provider azuretranslator
lrm translate --only-missing --provider openai
lrm translate --only-missing --provider ollamaUse free providers (no API key needed):
lrm translate --only-missing --provider lingva # Google quality via proxy
lrm translate --only-missing --provider mymemory # 5K chars/day limitPreview without saving (dry run):
lrm translate --dry-runSpecify source language explicitly:
lrm translate --source-language en --target-languages fr,deCombined example:
lrm translate "Welcome*" \
--provider deepl \
--source-language en \
--target-languages fr,de,es,it \
--only-missing \
--dry-runTranslate specific keys with overwrite protection:
# First attempt - will prompt if translations exist
lrm translate Welcome* --target-languages fr
# Skip prompt with --overwrite flag
lrm translate Welcome* --target-languages fr --overwriteTo prevent accidental overwrites of existing translations, the translate command requires explicit intent:
Level 1 - Execution Gate:
- Translation only executes when either
--only-missingOR a KEY pattern is provided - Running
lrm translatewithout either flag will show an error
Level 2 - Overwrite Protection:
- When using a KEY pattern that matches existing translations, you'll be prompted for confirmation
- Use
--overwriteflag to skip the confirmation prompt - Use
--only-missingto safely translate only missing/empty keys
Safe usage patterns:
# Safe: Only translate missing keys
lrm translate --only-missing --target-languages es
# Safe: Translate specific new keys
lrm translate NewFeature* --target-languages es
# Caution: Overwrites with confirmation
lrm translate Welcome* --target-languages es
# Caution: Overwrites without confirmation
lrm translate Welcome* --target-languages es --overwrite0- Translation succeeded1- Translation failed (provider not configured, API error, etc.)
- Provider name:
google - Requirements: Google Cloud Platform account, Translation API enabled
- Languages: 100+ languages
- Quality: High (neural machine translation)
- Provider name:
deepl - Requirements: DeepL API account (Free or Pro)
- Languages: 30+ languages
- Quality: Highest (best-in-class translations)
- Provider name:
libretranslate - Requirements: None for public instances
- Languages: 30+ languages
- Quality: Good (open-source alternative)
- Provider name:
azuretranslator - Requirements: Azure account, Cognitive Services Translator resource
- Languages: 100+ languages
- Quality: High (neural machine translation)
- Configuration: Requires API key and optionally region and endpoint
- Provider name:
openai - Requirements: OpenAI API account and key
- Languages: All major languages
- Quality: Excellent (GPT models with context awareness)
- Configuration: Requires API key, optionally specify model (e.g., gpt-4, gpt-3.5-turbo)
- Provider name:
claude - Requirements: Anthropic API account and key
- Languages: All major languages
- Quality: Excellent (Claude models with strong multilingual support)
- Configuration: Requires API key, optionally specify model (e.g., claude-3-opus, claude-3-sonnet)
- Provider name:
azureopenai - Requirements: Azure account with OpenAI service deployment
- Languages: All major languages
- Quality: Excellent (GPT models via Azure)
- Configuration: Requires API key, endpoint, and deployment name
- Provider name:
ollama - Requirements: Ollama installed locally or accessible endpoint
- Languages: Depends on model (e.g., llama3.2 supports many languages)
- Quality: Good to Excellent (depends on model choice)
- Configuration: API URL (default: http://localhost:11434), model name
Manage translation provider API keys and configuration.
Store an API key in the secure credential store.
lrm config set-api-key --provider <PROVIDER> --key <KEY>Options:
-p, --provider <PROVIDER>- Provider name:google,deepl,libretranslate,azuretranslator,openai,claude,azureopenai,ollama,lingva,mymemory-k, --key <KEY>- API key to store
Example:
lrm config set-api-key --provider google --key "your-api-key"
lrm config set-api-key -p deepl -k "your-deepl-key"Check where an API key is configured from (environment variable, secure store, or config file).
lrm config get-api-key --provider <PROVIDER>Options:
--provider <PROVIDER>- Provider name
Example:
lrm config get-api-key --provider googleOutput:
✓ API key for 'google' is configured.
Source: Environment Variable (LRM_GOOGLE_API_KEY)
Delete an API key from the secure credential store.
lrm config delete-api-key --provider <PROVIDER>Options:
-p, --provider <PROVIDER>- Provider name
Example:
lrm config delete-api-key --provider googleList all translation providers and their configuration status.
lrm config list-providersExample Output:
╭────────────────┬──────────────────┬────────────────────────╮
│ Provider │ Status │ Source │
├────────────────┼──────────────────┼────────────────────────┤
│ google │ ✓ Configured │ Environment Variable │
│ deepl │ ✗ Not configured │ N/A │
│ libretranslate │ ✓ Configured │ Configuration File │
╰────────────────┴──────────────────┴────────────────────────╯
Translation providers require API keys. Three methods are supported (in priority order):
-
Environment Variables (recommended for CI/CD):
export LRM_GOOGLE_API_KEY="your-key" export LRM_DEEPL_API_KEY="your-key" export LRM_LIBRETRANSLATE_API_KEY="your-key"
-
Secure Credential Store (encrypted, optional):
lrm config set-api-key --provider google --key "your-key"Enable in
lrm.json:{ "Translation": { "UseSecureCredentialStore": true } } -
Configuration File (plain text): Add to
lrm.json:{ "Translation": { "ApiKeys": { "Google": "your-google-api-key", "DeepL": "your-deepl-api-key", "LibreTranslate": "your-libretranslate-api-key" } } }⚠️ WARNING: Do not commit API keys to version control!
Create or update lrm.json:
{
"DefaultLanguageCode": "en",
"Translation": {
"DefaultProvider": "google",
"MaxRetries": 3,
"TimeoutSeconds": 30,
"BatchSize": 10,
"UseSecureCredentialStore": false,
"ApiKeys": {
"Google": "your-api-key-here"
}
}
}See docs/TRANSLATION.md for complete translation documentation.
Description: Execute multiple LRM commands sequentially in a single invocation. Chains commands together with a simple separator syntax, enabling powerful automation workflows without writing scripts.
Arguments:
<COMMANDS>- Commands to execute, separated by ' -- ' (space-dash-dash-space) (required)
Options:
--continue-on-error- Continue executing commands even if one fails (default: stop on first error)--dry-run- Show what commands would be executed without running them-h, --help- Show help information
Command Separation:
Commands are separated by -- (space-dash-dash-space). Each command is a complete LRM command with all its arguments and options:
lrm chain "validate -- translate --only-missing -- export"Behavior:
- Sequential execution - Commands run in the order specified
- Exit code propagation - Returns 0 if all commands succeed, 1 if any fails
- Error handling modes:
- Default (stop-on-error): Stops at first failure and returns its exit code
- Continue-on-error: Executes all commands regardless of failures, returns 1 if any failed
Quoting and Arguments:
- Commands can include quoted arguments with spaces:
lrm chain "add \"New Key\" --lang \"default:New Value\" -- validate" - Escape quotes within quoted strings using backslash:
lrm chain "add Key --lang \"default:Value with \\\"quotes\\\"\" -- validate" - Global options (
--path,--config-file) must be specified per command, not at the chain level
Examples:
Translation workflow:
# Validate, translate missing keys, export to CSV
lrm chain "validate --format json -- translate --only-missing -- export -o output.csv"Validation and scanning:
# Run both validation and code scanning
lrm chain "validate -- scan --strict"
# Check with specific source path
lrm chain "validate -- scan --source-path ./src --show-unused"Backup before operations:
# Create backup before updating a key
lrm chain "backup create --operation before-update -- update SaveButton --lang default:Save -- validate"
# Backup, translate, validate
lrm chain "backup create -- translate --only-missing -- validate"Import and validation pipeline:
# Import CSV, validate, run scan
lrm chain "import translations.csv -- validate -- scan"
# Import with continue-on-error to see all issues
lrm chain "import translations.csv -- validate -- scan" --continue-on-errorMulti-language operations:
# Add French, copy from default, translate
lrm chain "add-language -c fr --copy-from default -- translate --target-languages fr --only-missing"
# Remove old language, add new one
lrm chain "remove-language -c fr-CA -y -- add-language -c fr -y"Dry run to preview:
# See what would be executed
lrm chain "validate -- translate --only-missing" --dry-run
# Output:
# Execution Plan:
#
# ═══ Step 1/2 ═══
# validate
#
# ═══ Step 2/2 ═══
# translate --only-missingComplex workflows:
# Complete translation workflow with error handling
lrm chain "validate --format json -- translate --only-missing --provider deepl -- validate --format json -- export -o output.csv" --continue-on-error
# Multi-step key management
lrm chain "view \"Error.*\" --keys-only -- add NewError --lang default:\"New Error\" -- merge-duplicates --all --auto-first"
# Backup, update multiple keys, validate
lrm chain "backup create --operation batch-update -- update Key1 --lang default:Value1 -- update Key2 --lang default:Value2 -- validate"CI/CD integration:
# Validation pipeline (fail on any error)
lrm chain "validate --format json -- scan --strict --format json"
# Translation pipeline with continue-on-error
lrm chain "translate --only-missing -- validate" --continue-on-error
# Full quality check
lrm chain "validate --format json -- scan --strict --format json -- stats --format json"Exit codes:
0- All commands succeeded1- One or more commands failed (or empty chain, invalid syntax)
Error Handling Examples:
Stop on first error (default):
$ lrm chain "validate -- scan --invalid-option -- export"
# validate runs
# scan fails with unknown option
# export DOES NOT run
# Returns: exit code 1Continue on error:
$ lrm chain "validate -- scan --invalid-option -- export" --continue-on-error
# validate runs
# scan fails with unknown option (recorded)
# export STILL runs
# Returns: exit code 1 (because scan failed)Use Cases:
Development Workflow:
- Check quality before commit:
lrm chain "validate -- scan" - Update and verify:
lrm chain "update Key --lang default:Value -- validate" - Safe translation:
lrm chain "backup create -- translate --only-missing -- validate"
Automation:
- Nightly translation job:
lrm chain "translate --only-missing -- export -o daily.csv" - Import from external system:
lrm chain "import external.csv -- validate -- scan" - Multi-language setup:
lrm chain "add-language -c fr -y -- add-language -c de -y -- add-language -c es -y"
Maintenance:
- Cleanup workflow:
lrm chain "merge-duplicates --all --auto-first -- scan --show-unused" - Backup rotation:
lrm chain "backup create --operation weekly -- backup prune --keep 10 -y"
Tips:
-
Use dry-run to preview complex chains before executing:
lrm chain "command1 -- command2 -- command3" --dry-run -
Quote the entire command chain to prevent shell interpretation:
lrm chain "validate -- scan" # Good lrm chain validate -- scan # May fail due to shell parsing
-
Use continue-on-error for reporting/diagnostic workflows:
lrm chain "validate -- scan -- stats" --continue-on-error -
Combine with format options for CI/CD:
lrm chain "validate --format json -- scan --format json" -
Create named backup points before risky operations:
lrm chain "backup create --operation before-refactor -- update Key1 ... -- update Key2 ..."
Limitations:
- Commands within chain cannot use interactive prompts (use
-yflags) - Each command executes in a new context (no shared state between commands)
- Global options must be specified per command, not inherited
- The TUI (
edit) command cannot be used in chains (requires interactive terminal)
Start a web server with REST API and browser-based UI for managing localization resources.
Usage:
lrm web [OPTIONS]Options:
| Option | Description | Default |
|---|---|---|
-p, --path <PATH> |
Path to Resources folder | Current directory |
--source-path <PATH> |
Path to source code for scanning | Parent of resource path |
--port <PORT> |
Port to bind the web server to | 5000 |
--bind-address <ADDRESS> |
Address to bind to (localhost, 0.0.0.0, *) | localhost |
--no-open-browser |
Don't automatically open browser on startup | false |
--enable-https |
Enable HTTPS | false |
--cert-path <PATH> |
Path to HTTPS certificate file (.pfx) | - |
--cert-password <PASSWORD> |
Password for HTTPS certificate | - |
Examples:
# Start web server on default port (localhost:5000)
lrm web
# Start with custom path
lrm web --path /path/to/resources
# Custom port and bind to all interfaces
lrm web --port 8080 --bind-address 0.0.0.0
# With HTTPS
lrm web --enable-https --cert-path ./cert.pfx --cert-password mypassword
# Don't auto-open browser (useful for remote/headless)
lrm web --no-open-browserWeb UI Features:
The web server provides a browser-based UI with:
- Dashboard - Overview with statistics and quick actions
- Resource Editor - Browse, search, and manage all keys
- Key Editor - Edit individual keys with inline translation
- Validation - Run validation checks
- Code Scanner - Find unused/missing keys
- Translation - Batch translate missing values
- Backups - Manage backup versions
- Settings - Language management and configuration
- Export/Import - Export to JSON/CSV formats
REST API:
All operations are also available via REST API:
- Base URL:
http://localhost:5000/api - Swagger UI:
http://localhost:5000/swagger
For complete API documentation, see API.md.
For complete Web UI documentation, see WEBUI.md.
Configuration:
Web server settings can also be configured in lrm.json:
{
"web": {
"port": 5000,
"bindAddress": "localhost",
"autoOpenBrowser": true,
"enableHttps": false
}
}Environment Variables:
| Variable | Description |
|---|---|
LRM_WEB_PORT |
Override default port |
LRM_WEB_BIND_ADDRESS |
Override bind address |
LRM_WEB_AUTO_OPEN_BROWSER |
Enable/disable auto browser open |
For more information:
- Installation Guide
- Usage Examples
- Translation Guide
- Web UI Guide
- REST API Reference
- CI/CD Integration
- Cloud Sync Guide - Cloud synchronization commands (
lrm cloud clone,push,pull, etc.) - Contributing