.NET WPF / BAML · LocBaml alternative
WPF and BAML localization from the compiled build.
Lingobit reads the BAML inside your compiled WPF assemblies, shows a visual preview while you translate, and writes satellite assemblies for each language, on .NET Framework 4.8 and .NET 5–10.
- Input
- Your compiled
.exeand.dllfiles - Output
.resources.dllsatellite assemblies in culture folders- .NET
- Framework 4.8 and .NET 5–10, detected automatically
- Preview
- Compiled BAML from the built application
On this page
LocBaml alternative
Everything LocBaml does, Lingobit does too. On .NET 5–10 as well.
LocBaml is a Microsoft sample for .NET Framework; developers report that it cannot load WPF assemblies built for .NET Core 3.1 and .NET 6. Lingobit does each of its steps on .NET Framework 4.8 and .NET 5–10, and the work LocBaml left to you.
- locbaml /parseReads the BAMLin the
.exeand.dllyou ship, keyed byx:Uid. - CSV in ExcelTranslate with the window in viewor send translators CSV, XLIFF 1.2, or a translator project.
- locbaml /generateSatellites for all languageswith the version of your assembly, signed with your key if needed.
- locbaml.exe in a scriptCommand line toofor your build script. Professional and higher.
What LocBaml left to you: Validation Pseudo-translation Scan for Changes on every build Import of the translations you shipped
Tutorial
Localize a WPF application with Lingobit, step by step.
The steps follow the WPF Localization sample that comes with Localizer: two windows in English, a German translation, and a second version of the application. Use your own build in the same way. If you used LocBaml before, the steps say which LocBaml step they replace.
WPF compiles XAML into BAML; languages ship as satellite assemblies.
When you build a WPF application, every window and page written in XAML is compiled into BAML and stored inside the assembly. Lingobit works on that compiled BAML: it writes the same windows in each language into a satellite assembly, and your code stays where it is.
At startup, WPF picks the language folder.
.NET uses the current UI culture, from Windows or set by your application, and loads the windows from the matching folder next to the application. You copy the folders with the release; nothing is rebuilt.
BAML or RESX: choose by what your build ships.
Most WPF text is in XAML and is compiled into BAML. Text that your XAML takes from .resx files, through {x:Static} bindings, is compiled into the same assembly, and Lingobit translates it there together with the windows. Translate the .resx files themselves only when the translated files must go back into source control.
| Compiled build Recommended | RESX files Alternative | |
|---|---|---|
| Input | .exe, .dll | .resx files from your source |
| What gets translated | Windows (BAML) and the .NET resources in the same assemblies | The strings in the .resx files only |
| Preview | The WPF windows, as they are in the build | None: a list of strings |
| Output | .resources.dll satellite assemblies, ready to ship | Translated .resx files; your build makes the satellites |
| Use when | You ship the compiled application; this is most WPF projects | Translated .resx files must stay in source control |
Moving from LocBaml.
Keep what worked in the LocBaml approach, x:Uid keys and satellite assemblies, and stop parsing and merging CSV files.
With LocBaml, for each assembly and language
msbuild -t:updateuid MyApp.csproj
msbuild MyApp.csproj
LocBaml.exe /parse MyApp.resources.dll /out:MyApp.csv
rem translate MyApp.csv in Excel
LocBaml.exe /generate MyApp.resources.dll
/trans:MyApp.de-DE.csv /out:de-DE /cul:de-DE
rem copy, version, and sign the satellite
rem next build: parse again, merge the CSV by hand
With Lingobit, once
- Keep your
x:Uidvalues and keep checking them withupdateuidandcheckuid. - Create a project from the current build with the same target languages; on .NET 5–10, add
MyApp.dll. No<UICulture>needed. - Import the translations you shipped from your existing satellite assemblies with Import Translations from Localized Files. LocBaml's CSV files are not imported.
- Scan for Changes on every next build instead of parsing and merging CSV files again.
Reference
Culture decides which resources load and how text behaves.
If the application does not set a language itself, .NET uses the current UI culture and loads the best match it has: de-AT, then de, then the neutral resources in the main assembly.
- Each window is looked up on its own. A window comes whole from one folder; a window that is missing in
de\opens in the neutral language. - Ship the parent culture. A
de\folder servesde-DE,de-AT, andde-CH; addde-CH\only when Swiss German text differs.
Choose the language in your app instead of relying on fallback.
Many applications let users pick the language. Set the culture yourself, before WPF loads the first window:
- List the languages you ship from the culture folders next to the application.
- Read the saved choice or a command-line switch; fall back to the source language.
- Set
CurrentUICulturebeforeInitializeComponentof the application. - Restart to switch after the user picks another language.
[STAThread]
public static void Main(string[] args)
{
var culture = CultureInfo.GetCultureInfo(LoadSavedLanguage() ?? "en-US");
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
var app = new App();
app.InitializeComponent();
app.Run();
}
The WPF sample does exactly this: its Language menu lists only the cultures whose satellites contain the windows, and --culture de-DE starts it in German.
xml:lang and neutral resources.
xml:lang
Set it in the WPF source when the application needs language-specific text behavior: font fallback, number substitution, spell checking, hyphenation, and text shaping. It is part of the application setup, not of the translation.
Neutral resources
Set UICulture only when the neutral-language BAML should go into a neutral-language satellite assembly; keep NeutralResourcesLanguage and UltimateResourceFallbackLocation aligned with that choice.
Show the settings
Neutral resources in the main assembly
[assembly: NeutralResourcesLanguage(
"en-US",
UltimateResourceFallbackLocation.MainAssembly)]Neutral resources in a satellite assembly
<PropertyGroup>
<UICulture>en-US</UICulture>
</PropertyGroup>
[assembly: NeutralResourcesLanguage(
"en-US",
UltimateResourceFallbackLocation.Satellite)]<Window x:Class="MyApp.MainWindow" xml:lang="de-DE">
Do and don't.
Do
- Localize the build you release, every time from the current files.
- Keep
x:Uidvalues stable between versions. - Pseudo-translate and run the build before translators start.
- Look at long translations in the preview.
- Ship the parent culture folder, such as
de\.
Don't
- Regenerate UIDs after localization has started.
- Give windows fixed widths that only fit English.
- Build UI text in code from pieces of strings.
- Mix the two neutral-resource layouts in one project.
- Set the culture after the first window is created.
Typical localizability problems in WPF applications.
Problems in the code that translation cannot fix, how each shows up in the localized build, and how to find it before translators start. The general checklist is in Software internationalization; the test build in Pseudo-localization.
| Problem | How it shows | Find and fix |
|---|---|---|
Elements have no x:Uid | Translations cannot be matched to the next version | Run msbuild /t:updateuid once, check with /t:checkuid, and keep the values stable |
| Text is set in code-behind or a view model | It stays in English: it is not in the BAML | Move it into .resx; Lingobit Extractor finds hard-coded C# strings |
| Sentences are built from pieces | Word order is wrong in other languages | Use one resource with placeholders and string.Format; Validation reports placeholders that do not match the source |
| Widths are fixed | German text is clipped in buttons and grid columns | Use Auto and star sizes; pseudo-translate with longer text and check the windows in the preview |
| Dates in bindings use US formats | StringFormat ignores the user's culture | Set FrameworkElement.Language; see Change the language at runtime |
Troubleshooting.
| Symptom | Likely cause | What to do |
|---|---|---|
| The application stays in English | The satellite is not in a culture folder next to the assembly, or the UI culture has no matching folder | Copy the folders with the release; ship the parent culture; set the culture before the first window |
| One window stays in English | The window comes from another assembly of the application | Add that DLL to the project and create its satellite too |
| Some strings stay in English | They are written in C# code, not in XAML or resources | Move them into .resx, by hand or with Extractor |
| Translations are New again after an update | x:Uid values were renamed or regenerated | Keep UIDs stable; import translations from your previous satellites |
| The preview does not open a window | An assembly the window needs is missing | Keep the dependencies next to the assembly you add; translate in the table meanwhile |
| A .NET Framework 4.8 application ignores the satellites | The main assembly is strong-named, and the satellites are not signed | Sign the satellites with your key in the project |
| Creating .NET 5–10 satellites fails | The .NET SDK of that version is not installed | Install it, or allow a newer SDK in the project |
| The localized build crashes | A translation breaks a format string or resource | Run Validation; use Crash Finder (Enterprise) |
| The application is on .NET 1.x–3.5 | Localizer 10 supports .NET Framework 4.8 and .NET 5–10 | Use Localizer 9 |
The WPF Localization sample.
Localizer installs a WPF sample with its project, so you can try every step above without your own build.
- Two windows: the main window with Print Settings, Profiles, and Resources tabs, and Export Options.
- English source, a German translation, and a Language menu that restarts the application.
- Two deliberate defects: a German caption too long for its column, to spot in the preview, and a broken format string.
- Version 2 of the application to try Scan for Changes.
More about WPF localization.
RESX-based WPF localization
Some WPF applications bind UI text to RESX resources rather than relying on BAML. Use this path when translated .resx files must stay in source control and be compiled by the normal Visual Studio, MSBuild, or CI process.
Input: Resources.resx Strings.resx ValidationMessages.resx
Output: Resources.de.resx Strings.de.resx ValidationMessages.de.resx
- Translated resource files stay in the source and build workflow, and developers review the changes in source control.
- Localization stays tied to compilation: Visual Studio, MSBuild, or CI builds the satellite assemblies.
- Visual context is weaker than in the BAML / binary workflow.
Reuse existing WPF translations
If previous WPF translations exist, start from the current original build, choose the target languages, and import the translations that still match from:
- existing
.resources.dllsatellite assemblies; - previous localized WPF binaries;
- localized
.resxfiles.
What to check in the pseudo-localized WPF build
- BAML resources are extracted, and
x:Uidvalues are present and stable. - Longer text still fits; wrapping and automatic layout behave correctly.
FlowDirectionand font fallback are acceptable for the target languages.- No hardcoded strings were missed, and the application does not crash. If it does, Crash Finder (Enterprise) isolates the resource or translation that causes it.
WPF localization FAQ
Does LocBaml work with .NET 8?
LocBaml is a Microsoft sample that targets .NET Framework. Developers report that it cannot load WPF assemblies built for .NET Core 3.1 and .NET 6. Lingobit reads the BAML in WPF builds on .NET Framework 4.8 and .NET 5–10, including .NET 8.
Do I still need x:Uid?
Yes. Lingobit matches translations to the x:Uid keys in every next version. Add them with msbuild /t:updateuid, check them with msbuild /t:checkuid, and do not regenerate them after localization starts.
Can I keep the translations I made with LocBaml?
Yes, through the satellite assemblies you built: Import Translations from Localized Files takes the translations from existing satellites where they still match the current build. Lingobit does not import LocBaml's CSV files.
Do I need a neutral-language satellite and UICulture, as with LocBaml?
No. Lingobit reads the BAML from the assemblies you ship, including the main assembly. Set UICulture only when you want the neutral-language resources in a satellite; see xml:lang and neutral resources.
Can I change a translation without rebuilding the WPF application?
Yes, when you localize the compiled build. Lingobit writes de\MyApp.resources.dll from the assemblies you ship: correct the translation in the project, run Create Localized Files again, and replace the satellite. The main assembly stays as it is. Create the satellite from the same build you ship, so its version matches the main assembly. Translated .resx files, by contrast, need your build to compile them again.
How do I run msbuild /t:updateuid for all projects in a solution?
Run it for each project that has XAML: msbuild MyApp.csproj /t:updateuid. In an SDK project with several target frameworks (<TargetFrameworks>), the target is only found for one framework at a time, so name it: /p:TargetFramework=net8.0-windows. The UIDs go into the XAML files and serve every framework. Check them with /t:checkuid before localization starts.
Why does ResourceManager.GetString return only English?
.NET found no satellite for the current UI culture: the culture folder is not next to the assembly, its name does not match the culture, or the culture was set after the first resources were read. Go through Satellite assembly not loading.
Related paths
- What is BAML? — The compiled form of XAML and where it lives in the build.
- Change the language at runtime — Restart or recreate the windows; dates in bindings.
- .NET WinForms — Visual form editor and binary localization of WinForms assemblies.
- .NET satellite assemblies — Folder layout, names, and fallback of the satellites WPF loads.
- Satellite assembly not loading — A checklist when the application stays in English.
- .NET Resources — RESX files, shared resource libraries, and compiled .NET resources.
- Extractor — Move hardcoded C# strings into resources.
- Localization QA — Validation, pseudo-translation, and Crash Finder.