diff --git a/web/src/context/l10n.jsx b/web/src/context/l10n.jsx
index a04bb57018..436c04cd77 100644
--- a/web/src/context/l10n.jsx
+++ b/web/src/context/l10n.jsx
@@ -165,17 +165,21 @@ function findSupportedLanguage(languages) {
/**
* Reloads the page
*
- * It uses the window.location.replace instead of the reload function dropping
- * the "lang" argument from the URL.
+ * It uses the window.location.replace instead of the reload function
+ * synchronizing the "lang" argument from the URL if present.
+ *
+ * @param {string} newLanguage
*/
-function reload() {
+function reload(newLanguage) {
const query = new URLSearchParams(window.location.search);
- query.delete("lang");
- let url = window.location.pathname;
- if (query.size > 0) {
- url = `${url}?${query.toString()}`;
+ if (query.has("lang") && query.get("lang") !== newLanguage) {
+ query.set("lang", newLanguage);
+ // Calling search() with a different value makes the browser to navigate
+ // to the new URL.
+ window.location.search = query.toString();
+ } else {
+ window.location.reload();
}
- window.location.replace(url);
}
/**
@@ -198,10 +202,14 @@ function reload() {
function L10nProvider({ children }) {
const client = useInstallerClient();
const [language, setLanguage] = useState(undefined);
+ const [backendPending, setBackendPending] = useState(false);
const { cancellablePromise } = useCancellablePromise();
const storeBackendLanguage = useCallback(async languageString => {
- if (!client) return false;
+ if (!client) {
+ setBackendPending(true);
+ return false;
+ }
const currentLang = await cancellablePromise(client.language.getUILanguage());
const normalizedLang = languageFromBackend(currentLang);
@@ -233,7 +241,7 @@ function L10nProvider({ children }) {
let mustReload = storeUILanguage(newLanguage);
mustReload = await storeBackendLanguage(newLanguage) || mustReload;
if (mustReload) {
- reload();
+ reload(newLanguage);
} else {
setLanguage(newLanguage);
}
@@ -243,6 +251,13 @@ function L10nProvider({ children }) {
if (!language) changeLanguage();
}, [changeLanguage, language]);
+ useEffect(() => {
+ if (!client || !backendPending) return;
+
+ storeBackendLanguage(language);
+ setBackendPending(false);
+ }, [client, language, backendPending, storeBackendLanguage]);
+
return (
{children}
);
diff --git a/web/src/context/l10n.test.jsx b/web/src/context/l10n.test.jsx
index 47f29ad84c..47e975fbbe 100644
--- a/web/src/context/l10n.test.jsx
+++ b/web/src/context/l10n.test.jsx
@@ -76,10 +76,10 @@ describe("L10nProvider", () => {
const origLocation = window.location;
const origNavigator = window.navigator;
- // mock window.location.replace
+ // mock window.location.reload and search
beforeAll(() => {
delete window.location;
- window.location = { replace: jest.fn(), pathname: "/" };
+ window.location = { reload: jest.fn(), search: "" };
delete window.navigator;
window.navigator = { languages: ["es-es", "cs-cz"] };
@@ -110,14 +110,15 @@ describe("L10nProvider", () => {
it("displays the children content and does not reload", async () => {
render(
- Testing content
+
);
// children are displayed
- await screen.findByText("Testing content");
+ await screen.findByText("hello");
- expect(window.location.replace).not.toHaveBeenCalled();
+ expect(window.location.search).toEqual("");
+ expect(window.location.reload).not.toHaveBeenCalled();
});
});
@@ -135,7 +136,7 @@ describe("L10nProvider", () => {
);
- await waitFor(() => expect(window.location.replace).toHaveBeenCalledWith("/"));
+ await waitFor(() => expect(window.location.reload).toHaveBeenCalled());
// reload the component
render(
@@ -163,7 +164,7 @@ describe("L10nProvider", () => {
);
- await waitFor(() => expect(window.location.replace).toHaveBeenCalledWith("/"));
+ await waitFor(() => expect(window.location.reload).toHaveBeenCalled());
render(
@@ -184,7 +185,7 @@ describe("L10nProvider", () => {
);
- await waitFor(() => expect(window.location.replace).toHaveBeenCalledWith("/"));
+ await waitFor(() => expect(window.location.reload).toHaveBeenCalled());
render(
@@ -220,7 +221,8 @@ describe("L10nProvider", () => {
expect(setUILanguageFn).not.toHaveBeenCalled();
expect(document.cookie).toEqual("CockpitLang=cs-cz");
- expect(window.location.replace).not.toHaveBeenCalled();
+ expect(window.location.reload).not.toHaveBeenCalled();
+ expect(window.location.search).toEqual("?lang=cs-CZ");
});
});
@@ -238,7 +240,7 @@ describe("L10nProvider", () => {
);
- await waitFor(() => expect(window.location.replace).toHaveBeenCalledWith("/"));
+ await waitFor(() => expect(window.location.search).toEqual("lang=cs-cz"));
// reload the component
render(
@@ -265,7 +267,7 @@ describe("L10nProvider", () => {
);
- await waitFor(() => expect(window.location.replace).toHaveBeenCalledWith("/"));
+ await waitFor(() => expect(window.location.search).toEqual("lang=cs-cz"));
// reload the component
render(