diff --git a/studio/frontend/src/components/ui/sonner.tsx b/studio/frontend/src/components/ui/sonner.tsx index d6df0f4eaa..aec1235b81 100644 --- a/studio/frontend/src/components/ui/sonner.tsx +++ b/studio/frontend/src/components/ui/sonner.tsx @@ -90,7 +90,7 @@ const Toaster = ({ ...props }: ToasterProps) => { // Pin the close button inside the toast's top-right corner. // Sonner defaults to the left/outside edge, so keep the horizontal // override here and the top offset in index.css. - "--toast-close-button-start": "unset", + "--toast-close-button-start": "auto", "--toast-close-button-end": "8px", "--toast-close-button-transform": "none", } as React.CSSProperties diff --git a/studio/frontend/src/features/settings/components/language-select.tsx b/studio/frontend/src/features/settings/components/language-select.tsx index 01fe049a56..1f388d6f2c 100644 --- a/studio/frontend/src/features/settings/components/language-select.tsx +++ b/studio/frontend/src/features/settings/components/language-select.tsx @@ -35,7 +35,11 @@ export function LanguageSelect() { > - + {t("settings.appearance.language.autoDetect")} diff --git a/studio/frontend/src/i18n/locale-store.ts b/studio/frontend/src/i18n/locale-store.ts index cd5cac8db0..792e7e77fb 100644 --- a/studio/frontend/src/i18n/locale-store.ts +++ b/studio/frontend/src/i18n/locale-store.ts @@ -98,7 +98,6 @@ function writeStoredPreference(preference: LocalePreference): void { function syncDocumentLang(locale: Locale): void { if (typeof document === "undefined") return; document.documentElement.lang = locale; - document.documentElement.dir = LOCALES[locale].dir; } function notifySubscribers(): void { diff --git a/studio/frontend/src/i18n/messages.ts b/studio/frontend/src/i18n/messages.ts index 074f4ab44f..ead94a966e 100644 --- a/studio/frontend/src/i18n/messages.ts +++ b/studio/frontend/src/i18n/messages.ts @@ -15,19 +15,18 @@ import { de } from "./locales/de"; import { ko } from "./locales/ko"; import type { InterpolationValues, MessageKey } from "./types"; -// dir sets documentElement.dir; Arabic stays ltr (CSS still physical-direction) but renders rtl via bidi. export const LOCALES = { - en: { label: "English", nativeLabel: "English", dir: "ltr" }, - "zh-CN": { label: "Chinese (Simplified)", nativeLabel: "简体中文", dir: "ltr" }, - ja: { label: "Japanese", nativeLabel: "日本語", dir: "ltr" }, - ko: { label: "Korean", nativeLabel: "한국어", dir: "ltr" }, - es: { label: "Spanish", nativeLabel: "Español", dir: "ltr" }, - "pt-BR": { label: "Portuguese (Brazil)", nativeLabel: "Português (Brasil)", dir: "ltr" }, - fr: { label: "French", nativeLabel: "Français", dir: "ltr" }, - de: { label: "German", nativeLabel: "Deutsch", dir: "ltr" }, - ru: { label: "Russian", nativeLabel: "Русский", dir: "ltr" }, - hi: { label: "Hindi", nativeLabel: "हिन्दी", dir: "ltr" }, - ar: { label: "Arabic", nativeLabel: "العربية", dir: "ltr" }, + en: { label: "English", nativeLabel: "English" }, + "zh-CN": { label: "Chinese (Simplified)", nativeLabel: "简体中文" }, + ja: { label: "Japanese", nativeLabel: "日本語" }, + ko: { label: "Korean", nativeLabel: "한국어" }, + es: { label: "Spanish", nativeLabel: "Español" }, + "pt-BR": { label: "Portuguese (Brazil)", nativeLabel: "Português (Brasil)" }, + fr: { label: "French", nativeLabel: "Français" }, + de: { label: "German", nativeLabel: "Deutsch" }, + ru: { label: "Russian", nativeLabel: "Русский" }, + hi: { label: "Hindi", nativeLabel: "हिन्दी" }, + ar: { label: "Arabic", nativeLabel: "العربية" }, } as const; export type Locale = keyof typeof LOCALES; @@ -105,4 +104,4 @@ export function isSupportedLocale(value: unknown): value is Locale { typeof value === "string" && Object.prototype.hasOwnProperty.call(LOCALES, value) ); -} \ No newline at end of file +} diff --git a/tests/studio/test_locale_root_direction_contract.py b/tests/studio/test_locale_root_direction_contract.py new file mode 100644 index 0000000000..1baabdbbca --- /dev/null +++ b/tests/studio/test_locale_root_direction_contract.py @@ -0,0 +1,30 @@ +"""Regression guard for locale changes affecting the entire Studio layout.""" + +from pathlib import Path + + +REPO = Path(__file__).resolve().parents[2] +LOCALE_STORE = REPO / "studio/frontend/src/i18n/locale-store.ts" +MESSAGES = REPO / "studio/frontend/src/i18n/messages.ts" +SONNER = REPO / "studio/frontend/src/components/ui/sonner.tsx" + + +def test_locale_changes_do_not_force_document_direction(): + src = LOCALE_STORE.read_text(encoding = "utf-8") + assert "document.documentElement.lang = locale" in src + assert "document.documentElement.dir" not in src, ( + "locale changes must not force the root direction; html[dir] changes " + "third-party component layout, including Sonner close-button positioning" + ) + + +def test_locale_metadata_does_not_advertise_unused_layout_direction(): + src = MESSAGES.read_text(encoding = "utf-8") + locales_block = src[src.index("export const LOCALES") : src.index("export type Locale")] + assert "dir:" not in locales_block + + +def test_toast_close_position_does_not_inherit_root_direction(): + src = SONNER.read_text(encoding = "utf-8") + assert '"--toast-close-button-start": "auto"' in src + assert '"--toast-close-button-start": "unset"' not in src