.NET Resources

.NET resource localization from .resx files.

Translate the .resx files in your source, with forms in the form editor, check them, and write Form1.de.resx next to each file. Your build compiles the translated files into satellite assemblies, as before.

Shipping a compiled build? Translate it directly

Your source RESX Form1.resx Lingobit Localizer Harbor Supply 12 New Order Neue Bestellung Customer: Kunde: Quantity: Menge: Create Cancel Erstellen Abbrechen The form from its .resx file, translated in the form editor You get RESX Form1.resx DEForm1.de.resx FRForm1.fr.resx JAForm1.ja.resx A translated .resx file for each language; your build does the rest Your source RESX Form1.resx Translate in LingobitForm editor · Safe Harbor Supply 12 New Order Neue Bestellung Customer: Kunde: Quantity: Menge: Create Cancel Erstellen Abbrechen You get RESX Form1.resx source DEde.resx FRfr.resx JAja.resx
Input
.resx files from your source; also .resw and .resources
Output
Form1.de.resx next to each source file
Runtime
Your build makes satellites; .NET loads them by UI culture
Preview
Forms in the form editor (Safe); strings in the table
On this page

Tutorial

Localize .NET resource files, step by step.

The RESX workflow: translated .resx files go back to your source, and your build makes the satellites.

Text in code C# Show("File saved."); Stays in English in every language Extractor Text in resources C# Show(Strings.FileSaved); RESX Strings.resx FileSavedFile saved. DE Datei gespeichert. Translated with the windows Text in code stays in English C# Show("File saved."); Extractor Text in resources C# Show(Strings.FileSaved); RESX Strings.resx FileSavedFile saved. DE Datei gespeichert. Translated with the windows
  1. Text in code C# Show("File saved."); Stays in English in every language Extractor Text in resources C# Show(Strings.FileSaved); RESX Strings.resx FileSavedFile saved. DE Datei gespeichert. Translated with the windows Text in code stays in English C# Show("File saved."); Extractor Text in resources C# Show(Strings.FileSaved); RESX Strings.resx FileSavedFile saved. DE Datei gespeichert. Translated with the windows

Your source RESX Form1.resx Project DE FR JA LOC MyApp.loc Form1.resxform New Order Customer: Strings.resxstrings ExportSummaryFormat FileSaved Writes Form1.de.resx RESX Your source RESX Form1.resx Project DE FR JA LOC MyApp.loc Form1.resxform New Order Customer: Strings.resxstrings ExportSummaryFormat FileSaved Writes Form1.de.resx RESX
  1. Your source RESX Form1.resx Project DE FR JA LOC MyApp.loc Form1.resxform New Order Customer: Strings.resxstrings ExportSummaryFormat FileSaved Writes Form1.de.resx RESX Your source RESX Form1.resx Project DE FR JA LOC MyApp.loc Form1.resxform New Order Customer: Strings.resxstrings ExportSummaryFormat FileSaved Writes Form1.de.resx RESX

Project MyApp.loc Form1.resx Strings.resx Errors.resx Harbor Supply Quantity: 12 Create Cancel New Order Neue Bestellung Customer: Kunde: SourceGerman New Order Neue Bestellung Customer: Kunde: Project MyApp.loc Form1.resx Strings.resx Harbor Supply Quantity: 12 Create Cancel New Order Neue Bestellung Customer: Kunde: SourceGerman New Order Neue Bestellung Customer: Kunde:
ProjectDEFRJAMyApp.locForm1.resxNew OrderStrings.resx PrepareTranslationTaskImportTranslationResults TranslatorDENew OrderNeue BestellungCustomer:Kunde:CreateErstellenSourceGermanNew OrderNeue BestellungCustomer:Kunde:Quantity:Menge:Validation on save Or their CAT toolXLIFF 1.2for the tool the translatoralready uses ProjectDEFRJAMyApp.locForm1.resxNew OrderStrings.resx PrepareTranslation Task TranslatorDENew OrderNeue BestellungCustomer:Kunde:CreateErstellenSourceGermanNew OrderNeue BestellungCustomer:Kunde:Quantity:Menge:Validation on save Or their CAT toolXLIFF 1.2for the tool the translatoralready uses ImportResults
Project Auto Translate Using Harbor Supply 12 New Order Neue Bestellung Customer: Kunde: Quantity: Menge: Ship today Noch heute versenden Create Cancel Erstellen Abbrechen DeepL… Google Translate… Azure Translator… Translation Memory… Terminology… Pseudo Translate… Project Auto Translate Using Harbor Supply 12 New Order Neue Bestellung Customer: Kunde: Quantity: Menge: Ship today Noch heute versenden Create Cancel Erstellen Abbrechen DeepL… Google Translate… Azure Translator… Translation Memory… Terminology… Pseudo Translate…
  1. Project MyApp.loc Form1.resx Strings.resx Errors.resx Harbor Supply Quantity: 12 Create Cancel New Order Neue Bestellung Customer: Kunde: SourceGerman New Order Neue Bestellung Customer: Kunde: Project MyApp.loc Form1.resx Strings.resx Harbor Supply Quantity: 12 Create Cancel New Order Neue Bestellung Customer: Kunde: SourceGerman New Order Neue Bestellung Customer: Kunde:
  2. ProjectDEFRJAMyApp.locForm1.resxNew OrderStrings.resx PrepareTranslationTaskImportTranslationResults TranslatorDENew OrderNeue BestellungCustomer:Kunde:CreateErstellenSourceGermanNew OrderNeue BestellungCustomer:Kunde:Quantity:Menge:Validation on save Or their CAT toolXLIFF 1.2for the tool the translatoralready uses ProjectDEFRJAMyApp.locForm1.resxNew OrderStrings.resx PrepareTranslation Task TranslatorDENew OrderNeue BestellungCustomer:Kunde:CreateErstellenSourceGermanNew OrderNeue BestellungCustomer:Kunde:Quantity:Menge:Validation on save Or their CAT toolXLIFF 1.2for the tool the translatoralready uses ImportResults
  3. Project Auto Translate Using Harbor Supply 12 New Order Neue Bestellung Customer: Kunde: Quantity: Menge: Ship today Noch heute versenden Create Cancel Erstellen Abbrechen DeepL… Google Translate… Azure Translator… Translation Memory… Terminology… Pseudo Translate… Project Auto Translate Using Harbor Supply 12 New Order Neue Bestellung Customer: Kunde: Quantity: Menge: Ship today Noch heute versenden Create Cancel Erstellen Abbrechen DeepL… Google Translate… Azure Translator… Translation Memory… Terminology… Pseudo Translate…

