From 4c3ba626659b154597559504c99a8389ada13b3c Mon Sep 17 00:00:00 2001 From: Graham Neubig Date: Thu, 14 Aug 2025 00:10:49 -0400 Subject: [PATCH] Fix i18n language code handling to prevent 404 errors on first load (#10257) Co-authored-by: OpenHands --- frontend/__tests__/i18n/translations.test.tsx | 61 ++++++++++++++++++- frontend/src/i18n/index.ts | 10 ++- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/frontend/__tests__/i18n/translations.test.tsx b/frontend/__tests__/i18n/translations.test.tsx index a19d263f74..a1698bc861 100644 --- a/frontend/__tests__/i18n/translations.test.tsx +++ b/frontend/__tests__/i18n/translations.test.tsx @@ -1,5 +1,5 @@ import { screen } from "@testing-library/react"; -import { describe, expect, it } from "vitest"; +import { describe, expect, it, vi } from "vitest"; import i18n from "../../src/i18n"; import { AccountSettingsContextMenu } from "../../src/components/features/context-menu/account-settings-context-menu"; import { renderWithProviders } from "../../test-utils"; @@ -17,4 +17,63 @@ describe("Translations", () => { screen.getByTestId("account-settings-context-menu"), ).toBeInTheDocument(); }); + + it("should not attempt to load unsupported language codes", async () => { + // Test that the configuration prevents 404 errors by not attempting to load + // unsupported language codes like 'en-US@posix' + const originalLanguage = i18n.language; + + try { + // With nonExplicitSupportedLngs: false, i18next will not attempt to load + // unsupported language codes, preventing 404 errors + + // Test with a language code that includes region but is not in supportedLngs + await i18n.changeLanguage("en-US@posix"); + + // Since "en-US@posix" is not in supportedLngs and nonExplicitSupportedLngs is false, + // i18next should fall back to the fallbackLng ("en") + expect(i18n.language).toBe("en"); + + // Test another unsupported region code + await i18n.changeLanguage("ja-JP"); + + // Even with nonExplicitSupportedLngs: false, i18next still falls back to base language + // if it exists in supportedLngs, but importantly, it won't make a 404 request first + expect(i18n.language).toBe("ja"); + + // Test that supported languages still work + await i18n.changeLanguage("ja"); + expect(i18n.language).toBe("ja"); + + await i18n.changeLanguage("zh-CN"); + expect(i18n.language).toBe("zh-CN"); + + } finally { + // Restore the original language + await i18n.changeLanguage(originalLanguage); + } + }); + + it("should have proper i18n configuration", () => { + // Test that the i18n instance has the expected configuration + expect(i18n.options.supportedLngs).toBeDefined(); + + // nonExplicitSupportedLngs should be false to prevent 404 errors + expect(i18n.options.nonExplicitSupportedLngs).toBe(false); + + // fallbackLng can be a string or array, check if it includes "en" + const fallbackLng = i18n.options.fallbackLng; + if (Array.isArray(fallbackLng)) { + expect(fallbackLng).toContain("en"); + } else { + expect(fallbackLng).toBe("en"); + } + + // Test that supported languages include both base and region-specific codes + const supportedLngs = i18n.options.supportedLngs as string[]; + expect(supportedLngs).toContain("en"); + expect(supportedLngs).toContain("zh-CN"); + expect(supportedLngs).toContain("zh-TW"); + expect(supportedLngs).toContain("ko-KR"); + }); }); diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index ca313c423d..f7a57b52a5 100644 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -27,7 +27,15 @@ i18n .init({ fallbackLng: "en", debug: import.meta.env.NODE_ENV === "development", - load: "currentOnly", + + // Define supported languages explicitly to prevent 404 errors + // According to i18next documentation, this is the recommended way to prevent + // 404 requests for unsupported language codes like 'en-US@posix' + supportedLngs: AvailableLanguages.map((lang) => lang.value), + + // Do NOT set nonExplicitSupportedLngs: true as it causes 404 errors + // for region-specific codes not in supportedLngs (per i18next developer) + nonExplicitSupportedLngs: false, }); export default i18n;