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

  

  

 

posted @ 2020-08-04 10:54  PanPan003  阅读(773)  评论(0编辑  收藏  举报