ru.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import * as util from "../core/util.js";
  2. function getRussianPlural(count, one, few, many) {
  3. const absCount = Math.abs(count);
  4. const lastDigit = absCount % 10;
  5. const lastTwoDigits = absCount % 100;
  6. if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
  7. return many;
  8. }
  9. if (lastDigit === 1) {
  10. return one;
  11. }
  12. if (lastDigit >= 2 && lastDigit <= 4) {
  13. return few;
  14. }
  15. return many;
  16. }
  17. const Sizable = {
  18. string: {
  19. unit: {
  20. one: "символ",
  21. few: "символа",
  22. many: "символов",
  23. },
  24. verb: "иметь",
  25. },
  26. file: {
  27. unit: {
  28. one: "байт",
  29. few: "байта",
  30. many: "байт",
  31. },
  32. verb: "иметь",
  33. },
  34. array: {
  35. unit: {
  36. one: "элемент",
  37. few: "элемента",
  38. many: "элементов",
  39. },
  40. verb: "иметь",
  41. },
  42. set: {
  43. unit: {
  44. one: "элемент",
  45. few: "элемента",
  46. many: "элементов",
  47. },
  48. verb: "иметь",
  49. },
  50. };
  51. function getSizing(origin) {
  52. return Sizable[origin] ?? null;
  53. }
  54. export const parsedType = (data) => {
  55. const t = typeof data;
  56. switch (t) {
  57. case "number": {
  58. return Number.isNaN(data) ? "NaN" : "число";
  59. }
  60. case "object": {
  61. if (Array.isArray(data)) {
  62. return "массив";
  63. }
  64. if (data === null) {
  65. return "null";
  66. }
  67. if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) {
  68. return data.constructor.name;
  69. }
  70. }
  71. }
  72. return t;
  73. };
  74. const Nouns = {
  75. regex: "ввод",
  76. email: "email адрес",
  77. url: "URL",
  78. emoji: "эмодзи",
  79. uuid: "UUID",
  80. uuidv4: "UUIDv4",
  81. uuidv6: "UUIDv6",
  82. nanoid: "nanoid",
  83. guid: "GUID",
  84. cuid: "cuid",
  85. cuid2: "cuid2",
  86. ulid: "ULID",
  87. xid: "XID",
  88. ksuid: "KSUID",
  89. datetime: "ISO дата и время",
  90. date: "ISO дата",
  91. time: "ISO время",
  92. duration: "ISO длительность",
  93. ipv4: "IPv4 адрес",
  94. ipv6: "IPv6 адрес",
  95. cidrv4: "IPv4 диапазон",
  96. cidrv6: "IPv6 диапазон",
  97. base64: "строка в формате base64",
  98. base64url: "строка в формате base64url",
  99. json_string: "JSON строка",
  100. e164: "номер E.164",
  101. jwt: "JWT",
  102. template_literal: "ввод",
  103. };
  104. const error = (issue) => {
  105. switch (issue.code) {
  106. case "invalid_type":
  107. return `Неверный ввод: ожидалось ${issue.expected}, получено ${parsedType(issue.input)}`;
  108. case "invalid_value":
  109. if (issue.values.length === 1)
  110. return `Неверный ввод: ожидалось ${util.stringifyPrimitive(issue.values[0])}`;
  111. return `Неверный вариант: ожидалось одно из ${util.joinValues(issue.values, "|")}`;
  112. case "too_big": {
  113. const adj = issue.inclusive ? "<=" : "<";
  114. const sizing = getSizing(issue.origin);
  115. if (sizing) {
  116. const maxValue = Number(issue.maximum);
  117. const unit = getRussianPlural(maxValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
  118. return `Слишком большое значение: ожидалось, что ${issue.origin ?? "значение"} будет иметь ${adj}${issue.maximum.toString()} ${unit}`;
  119. }
  120. return `Слишком большое значение: ожидалось, что ${issue.origin ?? "значение"} будет ${adj}${issue.maximum.toString()}`;
  121. }
  122. case "too_small": {
  123. const adj = issue.inclusive ? ">=" : ">";
  124. const sizing = getSizing(issue.origin);
  125. if (sizing) {
  126. const minValue = Number(issue.minimum);
  127. const unit = getRussianPlural(minValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
  128. return `Слишком маленькое значение: ожидалось, что ${issue.origin} будет иметь ${adj}${issue.minimum.toString()} ${unit}`;
  129. }
  130. return `Слишком маленькое значение: ожидалось, что ${issue.origin} будет ${adj}${issue.minimum.toString()}`;
  131. }
  132. case "invalid_format": {
  133. const _issue = issue;
  134. if (_issue.format === "starts_with")
  135. return `Неверная строка: должна начинаться с "${_issue.prefix}"`;
  136. if (_issue.format === "ends_with")
  137. return `Неверная строка: должна заканчиваться на "${_issue.suffix}"`;
  138. if (_issue.format === "includes")
  139. return `Неверная строка: должна содержать "${_issue.includes}"`;
  140. if (_issue.format === "regex")
  141. return `Неверная строка: должна соответствовать шаблону ${_issue.pattern}`;
  142. return `Неверный ${Nouns[_issue.format] ?? issue.format}`;
  143. }
  144. case "not_multiple_of":
  145. return `Неверное число: должно быть кратным ${issue.divisor}`;
  146. case "unrecognized_keys":
  147. return `Нераспознанн${issue.keys.length > 1 ? "ые" : "ый"} ключ${issue.keys.length > 1 ? "и" : ""}: ${util.joinValues(issue.keys, ", ")}`;
  148. case "invalid_key":
  149. return `Неверный ключ в ${issue.origin}`;
  150. case "invalid_union":
  151. return "Неверные входные данные";
  152. case "invalid_element":
  153. return `Неверное значение в ${issue.origin}`;
  154. default:
  155. return `Неверные входные данные`;
  156. }
  157. };
  158. export { error };
  159. export default function () {
  160. return {
  161. localeError: error,
  162. };
  163. }