diff --git a/packages/core/src/locales.ts b/packages/core/src/locales.ts index b483c9f89f..1edc830874 100644 --- a/packages/core/src/locales.ts +++ b/packages/core/src/locales.ts @@ -4,6 +4,7 @@ import be from "./locales/be.js"; import cs from "./locales/cs.js"; import en from "./locales/en.js"; import es from "./locales/es.js"; +import fa from "./locales/fa.js"; import ko from "./locales/ko.js"; import ota from "./locales/ota.js"; import ru from "./locales/ru.js"; @@ -21,4 +22,4 @@ import fr from "./locales/fr.js"; import ja from "./locales/ja.js"; import pt from "./locales/pt.js"; -export { ar, az, be, cs, es, en, fi, fr, he, hu, id, it, ja, ko, ota, pl, pt, ru, tr, ua, vi, zhCN }; +export { ar, az, be, cs, es, en, fa, fi, fr, he, hu, id, it, ja, ko, ota, pl, pt, ru, tr, ua, vi, zhCN }; diff --git a/packages/core/src/locales/fa.ts b/packages/core/src/locales/fa.ts new file mode 100644 index 0000000000..123ed11ca9 --- /dev/null +++ b/packages/core/src/locales/fa.ts @@ -0,0 +1,134 @@ +import type { $ZodStringFormats } from "../checks.js"; +import type * as errors from "../errors.js"; +import * as util from "../util.js"; + +const Sizable: Record = { + string: { unit: "کاراکتر", verb: "داشته باشد" }, + file: { unit: "بایت", verb: "داشته باشد" }, + array: { unit: "آیتم", verb: "داشته باشد" }, + set: { unit: "آیتم", verb: "داشته باشد" }, +}; + +function getSizing(origin: string): { unit: string; verb: string } | null { + return Sizable[origin] ?? null; +} + +export const parsedType = (data: any): string => { + const t = typeof data; + + switch (t) { + case "number": { + return Number.isNaN(data) ? "NaN" : "عدد"; + } + case "object": { + if (Array.isArray(data)) { + return "آرایه"; + } + if (data === null) { + return "null"; + } + + if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { + return data.constructor.name; + } + } + } + return t; +}; + +const Nouns: { + [k in $ZodStringFormats | (string & {})]?: string; +} = { + regex: "ورودی", + email: "آدرس ایمیل", + url: "URL", + emoji: "ایموجی", + uuid: "UUID", + uuidv4: "UUIDv4", + uuidv6: "UUIDv6", + nanoid: "nanoid", + guid: "GUID", + cuid: "cuid", + cuid2: "cuid2", + ulid: "ULID", + xid: "XID", + ksuid: "KSUID", + datetime: "تاریخ و زمان ایزو", + date: "تاریخ ایزو", + time: "زمان ایزو", + duration: "مدت زمان ایزو", + ipv4: "IPv4 آدرس", + ipv6: "IPv6 آدرس", + cidrv4: "IPv4 دامنه", + cidrv6: "IPv6 دامنه", + base64: "base64-encoded رشته", + base64url: "base64url-encoded رشته", + json_string: "JSON رشته", + e164: "E.164 عدد", + jwt: "JWT", + template_literal: "ورودی", +}; + +const error: errors.$ZodErrorMap = (issue) => { + switch (issue.code) { + case "invalid_type": + return `ورودی نامعتبر: می‌بایست ${issue.expected} می‌بود، ${parsedType(issue.input)} دریافت شد`; + case "invalid_value": + if (issue.values.length === 1) { + return `ورودی نامعتبر: می‌بایست ${util.stringifyPrimitive(issue.values[0])} می‌بود`; + } + return `گزینه نامعتبر: می‌بایست یکی از ${util.joinValues(issue.values, "|")} می‌بود`; + case "too_big": { + const adj = issue.inclusive ? "<=" : "<"; + const sizing = getSizing(issue.origin); + if (sizing) { + return `خیلی بزرگ: ${issue.origin ?? "مقدار"} باید ${adj}${issue.maximum.toString()} ${sizing.unit ?? "عنصر"} باشد`; + } + return `خیلی بزرگ: ${issue.origin ?? "مقدار"} باید ${adj}${issue.maximum.toString()} باشد`; + } + case "too_small": { + const adj = issue.inclusive ? ">=" : ">"; + const sizing = getSizing(issue.origin); + if (sizing) { + return `خیلی کوچک: ${issue.origin} باید ${adj}${issue.minimum.toString()} ${sizing.unit} باشد`; + } + return `خیلی کوچک: ${issue.origin} باید ${adj}${issue.minimum.toString()} باشد`; + } + case "invalid_format": { + const _issue = issue as errors.$ZodStringFormatIssues; + if (_issue.format === "starts_with") { + return `رشته نامعتبر: باید با "${_issue.prefix}" شروع شود`; + } + if (_issue.format === "ends_with") { + return `رشته نامعتبر: باید با "${_issue.suffix}" تمام شود`; + } + if (_issue.format === "includes") { + return `رشته نامعتبر: باید شامل "${_issue.includes}" باشد`; + } + if (_issue.format === "regex") { + return `رشته نامعتبر: باید با الگوی ${_issue.pattern} مطابقت داشته باشد`; + } + return `${Nouns[_issue.format] ?? issue.format} نامعتبر`; + } + case "not_multiple_of": + return `عدد نامعتبر: باید مضرب ${issue.divisor} باشد`; + case "unrecognized_keys": + return `کلید${issue.keys.length > 1 ? "های" : ""} ناشناس: ${util.joinValues(issue.keys, ", ")}`; + case "invalid_key": + return `کلید ناشناس در ${issue.origin}`; + case "invalid_union": + return `ورودی نامعتبر`; + case "invalid_element": + return `مقدار نامعتبر در ${issue.origin}`; + default: + return `ورودی نامعتبر`; + } +}; + +export { error }; + +export default function (): { localeError: errors.$ZodErrorMap } { + return { + localeError: error, + }; +} diff --git a/packages/docs/content/error-customization.mdx b/packages/docs/content/error-customization.mdx index 64444b35e3..7b8a8225f2 100644 --- a/packages/docs/content/error-customization.mdx +++ b/packages/docs/content/error-customization.mdx @@ -359,6 +359,7 @@ The following locales are available: - `az` — Azerbaijani - `be` — Belarusian - `en` — English +- `fa` — Farsi - `ko` — Korean - `ota` — Türkî - `es` — Spanish