Output · Validation C# Format String: inconsistent arguments ExportSummaryFormat Fixed Resource ExportSummaryFormat Source Export {0} pages to {1}. Export %d pages to %s. Export <b>all</b> pages. Export %1 pages to %2. German {0} Seiten nach {2} exportieren. %d Seiten nach %d exportieren. <b>Alle</i> Seiten exportieren. %1 Seiten nach %3 exportieren. {0} Seiten nach {1} exportieren. %d Seiten nach %s exportieren. <b>Alle</b> Seiten exportieren. %1 Seiten nach %2 exportieren. Output · Validation C# Format String: inconsistent arguments ExportSummaryFormat Fixed ExportSummaryFormat Source Export {0} pages to {1}. Export %d pages to %s. Export <b>all</b> pages. Export %1 pages to %2. German {0} Seiten nach {2} exportieren. %d Seiten nach %d exportieren. <b>Alle</i> Seiten exportieren. %1 Seiten nach %3 exportieren. {0} Seiten nach {1} exportieren. %d Seiten nach %s exportieren. <b>Alle</b> Seiten exportieren. %1 Seiten nach %2 exportieren.
  1. Output · Validation C# Format String: inconsistent arguments ExportSummaryFormat Fixed Resource ExportSummaryFormat Source Export {0} pages to {1}. Export %d pages to %s. Export <b>all</b> pages. Export %1 pages to %2. German {0} Seiten nach {2} exportieren. %d Seiten nach %d exportieren. <b>Alle</i> Seiten exportieren. %1 Seiten nach %3 exportieren. {0} Seiten nach {1} exportieren. %d Seiten nach %s exportieren. <b>Alle</b> Seiten exportieren. %1 Seiten nach %2 exportieren. Output · Validation C# Format String: inconsistent arguments ExportSummaryFormat Fixed ExportSummaryFormat Source Export {0} pages to {1}. Export %d pages to %s. Export <b>all</b> pages. Export %1 pages to %2. German {0} Seiten nach {2} exportieren. %d Seiten nach %d exportieren. <b>Alle</i> Seiten exportieren. %1 Seiten nach %3 exportieren. {0} Seiten nach {1} exportieren. %d Seiten nach %s exportieren. <b>Alle</b> Seiten exportieren. %1 Seiten nach %2 exportieren.

Your source RESX Strings.resx Lingobit Localizer Project SourceGerman New Order Neue Bestellung Customer: Kunde: Quantity: Menge: Each string, translated in the project You get Strings.resx Strings.de.resx Strings.fr.resx Strings.ja.resx A translated file for each language; your build does the rest Your source RESX Strings.resx Translate in Lingobit Project SourceGerman New Order Neue Bestellung Customer: Kunde: Quantity: Menge: You get Strings.resx source Strings.de.resx Strings.fr.resx Strings.ja.resx
  1. Your source RESX Strings.resx Lingobit Localizer Project SourceGerman New Order Neue Bestellung Customer: Kunde: Quantity: Menge: Each string, translated in the project You get Strings.resx Strings.de.resx Strings.fr.resx Strings.ja.resx A translated file for each language; your build does the rest Your source RESX Strings.resx Translate in Lingobit Project SourceGerman New Order Neue Bestellung Customer: Kunde: Quantity: Menge: You get Strings.resx source Strings.de.resx Strings.fr.resx Strings.ja.resx

