diff --git a/examples/with-next-i18next/next-i18next.config.js b/examples/with-next-i18next/next-i18next.config.js
index bb771a2..b618a78 100644
--- a/examples/with-next-i18next/next-i18next.config.js
+++ b/examples/with-next-i18next/next-i18next.config.js
@@ -7,6 +7,7 @@ module.exports = {
defaultLocale: "en",
locales: [
"en",
+ "he",
"ja",
"fr",
"ar",
diff --git a/examples/with-next-i18next/pages/index.tsx b/examples/with-next-i18next/pages/index.tsx
index 6fcdd31..2df0f3e 100644
--- a/examples/with-next-i18next/pages/index.tsx
+++ b/examples/with-next-i18next/pages/index.tsx
@@ -78,6 +78,7 @@ export default function HookForm() {
+
diff --git a/examples/with-next-i18next/public/locales/he/common.json b/examples/with-next-i18next/public/locales/he/common.json
new file mode 100644
index 0000000..fff6f98
--- /dev/null
+++ b/examples/with-next-i18next/public/locales/he/common.json
@@ -0,0 +1,7 @@
+{
+ "username": "שם משתמש",
+ "username_placeholder": "ישראל ישראלי",
+ "email": "דואר אלקטרוני",
+ "favoriteNumber": "מספר אהוב",
+ "submit": "שלח"
+}
diff --git a/examples/with-next-i18next/public/locales/he/zod.json b/examples/with-next-i18next/public/locales/he/zod.json
new file mode 100644
index 0000000..9df923c
--- /dev/null
+++ b/examples/with-next-i18next/public/locales/he/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": "ערך לא תקין לסוג enum. ציפיתי ל-{{- options}}, קיבלתי '{{received}}'",
+ "invalid_arguments": "פרמטרים לפונקציה לא תקינים",
+ "invalid_return_type": "סוג ההחזרה של הפונקציה לא תקין",
+ "invalid_date": "תאריך לא תקין",
+ "custom": "קלט לא תקין",
+ "invalid_intersection_types": "לא ניתן למזג את הסוגים",
+ "not_multiple_of": "המספר חייב להיות מכפלה של {{multipleOf}}",
+ "not_finite": "המספר חייב להיות סופי",
+ "invalid_string": {
+ "email": "כתובת דוא\"ל לא תקינה",
+ "url": "כתובת אינטרנט לא תקינה",
+ "uuid": "מזהה UUID לא תקין",
+ "cuid": "מזהה CUID לא תקין",
+ "regex": "קלט לא תקין",
+ "datetime": "תאריך ושעה לא תקינים",
+ "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": "כתובת אינטרנט",
+ "uuid": "מזהה UUID",
+ "cuid": "מזהה CUID",
+ "regex": "קלט רגולרי",
+ "datetime": "תאריך ושעה"
+ },
+ "types": {
+ "function": "פונקציה",
+ "number": "מספר",
+ "string": "מחרוזת",
+ "nan": "NaN",
+ "integer": "מספר שלם",
+ "float": "מספר עשרוני",
+ "boolean": "בוליאני",
+ "date": "תאריך",
+ "bigint": "מספר גדול",
+ "undefined": "לא מוגדר",
+ "symbol": "סמל",
+ "null": "null",
+ "array": "מערך",
+ "object": "אובייקט",
+ "unknown": "לא ידוע",
+ "promise": "Promise",
+ "void": "void",
+ "never": "לעולם לא",
+ "map": "מפה",
+ "set": "סט"
+ }
+}
diff --git a/packages/core/locales/he/zod.json b/packages/core/locales/he/zod.json
new file mode 100644
index 0000000..9df923c
--- /dev/null
+++ b/packages/core/locales/he/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": "ערך לא תקין לסוג enum. ציפיתי ל-{{- options}}, קיבלתי '{{received}}'",
+ "invalid_arguments": "פרמטרים לפונקציה לא תקינים",
+ "invalid_return_type": "סוג ההחזרה של הפונקציה לא תקין",
+ "invalid_date": "תאריך לא תקין",
+ "custom": "קלט לא תקין",
+ "invalid_intersection_types": "לא ניתן למזג את הסוגים",
+ "not_multiple_of": "המספר חייב להיות מכפלה של {{multipleOf}}",
+ "not_finite": "המספר חייב להיות סופי",
+ "invalid_string": {
+ "email": "כתובת דוא\"ל לא תקינה",
+ "url": "כתובת אינטרנט לא תקינה",
+ "uuid": "מזהה UUID לא תקין",
+ "cuid": "מזהה CUID לא תקין",
+ "regex": "קלט לא תקין",
+ "datetime": "תאריך ושעה לא תקינים",
+ "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": "כתובת אינטרנט",
+ "uuid": "מזהה UUID",
+ "cuid": "מזהה CUID",
+ "regex": "קלט רגולרי",
+ "datetime": "תאריך ושעה"
+ },
+ "types": {
+ "function": "פונקציה",
+ "number": "מספר",
+ "string": "מחרוזת",
+ "nan": "NaN",
+ "integer": "מספר שלם",
+ "float": "מספר עשרוני",
+ "boolean": "בוליאני",
+ "date": "תאריך",
+ "bigint": "מספר גדול",
+ "undefined": "לא מוגדר",
+ "symbol": "סמל",
+ "null": "null",
+ "array": "מערך",
+ "object": "אובייקט",
+ "unknown": "לא ידוע",
+ "promise": "Promise",
+ "void": "void",
+ "never": "לעולם לא",
+ "map": "מפה",
+ "set": "סט"
+ }
+}
diff --git a/packages/core/tests/integrations/he.test.ts b/packages/core/tests/integrations/he.test.ts
new file mode 100644
index 0000000..d66ebbd
--- /dev/null
+++ b/packages/core/tests/integrations/he.test.ts
@@ -0,0 +1,211 @@
+import { test, expect, beforeAll } from "vitest";
+import { z } from "zod";
+import { init, getErrorMessage, getErrorMessageFromZodError } from "./helpers";
+
+const LOCALE = "he";
+
+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(
+ "כתובת אינטרנט לא תקינה"
+ );
+ 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(
+ "ערך לא תקין לסוג enum. ציפיתי ל-'A' | 'B' | 'C', קיבלתי 'D'"
+ );
+ 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("קלט לא תקין");
+});