@jarenjs/locales 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/de.js ADDED
@@ -0,0 +1,131 @@
1
+ //@ts-check
2
+
3
+ /**
4
+ * German (de) message catalog for @jarenjs/validate and @jarenjs/forms.
5
+ *
6
+ * A catalog is a plain flat object `{ [key]: closure | template string }`;
7
+ * compile it with `compileMessageCatalog` from either consumer package
8
+ * and hand it to `localizeErrors` (validate) or the `catalog` parameters
9
+ * of `validateField` / `evaluateFormRules` (forms). A pack imports only
10
+ * the shared rendering helpers; key parity with the built-in English
11
+ * catalogs is enforced by tests in the repo, not by imports.
12
+ *
13
+ * Globalization mechanics (the pack-authoring pattern - see
14
+ * packages/validate/docs/ERROR-MESSAGES.md):
15
+ * - `Intl.PluralRules` picks plural categories ("1 Eigenschaft" /
16
+ * "2 Eigenschaften"; "Zeichen" is invariant and needs none),
17
+ * - `Intl.NumberFormat` renders numeric limits the German way,
18
+ * - `Intl.ListFormat` renders enum alternatives ("a, b oder c"),
19
+ * all held as module-level singletons (allocation discipline).
20
+ */
21
+
22
+ import {
23
+ formatMessageValue,
24
+ makeNumberRenderer,
25
+ makePluralPicker,
26
+ makeTypeNamer,
27
+ } from './helpers.js';
28
+
29
+ //#region Intl singletons
30
+
31
+ const pluralRules = new Intl.PluralRules('de');
32
+ const numberFormat = new Intl.NumberFormat('de-DE');
33
+ const listFormat = new Intl.ListFormat('de', { style: 'long', type: 'disjunction' });
34
+
35
+ /** Pick the German singular or plural noun form for a count. */
36
+ const plural = makePluralPicker(pluralRules);
37
+
38
+ /**
39
+ * Render a numeric limit through the German number format; non-numbers
40
+ * (e.g. an unresolved $data pointer) render as-is.
41
+ */
42
+ const num = makeNumberRenderer(numberFormat);
43
+
44
+ /** German names (with article) for the JSON Schema type keyword values. */
45
+ const TYPE_NAMES = {
46
+ string: 'eine Zeichenkette (string)',
47
+ number: 'eine Zahl',
48
+ integer: 'eine ganze Zahl',
49
+ boolean: 'ein boolescher Wert',
50
+ array: 'eine Liste (array)',
51
+ object: 'ein Objekt',
52
+ null: 'null',
53
+ };
54
+
55
+ /** Type keyword values under their German display name, article included. */
56
+ const typeName = makeTypeNamer(TYPE_NAMES);
57
+
58
+ //#endregion
59
+
60
+ /**
61
+ * The German catalog. Covers every key of validate's `messagesEn`, every
62
+ * `form/*` key of forms' `formsMessagesEn`, `x-form/assert`, and the
63
+ * `JQ2xxx` codes reachable through `$query`.
64
+ * @type {Record<string, string | ((params: any, error?: object) => string)>}
65
+ */
66
+ export const de = {
67
+ //#region @jarenjs/validate (document voice)
68
+ type: (p) => p.types
69
+ ? `muss einer der folgenden Typen sein: ${p.types.join(', ')}`
70
+ : `muss ${typeName(p.type)} sein`,
71
+ required: (p) => p.missingProperty
72
+ ? `muss die Pflichteigenschaft '${p.missingProperty}' enthalten`
73
+ : 'muss die Pflichteigenschaften enthalten',
74
+ minimum: (p) => `muss ${p.comparison} ${num(p.limit)} sein`,
75
+ maximum: (p) => `muss ${p.comparison} ${num(p.limit)} sein`,
76
+ exclusiveMinimum: (p) => `muss ${p.comparison} ${num(p.limit)} sein`,
77
+ exclusiveMaximum: (p) => `muss ${p.comparison} ${num(p.limit)} sein`,
78
+ multipleOf: (p) => `muss ein Vielfaches von ${num(p.multipleOf)} sein`,
79
+ minLength: (p) => `darf nicht weniger als ${num(p.limit)} Zeichen enthalten`,
80
+ maxLength: (p) => `darf nicht mehr als ${num(p.limit)} Zeichen enthalten`,
81
+ pattern: 'muss dem Muster "{pattern}" entsprechen',
82
+ additionalProperties: (p) => p.additionalProperty
83
+ ? `darf die zusätzliche Eigenschaft '${p.additionalProperty}' nicht enthalten`
84
+ : 'darf keine zusätzlichen Eigenschaften enthalten',
85
+ minProperties: (p) => `darf nicht weniger als ${num(p.limit)} ${plural(p.limit, 'Eigenschaft', 'Eigenschaften')} enthalten`,
86
+ maxProperties: (p) => `darf nicht mehr als ${num(p.limit)} ${plural(p.limit, 'Eigenschaft', 'Eigenschaften')} enthalten`,
87
+ minItems: (p) => `darf nicht weniger als ${num(p.limit)} ${plural(p.limit, 'Element', 'Elemente')} enthalten`,
88
+ maxItems: (p) => `darf nicht mehr als ${num(p.limit)} ${plural(p.limit, 'Element', 'Elemente')} enthalten`,
89
+ uniqueItems: 'darf keine doppelten Elemente enthalten',
90
+ contains: 'muss mindestens ein gültiges Element enthalten',
91
+ items: 'die Elemente der Liste sind ungültig',
92
+ allOf: 'muss allen Teilschemata entsprechen',
93
+ anyOf: 'muss einem Teilschema in anyOf entsprechen',
94
+ oneOf: 'muss genau einem Teilschema in oneOf entsprechen',
95
+ not: 'darf dem Teilschema NICHT entsprechen',
96
+ format: 'muss dem Format "{format}" entsprechen',
97
+ if: 'muss dem "if"-Schema entsprechen',
98
+ then: 'muss dem "then"-Schema entsprechen',
99
+ else: 'muss dem "else"-Schema entsprechen',
100
+ 'false schema': 'das boolesche Schema false ist immer ungültig',
101
+ $query: (p) => p.code
102
+ ? `die '$query'-Assertion meldete ${p.code} bei '${p.docPath}'`
103
+ : "muss die '$query'-Assertion erfüllen",
104
+ JQ2001: (p) => `die '$query'-Assertion konnte nicht ausgewertet werden (${p.code} bei '${p.docPath}')`,
105
+ JQ2003: (p) => `die '$query'-Assertion lieferte mehrere Ergebnisse (${p.code} bei '${p.docPath}')`,
106
+ //#endregion
107
+
108
+ //#region @jarenjs/forms (second-person field voice)
109
+ 'form/required': 'Dieses Feld ist erforderlich',
110
+ 'form/type': (p) => `Muss ${typeName(p.type)} sein`,
111
+ 'form/const': (p) => `Muss ${formatMessageValue(p.constValue)} sein`,
112
+ 'form/enum': (p) => `Muss ${Array.isArray(p.enumValues) ? listFormat.format(p.enumValues.map(formatMessageValue)) : formatMessageValue(p.enumValues)} sein`,
113
+ 'form/minLength': (p) => `Muss mindestens ${num(p.limit)} Zeichen enthalten (derzeit ${num(p.len)})`,
114
+ 'form/maxLength': (p) => `Darf höchstens ${num(p.limit)} Zeichen enthalten (derzeit ${num(p.len)})`,
115
+ 'form/pattern': 'Muss dem Muster {pattern} entsprechen',
116
+ 'form/format': (p) => `Muss dem Format ${p.format} entsprechen`,
117
+ 'form/minimum': (p) => `Muss mindestens ${num(p.limit)} sein`,
118
+ 'form/maximum': (p) => `Darf höchstens ${num(p.limit)} sein`,
119
+ 'form/exclusiveMinimum': (p) => `Muss größer als ${num(p.limit)} sein`,
120
+ 'form/exclusiveMaximum': (p) => `Muss kleiner als ${num(p.limit)} sein`,
121
+ 'form/multipleOf': (p) => `Muss ein Vielfaches von ${num(p.multipleOf)} sein`,
122
+ 'form/minItems': (p) => `Muss mindestens ${num(p.limit)} ${plural(p.limit, 'Element', 'Elemente')} enthalten`,
123
+ 'form/maxItems': (p) => `Darf höchstens ${num(p.limit)} ${plural(p.limit, 'Element', 'Elemente')} enthalten`,
124
+ 'form/uniqueItems': 'Die Elemente müssen eindeutig sein',
125
+ 'form/minProperties': (p) => `Muss mindestens ${num(p.limit)} ${plural(p.limit, 'Eigenschaft', 'Eigenschaften')} enthalten`,
126
+ 'form/maxProperties': (p) => `Darf höchstens ${num(p.limit)} ${plural(p.limit, 'Eigenschaft', 'Eigenschaften')} enthalten`,
127
+ 'x-form/assert': 'Ungültiger Wert',
128
+ 'form/addItem': 'Element hinzufügen',
129
+ 'form/removeItem': 'Element entfernen',
130
+ //#endregion
131
+ };
package/src/es.js ADDED
@@ -0,0 +1,131 @@
1
+ //@ts-check
2
+
3
+ /**
4
+ * Spanish (es) message catalog for @jarenjs/validate and @jarenjs/forms.
5
+ *
6
+ * A catalog is a plain flat object `{ [key]: closure | template string }`;
7
+ * compile it with `compileMessageCatalog` from either consumer package
8
+ * and hand it to `localizeErrors` (validate) or the `catalog` parameters
9
+ * of `validateField` / `evaluateFormRules` (forms). A pack imports only
10
+ * the shared rendering helpers; key parity with the built-in English
11
+ * catalogs is enforced by tests in the repo, not by imports.
12
+ *
13
+ * Globalization mechanics (the pack-authoring pattern - see
14
+ * packages/validate/docs/ERROR-MESSAGES.md):
15
+ * - `Intl.PluralRules` picks plural categories, and the singular of
16
+ * "caracteres" shifts its accent ("1 carácter" / "2 caracteres"),
17
+ * - `Intl.NumberFormat` renders numeric limits the Spanish way,
18
+ * - `Intl.ListFormat` renders enum alternatives ("a, b o c"),
19
+ * all held as module-level singletons (allocation discipline).
20
+ */
21
+
22
+ import {
23
+ formatMessageValue,
24
+ makeNumberRenderer,
25
+ makePluralPicker,
26
+ makeTypeNamer,
27
+ } from './helpers.js';
28
+
29
+ //#region Intl singletons
30
+
31
+ const pluralRules = new Intl.PluralRules('es');
32
+ const numberFormat = new Intl.NumberFormat('es-ES');
33
+ const listFormat = new Intl.ListFormat('es', { style: 'long', type: 'disjunction' });
34
+
35
+ /** Pick the Spanish singular or plural noun form for a count. */
36
+ const plural = makePluralPicker(pluralRules);
37
+
38
+ /**
39
+ * Render a numeric limit through the Spanish number format; non-numbers
40
+ * (e.g. an unresolved $data pointer) render as-is.
41
+ */
42
+ const num = makeNumberRenderer(numberFormat);
43
+
44
+ /** Spanish names (with article) for the JSON Schema type keyword values. */
45
+ const TYPE_NAMES = {
46
+ string: 'una cadena (string)',
47
+ number: 'un número',
48
+ integer: 'un número entero',
49
+ boolean: 'un booleano',
50
+ array: 'una lista (array)',
51
+ object: 'un objeto',
52
+ null: 'null',
53
+ };
54
+
55
+ /** Type keyword values under their Spanish display name, article included. */
56
+ const typeName = makeTypeNamer(TYPE_NAMES);
57
+
58
+ //#endregion
59
+
60
+ /**
61
+ * The Spanish catalog. Covers every key of validate's `messagesEn`, every
62
+ * `form/*` key of forms' `formsMessagesEn`, `x-form/assert`, and the
63
+ * `JQ2xxx` codes reachable through `$query`.
64
+ * @type {Record<string, string | ((params: any, error?: object) => string)>}
65
+ */
66
+ export const es = {
67
+ //#region @jarenjs/validate (document voice)
68
+ type: (p) => p.types
69
+ ? `debe ser uno de los siguientes tipos: ${p.types.join(', ')}`
70
+ : `debe ser ${typeName(p.type)}`,
71
+ required: (p) => p.missingProperty
72
+ ? `debe tener la propiedad obligatoria '${p.missingProperty}'`
73
+ : 'debe tener las propiedades obligatorias',
74
+ minimum: (p) => `debe ser ${p.comparison} ${num(p.limit)}`,
75
+ maximum: (p) => `debe ser ${p.comparison} ${num(p.limit)}`,
76
+ exclusiveMinimum: (p) => `debe ser ${p.comparison} ${num(p.limit)}`,
77
+ exclusiveMaximum: (p) => `debe ser ${p.comparison} ${num(p.limit)}`,
78
+ multipleOf: (p) => `debe ser un múltiplo de ${num(p.multipleOf)}`,
79
+ minLength: (p) => `no debe tener menos de ${num(p.limit)} ${plural(p.limit, 'carácter', 'caracteres')}`,
80
+ maxLength: (p) => `no debe tener más de ${num(p.limit)} ${plural(p.limit, 'carácter', 'caracteres')}`,
81
+ pattern: 'debe coincidir con el patrón "{pattern}"',
82
+ additionalProperties: (p) => p.additionalProperty
83
+ ? `no debe tener la propiedad adicional '${p.additionalProperty}'`
84
+ : 'no debe tener propiedades adicionales',
85
+ minProperties: (p) => `no debe tener menos de ${num(p.limit)} ${plural(p.limit, 'propiedad', 'propiedades')}`,
86
+ maxProperties: (p) => `no debe tener más de ${num(p.limit)} ${plural(p.limit, 'propiedad', 'propiedades')}`,
87
+ minItems: (p) => `no debe tener menos de ${num(p.limit)} ${plural(p.limit, 'elemento', 'elementos')}`,
88
+ maxItems: (p) => `no debe tener más de ${num(p.limit)} ${plural(p.limit, 'elemento', 'elementos')}`,
89
+ uniqueItems: 'no debe tener elementos duplicados',
90
+ contains: 'debe contener al menos un elemento válido',
91
+ items: 'los elementos de la lista no son válidos',
92
+ allOf: 'debe cumplir todos los subesquemas',
93
+ anyOf: 'debe cumplir un subesquema de anyOf',
94
+ oneOf: 'debe cumplir exactamente un subesquema de oneOf',
95
+ not: 'NO debe cumplir el subesquema',
96
+ format: 'debe coincidir con el formato "{format}"',
97
+ if: 'debe cumplir el esquema "if"',
98
+ then: 'debe cumplir el esquema "then"',
99
+ else: 'debe cumplir el esquema "else"',
100
+ 'false schema': 'el esquema booleano false siempre es inválido',
101
+ $query: (p) => p.code
102
+ ? `la aserción '$query' produjo ${p.code} en '${p.docPath}'`
103
+ : "debe cumplir la aserción '$query'",
104
+ JQ2001: (p) => `la aserción '$query' no se pudo evaluar (${p.code} en '${p.docPath}')`,
105
+ JQ2003: (p) => `la aserción '$query' produjo varios resultados (${p.code} en '${p.docPath}')`,
106
+ //#endregion
107
+
108
+ //#region @jarenjs/forms (second-person field voice)
109
+ 'form/required': 'Este campo es obligatorio',
110
+ 'form/type': (p) => `Debe ser ${typeName(p.type)}`,
111
+ 'form/const': (p) => `Debe ser ${formatMessageValue(p.constValue)}`,
112
+ 'form/enum': (p) => `Debe ser ${Array.isArray(p.enumValues) ? listFormat.format(p.enumValues.map(formatMessageValue)) : formatMessageValue(p.enumValues)}`,
113
+ 'form/minLength': (p) => `Debe tener al menos ${num(p.limit)} ${plural(p.limit, 'carácter', 'caracteres')} (actualmente ${num(p.len)})`,
114
+ 'form/maxLength': (p) => `Debe tener como máximo ${num(p.limit)} ${plural(p.limit, 'carácter', 'caracteres')} (actualmente ${num(p.len)})`,
115
+ 'form/pattern': 'Debe coincidir con el patrón {pattern}',
116
+ 'form/format': (p) => `Debe cumplir el formato ${p.format}`,
117
+ 'form/minimum': (p) => `Debe ser al menos ${num(p.limit)}`,
118
+ 'form/maximum': (p) => `Debe ser como máximo ${num(p.limit)}`,
119
+ 'form/exclusiveMinimum': (p) => `Debe ser mayor que ${num(p.limit)}`,
120
+ 'form/exclusiveMaximum': (p) => `Debe ser menor que ${num(p.limit)}`,
121
+ 'form/multipleOf': (p) => `Debe ser un múltiplo de ${num(p.multipleOf)}`,
122
+ 'form/minItems': (p) => `Debe tener al menos ${num(p.limit)} ${plural(p.limit, 'elemento', 'elementos')}`,
123
+ 'form/maxItems': (p) => `Debe tener como máximo ${num(p.limit)} ${plural(p.limit, 'elemento', 'elementos')}`,
124
+ 'form/uniqueItems': 'Los elementos deben ser únicos',
125
+ 'form/minProperties': (p) => `Debe tener al menos ${num(p.limit)} ${plural(p.limit, 'propiedad', 'propiedades')}`,
126
+ 'form/maxProperties': (p) => `Debe tener como máximo ${num(p.limit)} ${plural(p.limit, 'propiedad', 'propiedades')}`,
127
+ 'x-form/assert': 'Valor no válido',
128
+ 'form/addItem': 'Añadir elemento',
129
+ 'form/removeItem': 'Eliminar elemento',
130
+ //#endregion
131
+ };
package/src/fr.js ADDED
@@ -0,0 +1,131 @@
1
+ //@ts-check
2
+
3
+ /**
4
+ * French (fr) message catalog for @jarenjs/validate and @jarenjs/forms.
5
+ *
6
+ * A catalog is a plain flat object `{ [key]: closure | template string }`;
7
+ * compile it with `compileMessageCatalog` from either consumer package
8
+ * and hand it to `localizeErrors` (validate) or the `catalog` parameters
9
+ * of `validateField` / `evaluateFormRules` (forms). A pack imports only
10
+ * the shared rendering helpers; key parity with the built-in English
11
+ * catalogs is enforced by tests in the repo, not by imports.
12
+ *
13
+ * Globalization mechanics (the pack-authoring pattern - see
14
+ * packages/validate/docs/ERROR-MESSAGES.md):
15
+ * - `Intl.PluralRules` picks plural categories (French counts 0 and 1
16
+ * as singular: "0 caractère" / "2 caractères"),
17
+ * - `Intl.NumberFormat` renders numeric limits the French way,
18
+ * - `Intl.ListFormat` renders enum alternatives ("a, b ou c"),
19
+ * all held as module-level singletons (allocation discipline).
20
+ */
21
+
22
+ import {
23
+ formatMessageValue,
24
+ makeNumberRenderer,
25
+ makePluralPicker,
26
+ makeTypeNamer,
27
+ } from './helpers.js';
28
+
29
+ //#region Intl singletons
30
+
31
+ const pluralRules = new Intl.PluralRules('fr');
32
+ const numberFormat = new Intl.NumberFormat('fr-FR');
33
+ const listFormat = new Intl.ListFormat('fr', { style: 'long', type: 'disjunction' });
34
+
35
+ /** Pick the French singular or plural noun form for a count. */
36
+ const plural = makePluralPicker(pluralRules);
37
+
38
+ /**
39
+ * Render a numeric limit through the French number format; non-numbers
40
+ * (e.g. an unresolved $data pointer) render as-is.
41
+ */
42
+ const num = makeNumberRenderer(numberFormat);
43
+
44
+ /** French names (with article) for the JSON Schema type keyword values. */
45
+ const TYPE_NAMES = {
46
+ string: 'une chaîne (string)',
47
+ number: 'un nombre',
48
+ integer: 'un nombre entier',
49
+ boolean: 'un booléen',
50
+ array: 'une liste (array)',
51
+ object: 'un objet',
52
+ null: 'null',
53
+ };
54
+
55
+ /** Type keyword values under their French display name, article included. */
56
+ const typeName = makeTypeNamer(TYPE_NAMES);
57
+
58
+ //#endregion
59
+
60
+ /**
61
+ * The French catalog. Covers every key of validate's `messagesEn`, every
62
+ * `form/*` key of forms' `formsMessagesEn`, `x-form/assert`, and the
63
+ * `JQ2xxx` codes reachable through `$query`.
64
+ * @type {Record<string, string | ((params: any, error?: object) => string)>}
65
+ */
66
+ export const fr = {
67
+ //#region @jarenjs/validate (document voice)
68
+ type: (p) => p.types
69
+ ? `doit être l'un des types suivants : ${p.types.join(', ')}`
70
+ : `doit être ${typeName(p.type)}`,
71
+ required: (p) => p.missingProperty
72
+ ? `doit contenir la propriété obligatoire '${p.missingProperty}'`
73
+ : 'doit contenir les propriétés obligatoires',
74
+ minimum: (p) => `doit être ${p.comparison} ${num(p.limit)}`,
75
+ maximum: (p) => `doit être ${p.comparison} ${num(p.limit)}`,
76
+ exclusiveMinimum: (p) => `doit être ${p.comparison} ${num(p.limit)}`,
77
+ exclusiveMaximum: (p) => `doit être ${p.comparison} ${num(p.limit)}`,
78
+ multipleOf: (p) => `doit être un multiple de ${num(p.multipleOf)}`,
79
+ minLength: (p) => `ne doit pas contenir moins de ${num(p.limit)} ${plural(p.limit, 'caractère', 'caractères')}`,
80
+ maxLength: (p) => `ne doit pas contenir plus de ${num(p.limit)} ${plural(p.limit, 'caractère', 'caractères')}`,
81
+ pattern: 'doit correspondre au motif "{pattern}"',
82
+ additionalProperties: (p) => p.additionalProperty
83
+ ? `ne doit pas contenir la propriété supplémentaire '${p.additionalProperty}'`
84
+ : 'ne doit pas contenir de propriétés supplémentaires',
85
+ minProperties: (p) => `ne doit pas contenir moins de ${num(p.limit)} ${plural(p.limit, 'propriété', 'propriétés')}`,
86
+ maxProperties: (p) => `ne doit pas contenir plus de ${num(p.limit)} ${plural(p.limit, 'propriété', 'propriétés')}`,
87
+ minItems: (p) => `ne doit pas contenir moins de ${num(p.limit)} ${plural(p.limit, 'élément', 'éléments')}`,
88
+ maxItems: (p) => `ne doit pas contenir plus de ${num(p.limit)} ${plural(p.limit, 'élément', 'éléments')}`,
89
+ uniqueItems: "ne doit pas contenir d'éléments en double",
90
+ contains: 'doit contenir au moins un élément valide',
91
+ items: 'les éléments de la liste sont invalides',
92
+ allOf: 'doit satisfaire tous les sous-schémas',
93
+ anyOf: 'doit satisfaire un sous-schéma de anyOf',
94
+ oneOf: 'doit satisfaire exactement un sous-schéma de oneOf',
95
+ not: 'ne doit PAS satisfaire le sous-schéma',
96
+ format: 'doit correspondre au format "{format}"',
97
+ if: 'doit satisfaire le schéma "if"',
98
+ then: 'doit satisfaire le schéma "then"',
99
+ else: 'doit satisfaire le schéma "else"',
100
+ 'false schema': 'le schéma booléen false est toujours invalide',
101
+ $query: (p) => p.code
102
+ ? `l'assertion '$query' a levé ${p.code} à '${p.docPath}'`
103
+ : "doit satisfaire l'assertion '$query'",
104
+ JQ2001: (p) => `l'assertion '$query' n'a pas pu être évaluée (${p.code} à '${p.docPath}')`,
105
+ JQ2003: (p) => `l'assertion '$query' a produit plusieurs résultats (${p.code} à '${p.docPath}')`,
106
+ //#endregion
107
+
108
+ //#region @jarenjs/forms (second-person field voice)
109
+ 'form/required': 'Ce champ est obligatoire',
110
+ 'form/type': (p) => `Doit être ${typeName(p.type)}`,
111
+ 'form/const': (p) => `Doit être ${formatMessageValue(p.constValue)}`,
112
+ 'form/enum': (p) => `Doit être ${Array.isArray(p.enumValues) ? listFormat.format(p.enumValues.map(formatMessageValue)) : formatMessageValue(p.enumValues)}`,
113
+ 'form/minLength': (p) => `Doit contenir au moins ${num(p.limit)} ${plural(p.limit, 'caractère', 'caractères')} (actuellement ${num(p.len)})`,
114
+ 'form/maxLength': (p) => `Doit contenir au plus ${num(p.limit)} ${plural(p.limit, 'caractère', 'caractères')} (actuellement ${num(p.len)})`,
115
+ 'form/pattern': 'Doit correspondre au motif {pattern}',
116
+ 'form/format': (p) => `Doit respecter le format ${p.format}`,
117
+ 'form/minimum': (p) => `Doit être au moins ${num(p.limit)}`,
118
+ 'form/maximum': (p) => `Doit être au plus ${num(p.limit)}`,
119
+ 'form/exclusiveMinimum': (p) => `Doit être supérieur à ${num(p.limit)}`,
120
+ 'form/exclusiveMaximum': (p) => `Doit être inférieur à ${num(p.limit)}`,
121
+ 'form/multipleOf': (p) => `Doit être un multiple de ${num(p.multipleOf)}`,
122
+ 'form/minItems': (p) => `Doit contenir au moins ${num(p.limit)} ${plural(p.limit, 'élément', 'éléments')}`,
123
+ 'form/maxItems': (p) => `Doit contenir au plus ${num(p.limit)} ${plural(p.limit, 'élément', 'éléments')}`,
124
+ 'form/uniqueItems': 'Les éléments doivent être uniques',
125
+ 'form/minProperties': (p) => `Doit contenir au moins ${num(p.limit)} ${plural(p.limit, 'propriété', 'propriétés')}`,
126
+ 'form/maxProperties': (p) => `Doit contenir au plus ${num(p.limit)} ${plural(p.limit, 'propriété', 'propriétés')}`,
127
+ 'x-form/assert': 'Valeur invalide',
128
+ 'form/addItem': 'Ajouter un élément',
129
+ "form/removeItem": "Supprimer l'élément",
130
+ //#endregion
131
+ };
package/src/helpers.js ADDED
@@ -0,0 +1,59 @@
1
+ //@ts-check
2
+
3
+ /**
4
+ * The pack-authoring toolkit: the rendering steps every locale pack
5
+ * performs identically, parameterised by the one thing that is actually
6
+ * per-language.
7
+ *
8
+ * Each factory takes a pack's own `Intl` singleton or translated table
9
+ * and returns the render closure the catalog entries call. Building the
10
+ * closure once at module load keeps the packs' allocation discipline:
11
+ * nothing is constructed per message. This module is internal to
12
+ * `@jarenjs/locales` - packs import it, consumers never see it.
13
+ */
14
+
15
+ export { formatMessageValue } from '@jarenjs/core/message';
16
+
17
+ /**
18
+ * Build a numeric-limit renderer over a pack's number format. Values
19
+ * that are not numbers (e.g. an unresolved $data pointer) render as-is,
20
+ * so a limit is always readable even when it never resolved.
21
+ *
22
+ * @param {Intl.NumberFormat} numberFormat - The pack's number format
23
+ * @returns {(value: unknown) => string} The limit renderer
24
+ */
25
+ export function makeNumberRenderer(numberFormat) {
26
+ return function renderNumber(value) {
27
+ return typeof value === 'number' ? numberFormat.format(value) : String(value);
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Build a two-form noun picker over a pack's plural rules: the count's
33
+ * CLDR category selects the `one` form, everything else the `other`
34
+ * form. Only for languages whose counted messages need exactly two
35
+ * forms - a pack that needs more categories, or that avoids agreement
36
+ * altogether by phrasing around a fixed noun, does not use this.
37
+ *
38
+ * @param {Intl.PluralRules} pluralRules - The pack's plural rules
39
+ * @returns {(count: number, one: string, other: string) => string} The form picker
40
+ */
41
+ export function makePluralPicker(pluralRules) {
42
+ return function pickPluralForm(count, one, other) {
43
+ return pluralRules.select(count) === 'one' ? one : other;
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Build a type-name renderer over a pack's translated table. An
49
+ * unlisted type (a custom or future keyword value) renders under its
50
+ * JSON Schema name rather than disappearing.
51
+ *
52
+ * @param {Record<string, string>} typeNames - The pack's translated type names
53
+ * @returns {(type: string) => string} The type-name renderer
54
+ */
55
+ export function makeTypeNamer(typeNames) {
56
+ return function renderTypeName(type) {
57
+ return typeNames[type] ?? type;
58
+ };
59
+ }
package/src/index.js ADDED
@@ -0,0 +1,26 @@
1
+ //@ts-check
2
+
3
+ /**
4
+ * @jarenjs/locales - locale packs (message catalogs) for the error
5
+ * messages of @jarenjs/validate and @jarenjs/forms.
6
+ *
7
+ * Each pack is a plain flat object of message-key -> closure/template
8
+ * entries (the catalog contract of
9
+ * packages/validate/docs/ERROR-MESSAGES.md); compile them with
10
+ * `compileMessageCatalog` from the consuming package. A pack holds its
11
+ * own translations and `Intl` singletons, and imports nothing but the
12
+ * rendering helpers of `./helpers.js` - never a consumer package, so
13
+ * either consumer can serve any pack.
14
+ */
15
+
16
+ export { ar } from './ar.js';
17
+ export { de } from './de.js';
18
+ export { es } from './es.js';
19
+ export { fr } from './fr.js';
20
+ export { ja } from './ja.js';
21
+ export { ko } from './ko.js';
22
+ export { nl } from './nl.js';
23
+ export { pt } from './pt.js';
24
+ export { ru } from './ru.js';
25
+ export { tr } from './tr.js';
26
+ export { zhTW } from './zh-tw.js';
package/src/ja.js ADDED
@@ -0,0 +1,126 @@
1
+ //@ts-check
2
+
3
+ /**
4
+ * Japanese (ja) message catalog for @jarenjs/validate and @jarenjs/forms.
5
+ *
6
+ * A catalog is a plain flat object `{ [key]: closure | template string }`;
7
+ * compile it with `compileMessageCatalog` from either consumer package
8
+ * and hand it to `localizeErrors` (validate) or the `catalog` parameters
9
+ * of `validateField` / `evaluateFormRules` (forms). A pack imports only
10
+ * the shared rendering helpers; key parity with the built-in English
11
+ * catalogs is enforced by tests in the repo, not by imports.
12
+ *
13
+ * Globalization mechanics (the pack-authoring pattern - see
14
+ * packages/validate/docs/ERROR-MESSAGES.md):
15
+ * - Japanese has no grammatical plural, so there is no plural helper
16
+ * here; counts read through counters ("2 文字", "3 個"),
17
+ * - `Intl.NumberFormat` renders numeric limits the Japanese way,
18
+ * - `Intl.ListFormat` renders enum alternatives ("a、b、または c"),
19
+ * all held as module-level singletons (allocation discipline).
20
+ */
21
+
22
+ import {
23
+ formatMessageValue,
24
+ makeNumberRenderer,
25
+ makeTypeNamer,
26
+ } from './helpers.js';
27
+
28
+ //#region Intl singletons
29
+
30
+ const numberFormat = new Intl.NumberFormat('ja-JP');
31
+ const listFormat = new Intl.ListFormat('ja', { style: 'long', type: 'disjunction' });
32
+
33
+ /**
34
+ * Render a numeric limit through the Japanese number format; non-numbers
35
+ * (e.g. an unresolved $data pointer) render as-is.
36
+ */
37
+ const num = makeNumberRenderer(numberFormat);
38
+
39
+ /** Japanese names for the JSON Schema type keyword values. */
40
+ const TYPE_NAMES = {
41
+ string: '文字列 (string)',
42
+ number: '数値',
43
+ integer: '整数',
44
+ boolean: '真偽値',
45
+ array: '配列 (array)',
46
+ object: 'オブジェクト',
47
+ null: 'null',
48
+ };
49
+
50
+ /** Type keyword values under their Japanese display name. */
51
+ const typeName = makeTypeNamer(TYPE_NAMES);
52
+
53
+ //#endregion
54
+
55
+ /**
56
+ * The Japanese catalog. Covers every key of validate's `messagesEn`,
57
+ * every `form/*` key of forms' `formsMessagesEn`, `x-form/assert`, and
58
+ * the `JQ2xxx` codes reachable through `$query`.
59
+ * @type {Record<string, string | ((params: any, error?: object) => string)>}
60
+ */
61
+ export const ja = {
62
+ //#region @jarenjs/validate (document voice)
63
+ type: (p) => p.types
64
+ ? `次のいずれかの型でなければなりません: ${p.types.join(', ')}`
65
+ : `${typeName(p.type)}でなければなりません`,
66
+ required: (p) => p.missingProperty
67
+ ? `必須プロパティ '${p.missingProperty}' が必要です`
68
+ : '必須プロパティが必要です',
69
+ minimum: (p) => `${p.comparison} ${num(p.limit)} でなければなりません`,
70
+ maximum: (p) => `${p.comparison} ${num(p.limit)} でなければなりません`,
71
+ exclusiveMinimum: (p) => `${p.comparison} ${num(p.limit)} でなければなりません`,
72
+ exclusiveMaximum: (p) => `${p.comparison} ${num(p.limit)} でなければなりません`,
73
+ multipleOf: (p) => `${num(p.multipleOf)} の倍数でなければなりません`,
74
+ minLength: (p) => `${num(p.limit)} 文字以上でなければなりません`,
75
+ maxLength: (p) => `${num(p.limit)} 文字以下でなければなりません`,
76
+ pattern: 'パターン "{pattern}" に一致しなければなりません',
77
+ additionalProperties: (p) => p.additionalProperty
78
+ ? `追加のプロパティ '${p.additionalProperty}' は使用できません`
79
+ : '追加のプロパティは使用できません',
80
+ minProperties: (p) => `プロパティは ${num(p.limit)} 個以上でなければなりません`,
81
+ maxProperties: (p) => `プロパティは ${num(p.limit)} 個以下でなければなりません`,
82
+ minItems: (p) => `項目は ${num(p.limit)} 個以上でなければなりません`,
83
+ maxItems: (p) => `項目は ${num(p.limit)} 個以下でなければなりません`,
84
+ uniqueItems: '重複する項目は使用できません',
85
+ contains: '有効な項目を少なくとも 1 つ含まなければなりません',
86
+ items: '配列の項目が無効です',
87
+ allOf: 'すべてのサブスキーマに一致しなければなりません',
88
+ anyOf: 'anyOf のいずれかのサブスキーマに一致しなければなりません',
89
+ oneOf: 'oneOf のちょうど 1 つのサブスキーマに一致しなければなりません',
90
+ not: 'サブスキーマに一致してはいけません',
91
+ format: '形式 "{format}" に一致しなければなりません',
92
+ if: '"if" スキーマに一致しなければなりません',
93
+ then: '"then" スキーマに一致しなければなりません',
94
+ else: '"else" スキーマに一致しなければなりません',
95
+ 'false schema': 'ブールスキーマ false は常に無効です',
96
+ $query: (p) => p.code
97
+ ? `'$query' アサーションが '${p.docPath}' で ${p.code} を発生させました`
98
+ : "'$query' アサーションを満たさなければなりません",
99
+ JQ2001: (p) => `'$query' アサーションを評価できませんでした('${p.docPath}' で ${p.code})`,
100
+ JQ2003: (p) => `'$query' アサーションが複数の結果を返しました('${p.docPath}' で ${p.code})`,
101
+ //#endregion
102
+
103
+ //#region @jarenjs/forms (second-person field voice)
104
+ 'form/required': 'この項目は必須です',
105
+ 'form/type': (p) => `${typeName(p.type)}でなければなりません`,
106
+ 'form/const': (p) => `${formatMessageValue(p.constValue)} でなければなりません`,
107
+ 'form/enum': (p) => `${Array.isArray(p.enumValues) ? listFormat.format(p.enumValues.map(formatMessageValue)) : formatMessageValue(p.enumValues)} のいずれかでなければなりません`,
108
+ 'form/minLength': (p) => `${num(p.limit)} 文字以上で入力してください(現在 ${num(p.len)} 文字)`,
109
+ 'form/maxLength': (p) => `${num(p.limit)} 文字以下で入力してください(現在 ${num(p.len)} 文字)`,
110
+ 'form/pattern': 'パターン {pattern} に一致しなければなりません',
111
+ 'form/format': (p) => `有効な ${p.format} 形式で入力してください`,
112
+ 'form/minimum': (p) => `${num(p.limit)} 以上でなければなりません`,
113
+ 'form/maximum': (p) => `${num(p.limit)} 以下でなければなりません`,
114
+ 'form/exclusiveMinimum': (p) => `${num(p.limit)} より大きくなければなりません`,
115
+ 'form/exclusiveMaximum': (p) => `${num(p.limit)} より小さくなければなりません`,
116
+ 'form/multipleOf': (p) => `${num(p.multipleOf)} の倍数でなければなりません`,
117
+ 'form/minItems': (p) => `項目は ${num(p.limit)} 個以上必要です`,
118
+ 'form/maxItems': (p) => `項目は ${num(p.limit)} 個以下にしてください`,
119
+ 'form/uniqueItems': '項目は一意でなければなりません',
120
+ 'form/minProperties': (p) => `プロパティは ${num(p.limit)} 個以上必要です`,
121
+ 'form/maxProperties': (p) => `プロパティは ${num(p.limit)} 個以下にしてください`,
122
+ 'x-form/assert': '無効な値です',
123
+ 'form/addItem': '項目を追加',
124
+ 'form/removeItem': '項目を削除',
125
+ //#endregion
126
+ };