aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
authorShadowghost <Ghost_of_Stone@web.de>2026-05-04 21:57:11 +0200
committerShadowghost <Ghost_of_Stone@web.de>2026-05-12 23:18:38 +0200
commit5cfb379aa63689435077c8f1ebc10c98f625238c (patch)
tree8493e6f87a7e244905479c990ba6afedff0742e8 /Emby.Server.Implementations
parent4be3f5f1f9ff8bd0333033d6ad9c99711da03f96 (diff)
Use native middleware
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketConnection.cs28
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketManager.cs4
-rw-r--r--Emby.Server.Implementations/Localization/LocalizationManager.cs63
3 files changed, 33 insertions, 62 deletions
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;
@@ -73,12 +71,6 @@ namespace Emby.Server.Implementations.HttpServer
public IPAddress? RemoteEndPoint { get; }
/// <summary>
- /// Gets or initializes the culture fallback chain captured from the
- /// <c>Accept-Language</c> header of the upgrade request.
- /// </summary>
- public IReadOnlyList<string>? RequestCultureFallback { get; init; }
-
- /// <summary>
/// Gets or initializes the UI culture name captured from the upgrade request.
/// </summary>
public string? RequestUICulture { get; init; }
@@ -98,22 +90,18 @@ namespace Emby.Server.Implementations.HttpServer
/// <inheritdoc />
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"];
- /// <summary>
- /// Gets the mapping from BCP-47 hyphenated culture codes to Jellyfin's underscore-based codes.
- /// </summary>
- public static readonly FrozenDictionary<string, string> Bcp47ToJellyfinMap = new Dictionary<string, string>(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<string, string> _bcp47ToJellyfinMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
["es-419"] = "es_419",
["es-DO"] = "es_DO",
@@ -47,8 +45,6 @@ namespace Emby.Server.Implementations.Localization
private readonly Dictionary<string, Dictionary<string, ParentalRatingScore?>> _allParentalRatings = new(StringComparer.OrdinalIgnoreCase);
- private static readonly AsyncLocal<IReadOnlyList<string>?> _requestCultureFallback = new();
-
private readonly ConcurrentDictionary<string, Dictionary<string, string>> _cultureOnlyDictionaries = new(StringComparer.OrdinalIgnoreCase);
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
@@ -76,24 +72,28 @@ namespace Emby.Server.Implementations.Localization
}
/// <summary>
- /// 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.
/// </summary>
- public static IReadOnlyList<string>? RequestCultureFallback
+ /// <returns>A list of <see cref="CultureInfo"/> objects covering every embedded translation.</returns>
+ public static IList<CultureInfo> GetSupportedUICultures()
{
- get => _requestCultureFallback.Value;
- set => _requestCultureFallback.Value = value;
- }
+ var cultures = new List<CultureInfo>();
+ 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.
+ }
+ }
- /// <summary>
- /// Checks whether a translation resource file exists for the given culture code.
- /// </summary>
- /// <param name="culture">The culture code to check (e.g. "de", "pt-BR", "es_419").</param>
- /// <returns><c>true</c> if an embedded translation resource exists for the culture.</returns>
- 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
/// <inheritdoc />
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('_', '-');