Form1.resx 1.0 1.1 New Order Customer: Client: Harbor Supply Quantity: 12 Ship today Gift wrap Create Cancel Project Scan for Changes Neue Bestellung Kunde: Updated Harbor Supply Menge: 12 Noch heute versenden Removed Gift wrap New Erstellen Abbrechen Rows are matched by resource name: Client keeps the translation of Customer. Form1.resx 1.0 1.1 New Order Customer: Client: Harbor Supply Quantity: 12 Ship today Gift wrap Create Cancel Project Scan for Changes Neue Bestellung Kunde: Updated Harbor Supply Menge: 12 Noch heute versenden Removed Gift wrap New Erstellen Abbrechen Rows are matched by resource name.
Translated earlier MyApp.exe de\ DE Form1.resx fr\ FR Form1.resx Project Not Translated Imported DE FR MyApp.exe Form1.resx Strings.resx Import from Localized Files Translated with another tool or long ago? Add your build: Lingobit finds the localized files and offers to import them. Import Translations from Localized Files GermanForm1.de.resx FrenchForm1.fr.resx OK Cancel OK Translated earlier MyApp.exe de\ DE Form1.resx fr\ FR Form1.resx Project Not Translated Imported DE FR MyApp.exe Form1.resx Strings.resx Import from Localized Files Translated with another tool or long ago? Add your build: Lingobit offers the import. Import Translations from Localized Files GermanForm1.de.resx FrenchForm1.fr.resx OK Cancel OK
  1. Form1.resx 1.0 1.1 New Order Customer: Client: Harbor Supply Quantity: 12 Ship today Gift wrap Create Cancel Project Scan for Changes Neue Bestellung Kunde: Updated Harbor Supply Menge: 12 Noch heute versenden Removed Gift wrap New Erstellen Abbrechen Rows are matched by resource name: Client keeps the translation of Customer. Form1.resx 1.0 1.1 New Order Customer: Client: Harbor Supply Quantity: 12 Ship today Gift wrap Create Cancel Project Scan for Changes Neue Bestellung Kunde: Updated Harbor Supply Menge: 12 Noch heute versenden Removed Gift wrap New Erstellen Abbrechen Rows are matched by resource name.
  2. Translated earlier MyApp.exe de\ DE Form1.resx fr\ FR Form1.resx Project Not Translated Imported DE FR MyApp.exe Form1.resx Strings.resx Import from Localized Files Translated with another tool or long ago? Add your build: Lingobit finds the localized files and offers to import them. Import Translations from Localized Files GermanForm1.de.resx FrenchForm1.fr.resx OK Cancel OK Translated earlier MyApp.exe de\ DE Form1.resx fr\ FR Form1.resx Project Not Translated Imported DE FR MyApp.exe Form1.resx Strings.resx Import from Localized Files Translated with another tool or long ago? Add your build: Lingobit offers the import. Import Translations from Localized Files GermanForm1.de.resx FrenchForm1.fr.resx OK Cancel OK

Lingobit translates the .resx files; your build makes the satellites.

Lingobit reads each .resx file of your project and writes a translated copy next to it: Strings.de.resx, Strings.fr.resx. Visual Studio or MSBuild compiles them into satellite assemblies in culture folders, and at startup .NET loads the resources of the current UI culture.

At startup UI culture de-DE from Windows or set by the app Release folder EXE MyApp.exe DE de\ loaded FR fr\ JA ja\ The window Neue Bestellung Kunde: Menge: Erstellen in German At startup UI culture de-DE Windows or app EXE MyApp.exe DEde\ FRfr\ JAja\ Neue Bestellung Kunde: Erstellen Menge:

Lingobit does

  • Translates strings and form properties in your .resx files, and shows forms in the form editor.
  • Reuses earlier translations and the translation memory.
  • Checks placeholders such as {0}, hotkeys, empty and too long translations, and more.
  • Writes Form1.de.resx and the other languages next to each source file.

Your project keeps

  • The .resx files in source control, with the translated ones.
  • The build that compiles satellite assemblies.
  • Loading the resources and choosing the language.
  • The final test in the running application.

RESX files or the compiled build: choose by what you keep.

Translate the .resx files when the translated files must live in source control. When you only ship the build, translating the compiled assemblies gives the full form preview and needs no rebuild.

