.Net Core 3 IStringLocalizer.WithCulture (CultureInfo) está obsoleto

9

He actualizado un proyecto de .Net Core 2.2 a .Net Core 3.0.

Después de tratar de corregir todas las advertencias y errores, ahora estoy tratando de encontrar una solución a esta advertencia:

'IStringLocalizer.WithCulture(CultureInfo)' is obsolete: 'This method is obsolete.
 Use `CurrentCulture` and `CurrentUICulture` instead.'

Estoy usando esto para cambiar el idioma del sitio web por usuario registrado. Tengo esta implementación para cambiar la cultura del sitio web por usuario:

public class CultureLocalizer : ICultureLocalizer
{
    private readonly IStringLocalizer localizer;
    public CultureLocalizer(IStringLocalizerFactory factory)
    {
        var type = typeof(Resources.PageResources);
        var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
        localizer = factory.Create("PageResources", assemblyName.Name);
    }

    // if we have formatted string we can provide arguments         
    // e.g.: @Localizer.Text("Hello {0}", User.Name)
    public LocalizedString Get(string key, params string[] arguments)
    {
        return arguments == null ? localizer[key] : localizer[key, arguments];
    }

    public LocalizedString Get(Enum key, params string[] arguments)
    {
        return arguments == null ? localizer[key.ToString()] : localizer[key.ToString(), arguments];
    }

    public LocalizedString Get(CultureInfo culture, string key, params string[] arguments)
    {
        // This is obsolete
        return arguments == null ? localizer.WithCulture(culture)[key] : localizer.WithCulture(culture)[key, arguments];
    }

    public LocalizedString Get(CultureInfo culture, Enum key, params string[] arguments)
    {
        // This is obsolete
        return arguments == null ? localizer.WithCulture(culture)[key.ToString()] : localizer.WithCulture(culture)[key.ToString(), arguments];
    }
}

Y esta es la clase ficticia que solo contiene el .resxarchivo para las traducciones:

// dummy class for grouping localization resources
public class PageResources
{
}

No pude encontrar nada en la web que se refiera a cómo resolver esta advertencia, excepto esta discusión sobre github que parece no tener solución todavía.

¿Alguien más había tropezado con esta advertencia y encontrado una solución?

Liran Friedman
fuente

Respuestas:

4

Ya se menciona aquí el código fuente

    /// <summary>
    /// Creates a new <see cref="IStringLocalizer"/> for a specific <see cref="CultureInfo"/>.
    /// </summary>
    /// <param name="culture">The <see cref="CultureInfo"/> to use.</param>
    /// <returns>A culture-specific <see cref="IStringLocalizer"/>.</returns>
    [Obsolete("This method is obsolete. Use `CurrentCulture` and `CurrentUICulture` instead.")]
    IStringLocalizer WithCulture(CultureInfo culture);

Así es como se usan en .Net Core 3.0

public static void Main()  
   {
      // Display the name of the current thread culture.
      Console.WriteLine("CurrentCulture is {0}.", CultureInfo.CurrentCulture.Name);

      // Change the current culture to th-TH.
      CultureInfo.CurrentCulture = new CultureInfo("th-TH", false);
      Console.WriteLine("CurrentCulture is now {0}.", CultureInfo.CurrentCulture.Name);

      // Display the name of the current UI culture.
      Console.WriteLine("CurrentUICulture is {0}.", CultureInfo.CurrentUICulture.Name);

      // Change the current UI culture to ja-JP.
      CultureInfo.CurrentUICulture = new CultureInfo( "ja-JP", false );
      Console.WriteLine("CurrentUICulture is now {0}.", CultureInfo.CurrentUICulture.Name);
   }

Actualización: este enfoque es posible hasta que podamos tener un anuncio oficial de Microsoft

Puedes crear un servicio como este

public class LocalizationService
    {
        private readonly IStringLocalizer _localizer;

        public LocalizationService(IStringLocalizerFactory factory)
        {
            var type = typeof(SharedResource);
            var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
            _localizer = factory.Create("SharedResource", assemblyName.Name);
        }

        public LocalizedString GetLocalizedHtmlString(string key)
        {
            return _localizer[key];
        }
    }

Luego en tu startup.cs

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)
        {
            services.AddScoped<LocalizationService>();
            services.AddLocalization(options => options.ResourcesPath = "Resources");

            services.Configure<RequestLocalizationOptions>(options =>
            {
                var supportedCultures = new[]
                {
                    new CultureInfo("en"),
                    new CultureInfo("nl")
                };

                options.DefaultRequestCulture = new RequestCulture(culture: "en", uiCulture: "en");
                options.SupportedCultures = supportedCultures;
                options.SupportedUICultures = supportedCultures;
            });

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

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            var localizationOption = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
            app.UseRequestLocalization(localizationOption.Value);

            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }

Puedes ver mi código completo aquí

Tony Ngo
fuente
He actualizado mi pregunta con el código que estoy usando. ¿Podrías echarle un vistazo? Porque no parece compatible con tu solución.
Liran Friedman
@LiranFriedman ¿de dónde sacas ICultureLocalizer? Estoy tratando de buscar esa interfaz pero no puedo encontrarla
Tony Ngo
¿Podría explicar cómo cambia la cultura por usuario? Cada usuario selecciona su idioma preferido en su perfil. Además, ¿cómo podría verificar para ver si funciona?
Liran Friedman
Para aquellos que usan esto en una aplicación de consola, es importante usarlo CurrentUICultureporque CurrentCultureparece no tener ningún efecto StringLocalizer. Si lo usa en una aplicación web, puede usarlo services.Configure<RequestLocalizationOptions>para ajustar el comportamiento para detectar el idioma de solicitud del usuario actual, pero tenga en cuenta los valores predeterminados de Microsoft (encabezados, cookies, lo que sea) para la detección automática de idioma. Por esta razón, prefiero adaptarme RequestCultureProvidersa mi propio mecanismo conocido para detectar el idioma del usuario.
JustAMartin