diff --git a/apps/scratch-frame/src/ScratchEditor.jsx b/apps/scratch-frame/src/ScratchEditor.jsx index 4c159827c..2a120e52a 100644 --- a/apps/scratch-frame/src/ScratchEditor.jsx +++ b/apps/scratch-frame/src/ScratchEditor.jsx @@ -40,6 +40,7 @@ const ScratchEditor = ({ locale, apiUrl, accessToken: initialAccessToken, + projectLocale, }) => { const [accessToken, setAccessToken] = useState(initialAccessToken); @@ -89,6 +90,10 @@ const ScratchEditor = ({ basePath={`${import.meta.env.REACT_APP_SCRATCH_FRAME_URL}/scratch-gui/`} onStorageInit={(storage) => { scratchFetchApiRef.current = storage.scratchFetch; + scratchFetchApiRef.current.setMetadata( + "X-Project-Locale", + projectLocale, + ); if (accessToken) { scratchFetchApiRef.current.setMetadata("Authorization", accessToken); } diff --git a/apps/scratch-frame/src/ScratchEditor.test.jsx b/apps/scratch-frame/src/ScratchEditor.test.jsx index 6b2483fd0..185e7a1ed 100644 --- a/apps/scratch-frame/src/ScratchEditor.test.jsx +++ b/apps/scratch-frame/src/ScratchEditor.test.jsx @@ -102,6 +102,32 @@ describe("ScratchEditor", () => { ); }); + test("sends the project locale with scratch requests after storage init", () => { + render( + , + ); + + const scratchGuiProps = mockWrappedScratchGui.mock.calls[0][0]; + const scratchStorage = { + scratchFetch: { + setMetadata: vi.fn(), + }, + }; + + scratchGuiProps.onStorageInit(scratchStorage); + + expect(scratchStorage.scratchFetch.setMetadata).toHaveBeenCalledWith( + "X-Project-Locale", + "fr-FR", + ); + }); + test("updates scratchFetch metadata when scratch-gui-update-token message is received", () => { render( , ); diff --git a/apps/scratch-frame/src/scratch.test.js b/apps/scratch-frame/src/scratch.test.js index bd325320a..21f8f34a3 100644 --- a/apps/scratch-frame/src/scratch.test.js +++ b/apps/scratch-frame/src/scratch.test.js @@ -149,7 +149,9 @@ describe("scratch handshake retries", () => { ); await loadScratchModule(); - expect(mountScratchEditor().locale).toBe(expected); + const scratchEditorProps = mountScratchEditor(); + expect(scratchEditorProps.locale).toBe(expected); + expect(scratchEditorProps.projectLocale).toBe(locale); }, ); diff --git a/cypress/e2e/spec-scratch.cy.js b/cypress/e2e/spec-scratch.cy.js index 8c4c14f90..4d16536e7 100644 --- a/cypress/e2e/spec-scratch.cy.js +++ b/cypress/e2e/spec-scratch.cy.js @@ -10,6 +10,7 @@ import { const origin = "http://localhost:3011/web-component.html"; const scratchFrameOrigin = Cypress.env("REACT_APP_SCRATCH_FRAME_URL"); const authKey = "oidc.user:https://auth-v1.raspberrypi.org:editor-api"; +const scratchProjectsApiMatcher = "**/api/scratch/projects/**"; const user = { access_token: "dummy-access-token", profile: { @@ -107,6 +108,18 @@ describe("Scratch locale", () => { }); }); + it("sets a header with the project locale", () => { + cy.intercept("GET", scratchProjectsApiMatcher).as("scratchProjectRequest"); + + cy.visit(scratchProjectURL({ locale: "fr-FR" })); + + cy.wait("@scratchProjectRequest") + .its("request.headers") + .then((headers) => { + expect(headers["x-project-locale"]).to.equal("fr-FR"); + }); + }); + it("falls back to English when Scratch does not support the locale", () => { cy.visit(scratchProjectURL({ locale: "vls-BE" })); @@ -220,7 +233,6 @@ describe("Scratch save integration", () => { }); describe("Scratch Authorization header", () => { - const scratchProjectsApiMatcher = "**/api/scratch/projects/**"; const remixApiMatcher = "**/api/projects/*/remix"; it("includes Authorization header when authKey and access token are present in localStorage", () => {