diff --git a/examples/with-next-i18next/next-i18next.config.js b/examples/with-next-i18next/next-i18next.config.js index 3898752..65f68b3 100644 --- a/examples/with-next-i18next/next-i18next.config.js +++ b/examples/with-next-i18next/next-i18next.config.js @@ -29,6 +29,7 @@ module.exports = { "ro", "uk-UA", "uz", + "hr-HR", "fi", ], }, diff --git a/examples/with-next-i18next/pages/index.tsx b/examples/with-next-i18next/pages/index.tsx index a48a7c8..9574225 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/hr-HR/common.json b/examples/with-next-i18next/public/locales/hr-HR/common.json new file mode 100644 index 0000000..f6d56e7 --- /dev/null +++ b/examples/with-next-i18next/public/locales/hr-HR/common.json @@ -0,0 +1,7 @@ +{ + "username": "Korisničko ime", + "username_placeholder": "Ivan Horvat", + "email": "Email", + "favoriteNumber": "Najdraži broj", + "submit": "Pošalji" +} diff --git a/examples/with-next-i18next/public/locales/hr-HR/zod.json b/examples/with-next-i18next/public/locales/hr-HR/zod.json new file mode 100644 index 0000000..4b92a69 --- /dev/null +++ b/examples/with-next-i18next/public/locales/hr-HR/zod.json @@ -0,0 +1,112 @@ +{ + "errors": { + "invalid_type": "Očekivano: {{expected}}, uneseno: {{received}}", + "invalid_type_received_undefined": "Obvezno polje", + "invalid_literal": "Neispravna literalna vrijednost, očekivano {{expected}}", + "unrecognized_keys": "Neprepoznat(i) ključ(evi) u objektu: {{- keys}}", + "invalid_union": "Neispravan unos", + "invalid_union_discriminator": "Neispravna vrijednost diskriminatora. Očekivano {{- options}}", + "invalid_enum_value": "Neispravna vrijednost enumeracije. Očekivano {{- options}}, uneseno '{{received}}'", + "invalid_arguments": "Neispravni argumenti funkcije", + "invalid_return_type": "Neispravan tip povratne vrijednosti", + "invalid_date": "Neispravan datum", + "custom": "Neispravan unos", + "invalid_intersection_types": "Rezultati presjecanja nisu se mogli spojiti", + "not_multiple_of": "Broj mora biti višekratnik od {{multipleOf}}", + "not_finite": "Broj mora biti konačan", + "invalid_string": { + "email": "Neispravan {{validation}}", + "url": "Neispravan {{validation}}", + "uuid": "Neispravan {{validation}}", + "cuid": "Neispravan {{validation}}", + "regex": "Neispravno", + "datetime": "Neispravan {{validation}}", + "startsWith": "Neispravan unos: mora započeti s \"{{startsWith}}\"", + "endsWith": "Neispravan unos: mora završiti s \"{{endsWith}}\"" + }, + "too_small": { + "array": { + "exact": "Niz mora sadržavati točno {{minimum}} element(a)", + "inclusive": "Niz mora sadržavati barem {{minimum}} element(a)", + "not_inclusive": "Niz mora sadržavati više od {{minimum}} element(a)" + }, + "string": { + "exact": "Tekst mora sadržavati točno {{minimum}} znak(ova)", + "inclusive": "Tekst mora sadržavati barem {{minimum}} znak(ova)", + "not_inclusive": "Tekst mora sadržavati više od {{minimum}} znak(ova)" + }, + "number": { + "exact": "Broj mora biti točno {{minimum}}", + "inclusive": "Broj mora biti veći od ili jednak {{minimum}}", + "not_inclusive": "Broj mora biti veći od {{minimum}}" + }, + "set": { + "exact": "Neispravan unos", + "inclusive": "Neispravan unos", + "not_inclusive": "Neispravan unos" + }, + "date": { + "exact": "Datum mora biti točno {{- minimum, datetime}}", + "inclusive": "Datum mora biti veći od ili jednak {{- minimum, datetime}}", + "not_inclusive": "Datum mora biti veći od {{- minimum, datetime}}" + } + }, + "too_big": { + "array": { + "exact": "Niz mora sadržavati točno {{maximum}} element(a)", + "inclusive": "Niz mora sadržavati najviše {{maximum}} element(a)", + "not_inclusive": "Niz mora sadržavati manje od {{maximum}} element(a)" + }, + "string": { + "exact": "Tekst mora sadržavati točno {{maximum}} znak(ova)", + "inclusive": "Tekst mora sadržavati najviše {{maximum}} znak(ova)", + "not_inclusive": "Tekst mora sadržavati manje od {{maximum}} znak(ova)" + }, + "number": { + "exact": "Broj mora biti točno {{maximum}}", + "inclusive": "Broj mora biti manji od ili jednak {{maximum}}", + "not_inclusive": "Broj mora biti manji od {{maximum}}" + }, + "set": { + "exact": "Neispravan unos", + "inclusive": "Neispravan unos", + "not_inclusive": "Neispravan unos" + }, + "date": { + "exact": "Datum mora biti točno {{- maximum, datetime}}", + "inclusive": "Datum mora biti manji od ili jednak {{- maximum, datetime}}", + "not_inclusive": "Datum mora biti manji od {{- maximum, datetime}}" + } + } + }, + "validations": { + "email": "email", + "url": "url", + "uuid": "uuid", + "cuid": "cuid", + "regex": "regex", + "datetime": "datum i vrijeme" + }, + "types": { + "function": "funkcija", + "number": "broj", + "string": "tekst", + "nan": "nan", + "integer": "broj", + "float": "decimalni broj", + "boolean": "boolean", + "date": "datum", + "bigint": "broj", + "undefined": "nedefinirana vrijednost", + "symbol": "simbol", + "null": "null", + "array": "niz", + "object": "objekt", + "unknown": "nepoznato", + "promise": "promise", + "void": "void", + "never": "nikad", + "map": "mapa", + "set": "set" + } +} diff --git a/packages/core/locales/hr-HR/zod.json b/packages/core/locales/hr-HR/zod.json new file mode 100644 index 0000000..4b92a69 --- /dev/null +++ b/packages/core/locales/hr-HR/zod.json @@ -0,0 +1,112 @@ +{ + "errors": { + "invalid_type": "Očekivano: {{expected}}, uneseno: {{received}}", + "invalid_type_received_undefined": "Obvezno polje", + "invalid_literal": "Neispravna literalna vrijednost, očekivano {{expected}}", + "unrecognized_keys": "Neprepoznat(i) ključ(evi) u objektu: {{- keys}}", + "invalid_union": "Neispravan unos", + "invalid_union_discriminator": "Neispravna vrijednost diskriminatora. Očekivano {{- options}}", + "invalid_enum_value": "Neispravna vrijednost enumeracije. Očekivano {{- options}}, uneseno '{{received}}'", + "invalid_arguments": "Neispravni argumenti funkcije", + "invalid_return_type": "Neispravan tip povratne vrijednosti", + "invalid_date": "Neispravan datum", + "custom": "Neispravan unos", + "invalid_intersection_types": "Rezultati presjecanja nisu se mogli spojiti", + "not_multiple_of": "Broj mora biti višekratnik od {{multipleOf}}", + "not_finite": "Broj mora biti konačan", + "invalid_string": { + "email": "Neispravan {{validation}}", + "url": "Neispravan {{validation}}", + "uuid": "Neispravan {{validation}}", + "cuid": "Neispravan {{validation}}", + "regex": "Neispravno", + "datetime": "Neispravan {{validation}}", + "startsWith": "Neispravan unos: mora započeti s \"{{startsWith}}\"", + "endsWith": "Neispravan unos: mora završiti s \"{{endsWith}}\"" + }, + "too_small": { + "array": { + "exact": "Niz mora sadržavati točno {{minimum}} element(a)", + "inclusive": "Niz mora sadržavati barem {{minimum}} element(a)", + "not_inclusive": "Niz mora sadržavati više od {{minimum}} element(a)" + }, + "string": { + "exact": "Tekst mora sadržavati točno {{minimum}} znak(ova)", + "inclusive": "Tekst mora sadržavati barem {{minimum}} znak(ova)", + "not_inclusive": "Tekst mora sadržavati više od {{minimum}} znak(ova)" + }, + "number": { + "exact": "Broj mora biti točno {{minimum}}", + "inclusive": "Broj mora biti veći od ili jednak {{minimum}}", + "not_inclusive": "Broj mora biti veći od {{minimum}}" + }, + "set": { + "exact": "Neispravan unos", + "inclusive": "Neispravan unos", + "not_inclusive": "Neispravan unos" + }, + "date": { + "exact": "Datum mora biti točno {{- minimum, datetime}}", + "inclusive": "Datum mora biti veći od ili jednak {{- minimum, datetime}}", + "not_inclusive": "Datum mora biti veći od {{- minimum, datetime}}" + } + }, + "too_big": { + "array": { + "exact": "Niz mora sadržavati točno {{maximum}} element(a)", + "inclusive": "Niz mora sadržavati najviše {{maximum}} element(a)", + "not_inclusive": "Niz mora sadržavati manje od {{maximum}} element(a)" + }, + "string": { + "exact": "Tekst mora sadržavati točno {{maximum}} znak(ova)", + "inclusive": "Tekst mora sadržavati najviše {{maximum}} znak(ova)", + "not_inclusive": "Tekst mora sadržavati manje od {{maximum}} znak(ova)" + }, + "number": { + "exact": "Broj mora biti točno {{maximum}}", + "inclusive": "Broj mora biti manji od ili jednak {{maximum}}", + "not_inclusive": "Broj mora biti manji od {{maximum}}" + }, + "set": { + "exact": "Neispravan unos", + "inclusive": "Neispravan unos", + "not_inclusive": "Neispravan unos" + }, + "date": { + "exact": "Datum mora biti točno {{- maximum, datetime}}", + "inclusive": "Datum mora biti manji od ili jednak {{- maximum, datetime}}", + "not_inclusive": "Datum mora biti manji od {{- maximum, datetime}}" + } + } + }, + "validations": { + "email": "email", + "url": "url", + "uuid": "uuid", + "cuid": "cuid", + "regex": "regex", + "datetime": "datum i vrijeme" + }, + "types": { + "function": "funkcija", + "number": "broj", + "string": "tekst", + "nan": "nan", + "integer": "broj", + "float": "decimalni broj", + "boolean": "boolean", + "date": "datum", + "bigint": "broj", + "undefined": "nedefinirana vrijednost", + "symbol": "simbol", + "null": "null", + "array": "niz", + "object": "objekt", + "unknown": "nepoznato", + "promise": "promise", + "void": "void", + "never": "nikad", + "map": "mapa", + "set": "set" + } +} diff --git a/packages/core/tests/integrations/hr-HR.test.ts b/packages/core/tests/integrations/hr-HR.test.ts new file mode 100644 index 0000000..4c30e74 --- /dev/null +++ b/packages/core/tests/integrations/hr-HR.test.ts @@ -0,0 +1,209 @@ +import { test, expect, beforeAll } from "vitest"; +import { z } from "zod"; +import { init, getErrorMessage, getErrorMessageFromZodError } from "./helpers"; + +const LOCALE = "hr-HR"; + +beforeAll(async () => { + await init(LOCALE); +}); + +test("string parser error messages", () => { + const schema = z.string(); + + expect(getErrorMessage(schema.safeParse(undefined))).toEqual("Obvezno polje"); + expect(getErrorMessage(schema.safeParse(1))).toEqual( + "Očekivano: tekst, uneseno: broj" + ); + expect(getErrorMessage(schema.safeParse(true))).toEqual( + "Očekivano: tekst, uneseno: boolean" + ); + expect(getErrorMessage(schema.safeParse(Date))).toEqual( + "Očekivano: tekst, uneseno: funkcija" + ); + expect(getErrorMessage(schema.safeParse(new Date()))).toEqual( + "Očekivano: tekst, uneseno: datum" + ); + expect(getErrorMessage(schema.email().safeParse(""))).toEqual( + "Neispravan email" + ); + expect(getErrorMessage(schema.url().safeParse(""))).toEqual("Neispravan url"); + expect(getErrorMessage(schema.regex(/aaa/).safeParse(""))).toEqual( + "Neispravno" + ); + expect(getErrorMessage(schema.startsWith("foo").safeParse(""))).toEqual( + 'Neispravan unos: mora započeti s "foo"' + ); + expect(getErrorMessage(schema.endsWith("bar").safeParse(""))).toEqual( + 'Neispravan unos: mora završiti s "bar"' + ); + expect(getErrorMessage(schema.min(5).safeParse("a"))).toEqual( + "Tekst mora sadržavati barem 5 znak(ova)" + ); + expect(getErrorMessage(schema.max(5).safeParse("abcdef"))).toEqual( + "Tekst mora sadržavati najviše 5 znak(ova)" + ); + expect(getErrorMessage(schema.length(5).safeParse("abcdef"))).toEqual( + "Tekst mora sadržavati točno 5 znak(ova)" + ); + expect( + getErrorMessage(schema.datetime().safeParse("2020-01-01T00:00:00+02:00")) + ).toEqual("Neispravan datum i vrijeme"); +}); + +test("number parser error messages", () => { + const schema = z.number(); + + expect(getErrorMessage(schema.safeParse(undefined))).toEqual("Obvezno polje"); + expect(getErrorMessage(schema.safeParse(""))).toEqual( + "Očekivano: broj, uneseno: tekst" + ); + expect(getErrorMessage(schema.safeParse(null))).toEqual( + "Očekivano: broj, uneseno: null" + ); + expect(getErrorMessage(schema.safeParse(NaN))).toEqual( + "Očekivano: broj, uneseno: nan" + ); + expect(getErrorMessage(schema.int().safeParse(0.1))).toEqual( + "Očekivano: broj, uneseno: decimalni broj" + ); + expect(getErrorMessage(schema.multipleOf(5).safeParse(2))).toEqual( + "Broj mora biti višekratnik od 5" + ); + expect(getErrorMessage(schema.step(0.1).safeParse(0.0001))).toEqual( + "Broj mora biti višekratnik od 0.1" + ); + expect(getErrorMessage(schema.lt(5).safeParse(10))).toEqual( + "Broj mora biti manji od 5" + ); + expect(getErrorMessage(schema.lte(5).safeParse(10))).toEqual( + "Broj mora biti manji od ili jednak 5" + ); + expect(getErrorMessage(schema.gt(5).safeParse(1))).toEqual( + "Broj mora biti veći od 5" + ); + expect(getErrorMessage(schema.gte(5).safeParse(1))).toEqual( + "Broj mora biti veći od ili jednak 5" + ); + expect(getErrorMessage(schema.nonnegative().safeParse(-1))).toEqual( + "Broj mora biti veći od ili jednak 0" + ); + expect(getErrorMessage(schema.nonpositive().safeParse(1))).toEqual( + "Broj mora biti manji od ili jednak 0" + ); + expect(getErrorMessage(schema.negative().safeParse(1))).toEqual( + "Broj mora biti manji od 0" + ); + expect(getErrorMessage(schema.positive().safeParse(0))).toEqual( + "Broj mora biti veći od 0" + ); + expect(getErrorMessage(schema.finite().safeParse(Infinity))).toEqual( + "Broj mora biti konačan" + ); +}); + +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( + "Očekivano: datum, uneseno: tekst" + ); + expect( + getErrorMessage(schema.min(testDate).safeParse(new Date("2022-07-29"))) + ).toEqual( + `Datum mora biti veći od ili jednak ${testDate.toLocaleDateString(LOCALE)}` + ); + expect( + getErrorMessage(schema.max(testDate).safeParse(new Date("2022-08-02"))) + ).toEqual( + `Datum mora biti manji od ili jednak ${testDate.toLocaleDateString(LOCALE)}` + ); + try { + await schema.parseAsync(new Date("invalid")); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Neispravan datum"); + } +}); + +test("array parser error messages", () => { + const schema = z.string().array(); + + expect(getErrorMessage(schema.safeParse(""))).toEqual( + "Očekivano: niz, uneseno: tekst" + ); + expect(getErrorMessage(schema.min(5).safeParse([""]))).toEqual( + "Niz mora sadržavati barem 5 element(a)" + ); + expect(getErrorMessage(schema.max(2).safeParse(["", "", ""]))).toEqual( + "Niz mora sadržavati najviše 2 element(a)" + ); + expect(getErrorMessage(schema.nonempty().safeParse([]))).toEqual( + "Niz mora sadržavati barem 1 element(a)" + ); + expect(getErrorMessage(schema.length(2).safeParse([]))).toEqual( + "Niz mora sadržavati točno 2 element(a)" + ); +}); + +test("function parser error messages", () => { + const functionParse = z + .function(z.tuple([z.string()]), z.number()) + .parse((a: any) => a); + expect(getErrorMessageFromZodError(() => functionParse(""))).toEqual( + "Neispravan tip povratne vrijednosti" + ); + expect(getErrorMessageFromZodError(() => functionParse(1 as any))).toEqual( + "Neispravni argumenti funkcije" + ); +}); + +test("other parser error messages", () => { + expect( + getErrorMessage( + z + .intersection( + z.number(), + z.number().transform((x) => x + 1) + ) + .safeParse(1234) + ) + ).toEqual("Rezultati presjecanja nisu se mogli spojiti"); + expect(getErrorMessage(z.literal(12).safeParse(""))).toEqual( + "Neispravna literalna vrijednost, očekivano 12" + ); + expect(getErrorMessage(z.enum(["A", "B", "C"]).safeParse("D"))).toEqual( + "Neispravna vrijednost enumeracije. Očekivano 'A' | 'B' | 'C', uneseno 'D'" + ); + expect( + getErrorMessage( + z + .object({ dog: z.string() }) + .strict() + .safeParse({ dog: "", cat: "", rat: "" }) + ) + ).toEqual("Neprepoznat(i) ključ(evi) u objektu: '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("Neispravna vrijednost diskriminatora. Očekivano 'a' | 'b'"); + expect( + getErrorMessage(z.union([z.string(), z.number()]).safeParse([true])) + ).toEqual("Neispravan unos"); + expect( + getErrorMessage( + z + .string() + .refine(() => { + return false; + }) + .safeParse("") + ) + ).toEqual("Neispravan unos"); +});