Petal learns French, and the pack that shipped was misspelling itself
Phase 24, the fr half: langpack, Hunspell dictionary, Piper voice, and the lexicon coverage that turned out to have been measured already (63.1%, better than pt-PT's 62.1%). No migration; not deployed. The plan recorded that build_ptpt_dictionary.py "generalizes" to French. It did not. It handled single-character flags and plain PFX/SFX and stopped on everything else, and fr.aff uses four of the things it stopped on. FLAG long is the dangerous one: French flags are two characters, so the old reader's set(flagstr) yields a bag of unrelated letters and expands every entry through the wrong paradigm without ever erroring. Plus continuation flags (French really does affix an affixed form), NEEDAFFIX on 68,075 of 84,140 stems, and FULLSTRIP. Renamed build_hunspell_dictionary.py with a per-language profile, asserting that CIRCUMFIX and FORBIDDENWORD are still unused rather than assuming it — and it rebuilds pt-PT byte-identical to the shipped asset, which is the only thing that makes "generalized" a claim rather than a hope. Elision was decided by building both halves and measuring. Keeping l'arbre and its thirty-three siblings: 3,159,832 forms, 8.25 MB gzipped. Dropping them: 473,326 and 1.19 MB. They are not new words, but the tokenizer keeps internal apostrophes, so they genuinely would have been underlined — so they moved out of the dictionary into withElision, which splits at a known clitic and still requires the remainder to be a word (l'zzzz stays flagged). Real nspell: 369 ms and 74 MB, against pt-PT's 842 ms and 139 MB, on the larger language. Where the regional trap lives is the mirror image of Portuguese's: every fr_* Piper voice is fr_FR and Debian's fr_FR/fr_CA/fr_BE dictionaries are one shared word list, so nothing can be quietly wrong about the country and the whole decision sits in the copy. What French has instead is the 1990 reform, packaged three ways; comprehensive ships, because Petal never corrects her French and coût and cout are both correct. Then the interim review pass, at the user's suggestion and explicitly "for now": four models read each Latin pack independently, and only findings at least two of them reached on their own were applied — five per pack. It earned its keep on the pack that was already live. pt-PT was carrying pre-Acordo spellings (adjectivos, actualmente) in a file whose own header commits to post-Acordo, plus Brazilian decepção, because the Phase 21 greps checked for Brazilian vocabulary and never checked the pack against its own spelling policy. That grep now exists and was confirmed to fail on the old text before being kept. Where reviewers agreed a line was wrong but split on the fix, the wording is mine and the reasoning is in BUILD_PLAN rather than averaged away. Still owed, and both packs now say so precisely: a quorum of models agreeing is agreement, not authority. No native speaker has read either pack, and none of this has been seen in a browser. go build/vet/test clean, tsc, vite build, vitest 190/190. Claude-Session: https://claude.ai/code/session_016y6gyuHkQXPiEuW8RGQyua
This commit is contained in:
@@ -0,0 +1,486 @@
|
||||
// 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…',
|
||||
findPlaceholder: 'Rechercher · Find',
|
||||
findNone: 'Rien · 0',
|
||||
matchCase: 'Match case · Respecter la casse',
|
||||
close: 'Close · Fermer',
|
||||
replacePlaceholder: 'Remplacer par · Replace',
|
||||
replace: 'Remplacer',
|
||||
replaceAll: 'Tout',
|
||||
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é",
|
||||
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',
|
||||
},
|
||||
}
|
||||
+20
-11
@@ -1,12 +1,21 @@
|
||||
// The European Portuguese pack — the first pair that is not Chinese, and the
|
||||
// one that proves a language really is data.
|
||||
//
|
||||
// ⚠️ WRITTEN BUT NOT YET REVIEWED BY A NATIVE SPEAKER.
|
||||
// ⚠️ REVIEWED BY FOUR MODELS, NOT BY A pt-PT SPEAKER.
|
||||
// SUGGESTIONS.md §3 sets the bar: "the pt-PT pack should be reviewed by a pt-PT
|
||||
// speaker before it's trusted — same standard the zh copy got by being written
|
||||
// for a real reader." That review has not happened. Until it does, treat every
|
||||
// line here as a good-faith draft rather than as shipped copy, and expect a
|
||||
// speaker to change the register long before they change the vocabulary.
|
||||
// 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 European Portuguese speakers, and only findings at least two
|
||||
// of them reached on their own were applied — see BUILD_PLAN Phase 24.
|
||||
//
|
||||
// It found something worth the whole exercise: this file was carrying
|
||||
// **pre-Acordo spellings** — *adjectivos*, *actualmente* — in direct
|
||||
// contradiction of the paragraph directly below, and *decepção*, which is the
|
||||
// Brazilian form. The test greps guarded against Brazilian vocabulary and never
|
||||
// against the pack's own stated spelling policy; they do now. Treat this as a
|
||||
// better-checked draft, and still expect a speaker to change the register long
|
||||
// before they change the vocabulary.
|
||||
//
|
||||
// European Portuguese, not Brazilian. That is the single most likely way for
|
||||
// this file to go quietly wrong, so the choices are deliberate throughout:
|
||||
@@ -93,7 +102,7 @@ export const ptPT: Pack = {
|
||||
{ native: 'A tua cama deve estar com saudades 🛏️', en: 'I bet your bed is missing you right now.' },
|
||||
{ native: 'Cansada não se escreve bem — vai descansar 🌙', en: 'A tired writer is a bad writer — get some rest.' },
|
||||
{ native: 'Dorme sobre o assunto, que as ideias vêm sozinhas ✨', en: 'Sleep is a wondrous enabler.' },
|
||||
{ native: 'Ouves? Pois não… está toda a gente a dormir, e tu também devias 😴', en: "Hear that? No… you don't, because everyone is sleeping and you should be too." },
|
||||
{ native: 'Ouves? Pois não ouves… está toda a gente a dormir, e tu também devias 😴', en: "Hear that? No… you don't, because everyone is sleeping and you should be too." },
|
||||
// Portuguese proverbs on sleep and haste, in place of the Chinese ones —
|
||||
// a pack is not a translation of another pack.
|
||||
{ native: 'Deitar cedo e cedo erguer dá saúde e faz crescer.', en: 'Early to bed and early to rise makes you healthy and helps you grow.' },
|
||||
@@ -135,7 +144,7 @@ export const ptPT: Pack = {
|
||||
names: {
|
||||
cat: 'Gato dorminhoco',
|
||||
dog: 'Cão contente',
|
||||
'wiggle-dog': 'Cão abanão',
|
||||
'wiggle-dog': 'Cão abana-rabo',
|
||||
butterfly: 'Borboleta',
|
||||
parrot: 'Papagaio',
|
||||
},
|
||||
@@ -170,7 +179,7 @@ export const ptPT: Pack = {
|
||||
ageIsNotHave: (years) => `Em inglês a idade é com o verbo *to be*, não com *have*: “I am ${years} years old”.`,
|
||||
agreeIsAVerb: '“Agree” já é o verbo — não leva *to be* à frente: diz-se “I agree”.',
|
||||
forNotSince: (duration) => `Para uma duração usa-se “for”: “for ${duration}”. O “since” marca o início (since 2020).`,
|
||||
veryBeforeVerb: (verb) => `“Very” só acompanha adjectivos, não verbos: “really ${verb}”, ou “${verb} … very much”.`,
|
||||
veryBeforeVerb: (verb) => `“Very” só acompanha adjetivos, não verbos: “really ${verb}”, ou “${verb} … very much”.`,
|
||||
turnOnNotOpen: (thing, on) => `Em inglês os aparelhos não se abrem nem se fecham — ligam-se e desligam-se: “turn ${on ? 'on' : 'off'} the ${thing}”.`,
|
||||
althoughOrBut: (word) => `Em inglês usa-se “${word}” ou “but”, nunca os dois na mesma frase.`,
|
||||
},
|
||||
@@ -181,8 +190,8 @@ export const ptPT: Pack = {
|
||||
// que ela queria.
|
||||
falseFriends: {
|
||||
actually: {
|
||||
native: '“Actually” quer dizer *na verdade*, não *actualmente*. Para “actualmente” diz-se “currently” / “nowadays”.',
|
||||
en: '“Actually” means *in fact*. For the Portuguese *actualmente*, English uses “currently”.',
|
||||
native: '“Actually” quer dizer *na verdade*, não *atualmente*. Para “atualmente” diz-se “currently” / “nowadays”.',
|
||||
en: '“Actually” means *in fact*. For the Portuguese *atualmente*, English uses “currently”.',
|
||||
},
|
||||
eventually: {
|
||||
native: '“Eventually” quer dizer *por fim, mais cedo ou mais tarde* — não *eventualmente*. Para isso: “possibly” ou “if necessary”.',
|
||||
@@ -245,8 +254,8 @@ export const ptPT: Pack = {
|
||||
en: '“Costume” is fancy dress; *costumes* are “customs”.',
|
||||
},
|
||||
deception: {
|
||||
native: '“Deception” é *engano*. A *decepção* é “disappointment”.',
|
||||
en: '“Deception” means being misled; *decepção* is “disappointment”.',
|
||||
native: '“Deception” é *engano*. A *deceção* é “disappointment”.',
|
||||
en: '“Deception” means being misled; *deceção* is “disappointment”.',
|
||||
},
|
||||
injury: {
|
||||
native: '“Injury” é uma *lesão*. A *injúria* é “insult”.',
|
||||
|
||||
Reference in New Issue
Block a user