229 lines
8.2 KiB
TypeScript
229 lines
8.2 KiB
TypeScript
import { afterEach, describe, expect, it } from 'vitest'
|
|
import { messages } from './messages'
|
|
import { setLocale, t } from './index'
|
|
|
|
const ROLE_KEYS = [
|
|
'Access',
|
|
'Roles',
|
|
'New role',
|
|
'Who can do what on this site. Each user has one role.',
|
|
'No custom roles yet',
|
|
"Couldn't load roles",
|
|
'You can see roles but not change them',
|
|
'Content permissions',
|
|
'Quick presets',
|
|
'Read only',
|
|
'Write own',
|
|
'Full content',
|
|
'General permissions',
|
|
'Expand all',
|
|
'{0} unsaved changes',
|
|
'Give the role a name.',
|
|
'A role named "{0}" already exists. Choose a different name.',
|
|
'This role changed while you were editing',
|
|
'Your access changed',
|
|
'The Owner role is locked',
|
|
'Only the owner can edit built-in roles',
|
|
'What this role can do',
|
|
'Role created',
|
|
'{0} is ready. Assign it from Users.',
|
|
'Role saved',
|
|
'{0} members have this role. Move them to another role first. Then {1} can be deleted.',
|
|
'Move {0} members and delete role',
|
|
"No one has this role. This can't be undone.",
|
|
'Can {0}.',
|
|
"Can't {0}.",
|
|
] as const
|
|
|
|
const PLACEHOLDER = /\{\d+\}/g
|
|
|
|
afterEach(() => setLocale('en'))
|
|
|
|
describe('Roles screens copy', () => {
|
|
it.each(ROLE_KEYS)('"%s" has a French entry', (key) => {
|
|
expect((messages as Record<string, string>)[key]).toMatch(/\S/)
|
|
})
|
|
|
|
it('keeps the same placeholders in French as in English for every entry', () => {
|
|
const mismatches = Object.entries(messages).filter(([english, french]) => {
|
|
const expected = (english.match(PLACEHOLDER) ?? []).sort().join()
|
|
const actual = (french.match(PLACEHOLDER) ?? []).sort().join()
|
|
return expected !== actual
|
|
})
|
|
|
|
expect(mismatches.map(([english]) => english)).toEqual([])
|
|
})
|
|
|
|
it('renders French with its values', () => {
|
|
setLocale('fr')
|
|
|
|
expect(t('{0} unsaved changes', [3])).toBe('3 modifications non enregistrées')
|
|
expect(t('Roles')).toBe('Rôles')
|
|
})
|
|
})
|
|
|
|
const USERS_ROLES_KEYS = [
|
|
'Your role',
|
|
'See what I can do',
|
|
'What you can do',
|
|
'A summary of your role, {0}. Read-only.',
|
|
'Change role',
|
|
'Change role for {0}',
|
|
'Their API keys follow the new role.',
|
|
'Transfer ownership to {0}',
|
|
'Type {0} to confirm',
|
|
'The email must match exactly.',
|
|
"Keys follow their creator's role",
|
|
'Follows role',
|
|
'What changed',
|
|
'Role {0} created',
|
|
'Role {0} edited',
|
|
'Role {0} deleted',
|
|
"{0}'s role changed from {1} to {2}",
|
|
'Ownership transferred from {0} to {1}',
|
|
'They get an email with a link to set a password.',
|
|
'Writer is the default. You can change a role later.',
|
|
] as const
|
|
|
|
describe('Users, Profile, API keys and Activity copy for roles', () => {
|
|
it.each(USERS_ROLES_KEYS)('"%s" has a French entry', (key) => {
|
|
expect((messages as Record<string, string>)[key]).toMatch(/\S/)
|
|
})
|
|
})
|
|
|
|
const FINAL_COPY: [string, (string | number)[], string][] = [
|
|
[
|
|
'{0} is now {1}, and their API keys follow the new role.',
|
|
['Ines Duarte', 'Content lead'],
|
|
'Ines Duarte a maintenant le rôle Content lead, et ses clés API suivent le nouveau rôle.',
|
|
],
|
|
["Couldn't save the role", [], "Impossible d'enregistrer le rôle"],
|
|
[
|
|
'Your changes are still here. Try again in a moment.',
|
|
[],
|
|
'Vos modifications sont toujours là. Réessayez dans un instant.',
|
|
],
|
|
['Try again', [], 'Réessayer'],
|
|
["Couldn't change the role", [], 'Impossible de modifier le rôle'],
|
|
[
|
|
'Nothing was changed. Try again in a moment.',
|
|
[],
|
|
"Rien n'a été modifié. Réessayez dans un instant.",
|
|
],
|
|
[
|
|
"Your role can't assign a role with more power than yours.",
|
|
[],
|
|
'Votre rôle ne peut pas attribuer un rôle plus puissant que le vôtre.',
|
|
],
|
|
['{0} no longer exists', ['Writer'], "Writer n'existe plus"],
|
|
[
|
|
'It was deleted somewhere else. Choose another role to move the members to.',
|
|
[],
|
|
'Il a été supprimé ailleurs. Choisissez un autre rôle pour y déplacer les membres.',
|
|
],
|
|
['Role still has members', [], 'Le rôle a encore des membres'],
|
|
[
|
|
'{0} now has 1 member. Move them to another role first.',
|
|
['Intern'],
|
|
"Intern a maintenant 1 membre. Déplacez-le d'abord vers un autre rôle.",
|
|
],
|
|
[
|
|
'{0} now has {1} members. Move them to another role first.',
|
|
['Intern', 3],
|
|
"Intern a maintenant 3 membres. Déplacez-les d'abord vers un autre rôle.",
|
|
],
|
|
["Couldn't move the members", [], 'Impossible de déplacer les membres'],
|
|
['Enter a valid email address.', [], 'Saisissez une adresse e-mail valide.'],
|
|
['This address already has an account.', [], 'Cette adresse a déjà un compte.'],
|
|
["Couldn't send the invite", [], "Impossible d'envoyer l'invitation"],
|
|
['Try again in a moment.', [], 'Réessayez dans un instant.'],
|
|
['Role changed elsewhere', [], 'Rôle modifié ailleurs'],
|
|
[
|
|
'{0} edited {1}, so nothing was saved. Reload and try again.',
|
|
['Jonas Weber', 'Contributor'],
|
|
"Jonas Weber a modifié Contributor, donc rien n'a été enregistré. Rechargez et réessayez.",
|
|
],
|
|
['Reload', [], 'Recharger'],
|
|
['That role no longer exists', [], "Ce rôle n'existe plus"],
|
|
['Role not changed', [], 'Rôle non modifié'],
|
|
[
|
|
"{0}'s role changed in the meantime, so nothing was saved. Reload and try again.",
|
|
['Ines Duarte'],
|
|
"Le rôle de Ines Duarte a changé entre-temps, donc rien n'a été enregistré. Rechargez et réessayez.",
|
|
],
|
|
['Ownership not transferred', [], 'Propriété non transférée'],
|
|
[
|
|
"{0}'s role changed in the meantime, so nothing was transferred. Check it and try again.",
|
|
['Jonas Weber'],
|
|
"Le rôle de Jonas Weber a changé entre-temps, donc rien n'a été transféré. Vérifiez-le et réessayez.",
|
|
],
|
|
['User not removed', [], 'Utilisateur non retiré'],
|
|
[
|
|
"{0}'s role changed in the meantime, so nothing was removed. Check it and try again.",
|
|
['Ines Duarte'],
|
|
"Le rôle de Ines Duarte a changé entre-temps, donc rien n'a été retiré. Vérifiez-le et réessayez.",
|
|
],
|
|
['Role changed in the meantime', [], 'Rôle modifié entre-temps'],
|
|
[
|
|
'{0} is now {1}. Your choice is kept. Check it and try again.',
|
|
['Ines Duarte', 'Admin'],
|
|
'Ines Duarte a maintenant le rôle Admin. Votre choix est conservé. Vérifiez-le et réessayez.',
|
|
],
|
|
[
|
|
'{0} is now {1}. What you typed is kept. Check the change, then try again.',
|
|
['Jonas Weber', 'Writer'],
|
|
'Jonas Weber a maintenant le rôle Writer. Ce que vous avez saisi est conservé. Vérifiez le changement, puis réessayez.',
|
|
],
|
|
['Reload member', [], 'Recharger le membre'],
|
|
['Role reloaded', [], 'Rôle rechargé'],
|
|
[
|
|
'Your {0} changes are still here. Review them, then save.',
|
|
[2],
|
|
'Vos 2 modifications sont toujours là. Relisez-les, puis enregistrez.',
|
|
],
|
|
['Use the saved role', [], 'Utiliser le rôle enregistré'],
|
|
['Keep my edits', [], 'Garder mes modifications'],
|
|
['Loading…', [], 'Chargement…'],
|
|
['Locked', [], 'Verrouillé'],
|
|
]
|
|
|
|
describe('Final copy: toasts and errors, EN and FR', () => {
|
|
it.each(FINAL_COPY)('"%s" reads in English and in French', (key, values, french) => {
|
|
expect(t(key as keyof typeof messages, values)).toContain(
|
|
key.replace(/\{(\d+)\}/g, (_, index) => String(values[Number(index)])),
|
|
)
|
|
setLocale('fr')
|
|
expect(t(key as keyof typeof messages, values).replace(/\u2019/g, "'")).toBe(french)
|
|
})
|
|
})
|
|
|
|
const PROPOSED_COPY = [
|
|
'Remove user',
|
|
'Remove {0}?',
|
|
'They lose access straight away, and the API keys they created stop working. Their articles, entries and media stay.',
|
|
"Couldn't remove the user",
|
|
'User removed',
|
|
'{0} no longer has access.',
|
|
"You can't remove yourself. Ask another owner or admin.",
|
|
'Online articles and the drafts you created.',
|
|
'Drafts by others are hidden',
|
|
'Your role reads online articles and the drafts you created. The counts follow the same rule.',
|
|
'You have no drafts',
|
|
"Drafts you create appear here. Your role can't see drafts by other people.",
|
|
'Your role shows only entries you created.',
|
|
"Entries by others aren't shown",
|
|
'Your role reads only entries you created. Ask an owner or admin if you need to see more.',
|
|
"You haven't created {0} yet",
|
|
"Your role shows only entries you created, so other people's {0} aren't listed here. Use New entry to add one.",
|
|
'{0} saved changes to {1} at {2}.',
|
|
'Your 1 change is still here. Review it, then save.',
|
|
'read online articles and their own drafts',
|
|
'read only entries they created',
|
|
] as const
|
|
|
|
describe('Proposed copy that the design does not give', () => {
|
|
it.each(PROPOSED_COPY)('"%s" has a French entry', (key) => {
|
|
expect((messages as Record<string, string>)[key]).toMatch(/\S/)
|
|
})
|
|
})
|