The RESX workflow and the compiled-build workflow
RESX filesCompiled build
Input.resx files from your source.exe, .dll
PreviewForms in the Safe editor; strings in the tableForms in the Full editor, or Safe
OutputTranslated .resx files; your build makes the satellites.resources.dll satellites, ready to ship
Use whenTranslated files stay in source control and go through your buildYou ship the compiled application

Reference

Culture decides which resources load.

.NET takes each resource from the best match it has for the current UI culture: de-AT, then de, then the neutral resources in the main assembly.

UI culture de-DE: each string is looked up on its own de-DE\not shippedde\neutralMyApp.exeCustomer:—Kunde:Customer:Quantity:—Menge:Quantity:Cancel—missingCancel Neue BestellungKunde:Menge:Cancel Cancel is missing in de\,so it comes from the neutralresources; the rest is German Each string on its own de-DE\not shippedde\neutralMyApp.exeCustomer:—Kunde:Customer:Quantity:—Menge:Quantity:Cancel—missingCancel Neue BestellungKunde:Menge:Cancel
  • A missing string shows the neutral text from Strings.resx; it does not break the application.
  • Translate to the parent culture. Strings.de.resx serves de-DE, de-AT, and de-CH. Lingobit names the file after the project language: German writes Strings.de.resx, German (Germany) writes Strings.de-DE.resx, which serves only de-DE.
// Strings.resx generates a class; the property reads the current UI culture
label.Text = Strings.ExportSummary;

// or through ResourceManager
var rm = new ResourceManager("MyApp.Strings", typeof(Program).Assembly);
string text = rm.GetString("ExportSummary");

Choose the language in your app.

Set the culture before the first resource is read; otherwise .NET uses the Windows language:

var culture = CultureInfo.GetCultureInfo(LoadSavedLanguage() ?? "en-US");
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

Do and don't.

Do

  • Keep UI text in .resx; move hard-coded C# and VB strings with Lingobit Extractor.
  • Keep resource names stable: translations are matched to them.
  • Set Localizable = true on forms, so their text is in the form's .resx.
  • Commit the translated .resx files and let your build make the satellites.

Don't

  • Edit Form1.de.resx by hand: the next Create overwrites it.
  • Rename resources after translation has started without a reason.
  • Build messages in code from translated pieces.
  • Send .resx files to translators: they work in Lingobit.

Troubleshooting.

Symptoms, causes, and what to do
SymptomLikely causeWhat to do
The application stays in EnglishThe translated .resx files are not in the project, so no satellite was built, or the UI culture has no matchInclude the files in the project, rebuild, and check the culture folders next to the application
A form has no text to translateIts Localizable property is false, so the text is in codeSet Localizable = true in the designer and run Scan for Changes
Translations are New again after an updateResources were renamedKeep names stable; import translations from your existing translated .resx files
The application crashes with one languageA translation breaks a placeholder such as {0}Run Validation: it reports placeholders that do not match the source

The ASP.NET ResX sample.

Localizer installs an ASP.NET Web Forms sample whose text is in .resx files.

  • Pages, a master page, and a user control with their resources in App_LocalResources.
  • Global resources in Properties\Resources.resx, translated in the same project.

More about .NET resource localization.

Why teams keep the RESX source/build workflow
Input:  Resources.resx  ValidationMessages.resx  SharedResources.resx
Output: Resources.de.resx  ValidationMessages.de.resx  SharedResources.de.resx
  • Translations stay in source control, and developers review resource changes as normal source changes.
  • Visual Studio, MSBuild, or CI stays responsible for the final satellite assemblies.
  • Several projects can share the same RESX resources.
  • The trade-off: localization stays tied to development.
Compiled .resources files and satellite assemblies

During the build, RESX files are compiled into binary resources: the neutral resources go into the main assembly, the localized ones into .resources.dll satellite assemblies in culture folders such as de\, fr\, or ja\. At runtime, ResourceManager selects resources by CurrentUICulture.

Compiled .resources files are usually intermediate build artifacts. They appear in some workflows, but standard .NET deployment uses satellite assemblies.

Hardcoded C# strings to review with Extractor

Not every user-visible message starts in a RESX file. Lingobit Extractor finds hardcoded C# strings and moves them into RESX resources. Review in particular:

  • validation and error messages shown to users;
  • command output, status messages, and labels or captions created in code;
  • emails, notifications, and reports.
ASP.NET Core and Blazor

Resources that IStringLocalizer reads in ASP.NET Core and Blazor are ordinary .resx files, such as Resources\Messages.resx: Lingobit writes Messages.de.resx next to the source, and the app shows the German text. The visual form editor is for Windows Forms forms only; these files are translated as strings in the table. Text written inside .cshtml and .razor markup is not translated: move it into .resx.

Reuse existing .NET translations

Add the current original files, choose the target languages, and import the translations that still match from existing .resources.dll satellite assemblies, localized .resx files, or previous localized builds.