diff --git a/app/core/src/main/java/stirling/software/SPDF/service/LanguageService.java b/app/core/src/main/java/stirling/software/SPDF/service/LanguageService.java index 4731716a92..6ab696b3a7 100644 --- a/app/core/src/main/java/stirling/software/SPDF/service/LanguageService.java +++ b/app/core/src/main/java/stirling/software/SPDF/service/LanguageService.java @@ -42,9 +42,10 @@ public class LanguageService { languageCode -> { Set allowedLanguages = new HashSet<>(applicationProperties.getUi().getLanguages()); + // Empty list means all languages are allowed (no filtering) + // Non-empty list acts as a strict whitelist return allowedLanguages.isEmpty() - || allowedLanguages.contains(languageCode) - || "en_GB".equals(languageCode); + || allowedLanguages.contains(languageCode); }) .collect(Collectors.toSet()); diff --git a/app/core/src/main/resources/settings.yml.template b/app/core/src/main/resources/settings.yml.template index 363f399362..884c2a5a94 100644 --- a/app/core/src/main/resources/settings.yml.template +++ b/app/core/src/main/resources/settings.yml.template @@ -240,7 +240,7 @@ system: ui: appNameNavbar: "" # name displayed on the navigation bar logoStyle: classic # Options: 'classic' (default - classic S icon) or 'modern' (minimalist logo) - languages: [] # If empty, all languages are enabled. To display only German and Polish ["de_DE", "pl_PL"]. British English is always enabled. + languages: [] # If empty, all languages are enabled. To restrict to specific languages, use a whitelist like ["de_DE", "pl_PL", "sv_SE"]. Empty list or not restricting any languages will enable all available languages. defaultHideUnavailableTools: false # Default user preference: hide disabled tools instead of greying them out defaultHideUnavailableConversions: false # Default user preference: hide disabled conversion options instead of greying them out hideDisabledTools: diff --git a/app/core/src/test/java/stirling/software/SPDF/service/LanguageServiceBasicTest.java b/app/core/src/test/java/stirling/software/SPDF/service/LanguageServiceBasicTest.java index 542ebe8af1..79b23f8076 100644 --- a/app/core/src/test/java/stirling/software/SPDF/service/LanguageServiceBasicTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/service/LanguageServiceBasicTest.java @@ -93,7 +93,7 @@ class LanguageServiceBasicTest { // Configure the test service ((LanguageServiceForTest) languageService).setMockResources(mockResources); - // Allow only specific languages (en_GB is always included) + // Allow only specific languages - strict whitelist when(applicationProperties.getUi().getLanguages()) .thenReturn(Arrays.asList("en_US", "fr_FR")); @@ -103,7 +103,7 @@ class LanguageServiceBasicTest { // Verify filtering by restrictions assertTrue(supportedLanguages.contains("en_US"), "Allowed language should be included"); assertTrue(supportedLanguages.contains("fr_FR"), "Allowed language should be included"); - assertTrue(supportedLanguages.contains("en_GB"), "en_GB should always be included"); + assertFalse(supportedLanguages.contains("en_GB"), "en_GB should NOT be included when not in whitelist"); assertFalse(supportedLanguages.contains("de_DE"), "Restricted language should be excluded"); } diff --git a/app/core/src/test/java/stirling/software/SPDF/service/LanguageServiceTest.java b/app/core/src/test/java/stirling/software/SPDF/service/LanguageServiceTest.java index b6587cd28f..734f7589e6 100644 --- a/app/core/src/test/java/stirling/software/SPDF/service/LanguageServiceTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/service/LanguageServiceTest.java @@ -69,15 +69,15 @@ class LanguageServiceTest { // Setup Set expectedLanguages = new HashSet<>(Arrays.asList("en_US", "fr_FR", "de_DE", "en_GB")); - Set allowedLanguages = new HashSet<>(Arrays.asList("en_US", "fr_FR", "en_GB")); + Set allowedLanguages = new HashSet<>(Arrays.asList("en_US", "fr_FR")); // Mock the resource resolver response Resource[] mockResources = createMockResources(expectedLanguages); ((LanguageServiceForTest) languageService).setMockResources(mockResources); - // Set language restrictions in properties + // Set language restrictions in properties - strict whitelist only when(applicationProperties.getUi().getLanguages()) - .thenReturn(Arrays.asList("en_US", "fr_FR")); // en_GB is always allowed + .thenReturn(Arrays.asList("en_US", "fr_FR")); // Test Set supportedLanguages = languageService.getSupportedLanguages(); @@ -86,8 +86,9 @@ class LanguageServiceTest { assertEquals( allowedLanguages, supportedLanguages, - "Should return only allowed languages, plus en_GB which is always allowed"); - assertTrue(supportedLanguages.contains("en_GB"), "en_GB should always be included"); + "Should return only whitelisted languages"); + assertFalse(supportedLanguages.contains("en_GB"), "en_GB should NOT be included when not in whitelist"); + assertFalse(supportedLanguages.contains("de_DE"), "de_DE should NOT be included when not in whitelist"); } @Test diff --git a/frontend/src/core/i18n.ts b/frontend/src/core/i18n.ts index 0b22a65bb7..71239586ed 100644 --- a/frontend/src/core/i18n.ts +++ b/frontend/src/core/i18n.ts @@ -240,10 +240,11 @@ export function updateSupportedLanguages(configLanguages?: string[] | null, defa i18n.options.supportedLngs = validLanguages; i18n.options.fallbackLng = fallback; - // If current language is not in the new supported list, switch to fallback + // If current language is not in the new supported list, switch to fallback with higher priority to override browser detection const currentLang = normalizeLanguageCode(i18n.language || ''); if (currentLang && !validLanguages.includes(currentLang)) { - setLanguageWithPriority(fallback, LanguageSource.Fallback); + // Use ServerDefault priority to override browser detection when language not in whitelist + setLanguageWithPriority(fallback, LanguageSource.ServerDefault); } else if (validDefault) { // Apply server default (respects user choice if already set) setLanguageWithPriority(validDefault, LanguageSource.ServerDefault);