A modern Fluent-design editor for translation files. Supports both .ini and flat .json localization files used by a wide variety of Windows applications.
- Fluent / Win11 native look — Mica backdrop, rounded corners, runtime dark/light toggle
- Poedit-style edit panel — browse rows in a read-only grid up top, edit the selected translation in a roomy multi-line panel below with a draggable splitter; advance with Ctrl+↓
- Side-by-side source and target with English on the left and translation on the right
- Severity-colored row markers with a toolbar legend popup
- Live search across keys, English, and translations (Ctrl+F)
- Missing-only filter and Potential-issues-only filter — focus on what needs attention
- Next-missing jump (Ctrl+G) — scrolls into view
- Click any English cell to copy the source text to the clipboard — handy when pasting into a browser translator, dictionary, or AI chat
- Syntax-highlighted header editor — edit the file's comment header with placeholder support (
$author,$email,$timestamp,$app_version) - Auto-save with debounced atomic writes — no half-written files on crash
- Session restore — reopens your last source + target file pair on launch
- Per-Monitor DPI v2 awareness — sharp on any display
.ini— UTF-16 LE BOM format with sections (as used by many older Windows apps). Byte-exact preservation of comments, blank lines, key order, whitespace, and encoding..json— flat key/value localization files. Preserves key order, indentation, and non-string values (arrays, numbers) byte-clean on round-trip.
- Stale-translation detection — when the source English changes between releases, affected translations get flagged with a tooltip showing the previous English. Powered by a sidecar
.tracking.jsonthat snapshots English-per-key on every save. - Placeholder validation — warns when
%s,%d,{0},&File,<b>tags, escape sequences, etc. don't match between source and translation. Catches a whole class of crash bugs in the localized app. - Glossary enforcement — define rules like "Clean → Rens" and the editor flags every row where the source contains "Clean" but the translation doesn't contain "Rens". Edit rules in the Glossary window; stored in a sidecar
.glossary.json. - Eleven heuristic checks — untranslated leftovers, length drift, punctuation/whitespace/newline mismatches, bracket and quote balance, HTML/XML tag balance, markdown emphasis, URL preservation, suspicious script mixing, and version/number drift. Each warning carries a severity (Error / Warning / Info) that drives its row marker color.
- Per-category toggles — Settings → Validation lets you switch off individual heuristic categories or silence all heuristics at once with a master switch. Hard validators (placeholders, glossary, stale) always run. Changes apply immediately, including to the Issues-only filter.
Right-click any row to manage its review state. Exactly one mutually-exclusive action is shown depending on the row's current state:
| Row state | Menu action | Effect |
|---|---|---|
| Clean (no flags, no violations) | Mark for review | Adds a yellow marker, counts toward Potential issues |
| Auto-flagged by validators | Dismiss potential issue | Suppresses the marker, drops from the count |
| Already dismissed | Restore potential issue | Brings the auto-validator marker back |
| Manually flagged | Unmark | Clears the manual review flag |
Dismissal and manual-flag state is persisted in a sidecar <name>.ignore.json so it travels with the translation in version control. Reviewers on other machines see the same set of acknowledged or flagged rows.
- Per-file editable header — click Edit header in the editor to view and edit the comment block at the top of the file in a syntax-highlighted code editor (comments green, placeholders cyan, line numbers). The header is loaded straight from the file; there's no global template.
- Placeholders —
$author,$email,$timestamp, and$app_versionare substituted with live values when the file is saved and recovered back to placeholders when reopened, so timestamps stay current rather than baking in. - Per-source app version — record the version of the application being translated; stored in a
<source>.project.jsonsidecar and used by the$app_versionplaceholder.
- Auto-insert missing keys — translating a key that doesn't exist in the target yet inserts it in the correct section
- Run as administrator — if a save fails because the file is in a protected folder, the app offers to relaunch elevated and reopen your files; a Restart-as-administrator button is also in Settings → Workspace
- Sidecar metadata travels with the file in version control:
<name>.glossary.json— per-file glossary rules<name>.tracking.json— per-key English snapshots for stale detection<name>.ignore.json— dismissed issues and manual review flags<source>.project.json— app version for the translated application
| Shortcut | Action |
|---|---|
Ctrl+O |
Open source file |
Ctrl+Shift+O |
Open target file |
Ctrl+S |
Save |
Ctrl+F |
Focus search |
Ctrl+G |
Jump to next missing entry |
| Color | Meaning |
|---|---|
| Red (3px) | Hard error — stale translation, placeholder mismatch, or glossary violation. Hover for details. |
| Yellow (2px) | Soft warning — heuristic detected something worth verifying, or manually flagged for review. |
| Orange (2px) | Translation missing. |
| (none) | Clean. |
Requires the .NET 10 SDK and Windows 10 (1809+) or Windows 11.
dotnet restore
dotnet build
dotnet run --project UniversalTranslatorOr open UniversalTranslator.sln in JetBrains Rider or Visual Studio 2022.
The csproj already includes the publish defaults. Just:
dotnet publish UniversalTranslator -c ReleaseProduces a ~75 MB self-contained .exe at:
UniversalTranslator\bin\Release\net10.0-windows\win-x64\publish\UniversalTranslator.exe
No installer, no .NET runtime required on the target machine. Copy the .exe anywhere and run.
UniversalTranslator.sln
└── UniversalTranslator/ # WPF app
├── App.xaml(.cs) # DI host, theme setup, top-level exception handlers
├── Views/
│ ├── MainWindow.xaml(.cs) # FluentWindow shell, title-bar icon
│ ├── EditorPage.xaml(.cs) # the main editor UI
│ ├── GlossaryWindow.xaml(.cs) # glossary rules editor
│ └── AboutWindow.xaml(.cs) # version + GitHub link
├── ViewModels/
│ ├── MainWindowViewModel.cs
│ ├── EditorViewModel.cs # commands, search, auto-save, validation orchestration
│ └── TranslationEntryViewModel.cs # per-row validation state
├── Models/
│ ├── ITranslationFile.cs # format-agnostic file interface
│ ├── IniFile.cs / IniLine.cs # .ini in-memory model
│ ├── JsonFile.cs # .json in-memory model
│ ├── Glossary.cs # rules + violation matching
│ ├── TranslationTracking.cs # per-key English snapshots for stale detection
│ └── DismissedIssues.cs # dismissed + manually-flagged keys
├── Services/
│ ├── ITranslationFileService.cs # extension-based format dispatcher
│ ├── IniFileService.cs # BOM-aware encoding sniffer, atomic writes
│ ├── JsonFileService.cs # order-preserving reader/writer
│ ├── GlossaryService.cs # sidecar .glossary.json persistence
│ ├── TrackingService.cs # sidecar .tracking.json persistence
│ ├── DismissedIssuesService.cs # sidecar .ignore.json persistence
│ ├── PlaceholderValidator.cs # printf, brace, accelerator, HTML-tag checks
│ ├── HeuristicValidator.cs # length drift, version-number leftovers
│ └── SettingsService.cs # JSON-persisted prefs at %APPDATA%/UniversalTranslator
└── Converters/ # XAML value converters
- MVVM via CommunityToolkit.Mvvm source generators
- DI via Microsoft.Extensions.Hosting
- Format abstraction —
ITranslationFilelets the editor work with any key/value format; adding a new format (XLIFF, .po, .resx) is one new model + one I/O service, no UI changes - Atomic writes everywhere —
.tmp+ rename, crash-safe - Format preservation — every line / property tracked individually so only mutated values change on save
- Sidecar metadata keeps the editor's extra state (glossary, tracking, dismissals) out of the translation file itself, so the underlying tool reads a clean file
GPL-3.0. See LICENSE for full terms.