@byline/i18n 2.6.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.
Files changed (44) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +166 -0
  3. package/dist/admin/en.js +424 -0
  4. package/dist/admin/fr.js +424 -0
  5. package/dist/admin/index.d.ts +44 -0
  6. package/dist/admin/index.js +27 -0
  7. package/dist/formatter.d.ts +40 -0
  8. package/dist/formatter.js +65 -0
  9. package/dist/index.d.ts +33 -0
  10. package/dist/index.js +3 -0
  11. package/dist/merge.d.ts +39 -0
  12. package/dist/merge.js +58 -0
  13. package/dist/react/i18n-context.d.ts +29 -0
  14. package/dist/react/i18n-context.js +3 -0
  15. package/dist/react/i18n-provider.d.ts +31 -0
  16. package/dist/react/i18n-provider.js +38 -0
  17. package/dist/react/index.d.ts +24 -0
  18. package/dist/react/index.js +4 -0
  19. package/dist/react/language-menu.d.ts +15 -0
  20. package/dist/react/language-menu.js +78 -0
  21. package/dist/react/use-translation.d.ts +24 -0
  22. package/dist/react/use-translation.js +16 -0
  23. package/dist/resolve.d.ts +21 -0
  24. package/dist/resolve.js +28 -0
  25. package/dist/types.d.ts +65 -0
  26. package/dist/types.js +1 -0
  27. package/package.json +100 -0
  28. package/src/admin/en.json +423 -0
  29. package/src/admin/fr.json +423 -0
  30. package/src/admin/index.test.node.ts +68 -0
  31. package/src/admin/index.ts +99 -0
  32. package/src/formatter.test.node.ts +163 -0
  33. package/src/formatter.ts +166 -0
  34. package/src/index.ts +47 -0
  35. package/src/merge.test.node.ts +85 -0
  36. package/src/merge.ts +135 -0
  37. package/src/react/i18n-context.ts +45 -0
  38. package/src/react/i18n-provider.tsx +76 -0
  39. package/src/react/index.ts +26 -0
  40. package/src/react/language-menu.tsx +115 -0
  41. package/src/react/use-translation.ts +45 -0
  42. package/src/resolve.test.node.ts +128 -0
  43. package/src/resolve.ts +84 -0
  44. package/src/types.ts +72 -0
