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:
- Specific culture — e.g.
en-US→AppResources.en-US.resx - Neutral culture — e.g.
en→AppResources.en.resx - 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.