
Maui Localization
- 34 installs
- 163 repo stars
- Updated July 6, 2026
- davidortinau/maui-skills
Localizes .NET MAUI apps with multi-language support via .resx files, culture resolution, runtime switching, and RTL layout.
About
Guides localizing .NET MAUI apps with .resx resource files, culture resolution and runtime switching, RTL layout and platform language declarations. A developer uses it when adding multi-language support to a MAUI app.
- Multi-language support via .resx files with runtime switching
- RTL layout and platform language declarations
Maui Localization by the numbers
- 34 all-time installs (skills.sh)
- Ranked #650 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/davidortinau/maui-skills --skill maui-localizationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 34 |
|---|---|
| repo stars | ★ 163 |
| Last updated | July 6, 2026 |
| Repository | davidortinau/maui-skills ↗ |
What it does
Localizes .NET MAUI apps with multi-language support via .resx files, culture resolution, runtime switching, and RTL layout.
Files
.NET MAUI Localization
Common gotchas
| Issue | Fix |
|---|---|
ResourceManager returns null for default culture | Set <NeutralLanguage>en-US</NeutralLanguage> in .csproj |
| iOS ignores culture overrides | CFBundleLocalizations missing from Info.plist |
| Windows doesn't show correct language | <Resource Language="..." /> missing from Package.appxmanifest |
x:Static bindings don't update on language switch | x:Static is one-time — use binding approach with INotifyPropertyChanged |
.Designer.cs not regenerating in VS Code | Add <CoreCompileDependsOn>PrepareResources;$(CoreCompileDependsOn)</CoreCompileDependsOn> and run dotnet build |
⚠️ NeutralLanguage is mandatory
<!-- ✅ Always set in .csproj -->
<PropertyGroup>
<NeutralLanguage>en-US</NeutralLanguage>
</PropertyGroup>
<!-- ❌ Missing this causes ResourceManager to return null at runtime -->Platform declarations — don't forget these
iOS / Mac Catalyst
⚠️ Without this, iOS won't offer your app's languages in system Settings:
<!-- Platforms/iOS/Info.plist AND Platforms/MacCatalyst/Info.plist -->
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>es</string>
<string>fr</string>
</array>Windows
<!-- Platforms/Windows/Package.appxmanifest -->
<Resources>
<Resource Language="en-US" />
<Resource Language="es" />
<Resource Language="fr-FR" />
</Resources>Android
Android picks up .resx-based localization automatically. No additional manifest entries required. ✅
Runtime language switching — x:Static trap
<!-- ❌ Won't update when language changes at runtime -->
<Label Text="{x:Static resx:AppResources.WelcomeMessage}" />
<!-- ✅ Updates dynamically via INotifyPropertyChanged -->
<Label Text="{Binding [WelcomeMessage], Source={x:Static local:LocalizationResourceManager.Instance}}" />When switching culture, set all three properties or formatting is inconsistent:
// ✅ Complete culture switch
var culture = new CultureInfo("es");
CultureInfo.CurrentUICulture = culture; // resource lookup
CultureInfo.CurrentCulture = culture; // dates/numbers
AppResources.Culture = culture; // ResourceManager
// ❌ Only sets UI culture — dates/numbers stay in old culture
CultureInfo.CurrentUICulture = new CultureInfo("es");RTL layout — set FlowDirection at page level
<!-- ✅ Page-level — children inherit -->
<ContentPage FlowDirection="RightToLeft">
<StackLayout FlowDirection="MatchParent" />
</ContentPage>
<!-- ❌ Only on child — parent still LTR, layout breaks -->
<ContentPage>
<StackLayout FlowDirection="RightToLeft" />
</ContentPage>VS Code pitfall
⚠️ .Designer.cs may not regenerate on save. Add to .csproj and run dotnet build after .resx changes:
<CoreCompileDependsOn>PrepareResources;$(CoreCompileDependsOn)</CoreCompileDependsOn>Decision framework
| Need | Approach |
|---|---|
| Static multilingual strings | .resx files with x:Static bindings |
| Runtime language switching | LocalizationResourceManager with INotifyPropertyChanged bindings |
| Culture-specific images | Name images banner_{culture}.png or store paths in .resx |
| RTL support | Set FlowDirection at page level, detect with TextInfo.IsRightToLeft |
| Date/number formatting | Set CultureInfo.CurrentCulture alongside CurrentUICulture |
Quick checklist
- [ ]
NeutralLanguageset in.csproj - [ ] Default
AppResources.resxcontains all keys - [ ] Each target language has its own
AppResources.{culture}.resx - [ ] iOS/Mac:
CFBundleLocalizationslists all supported languages - [ ] Windows:
Package.appxmanifestdeclares<Resource Language="..." /> - [ ] RTL cultures set
FlowDirectionat page/app level - [ ] Runtime switching sets all three:
CurrentUICulture,CurrentCulture,AppResources.Culture - [ ]
dotnet buildregenerates.Designer.csafter.resxchanges
Localization API Reference
Resource Files (.resx)
.NET MAUI uses standard .NET resource files for localization. Each .resx file contains name/value string pairs.
File Naming Convention
| File | Purpose |
|---|---|
AppResources.resx | Default (fallback) language |
AppResources.es.resx | Spanish (neutral) |
AppResources.fr-FR.resx | French – France (specific) |
AppResources.zh-Hans.resx | Chinese Simplified |
Place resource files in a Resources/Strings folder or project root. The naming pattern is {BaseName}.{CultureCode}.resx.
Project Configuration
Set the neutral language in .csproj so the ResourceManager resolves the default culture correctly:
<PropertyGroup>
<NeutralLanguage>en-US</NeutralLanguage>
</PropertyGroup>Generated Accessor Class
The default .resx file auto-generates a strongly-typed class (typically AppResources) with static properties for each string key:
// Auto-generated — do not edit manually
public static string WelcomeMessage => ResourceManager.GetString("WelcomeMessage", resourceCulture);Access strings in C#: string welcome = AppResources.WelcomeMessage;
Culture Resolution Order
The runtime resolves resources in this order:
1. Specific culture — e.g. en-US → AppResources.en-US.resx 2. Neutral culture — e.g. en → AppResources.en.resx 3. Default (fallback) — AppResources.resx
If no match is found at any level, the fallback file is used.
XAML Usage
Using x:Static
<ContentPage xmlns:resx="clr-namespace:MyApp.Resources.Strings">
<Label Text="{x:Static resx:AppResources.WelcomeMessage}" />
</ContentPage>Using a Binding with a Localization Service
For runtime language switching without restarting, expose resource strings through a helper that raises PropertyChanged:
public class LocalizationResourceManager : INotifyPropertyChanged
{
public static LocalizationResourceManager Instance { get; } = new();
public string this[string key] =>
AppResources.ResourceManager.GetString(key, AppResources.Culture)!;
public event PropertyChangedEventHandler? PropertyChanged;
public void SetCulture(CultureInfo culture)
{
AppResources.Culture = culture;
CultureInfo.CurrentUICulture = culture;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
}
}<Label Text="{Binding [WelcomeMessage], Source={x:Static local:LocalizationResourceManager.Instance}}" />Runtime Culture Switching
Change the UI culture at runtime:
var culture = new CultureInfo("es");
CultureInfo.CurrentUICulture = culture;
CultureInfo.CurrentCulture = culture; // for dates/numbers
AppResources.Culture = culture;Platform Declarations
iOS and Mac Catalyst
Add supported localizations to Platforms/iOS/Info.plist (and Platforms/MacCatalyst/Info.plist):
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>es</string>
<string>fr</string>
</array>Windows
Declare supported languages in Platforms/Windows/Package.appxmanifest:
<Resources>
<Resource Language="en-US" />
<Resource Language="es" />
<Resource Language="fr-FR" />
</Resources>Android
Android picks up .resx-based localization automatically. No additional manifest entries are required.
RTL Layout Support
Set FlowDirection to support right-to-left languages (Arabic, Hebrew, etc.):
<!-- App-wide -->
<Application FlowDirection="RightToLeft" />
<!-- Per-page or per-element -->
<ContentPage FlowDirection="RightToLeft">
<StackLayout FlowDirection="MatchParent">
<Label Text="{x:Static resx:AppResources.Greeting}" />
</StackLayout>
</ContentPage>Detect and apply at runtime:
bool isRtl = CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft;
FlowDirection = isRtl ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;Image Localization
For culture-specific images, use a naming or folder convention and select at runtime:
string cultureSuffix = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
string imageName = $"banner_{cultureSuffix}.png";
bannerImage.Source = ImageSource.FromFile(
FileSystem.AppPackageFileExistsAsync(imageName).Result ? imageName : "banner.png");Alternatively, reference image paths in .resx files so each culture points to its own asset.
VS Code Setup
When using VS Code (not Visual Studio), the auto-generated .Designer.cs file for .resx may not regenerate on save. Ensure DesignTimeBuild is enabled:
<PropertyGroup>
<CoreCompileDependsOn>PrepareResources;$(CoreCompileDependsOn)</CoreCompileDependsOn>
</PropertyGroup>Run dotnet build after adding or modifying .resx entries to regenerate the accessor class.