如何在不使用RESX文件的情况下实现.NET MAUI本地化
不使用RESX,通过Web API实现MAUI Hybrid/Blazor WASM本地化
MAUI Hybrid 实现方案
1. 定义本地化实体与服务接口
先定义存储翻译数据的实体类,以及统一的本地化服务接口:
// 翻译内容实体 public class Translation { public string Key { get; set; } public string Culture { get; set; } public string Value { get; set; } } // 本地化服务接口 public interface ILocalizationService { Task<Dictionary<string, string>> GetTranslationsAsync(string culture); }
2. 实现Web API调用的本地化服务
实现接口,调用后端API获取翻译数据,并加入内存缓存减少重复请求:
public class ApiLocalizationService : ILocalizationService { private readonly HttpClient _httpClient; private readonly Dictionary<string, Dictionary<string, string>> _cache = new(); public ApiLocalizationService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<Dictionary<string, string>> GetTranslationsAsync(string culture) { // 优先从缓存读取 if (_cache.TryGetValue(culture, out var translations)) return translations; // 调用API获取数据 var response = await _httpClient.GetFromJsonAsync<List<Translation>>($"api/localization/{culture}"); if (response == null) return new Dictionary<string, string>(); // 转换为字典并存入缓存 translations = response.ToDictionary(t => t.Key, t => t.Value); _cache[culture] = translations; return translations; } }
3. 注册服务到依赖注入容器
在MauiProgram.cs中注册HttpClient和本地化服务:
builder.Services.AddHttpClient<ILocalizationService, ApiLocalizationService>(client => { client.BaseAddress = new Uri("https://your-api-domain.com/"); });
4. 创建本地化标记扩展(便于XAML调用)
写一个标记扩展类,直接在XAML中绑定翻译内容:
[ContentProperty(nameof(Key))] public class TranslateExtension : IMarkupExtension<BindingBase> { public string Key { get; set; } public BindingBase ProvideValue(IServiceProvider serviceProvider) { var localizationService = serviceProvider.GetService<ILocalizationService>(); var currentCulture = CultureInfo.CurrentUICulture.Name; return new Binding { Source = localizationService.GetTranslationsAsync(currentCulture).Result, Path = $"[{Key}]", Mode = BindingMode.OneWay }; } object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) { return ProvideValue(serviceProvider); } }
在XAML中使用:
<ContentPage xmlns:local="clr-namespace:YourAppNamespace"> <Label Text="{local:Translate WelcomeMessage}" /> </ContentPage>
Blazor WASM 实现方案
1. 复用实体与服务接口
直接使用MAUI部分定义的Translation实体和ILocalizationService接口即可。
2. 实现带缓存的API本地化服务
public class ApiLocalizationService : ILocalizationService { private readonly HttpClient _httpClient; private readonly IMemoryCache _cache; public ApiLocalizationService(HttpClient httpClient, IMemoryCache cache) { _httpClient = httpClient; _cache = cache; } public async Task<Dictionary<string, string>> GetTranslationsAsync(string culture) { var cacheKey = $"translations_{culture}"; if (_cache.TryGetValue(cacheKey, out Dictionary<string, string> translations)) return translations; translations = await _httpClient.GetFromJsonAsync<Dictionary<string, string>>($"api/localization/{culture}") ?? new Dictionary<string, string>(); // 缓存1小时 _cache.Set(cacheKey, translations, TimeSpan.FromHours(1)); return translations; } }
3. 注册服务与自定义IStringLocalizer
为了兼容Blazor原生的本地化注入方式,自定义IStringLocalizer实现:
public class ApiStringLocalizer : IStringLocalizer { private readonly ILocalizationService _localizationService; private readonly string _currentCulture; public ApiStringLocalizer(ILocalizationService localizationService) { _localizationService = localizationService; _currentCulture = CultureInfo.CurrentUICulture.Name; } public LocalizedString this[string name] { get { var translations = _localizationService.GetTranslationsAsync(_currentCulture).Result; var value = translations.TryGetValue(name, out var val) ? val : name; return new LocalizedString(name, value); } } public LocalizedString this[string name, params object[] arguments] { get { var rawValue = this[name].Value; var formatted = string.Format(rawValue, arguments); return new LocalizedString(name, formatted); } } public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures) { var translations = _localizationService.GetTranslationsAsync(_currentCulture).Result; return translations.Select(kv => new LocalizedString(kv.Key, kv.Value)); } public IStringLocalizer WithCulture(CultureInfo culture) { // 可选:实现多文化切换逻辑 return new ApiStringLocalizer(_localizationService); } } // 泛型版本,支持组件级注入 public class ApiStringLocalizer<T> : IStringLocalizer<T> { private readonly IStringLocalizer _localizer; public ApiStringLocalizer(ILocalizationService localizationService) { _localizer = new ApiStringLocalizer(localizationService); } public LocalizedString this[string name] => _localizer[name]; public LocalizedString this[string name, params object[] arguments] => _localizer[name, arguments]; public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures) => _localizer.GetAllStrings(includeParentCultures); public IStringLocalizer WithCulture(CultureInfo culture) => _localizer.WithCulture(culture); }
在Program.cs中注册服务:
builder.Services.AddHttpClient<ILocalizationService, ApiLocalizationService>(client => { client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress); }); builder.Services.AddMemoryCache(); builder.Services.AddSingleton(typeof(IStringLocalizer<>), typeof(ApiStringLocalizer<>));
4. 在Blazor组件中使用
@inject IStringLocalizer<Index> Localizer <h1>@Localizer["WelcomeMessage"]</h1> <p>@Localizer["Greeting", "John"]</p>
内容的提问来源于stack exchange,提问作者kazou
相关产品推荐
相关产品推荐

