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", () => {