locales.ts 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import type { FormKitValidationMessages } from '@formkit/validation'
  3. import { createMessageName } from '@formkit/validation'
  4. import type { FormKitLocale } from '@formkit/i18n'
  5. import { i18n } from '#shared/i18n.ts'
  6. import { commaSeparatedList, order } from '#shared/utils/formatter.ts'
  7. import type { ComputedRef } from 'vue'
  8. interface FormKitLocaleExtended extends FormKitLocale {
  9. validation: FormKitValidationMessages
  10. }
  11. // TODO: Use translateLabel for all validation messages if we stay with the labels inside of the messages. It's a open
  12. // question if we want use them inside of the messages.
  13. const loadLocales = (): FormKitLocaleExtended => {
  14. return {
  15. ui: {
  16. /**
  17. * Shown on a button for adding additional items.
  18. */
  19. add: () => i18n.t('Add'),
  20. /**
  21. * Shown when a button to remove items is visible.
  22. */
  23. remove: () => i18n.t('Remove'),
  24. /**
  25. * Shown when there are multiple items to remove at the same time.
  26. */
  27. removeAll: () => i18n.t('Remove all'),
  28. /**
  29. * Shown when all fields are not filled out correctly.
  30. */
  31. incomplete: () =>
  32. i18n.t('Sorry, not all fields are filled out correctly.'),
  33. /**
  34. * Shown in a button inside a form to submit the form.
  35. */
  36. submit: () => i18n.t('Submit'),
  37. /**
  38. * Shown when no files are selected.
  39. */
  40. noFiles: () => i18n.t('No file chosen.'),
  41. /**
  42. * Shown on buttons that move fields up in a list.
  43. */
  44. moveUp: () => i18n.t('Move up'),
  45. /**
  46. * Shown on buttons that move fields down in a list.
  47. */
  48. moveDown: () => i18n.t('Move down'),
  49. /**
  50. * Shown when something is actively loading.
  51. */
  52. isLoading: () => i18n.t('Loading…'),
  53. /**
  54. * Shown when there is more to load.
  55. */
  56. loadMore: () => i18n.t('Load more'),
  57. /**
  58. * Show on buttons that navigate state forward
  59. */
  60. next: () => i18n.t('Next'),
  61. /**
  62. * Show on buttons that navigate state backward
  63. */
  64. prev: () => i18n.t('Previous'),
  65. /**
  66. * Shown when adding all values.
  67. */
  68. addAllValues: () => i18n.t('Add all values'),
  69. /**
  70. * Shown when adding selected values.
  71. */
  72. addSelectedValues: () => i18n.t('Add selected values'),
  73. /**
  74. * Shown when removing all values.
  75. */
  76. removeAllValues: () => i18n.t('Remove all values'),
  77. /**
  78. * Shown when removing selected values.
  79. */
  80. removeSelectedValues: () => i18n.t('Remove selected values'),
  81. /**
  82. * Shown when there is a date to choose.
  83. */
  84. chooseDate: () => i18n.t('Choose date'),
  85. /**
  86. * Shown when there is a date to change.
  87. */
  88. changeDate: () => i18n.t('Change date'),
  89. /**
  90. * Shown above error summaries when someone attempts to submit a form with
  91. * errors and the developer has implemented `<FormKitSummary />`.
  92. */
  93. summaryHeader: () => i18n.t('There were errors in your form.'),
  94. /*
  95. * Shown when there is something to close
  96. */
  97. close: () => i18n.t('Close'),
  98. /**
  99. * Shown when there is something to open.
  100. */
  101. open: () => i18n.t('Open'),
  102. },
  103. validation: {
  104. /**
  105. * The value is not an accepted value.
  106. * @see {@link https://docs.formkit.com/essentials/validation#accepted}
  107. */
  108. accepted({ name }) {
  109. /* <i18n case="Shown when the user-provided value is not a valid 'accepted' value."> */
  110. return i18n.t('Please accept the %s.', name)
  111. /* </i18n> */
  112. },
  113. /**
  114. * The value is not letter and/or spaces
  115. * @see {@link https://docs.formkit.com/essentials/validation#alpha-spaces}
  116. */
  117. alpha_spaces() {
  118. /* <i18n case="Shown when the user-provided value contains non-alphabetical and non-space characters."> */
  119. return i18n.t('This field can only contain letters and spaces.')
  120. /* </i18n> */
  121. },
  122. /**
  123. * The date is not after
  124. * @see {@link https://docs.formkit.com/essentials/validation#date-after}
  125. */
  126. date_after({ args }) {
  127. if (Array.isArray(args) && args.length) {
  128. /* <i18n case="Shown when the user-provided date is not after the date supplied to the rule."> */
  129. return i18n.t(
  130. 'This field must have a value that is after %s.',
  131. i18n.date(args[0]),
  132. )
  133. /* </i18n> */
  134. }
  135. /* <i18n case="Shown when the user-provided date is not after today's date, since no date was supplied to the rule."> */
  136. return i18n.t('This field must have a value that is in the future.')
  137. /* </i18n> */
  138. },
  139. /**
  140. * The value is not a letter.
  141. * @see {@link https://docs.formkit.com/essentials/validation#alpha}
  142. */
  143. alpha() {
  144. /* <i18n case="Shown when the user-provided value contains non-alphabetical characters."> */
  145. return i18n.t('This field can only contain alphabetical characters.')
  146. /* </i18n> */
  147. },
  148. /**
  149. * The value is not alphanumeric
  150. * @see {@link https://docs.formkit.com/essentials/validation#alphanumeric}
  151. */
  152. alphanumeric() {
  153. /* <i18n case="Shown when the user-provided value contains non-alphanumeric characters."> */
  154. return i18n.t('This field can only contain letters and numbers.')
  155. /* </i18n> */
  156. },
  157. /**
  158. * The value have no letter.
  159. * @see {@link https://formkit.com/essentials/validation#contains_alpha}
  160. */
  161. contains_alpha() {
  162. /* <i18n case="Shown when the user-provided value contains only non-alphabetical characters."> */
  163. return i18n.t('This field must contain alphabetical characters.')
  164. /* </i18n> */
  165. },
  166. /**
  167. * The value have no alphanumeric
  168. * @see {@link https://formkit.com/essentials/validation#contains_alphanumeric}
  169. */
  170. contains_alphanumeric() {
  171. /* <i18n case="Shown when the user-provided value contains only non-alphanumeric characters."> */
  172. return i18n.t('This field must contain letters or numbers.')
  173. /* </i18n> */
  174. },
  175. /**
  176. * The value have no letter and/or spaces
  177. * @see {@link https://formkit.com/essentials/validation#contains_alpha-spaces}
  178. */
  179. contains_alpha_spaces() {
  180. /* <i18n case="Shown when the user-provided value contains only non-alphabetical and non-space characters."> */
  181. return i18n.t('This field must contain letters or spaces.')
  182. /* </i18n> */
  183. },
  184. /**
  185. * The value have no symbol
  186. * @see {@link https://formkit.com/essentials/validation#contains_symbol}
  187. */
  188. contains_symbol() {
  189. /* <i18n case="Shown when the user-provided value contains only alphanumeric and space characters."> */
  190. return i18n.t('This field must contain a symbol.')
  191. /* </i18n> */
  192. },
  193. /**
  194. * The value have no uppercase
  195. * @see {@link https://formkit.com/essentials/validation#contains_uppercase}
  196. */
  197. contains_uppercase() {
  198. /* <i18n case="Shown when the user-provided value contains only non-alphabetical-uppercase characters."> */
  199. return i18n.t('This field must contain an uppercase letter.')
  200. /* </i18n> */
  201. },
  202. /**
  203. * The value have no lowercase
  204. * @see {@link https://formkit.com/essentials/validation#contains_lowercase}
  205. */
  206. contains_lowercase() {
  207. /* <i18n case="Shown when the user-provided value contains only non-alphabetical-lowercase characters."> */
  208. return i18n.t('This field must contain a lowercase letter.')
  209. /* </i18n> */
  210. },
  211. /**
  212. * The value have no numeric
  213. * @see {@link https://formkit.com/essentials/validation#contains_numeric}
  214. */
  215. contains_numeric() {
  216. /* <i18n case="Shown when the user-provided value have no numeric."> */
  217. return i18n.t('This field must contain numbers.')
  218. /* </i18n> */
  219. },
  220. /**
  221. * The value is not symbol
  222. * @see {@link https://formkit.com/essentials/validation#symbol}
  223. */
  224. symbol() {
  225. /* <i18n case="Shown when the user-provided value contains alphanumeric and space characters."> */
  226. return i18n.t('This field must be a symbol.')
  227. /* </i18n> */
  228. },
  229. /**
  230. * The value is not uppercase
  231. * @see {@link https://formkit.com/essentials/validation#uppercase}
  232. */
  233. uppercase() {
  234. /* <i18n case="Shown when the user-provided value contains non-alphabetical-uppercase characters."> */
  235. return i18n.t('This field can only contain uppercase letters.')
  236. /* </i18n> */
  237. },
  238. /**
  239. * The value is not lowercase
  240. * @see {@link https://formkit.com/essentials/validation#lowercase}
  241. */
  242. lowercase() {
  243. /* <i18n case="Shown when the user-provided value contains non-alphabetical-lowercase characters."> */
  244. return i18n.t('This field can only contain lowercase letters.')
  245. /* </i18n> */
  246. },
  247. /**
  248. * The date is not before
  249. * @see {@link https://docs.formkit.com/essentials/validation#date-before}
  250. */
  251. date_before({ args }) {
  252. if (Array.isArray(args) && args.length) {
  253. /* <i18n case="Shown when the user-provided date is not before the date supplied to the rule."> */
  254. return i18n.t(
  255. 'This field must have a value that is before %s.',
  256. i18n.date(args[0]),
  257. )
  258. /* </i18n> */
  259. }
  260. /* <i18n case="Shown when the user-provided date is not before today's date, since no date was supplied to the rule."> */
  261. return i18n.t('This field must have a value that is in the past.')
  262. /* </i18n> */
  263. },
  264. /**
  265. * The value is not between two numbers
  266. * @see {@link https://docs.formkit.com/essentials/validation#between}
  267. */
  268. between({ args }) {
  269. if (Number.isNaN(args[0]) || Number.isNaN(args[1])) {
  270. /* <i18n case="Shown when any of the arguments supplied to the rule were not a number."> */
  271. return i18n.t(
  272. "This field was configured incorrectly and can't be submitted.",
  273. )
  274. /* </i18n> */
  275. }
  276. const [first, second] = order(args[0], args[1])
  277. /* <i18n case="Shown when the user-provided value is not between two numbers."> */
  278. return i18n.t(
  279. 'This field must have a value that is between %s and %s.',
  280. first,
  281. second,
  282. )
  283. /* </i18n> */
  284. },
  285. /**
  286. * The confirmation field does not match
  287. * @see {@link https://docs.formkit.com/essentials/validation#confirm}
  288. */
  289. confirm() {
  290. // TODO: Check if message is in a good shape (e.g. for the usage for password + confirm password).
  291. /* <i18n case="Shown when the user-provided value does not equal the value of the matched input."> */
  292. return i18n.t("This field doesn't correspond to the expected value.")
  293. /* </i18n> */
  294. },
  295. /**
  296. * The value is not a valid date
  297. * @see {@link https://docs.formkit.com/essentials/validation#date-format}
  298. */
  299. date_format({ args }) {
  300. if (Array.isArray(args) && args.length) {
  301. /* <i18n case="Shown when the user-provided date does not satisfy the date format supplied to the rule."> */
  302. return i18n.t(
  303. 'This field isn\'t a valid date, please use the format "%s".',
  304. args[0],
  305. )
  306. /* </i18n> */
  307. }
  308. /* <i18n case="Shown when no date argument was supplied to the rule."> */
  309. return i18n.t(
  310. "This field was configured incorrectly and can't be submitted.",
  311. )
  312. /* </i18n> */
  313. },
  314. /**
  315. * Is not within expected date range
  316. * @see {@link https://docs.formkit.com/essentials/validation#date-between}
  317. */
  318. date_between({ args }) {
  319. /* <i18n case="Shown when the user-provided date is not between the start and end dates supplied to the rule. "> */
  320. return i18n.t(
  321. 'This field must have a value that is between %s and %s.',
  322. i18n.date(args[0]),
  323. i18n.date(args[1]),
  324. )
  325. /* </i18n> */
  326. },
  327. /**
  328. * Shown when the user-provided value is not a valid email address.
  329. * @see {@link https://docs.formkit.com/essentials/validation#email}
  330. */
  331. email: i18n.t('Please enter a valid email address.'),
  332. /**
  333. * Does not end with the specified value
  334. * @see {@link https://docs.formkit.com/essentials/validation#ends-with}
  335. */
  336. ends_with({ args }) {
  337. /* <i18n case="Shown when the user-provided value does not end with the substring supplied to the rule."> */
  338. return i18n.t(
  339. 'This field doesn\'t end with "%s".',
  340. commaSeparatedList(args),
  341. )
  342. /* </i18n> */
  343. },
  344. /**
  345. * Is not an allowed value
  346. * @see {@link https://docs.formkit.com/essentials/validation#is}
  347. */
  348. is() {
  349. /* <i18n case="Shown when the user-provided value is not one of the values supplied to the rule."> */
  350. return i18n.t("This field doesn't contain an allowed value.")
  351. /* </i18n> */
  352. },
  353. /**
  354. * Does not match specified length
  355. * @see {@link https://docs.formkit.com/essentials/validation#length}
  356. */
  357. length({ args: [first = 0, second = Infinity] }) {
  358. const min = Number(first) <= Number(second) ? first : second
  359. const max = Number(second) >= Number(first) ? second : first
  360. if (min === 1 && max === Infinity) {
  361. /* <i18n case="Shown when the length of the user-provided value is not at least one character."> */
  362. return i18n.t('This field must contain at least one character.')
  363. /* </i18n> */
  364. }
  365. if (min === 0 && max) {
  366. /* <i18n case="Shown when first argument supplied to the rule is 0, and the user-provided value is longer than the max (the 2nd argument) supplied to the rule."> */
  367. return i18n.t(
  368. 'This field must not contain more than %s characters.',
  369. max,
  370. )
  371. /* </i18n> */
  372. }
  373. if (min && max === Infinity) {
  374. /* <i18n case="Shown when the length of the user-provided value is less than the minimum supplied to the rule and there is no maximum supplied to the rule."> */
  375. return i18n.t('This field must contain at least %s characters.', min)
  376. /* </i18n> */
  377. }
  378. /* <i18n case="Shown when the length of the user-provided value is between the two lengths supplied to the rule."> */
  379. return i18n.t(
  380. 'This field must contain between %s and %s characters.',
  381. min,
  382. max,
  383. )
  384. /* </i18n> */
  385. },
  386. /**
  387. * Value is not a match
  388. * @see {@link https://docs.formkit.com/essentials/validation#matches}
  389. */
  390. matches() {
  391. /* <i18n case="Shown when the user-provided value does not match any of the values or RegExp patterns supplied to the rule. "> */
  392. return i18n.t("This field doesn't contain an allowed value.")
  393. /* </i18n> */
  394. },
  395. /**
  396. * Exceeds maximum allowed value
  397. * @see {@link https://docs.formkit.com/essentials/validation#max}
  398. */
  399. max({ node: { value }, args }) {
  400. if (Array.isArray(value)) {
  401. /* <i18n case="Shown when the length of the array of user-provided values is longer than the max supplied to the rule."> */
  402. return i18n.t("This field can't have more than %s entries.", args[0])
  403. /* </i18n> */
  404. }
  405. /* <i18n case="Shown when the user-provided value is greater than the maximum number supplied to the rule."> */
  406. return i18n.t(
  407. 'This field must have a value that is at most %s.',
  408. args[0],
  409. )
  410. /* </i18n> */
  411. },
  412. /**
  413. * The (field-level) value does not match specified mime type
  414. * @see {@link https://docs.formkit.com/essentials/validation#mime}
  415. */
  416. mime({ args }) {
  417. if (!args[0]) {
  418. /* <i18n case="Shown when no file formats were supplied to the rule."> */
  419. return i18n.t('No file formats allowed.')
  420. /* </i18n> */
  421. }
  422. /* <i18n case="Shown when the mime type of user-provided file does not match any mime types supplied to the rule."> */
  423. return i18n.t('This field must be of the type "%s".', args[0])
  424. /* </i18n> */
  425. },
  426. /**
  427. * Does not fulfill minimum allowed value
  428. * @see {@link https://docs.formkit.com/essentials/validation#min}
  429. */
  430. min({ node: { value }, args }) {
  431. if (Array.isArray(value)) {
  432. /* <i18n case="Shown when the length of the array of user-provided values is shorter than the min supplied to the rule."> */
  433. return i18n.t("This field can't have less than %s entries.", args[0])
  434. /* </i18n> */
  435. }
  436. /* <i18n case="Shown when the user-provided value is less than the minimum number supplied to the rule."> */
  437. return i18n.t(
  438. 'This field must have a value that is at least %s.',
  439. args[0],
  440. )
  441. /* </i18n> */
  442. },
  443. /**
  444. * Is not an allowed value
  445. * @see {@link https://docs.formkit.com/essentials/validation#not}
  446. */
  447. not({ node: { value } }) {
  448. /* <i18n case="Shown when the user-provided value matches one of the values supplied to (and thus disallowed by) the rule."> */
  449. return i18n.t(
  450. 'This field can\'t contain the value "%s".',
  451. value as string,
  452. )
  453. /* </i18n> */
  454. },
  455. /**
  456. * Is not a number
  457. * @see {@link https://docs.formkit.com/essentials/validation#number}
  458. */
  459. number() {
  460. /* <i18n case="Shown when the user-provided value is not a number."> */
  461. return i18n.t('This field must contain a number.')
  462. /* </i18n> */
  463. },
  464. /**
  465. * Required field.
  466. * @see {@link https://docs.formkit.com/essentials/validation#required}
  467. */
  468. required() {
  469. /* <i18n case="Shown when a user does not provide a value to a required input."> */
  470. return i18n.t('This field is required.')
  471. /* </i18n> */
  472. },
  473. /**
  474. * Require one field.
  475. * @see {@link https://formkit.com/essentials/validation#require-one}
  476. */
  477. require_one: ({ name, node, args: inputNames }) => {
  478. const labels = inputNames
  479. .map((name) => {
  480. const dependentNode = node.at(name)
  481. if (dependentNode) {
  482. return createMessageName(dependentNode)
  483. }
  484. return false
  485. })
  486. .filter((name) => !!name) as unknown as ComputedRef<string>[]
  487. labels.unshift(name as unknown as ComputedRef<string>)
  488. /* <i18n case="Shown when the user-provided has not provided a value for at least one of the required fields."> */
  489. // return `${labels.join(' or ')} is required.`
  490. const translatedSeparator = i18n.t('or')
  491. return i18n.t(
  492. '%s is required.',
  493. labels
  494. .map((label: ComputedRef<string>) => label.value)
  495. .join(` ${translatedSeparator} `),
  496. )
  497. /* </i18n> */
  498. },
  499. /**
  500. * Does not start with specified value
  501. * @see {@link https://docs.formkit.com/essentials/validation#starts-with}
  502. */
  503. starts_with({ args }) {
  504. /* <i18n case="Shown when the user-provided value does not start with the substring supplied to the rule."> */
  505. return i18n.t(
  506. 'This field doesn\'t start with "%s".',
  507. commaSeparatedList(args),
  508. )
  509. /* </i18n> */
  510. },
  511. /**
  512. * Is not a url
  513. * @see {@link https://docs.formkit.com/essentials/validation#url}
  514. */
  515. url() {
  516. /* <i18n case="Shown when the user-provided value is not a valid url."> */
  517. return i18n.t('Please include a valid url.')
  518. /* </i18n> */
  519. },
  520. /**
  521. * Shown when the date is invalid.
  522. */
  523. invalidDate: () => i18n.t('The selected date is invalid.'),
  524. },
  525. }
  526. }
  527. export default loadLocales