@@ -0,0 +1,423 @@
1
+ {
2
+ "common.actions.save": "Enregistrer",
3
+ "common.actions.cancel": "Annuler",
4
+ "common.actions.delete": "Supprimer",
5
+ "common.actions.confirm": "Confirmer",
6
+ "common.actions.close": "Fermer",
7
+ "common.actions.edit": "Modifier",
8
+ "common.actions.create": "Créer",
9
+ "common.actions.duplicate": "Dupliquer",
10
+ "common.actions.preview": "Aperçu",
11
+ "common.actions.publish": "Publier",
12
+ "common.actions.unpublish": "Dépublier",
13
+ "common.actions.restore": "Restaurer",
14
+ "common.actions.search": "Rechercher",
15
+ "common.actions.select": "Sélectionner",
16
+ "common.pager.previous": "Précédent",
17
+ "common.pager.next": "Suivant",
18
+ "common.pager.pageOf": "Page {page, number} sur {total, number}",
19
+ "common.actions.signIn": "Se connecter",
20
+ "common.actions.signOut": "Se déconnecter",
21
+ "common.actions.signingOut": "Déconnexion en cours…",
22
+ "common.actions.home": "Accueil",
23
+ "common.actions.tryAgain": "Réessayer",
24
+ "common.actions.goToHomepage": "Aller à l'accueil",
25
+ "common.fields.email": "E-mail",
26
+ "common.fields.password": "Mot de passe",
27
+ "common.boolean.yes": "Oui",
28
+ "common.boolean.no": "Non",
29
+ "common.notSet": "Non défini",
30
+ "common.never": "Jamais",
31
+ "common.empty.noResults": "Aucun résultat.",
32
+ "common.loading": "Chargement…",
33
+ "common.status.draft": "Brouillon",
34
+ "common.status.published": "Publié",
35
+ "common.status.archived": "Archivé",
36
+ "language.menuLabel": "Changer de langue",
37
+ "language.useBrowserDefault": "Utiliser la langue du navigateur",
38
+ "chrome.sidebar.collapse": "Réduire la barre latérale",
39
+ "chrome.sidebar.expand": "Développer la barre latérale",
40
+ "chrome.account": "Compte",
41
+ "chrome.languageMenu": "Langue",
42
+ "chrome.appBar.signedInAs": "Connecté en tant que",
43
+ "chrome.menu.openAriaLabel": "Ouvrir le menu admin",
44
+ "chrome.menu.dashboard": "Tableau de bord",
45
+ "chrome.menu.adminUsers": "Utilisateurs",
46
+ "chrome.menu.adminRoles": "Rôles",
47
+ "chrome.menu.permissions": "Permissions",
48
+ "chrome.preview.on": "Aperçu actif",
49
+ "chrome.preview.off": "Aperçu inactif",
50
+ "chrome.preview.enableAriaLabel": "Activer le mode aperçu",
51
+ "chrome.preview.disableAriaLabel": "Désactiver le mode aperçu",
52
+ "chrome.preview.onTitle": "Les brouillons sont visibles sur le site public",
53
+ "chrome.preview.offTitle": "Le site public n'affiche que les contenus publiés",
54
+ "chrome.breadcrumbs.showHiddenAriaLabel": "Afficher les fils d'Ariane masqués",
55
+ "list.unread": "{count, plural, one {# non lu} other {# non lus}}",
56
+ "doc.publishedOn": "Publié le {date, date, medium}",
57
+ "validation.required": "Ce champ est obligatoire.",
58
+ "validation.tooShort": "Doit comporter au moins {min, number} caractères.",
59
+ "validation.tooLong": "Ne doit pas dépasser {max, number} caractères.",
60
+ "errors.unknown": "Une erreur est survenue. Veuillez réessayer.",
61
+ "common.errors.versionConflict": "Votre compte a été modifié ailleurs depuis que vous avez ouvert ce formulaire. Rechargez la page et réessayez.",
62
+ "common.errors.accountNotFound": "Votre compte admin est introuvable. Veuillez vous reconnecter.",
63
+ "common.errors.couldNotSave": "Impossible d'enregistrer les modifications. Veuillez réessayer.",
64
+ "common.feedback.saved": "Enregistré.",
65
+ "common.feedback.noChanges": "Aucune modification à enregistrer.",
66
+ "auth.signIn.title": "Connexion",
67
+ "auth.signIn.description": "Connectez-vous à l'admin Byline.",
68
+ "auth.signIn.errors.empty": "Saisissez votre adresse e-mail et votre mot de passe.",
69
+ "auth.signIn.errors.invalidCredentials": "Identifiants invalides.",
70
+ "account.intro": "Gérez votre profil et votre mot de passe.",
71
+ "account.sections.profile": "Profil",
72
+ "account.sections.password": "Mot de passe",
73
+ "account.sections.status": "Statut du compte",
74
+ "account.sections.preferences": "Préférences",
75
+ "account.editAriaLabel": "Modifier {section}",
76
+ "account.profile.givenName": "Prénom :",
77
+ "account.profile.familyName": "Nom :",
78
+ "account.profile.emailColon": "E-mail :",
79
+ "account.profile.username": "Nom d'utilisateur :",
80
+ "account.profile.created": "Créé le :",
81
+ "account.profile.updated": "Mis à jour le :",
82
+ "account.profile.lastLogin": "Dernière connexion :",
83
+ "account.profile.editButton": "Modifier le profil",
84
+ "account.password.intro": "Modifiez le mot de passe utilisé pour vous connecter à l'admin. Vous devrez saisir votre mot de passe actuel pour confirmer la modification.",
85
+ "account.password.editButton": "Changer le mot de passe",
86
+ "account.status.superAdmin": "Super-admin :",
87
+ "account.status.emailVerified": "E-mail vérifié :",
88
+ "account.status.status": "Statut :",
89
+ "account.status.enabled": "Activé",
90
+ "account.status.disabled": "Désactivé",
91
+ "account.status.help": "Ces indicateurs sont gérés par un administrateur disposant des autorisations appropriées et ne sont pas modifiables en libre-service.",
92
+ "account.preferences.interfaceLanguage": "Langue de l'interface :",
93
+ "account.preferences.editButton": "Changer de langue",
94
+ "account.preferences.help": "Le même paramètre est disponible dans le menu de langue de la barre supérieure.",
95
+ "account.update.fields.givenName": "Prénom",
96
+ "account.update.fields.familyName": "Nom",
97
+ "account.update.fields.username": "Nom d'utilisateur",
98
+ "account.update.fields.usernameHelp": "Facultatif. Laissez vide pour effacer.",
99
+ "account.update.errors.givenNameTooLong": "Le prénom ne doit pas dépasser {max, number} caractères",
100
+ "account.update.errors.familyNameTooLong": "Le nom ne doit pas dépasser {max, number} caractères",
101
+ "account.update.errors.usernameTooLong": "Le nom d'utilisateur ne doit pas dépasser {max, number} caractères",
102
+ "account.update.errors.invalidEmail": "Saisissez une adresse e-mail valide",
103
+ "account.update.errors.emailTooLong": "L'adresse e-mail ne doit pas dépasser {max, number} caractères",
104
+ "account.update.errors.emailInUse": "Cette adresse e-mail est déjà utilisée.",
105
+ "account.changePassword.intro": "Les autres sessions actives resteront valides jusqu'à l'expiration de leurs jetons. Déconnectez-vous ailleurs si vous pensez qu'un autre appareil a été compromis.",
106
+ "account.changePassword.fields.current": "Mot de passe actuel",
107
+ "account.changePassword.fields.new": "Nouveau mot de passe",
108
+ "account.changePassword.fields.confirm": "Confirmez le nouveau mot de passe",
109
+ "account.changePassword.errors.currentRequired": "Veuillez saisir votre mot de passe actuel",
110
+ "account.changePassword.errors.confirmRequired": "Veuillez confirmer le nouveau mot de passe",
111
+ "account.changePassword.errors.mismatch": "Les nouveaux mots de passe ne correspondent pas",
112
+ "account.changePassword.errors.currentIncorrect": "Le mot de passe actuel est incorrect.",
113
+ "account.changePassword.errors.couldNotChange": "Impossible de modifier le mot de passe. Veuillez réessayer.",
114
+ "account.changePassword.feedback.updated": "Mot de passe mis à jour.",
115
+ "dashboard.collectionDescription": "Collection {label}",
116
+ "dashboard.totalCount": "{count, number} au total",
117
+ "adminUsers.list.title": "Utilisateurs admin",
118
+ "adminUsers.list.columns.givenName": "Prénom",
119
+ "adminUsers.list.columns.familyName": "Nom",
120
+ "adminUsers.list.columns.email": "E-mail",
121
+ "adminUsers.list.columns.updated": "Mis à jour",
122
+ "adminUsers.list.columns.created": "Créé",
123
+ "adminUsers.list.createAriaLabel": "Créer un nouvel utilisateur admin",
124
+ "adminUsers.list.searchPlaceholder": "Rechercher par nom ou e-mail",
125
+ "adminUsers.list.pagerTopAriaLabel": "Pagination supérieure",
126
+ "adminUsers.list.pagerBottomAriaLabel": "Pagination inférieure",
127
+ "adminUsers.list.newDrawerTitle": "Nouvel utilisateur admin",
128
+ "adminUsers.list.createdToastTitle": "Utilisateur admin créé",
129
+ "adminUsers.breadcrumbDetail": "Utilisateur",
130
+ "adminUsers.detail.sections.account": "Détails du compte",
131
+ "adminUsers.detail.sections.roles": "Rôles",
132
+ "adminUsers.detail.sections.password": "Mot de passe",
133
+ "adminUsers.detail.sections.delete": "Supprimer l'utilisateur",
134
+ "adminUsers.detail.panels.update": "Détails du compte",
135
+ "adminUsers.detail.panels.setPassword": "Définir le mot de passe",
136
+ "adminUsers.detail.panels.delete": "Supprimer l'utilisateur admin",
137
+ "adminUsers.detail.panels.roles": "Rôles de l'utilisateur",
138
+ "adminUsers.detail.updateButton": "Modifier les détails",
139
+ "adminUsers.detail.rolesEmpty": "Aucun rôle attribué.",
140
+ "adminUsers.detail.editRolesButton": "Modifier les rôles",
141
+ "adminUsers.detail.password.intro": "Définissez un nouveau mot de passe pour cet utilisateur.",
142
+ "adminUsers.detail.password.setButton": "Définir le mot de passe",
143
+ "adminUsers.detail.delete.intro": "Supprimer définitivement cet utilisateur admin.",
144
+ "adminUsers.detail.delete.button": "Supprimer l'utilisateur admin",
145
+ "adminUsers.detail.rolesSavedToast": "Rôles enregistrés",
146
+ "adminUsers.detail.rolesAssignedDescription": "{count, plural, one {# rôle} other {# rôles}} attribué(s) à {email}.",
147
+ "adminUsers.delete.userLabel": "Utilisateur :",
148
+ "adminUsers.delete.emailLabel": "E-mail :",
149
+ "adminUsers.delete.warning": "Cela supprimera définitivement l'utilisateur admin. L'action est irréversible. Toutes les sessions actives seront invalidées au prochain rafraîchissement.",
150
+ "adminUsers.delete.confirmButton": "Supprimer l'utilisateur",
151
+ "adminUsers.delete.errors.selfDelete": "Vous ne pouvez pas supprimer votre propre compte admin.",
152
+ "adminUsers.delete.errors.versionConflict": "Cet utilisateur a été modifié ailleurs depuis l'ouverture de cette boîte de dialogue. Fermez la fenêtre et rechargez avant de réessayer.",
153
+ "adminUsers.delete.errors.notFound": "Cet utilisateur a déjà été supprimé.",
154
+ "adminUsers.delete.errors.fallback": "Impossible de supprimer cet utilisateur admin. Veuillez réessayer.",
155
+ "adminUsers.create.fields.password": "Mot de passe initial",
156
+ "adminUsers.create.fields.passwordHelp": "L'utilisateur pourra le modifier depuis son propre compte après s'être connecté.",
157
+ "adminUsers.create.fields.usernameHelp": "Facultatif.",
158
+ "adminUsers.create.flags.enabledLabel": "Activé",
159
+ "adminUsers.create.flags.enabledHelp": "Les comptes désactivés ne peuvent pas se connecter.",
160
+ "adminUsers.create.flags.emailVerifiedLabel": "E-mail vérifié",
161
+ "adminUsers.create.flags.emailVerifiedHelp": "Ignorer le processus de vérification pour ce compte.",
162
+ "adminUsers.create.flags.superAdminLabel": "Super-admin",
163
+ "adminUsers.create.flags.superAdminHelp": "Les super-admins ignorent toutes les vérifications d'autorisations — à accorder avec prudence.",
164
+ "adminUsers.create.errors.fallback": "Impossible de créer cet utilisateur admin. Veuillez réessayer.",
165
+ "adminUsers.update.errors.versionConflict": "Cet utilisateur a été modifié ailleurs depuis l'ouverture de ce formulaire. Rechargez pour obtenir les valeurs actuelles, puis réessayez.",
166
+ "adminUsers.update.errors.notFound": "Cet utilisateur n'existe plus.",
167
+ "adminUsers.setPassword.intro": "Définit un nouveau mot de passe pour {email}. L'utilisateur devra se reconnecter avec le nouveau mot de passe.",
168
+ "adminUsers.setPassword.errors.fallback": "Impossible de définir le mot de passe. Veuillez réessayer.",
169
+ "adminUsers.roles.emptyCatalog": "Aucun rôle n'a encore été créé. Créez d'abord des rôles dans /admin/roles.",
170
+ "adminUsers.roles.errors.userNotFound": "Cet utilisateur n'existe plus.",
171
+ "adminUsers.roles.errors.roleNotFound": "Un ou plusieurs rôles sélectionnés n'existent plus. Rechargez la page et réessayez.",
172
+ "adminUsers.roles.errors.fallback": "Impossible d'enregistrer les rôles. Veuillez réessayer.",
173
+ "routeError.titles.notFound": "Introuvable",
174
+ "routeError.titles.validation": "Erreur de validation",
175
+ "routeError.titles.conflict": "Conflit",
176
+ "routeError.titles.invalidTransition": "Transition non valide",
177
+ "routeError.titles.patchFailed": "Échec de la mise à jour",
178
+ "routeError.titles.database": "Erreur de base de données",
179
+ "routeError.titles.storage": "Erreur de stockage",
180
+ "routeError.titles.unhandled": "Erreur inattendue",
181
+ "routeError.defaultMessage": "Une erreur inattendue est survenue. Veuillez réessayer.",
182
+ "routeError.notFound.title": "Page introuvable",
183
+ "routeError.notFound.message": "La page que vous recherchez n'existe pas ou a été déplacée.",
184
+ "adminRoles.list.title": "Rôles admin",
185
+ "adminRoles.list.empty": "Aucun rôle admin trouvé",
186
+ "adminRoles.list.columns.name": "Nom",
187
+ "adminRoles.list.columns.machineName": "Nom machine",
188
+ "adminRoles.list.columns.description": "Description",
189
+ "adminRoles.list.columns.created": "Créé",
190
+ "adminRoles.list.createAriaLabel": "Créer un nouveau rôle admin",
191
+ "adminRoles.list.newDrawerTitle": "Nouveau rôle admin",
192
+ "adminRoles.list.createdToastTitle": "Rôle admin créé",
193
+ "adminRoles.breadcrumbDetail": "Rôle",
194
+ "adminRoles.list.saveOrder": "Enregistrer l'ordre",
195
+ "adminRoles.list.orderSavedToast": "Ordre enregistré",
196
+ "adminRoles.list.orderFailedToast": "Impossible d'enregistrer le nouvel ordre",
197
+ "adminRoles.list.orderFailedDescription": "Veuillez réessayer.",
198
+ "adminRoles.detail.title": "Détails du rôle",
199
+ "adminRoles.detail.editDetailsButton": "Modifier les détails",
200
+ "adminRoles.detail.deleteButton": "Supprimer le rôle",
201
+ "adminRoles.detail.fields.name": "Nom :",
202
+ "adminRoles.detail.fields.machineName": "Nom machine :",
203
+ "adminRoles.detail.fields.description": "Description :",
204
+ "adminRoles.detail.fields.created": "Créé :",
205
+ "adminRoles.detail.fields.updated": "Mis à jour :",
206
+ "adminRoles.detail.panels.update": "Détails du rôle",
207
+ "adminRoles.detail.panels.delete": "Supprimer le rôle admin",
208
+ "adminRoles.detail.permissionsSavedToast": "Permissions enregistrées",
209
+ "adminRoles.detail.permissionsSavedDescription": "{count, plural, one {# autorisation accordée} other {# autorisations accordées}} à {role}.",
210
+ "adminRoles.delete.roleLabel": "Rôle :",
211
+ "adminRoles.delete.machineLabel": "Nom machine :",
212
+ "adminRoles.delete.warning": "Cela supprimera définitivement le rôle. Les utilisateurs qui en disposent le perdent ; toutes les autorisations spécifiques au rôle sont retirées. L'action est irréversible.",
213
+ "adminRoles.delete.confirmButton": "Supprimer le rôle",
214
+ "adminRoles.delete.errors.versionConflict": "Ce rôle a été modifié ailleurs depuis l'ouverture de cette boîte de dialogue. Fermez la fenêtre et rechargez avant de réessayer.",
215
+ "adminRoles.delete.errors.notFound": "Ce rôle a déjà été supprimé.",
216
+ "adminRoles.delete.errors.fallback": "Impossible de supprimer ce rôle. Veuillez réessayer.",
217
+ "adminRoles.fields.name": "Nom",
218
+ "adminRoles.fields.machineName": "Nom machine",
219
+ "adminRoles.fields.description": "Description",
220
+ "adminRoles.create.fields.nameHelp": "Libellé lisible, par ex. « Éditeur ».",
221
+ "adminRoles.create.fields.machineNameHelp": "Identifiant stable côté code, par ex. « editor ». Non modifiable ultérieurement.",
222
+ "adminRoles.create.errors.nameRequired": "Le nom est obligatoire",
223
+ "adminRoles.create.errors.nameTooLong": "Le nom ne doit pas dépasser {max, number} caractères",
224
+ "adminRoles.create.errors.machineNameRequired": "Le nom machine est obligatoire",
225
+ "adminRoles.create.errors.machineNameTooLong": "Le nom machine ne doit pas dépasser {max, number} caractères",
226
+ "adminRoles.create.errors.machineNameInvalid": "Lettres minuscules, chiffres, tirets et traits de soulignement uniquement",
227
+ "adminRoles.create.errors.descriptionTooLong": "La description ne doit pas dépasser {max, number} caractères",
228
+ "adminRoles.create.errors.machineNameInUse": "Ce nom machine est déjà utilisé.",
229
+ "adminRoles.create.errors.fallback": "Impossible de créer ce rôle admin. Veuillez réessayer.",
230
+ "adminRoles.update.fields.machineNameHelp": "L'identifiant stable côté code. Non modifiable après création.",
231
+ "adminRoles.update.errors.versionConflict": "Ce rôle a été modifié ailleurs depuis l'ouverture de ce formulaire. Rechargez pour obtenir les valeurs actuelles, puis réessayez.",
232
+ "adminRoles.update.errors.notFound": "Ce rôle n'existe plus.",
233
+ "adminRoles.permissions.modeAriaLabel": "Mode des permissions",
234
+ "adminRoles.permissions.viewMode": "Afficher",
235
+ "adminRoles.permissions.editMode": "Modifier",
236
+ "adminRoles.permissions.selectAll": "Tout sélectionner",
237
+ "adminRoles.permissions.clear": "Effacer",
238
+ "adminRoles.permissions.groupCount": "{selected, number} sur {total, number} {mode, select, edit {sélectionnée(s)} other {accordée(s)}}",
239
+ "adminRoles.permissions.counter": "{selected, number} sur {total, number} {mode, select, edit {sélectionnée(s)} other {accordée(s)}} pour {role}",
240
+ "adminRoles.permissions.errors.roleNotFound": "Ce rôle n'existe plus.",
241
+ "adminRoles.permissions.errors.abilityUnregistered": "Une ou plusieurs autorisations sélectionnées ne sont plus enregistrées. Rechargez la page et réessayez.",
242
+ "adminRoles.permissions.errors.fallback": "Impossible d'enregistrer les permissions. Veuillez réessayer.",
243
+ "adminPermissions.title": "Inspecteur des autorisations",
244
+ "adminPermissions.countPill": "{count, number} enregistrée(s)",
245
+ "adminPermissions.lead": "Vue en lecture seule de toutes les autorisations enregistrées via bylineCore.abilities. Les collections enregistrent automatiquement les autorisations CRUD et de flux de travail ; les sous-systèmes admin déclarent leurs propres clés à la racine de composition via registerAdminAbilities.",
246
+ "adminPermissions.empty": "Aucune autorisation n'est enregistrée.",
247
+ "adminPermissions.group.abilitiesCount": "{count, plural, one {# autorisation} other {# autorisations}}",
248
+ "adminPermissions.row.holdersButton": "Détenteurs",
249
+ "adminPermissions.row.hideButton": "Masquer",
250
+ "adminPermissions.matrix.rolesTitle": "Rôles ({count, number})",
251
+ "adminPermissions.matrix.rolesEmpty": "Aucun rôle n'accorde cette autorisation.",
252
+ "adminPermissions.matrix.usersTitle": "Utilisateurs admin ({count, number})",
253
+ "adminPermissions.matrix.usersEmpty": "Aucun utilisateur admin ne dispose de cette autorisation.",
254
+ "adminPermissions.source.collection": "collection",
255
+ "adminPermissions.source.admin": "admin",
256
+ "adminPermissions.source.plugin": "extension",
257
+ "adminPermissions.source.core": "noyau",
258
+ "adminPermissions.source.unknown": "inconnu",
259
+ "collections.list.statusFilterAll": "Tous",
260
+ "collections.list.createAriaLabel": "Créer",
261
+ "collections.list.searchPlaceholder": "Rechercher",
262
+ "collections.list.pagerTopAriaLabel": "Pagination supérieure",
263
+ "collections.list.pagerBottomAriaLabel": "Pagination inférieure",
264
+ "collections.list.dragHandleAriaLabel": "Glisser pour réordonner",
265
+ "collections.list.dragDisabledAriaLabel": "Glisser-déposer désactivé tant que des filtres ou une recherche sont actifs",
266
+ "collections.list.sortManualOrderAriaLabel": "Trier par ordre manuel",
267
+ "collections.list.reorderFailedToast": "Impossible d'enregistrer le nouvel ordre",
268
+ "collections.list.reorderFailedDescription": "Veuillez réessayer.",
269
+ "collections.create.errorToastTitle": "Création : {label}",
270
+ "collections.create.errorToastDescription": "Une erreur est survenue lors de la création de {label}.",
271
+ "collections.edit.statusUpdateTitle": "Mise à jour du statut : {label}",
272
+ "collections.edit.statusChangedDescription": "Statut modifié en « {status} ».",
273
+ "collections.edit.statusChangeFailedDescription": "Échec du changement de statut : {message}",
274
+ "collections.edit.unpublishTitle": "Dépublication : {label}",
275
+ "collections.edit.unpublishedDescription": "La version publiée a été retirée.",
276
+ "collections.edit.unpublishFailedDescription": "Échec de la dépublication : {message}",
277
+ "collections.edit.duplicatedTitle": "{label} dupliqué",
278
+ "collections.edit.duplicateTitle": "Duplication : {label}",
279
+ "collections.edit.duplicatedAutoPathDescription": "Créé avec le chemin généré automatiquement « {path} » (le slug préféré était déjà utilisé).",
280
+ "collections.edit.duplicatedPathDescription": "Créé avec le chemin « {path} ». Mettez à jour le titre et le chemin dans le nouveau document.",
281
+ "collections.edit.duplicatedSuccessMessage": "{label} dupliqué.",
282
+ "collections.edit.duplicateFailedDescription": "Échec de la duplication : {message}",
283
+ "collections.edit.copyToLocaleTitle": "Copie vers la locale : {label}",
284
+ "collections.edit.copiedFieldsDescription": "{count, plural, one {# champ copié} other {# champs copiés}} de {source} vers {target}.",
285
+ "collections.edit.copiedNoFieldsDescription": "Aucun champ à copier de {source} vers {target} selon la règle actuelle.",
286
+ "collections.edit.copiedSuccessMessage": "Copié de {source} vers {target}.",
287
+ "collections.edit.copyFailedDescription": "Échec de la copie : {message}",
288
+ "collections.edit.deleteTitle": "Suppression : {label}",
289
+ "collections.edit.deletedDescription": "{label} a été supprimé.",
290
+ "collections.edit.deleteFailedDescription": "Échec de la suppression : {message}",
291
+ "collections.edit.updateTitle": "Mise à jour : {label}",
292
+ "collections.edit.updatedDescription": "{label} mis à jour.",
293
+ "collections.edit.updateFailedDescription": "Une erreur est survenue lors de la mise à jour de {label}.",
294
+ "collections.history.title": "Historique : {label}",
295
+ "collections.history.compareAriaLabel": "Comparer cette version avec la version actuelle",
296
+ "collections.history.compareTitle": "Comparer avec la version actuelle",
297
+ "collections.history.restoreButton": "Restaurer",
298
+ "collections.history.restoreButtonTitle": "Restaurer cette version comme brouillon actuel",
299
+ "collections.history.restoreModalTitle": "Restaurer la version",
300
+ "collections.restore.versionLabel": "Version :",
301
+ "collections.restore.createdLabel": "Créée :",
302
+ "collections.restore.warning": "Cela créera une nouvelle version brouillon de ce document à partir du contenu de la version {version}, et ce brouillon deviendra la version actuelle. Les versions existantes (y compris toute version publiée) sont conservées dans l'historique. Le brouillon restauré devra être publié via le flux de travail habituel.",
303
+ "collections.restore.confirmButton": "Restaurer comme brouillon",
304
+ "collections.restore.errors.alreadyCurrent": "Cette version est déjà la version actuelle du document.",
305
+ "collections.restore.errors.notFound": "La version sélectionnée est introuvable. L'historique est peut-être obsolète.",
306
+ "collections.restore.errors.forbidden": "Vous n'avez pas l'autorisation de restaurer des versions de cette collection.",
307
+ "collections.restore.errors.fallback": "Impossible de restaurer cette version. Veuillez réessayer.",
308
+ "collections.api.title": "API : {label}",
309
+ "collections.viewMenu.contentLocaleLabel": "Langue du contenu :",
310
+ "collections.viewMenu.localeAll": "Toutes",
311
+ "collections.viewMenu.depthLabel": "Profondeur :",
312
+ "collections.viewMenu.apiButton": "API",
313
+ "collections.preview.toastTitle": "Aperçu",
314
+ "collections.preview.failedDescription": "Impossible d'activer le mode aperçu : {message}",
315
+ "collections.preview.openAriaLabel": "Ouvrir l'aperçu",
316
+ "collections.preview.title": "Aperçu",
317
+ "collections.breadcrumbs.create": "Créer",
318
+ "collections.breadcrumbs.history": "Historique",
319
+ "collections.list.createdToastTitle": "{label} créé",
320
+ "collections.list.createdToastDescription": "{label} créé avec succès.",
321
+ "documentActions.copyToLocaleMenuItem": "Copier vers une langue",
322
+ "documentActions.delete.title": "Supprimer le document",
323
+ "documentActions.delete.warning": "Attention : cette action est irréversible. Voulez-vous vraiment supprimer ce document ?",
324
+ "documentActions.duplicate.title": "Dupliquer le document",
325
+ "documentActions.duplicate.intro": "Un nouveau document sera créé avec toutes les traductions (le cas échéant) clonées depuis celui-ci. Après la duplication, vous devriez :",
326
+ "documentActions.duplicate.bulletTitle": "Mettre à jour le titre du document (y compris les versions traduites). Le titre comporte actuellement le suffixe",
327
+ "documentActions.duplicate.bulletPath": "Vérifier le chemin système dans le widget de chemin — le chemin généré automatiquement reflétera le titre suffixé et ne correspondra probablement pas à ce que vous souhaitez à long terme.",
328
+ "documentActions.duplicate.previewLabel": "Aperçu (langue actuelle) :",
329
+ "documentActions.duplicate.busyButton": "Duplication…",
330
+ "documentActions.copyToLocale.title": "Copier vers une langue",
331
+ "documentActions.copyToLocale.intro": "Copiez le contenu de ce document d'une langue vers une autre. Les champs non traduisibles sont partagés entre les langues et ne changeront pas.",
332
+ "documentActions.copyToLocale.fromLabel": "Depuis :",
333
+ "documentActions.copyToLocale.toLabel": "Vers :",
334
+ "documentActions.copyToLocale.targetAriaLabel": "Langue cible",
335
+ "documentActions.copyToLocale.overwriteLabel": "Écraser les données existantes dans la langue cible",
336
+ "documentActions.copyToLocale.overwriteHelp": "Décoché : ne remplit que les champs cibles actuellement vides. Coché : remplace chaque champ traduisible par la valeur de la source.",
337
+ "documentActions.copyToLocale.confirmButton": "Copier",
338
+ "documentActions.copyToLocale.busyButton": "Copie en cours…",
339
+ "forms.status.label": "Statut :",
340
+ "forms.status.lastModified": "Dernière modification :",
341
+ "forms.status.created": "Créé :",
342
+ "forms.status.publishedLive": "Une version publiée est actuellement en ligne.",
343
+ "forms.status.publishedOn": "Publié le {date, date, medium}",
344
+ "forms.heading.create": "Créer",
345
+ "forms.heading.edit": "Modifier",
346
+ "forms.heading.createLabel": "Créer : {label}",
347
+ "forms.heading.editLabel": "Modifier : {label}",
348
+ "forms.actions.uploading": "Téléversement…",
349
+ "forms.actions.revertTo": "Revenir à {label}",
350
+ "forms.uploadFailedFieldError": "Échec du téléversement : {message}",
351
+ "forms.restoreWarnings.title": "Ce document a été chargé via une reconstruction au mieux possible",
352
+ "forms.restoreWarnings.body": "Le schéma de la collection a changé depuis la dernière sauvegarde de ce document et {count, plural, one {# champ n'a pas pu être restauré} other {# champs n'ont pas pu être restaurés}} selon la forme actuelle. Le formulaire ci-dessous n'affiche que les champs correspondant au nouveau schéma. L'enregistrement remplacera le document par la nouvelle forme — toute donnée non correspondante sera perdue. Pour la préserver, copiez ce qu'il vous faut avant d'enregistrer, ou supprimez ce document et recréez-le. Erreurs :",
353
+ "forms.navigationGuard.title": "Quitter sans enregistrer ?",
354
+ "forms.navigationGuard.message": "Vos modifications n'ont pas été enregistrées. Si vous quittez maintenant, vous les perdrez.",
355
+ "forms.navigationGuard.stayButton": "Rester sur cette page",
356
+ "forms.navigationGuard.leaveButton": "Quitter quand même",
357
+ "pathWidget.label": "Chemin",
358
+ "pathWidget.suggestedHint": "Suggestion : « {formatted} »",
359
+ "pathWidget.readOnlyHint": "Le chemin est défini dans la langue par défaut (« {locale} ») et s'applique à toutes les traductions.",
360
+ "pathWidget.willBeSavedAs": "Sera enregistré sous « {preview} »",
361
+ "pathWidget.srDescription": "Chemin URL géré par le système pour ce document.",
362
+ "pathWidget.regenerateButton": "Régénérer depuis {field}",
363
+ "pathWidget.regenerateAriaLabel": "Régénérer le chemin depuis le champ {field}",
364
+ "fields.blocks.addBlockAriaLabel": "Ajouter un bloc",
365
+ "fields.blocks.modalTitle": "Blocs",
366
+ "fields.array.addItemAriaLabel": "Ajouter un élément",
367
+ "fields.relation.selectPickerTitle": "Sélectionner {label}",
368
+ "fields.relation.changeAriaLabel": "Modifier {label}",
369
+ "fields.relation.removeAriaLabel": "Supprimer {label}",
370
+ "fields.relation.selectButton": "Sélectionner {label}…",
371
+ "fields.relation.unknownError": "Le champ de relation « {name} » cible une collection inconnue « {target} ».",
372
+ "fields.relation.unknownHint": "Enregistrez la collection dans votre configuration Byline ou corrigez le chemin cible.",
373
+ "fields.relation.picker.searchPlaceholder": "Rechercher",
374
+ "fields.relation.picker.empty": "Aucun document trouvé",
375
+ "fields.relation.picker.loadFailed": "Échec du chargement des documents",
376
+ "fields.file.empty": "Aucun fichier sélectionné",
377
+ "fields.file.downloadAriaLabel": "Télécharger le fichier",
378
+ "fields.file.removeAriaLabel": "Supprimer le fichier",
379
+ "fields.file.openInNewTabAriaLabel": "Ouvrir {filename} dans un nouvel onglet",
380
+ "fields.file.upload.zoneAriaLabel": "Téléverser un fichier — glisser-déposer ou cliquer pour parcourir",
381
+ "fields.file.upload.label": "Déposez le fichier ici ou",
382
+ "fields.file.upload.browse": "parcourir",
383
+ "fields.image.empty": "Aucune image sélectionnée",
384
+ "fields.image.removeAriaLabel": "Supprimer l'image",
385
+ "fields.image.openLightboxAriaLabel": "Ouvrir l'aperçu en taille réelle",
386
+ "fields.image.upload.zoneAriaLabel": "Téléverser une image — glisser-déposer ou cliquer pour parcourir",
387
+ "fields.image.upload.label": "Déposez l'image ici ou",
388
+ "fields.image.upload.browse": "parcourir",
389
+ "fields.image.upload.hint": "JPEG, PNG, WebP, GIF, SVG, AVIF",
390
+ "fields.image.upload.processing": "Traitement…",
391
+ "fields.image.upload.errors.notAnImage": "Veuillez sélectionner un fichier image.",
392
+ "fields.image.upload.errors.cannotRead": "Impossible de lire l'image. Veuillez essayer un autre fichier.",
393
+ "fields.fileMeta.filename": "Nom de fichier :",
394
+ "fields.fileMeta.original": "Original :",
395
+ "fields.fileMeta.type": "Type :",
396
+ "fields.fileMeta.size": "Taille :",
397
+ "fields.fileMeta.status": "Statut :",
398
+ "fields.fileMeta.storage": "Stockage :",
399
+ "fields.fileMeta.path": "Chemin :",
400
+ "fields.fileMeta.pendingUpload": "Téléversement en attente",
401
+ "fields.fileMeta.willUploadOnSave": "Sera téléversé à l'enregistrement",
402
+ "fields.imageMeta.dimensions": "Dimensions :",
403
+ "fields.imageMeta.format": "Format :",
404
+ "fields.imageMeta.thumbnail": "Miniature :",
405
+ "fields.imageMeta.thumbnailGenerated": "Générée",
406
+ "fields.imageMeta.thumbnailPending": "En attente",
407
+ "fields.sortable.expandAriaLabel": "Développer l'élément",
408
+ "fields.sortable.collapseAriaLabel": "Réduire l'élément",
409
+ "fields.draggableMenu.addBelow": "Ajouter en dessous",
410
+ "fields.draggableMenu.remove": "Supprimer",
411
+ "diffModal.title": "Comparaison de versions",
412
+ "diffModal.subtitleBefore": "Comparaison de",
413
+ "diffModal.subtitleAfter": "(à gauche) avec la version actuelle (à droite)",
414
+ "diffModal.closeAriaLabel": "Fermer la comparaison",
415
+ "diffModal.loading": "Chargement de la version…",
416
+ "diffModal.loadFailed": "Échec du chargement de la version",
417
+ "diffModal.currentVersion": "Version actuelle",
418
+ "statusBadge.publishedVersionLive": "Une version publiée est en ligne",
419
+ "presentation.formTabsAriaLabel": "Onglets du formulaire",
420
+ "validation.password.tooShort": "Le mot de passe doit comporter au moins 8 caractères.",
421
+ "validation.password.tooLong": "Le mot de passe ne doit pas dépasser 128 caractères.",
422
+ "validation.password.complexity": "Le mot de passe doit contenir au moins une lettre majuscule, une lettre minuscule, un chiffre et un caractère parmi : #?!@$%^&*-"
423
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+
9
+ import { describe, expect, it } from 'vitest'
10
+
11
+ import { adminTranslations, bundledLocales, en, fr } from './index.js'
12
+
13
+ describe('bundled locale data', () => {
14
+ it('exposes a non-empty bundledLocales list', () => {
15
+ expect(bundledLocales.length).toBeGreaterThan(0)
16
+ expect(bundledLocales).toContain('en')
17
+ })
18
+
19
+ it('exports the en bundle as a flat key → string record', () => {
20
+ const keys = Object.keys(en)
21
+ expect(keys.length).toBeGreaterThan(0)
22
+ for (const key of keys) {
23
+ expect(typeof en[key]).toBe('string')
24
+ }
25
+ })
26
+
27
+ it('exports the fr bundle with the same key set as en (no drift)', () => {
28
+ expect(new Set(Object.keys(fr))).toEqual(new Set(Object.keys(en)))
29
+ })
30
+
31
+ it('carries at least the headline action keys', () => {
32
+ expect(en['common.actions.save']).toBe('Save')
33
+ expect(fr['common.actions.save']).toBe('Enregistrer')
34
+ })
35
+ })
36
+
37
+ describe('adminTranslations()', () => {
38
+ it('defaults to the English byline-admin namespace when called with no args', () => {
39
+ const bundle = adminTranslations()
40
+ expect(bundle.en?.['byline-admin']?.['common.actions.save']).toBe('Save')
41
+ expect(bundle.fr).toBeUndefined()
42
+ })
43
+
44
+ it('returns only the requested locales', () => {
45
+ const bundle = adminTranslations({ locales: ['en', 'fr'] })
46
+ expect(bundle.en?.['byline-admin']?.['common.actions.save']).toBe('Save')
47
+ expect(bundle.fr?.['byline-admin']?.['common.actions.save']).toBe('Enregistrer')
48
+ })
49
+
50
+ it('returns an empty bundle when an empty locales list is passed', () => {
51
+ const bundle = adminTranslations({ locales: [] })
52
+ expect(bundle).toEqual({})
53
+ })
54
+
55
+ it('throws on an unknown locale code with the available set in the message', () => {
56
+ expect(() => adminTranslations({ locales: ['xx'] })).toThrow(/no bundled translation/i)
57
+ expect(() => adminTranslations({ locales: ['xx'] })).toThrow(/Available:.*en/i)
58
+ })
59
+
60
+ it('preserves locale order in the returned bundle keys', () => {
61
+ const bundle = adminTranslations({ locales: ['fr', 'en'] })
62
+ expect(Object.keys(bundle)).toEqual(['fr', 'en'])
63
+ })
64
+
65
+ it('every code in bundledLocales is accepted', () => {
66
+ expect(() => adminTranslations({ locales: bundledLocales })).not.toThrow()
67
+ })
68
+ })
@@ -0,0 +1,99 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+
9
+ /**
10
+ * `@byline/i18n/admin` — the built-in `byline-admin` namespace bundle
11
+ * and the `adminTranslations()` registry factory.
12
+ *
13
+ * Locale source files (`en.json`, `fr.json`, …) live alongside this
14
+ * module. Each is authored as plain JSON — translator-friendly, native
15
+ * to every translation tool, clean diffs — and Rslib inlines each into
16
+ * the ESM build at compile time. Consumers receive a plain JS module
17
+ * exporting the parsed objects; no `.json` URL crosses any runtime
18
+ * loader.
19
+ *
20
+ * Adding a locale: drop a new JSON file in this directory and add it to
21
+ * the `BUNDLES` map below. No new package, no new build, no new
22
+ * publishing step. Translators iterate on a single file.
23
+ *
24
+ * Plugins / extensions / custom fields follow the same shape inside
25
+ * their own packages — `@byline/ai/i18n/en.json`, etc. — and expose
26
+ * their own factory taking the same `{ locales }` shape.
27
+ */
28
+
29
+ import { mergeTranslations } from '../merge.js'
30
+ import enJson from './en.json'
31
+ import frJson from './fr.json'
32
+ import type { LocaleCode, NamespaceTranslations, TranslationBundle } from '../types.js'
33
+
34
+ const en: NamespaceTranslations = enJson
35
+ const fr: NamespaceTranslations = frJson
36
+
37
+ /**
38
+ * Map of every bundled locale → its `byline-admin` namespace
39
+ * translations. Static `import` statements above mean a consumer's
40
+ * bundler sees a fixed-size set at build time. Today's locales bundle
41
+ * eagerly; lazy loading is the [Phase 3](../../docs/I18N.md#phase-3--lazy-locale-loading)
42
+ * migration once locale count grows past ~5.
43
+ */
44
+ const BUNDLES: Readonly<Record<LocaleCode, NamespaceTranslations>> = {
45
+ en,
46
+ fr,
47
+ }
48
+
49
+ /** Locale codes for which a bundled translation ships in-package. */
50
+ export const bundledLocales: readonly LocaleCode[] = Object.freeze(Object.keys(BUNDLES))
51
+
52
+ /** Re-exported as typed consts for plugin authors who want the literal-key autocomplete. */
53
+ export { en, fr }
54
+ export type AdminNamespaceTranslations = typeof enJson
55
+
56
+ export interface AdminTranslationsOptions {
57
+ /**
58
+ * Locale codes to include in the returned bundle. Each must appear in
59
+ * `bundledLocales` — unknown codes throw at config time. Defaults to
60
+ * `['en']` when omitted, which is always available.
61
+ */
62
+ locales?: readonly LocaleCode[]
63
+ }
64
+
65
+ /**
66
+ * Build a `TranslationBundle` carrying the `byline-admin` namespace for
67
+ * each requested locale. Compose with plugin / extension bundles via
68
+ * `mergeTranslations(...)` in the host's `admin.config.ts`.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * import { adminTranslations } from '@byline/i18n/admin'
73
+ *
74
+ * defineClientConfig({
75
+ * i18n: {
76
+ * interface: { defaultLocale: 'en', locales: ['en', 'fr'] },
77
+ * translations: adminTranslations({ locales: ['en', 'fr'] }),
78
+ * },
79
+ * })
80
+ * ```
81
+ *
82
+ * @throws when a requested code is not in `bundledLocales`.
83
+ */
84
+ export function adminTranslations(options: AdminTranslationsOptions = {}): TranslationBundle {
85
+ const locales = options.locales ?? ['en']
86
+ const partials: TranslationBundle[] = []
87
+ for (const locale of locales) {
88
+ const bundle = BUNDLES[locale]
89
+ if (bundle == null) {
90
+ throw new Error(
91
+ `[adminTranslations] no bundled translation for locale '${locale}'. ` +
92
+ `Available: [${bundledLocales.join(', ')}]. ` +
93
+ `To add a locale, drop a new JSON file in @byline/i18n/src/admin/.`
94
+ )
95
+ }
96
+ partials.push({ [locale]: { 'byline-admin': bundle } })
97
+ }
98
+ return mergeTranslations(...partials)
99
+ }