Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor WASM Pre-Rendering Localization Behaviour #26890

Closed
TomJD opened this issue Oct 14, 2020 · 5 comments
Closed

Blazor WASM Pre-Rendering Localization Behaviour #26890

TomJD opened this issue Oct 14, 2020 · 5 comments
Assignees
Labels
area-blazor Includes: Blazor, Razor Components feature-blazor-wasm This issue is related to and / or impacts Blazor WebAssembly ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Status: Resolved
Milestone

Comments

@TomJD
Copy link

TomJD commented Oct 14, 2020

Describe the bug

Added localization to Blazor WASM with pre-rendering enabled. When pre-rendering is disabled, the localization language gets picked up instantly upon load. With pre-rendering on, it first shows the initial language (en-GB in my use case) and then switches to the selected language (fr-FR in my use case) after loading.

I would like to know how I can avoid this visible change of culture.

I am storing the culture in LocalStorage and picking it up in Program.cs. (currently hard-coded in the repo due to testing). Also attempted via Cookie.

To Reproduce

minimal repo Available

Exceptions (if any)

Further technical details

  • ASP.NET Core 5.0.100-rc.1.20452.10
    .NET runtimes installed:
    Microsoft.AspNetCore.All 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
    Microsoft.AspNetCore.All 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
    Microsoft.AspNetCore.All 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
    Microsoft.AspNetCore.All 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
    Microsoft.AspNetCore.All 2.1.22 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
    Microsoft.AspNetCore.All 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
    Microsoft.AspNetCore.All 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
    Microsoft.AspNetCore.All 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
    Microsoft.AspNetCore.All 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
    Microsoft.AspNetCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 2.1.22 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 3.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 3.1.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.AspNetCore.App 5.0.0-rc.1.20451.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
    Microsoft.NETCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 2.1.22 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 3.1.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 3.1.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.NETCore.App 5.0.0-rc.1.20451.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
    Microsoft.WindowsDesktop.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
    Microsoft.WindowsDesktop.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
    Microsoft.WindowsDesktop.App 3.1.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
    Microsoft.WindowsDesktop.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
    Microsoft.WindowsDesktop.App 3.1.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
    Microsoft.WindowsDesktop.App 5.0.0-rc.1.20452.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

  • VS Community Preview Version 16.8.0 Preview 3.2

@javiercn javiercn added area-blazor Includes: Blazor, Razor Components feature-blazor-wasm This issue is related to and / or impacts Blazor WebAssembly labels Oct 14, 2020
@javiercn
Copy link
Member

@TomJD thanks for contacting us.

Do you setup the culture on the request? Prerendering will pick up the culture on the server or the culture set by the localization middleware.

@mkArtakMSFT mkArtakMSFT added the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Oct 14, 2020
@TomJD
Copy link
Author

TomJD commented Oct 14, 2020

Hello @javiercn thank you for your time.

I registered it in the Startup file on the server. This is what I have so far:

Program.cs

        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);

            builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
            builder.Services.AddScoped<IWeatherForecastService, WeatherForecastService>();

            builder.Services.AddBlazoredLocalStorage();
            builder.Services.AddLocalization(/*options => options.ResourcesPath = "Resources"*/);
            var host = builder.Build();

            // removed

            await host.RunAsync();
        }

and on the Server project:

ConfigureServices
services.AddLocalization();

Configure

            var supportedCultures = new CultureInfo[]
            {
                new CultureInfo("en"),
                new CultureInfo("fr")
            };
            app.UseRequestLocalization(new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture("fr"),
                SupportedCultures = supportedCultures,
                SupportedUICultures = supportedCultures,
                RequestCultureProviders = new[] { new CookieRequestCultureProvider() }
            });

The first load is French, and changes automatically over to English. The cookie exists with French culture, so I cannot find what is causing the switching back to English... translations found within the .resx are correct

@ghost ghost added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Oct 14, 2020
@TomJD
Copy link
Author

TomJD commented Oct 14, 2020

After a glass of red wine and some further digging, this seems to work, but does not seem ideal:

Program.cs (hard coded French default)

        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);


            builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
            builder.Services.AddScoped<IWeatherForecastService, WeatherForecastService>();


            builder.Services.AddBlazoredLocalStorage();
            builder.Services.AddLocalization(/*options => options.ResourcesPath = "Resources"*/);
            var host = builder.Build();

            var culture = new CultureInfo("fr");
            CultureInfo.DefaultThreadCurrentCulture = culture;
            CultureInfo.DefaultThreadCurrentUICulture = culture;

            await host.RunAsync();
        }

Startup.cs

ConfigureServices

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddLocalization();


            services.AddControllersWithViews();
            services.AddRazorPages();


            services.AddBlazoredLocalStorage();
            services.AddSingleton<IWeatherForecastService, WeatherForecastService>();
        }

Configure

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            var supportedCultures = new CultureInfo[]
            {
                new CultureInfo("en"),
                new CultureInfo("fr")
            };
            app.UseRequestLocalization(new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture(supportedCultures[1]),
                SupportedCultures = supportedCultures,
                SupportedUICultures = supportedCultures,
                RequestCultureProviders = new[] { new CookieRequestCultureProvider() }
            });

[...]
}

It seems that because it is being rendered twice, once by the client and then once by the server, the settings is being overwritten. For instance, if I force

English in the Configure and French in Program.cs , the UI ends up in French.
French in the Configure and English in Program.cs , the UI ends up in English.

Is there a way to avoid this? At the moment, it seems that services registered on the client also need to be registered on the server. So in my use case, I would need to use JSInterop to read the cookie being set for the localization and pass it in the config of Program.cs as well as reading the cookie on the server perhaps via middleware so they are the equally configured on both, client & server.

If one is different than the other, the culture set in Program.cs overwrites.

Or perhaps I'm lost... ?

@mkArtakMSFT mkArtakMSFT removed the Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. label Oct 15, 2020
@mkArtakMSFT mkArtakMSFT added this to the Discussions milestone Oct 15, 2020
@SteveSandersonMS
Copy link
Member

I'm not 100% certain what your desired behavior is, but if you want both prerendering (server-side) and interactive rendering (client-side) to run as the same culture then you'll need to store the culture choice somewhere accessible to both server and client code.

For example, you might choose to store it in a cookie, and use the server's UseRequestLocalization middleware to pick it up and set the server-side thread culture. Then you could, on the server, emit that choice of culture into the resulting HTML page by adding some expression into your _Host.cshtml file (for example, write it out as a <meta> tag on the page). Then your WebAssembly Program.cs could use JS interop to read that value from the DOM and use it to set the culture. Then you'd be sure always to have consistency between the two.

@SteveSandersonMS SteveSandersonMS added the ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. label Oct 15, 2020
@ghost ghost added the Status: Resolved label Oct 15, 2020
@ghost
Copy link

ghost commented Oct 16, 2020

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.

@ghost ghost closed this as completed Oct 16, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Nov 15, 2020
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components feature-blazor-wasm This issue is related to and / or impacts Blazor WebAssembly ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Status: Resolved
Projects
None yet
Development

No branches or pull requests

4 participants