.Net Core之动态多国语言
我封装了一个开源库DynamicLocalizer,方便集成
- nuget:https://www.nuget.org/packages/DynamicLocalizer/
- github:https://github.com/2kking/DynamicLocalizer
不只是 .Net Core,几乎是所有平台的多国语言都是写死的,但有的时候需要动的多国语言该怎么办呢?这里提供一种方案:.Net Core + EF Core (也就是数据库资源)
-
.Net Core默认的StringLocalizer只支持Resource文件,语言种类是固定的,内容也无法在运行时更改,我们现在的方案是支持数据库,也可以在运行时实时修改内容,并且语言种类都是动态的:
-
动态语言类型:官方的RequestLocalizationMiddleware是要求写死语言类型的,我们这里重写:
public class CustomRequestLocalizationMiddleware { private readonly RequestDelegate _next; private readonly RequestLocalizationOptions _options; /// <summary> /// Creates a new <see cref="RequestLocalizationMiddleware"/>. /// </summary> /// <param name="next">The <see cref="RequestDelegate"/> representing the next middleware in the pipeline.</param> /// <param name="options">The <see cref="RequestLocalizationOptions"/> representing the options for the /// <see cref="CustomRequestLocalizationMiddleware"/>.</param> public CustomRequestLocalizationMiddleware(RequestDelegate next, IOptions<RequestLocalizationOptions> options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } _next = next ?? throw new ArgumentNullException(nameof(next)); _options = options.Value; } /// <summary> /// Invokes the logic of the middleware. /// </summary> /// <param name="context">The <see cref="HttpContext"/>.</param> /// <returns>A <see cref="Task"/> that completes when the middleware has completed processing.</returns> public async Task Invoke(HttpContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var requestCulture = _options.DefaultRequestCulture; IRequestCultureProvider winningProvider = null; if (_options.RequestCultureProviders != null) { foreach (var provider in _options.RequestCultureProviders) { var providerResultCulture = await provider.DetermineProviderCultureResult(context); if (providerResultCulture == null) { continue; } var cultures = providerResultCulture.Cultures; var uiCultures = providerResultCulture.UICultures; CultureInfo cultureInfo = new CultureInfo(cultures.FirstOrDefault().Value); CultureInfo uiCultureInfo = new CultureInfo(uiCultures.FirstOrDefault().Value); if (cultureInfo == null && uiCultureInfo == null) { continue; } if (cultureInfo == null && uiCultureInfo != null) { cultureInfo = _options.DefaultRequestCulture.Culture; } if (cultureInfo != null && uiCultureInfo == null) { uiCultureInfo = _options.DefaultRequestCulture.UICulture; } var result = new RequestCulture(cultureInfo, uiCultureInfo); if (result != null) { requestCulture = result; winningProvider = provider; break; } } } context.Features.Set<IRequestCultureFeature>(new RequestCultureFeature(requestCulture, winningProvider)); SetCurrentThreadCulture(requestCulture); await _next(context); } private static void SetCurrentThreadCulture(RequestCulture requestCulture) { CultureInfo.CurrentCulture = requestCulture.Culture; CultureInfo.CurrentUICulture = requestCulture.UICulture; } }
-
动态数据库资源,我们模仿StringLocalizer,重写一个DbStringLocalizer,并以Singleton注入即可使用:
public class DbStringLocalizer : IDbStringLocalizer { private readonly Func<LocalizationContext> _contextFactory; private ConcurrentDictionary<string, string> _localizations; public DbStringLocalizer(Func<LocalizationContext> contextFactory) { _contextFactory = contextFactory; } public LocalizedString this[string name] { get { var text = GetText(name, out bool notSucceed); return new LocalizedString(name, text, notSucceed); } } public LocalizedString this[string name, params object[] arguments] { get { var text = GetText(name, out bool notSucceed); var value = string.Format(text ?? name, arguments); return new LocalizedString(name, value, notSucceed); } } //更新资源的时候,重置即可 public void ResetCache() { _localizations = GetAllFromDb(); } private string GetText(string key, out bool notSucceed) { var culture = CultureInfo.CurrentCulture.ToString(); string computedKey = $"{key}.{culture}"; if (_localizations == null) { ResetCache(); } if (_localizations.TryGetValue(computedKey, out string result)) { notSucceed = false; return result; } computedKey = $"{key}.{Constants.DefaultCulture}"; if (_localizations.TryGetValue(computedKey, out result)) { notSucceed = false; return result; } notSucceed = true; return key; } private ConcurrentDictionary<string, string> GetAllFromDb() { using (_context = _contextFactory()) { var items = _context.Resource.Where(data => data.Platform == (int) Platform_Type.Server) .ToDictionary(e => e.Code + "." + e.Culture, e => e.Text); return new ConcurrentDictionary<string, string>(items); } } }
-
-
在Startup配置后,在使用的时候就像官方的StringLocalizer一样注入使用即可;
var options = new RequestLocalizationOptions { DefaultRequestCulture = new RequestCulture(Constants.DefaultCulture) }; app.UseMiddleware<CustomRequestLocalizationMiddleware>(Options.Create(options));