feat: add internationalization message platform

This commit is contained in:
donghyeon-ka
2026-07-26 16:17:39 +09:00
parent b8c0444217
commit 668bf05b48
57 changed files with 1711 additions and 201 deletions
+24 -12
View File
@@ -1,4 +1,8 @@
import type { ApiFailure } from "../../contracts/errors.js";
import {
formatMessage,
type ParameterlessMessageKey,
} from "../i18n/index.js";
export type FormValues = Readonly<Record<string, unknown>>;
export type FieldName<Values extends FormValues> = Extract<keyof Values, string>;
@@ -23,24 +27,32 @@ export type MappedValidationFailure<Values extends FormValues> = Readonly<{
}>;
const VALIDATION_COPY = Object.freeze({
REQUIRED: "필수 입력값입니다.",
too_small: "입력값이 너무 짧습니다.",
too_big: "입력값이 너무 깁니다.",
invalid_type: "입력 형식을 확인해 주세요.",
invalid_format: "입력 형식을 확인해 주세요.",
invalid_value: "허용된 값을 선택해 주세요.",
REQUIRED: "form.validation.required",
too_small: "form.validation.tooSmall",
too_big: "form.validation.tooBig",
invalid_type: "form.validation.invalidType",
invalid_format: "form.validation.invalidFormat",
invalid_value: "form.validation.invalidValue",
});
export function validationMessage(code: string): string {
return (
type MessageResolver = (key: ParameterlessMessageKey) => string;
const defaultMessage: MessageResolver = (key) => formatMessage("ko-KR", key);
export function validationMessage(
code: string,
message: MessageResolver = defaultMessage,
): string {
return message(
VALIDATION_COPY[code as keyof typeof VALIDATION_COPY] ??
"입력값을 확인해 주세요."
"form.validation.unknown",
);
}
export function mapValidationFailureToFields<Values extends FormValues>(
failure: ApiFailure,
allowedFields: readonly FieldName<Values>[],
message: MessageResolver = defaultMessage,
): MappedValidationFailure<Values> {
if (failure.kind !== "VALIDATION_REJECTED") {
return Object.freeze({ fieldErrors: Object.freeze({}), formErrors: [] });
@@ -51,15 +63,15 @@ export function mapValidationFailureToFields<Values extends FormValues>(
const issues = failure.validationIssues ?? [];
if (issues.length === 0) {
formErrors.push("입력값을 다시 확인해 주세요.");
formErrors.push(message("form.validation.retry"));
}
for (const issue of issues) {
const field = issue.path.split(".").at(0) ?? "";
if (allowed.has(field)) {
const name = field as FieldName<Values>;
fieldErrors[name] ??= validationMessage(issue.code);
fieldErrors[name] ??= validationMessage(issue.code, message);
} else {
formErrors.push("서버가 확인하지 못한 입력 항목이 있습니다.");
formErrors.push(message("form.validation.unknownField"));
}
}
return Object.freeze({