.NET WPF / BAML
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
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.
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 |
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.
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.
BAML / binary localization instead of LocBaml
BAML / binary localization works from the compiled application: localizable WPF UI is extracted from BAML resources, translated, validated, and written into standard .resources.dll satellite assemblies. Translators stay outside the source tree, and there is no manual LocBaml-style export and import.
If your project supports the standard WPF UID targets, add and check x:Uid values with them:
msbuild /t:updateuid MyProject.csproj
msbuild /t:checkuid MyProject.csproj
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.
Related paths
- .NET WinForms — Visual form editor and binary localization of WinForms assemblies.
- .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.