diff --git a/examples/with-next-i18next/next-i18next.config.js b/examples/with-next-i18next/next-i18next.config.js
index 0d01f7f..2a99f31 100644
--- a/examples/with-next-i18next/next-i18next.config.js
+++ b/examples/with-next-i18next/next-i18next.config.js
@@ -8,6 +8,7 @@ module.exports = {
locales: [
"en",
"he",
+ "ko",
"ja",
"fr",
"ar",
diff --git a/examples/with-next-i18next/pages/index.tsx b/examples/with-next-i18next/pages/index.tsx
index 5fabf25..c955338 100644
--- a/examples/with-next-i18next/pages/index.tsx
+++ b/examples/with-next-i18next/pages/index.tsx
@@ -83,6 +83,7 @@ export default function HookForm() {
+
diff --git a/examples/with-next-i18next/public/locales/ko/common.json b/examples/with-next-i18next/public/locales/ko/common.json
new file mode 100644
index 0000000..c4a4d9b
--- /dev/null
+++ b/examples/with-next-i18next/public/locales/ko/common.json
@@ -0,0 +1,7 @@
+{
+ "username": "사용자 명",
+ "username_placeholder": "홍길동",
+ "email": "이메일",
+ "favoriteNumber": "좋아하는 숫자",
+ "submit": "제출"
+}
diff --git a/examples/with-next-i18next/public/locales/ko/zod.json b/examples/with-next-i18next/public/locales/ko/zod.json
new file mode 100644
index 0000000..f98bbec
--- /dev/null
+++ b/examples/with-next-i18next/public/locales/ko/zod.json
@@ -0,0 +1,112 @@
+{
+ "errors": {
+ "invalid_type": "{{expected}} 입력을 기대하였지만, {{received}}이 입력되었습니다.",
+ "invalid_type_received_undefined": "필수 입력 값 입니다.",
+ "invalid_literal": "허용되지 않은 리터럴 값 입니다. 입력 가능한 값은 {{expected}} 입니다.",
+ "unrecognized_keys": "객체 키 {{- keys}} 값은 허용되지 않습니다.",
+ "invalid_union": "허용되지 않은 입력 값입니다.",
+ "invalid_union_discriminator": "허용되지 않은 입력 값입니다. 입력 가능한 값은 {{- options}} 입니다.",
+ "invalid_enum_value": "'{{received}}'값은 허용되지 않습니다. 입력 가능한 값은 {{- options}} 입니다.",
+ "invalid_arguments": "허용되지 않은 파라메터 타입입니다.",
+ "invalid_return_type": "허용되지 않은 반환 타입입니다.",
+ "invalid_date": "허용되지 않은 날짜 값 입니다.",
+ "custom": "허용되지 않은 입력 값 입니다.",
+ "invalid_intersection_types": "교차 타입을 만족하지 않습니다.",
+ "not_multiple_of": "{{multipleOf}}의 배수이어야 합니다.",
+ "not_finite": "유한한 값이어야 합니다.",
+ "invalid_string": {
+ "email": "허용되지 않은 {{validation}} 형식 입니다.",
+ "url": "허용되지 않은 {{validation}} 형식 입니다.",
+ "uuid": "허용되지 않은 {{validation}} 형식 입니다.",
+ "cuid": "허용되지 않은 {{validation}} 형식 입니다.",
+ "regex": "허용되지 않은 형식 입니다.",
+ "datetime": "허용되지 않은 {{validation}} 형식 입니다.",
+ "startsWith": "\"{{startsWith}}\"로 시작하는 문자열이어야 합니다.",
+ "endsWith": "\"{{endsWith}}\"로 끝나는 문자열이어야 합니다."
+ },
+ "too_small": {
+ "array": {
+ "exact": "{{minimum}}개 이어야 합니다.",
+ "inclusive": "{{minimum}}개 보다 많거나 같아야 합니다.",
+ "not_inclusive": "{{minimum}}개 보다 많아야 합니다."
+ },
+ "string": {
+ "exact": "{{minimum}}자를 입력해야 합니다.",
+ "inclusive": "{{minimum}}자 보다 많거나 같아야 합니다.",
+ "not_inclusive": "{{minimum}}자 보다 많아야 합니다."
+ },
+ "number": {
+ "exact": "{{minimum}}이어야 합니다.",
+ "inclusive": "{{minimum}}보다 크거나 같은 값이어야 합니다.",
+ "not_inclusive": "{{minimum}}보다 큰 값이어야 합니다."
+ },
+ "set": {
+ "exact": "허용되지 않은 입력 값 입니다.",
+ "inclusive": "허용되지 않은 입력 값 입니다.",
+ "not_inclusive": "허용되지 않은 입력 값 입니다."
+ },
+ "date": {
+ "exact": "{{- minimum, datetime}}과 같은 날짜 이어야 합니다.",
+ "inclusive": "{{- minimum, datetime}}보다 이후이거나 같아야 합니다.",
+ "not_inclusive": "{{- minimum, datetime}}보다 이후 이어야 합니다."
+ }
+ },
+ "too_big": {
+ "array": {
+ "exact": "{{maximum}}개 이어야 합니다.",
+ "inclusive": "{{maximum}}개 보다 작거나 같아야 합니다.",
+ "not_inclusive": "{{maximum}}개 보다 작아야 합니다."
+ },
+ "string": {
+ "exact": "{{maximum}}자를 입력해야 합니다.",
+ "inclusive": "{{maximum}}자 보다 작거나 같아야 합니다.",
+ "not_inclusive": "{{maximum}}자 보다 작아야 합니다."
+ },
+ "number": {
+ "exact": "{{maximum}}이어야 합니다.",
+ "inclusive": "{{maximum}}보다 작거나 같은 값이어야 합니다.",
+ "not_inclusive": "{{maximum}}보다 작은 값이어야 합니다."
+ },
+ "set": {
+ "exact": "허용되지 않은 입력 값 입니다.",
+ "inclusive": "허용되지 않은 입력 값 입니다.",
+ "not_inclusive": "허용되지 않은 입력 값 입니다."
+ },
+ "date": {
+ "exact": "{{- maximum, datetime}}과 같은 날짜 이어야 합니다.",
+ "inclusive": "{{- maximum, datetime}}보다 이전이거나 같아야 합니다.",
+ "not_inclusive": "{{- maximum, datetime}}보다 이전이어야 합니다."
+ }
+ }
+ },
+ "validations": {
+ "email": "이메일",
+ "url": "URL",
+ "uuid": "UUID",
+ "cuid": "CUID",
+ "regex": "정규식",
+ "datetime": "날짜"
+ },
+ "types": {
+ "function": "함수 타입",
+ "number": "숫자 타입",
+ "string": "문자열 타입",
+ "nan": "NaN 값",
+ "integer": "정수 타입",
+ "float": "실수 타입",
+ "boolean": "논리값 타입",
+ "date": "날짜 타입",
+ "bigint": "bigint 타입",
+ "undefined": "undefined 타입",
+ "symbol": "symbol 타입",
+ "null": "null 값",
+ "array": "배열 타입",
+ "object": "객체 타입",
+ "unknown": "unknown 타입",
+ "promise": "promise 타입",
+ "void": "void 타입",
+ "never": "never 타입",
+ "map": "map 타입",
+ "set": "set 타입"
+ }
+}
diff --git a/packages/core/locales/ko/zod.json b/packages/core/locales/ko/zod.json
new file mode 100644
index 0000000..f98bbec
--- /dev/null
+++ b/packages/core/locales/ko/zod.json
@@ -0,0 +1,112 @@
+{
+ "errors": {
+ "invalid_type": "{{expected}} 입력을 기대하였지만, {{received}}이 입력되었습니다.",
+ "invalid_type_received_undefined": "필수 입력 값 입니다.",
+ "invalid_literal": "허용되지 않은 리터럴 값 입니다. 입력 가능한 값은 {{expected}} 입니다.",
+ "unrecognized_keys": "객체 키 {{- keys}} 값은 허용되지 않습니다.",
+ "invalid_union": "허용되지 않은 입력 값입니다.",
+ "invalid_union_discriminator": "허용되지 않은 입력 값입니다. 입력 가능한 값은 {{- options}} 입니다.",
+ "invalid_enum_value": "'{{received}}'값은 허용되지 않습니다. 입력 가능한 값은 {{- options}} 입니다.",
+ "invalid_arguments": "허용되지 않은 파라메터 타입입니다.",
+ "invalid_return_type": "허용되지 않은 반환 타입입니다.",
+ "invalid_date": "허용되지 않은 날짜 값 입니다.",
+ "custom": "허용되지 않은 입력 값 입니다.",
+ "invalid_intersection_types": "교차 타입을 만족하지 않습니다.",
+ "not_multiple_of": "{{multipleOf}}의 배수이어야 합니다.",
+ "not_finite": "유한한 값이어야 합니다.",
+ "invalid_string": {
+ "email": "허용되지 않은 {{validation}} 형식 입니다.",
+ "url": "허용되지 않은 {{validation}} 형식 입니다.",
+ "uuid": "허용되지 않은 {{validation}} 형식 입니다.",
+ "cuid": "허용되지 않은 {{validation}} 형식 입니다.",
+ "regex": "허용되지 않은 형식 입니다.",
+ "datetime": "허용되지 않은 {{validation}} 형식 입니다.",
+ "startsWith": "\"{{startsWith}}\"로 시작하는 문자열이어야 합니다.",
+ "endsWith": "\"{{endsWith}}\"로 끝나는 문자열이어야 합니다."
+ },
+ "too_small": {
+ "array": {
+ "exact": "{{minimum}}개 이어야 합니다.",
+ "inclusive": "{{minimum}}개 보다 많거나 같아야 합니다.",
+ "not_inclusive": "{{minimum}}개 보다 많아야 합니다."
+ },
+ "string": {
+ "exact": "{{minimum}}자를 입력해야 합니다.",
+ "inclusive": "{{minimum}}자 보다 많거나 같아야 합니다.",
+ "not_inclusive": "{{minimum}}자 보다 많아야 합니다."
+ },
+ "number": {
+ "exact": "{{minimum}}이어야 합니다.",
+ "inclusive": "{{minimum}}보다 크거나 같은 값이어야 합니다.",
+ "not_inclusive": "{{minimum}}보다 큰 값이어야 합니다."
+ },
+ "set": {
+ "exact": "허용되지 않은 입력 값 입니다.",
+ "inclusive": "허용되지 않은 입력 값 입니다.",
+ "not_inclusive": "허용되지 않은 입력 값 입니다."
+ },
+ "date": {
+ "exact": "{{- minimum, datetime}}과 같은 날짜 이어야 합니다.",
+ "inclusive": "{{- minimum, datetime}}보다 이후이거나 같아야 합니다.",
+ "not_inclusive": "{{- minimum, datetime}}보다 이후 이어야 합니다."
+ }
+ },
+ "too_big": {
+ "array": {
+ "exact": "{{maximum}}개 이어야 합니다.",
+ "inclusive": "{{maximum}}개 보다 작거나 같아야 합니다.",
+ "not_inclusive": "{{maximum}}개 보다 작아야 합니다."
+ },
+ "string": {
+ "exact": "{{maximum}}자를 입력해야 합니다.",
+ "inclusive": "{{maximum}}자 보다 작거나 같아야 합니다.",
+ "not_inclusive": "{{maximum}}자 보다 작아야 합니다."
+ },
+ "number": {
+ "exact": "{{maximum}}이어야 합니다.",
+ "inclusive": "{{maximum}}보다 작거나 같은 값이어야 합니다.",
+ "not_inclusive": "{{maximum}}보다 작은 값이어야 합니다."
+ },
+ "set": {
+ "exact": "허용되지 않은 입력 값 입니다.",
+ "inclusive": "허용되지 않은 입력 값 입니다.",
+ "not_inclusive": "허용되지 않은 입력 값 입니다."
+ },
+ "date": {
+ "exact": "{{- maximum, datetime}}과 같은 날짜 이어야 합니다.",
+ "inclusive": "{{- maximum, datetime}}보다 이전이거나 같아야 합니다.",
+ "not_inclusive": "{{- maximum, datetime}}보다 이전이어야 합니다."
+ }
+ }
+ },
+ "validations": {
+ "email": "이메일",
+ "url": "URL",
+ "uuid": "UUID",
+ "cuid": "CUID",
+ "regex": "정규식",
+ "datetime": "날짜"
+ },
+ "types": {
+ "function": "함수 타입",
+ "number": "숫자 타입",
+ "string": "문자열 타입",
+ "nan": "NaN 값",
+ "integer": "정수 타입",
+ "float": "실수 타입",
+ "boolean": "논리값 타입",
+ "date": "날짜 타입",
+ "bigint": "bigint 타입",
+ "undefined": "undefined 타입",
+ "symbol": "symbol 타입",
+ "null": "null 값",
+ "array": "배열 타입",
+ "object": "객체 타입",
+ "unknown": "unknown 타입",
+ "promise": "promise 타입",
+ "void": "void 타입",
+ "never": "never 타입",
+ "map": "map 타입",
+ "set": "set 타입"
+ }
+}
diff --git a/packages/core/tests/integrations/ko.test.ts b/packages/core/tests/integrations/ko.test.ts
new file mode 100644
index 0000000..3cdec72
--- /dev/null
+++ b/packages/core/tests/integrations/ko.test.ts
@@ -0,0 +1,217 @@
+import { test, expect, beforeAll } from "vitest";
+import { z } from "zod";
+import { init, getErrorMessage, getErrorMessageFromZodError } from "./helpers";
+
+const LOCALE = "ko";
+
+beforeAll(async () => {
+ await init(LOCALE);
+});
+
+test("string parser error messages", () => {
+ const schema = z.string();
+
+ expect(getErrorMessage(schema.safeParse(undefined))).toEqual(
+ "필수 입력 값 입니다."
+ );
+ expect(getErrorMessage(schema.safeParse(1))).toEqual(
+ "문자열 타입 입력을 기대하였지만, 숫자 타입이 입력되었습니다."
+ );
+ expect(getErrorMessage(schema.safeParse(true))).toEqual(
+ "문자열 타입 입력을 기대하였지만, 논리값 타입이 입력되었습니다."
+ );
+ expect(getErrorMessage(schema.safeParse(Date))).toEqual(
+ "문자열 타입 입력을 기대하였지만, 함수 타입이 입력되었습니다."
+ );
+ expect(getErrorMessage(schema.safeParse(new Date()))).toEqual(
+ "문자열 타입 입력을 기대하였지만, 날짜 타입이 입력되었습니다."
+ );
+ expect(getErrorMessage(schema.email().safeParse(""))).toEqual(
+ "허용되지 않은 이메일 형식 입니다."
+ );
+ expect(getErrorMessage(schema.url().safeParse(""))).toEqual(
+ "허용되지 않은 URL 형식 입니다."
+ );
+ expect(getErrorMessage(schema.regex(/aaa/).safeParse(""))).toEqual(
+ "허용되지 않은 형식 입니다."
+ );
+ expect(getErrorMessage(schema.startsWith("foo").safeParse(""))).toEqual(
+ '"foo"로 시작하는 문자열이어야 합니다.'
+ );
+ expect(getErrorMessage(schema.endsWith("bar").safeParse(""))).toEqual(
+ '"bar"로 끝나는 문자열이어야 합니다.'
+ );
+ expect(getErrorMessage(schema.min(5).safeParse("a"))).toEqual(
+ "5자 보다 많거나 같아야 합니다."
+ );
+ expect(getErrorMessage(schema.max(5).safeParse("abcdef"))).toEqual(
+ "5자 보다 작거나 같아야 합니다."
+ );
+ expect(getErrorMessage(schema.length(5).safeParse("abcdef"))).toEqual(
+ "5자를 입력해야 합니다."
+ );
+ expect(
+ getErrorMessage(schema.datetime().safeParse("2020-01-01T00:00:00+02:00"))
+ ).toEqual("허용되지 않은 날짜 형식 입니다.");
+});
+
+test("number parser error messages", () => {
+ const schema = z.number();
+
+ expect(getErrorMessage(schema.safeParse(undefined))).toEqual(
+ "필수 입력 값 입니다."
+ );
+ expect(getErrorMessage(schema.safeParse(""))).toEqual(
+ "숫자 타입 입력을 기대하였지만, 문자열 타입이 입력되었습니다."
+ );
+ expect(getErrorMessage(schema.safeParse(null))).toEqual(
+ "숫자 타입 입력을 기대하였지만, null 값이 입력되었습니다."
+ );
+ expect(getErrorMessage(schema.safeParse(NaN))).toEqual(
+ "숫자 타입 입력을 기대하였지만, NaN 값이 입력되었습니다."
+ );
+ expect(getErrorMessage(schema.int().safeParse(0.1))).toEqual(
+ "정수 타입 입력을 기대하였지만, 실수 타입이 입력되었습니다."
+ );
+ expect(getErrorMessage(schema.multipleOf(5).safeParse(2))).toEqual(
+ "5의 배수이어야 합니다."
+ );
+ expect(getErrorMessage(schema.step(0.1).safeParse(0.0001))).toEqual(
+ "0.1의 배수이어야 합니다."
+ );
+ expect(getErrorMessage(schema.lt(5).safeParse(10))).toEqual(
+ "5보다 작은 값이어야 합니다."
+ );
+ expect(getErrorMessage(schema.lte(5).safeParse(10))).toEqual(
+ "5보다 작거나 같은 값이어야 합니다."
+ );
+ expect(getErrorMessage(schema.gt(5).safeParse(1))).toEqual(
+ "5보다 큰 값이어야 합니다."
+ );
+ expect(getErrorMessage(schema.gte(5).safeParse(1))).toEqual(
+ "5보다 크거나 같은 값이어야 합니다."
+ );
+ expect(getErrorMessage(schema.nonnegative().safeParse(-1))).toEqual(
+ "0보다 크거나 같은 값이어야 합니다."
+ );
+ expect(getErrorMessage(schema.nonpositive().safeParse(1))).toEqual(
+ "0보다 작거나 같은 값이어야 합니다."
+ );
+ expect(getErrorMessage(schema.negative().safeParse(1))).toEqual(
+ "0보다 작은 값이어야 합니다."
+ );
+ expect(getErrorMessage(schema.positive().safeParse(0))).toEqual(
+ "0보다 큰 값이어야 합니다."
+ );
+ expect(getErrorMessage(schema.finite().safeParse(Infinity))).toEqual(
+ "유한한 값이어야 합니다."
+ );
+});
+
+test("date parser error messages", async () => {
+ const testDate = new Date("2022-08-01");
+ const schema = z.date();
+
+ expect(getErrorMessage(schema.safeParse("2022-12-01"))).toEqual(
+ "날짜 타입 입력을 기대하였지만, 문자열 타입이 입력되었습니다."
+ );
+ expect(
+ getErrorMessage(schema.min(testDate).safeParse(new Date("2022-07-29")))
+ ).toEqual(
+ `${testDate.toLocaleDateString(LOCALE)}보다 이후이거나 같아야 합니다.`
+ );
+ expect(
+ getErrorMessage(schema.max(testDate).safeParse(new Date("2022-08-02")))
+ ).toEqual(
+ `${testDate.toLocaleDateString(LOCALE)}보다 이전이거나 같아야 합니다.`
+ );
+ try {
+ await schema.parseAsync(new Date("invalid"));
+ } catch (err) {
+ expect((err as z.ZodError).issues[0].message).toEqual(
+ "허용되지 않은 날짜 값 입니다."
+ );
+ }
+});
+
+test("array parser error messages", () => {
+ const schema = z.string().array();
+
+ expect(getErrorMessage(schema.safeParse(""))).toEqual(
+ "배열 타입 입력을 기대하였지만, 문자열 타입이 입력되었습니다."
+ );
+ expect(getErrorMessage(schema.min(5).safeParse([""]))).toEqual(
+ "5개 보다 많거나 같아야 합니다."
+ );
+ expect(getErrorMessage(schema.max(2).safeParse(["", "", ""]))).toEqual(
+ "2개 보다 작거나 같아야 합니다."
+ );
+ expect(getErrorMessage(schema.nonempty().safeParse([]))).toEqual(
+ "1개 보다 많거나 같아야 합니다."
+ );
+ expect(getErrorMessage(schema.length(2).safeParse([]))).toEqual(
+ "2개 이어야 합니다."
+ );
+});
+
+test("function parser error messages", () => {
+ const functionParse = z
+ .function(z.tuple([z.string()]), z.number())
+ .parse((a: any) => a);
+ expect(getErrorMessageFromZodError(() => functionParse(""))).toEqual(
+ "허용되지 않은 반환 타입입니다."
+ );
+ expect(getErrorMessageFromZodError(() => functionParse(1 as any))).toEqual(
+ "허용되지 않은 파라메터 타입입니다."
+ );
+});
+
+test("other parser error messages", () => {
+ expect(
+ getErrorMessage(
+ z
+ .intersection(
+ z.number(),
+ z.number().transform((x) => x + 1)
+ )
+ .safeParse(1234)
+ )
+ ).toEqual("교차 타입을 만족하지 않습니다.");
+ expect(getErrorMessage(z.literal(12).safeParse(""))).toEqual(
+ "허용되지 않은 리터럴 값 입니다. 입력 가능한 값은 12 입니다."
+ );
+ expect(getErrorMessage(z.enum(["A", "B", "C"]).safeParse("D"))).toEqual(
+ "'D'값은 허용되지 않습니다. 입력 가능한 값은 'A' | 'B' | 'C' 입니다."
+ );
+ expect(
+ getErrorMessage(
+ z
+ .object({ dog: z.string() })
+ .strict()
+ .safeParse({ dog: "", cat: "", rat: "" })
+ )
+ ).toEqual("객체 키 'cat', 'rat' 값은 허용되지 않습니다.");
+ expect(
+ getErrorMessage(
+ z
+ .discriminatedUnion("type", [
+ z.object({ type: z.literal("a"), a: z.string() }),
+ z.object({ type: z.literal("b"), b: z.string() }),
+ ])
+ .safeParse({ type: "c", c: "abc" })
+ )
+ ).toEqual("허용되지 않은 입력 값입니다. 입력 가능한 값은 'a' | 'b' 입니다.");
+ expect(
+ getErrorMessage(z.union([z.string(), z.number()]).safeParse([true]))
+ ).toEqual("허용되지 않은 입력 값입니다.");
+ expect(
+ getErrorMessage(
+ z
+ .string()
+ .refine(() => {
+ return false;
+ })
+ .safeParse("")
+ )
+ ).toEqual("허용되지 않은 입력 값 입니다.");
+});