diff --git a/web/public/locales/en/validation.json b/web/public/locales/en/config/validation.json similarity index 100% rename from web/public/locales/en/validation.json rename to web/public/locales/en/config/validation.json diff --git a/web/src/components/config-form/ConfigForm.tsx b/web/src/components/config-form/ConfigForm.tsx index da0af36bf..612cf236a 100644 --- a/web/src/components/config-form/ConfigForm.tsx +++ b/web/src/components/config-form/ConfigForm.tsx @@ -68,10 +68,10 @@ export function ConfigForm({ formContext, i18nNamespace, }: ConfigFormProps) { - const { t } = useTranslation([ + const { t, i18n } = useTranslation([ i18nNamespace || "common", "views/settings", - "validation", + "config/validation", ]); const [showAdvanced, setShowAdvanced] = useState(false); @@ -117,7 +117,7 @@ export function ConfigForm({ ); // Create error transformer for user-friendly error messages - const errorTransformer = useMemo(() => createErrorTransformer(t), [t]); + const errorTransformer = useMemo(() => createErrorTransformer(i18n), [i18n]); const handleChange = useCallback( (e: IChangeEvent) => { diff --git a/web/src/lib/config-schema/errorMessages.ts b/web/src/lib/config-schema/errorMessages.ts index def4e6517..6eae3643c 100644 --- a/web/src/lib/config-schema/errorMessages.ts +++ b/web/src/lib/config-schema/errorMessages.ts @@ -2,7 +2,7 @@ // Maps JSON Schema validation keywords to user-friendly messages import type { ErrorTransformer } from "@rjsf/utils"; -import type { TFunction } from "i18next"; +import type { i18n as I18n } from "i18next"; export interface ErrorMessageMap { [keyword: string]: string | ((params: Record) => string); @@ -51,7 +51,9 @@ export const defaultErrorMessages: ErrorMessageMap = { * Creates an error transformer function for RJSF * Transforms technical JSON Schema errors into user-friendly messages */ -export function createErrorTransformer(t: TFunction): ErrorTransformer { +export function createErrorTransformer(i18n: I18n): ErrorTransformer { + const t = i18n.t.bind(i18n); + const getDefaultMessage = ( errorType: string, params: Record, @@ -117,31 +119,22 @@ export function createErrorTransformer(t: TFunction): ErrorTransformer { let message: string | undefined; - const missingTranslation = "__missing_translation__"; - // Try field-specific validation message first if (fieldPath) { const fieldKey = `${fieldPath}.validation.${errorType}`; - const translated = t(fieldKey, { - ...normalizedParams, - ns: ["config"], - defaultValue: missingTranslation, - }); - if (translated !== fieldKey && translated !== missingTranslation) { - message = translated; + if (i18n.exists(fieldKey)) { + message = t(fieldKey, normalizedParams); } } // Fall back to generic validation message if (!message) { const genericKey = errorType; - const translated = t(genericKey, { - ...normalizedParams, - ns: ["validation"], - defaultValue: missingTranslation, - }); - if (translated !== genericKey && translated !== missingTranslation) { - message = translated; + if (i18n.exists(genericKey, { ns: "config/validation" })) { + message = t(genericKey, { + ...normalizedParams, + ns: ["config/validation"], + }); } } diff --git a/web/src/utils/i18n.ts b/web/src/utils/i18n.ts index b53b67ca8..16735fbdb 100644 --- a/web/src/utils/i18n.ts +++ b/web/src/utils/i18n.ts @@ -72,6 +72,7 @@ i18n "config/semantic_search", "config/face_recognition", "config/lpr", + "config/validation", ], defaultNS: "common", diff --git a/web/src/views/settings/GlobalConfigView.tsx b/web/src/views/settings/GlobalConfigView.tsx index e46ef860c..dd0430401 100644 --- a/web/src/views/settings/GlobalConfigView.tsx +++ b/web/src/views/settings/GlobalConfigView.tsx @@ -95,6 +95,7 @@ const globalSectionConfigs: Record< "tls_client_key", "tls_insecure", ], + liveValidate: true, }, database: { i18nNamespace: "config/database",