From e25e73c6ca9f4670a994e725020a803b7c35670b Mon Sep 17 00:00:00 2001 From: Dotta Date: Thu, 14 May 2026 16:04:39 -0500 Subject: [PATCH] Address Greptile i18n review feedback --- ui/src/i18n/index.ts | 4 +++- ui/src/i18n/locale-validation.test.ts | 4 ++-- ui/src/i18n/locale-validation.ts | 14 ++++++++------ ui/src/main.tsx | 1 - 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ui/src/i18n/index.ts b/ui/src/i18n/index.ts index 2ab68d20d6b..fb0bacd814d 100644 --- a/ui/src/i18n/index.ts +++ b/ui/src/i18n/index.ts @@ -14,7 +14,9 @@ const i18nextOptions: InitOptions = { initAsync: false, }; -i18n.use(initReactI18next).init(i18nextOptions); +void i18n.use(initReactI18next).init(i18nextOptions).catch((error: unknown) => { + console.error("Failed to initialize i18next", error); +}); export function t(key: string, options: TOptions = {}) { return i18n.t(key, options); diff --git a/ui/src/i18n/locale-validation.test.ts b/ui/src/i18n/locale-validation.test.ts index e01d0b91b64..ab0e4178848 100644 --- a/ui/src/i18n/locale-validation.test.ts +++ b/ui/src/i18n/locale-validation.test.ts @@ -12,7 +12,7 @@ describe("locale validation", () => { }); it("accepts registered locale files", () => { - expect(Object.keys(localeMessages)).toEqual(["en"]); + expect(Object.keys(localeMessages)).toContain("en"); for (const [locale, messages] of Object.entries(localeMessages)) { expect(validateLocaleMessages(messages), locale).toEqual([]); } @@ -74,7 +74,7 @@ describe("locale validation", () => { validateLocaleMessages( { script: "", - handler: 'Create', + handler: 'Create', js: "javascript:alert(1)", data: "data:text/html,hello", url: "https://example.test", diff --git a/ui/src/i18n/locale-validation.ts b/ui/src/i18n/locale-validation.ts index 81cf9e98ef1..8450677b6a6 100644 --- a/ui/src/i18n/locale-validation.ts +++ b/ui/src/i18n/locale-validation.ts @@ -19,7 +19,7 @@ function hasRawHtml(value: string) { } function hasEventHandlerAttribute(value: string) { - return /\son[A-Za-z]+\s*=/.test(value); + return /\son[A-Za-z]+\s*=/i.test(value); } function urlsIn(value: string) { @@ -35,12 +35,15 @@ function hasBlockedData(value: string, englishValue: string) { [hasRawHtml(value), hasRawHtml(englishValue), "raw HTML tag"], ]; - const blocked = checks.find(([candidateHas, englishHas]) => candidateHas && !englishHas); - if (blocked) return blocked[2]; + const blocked = checks + .filter(([candidateHas, englishHas]) => candidateHas && !englishHas) + .map(([, , blockedPayload]) => blockedPayload); const englishUrls = new Set(urlsIn(englishValue)); const unexpectedUrl = urlsIn(value).find((url) => !englishUrls.has(url)); - return unexpectedUrl ? "unexpected URL" : null; + if (unexpectedUrl) blocked.push("unexpected URL"); + + return blocked; } function validateString(path: string[], candidateValue: string, englishValue: string, errors: string[]) { @@ -54,8 +57,7 @@ function validateString(path: string[], candidateValue: string, englishValue: st ); } - const blockedPayload = hasBlockedData(candidateValue, englishValue); - if (blockedPayload) { + for (const blockedPayload of hasBlockedData(candidateValue, englishValue)) { errors.push(`${formatPath(path)} contains disallowed ${blockedPayload}`); } diff --git a/ui/src/main.tsx b/ui/src/main.tsx index fa0ff02117a..b37c5a0824b 100644 --- a/ui/src/main.tsx +++ b/ui/src/main.tsx @@ -18,7 +18,6 @@ import { TooltipProvider } from "@/components/ui/tooltip"; import { initPluginBridge } from "./plugins/bridge-init"; import { PluginLauncherProvider } from "./plugins/launchers"; import "@mdxeditor/editor/style.css"; -import "./i18n"; import "./index.css"; initPluginBridge(React, ReactDOM);