From 4be3f5f1f9ff8bd0333033d6ad9c99711da03f96 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 4 May 2026 20:26:39 +0200 Subject: Add Accept-Language header support for per-request localization --- .../HttpServer/WebSocketConnection.cs | 36 ++++++++++++++++++++++ .../HttpServer/WebSocketManager.cs | 13 +++++++- 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/HttpServer') diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 373b0994a6..6dc6d9d289 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -1,5 +1,7 @@ using System; using System.Buffers; +using System.Collections.Generic; +using System.Globalization; using System.IO.Pipelines; using System.Net; using System.Net.WebSockets; @@ -7,6 +9,7 @@ using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using Emby.Server.Implementations.Localization; using Jellyfin.Extensions.Json; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net.WebSocketMessages; @@ -69,6 +72,17 @@ namespace Emby.Server.Implementations.HttpServer /// public IPAddress? RemoteEndPoint { get; } + /// + /// Gets or initializes the culture fallback chain captured from the + /// Accept-Language header of the upgrade request. + /// + public IReadOnlyList? RequestCultureFallback { get; init; } + + /// + /// Gets or initializes the UI culture name captured from the upgrade request. + /// + public string? RequestUICulture { get; init; } + /// public Func? OnReceive { get; set; } @@ -81,6 +95,28 @@ namespace Emby.Server.Implementations.HttpServer /// public WebSocketState State => _socket.State; + /// + public void ApplyRequestCulture() + { + if (RequestCultureFallback is not null) + { + LocalizationManager.RequestCultureFallback = RequestCultureFallback; + } + + if (!string.IsNullOrEmpty(RequestUICulture)) + { + try + { + CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo(RequestUICulture); + } + catch (CultureNotFoundException) + { + // Jellyfin culture codes (e.g. "es_419") aren't always valid .NET cultures — + // skip setting CurrentUICulture; RequestCultureFallback above carries the chain. + } + } + } + /// public async Task SendAsync(OutboundWebSocketMessage message, CancellationToken cancellationToken) { diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs index cb5b3993b8..3b5f6d1d09 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs @@ -4,9 +4,11 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net.WebSockets; using System.Threading.Tasks; +using Emby.Server.Implementations.Localization; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Http; @@ -48,13 +50,22 @@ namespace Emby.Server.Implementations.HttpServer WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false); + // Capture the culture context set by AcceptLanguageMiddleware so it can be + // restored both when processing incoming messages and when periodic + // listeners produce server-initiated payloads on background tasks. var connection = new WebSocketConnection( _loggerFactory.CreateLogger(), webSocket, authorizationInfo, context.GetNormalizedRemoteIP()) { - OnReceive = ProcessWebSocketMessageReceived + RequestCultureFallback = LocalizationManager.RequestCultureFallback, + RequestUICulture = CultureInfo.CurrentUICulture.Name + }; + connection.OnReceive = result => + { + connection.ApplyRequestCulture(); + return ProcessWebSocketMessageReceived(result); }; await using (connection.ConfigureAwait(false)) { -- cgit v1.2.3 From 5cfb379aa63689435077c8f1ebc10c98f625238c Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 4 May 2026 21:57:11 +0200 Subject: Use native middleware --- .../HttpServer/WebSocketConnection.cs | 28 ++--- .../HttpServer/WebSocketManager.cs | 4 +- .../Localization/LocalizationManager.cs | 63 ++++------ .../Middleware/AcceptLanguageMiddleware.cs | 137 --------------------- Jellyfin.Server/Startup.cs | 14 ++- .../Localization/LocalizationManagerTests.cs | 86 ++----------- 6 files changed, 54 insertions(+), 278 deletions(-) delete mode 100644 Jellyfin.Server/Middleware/AcceptLanguageMiddleware.cs (limited to 'Emby.Server.Implementations/HttpServer') diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 6dc6d9d289..17070c39ba 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -1,6 +1,5 @@ using System; using System.Buffers; -using System.Collections.Generic; using System.Globalization; using System.IO.Pipelines; using System.Net; @@ -9,7 +8,6 @@ using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using Emby.Server.Implementations.Localization; using Jellyfin.Extensions.Json; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net.WebSocketMessages; @@ -72,12 +70,6 @@ namespace Emby.Server.Implementations.HttpServer /// public IPAddress? RemoteEndPoint { get; } - /// - /// Gets or initializes the culture fallback chain captured from the - /// Accept-Language header of the upgrade request. - /// - public IReadOnlyList? RequestCultureFallback { get; init; } - /// /// Gets or initializes the UI culture name captured from the upgrade request. /// @@ -98,22 +90,18 @@ namespace Emby.Server.Implementations.HttpServer /// public void ApplyRequestCulture() { - if (RequestCultureFallback is not null) + if (string.IsNullOrEmpty(RequestUICulture)) { - LocalizationManager.RequestCultureFallback = RequestCultureFallback; + return; } - if (!string.IsNullOrEmpty(RequestUICulture)) + try { - try - { - CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo(RequestUICulture); - } - catch (CultureNotFoundException) - { - // Jellyfin culture codes (e.g. "es_419") aren't always valid .NET cultures — - // skip setting CurrentUICulture; RequestCultureFallback above carries the chain. - } + CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo(RequestUICulture); + } + catch (CultureNotFoundException) + { + // Codes that aren't valid .NET cultures are ignored. } } diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs index 3b5f6d1d09..dcdfda5472 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs @@ -8,7 +8,6 @@ using System.Globalization; using System.Linq; using System.Net.WebSockets; using System.Threading.Tasks; -using Emby.Server.Implementations.Localization; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Http; @@ -50,7 +49,7 @@ namespace Emby.Server.Implementations.HttpServer WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false); - // Capture the culture context set by AcceptLanguageMiddleware so it can be + // Capture the culture set by RequestLocalizationMiddleware so it can be // restored both when processing incoming messages and when periodic // listeners produce server-initiated payloads on background tasks. var connection = new WebSocketConnection( @@ -59,7 +58,6 @@ namespace Emby.Server.Implementations.HttpServer authorizationInfo, context.GetNormalizedRemoteIP()) { - RequestCultureFallback = LocalizationManager.RequestCultureFallback, RequestUICulture = CultureInfo.CurrentUICulture.Name }; connection.OnReceive = result => diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 2a7a3388aa..5c2376ea00 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -8,7 +8,6 @@ using System.IO; using System.Linq; using System.Reflection; using System.Text.Json; -using System.Threading; using System.Threading.Tasks; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; @@ -32,10 +31,9 @@ namespace Emby.Server.Implementations.Localization private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly; private static readonly string[] _unratedValues = ["n/a", "unrated", "not rated", "nr"]; - /// - /// Gets the mapping from BCP-47 hyphenated culture codes to Jellyfin's underscore-based codes. - /// - public static readonly FrozenDictionary Bcp47ToJellyfinMap = new Dictionary(StringComparer.OrdinalIgnoreCase) + // Maps BCP-47 hyphenated culture codes (set by ASP.NET Core's RequestLocalizationMiddleware + // and used as CurrentUICulture.Name) to Jellyfin's underscore-based resource file codes. + private static readonly FrozenDictionary _bcp47ToJellyfinMap = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["es-419"] = "es_419", ["es-DO"] = "es_DO", @@ -47,8 +45,6 @@ namespace Emby.Server.Implementations.Localization private readonly Dictionary> _allParentalRatings = new(StringComparer.OrdinalIgnoreCase); - private static readonly AsyncLocal?> _requestCultureFallback = new(); - private readonly ConcurrentDictionary> _cultureOnlyDictionaries = new(StringComparer.OrdinalIgnoreCase); private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; @@ -76,24 +72,28 @@ namespace Emby.Server.Implementations.Localization } /// - /// Gets or sets the per-request culture fallback chain resolved from Accept-Language. - /// Each entry is a Jellyfin culture code (e.g. "de", "nl", "en-US") in priority order. + /// Gets the supported UI cultures. /// - public static IReadOnlyList? RequestCultureFallback + /// A list of objects covering every embedded translation. + public static IList GetSupportedUICultures() { - get => _requestCultureFallback.Value; - set => _requestCultureFallback.Value = value; - } + var cultures = new List(); + foreach (var option in _localizationOptions) + { + // Resource files use underscores for some variants (e.g. es_419); + // CultureInfo only accepts hyphenated BCP-47 codes. + var code = option.Value.Replace('_', '-'); + try + { + cultures.Add(CultureInfo.GetCultureInfo(code)); + } + catch (CultureNotFoundException) + { + // Skip novelty codes (e.g. "pr" Pirate, "jbo" Lojban) that .NET cannot resolve. + } + } - /// - /// Checks whether a translation resource file exists for the given culture code. - /// - /// The culture code to check (e.g. "de", "pt-BR", "es_419"). - /// true if an embedded translation resource exists for the culture. - public static bool HasTranslation(string culture) - { - var resourceName = CoreResourcePrefix + GetResourceFilename(culture); - return _assembly.GetManifestResourceInfo(resourceName) is not null; + return cultures; } private static void OnConfigurationUpdated(object? sender, EventArgs e) @@ -472,21 +472,6 @@ namespace Emby.Server.Implementations.Localization /// public string GetLocalizedString(string phrase) { - var fallback = _requestCultureFallback.Value; - if (fallback is not null) - { - foreach (var culture in fallback) - { - var dict = GetLocalizationDictionary(culture); - if (dict.TryGetValue(phrase, out var value)) - { - return value; - } - } - - return phrase; - } - return GetLocalizedString(phrase, CultureInfo.CurrentUICulture.Name); } @@ -510,7 +495,7 @@ namespace Emby.Server.Implementations.Localization } // Normalize BCP-47 hyphenated codes to Jellyfin's underscore-based codes - if (Bcp47ToJellyfinMap.TryGetValue(culture, out var mapped)) + if (_bcp47ToJellyfinMap.TryGetValue(culture, out var mapped)) { culture = mapped; } @@ -626,7 +611,7 @@ namespace Emby.Server.Implementations.Localization private static string GetDisplayName(string cultureCode) { // Handle Jellyfin-specific codes that aren't valid CultureInfo names - if (Bcp47ToJellyfinMap.Values.Contains(cultureCode)) + if (_bcp47ToJellyfinMap.Values.Contains(cultureCode)) { // Convert underscore to hyphen for CultureInfo lookup var normalized = cultureCode.Replace('_', '-'); diff --git a/Jellyfin.Server/Middleware/AcceptLanguageMiddleware.cs b/Jellyfin.Server/Middleware/AcceptLanguageMiddleware.cs deleted file mode 100644 index 57390ae005..0000000000 --- a/Jellyfin.Server/Middleware/AcceptLanguageMiddleware.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; -using Emby.Server.Implementations.Localization; -using MediaBrowser.Controller.Configuration; -using Microsoft.AspNetCore.Http; - -namespace Jellyfin.Server.Middleware; - -/// -/// Middleware that resolves the Accept-Language request header -/// to an ordered list of Jellyfin-supported cultures, sets the fallback chain -/// on , and writes -/// the Content-Language response header. -/// -public class AcceptLanguageMiddleware -{ - private readonly RequestDelegate _next; - - /// - /// Initializes a new instance of the class. - /// - /// Next request delegate. - public AcceptLanguageMiddleware(RequestDelegate next) - { - _next = next; - } - - /// - /// Invoke request. - /// - /// Request context. - /// The server configuration manager. - /// Task. - public async Task Invoke(HttpContext context, IServerConfigurationManager configurationManager) - { - var chain = ResolveLanguages(context.Request, configurationManager); - if (chain is not null) - { - LocalizationManager.RequestCultureFallback = chain; - CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo(chain[0]); - } - - context.Response.OnStarting( - static state => - { - var (ctx, languages) = ((HttpContext, IReadOnlyList?))state; - if (languages is not null) - { - ctx.Response.Headers.ContentLanguage = string.Join(", ", languages); - } - else - { - var culture = CultureInfo.CurrentUICulture.Name; - if (!string.IsNullOrEmpty(culture)) - { - ctx.Response.Headers.ContentLanguage = culture; - } - } - - return Task.CompletedTask; - }, - (context, chain)); - - try - { - await _next(context).ConfigureAwait(false); - } - finally - { - LocalizationManager.RequestCultureFallback = null; - } - } - - private static IReadOnlyList? ResolveLanguages(HttpRequest request, IServerConfigurationManager configurationManager) - { - var acceptLanguageHeader = request.GetTypedHeaders().AcceptLanguage; - if (acceptLanguageHeader is null || acceptLanguageHeader.Count == 0) - { - return null; - } - - var languages = acceptLanguageHeader - .OrderByDescending(h => h.Quality ?? 1) - .Select(h => h.Value.ToString()); - - var chain = new List(); - var seen = new HashSet(StringComparer.OrdinalIgnoreCase); - - foreach (var lang in languages) - { - TryAddCulture(lang, chain, seen); - } - - // Append server default culture if not already present - var serverCulture = configurationManager.Configuration.UICulture; - if (!string.IsNullOrEmpty(serverCulture)) - { - TryAddCulture(serverCulture, chain, seen); - } - - // Ensure en-US is always the final fallback - TryAddCulture("en-US", chain, seen); - - return chain; - } - - private static void TryAddCulture(string lang, List chain, HashSet seen) - { - // Direct match - if (LocalizationManager.HasTranslation(lang) && seen.Add(lang)) - { - chain.Add(lang); - return; - } - - // BCP-47 to Jellyfin underscore mapping (e.g. es-419 -> es_419) - if (LocalizationManager.Bcp47ToJellyfinMap.TryGetValue(lang, out var mapped) && seen.Add(mapped)) - { - chain.Add(mapped); - return; - } - - // Parent culture fallback (e.g. de-DE -> de) - var dashIndex = lang.IndexOf('-', StringComparison.Ordinal); - if (dashIndex > 0) - { - var parent = lang[..dashIndex]; - if (LocalizationManager.HasTranslation(parent) && seen.Add(parent)) - { - chain.Add(parent); - } - } - } -} diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index ea677cf6d9..f1c8b532aa 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -7,6 +7,7 @@ using System.Net.Http.Headers; using System.Net.Mime; using System.Text; using Emby.Server.Implementations.EntryPoints; +using Emby.Server.Implementations.Localization; using Jellyfin.Api.Middleware; using Jellyfin.Database.Implementations; using Jellyfin.LiveTv.Extensions; @@ -17,13 +18,13 @@ using Jellyfin.Networking.HappyEyeballs; using Jellyfin.Server.Extensions; using Jellyfin.Server.HealthChecks; using Jellyfin.Server.Implementations.Extensions; -using Jellyfin.Server.Middleware; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Extensions; using MediaBrowser.XbmcMetadata; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -137,6 +138,15 @@ namespace Jellyfin.Server CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(serverUICulture); + services.Configure(options => + { + var supportedUICultures = LocalizationManager.GetSupportedUICultures(); + options.SupportedCultures = supportedUICultures; + options.SupportedUICultures = supportedUICultures; + options.DefaultRequestCulture = new RequestCulture(serverUICulture); + options.ApplyCurrentCultureToResponseHeaders = true; + }); + services.AddHostedService(); services.AddHostedService(); services.AddHostedService(); @@ -178,7 +188,7 @@ namespace Jellyfin.Server mainApp.UseCors(); - mainApp.UseMiddleware(); + mainApp.UseRequestLocalization(); if (config.RequireHttps && _serverApplicationHost.ListenWithHttps) { diff --git a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs index 1c4d0d4a8a..3b8fe5ca60 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs @@ -367,72 +367,7 @@ namespace Jellyfin.Server.Implementations.Tests.Localization } [Fact] - public void GetLocalizedString_FallbackChain_UsesFirstAvailableCulture() - { - var localizationManager = Setup(new ServerConfiguration - { - UICulture = "en-US" - }); - - // Set fallback chain: de -> fr -> en-US - // "Artists" exists in de as "Interpreten", should use de (first in chain) - LocalizationManager.RequestCultureFallback = new[] { "de", "fr", "en-US" }; - try - { - var translated = localizationManager.GetLocalizedString("Artists"); - Assert.Equal("Interpreten", translated); - } - finally - { - LocalizationManager.RequestCultureFallback = null; - } - } - - [Fact] - public void GetLocalizedString_FallbackChain_SkipsMissingAndUsesNext() - { - var localizationManager = Setup(new ServerConfiguration - { - UICulture = "en-US" - }); - - // "zz" has no translation file so the key won't be found there, - // should fall through to de which has "Artists" as "Interpreten" - LocalizationManager.RequestCultureFallback = new[] { "zz", "de", "en-US" }; - try - { - var translated = localizationManager.GetLocalizedString("Artists"); - Assert.Equal("Interpreten", translated); - } - finally - { - LocalizationManager.RequestCultureFallback = null; - } - } - - [Fact] - public void GetLocalizedString_FallbackChain_ReturnsKeyWhenNoTranslation() - { - var localizationManager = Setup(new ServerConfiguration - { - UICulture = "en-US" - }); - - var key = "CompletelyNonExistentKey"; - LocalizationManager.RequestCultureFallback = new[] { "de", "en-US" }; - try - { - var translated = localizationManager.GetLocalizedString(key); - Assert.Equal(key, translated); - } - finally - { - LocalizationManager.RequestCultureFallback = null; - } - } - - [Fact] - public void GetLocalizedString_NoFallbackChain_UsesCurrentUICulture() + public void GetLocalizedString_UsesCurrentUICulture() { var localizationManager = Setup(new ServerConfiguration { @@ -443,8 +378,6 @@ namespace Jellyfin.Server.Implementations.Tests.Localization try { CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("de"); - LocalizationManager.RequestCultureFallback = null; - var translated = localizationManager.GetLocalizedString("Artists"); Assert.Equal("Interpreten", translated); } @@ -454,16 +387,15 @@ namespace Jellyfin.Server.Implementations.Tests.Localization } } - [Theory] - [InlineData("de", true)] - [InlineData("en-US", true)] - [InlineData("fr", true)] - [InlineData("es_419", true)] - [InlineData("nonexistent", false)] - [InlineData("zz-ZZ", false)] - public void HasTranslation_ReturnsExpected(string culture, bool expected) + [Fact] + public void GetSupportedUICultures_IncludesCommonCultures() { - Assert.Equal(expected, LocalizationManager.HasTranslation(culture)); + var supported = LocalizationManager.GetSupportedUICultures(); + Assert.Contains(supported, c => c.Name.Equals("de", StringComparison.OrdinalIgnoreCase)); + Assert.Contains(supported, c => c.Name.Equals("en-US", StringComparison.OrdinalIgnoreCase)); + Assert.Contains(supported, c => c.Name.Equals("fr", StringComparison.OrdinalIgnoreCase)); + // Underscore variants get normalized to BCP-47 hyphen form for CultureInfo compatibility. + Assert.Contains(supported, c => c.Name.Equals("es-419", StringComparison.OrdinalIgnoreCase)); } private LocalizationManager Setup(ServerConfiguration config) -- cgit v1.2.3 From 93d7a1cf20442e4a82b2819f8a5bdbe4f6c0ae97 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 4 May 2026 23:57:34 +0200 Subject: Cleanup --- .../HttpServer/WebSocketConnection.cs | 15 ++++----------- .../HttpServer/WebSocketManager.cs | 6 +----- 2 files changed, 5 insertions(+), 16 deletions(-) (limited to 'Emby.Server.Implementations/HttpServer') diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 17070c39ba..e9bf3b93a7 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -71,9 +71,9 @@ namespace Emby.Server.Implementations.HttpServer public IPAddress? RemoteEndPoint { get; } /// - /// Gets or initializes the UI culture name captured from the upgrade request. + /// Gets or initializes the UI culture captured from the upgrade request. /// - public string? RequestUICulture { get; init; } + public CultureInfo? RequestUICulture { get; init; } /// public Func? OnReceive { get; set; } @@ -90,19 +90,12 @@ namespace Emby.Server.Implementations.HttpServer /// public void ApplyRequestCulture() { - if (string.IsNullOrEmpty(RequestUICulture)) + if (RequestUICulture is null) { return; } - try - { - CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo(RequestUICulture); - } - catch (CultureNotFoundException) - { - // Codes that aren't valid .NET cultures are ignored. - } + CultureInfo.CurrentUICulture = RequestUICulture; } /// diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs index dcdfda5472..072034c4bf 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs @@ -48,17 +48,13 @@ namespace Emby.Server.Implementations.HttpServer _logger.LogInformation("WS {IP} request", context.Connection.RemoteIpAddress); WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false); - - // Capture the culture set by RequestLocalizationMiddleware so it can be - // restored both when processing incoming messages and when periodic - // listeners produce server-initiated payloads on background tasks. var connection = new WebSocketConnection( _loggerFactory.CreateLogger(), webSocket, authorizationInfo, context.GetNormalizedRemoteIP()) { - RequestUICulture = CultureInfo.CurrentUICulture.Name + RequestUICulture = CultureInfo.CurrentUICulture }; connection.OnReceive = result => { -- cgit v1.2.3