Troubleshooting
"Lexis requires Unity 2023.1+ OR UniTask"
Cause: No async backend available.
Solution:
- Install UniTask: Window → Package Manager → + → Add package from git URL
- Enter:
https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask - Or upgrade to Unity 2023.1+
Missing translations show [MISSING: key]
Cause: Translation key not found in any loaded table.
Solutions:
- Verify the key exists in String Table Browser
- Check
LocalizationSettingsincludes the String Table - Ensure
Localization.Initialize()was called - Check for typos in key names (case-sensitive)
Localization not updating after language change
Cause: Components not subscribed to OnLocaleChanged.
Solution:
void OnEnable()
{
Localization.OnLocaleChanged += OnLocaleChanged;
}
void OnDisable()
{
Localization.OnLocaleChanged -= OnLocaleChanged;
}
void OnLocaleChanged(Locale newLocale)
{
RefreshUI();
}LocalizationSettings not loading
Cause: Settings not in Resources folder.
Solution:
- Move
LocalizationSettings.assettoAssets/Resources/ - Or call
Localization.Initialize(settings)with direct reference
Smart String not formatting correctly
Cause: Invalid syntax or missing arguments.
Solution:
- Validate template:
SmartStringParser.Validate(template, out errors) - Check argument count matches placeholders
- Ensure plural categories match target language
Editor tools not appearing
Cause: Assembly not recompiled after package install.
Solution:
- Assets → Reimport All
- Or restart Unity Editor
- Check Console for compilation errors
Enable verbose logging:
- Select
LocalizationSettings - Enable Log Missing Translations
- Check Console for warnings about missing keys
Run validation checks:
- Open Tools → KitStack → Lexis → String Table Browser
- Click Validation tab
- Click Run Validation
- Review and fix reported issues
Unused Key Detection scans your project to find localization keys that exist in string tables but are not referenced anywhere in your codebase. This helps reduce translation costs and keep your string tables clean.
Why Use Unused Key Detection?
| Benefit | Description |
|---|---|
| Cost Savings | Avoid translating strings that are no longer used |
| Cleaner Tables | Remove dead entries to improve maintainability |
| Bug Detection | Identify orphaned keys that may indicate missing features |
| Project Health | Keep localization data in sync with actual usage |
Running the Scanner
Option 1: From String Table Browser
- Open Tools → KitStack → Lexis → String Table Browser
- Click the Validation tab
- Click Scan Unused Keys
- Wait for the scan to complete (progress bar shows status)
- Review the results
Option 2: From Menu (Quick Access)
- Use Tools → KitStack → Lexis → Scan Unused Keys to run the scan directly
Scan Results
The scanner reports:
- Unused Keys (Warning): Keys defined in tables but not found in code or assets
- Dynamic Key Warnings (Info): Locations where dynamic key lookup is detected
Example Results:
[Warning] Unused key 'ui.old_button' in table 'UI': Old button text
[Warning] Unused key 'menu.deprecated' in table 'Menu': (no default value)
[Info] Dynamic key usage detected at PlayerUI.cs:42. Some keys may not be detected as used.What Gets Scanned
| Source | Patterns Detected |
|---|---|
| C# Code | Localization.Get("key"), new LocalizedString("key"), .Key = "key" |
| Scenes | Serialized LocalizedString fields in components |
| Prefabs | Serialized LocalizedString fields in prefabs |
| ScriptableObjects | Serialized LocalizedString fields in .asset files |
Detection Patterns in Code
The scanner detects these patterns:
// Direct lookups
Localization.Get("ui.title");
Localization.Get("MyTable", "my.key");
// LocalizedString construction
new LocalizedString("button.text");
new LocalizedString("UI", "dialog.title");
// Property assignment
localizedString.Key = "assigned.key";
// Asset lookups
LocalizedAsset<Sprite>.Load("icons.menu");Dynamic Key Detection
When the scanner detects dynamic key usage (keys constructed at runtime), it reports a warning because these keys cannot be statically analyzed:
// This triggers a dynamic key warning
string keyName = "ui." + buttonType;
Localization.Get(keyName); // ⚠️ Dynamic key detectedHandling Dynamic Keys:
- Use exclusion patterns for dynamic key prefixes
- Verify dynamic keys manually
- Consider refactoring to use static keys where possible
Exclusion Patterns
Exclude keys from unused detection using regex patterns. This is useful for:
- Keys used by dynamic lookup systems
- Debug/test keys
- Keys reserved for future use
Common Exclusion Patterns:
^test_.* // Exclude keys starting with "test_"
^debug_.* // Exclude debug keys
.*_placeholder // Exclude placeholder keys
^system\..* // Exclude system keysConfiguration
Configure detection settings programmatically:
using Lexis.Editor.Validation;
var detector = new UnusedKeyDetector();
var settings = new UnusedKeyDetectionSettings
{
ScanCode = true,
ScanScenes = true,
ScanPrefabs = true,
ScanScriptableObjects = true,
ExclusionPatterns = new[] { "^test_.*", "^debug_.*" }
};
var report = detector.ScanProject(localizationSettings, settings);
// Process results
foreach (var unused in report.UnusedKeys)
{
Debug.Log($"Unused: {unused.TableId}/{unused.Key}");
}
// Check statistics
Debug.Log($"Total Keys: {report.TotalKeysScanned}");
Debug.Log($"Unused: {report.UnusedKeyCount}");
Debug.Log($"Files Scanned: {report.FilesScanned}");
Debug.Log($"Duration: {report.ScanDuration.TotalSeconds:F1}s");CI/CD Integration
Run unused key detection from the command line for CI pipelines:
Basic usage:
Unity -batchmode -projectPath /path/to/project \
-executeMethod Lexis.Editor.Validation.UnusedKeyDetectorCI.RunFromCommandLine \
-quitFail build on unused keys:
Unity -batchmode -projectPath /path/to/project \
-executeMethod Lexis.Editor.Validation.UnusedKeyDetectorCI.RunFromCommandLine \
-failOnUnused \
-quitWith custom settings and output:
Unity -batchmode -projectPath /path/to/project \
-executeMethod Lexis.Editor.Validation.UnusedKeyDetectorCI.RunFromCommandLine \
-settingsPath "Assets/Settings/LocalizationSettings.asset" \
-outputFile "reports/unused-keys.json" \
-excludePattern "^test_.*" \
-excludePattern "^debug_.*" \
-quitCI Command Line Arguments:
| Argument | Description |
|---|---|
-settingsPath "path" | Path to LocalizationSettings asset (auto-detected if not specified) |
-failOnUnused | Exit with code 1 if unused keys are found |
-outputFile "path" | Write JSON report to specified file |
-excludePattern "pat" | Regex pattern to exclude (can be repeated) |
-skipScenes | Skip scene file scanning |
-skipPrefabs | Skip prefab file scanning |
-skipScriptableObjects | Skip ScriptableObject scanning |
-skipCode | Skip C# code scanning |
Exit Codes:
0: Success (no unused keys, or unused keys found but-failOnUnusednot set)1: Unused keys found (when-failOnUnusedis set)2: Error (settings not found, exception, etc.)
Programmatic API for Custom CI:
using Lexis.Editor.Validation;
// Find settings automatically
var settings = UnusedKeyDetectorCI.FindLocalizationSettings();
// Run with custom detection settings
var detectionSettings = new UnusedKeyDetectionSettings
{
ExclusionPatterns = new[] { "^test_.*" }
};
var report = UnusedKeyDetectorCI.Run(settings, detectionSettings);
// Process results
if (report.HasUnusedKeys)
{
// Handle unused keys...
}Best Practices
- Run Regularly: Scan for unused keys after major refactoring or feature removal
- Use Exclusion Patterns: Set up patterns for known dynamic key prefixes
- Review Before Deleting: Verify keys aren't used in external systems (server, localization vendors)
- Handle Dynamic Keys: Document dynamic key patterns in comments
- CI Integration: Add unused key detection to your build pipeline with
-failOnUnused
Performance Considerations
| Project Size | Typical Scan Time |
|---|---|
| Small (<100 files) | < 5 seconds |
| Medium (100-1000 files) | 5-30 seconds |
| Large (1000+ files) | 30+ seconds |
For large projects:
- Run scans during development, not on every build
- Use
CodeSearchPathsto limit scanning to specific folders - Disable
ScanScriptableObjectsif not using LocalizedString in SOs
