aboutsummaryrefslogtreecommitdiff
path: root/tests/Jellyfin.Server.Implementations.Tests
diff options
context:
space:
mode:
authorShadowghost <Ghost_of_Stone@web.de>2026-05-04 20:26:39 +0200
committerShadowghost <Ghost_of_Stone@web.de>2026-05-12 23:18:38 +0200
commit4be3f5f1f9ff8bd0333033d6ad9c99711da03f96 (patch)
treeb4ab723756891c153d1b67d49ffa45f579335b91 /tests/Jellyfin.Server.Implementations.Tests
parente9942c385775f33c70dbb4b910085ae2c563e898 (diff)
Add Accept-Language header support for per-request localization
Diffstat (limited to 'tests/Jellyfin.Server.Implementations.Tests')
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs161
1 files changed, 161 insertions, 0 deletions
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs
index acabaf3acb..1c4d0d4a8a 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using BitFaster.Caching;
@@ -305,6 +306,166 @@ namespace Jellyfin.Server.Implementations.Tests.Localization
Assert.Equal(key, translated);
}
+ [Fact]
+ public void GetLocalizedString_WithCulture_ReturnsTranslation()
+ {
+ var localizationManager = Setup(new ServerConfiguration
+ {
+ UICulture = "en-US"
+ });
+
+ var translated = localizationManager.GetLocalizedString("Artists", "de");
+ Assert.Equal("Interpreten", translated);
+ }
+
+ [Fact]
+ public void GetLocalizedString_WithCulture_FallsBackToEnUs()
+ {
+ var localizationManager = Setup(new ServerConfiguration
+ {
+ UICulture = "en-US"
+ });
+
+ // A culture with no translation file should fall back to en-US
+ var translated = localizationManager.GetLocalizedString("Artists", "zz");
+ Assert.Equal("Artists", translated);
+ }
+
+ [Fact]
+ public void GetLocalizedString_WithBcp47Normalization_ReturnsTranslation()
+ {
+ var localizationManager = Setup(new ServerConfiguration
+ {
+ UICulture = "en-US"
+ });
+
+ // es-419 is stored as es_419 in Jellyfin
+ var translated = localizationManager.GetLocalizedString("Default", "es-419");
+ Assert.NotEqual("Default", translated);
+ }
+
+ [Fact]
+ public void GetServerLocalizedString_UsesServerCulture()
+ {
+ var localizationManager = Setup(new ServerConfiguration
+ {
+ UICulture = "de"
+ });
+
+ // Even if CurrentUICulture is fr, GetServerLocalizedString should use the server's "de"
+ var previousCulture = CultureInfo.CurrentUICulture;
+ try
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("fr");
+ var translated = localizationManager.GetServerLocalizedString("Artists");
+ Assert.Equal("Interpreten", translated);
+ }
+ finally
+ {
+ CultureInfo.CurrentUICulture = previousCulture;
+ }
+ }
+
+ [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()
+ {
+ var localizationManager = Setup(new ServerConfiguration
+ {
+ UICulture = "en-US"
+ });
+
+ var previousCulture = CultureInfo.CurrentUICulture;
+ try
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("de");
+ LocalizationManager.RequestCultureFallback = null;
+
+ var translated = localizationManager.GetLocalizedString("Artists");
+ Assert.Equal("Interpreten", translated);
+ }
+ finally
+ {
+ CultureInfo.CurrentUICulture = previousCulture;
+ }
+ }
+
+ [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)
+ {
+ Assert.Equal(expected, LocalizationManager.HasTranslation(culture));
+ }
+
private LocalizationManager Setup(ServerConfiguration config)
{
var mockConfiguration = new Mock<IServerConfigurationManager>();