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;
                });
    

      

      

  • 相关阅读:
    HTML/CSS
    Python字符编码
    软件测试遇到的问题积累
    数学
    经济学路谱
    工具
    DataStage
    Shell编程—定时任务
    WebLogic部署
    imageView-scaleType 图片压缩属性
  • 原文地址:https://www.cnblogs.com/panpanwelcome/p/13431908.html
Copyright © 2011-2022 走看看