The last of the UX review's item 8. Ctrl+. and Ctrl+, step through the underlines from anywhere in the text; the card that opens takes focus and answers Tab / Shift+Tab / Enter / Del / ? / Esc itself. Answering a card advances to the next by itself, and the last one closes and puts the caret back in the prose — so a document is triaged in five presses of Enter. The item asked for bare Tab or n/p. Neither can exist in a text editor: an unmodified letter is a letter. They work fine once a card holds focus, which is where the item wanted them; getting there needs a chord that is safe to press mid-sentence, and mid-composition, so the entry keys are IME-guarded like every other binding. The queue is the underlines read off the decoration DOM in document order, not the suggestion list: a stop she cannot see is worse than one she never visits, and it guarantees the card can anchor itself. Escape is stopped at the card. Unhandled it would also have left distraction-free mode, restoring the sidebar and — via the rail-follows-the- mode fix — pulling the rail out from under her mid-triage. The legend is bilingual and leads with the pair language, unlike the card's English buttons: those name what she is learning, this is an instruction for operating Petal, like the status bar. Key names are as printed on her keyboard (Entrée, Suppr, Intro, Supr). The es pack's own punctuation test caught the "?" and is right in general; the key cap is one named exemption. Verified in a real browser at 1517x810 on a fresh database with no model, over CDP — a keystroke feature deserves real keystrokes. Both layouts, wrap in both directions, the accept/dismiss/advance loop, Ask Petal and back, the full triage-to-empty criterion, and Accept-all clicked from a keyboard card. The wiring has no unit test for the reason items 6, 7 and 8 recorded: jsdom has no layout. triage.ts is pure and tested; browser-verified is written down as browser-verified. Claude-Session: https://claude.ai/code/session_01GJHNvirh7Hzhc9RL3HAvz7
500 lines
28 KiB
TypeScript
500 lines
28 KiB
TypeScript
// The French pack — the third pair, and the first written against a groove
|
||
// rather than cutting one.
|
||
//
|
||
// ⚠️ REVIEWED BY FOUR MODELS, NOT BY A NATIVE SPEAKER.
|
||
// SUGGESTIONS.md §3 sets the bar: a pack should be reviewed by someone who
|
||
// speaks the pair before it is trusted — the same standard the zh copy got by
|
||
// being written for a real reader. That has still not happened. What has
|
||
// happened (2026-07-27) is an interim pass: four different models read this file
|
||
// independently as French speakers, and only findings at least two of them
|
||
// reached on their own were applied — five of them, listed in BUILD_PLAN Phase
|
||
// 24. A quorum of models agreeing is agreement, not authority: it caught a
|
||
// "clique droit" that is not French and an adjective disagreeing with "on", and
|
||
// it would not catch a line that is correct and lifeless. Treat this as a
|
||
// better-checked draft, and still expect a speaker to change the register long
|
||
// before the vocabulary.
|
||
//
|
||
// The choices this file makes, and why:
|
||
//
|
||
// * **Metropolitan French, not Québécois.** Unlike pt, the *dictionary* poses
|
||
// no regional question — Debian's fr_FR, fr_CA, fr_BE, fr_CH and fr_LU are
|
||
// all symlinks to one file — so the whole regional decision lives here in
|
||
// the copy: e-mail rather than courriel, tchatter rather than clavarder,
|
||
// week-end rather than fin de semaine. The Piper voice is fr_FR for the same
|
||
// reason. This is a choice, not a verdict; a Québécoise writer would want
|
||
// her own pack and should get one rather than a patched version of this.
|
||
// * **Tutoiement.** Petal is a companion in someone's private notebook, and
|
||
// *vous* would put a desk between them. Same call the pt-PT pack made about
|
||
// *tu* over *você*, for the same reason.
|
||
// * **"Se connecter" / "Se déconnecter"**, not "login" / "logout".
|
||
// * **French spacing and « guillemets », on purpose.** French puts a space
|
||
// before : ; ! ? and inside « », and this file does too — which is exactly
|
||
// the habit `prose.spaceBeforePunct` exists to warn her about in her
|
||
// *English*. The pack demonstrates, in its own punctuation, the rule its own
|
||
// prose note tells her not to carry across. It is an ordinary space rather
|
||
// than the typographically correct U+202F: a narrow no-break space is
|
||
// invisible in a diff, indistinguishable from a plain one in an editor, and
|
||
// the next pack author would strip it by accident. The cost is that a line
|
||
// may wrap before the « ! », which is a smaller problem than copy nobody can
|
||
// safely edit.
|
||
// * The 1990 spelling reform is left alone: this copy uses the traditional
|
||
// forms, and her dictionary accepts both (see build_hunspell_dictionary.py).
|
||
//
|
||
// French first, English underneath — same shape as the other packs, for the same
|
||
// reason: she reads her own language faster, and the English half is what she is
|
||
// here to learn.
|
||
|
||
import type { Pack } from '../types'
|
||
|
||
export const fr: Pack = {
|
||
code: 'fr',
|
||
nativeName: 'Français',
|
||
locale: 'fr-FR',
|
||
|
||
app: {
|
||
duplicateTitle: (title) => `${title} (copie)`,
|
||
garden: 'Jardin de mots',
|
||
history: 'Historique',
|
||
},
|
||
|
||
auth: {
|
||
title: 'Reconnecte-toi',
|
||
titleEn: 'Please sign in again',
|
||
bodyWithDraft:
|
||
'Ce que tu viens d’écrire est gardé sur cet appareil — reconnecte-toi et tout s’enregistrera tout seul.',
|
||
bodyWithDraftEn: "What you just wrote is safe on this device — it'll save itself once you're back in.",
|
||
bodyPlain: 'Ta session a expiré. Tout ce que tu as écrit est déjà enregistré.',
|
||
bodyPlainEn: 'Your session expired. Everything you wrote is already saved.',
|
||
signIn: 'Se connecter · Sign in',
|
||
},
|
||
|
||
companion: {
|
||
choose: 'Choisis un compagnon · Choose a companion',
|
||
|
||
encouragements: [
|
||
{ native: 'Voilà ! Cette phrase coule beaucoup mieux 🌸', en: 'Lovely — that reads so much smoother now.' },
|
||
{ native: 'Tu écris de mieux en mieux ✨', en: "You're getting better and better." },
|
||
{ native: 'J’aime beaucoup ce changement 💕', en: 'I really like that change.' },
|
||
{ native: 'Continue comme ça — tu y arrives !', en: 'Keep going — you’ve got this!' },
|
||
{ native: 'Mmh, c’est bien plus clair comme ça 👍', en: 'Mm, that’s much clearer.' },
|
||
{ native: 'Quel joli choix de mot 🌷', en: 'That’s such a good word choice.' },
|
||
{ native: 'Oh, ce paragraphe se lit tout seul ☁️', en: 'Ooh, that paragraph flows so nicely.' },
|
||
{ native: 'J’adore te voir écrire avec plus d’assurance 💛', en: 'I love watching you write with more confidence.' },
|
||
{ native: 'Chaque petit progrès compte 🌱', en: 'Every little bit of progress counts.' },
|
||
{ native: 'Tes mots brillent aujourd’hui ✨', en: 'Your words are sparkling today.' },
|
||
],
|
||
|
||
tips: [
|
||
{ native: 'Astuce : en anglais, les phrases courtes se lisent mieux.', en: 'Tip: shorter English sentences often read clearer.' },
|
||
{ native: 'N’oublie pas les articles « the » et « a ».', en: "Don't forget articles like “the” and “a”." },
|
||
{ native: 'Pour le passé, utilise le prétérit : go → went.', en: 'For the past, use past tense: go → went.' },
|
||
{ native: 'Lire à voix haute aide à repérer ce qui sonne bizarre.', en: 'Reading aloud helps you catch awkward spots.' },
|
||
{ native: 'Une idée par paragraphe, et tout devient limpide.', en: 'One idea per paragraph keeps it tidy.' },
|
||
{ native: 'Un doute ? Demande-moi ✨', en: 'Not sure about something? Just ask me. ✨' },
|
||
{ native: 'Le pluriel prend un « s » : two apples 🍎', en: 'Plurals take an “s”: two apples 🍎' },
|
||
// Two tips the zh pack has no use for: French and English share enough
|
||
// vocabulary to make both the traps below daily hazards.
|
||
{ native: 'Attention aux faux amis : « actually » ne veut pas dire *actuellement*.', en: 'Careful with false friends — “actually” means *in fact*.' },
|
||
{ native: 'En anglais, pas d’espace avant « ! » ni « ? » — c’est une habitude française.', en: 'English puts no space before “!” or “?” — that space is a French habit.' },
|
||
],
|
||
|
||
breaks: [
|
||
{ native: 'Tu écris depuis un moment — étire-toi et repose tes yeux 🍵', en: "You've been writing a while — stretch and rest your eyes. 🍵" },
|
||
{ native: 'Un verre d’eau et cinq minutes de pause ?', en: 'Sip some water and take five?' },
|
||
{ native: 'Regarde au loin un instant, ça soulage les yeux 🌿', en: 'Look into the distance for a moment — give your eyes a break. 🌿' },
|
||
],
|
||
|
||
// Late-night nudges. The English wit is the user's own and is kept word for
|
||
// word across every pack; the French line leads gently into it, exactly as
|
||
// the Mandarin and Portuguese ones do.
|
||
bedtime: [
|
||
{ native: 'Ton lit doit se demander où tu es 🛏️', en: 'I bet your bed is missing you right now.' },
|
||
{ native: 'Quand tu es fatiguée, tu écris mal — va te reposer 🌙', en: 'A tired writer is a bad writer — get some rest.' },
|
||
{ native: 'La nuit porte conseil ✨', en: 'Sleep is a wondrous enabler.' },
|
||
{ native: 'Tu entends ? Non… parce que tout le monde dort, et toi aussi tu devrais 😴', en: "Hear that? No… you don't, because everyone is sleeping and you should be too." },
|
||
// French proverbs on sleep and haste, in place of the Portuguese and
|
||
// Chinese ones — a pack is not a translation of another pack.
|
||
{ native: 'Qui dort dîne.', en: 'Sleep is its own kind of supper.' },
|
||
{ native: 'L’avenir appartient à ceux qui se lèvent tôt.', en: 'The future belongs to those who get up early.' },
|
||
{ native: 'Rien ne sert de courir, il faut partir à point.', en: 'No use running; you have to set off in good time.' },
|
||
],
|
||
|
||
greeting: { native: 'Coucou ! Je te tiens compagnie 🐱', en: "Hi! I'm right here keeping you company. 🐱" },
|
||
welcomeBack: { native: 'Te revoilà ✨ on continue !', en: 'Welcome back ✨ let’s keep going!' },
|
||
|
||
errors: [
|
||
{ native: 'Oups — un petit accroc, mais tes mots sont en sécurité.', en: 'Oops — a little hiccup, but your words are safe.' },
|
||
{ native: 'Zut, je me suis emmêlé les pinceaux une seconde — je reviens.', en: 'Haiya, I got stuck for a sec — back in a moment.' },
|
||
{ native: 'Ne t’en fais pas, on réessaie dans un instant 🍵', en: "Don't worry — let's try again in a bit. 🍵" },
|
||
],
|
||
|
||
milestone: (words: number) => ({
|
||
native: `Ouah ! Déjà ${words} mots 🎉`,
|
||
en: `Wow — ${words} words already! Amazing. 🎉`,
|
||
}),
|
||
|
||
// Une petite chose à écrire, proposée une fois par jour à une page blanche.
|
||
// Des souvenirs et des avis, jamais des exercices : il n’y a rien ici qu’on
|
||
// puisse rater, et c’est précisément l’intention.
|
||
invitations: [
|
||
{ native: 'Écris 50 mots : une petite chose qui t’a fait sourire aujourd’hui 🌸', en: 'Write 50 words: one small thing that made you smile today.' },
|
||
{ native: 'Écris 50 mots : la meilleure chose que tu as mangée aujourd’hui', en: 'Write 50 words: the best thing you ate today.' },
|
||
{ native: 'Écris 50 mots : ce que tu vois par ta fenêtre en ce moment', en: 'Write 50 words: what you can see out of your window right now.' },
|
||
{ native: 'Écris 50 mots : un endroit où tu retournerais volontiers', en: 'Write 50 words: somewhere you would happily go back to.' },
|
||
{ native: 'Écris 50 mots : une chose que tu as apprise cette semaine', en: 'Write 50 words: one thing you learned this week.' },
|
||
{ native: 'Écris 50 mots : un message à toi-même pour dans un an', en: 'Write 50 words: something to tell yourself a year from now.' },
|
||
{ native: 'Écris 50 mots : une chanson que tu écoutes en boucle en ce moment', en: 'Write 50 words: a song you have had on lately.' },
|
||
{ native: 'Écris 50 mots : quelqu’un que tu aimerais remercier aujourd’hui', en: 'Write 50 words: someone you would like to thank today.' },
|
||
],
|
||
inviteAccept: 'C’est parti · Let’s write',
|
||
inviteDecline: 'Pas aujourd’hui · Not today',
|
||
declined: { native: 'D’accord, je retourne dormir 😴', en: 'Fair enough — back to my nap. 😴' },
|
||
|
||
names: {
|
||
cat: 'Chat dormeur',
|
||
dog: 'Chien joyeux',
|
||
'wiggle-dog': 'Chien frétillant',
|
||
butterfly: 'Papillon',
|
||
parrot: 'Perroquet',
|
||
},
|
||
},
|
||
|
||
prose: {
|
||
longSentence: 'Cette phrase est un peu longue — la couper en deux ou trois la rendra plus claire 🌸',
|
||
commaSplice: 'Ici, deux phrases sont reliées par une simple virgule. Mets un point, ou relie-les avec « and / but ».',
|
||
vagueThis: (word) => `On ne sait pas bien à quoi « ${word} » renvoie — précise-le (par exemple « ${word} idea / change… »).`,
|
||
oxfordComma: 'Dans une énumération de trois éléments ou plus, une virgule avant « and / or » aide à lire (la virgule d’Oxford).',
|
||
transitionComma: (word) => `Après un mot de liaison en début de phrase, mets une virgule : « ${word}, … ».`,
|
||
capitalizeSentence: 'Commence chaque phrase par une majuscule.',
|
||
repeatedWord: (word) => `« ${word} » semble écrit deux fois — jette un œil.`,
|
||
capitalizeI: 'En anglais, le « I » (je) prend toujours une majuscule.',
|
||
// The rule this pack's own punctuation illustrates from the other side.
|
||
spaceBeforePunct: 'En anglais, pas d’espace avant la ponctuation : la virgule et le point se collent au mot. C’est l’inverse du français.',
|
||
spaceAfterPunct: 'Après une virgule ou un point, laisse un espace avant le mot suivant.',
|
||
articleAn: (word) => `Devant un son de voyelle, on met « an » : « an ${word} ».`,
|
||
articleA: (word) => `Devant un son de consonne, on met « a » : « a ${word} ».`,
|
||
uncountable: (word, singular) => `« ${word} » est indénombrable en anglais — pas de s, « ${singular} » suffit.`,
|
||
capitalizeProper: (fixed) => `En anglais, les langues, les nationalités, les jours et les mois prennent une majuscule : « ${fixed} ».`,
|
||
thirdPersonS: (subject, verb) => `Avec he/she/it, le verbe prend un -s : « ${subject} ${verb} ».`,
|
||
pluralAfter: (determiner, noun) => `Après « ${determiner} », le nom se met au pluriel : « ${determiner} ${noun}s ».`,
|
||
doubleDeterminer: (first, second) => `« ${first} ${second} » contient deux déterminants — n’en garde qu’un (enlève « ${first} », par exemple).`,
|
||
thereArePlural: (noun) => `Au pluriel, on dit « there are » : « there are ${noun}… ».`,
|
||
itsOwn: '« it’s » = « it is ». Pour dire « son / sa », c’est « its » — donc « its own ».',
|
||
itsIs: (rest) => `Ici c’est « it’s ${rest} » (it is) ; « its » est le possessif.`,
|
||
thanNotThen: (word) => `Dans une comparaison, on écrit « than », pas « then » : « ${word} than ».`,
|
||
preposition: (wrong, right) => `En anglais on dit « ${right} », pas « ${wrong} » — cette préposition est figée.`,
|
||
collocation: (wrong, right) => `En anglais, ces mots vont ensemble comme ceci : « ${right} », et non « ${wrong} ».`,
|
||
doubleComparative: (lead, word) => `« ${word} » est déjà le comparatif — pas besoin de « ${lead} » : « ${word} » suffit.`,
|
||
peopleArePlural: (verb) => `« People » est pluriel en anglais : « people ${verb} ».`,
|
||
ageIsNotHave: (years) => `En anglais, l’âge se dit avec *to be*, pas avec *avoir* : « I am ${years} years old ».`,
|
||
agreeIsAVerb: '« Agree » est déjà le verbe — pas de *to be* devant : on dit « I agree ».',
|
||
forNotSince: (duration) => `Pour une durée, on utilise « for » : « for ${duration} ». « Since » marque le point de départ (since 2020).`,
|
||
veryBeforeVerb: (verb) => `« Very » n’accompagne que les adjectifs, pas les verbes : « really ${verb} », ou « ${verb} … very much ».`,
|
||
turnOnNotOpen: (thing, on) => `En anglais, on n’ouvre pas un appareil, on l’allume : « turn ${on ? 'on' : 'off'} the ${thing} ».`,
|
||
althoughOrBut: (word) => `En anglais, on met « ${word} » ou « but », jamais les deux dans la même phrase.`,
|
||
},
|
||
|
||
// Les faux amis entre le français et l’anglais — le piège qui donne le
|
||
// sentiment d’être ridicule plutôt que simplement corrigée. D’où le simple
|
||
// avertissement : Petal ne remplace jamais le mot, parce que « actually »
|
||
// était peut-être bien celui qu’elle voulait.
|
||
falseFriends: {
|
||
actually: {
|
||
native: '« Actually » veut dire *en fait*, pas *actuellement*. Pour « actuellement », on dit « currently » ou « nowadays ».',
|
||
en: '“Actually” means *in fact*. For the French *actuellement*, English uses “currently”.',
|
||
},
|
||
eventually: {
|
||
native: '« Eventually » veut dire *finalement, tôt ou tard* — pas *éventuellement*. Pour cela : « possibly » ou « if necessary ».',
|
||
en: '“Eventually” means *in the end*, not *possibly*.',
|
||
},
|
||
library: {
|
||
native: '« Library » est la *bibliothèque*. La *librairie* se dit « bookshop » / « bookstore ».',
|
||
en: '“Library” is where books are lent; a shop that sells them is a “bookshop”.',
|
||
},
|
||
sensible: {
|
||
native: '« Sensible » veut dire *raisonnable*. Pour *sensible*, on dit « sensitive ».',
|
||
en: '“Sensible” means level-headed; the French *sensible* is “sensitive”.',
|
||
},
|
||
assist: {
|
||
native: '« Assist » veut dire *aider*. Pour *assister à* (être présent), on dit « attend ».',
|
||
en: '“Assist” means to help; *assister à* is “attend”.',
|
||
},
|
||
attend: {
|
||
native: '« Attend » veut dire *assister à*. Pour *attendre*, on dit « wait ».',
|
||
en: '“Attend” means to go to something; *attendre* is “to wait”.',
|
||
},
|
||
pretend: {
|
||
native: '« Pretend » veut dire *faire semblant*. Pour *prétendre* (affirmer), on dit « claim ».',
|
||
en: '“Pretend” means to fake something; *prétendre* is “to claim”.',
|
||
},
|
||
deception: {
|
||
native: '« Deception » veut dire *tromperie*. La *déception* se dit « disappointment ».',
|
||
en: '“Deception” means being misled; *déception* is “disappointment”.',
|
||
},
|
||
delay: {
|
||
native: '« Delay » veut dire *retard*. Un *délai* se dit « deadline » ou « time limit ».',
|
||
en: '“Delay” is lateness; a French *délai* is a “deadline”.',
|
||
},
|
||
achieve: {
|
||
native: '« Achieve » veut dire *réussir, accomplir*. Pour *achever* (terminer), on dit « finish » ou « complete ».',
|
||
en: '“Achieve” means to accomplish; *achever* is “to finish”.',
|
||
},
|
||
rest: {
|
||
native: '« Rest » veut dire *se reposer* (ou *le reste*). Pour *rester*, on dit « stay ».',
|
||
en: '“Rest” is to relax; *rester* is “to stay”.',
|
||
},
|
||
journey: {
|
||
native: '« Journey » est un *voyage*. Une *journée* se dit « day ».',
|
||
en: '“Journey” is a trip; *journée* is a “day”.',
|
||
},
|
||
location: {
|
||
native: '« Location » est un *endroit*. La *location* (louer) se dit « rental » ou « renting ».',
|
||
en: '“Location” is a place; the French *location* is a “rental”.',
|
||
},
|
||
travel: {
|
||
native: '« Travel » veut dire *voyager*. Pour *travailler*, on dit « work ».',
|
||
en: '“Travel” means to journey; *travailler* is “to work”.',
|
||
},
|
||
pass: {
|
||
native: '« Pass an exam » veut dire *réussir* un examen. Pour *passer* un examen, on dit « take an exam ».',
|
||
en: '“Pass an exam” means you succeeded; *passer un examen* is “to take” one.',
|
||
},
|
||
resume: {
|
||
native: '« Resume » veut dire *reprendre*. Un *résumé* se dit « summary » (aux États-Unis, « résumé » est un CV).',
|
||
en: '“Resume” means to start again; a *résumé* is a “summary”.',
|
||
},
|
||
college: {
|
||
native: '« College » est l’enseignement supérieur. Le *collège* français se dit « middle school ».',
|
||
en: '“College” is higher education; a French *collège* is “middle school”.',
|
||
},
|
||
envy: {
|
||
native: '« Envy » est la *jalousie*. Pour *avoir envie de*, on dit « to feel like » ou « to want ».',
|
||
en: '“Envy” is jealousy; *avoir envie de* is “to feel like”.',
|
||
},
|
||
crayon: {
|
||
native: '« Crayon » est un *crayon de couleur* (en cire). Le *crayon à papier* se dit « pencil ».',
|
||
en: '“Crayon” is a wax colouring stick; a French *crayon* is a “pencil”.',
|
||
},
|
||
coin: {
|
||
native: '« Coin » est une *pièce de monnaie*. Le *coin* (angle) se dit « corner ».',
|
||
en: '“Coin” is money; the French *coin* is a “corner”.',
|
||
},
|
||
figure: {
|
||
native: '« Figure » est un *chiffre* ou une *silhouette*. La *figure* (visage) se dit « face ».',
|
||
en: '“Figure” is a number or a shape; the French *figure* is a “face”.',
|
||
},
|
||
comprehensive: {
|
||
native: '« Comprehensive » veut dire *complet, exhaustif*. Pour *compréhensif* (indulgent), on dit « understanding ».',
|
||
en: '“Comprehensive” means thorough; *compréhensif* is “understanding”.',
|
||
},
|
||
},
|
||
|
||
docs: {
|
||
sortRecent: 'Récents · Recent',
|
||
sortTitle: 'Titre · Title',
|
||
sortLongest: 'Les plus longs · Longest',
|
||
backUpAll: 'Tout sauvegarder · Back up all :',
|
||
signOut: 'Se déconnecter · Sign out',
|
||
duplicate: 'Dupliquer · Duplicate',
|
||
searchPlaceholder: 'Rechercher · Search',
|
||
searching: 'Recherche… · Searching…',
|
||
noMatches: 'Aucun résultat · No matches',
|
||
tags: 'Étiquettes · Tags',
|
||
newTagPlaceholder: 'Nouvelle étiquette · New tag',
|
||
language: 'Langue · Language',
|
||
languageFailed: 'Le changement n’a pas abouti — la langue n’a pas bougé · Couldn’t switch',
|
||
},
|
||
|
||
editor: {
|
||
askPlaceholder: 'Ask why… / Demande pourquoi…',
|
||
chatFailed: 'Je n’ai pas réussi à répondre — repose-moi la question, s’il te plaît. 🌸\n\nI had trouble answering just now — please ask me again. 🌸',
|
||
findPlaceholder: 'Rechercher · Find',
|
||
findNone: 'Rien · 0',
|
||
matchCase: 'Match case · Respecter la casse',
|
||
close: 'Close · Fermer',
|
||
replacePlaceholder: 'Remplacer par · Replace',
|
||
replace: 'Remplacer',
|
||
replaceAll: 'Tout',
|
||
translateLabel: 'Traduction · Translate',
|
||
// The key names are the ones printed on a French keyboard — Entrée, Suppr,
|
||
// Échap — not their English equivalents. A legend she has to translate back
|
||
// to find the key is not a legend.
|
||
triageHint: {
|
||
native: 'Tab suivant · Entrée accepter · Suppr ignorer · ? demander à Petal · Échap quitter',
|
||
en: 'Tab next · Enter accept · Del dismiss · ? Ask Petal · Esc exit',
|
||
},
|
||
spelling: 'Orthographe · Spelling',
|
||
noSuggestions: 'Aucune suggestion · No suggestions',
|
||
addToDictionary: 'Ajouter au dictionnaire · Add to dictionary',
|
||
readSelection: 'Lire la sélection à voix haute · Read selection aloud',
|
||
rewrite: 'Réécrire · Rewrite',
|
||
rewriting: 'Réécriture… · Rewriting…',
|
||
rewriteFailed: 'La réécriture n’a pas abouti — réessaie · Couldn’t rewrite',
|
||
cancel: 'Annuler · Cancel',
|
||
retry: 'Réessayer · Retry',
|
||
useThis: 'Utiliser celle-ci · Use this',
|
||
word: 'Mot · Word',
|
||
inGarden: 'Déjà dans le jardin · In your garden (tap to remove)',
|
||
saveToGarden: 'Garder dans le jardin · Save to garden',
|
||
readAloud: 'Lire à voix haute · Read aloud',
|
||
readSlowly: 'Lire lentement · Read slowly',
|
||
readAloudNative: 'Lire en français · Read in French',
|
||
lookingUp: 'Recherche… · Looking up…',
|
||
definition: 'Définition · Definition',
|
||
synonyms: 'Synonymes · Synonyms',
|
||
tapToSwap: 'appuie pour changer · tap to swap',
|
||
nothingFound: 'Je n’ai pas trouvé ce mot · Nothing found for this word',
|
||
origin: 'Origine · Origin',
|
||
// The French pair sees this constantly — English took so much from French
|
||
// that the collisions are the rule rather than the exception: chat, pain,
|
||
// coin, sale, four, or, car, ton, son.
|
||
alsoIn: 'C’est aussi un mot français · Also a word in French',
|
||
wordBands: {
|
||
simple: { native: 'De tous les jours', en: 'Everyday word' },
|
||
standard: { native: 'Courant', en: 'Standard' },
|
||
advanced: { native: 'Avancé', en: 'Advanced' },
|
||
},
|
||
},
|
||
|
||
styles: {
|
||
natural: { native: 'Plus naturel', en: 'Natural' },
|
||
academic: { native: 'Académique', en: 'Academic' },
|
||
professional: { native: 'Professionnel', en: 'Professional' },
|
||
casual: { native: 'Décontracté', en: 'Casual' },
|
||
humorous: { native: 'Drôle', en: 'Humorous' },
|
||
creative: { native: 'Créatif', en: 'Creative' },
|
||
persuasive: { native: 'Persuasif', en: 'Persuasive' },
|
||
},
|
||
|
||
tones: {
|
||
general: { native: 'Général', en: 'General' },
|
||
academic: { native: 'Académique', en: 'Academic' },
|
||
professional: { native: 'Professionnel', en: 'Professional' },
|
||
casual: { native: 'Décontracté', en: 'Casual' },
|
||
humorous: { native: 'Drôle', en: 'Humorous' },
|
||
creative: { native: 'Créatif', en: 'Creative' },
|
||
persuasive: { native: 'Persuasif', en: 'Persuasive' },
|
||
},
|
||
|
||
exports: {
|
||
label: 'Exporter',
|
||
print: 'Imprimer / PDF',
|
||
formats: {
|
||
md: { native: 'Markdown', en: 'Markdown (.md)' },
|
||
docx: { native: 'Document Word', en: 'Word (.docx)' },
|
||
html: { native: 'Page web', en: 'Web page (.html)' },
|
||
txt: { native: 'Texte brut', en: 'Plain text (.txt)' },
|
||
},
|
||
},
|
||
|
||
garden: {
|
||
title: 'Jardin de mots · Vocabulary Garden',
|
||
titleWithFlower: '🌷 Jardin de mots · Vocabulary Garden',
|
||
reviewing: 'Révision · Reviewing — recall, then grade yourself',
|
||
subtitle: 'Words you looked up, blooming as you learn them',
|
||
reviewDue: (n) => `Réviser ${n} mot${n === 1 ? '' : 's'} · Review ${n} due 🌸`,
|
||
emptyLead: 'Ton jardin est encore vide.',
|
||
emptyHint: 'Fais un clic droit sur un mot anglais pour le chercher — et il germera ici.',
|
||
due: 'à réviser · due',
|
||
seen: (reps, intervalDays) => `revu ${reps}× · seen ${reps}× · intervalle ${intervalDays} j`,
|
||
readAloud: '🔊 Lire',
|
||
readSlowly: '🐢 Lentement',
|
||
source: '📄 Source',
|
||
remove: '🗑 Retirer',
|
||
growing: (n) => `🐱💤 ${n} fleur${n === 1 ? '' : 's'} au jardin · ${n} blossom${n > 1 ? 's' : ''} growing`,
|
||
end: 'Terminer · End',
|
||
promptProduction: 'Quel est le mot anglais ? · Which English word?',
|
||
promptRecognition: 'Qu’est-ce que ça veut dire ? · What does this mean?',
|
||
showAnswer: 'Voir la réponse · Show answer',
|
||
gradeAgain: { native: 'À revoir', en: 'Again' },
|
||
gradeGood: { native: 'Je m’en souviens', en: 'Good' },
|
||
gradeEasy: { native: 'Facile', en: 'Easy' },
|
||
},
|
||
|
||
journal: {
|
||
tabGarden: '🌷 Jardin · Garden',
|
||
tabJournal: '🌱 Progrès · Growth',
|
||
subtitle: 'Your own writing, month by month — only ever you and your past self',
|
||
empty: 'Écris encore un peu — cette page pousse à partir de ton propre travail. · Keep writing; this page grows out of your own work.',
|
||
keptHead: 'Ce mois-ci · This month',
|
||
kept: (n) => `${n} chose${n === 1 ? '' : 's'} que tu as retenue${n === 1 ? '' : 's'} · ${n} thing${n === 1 ? '' : 's'} you took on board`,
|
||
keptBefore: (n) => `${n} le mois précédent · ${n} the month before`,
|
||
stuckHead: 'Resté avec toi · Stayed with you',
|
||
stuck: (phrase, docs) =>
|
||
`« ${phrase} » — tu l’écris toute seule maintenant, dans ${docs} de tes textes · now in ${docs} of your pieces`,
|
||
fadedHead: 'Tu n’as plus besoin de corriger · You stopped needing this',
|
||
faded: (pattern, times) =>
|
||
`« ${pattern} » — ${times}× à l’époque, aucune ce mois-ci · ${times}× back then, none this month`,
|
||
cheerStuck: (phrase) => ({
|
||
native: `Tu écris « ${phrase} » toute seule maintenant ! 🌱`,
|
||
en: `You’re using “${phrase}” on your own now! 🌱`,
|
||
}),
|
||
cheerFaded: (pattern) => ({
|
||
native: `Ça fait un moment que « ${pattern} » n’a plus besoin d’être repris 😌`,
|
||
en: `“${pattern}” hasn’t needed fixing in a while 😌`,
|
||
}),
|
||
},
|
||
|
||
history: {
|
||
title: 'Historique · History',
|
||
kinds: {
|
||
manual: { native: 'Point gardé', en: 'Saved point' },
|
||
auto: { native: 'Automatique', en: 'Auto' },
|
||
pre_restore: { native: 'Avant restauration', en: 'Before restore' },
|
||
},
|
||
justNow: 'just now · à l’instant',
|
||
minutesAgo: (n) => `${n} min ago · il y a ${n} min`,
|
||
hoursAgo: (n) => `${n} hr ago · il y a ${n} h`,
|
||
daysAgo: (n) => `${n} day${n > 1 ? 's' : ''} ago · il y a ${n} jour${n > 1 ? 's' : ''}`,
|
||
preview: 'Aperçu · Preview',
|
||
restoring: 'Restoring…',
|
||
restoreThis: 'Restaurer cette version · Restore this version',
|
||
passport: '📜 Passeport d’écriture · Writing passport',
|
||
keepFullHistory: 'Garder tout l’historique · Keep full history',
|
||
},
|
||
|
||
status: {
|
||
savedLocally: 'Gardé sur cet appareil · Kept on this device',
|
||
helperRestingNative: 'L’assistant se repose',
|
||
helperRestingEn: "· Petal's helper is resting · ton texte est enregistré",
|
||
petalsToPolish: (n) => ({
|
||
native: `${n} ${n === 1 ? 'pétale' : 'pétales'} à polir`,
|
||
en: `${n} ${n === 1 ? 'petal' : 'petals'} to polish`,
|
||
}),
|
||
soundsOn: 'Sons activés · Sounds on',
|
||
soundsOff: 'Sons coupés · Sounds off',
|
||
petalsOn: 'Pétales activés · Petals on',
|
||
petalsOff: 'Pétales coupés · Petals off',
|
||
statsTitle: 'Statistiques · Writing stats',
|
||
stats: {
|
||
words: { native: 'Mots', en: 'Words' },
|
||
characters: { native: 'Caractères', en: 'Characters' },
|
||
sentences: { native: 'Phrases', en: 'Sentences' },
|
||
paragraphs: { native: 'Paragraphes', en: 'Paragraphs' },
|
||
pages: { native: 'Pages', en: 'Pages' },
|
||
readingTime: { native: 'Temps de lecture', en: 'Reading time' },
|
||
avgWordLength: { native: 'Longueur moyenne', en: 'Avg word length' },
|
||
variety: { native: 'Variété du vocabulaire', en: 'Word variety' },
|
||
readability: { native: 'Niveau de lecture', en: 'Reading level' },
|
||
},
|
||
readability: {
|
||
easy: { native: 'Facile', en: 'Easy' },
|
||
standard: { native: 'Courant', en: 'Standard' },
|
||
fairlyHard: { native: 'Assez difficile', en: 'Fairly hard' },
|
||
advanced: { native: 'Avancé', en: 'Advanced' },
|
||
},
|
||
},
|
||
|
||
toolbar: {
|
||
untitledHeading: '(sans titre)',
|
||
outline: 'Plan · Outline',
|
||
outlineHint: 'Utilise H1/H2/H3 pour créer des titres, et le plan apparaîtra ici.',
|
||
},
|
||
|
||
update: {
|
||
available: 'Une nouvelle version est disponible',
|
||
refresh: 'Actualiser · Refresh',
|
||
dismiss: 'Plus tard · Dismiss',
|
||
},
|
||
}
|