LRM provides a REST API when running in web server mode (lrm web). This allows programmatic access to all localization management features.
# Basic usage (localhost:5000)
lrm web --path /path/to/resources
# Custom port and bind address
lrm web --port 8080 --bind-address 0.0.0.0
# With HTTPS
lrm web --enable-https --cert-path /path/to/cert.pfx --cert-password mypassword
# Don't auto-open browser
lrm web --no-open-browser| Option | Description | Default |
|---|---|---|
--path, -p |
Path to resources folder | Current directory |
--source-path |
Path to source code for scanning | Parent of resource path |
--port |
Port to bind to | 5000 |
--bind-address |
Address to bind to | localhost |
--no-open-browser |
Don't auto-open browser | false |
--enable-https |
Enable HTTPS | false |
--cert-path |
Path to .pfx certificate | - |
--cert-password |
Certificate password | - |
Base URL: http://localhost:5000/api
GET /api/resources
Returns all discovered resource files.
Response:
[
{
"fileName": "Resources.resx",
"filePath": "/path/to/Resources.resx",
"code": "default",
"isDefault": true
},
{
"fileName": "Resources.el.resx",
"filePath": "/path/to/Resources.el.resx",
"code": "el",
"isDefault": false
}
]GET /api/resources/keys
Returns all localization keys with values across all languages.
Response:
[
{
"key": "SaveButton",
"values": {
"default": "Save",
"el": "Αποθήκευση",
"fr": "Enregistrer"
},
"occurrenceCount": 1,
"hasDuplicates": false
}
]GET /api/resources/keys/{keyName}
Returns detailed information for a specific key, including comments.
Parameters:
occurrence(optional): Specific occurrence index for duplicate keys
Response:
{
"key": "SaveButton",
"values": {
"default": { "value": "Save", "comment": "Button text", "isPlural": false },
"el": { "value": "Αποθήκευση", "comment": null, "isPlural": false }
},
"occurrenceCount": 1,
"hasDuplicates": false
}Response for Plural Key:
{
"key": "ItemCount",
"values": {
"default": {
"value": "{0} items",
"comment": null,
"isPlural": true,
"pluralForms": {
"one": "{0} item",
"other": "{0} items"
}
}
},
"occurrenceCount": 1,
"hasDuplicates": false
}POST /api/resources/keys
Add a new localization key.
Request Body (Simple Key):
{
"key": "NewKey",
"values": {
"default": "Default value",
"el": "Greek value"
},
"comment": "Optional comment"
}Request Body (Plural Key - JSON backend only):
{
"key": "ItemCount",
"isPlural": true,
"pluralValues": {
"default": {
"one": "{0} item",
"other": "{0} items"
},
"el": {
"one": "{0} αντικείμενο",
"other": "{0} αντικείμενα"
}
},
"comment": "Optional comment"
}Plural Forms:
zero- Used for zero quantity (some languages)one- Singular formtwo- Dual form (Arabic, Welsh, etc.)few- Few items (Slavic languages, etc.)many- Many items (Arabic, Polish, etc.)other- Default/plural form (required)
PUT /api/resources/keys/{keyName}
Update an existing key's values and comments.
Parameters:
occurrence(optional): Specific occurrence index for duplicate keys
Request Body (Simple Key):
{
"values": {
"default": { "value": "Updated value", "comment": "Comment for default language" },
"el": { "value": "Ενημερωμένη τιμή", "comment": "Comment for Greek" }
},
"comment": "Global fallback comment (used if per-language comment not provided)"
}Request Body (Plural Key):
{
"values": {
"default": {
"isPlural": true,
"pluralForms": {
"one": "{0} item selected",
"other": "{0} items selected"
}
}
}
}Notes:
- Each language entry in
valuescontains avalue(required) and optionalcomment - Per-language
commenttakes priority over the globalcommentfield - Only languages included in
valuesare updated; others remain unchanged - For plural keys, include
isPlural: trueandpluralFormsdictionary
DELETE /api/resources/keys/{keyName}
Delete a key from all language files.
Parameters:
occurrence(optional): Specific occurrence index for duplicate keysallDuplicates(optional): Delete all occurrences of duplicate key
POST /api/search
Search and filter resource keys with advanced options.
Request Body:
{
"pattern": "Error*",
"filterMode": "wildcard",
"caseSensitive": false,
"searchScope": "keysAndValues",
"statusFilters": ["missing", "duplicates"],
"limit": 100,
"offset": 0
}Filter Modes:
substring(default): Simple contains matchwildcard: Supports*(any chars) and?(single char)regex: Full regular expression
Search Scopes:
keys: Key names onlyvalues: Translation values onlykeysAndValues(default): Both keys and valuescomments: Comments onlyall: Keys, values, and comments
Status Filters:
missing: Keys with missing translationsextra: Keys in non-default but not in defaultduplicates: Keys with multiple occurrences
Response:
{
"results": [...],
"totalCount": 150,
"filteredCount": 25,
"appliedFilterMode": "wildcard"
}GET /api/validation
Run validation checks on all resource files.
Response:
{
"isValid": false,
"missingKeys": {
"el": ["NewKey", "AnotherKey"],
"fr": ["NewKey"]
},
"extraKeys": {},
"emptyValues": {},
"duplicateKeys": ["SomeKey"]
}GET /api/translation/providers
List available translation providers and their configuration status.
Response:
[
{
"name": "google",
"displayName": "Google Cloud Translation",
"isConfigured": true,
"requiresApiKey": true
}
]POST /api/translation/translate
Translate a specific key to target languages.
Request Body:
{
"key": "SaveButton",
"provider": "google",
"targetLanguages": ["el", "fr", "de"],
"onlyMissing": true
}Response:
{
"key": "SaveButton",
"translations": {
"el": "Αποθήκευση",
"fr": "Enregistrer",
"de": "Speichern"
},
"provider": "google",
"cached": false
}POST /api/translation/translate-all
Translate all missing values across all keys.
Request Body:
{
"provider": "google",
"targetLanguages": ["el", "fr"],
"onlyMissing": true,
"dryRun": false
}GET /api/scan
Scan source code for localization key usage.
Response:
{
"scannedFiles": 150,
"totalReferences": 423,
"unusedKeysCount": 5,
"missingKeysCount": 2,
"unused": ["OldKey1", "OldKey2"],
"missing": ["NewCodeKey"],
"references": [
{
"key": "SaveButton",
"referenceCount": 12,
"references": [...]
}
]
}GET /api/scan/unused
Get keys that exist in resources but are not referenced in code.
GET /api/scan/missing
Get keys referenced in code but not in resource files.
GET /api/scan/references/{keyName}
Get source code locations where a key is used.
Response:
{
"key": "SaveButton",
"references": [
{
"file": "src/Views/MainWindow.cs",
"line": 42,
"pattern": "Resources.SaveButton",
"confidence": "High"
}
]
}POST /api/scan/file
Scan a single source code file for localization key references. Useful for editor integrations and real-time validation.
Request:
{
"filePath": "/path/to/Controllers/HomeController.cs",
"content": "optional file content string"
}Parameters:
filePath(required): Absolute path to the file to scan (used for extension detection and result paths)content(optional): File content as a string. If provided, this content will be scanned instead of reading the file from disk. This is useful for scanning unsaved editor changes.
Request Examples:
Scan file from disk:
{
"filePath": "/path/to/Controllers/HomeController.cs"
}Scan in-memory content (e.g., unsaved editor changes):
{
"filePath": "/path/to/Controllers/HomeController.cs",
"content": "public class HomeController {\n var msg = Resources.NewUnsavedKey;\n}"
}Response:
Returns the same format as full codebase scan (ScanResponse), but with scannedFiles: 1 and empty unused array (unused keys require full codebase scan).
{
"scannedFiles": 1,
"totalReferences": 5,
"uniqueKeysFound": 3,
"unusedKeysCount": 0,
"missingKeysCount": 2,
"unused": [],
"missing": ["NewKey", "AnotherMissingKey"],
"references": [
{
"key": "WelcomeMessage",
"referenceCount": 2,
"references": [
{
"file": "/path/to/Controllers/HomeController.cs",
"line": 23,
"pattern": "Resources.WelcomeMessage",
"confidence": "High"
},
{
"file": "/path/to/Controllers/HomeController.cs",
"line": 67,
"pattern": "Resources.WelcomeMessage",
"confidence": "High"
}
]
},
{
"key": "NewKey",
"referenceCount": 1,
"references": [
{
"file": "/path/to/Controllers/HomeController.cs",
"line": 45,
"pattern": "Resources.NewKey",
"confidence": "High"
}
]
}
]
}Notes:
- The
filePathshould be an absolute path to a supported file type (.cs, .razor, .xaml, .cshtml) - When
contentis provided, the file doesn't need to exist on disk - only the extension is used for scanner selection - The
contentparameter enables real-time scanning of unsaved editor changes - Only supported file extensions will be scanned
- Response format is identical to full codebase scan for consistency
scannedFileswill always be1for single-file scansunusedwill always be empty (unused keys can only be determined by scanning entire codebase)- This consistent format makes it easy to add wildcard file support in the future
GET /api/stats
Get translation coverage statistics.
Response:
{
"totalKeys": 150,
"languages": [
{
"code": "default",
"name": "Default",
"translatedCount": 150,
"missingCount": 0,
"emptyCount": 0,
"coverage": 100.0
},
{
"code": "el",
"name": "Greek",
"translatedCount": 142,
"missingCount": 8,
"emptyCount": 0,
"coverage": 94.67
}
]
}GET /api/languages
List all language files.
POST /api/languages
Create a new language file.
Request Body:
{
"culture": "de",
"copyFrom": "default"
}DELETE /api/languages/{culture}
Remove a language file.
GET /api/backup
List all backup versions.
Query Parameters:
file: Filter by resource file namelimit: Maximum number to return
POST /api/backup
Create a manual backup.
Request Body:
{
"description": "Before major changes"
}POST /api/backup/restore
Restore from a backup version.
Request Body:
{
"file": "Resources.resx",
"version": 5,
"keys": ["Key1", "Key2"]
}GET /api/export?format=csv
Export resources to CSV or JSON format.
Query Parameters:
format:csvorjson
POST /api/import
Import translations from CSV.
Request Body: multipart/form-data with CSV file
GET /api/merge-duplicates
List all keys with duplicate entries.
POST /api/merge-duplicates/{keyName}
Merge duplicate occurrences of a key.
Request Body:
{
"keepOccurrence": 1
}Manage API keys securely using the encrypted credential store.
GET /api/credentials/providers
Get all translation providers with their credential configuration status.
Response:
{
"providers": [
{
"provider": "google",
"displayName": "Google Cloud Translation",
"requiresApiKey": true,
"source": "secure_store",
"isConfigured": true
},
{
"provider": "openai",
"displayName": "OpenAI",
"requiresApiKey": true,
"source": "environment",
"isConfigured": true
},
{
"provider": "lingva",
"displayName": "Lingva Translate",
"requiresApiKey": false,
"source": null,
"isConfigured": true
}
],
"useSecureCredentialStore": true
}Source Values:
environment: API key from environment variable (LRM_GOOGLE_API_KEY, etc.)secure_store: API key from encrypted credential storeconfig_file: API key fromlrm.json(plain text)null: No API key configured
PUT /api/credentials/{provider}
Store an API key in the secure credential store (AES-256 encrypted).
Request Body:
{
"apiKey": "sk-your-api-key-here"
}Response:
{
"success": true,
"message": "API key for google stored securely"
}DELETE /api/credentials/{provider}
Remove an API key from the secure credential store.
Response:
{
"success": true,
"message": "API key for google removed from secure store"
}GET /api/credentials/{provider}/source
Get where an API key is configured (without revealing the actual key).
Response:
{
"provider": "google",
"source": "secure_store",
"isConfigured": true
}POST /api/credentials/{provider}/test
Test provider connection by performing a sample translation.
Response (Success):
{
"success": true,
"provider": "google",
"message": "Connection successful! Test translation: 'Hello' -> 'Hola'"
}Response (Failure):
{
"success": false,
"provider": "google",
"message": "Authentication failed - check your API key"
}PUT /api/credentials/secure-store
Enable or disable the secure credential store in configuration.
Request Body:
{
"enabled": true
}Interactive API documentation is available at:
http://localhost:5000/swagger
Web server settings can be configured in lrm.json:
{
"web": {
"port": 5000,
"bindAddress": "localhost",
"autoOpenBrowser": true,
"enableHttps": false,
"httpsCertificatePath": null,
"httpsCertificatePassword": null,
"cors": {
"enabled": false,
"allowedOrigins": ["http://localhost:3000"],
"allowCredentials": false
}
}
}| 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 |
LRM_WEB_HTTPS_ENABLED |
Enable HTTPS |
LRM_WEB_HTTPS_CERT_PATH |
Certificate path |
LRM_WEB_HTTPS_CERT_PASSWORD |
Certificate password |
All endpoints return errors in this format:
{
"error": "Error message description"
}HTTP Status Codes:
200: Success400: Bad request (invalid parameters)404: Resource not found500: Server error