fix(i18n): localize shared MUI widget controls
This commit is contained in:
@@ -85,6 +85,13 @@ try {
|
||||
const titleId = await initialEdit.getAttribute('aria-labelledby');
|
||||
assert.ok(titleId);
|
||||
const edit = page.locator(`[role="dialog"][aria-labelledby="${titleId}"]`);
|
||||
const assertSharedLabels = async lang => {
|
||||
await expect(edit.locator('.MuiAutocomplete-popupIndicator')).toHaveAttribute('aria-label', lang === 'nb' ? 'Åpne' : 'Open');
|
||||
await expect(edit.locator('.MuiAutocomplete-clearIndicator')).toHaveAttribute('aria-label', lang === 'nb' ? 'Tøm' : 'Clear');
|
||||
await expect(page.locator('html')).toHaveAttribute('data-color-scheme', theme);
|
||||
await expect(edit.getByRole('combobox', { name: translations[lang].company, exact: true })).toHaveValue('Synthetic school');
|
||||
};
|
||||
await assertSharedLabels(language);
|
||||
if (flatEdit) {
|
||||
await expect(edit.locator('.MuiDialogContent-root .MuiPaper-outlined')).toHaveCount(0);
|
||||
for (const label of [copy.editJobApplicationDetails, copy.editJobStatusUpdate, copy.editJobRoleDetails, copy.editJobAttachmentsChecklist]) {
|
||||
@@ -98,8 +105,10 @@ try {
|
||||
await page.evaluate(value => { localStorage.setItem('uiLanguage', value); window.dispatchEvent(new StorageEvent('storage', { key: 'uiLanguage', newValue: value })); }, language === 'nb' ? 'en' : 'nb');
|
||||
const otherCopy = translations[language === 'nb' ? 'en' : 'nb'];
|
||||
await assertDay(edit.getByRole('group', { name: otherCopy.editJobDeadline, exact: true }), 23, language === 'nb' ? 'en' : 'nb');
|
||||
await assertSharedLabels(language === 'nb' ? 'en' : 'nb');
|
||||
await page.evaluate(value => { localStorage.setItem('uiLanguage', value); window.dispatchEvent(new StorageEvent('storage', { key: 'uiLanguage', newValue: value })); }, language);
|
||||
await expect(edit.getByRole('textbox', { name: copy.editJobJobTitle, exact: true })).toHaveValue('Retain teacher draft');
|
||||
await assertSharedLabels(language);
|
||||
assert.equal(detailReads, reads); assert.equal(writes.length, 0);
|
||||
for (const label of [copy.editJobAppliedOn, copy.editJobStatusChangedOn, copy.editJobReplyReceivedOn, copy.editJobFollowUpOn, copy.editJobDeadline]) await choose24(edit.getByRole('group', { name: label, exact: true }), label === copy.editJobDeadline);
|
||||
if (flatEdit) await edit.locator('.MuiDialogContent-root').evaluate(node => { node.scrollTop = 0; });
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { useMemo, type ReactNode } from "react";
|
||||
import { ThemeProvider, useTheme } from "@mui/material/styles";
|
||||
import { nbNO as materialNbNO } from "@mui/material/locale";
|
||||
import { deepmerge } from "@mui/utils";
|
||||
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
|
||||
import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
|
||||
import { nbNO } from "@mui/x-date-pickers/locales";
|
||||
@@ -7,9 +10,14 @@ import { useI18n } from "./i18n/I18nProvider";
|
||||
|
||||
export default function DateLocalizationProvider({ children }: { children: ReactNode }) {
|
||||
const { language } = useI18n();
|
||||
return <LocalizationProvider
|
||||
const theme = useTheme();
|
||||
const localizedTheme = useMemo(() => ({
|
||||
...theme,
|
||||
components: deepmerge(theme.components ?? {}, language === "nb" ? materialNbNO.components : {}),
|
||||
}), [theme, language]);
|
||||
return <ThemeProvider theme={localizedTheme}><LocalizationProvider
|
||||
dateAdapter={AdapterDateFns}
|
||||
adapterLocale={language === "nb" ? nb : enUS}
|
||||
localeText={language === "nb" ? nbNO.components.MuiLocalizationProvider.defaultProps.localeText : undefined}
|
||||
>{children}</LocalizationProvider>;
|
||||
>{children}</LocalizationProvider></ThemeProvider>;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import React, { useState } from "react";
|
||||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
|
||||
import { Autocomplete, TextField } from "@mui/material";
|
||||
import JobTrackerThemeProvider from "./ThemeProvider";
|
||||
import DateLocalizationProvider from "./DateLocalizationProvider";
|
||||
import { I18nProvider, useI18n } from "./i18n/I18nProvider";
|
||||
|
||||
@@ -13,6 +15,7 @@ function Form() {
|
||||
<button onClick={() => setLocalLanguage("nb")}>Bokmål</button>
|
||||
<button onClick={() => setLocalLanguage("en")}>English</button>
|
||||
<DatePicker label="Deadline" value={date} onChange={setDate} />
|
||||
<Autocomplete options={["Teacher", "Engineer"]} defaultValue="Teacher" renderInput={params => <TextField {...params} label="Occupation" />} />
|
||||
</>;
|
||||
}
|
||||
|
||||
@@ -28,6 +31,24 @@ test("Bokmål localizes date sections, calendar controls and displayed format",
|
||||
expect(screen.getByRole("group", { name: "Deadline" }).querySelector("input")).toHaveValue("23.11.2026");
|
||||
});
|
||||
|
||||
test("shared widget controls follow live UI language without losing selection or dark theme", () => {
|
||||
localStorage.setItem("uiLanguage", "nb");
|
||||
render(<JobTrackerThemeProvider preference="dark" systemPrefersDark={false}><I18nProvider><DateLocalizationProvider><Form /></DateLocalizationProvider></I18nProvider></JobTrackerThemeProvider>);
|
||||
expect(screen.getByRole("button", { name: "Åpne" })).toBeInTheDocument();
|
||||
fireEvent.focus(screen.getByRole("combobox", { name: "Occupation" }));
|
||||
expect(screen.getByTitle("Tøm")).toHaveAttribute("aria-label", "Tøm");
|
||||
const occupation = screen.getByRole("combobox", { name: "Occupation" });
|
||||
expect(occupation).toHaveValue("Teacher");
|
||||
fireEvent.click(screen.getByRole("button", { name: "English" }));
|
||||
expect(screen.getByRole("button", { name: "Open" })).toBeInTheDocument();
|
||||
expect(screen.getByTitle("Clear")).toHaveAttribute("aria-label", "Clear");
|
||||
expect(occupation).toHaveValue("Teacher");
|
||||
fireEvent.click(screen.getByRole("button", { name: "Bokmål" }));
|
||||
expect(screen.getByRole("button", { name: "Åpne" })).toBeInTheDocument();
|
||||
expect(occupation).toHaveValue("Teacher");
|
||||
expect(document.documentElement).toHaveAttribute("data-color-scheme", "dark");
|
||||
});
|
||||
|
||||
test("live UI language changes retain the selected day and unsaved form draft", () => {
|
||||
render(<I18nProvider><DateLocalizationProvider><Form /></DateLocalizationProvider></I18nProvider>);
|
||||
const title = screen.getByRole("textbox", { name: "Unsaved title" });
|
||||
|
||||
Reference in New Issue
Block a user