.NET 6 + Furion Internationalization

.NET provides us with excuses to customize international resources, IStringLocalizerFactory and IStringLocalizer. As long as these two excuses are implemented, we can customize our international resources. My internationalized resources are stored in the database. After the database is extracted according to the area code of the specified area, it is transferred to redis and then provided to various back-end services.

 in

IStringLocalizerFactory This interface requires us to implement the data source. It can be a json file or a database resource.

 IStringLocalizer This interface will be used at the bottom layer to create objects that implement the IStringLocalizer interface by the IStringLocalizerFactory interface. We use internationalization in various back-end services. In fact, we use instances that implement the IStringLocalizer interface.

Take a look at my IStringLocalizerFactory interface

namespace ***********
{
    public class SqlStringLocalizerFactory : IStringLocalizerFactory
    {
        private readonly ISysCacheService cache;

        public SqlStringLocalizerFactory(ISysCacheService _cache)
        {
            cache = _cache;
            //向Redis中注入翻译数据
            getTranslateLibToRedis();
        }

        public IStringLocalizer Create(Type resourceSource)
        {
//创建IStringLocalizer 接口的实例对象,默认都是使用此方法
            return new SqlStringLocalizer(this.cache);
        }

        public IStringLocalizer Create(string baseName, string location)
        {
//创建IStringLocalizer 接口的实例对象
            return new SqlStringLocalizer(this.cache);
        }

        /// <summary>
        /// 将数据库中所有的翻译数据注入到redis
        /// </summary>
        /// <returns></returns>
        public async void getTranslateLibToRedis()
        {
            //获取区域码列表,这里不能使用数据仓储,国际化服务会被注册为单例模式,仓储模型是个泛型,要用原生sql
            var cultureCodes = await @"select DISTINCT CultureCode from LocalizerCultureList;".SqlQueryAsync<string>();
            foreach (string cultureCode in cultureCodes)
            {
                //按区域码分类,并向redis中注入
                var libs = await @"SELECT CultureCode,TextKey,TranslatedText FROM [dbo].[LocalizerTranslationLib] where CultureCode=@Code;"
                               .SqlQueryAsync<LocslizerLibDto>(new { Code = cultureCode });

                Dictionary<string, string> localizerLib = new Dictionary<string, string>();

                foreach (LocslizerLibDto lib in libs)
                {
                    localizerLib.Add(lib.TextKey, lib.TranslatedText);
                }
                await cache.SetAsync(cultureCode, localizerLib);
            }

            //提供静态的国际化对象
            var sqlStringLocalizer = new SqlStringLocalizer(this.cache);
            LocalizerCommon.setLocalizerCommon(sqlStringLocalizer);
        }
    }

    /// <summary>
    /// 提供静态的国际化对象
    /// </summary>
    public static class LocalizerCommon
    {
        public static SqlStringLocalizer localizer;
        /// <summary>
        /// 添加国际化对象的引用
        /// </summary>
        /// <param name="_localizer"></param>
        public static void setLocalizerCommon(SqlStringLocalizer _localizer)
        {
            localizer = _localizer;
        }
        /// <summary>
        /// 获取国际化对象
        /// </summary>
        /// <returns></returns>
        public static SqlStringLocalizer getLocalizerCommon()
        {
            return localizer;
        }
    }
}

 Then just implement our IStringLocalizer

namespace ******
{
   public  class SqlStringLocalizer : IStringLocalizer
    {
        private readonly ISysCacheService cache;

        public SqlStringLocalizer(ISysCacheService _cache)
        {
            cache = _cache; //这是我的redis对象
        }

//为LocalizedString创建实例对象
        public LocalizedString this[string name]
        {
            get
            {
                var value = GetString(name).Result;//异步返回,要加一个Result,否则是Task类型
                return new LocalizedString(name, value ?? name, resourceNotFound: value == null);
            }
        }

        public LocalizedString this[string name, params object[] arguments]
        {
            get
            {
                var format = GetString(name).Result;
                var value = string.Format(format ?? name, arguments);
                return new LocalizedString(name, value, resourceNotFound: format == null);
            }
        }

        public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
        {
            throw new NotImplementedException();
        }

        public IStringLocalizer WithCulture(CultureInfo culture)
        {
            CultureInfo.DefaultThreadCurrentCulture = culture;
            throw new NotImplementedException();
        }
        /// <summary>
        /// redis中获取对应的翻译文本
        /// </summary>
        /// <param name="name">原始文本</param>
        /// <returns></returns>
        private  async Task<string> GetString(string name) 
        {
//CultureInfo.CurrentCulture.Name 当前环境的区域码,无需额外声明,这是.net框架中内置的,引入国际化服务即可生效
            var result= await cache.GetAsync<Dictionary<string,string>>(CultureInfo.CurrentCulture.Name);
            if (result != null)
                return result.GetValueOrDefault(name);
            else return null;
        }

    }
}

In the implementation class of IStringLocalizerFactory, don't forget to introduce the namespace where the IStringLocalizer implementation class is located.

After the above two steps, our custom internationalization resources have been configured. In order for us to use them at any time, we need to enable internationalization services in startup.

public void ConfigureServices(IServiceCollection services)
        {
    //其他代码

            //国际化服务
            services.AddSingleton<IStringLocalizerFactory, SqlStringLocalizerFactory>();
            services.AddLocalization();

    //其他代码
    }
    
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
//其他代码

            #region 国际化配置
            var supportedCultures = new List<CultureInfo>
            {
                new CultureInfo("en-US"),
                new CultureInfo("en-AU"),
                new CultureInfo("en-GB"),
                new CultureInfo("es-ES"),
                new CultureInfo("ja-JP"),
                new CultureInfo("fr-FR"),
                new CultureInfo("zh"),
                new CultureInfo("zh-CN")
            };

            var LocalizerOptions = new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture("en-US"),
                SupportedCultures = supportedCultures,
                SupportedUICultures = supportedCultures
            };
            app.UseRequestLocalization(LocalizerOptions);
            #endregion

            app.UseStaticFiles();
//其他代码

        }

Because we configured the static class, we can now use it anywhere without using dependency injection

 

// LocalizerCommon这是一个静态类,引入命名空间即可
SqlStringLocalizer localizer = LocalizerCommon.getLocalizerCommon();

//使用方式 localizer[key]
例 localizer["请求成功"].Value ; //为了返回的是一个string 可以加上 .Value后缀

 This method can still be called using dependency injection and sharedResource. The static method is just a trick to provide nationalized objects in places where dependency injection is not allowed.

There is no need to modify the code when using dependency injection. The .net framework provides us with such an interface. By default, it will look for the interface of IStringLocalizerFactory to implement it.


private readonly IStringLocalizer<SharedResource> localizer;

public 构造方法(
            IStringLocalizer<SharedResource> _localizer
        )
        {
            localizer = _localizer;
        }
//使用方式 localizer[key]
例 localizer["请求成功"].Value ; //为了返回的是一个string 可以加上 .Value后缀

//SharedResource is an empty class. It is a shared class that provides public international resources for entities. It is not used in my business here. Interested friends can study it in depth.

show results

 

 

 By bringing the culture parameter .net into usl, the area code can be automatically recognized. There is no need to display the reception on the backend of this parameter.

 I hope it will be helpful to your development, thank you! If there are any errors, please point them out.

Guess you like

Origin blog.csdn.net/weixin_43604220/article/details/127205677