代码之家  ›  专栏  ›  技术社区  ›  Jose A

在.NET Core 2.1中无法使用SharedResources的本地化

  •  1
  • Jose A  · 技术社区  · 6 年前

    我已经和这个问题斗争了好几个小时。。。我找不到它是什么。。。

    IStringLocalizer 以及 IHtmlLocalizer 似乎找不到资源文件。

    https://github.com/MormonJesus69420/SharedResourcesExample .Net Core Data Annotations - localization with shared resources https://stackoverflow.com/search?q=shared+resources+.net+core https://andrewlock.net/adding-localisation-to-an-asp-net-core-application/

    我可能忽略了一些愚蠢的事情。

    这是我的启动.cs:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using EduPlaTools.Data;
    using EduPlaTools.Models;
    using EduPlaTools.Services;
    using System.Globalization;
    using Microsoft.Extensions.Options;
    using Microsoft.AspNetCore.Localization;
    using Microsoft.AspNetCore.Mvc.Razor;
    using Pomelo.EntityFrameworkCore.MySql;
    using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
    using Microsoft.AspNetCore.HttpOverrides;
    
    namespace EduPlaTools
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
    
                // This is for string translation!
                // Adds Localization Services (StringLocalizer, HtmlLocalizer, etc.)
                // the opts.ResourcesPath = is the path in which the resources are found.
                // In our case the folder is named Resources!
                // There's specific and neutral resources.  (Specific en-US). (Neutral: es)
                /**
                 * If no ResourcesPath is specified, the view's resources will be expected to be next to the views.
                 * If ResourcesPath were set to "resources", then view resources would be expected to be ina  Resource directory,
                 * in a path speicifc to their veiw (Resources/Views/Home/About.en.resx, for example).
                 * 
                 * */
                services.AddLocalization(opts => opts.ResourcesPath = "Resources");
    
                // services.AddBContext
                // There are subtle differences between the original and the modified version.
    
                services.AddDbContextPool<ApplicationDbContext>(options =>
                    options.UseMySql(Configuration.GetConnectionString("MySQLConnection"),
                    mysqlOptions =>
                    {
                        mysqlOptions.ServerVersion(new Version(8, 0, 12), ServerType.MySql); // replace with your Server Version and Type
                    }
                    ));
                    //options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    
                services.AddIdentity<ApplicationUser, IdentityRole>()
                    .AddEntityFrameworkStores<ApplicationDbContext>()
                    .AddDefaultTokenProviders();
    
                // Add application services.
                services.AddTransient<IEmailSender, EmailSender>();
    
    
    
    
                services.AddMvc()
                        .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, options => options.ResourcesPath = "Resources")
                        .AddDataAnnotationsLocalization();
    
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                // This may be dangerous and is not recommended
                using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
                        .CreateScope())
                {
                    serviceScope.ServiceProvider.GetService<ApplicationDbContext>()
                         .Database.Migrate();
                }
    
                app.UseForwardedHeaders(new ForwardedHeadersOptions
                {
                    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
                });
    
                if (env.IsDevelopment())
                {
                    app.UseBrowserLink();
                    app.UseDeveloperExceptionPage();
                    app.UseDatabaseErrorPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
    
    
                // These must line up with the ending of the .resx files.
                // Example: SharedResources.en.resx, SharedResources.es.rex
    
                // If you want to add specific, then do it like:
                // new CultureInfo("en-US")
                List<CultureInfo> supportedCultures = new List<CultureInfo>
                {
                    new CultureInfo("es"),
                    new CultureInfo("en"),
                    new CultureInfo("es-ES"),
                    new CultureInfo("en-US")
                };
    
                // Registers the localization, and changes the localization per request.
                app.UseRequestLocalization(new RequestLocalizationOptions
                {
                    // We give the default support of Spanish.
                    DefaultRequestCulture = new RequestCulture("es"),
                    // Format numbers, dates, etc.
                    SupportedCultures = supportedCultures,
                    // The strings that we have localized
                    SupportedUICultures = supportedCultures
                });
    
                // This will seed the databse:
    
                SeedDatabase.Initialize(app.ApplicationServices);
    
                app.UseStaticFiles();
    
    
                app.UseAuthentication();
    
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}");
                });
            }
        }
    }
    

    @using  Microsoft.AspNetCore.Mvc.Localization
    
    @inject IViewLocalizer Localizer
    @inject IStringLocalizer<SharedResources> SharedLocalizer
    @inject IHtmlLocalizer<SharedResources> _localizer;
    
    @SharedLocalizer["Menu_Home"]
    

    目录结构如下:

    enter image description here

    Here are the contents of SharedResources.cs:
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace EduPlaTools
    {
        /**
         * This is a dummy class that is needed so Localization works.
         * Now in .NET Core Localization works as a service, and implementsw
         * naming conventions (AT the file level). Therefore, if the files do not
         * implement the correct name, there's going to be problems. 
         * 
         * See an example, here:
         * https://github.com/SteinTheRuler/ASP.NET-Core-Localization/blob/master/Resources/SharedResources.cs
         *
         * This is a workaround to create a Resource File that can be read by the entire
         * application. It's left in blank so the convention over configuration
         * picks it up.
         * 
         * */
        public class SharedResources
        {
        }
    }
    

    enter image description here

    enter image description here

    我也试过给他们改名,但没用。。(试过了)资源有限公司, 资源.rex)

    我试着设置断点来观察它的行为。当然,它没有找到资源文件。然后我把它和 Mormon's repo 通过调用不存在的密钥。我将它与我的输出进行了比较,但是Mormon的repo没有显示“SearchedLocation”(它是在以后的.NET核心版本中引入的吗?)

    摩门教回购: enter image description here

    enter image description here

    我知道这可能有点傻。。。但是已经快4个小时了,我不能停下来,因为我有很多事情要做!!

    有什么想法吗?

    2 回复  |  直到 4 年前
        1
  •  4
  •   LazZiya    6 年前

    如果要使用共享资源实现本地化,则必须创建自己的区域性本地化器类:

    public class CultureLocalizer
        {
            private readonly IStringLocalizer _localizer;
            public CultureLocalizer(IStringLocalizerFactory factory)
            {
                var type = typeof(ViewResource);
                var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
                _localizer = factory.Create("ViewResource", assemblyName.Name);
            }
    
            // if we have formatted string we can provide arguments         
            // e.g.: @Localizer.Text("Hello {0}", User.Name)
            public LocalizedString Text(string key, params string[] arguments)
            {
                return arguments == null
                    ? _localizer[key]
                    : _localizer[key, arguments];
            }
        }
    

    services.AddSingleton<CultureLocalizer>();
    

    并修改视图位置设置:

    services.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
                .AddViewLocalization(o=>o.ResourcesPath = "Resources")
    

    基于web的多文化web应用开发ASP.NET核心2.1页面:

    http://www.ziyad.info/en/articles/10-Developing_Multicultural_Web_Application

    它包括使用共享资源进行本地化的逐步教程,此外,本文还介绍如何本地化标识错误消息:

    http://ziyad.info/en/articles/20-Localizing_Identity_Error_Messages

        2
  •  2
  •   Jose A    6 年前

    回来 Startup.cs ,您有:

    services.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
                .AddViewLocalization(o=>o.ResourcesPath = "Resources")
    

    从技术上讲,您指示MVC在“Resources”文件夹中查找主路径,然后按照约定查找本地化的资源文件。

    因此 如果你想定位 Login.cshtml Views/Account/Login.chsmtl ,您必须在以下位置创建资源文件: Resources/Views/Account/Login.en.resx

    然后需要在视图中直接添加以下内容 登录.cshtml _ViewImports.cshtml 要将其引用到所有视图,请执行以下操作:

    @using Microsoft.AspNetCore.Mvc.Localization
    @inject IViewLocalizer Localizer
    

    之后,在代码中可以执行以下操作: Localizer["My_Resource_file_key"]


    以下是一些插图:

    Folder Structure for the Individual Localization

    Localized View

        3
  •  1
  •   Vočko    4 年前

    对先前答案的更新。由于.NET核心3最近发生了重大变化( https://github.com/dotnet/docs/issues/16964 ),仅当资源直接位于资源文件夹中时,接受的答案才起作用。 我已经创建了一个在视图中使用共享资源的解决方案(同样适用于控制器、数据注释、服务,无论您需要什么…)。

    YourApp.Resources 命名空间。然后创建与类同名的资源(在我的示例中 Views.cs MyApp.Resources.Shared Views.resx ).

    下面是加载共享资源的helper类:

    public class SharedViewLocalizer
    {
        private readonly IStringLocalizer _localizer;
    
        public SharedViewLocalizer(IStringLocalizerFactory factory)
        {
            var assemblyName = new AssemblyName(typeof(Resources.Shared.Views).GetTypeInfo().Assembly.FullName);
            localizer = factory.Create("Shared.Views", assemblyName.Name);
        }
    
        public string this[string key] => _localizer[key];
    
        public string this[string key, params object[] arguments] => _localizer[key, arguments];
    }
    

    你必须登记在 Startup.Configure

    services.AddSingleton<SharedViewLocalizer>();
    

    我想你用

    services.AddLocalization(options => options.ResourcesPath = "Resources");
    

    设置默认资源位置。

    然后在你看来,你使用它如下:

    @inject IViewLocalizer _localizer
    @inject SharedViewLocalizer _sharedLocalizer
    
    @_localizer["View spacific resource"] // Resource from Resources/Views/ControllerName/ViewName.resx
    @_sharedLocalizer["Shared resource"] // Resource from Resources/Shared/Views.resx
    @_sharedLocalizer["Also supports {0} number of arguments", "unlimited"]
    

    启动。配置 :

    services.AddMvc()
        .AddDataAnnotationsLocalization(options => 
        {
            options.DataAnnotationLocalizerProvider = (type, factory) =>
            {
               var assemblyName = new AssemblyName(typeof(DataAnnotations).GetTypeInfo().Assembly.FullName);
               return factory.Create("Shared.DataAnnotations", assemblyName.Name
            };
        })
        .AddViewLocalization();
    

    Resources.Shared 有一个空类叫做 DataAnnotations

    希望这有助于克服目前的突变问题。