zoukankan      html  css  js  c++  java
  • .net core 3.0 通过资源文件 实现多语言支持——资源文件无法获取的问题

    https://github.com/dotnet/aspnetcore/issues/17733

    https://github.com/dotnet/aspnetcore/issues/17729

    https://github.com/dotnet/aspnetcore/issues/18026

    Describe the bug

    Resources referenced through SharedResources via
    @inject IStringLocalizer<SharedResources> SharedResources
    does not work using .net core sdk version 3.1.100

    When changing to sdk 3.1.100 (or removing global.json) with installed .net core sdk 3.1, values from SharedResources is not displayed correctly ("ValueFromSharedResources" is displayed instead).

    Describe the bug

    Blazor server localization is not working in Visual Studio 16.4 + .NET Core 3.1 SDK.

    To Reproduce

    Please see
    https://github.com/mttrkm/BlazorLocalizationIssueWithCore3_1SDK
    Localization works with Visual Studio 16.3.10 + .NET Core 3.0 SDK.
    But that does not work by upgrading Visual Studio 16.4 + .NET Core 3.1 SDK.

    Further technical details

      • ASP.NET Core version
        3.0(Target) but SDK is 3.1

    I have setup globalization as per the documents here but something must be wrong cause I am only getting the value of the key not the value of the resource.

    The following is my code which i have more or less copied from the document link above.

    // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddLocalization(opts => { opts.ResourcesPath = "Resources"; });
    
            services.Configure<RequestLocalizationOptions>(opts =>
            {
                var supportedCultures = new List<CultureInfo> { new CultureInfo("en-GB"), new CultureInfo("fr-FR"), };
    
                opts.DefaultRequestCulture = new RequestCulture("en-GB");
    
                // Formatting numbers, dates, etc.
                opts.SupportedCultures = supportedCultures;
                // UI strings that we have localized.
                opts.SupportedUICultures = supportedCultures;
            });
            // Add framework services.
            services.AddControllersWithViews()
                .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
                // Maintain property names during serialization. See:
                // https://github.com/aspnet/Announcements/issues/194
                .AddNewtonsoftJson(options =>
                    options.SerializerSettings.ContractResolver = new DefaultContractResolver())
                .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix,
                    opts => { opts.ResourcesPath = "Resources"; })
                .AddDataAnnotationsLocalization();
            services.Configure<ConnectionStringConfig>(Configuration);
            //lets inject the connection string to the data layer 
            //but we should be using the api layer for any heavy lifting.
            services.AddHttpClient("externalservice", c =>
            {
                // Assume this is an "external" service which requires an API KEY
                c.BaseAddress = new Uri("https://localhost:5001/");
            });
        
            // Add Kendo UI services to the services container
                        services.AddKendo();
        }
    
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
    
            SetUpLocalization(app);
    
            app.UseHttpsRedirection();
            app.UseStaticFiles();
    
            app.UseRouting();
    
            app.UseAuthorization();
    
            var options = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
        
            app.UseRequestLocalization(options.Value);
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
            });
    
    
        }
        private static void SetUpLocalization(IApplicationBuilder app)
        {
            var supportedCultures = new[]
            {
                new CultureInfo("en-US"),
                new CultureInfo("en-GB"),
                new CultureInfo("pl")
            };
    
            var options = new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture("en-GB", "en-GB"),
                SupportedCultures = supportedCultures,
                SupportedUICultures = supportedCultures,
             
            };
            options.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context =>
            {
                // My custom request culture logic
                return new ProviderCultureResult("en");
            }));
    
            // Find the cookie provider with LINQ
            var cookieProvider = options.RequestCultureProviders
                .OfType<CookieRequestCultureProvider>()
                .First();
            // Set the new cookie name
            cookieProvider.CookieName = "UserCulture";
    
    
            // Configure the Localization middleware
            app.UseRequestLocalization(options);
    
    
    
    
        }
    

    This is my controller where I am accessing the resouce file key

    public class StockController : Controller
    {
        private  readonly IStringLocalizer<StockController> _localizer;
        
        RoundTableAPIClient apiClient = new RoundTableAPIClient();
        // GET
    
        public StockController(IStringLocalizer<StockController> localizer)
        {
          
            _localizer = localizer;
            
        }
        public IActionResult Index()  
        {
            var test = _localizer[ResourceKeys.StockPageTitle].Value;
            
    
            ViewBag.Title = _localizer["StockPageTitle"];
    
            return View();
        }
     }
    

    But I am not getting the value that is in my resource file I am just getting the text StockPageTItle which is incorrect also how does one give the en-GB as default in asp.net core routes that is not explained in the docs. enter code here
    enter image description here

    Please note also this screenshot saying the following. I presume it's not finding the resource even though I have the naming correct my culture is en-GB by the way.


    image

    why:

    After debugging, found the reason.
    If class SharedResource.cs and SharedResource.*.resx in same folder, the namespace will be error in compiled dll xxx.lang.dll.

    //here is the incorrect namesapce.
    .mresource public IdentityHub.PosSharedResource.zh.resources
    {
      // Offset: 0x00000000 Length: 0x000009D0
    }
    .mresource public IdentityHub.Resources.Views.FcAccount.LoggedOut.zh.resources
    {
      // Offset: 0x000009D8 Length: 0x00000238
    }
    .mresource public IdentityHub.Resources.Views.FcAccount.Shared.Welcome.zh.resources
    {
      // Offset: 0x00000C18 Length: 0x0000022C
    }
    

    As part of the 3.1 release, the .NET SDK changed how namespaces for resource files are calculated. Let's look at the sample shared by @emedbo:

    image

    Views.Home.Index.nb-NO.resx gets embedded as $AssemblyName.Resources.Views.Home.Index. However, SharedResources.nb-NO.resx is treated as a DependentUpon item on SharedResources and picks it's namespace which is WebApplication. This obviously doesn't work with the options.ResourcesPath = "Resources" setting.

     this seems to be an intentional change in how the 3.1 SDK generates namespaces for resources. The workaround you have seems to be an appropriate workaround. I'll follow up on the issue you linked to.

    HOW:

    1.

    There's few options here:

    a) Move the SharedResources file as noted #17733 (comment)
    b) Change the namespace of SharedResources to match the expected namespace for the resource. In this case, it would be WebApplication.Resources.
    c) You can configure the SDK to use pre-3.1 behavior by setting <EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention> in your project file.

    2.

    also the accessability of being able to do Resources.ResourceName to get the value from the default resource appears to be broken as well.

    3.

    Solved this It ended being I had to add the following I re did my Project.

    var supportedCultures = new string[] { "en-GB", "fr-FR" };
    app.UseRequestLocalization(options =>
    options
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures)
    .SetDefaultCulture("en-gb")
    .RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(context =>
    {
    return Task.FromResult(new ProviderCultureResult("en-gb"));
    }))
    );

    Also, I don't believe the above step was in the documentation i believe it needs to be adjusted.

    image

    4.

                services.AddDataAnnotationsLocalization(options =>
                {
                    options.DataAnnotationLocalizerProvider = (type, factory) =>
                    {
                        var sl = factory.Create("SharedResource", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
                        return sl;
                    };
                }).AddMvcLocalization()
                .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
    
                services.AddSingleton<IStringLocalizer>((sp) =>
                {
                    var factory = sp.GetRequiredService<IStringLocalizerFactory>();
                    var sl = factory.Create("SharedResource", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
                    return sl;
    
                });
    

    删除

    SharedResource.cs 

     

      

    取代:

                services.AddDataAnnotationsLocalization(options =>
                {
                    options.DataAnnotationLocalizerProvider = (type, factory) =>
                    {
                        var sl = factory.Create("SharedResource", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
                        return sl;
                    };
                }).AddMvcLocalization()
                .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
    
                services.AddSingleton<IStringLocalizer>((sp) =>
                {
                    var sharedLocalizer = sp.GetRequiredService<IStringLocalizer<SharedResource>>();
                    return sharedLocalizer;
                });
    

      

      

  • 相关阅读:
    Failed to load resource: the server responded with a status of 413 (Request Entity Too Large)
    钱能解决的都是小事——北漂18年(78)
    mysql 排序
    innodb和myisam表排序
    perl 内部字节字符转换
    encode_json 转换给定的perl数据结构为一个UTF-8编码的 2进制字符串 decode_json把UTF-8字节转换成字符
    perl /g
    perl 循环截取字符串
    eclipse报错:Compilation unit name must end with .java, or one of the registered Java-like exten
    用 Flask 来写个轻博客 (30) — 使用 Flask-Admin 增强文章管理功能
  • 原文地址:https://www.cnblogs.com/panpanwelcome/p/13431908.html
Copyright © 2011-2022 走看看