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);