The es pair, and a dictionary that was quietly Spain's
Phase 25. Spanish was never built — the groundwork was all [x] (DreamDict data, the prompt language, the L1 rule gating, TTS env-discovery), which is why the plan read as though it had shipped. shippedPairs was the honest answer: the server had been refusing es on purpose. The langpack is neutral Latin American, chosen with the user: tú, ustedes, no vosotros, and the pan-American half of every vocabulary split. A vitest greps for the peninsular twins the way fr is greped for québécismes — including coger, which is not merely regional but obscene through most of Latin America. The dictionary is the story. Debian's hunspell-es symlinks twenty country codes to one file, which reads as pan-Hispanic; RLA publishes twenty-four builds per release, one per country plus a generic es that is the union, and Debian ships peninsular es_ES. The 58,622-form gap is essentially voseo, so the first version of this commit underlined vení and tenés as misspellings and called it a considered gap. The MUST_ACCEPT list was written to catch exactly that and structurally could not: it asserted the pan-Hispanic vocabulary, and every RLA variant carries the full pan-Hispanic vocabulary — only the paradigms are localised. The REP table cited as the second witness is shared by all builds too. Two independent-looking proofs, neither able to distinguish anything, agreeing with each other. The profile now demands what discriminates, each verified against the build it targets: voseo rejects es_ES and Debian, vosotros rejects es_MX, and arepa/chévere/bacán reject es_AR, which has both paradigms and would otherwise pass. 717,640 forms, 1.74 MB gzipped, 762 ms / 97 MB in a real nspell. fr and pt-PT rebuild byte-identical from their own upstream debs, so the shared script still means what it meant. Shipping the union is fr's call arrived at from the other side: coût and cout are both correct French, tienes and tenés are both correct Spanish. The dictionary holds every variety because underlining is all it can do; the copy picks a register because speaking requires one. Reviewed by four models at the usual >=2-of-4 threshold, 5 of 27 findings applied — one catching the bedtime proverb as fr's Qui dort dîne calqued into Spanish, gloss and all, which is the rule the fr header states. One below-threshold finding (a missing ¡, seen by 1 of 4 because an absent opening mark has no closing ! to look wrong against) was applied and turned into an assertion instead: the suite now rejects any native line that closes ? or ! without opening one. piper-es on es_MX-ald-medium, not the es_ES-davefx-medium the plan named — six of Piper's nine Spanish voices are peninsular, so the obvious pick was the pt-PT trap through a different door. go build/vet/test, tsc, vite, vitest 251/251. Not deployed, not seen in a browser, not read by a native speaker, and no es account exists.
This commit is contained in:
+114
-5
@@ -4,12 +4,13 @@ import { onPackChange, pack, resetPackForTests, setPackLang, shippedPacks } from
|
||||
import { zh } from './packs/zh'
|
||||
import { ptPT } from './packs/pt-PT'
|
||||
import { fr } from './packs/fr'
|
||||
import { es } from './packs/es'
|
||||
import type { Pack } from './types'
|
||||
|
||||
// Every pack that ships. Shape assertions run over all of them, because the
|
||||
// point of Phase 19 was that a language is data — and data that only the first
|
||||
// author's pack satisfies isn't a shape, it's a coincidence.
|
||||
const PACKS: Pack[] = [zh, ptPT, fr]
|
||||
const PACKS: Pack[] = [zh, ptPT, fr, es]
|
||||
|
||||
// Every string a pack would ever put on screen, and nothing else — field names
|
||||
// excluded (see the pt-PT grep below for what including them cost). Templates are
|
||||
@@ -49,8 +50,10 @@ describe('pack selection', () => {
|
||||
it('falls back rather than blanking on a pair with no pack yet', () => {
|
||||
// A pair_lang the deployment has no copy for is a deployment that got ahead
|
||||
// of its translation. She should still get a working editor. (This was 'fr'
|
||||
// until Phase 24 gave fr a pack; 'es' is the pair still waiting for one.)
|
||||
setPackLang('es')
|
||||
// until Phase 24, then 'es' until Phase 25 — every pair PairLang names now
|
||||
// has a pack, so the stand-in is a regional code Petal has not decided
|
||||
// about, which is the realistic version of this failure anyway.)
|
||||
setPackLang('es-ES')
|
||||
expect(pack()).toBe(zh)
|
||||
setPackLang('klingon')
|
||||
expect(pack()).toBe(zh)
|
||||
@@ -70,7 +73,7 @@ describe('pack selection', () => {
|
||||
expect(seen).not.toHaveBeenCalled()
|
||||
|
||||
// An unshipped pair resolves back to zh, which is also not a change.
|
||||
setPackLang('es')
|
||||
setPackLang('es-ES')
|
||||
expect(seen).not.toHaveBeenCalled()
|
||||
|
||||
setPackLang('pt-PT')
|
||||
@@ -83,7 +86,7 @@ describe('pack selection', () => {
|
||||
// matching allowlist exists to enforce from the other side.
|
||||
it('offers exactly the pairs it has copy for', () => {
|
||||
const codes = shippedPacks().map((p) => p.code)
|
||||
expect(codes.sort()).toEqual(['fr', 'pt-PT', 'zh'])
|
||||
expect(codes.sort()).toEqual(['es', 'fr', 'pt-PT', 'zh'])
|
||||
// Every offered pair names itself, because a writer stranded on the wrong
|
||||
// pack can only read the label that is in her own language.
|
||||
for (const p of shippedPacks()) expect(p.nativeName.length).toBeGreaterThan(0)
|
||||
@@ -364,6 +367,97 @@ describe('the fr pack', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('the es pack', () => {
|
||||
// Spanish has no regional question in its dictionary at all — hunspell-es
|
||||
// ships twenty country codes and every one is a symlink to one pan-Hispanic
|
||||
// word list — so, even more than with French, the entire regional decision
|
||||
// lives in this file. Neutral Latin American was chosen deliberately, and a
|
||||
// stray peninsular form is invisible to everyone reviewing the diff.
|
||||
it('is Latin American, not peninsular', () => {
|
||||
const text = copyOf(es).toLowerCase()
|
||||
for (const bad of [
|
||||
'ordenador', 'vosotros', 'zumo', 'patata', 'coche',
|
||||
'gafas', 'billete', 'chaval', 'guay',
|
||||
// The one that is not merely regional: *coger* is an everyday verb in
|
||||
// Spain and obscene through most of Latin America. A companion in a
|
||||
// private notebook must never produce it by accident.
|
||||
'coger',
|
||||
]) {
|
||||
expect(text, `peninsular form "${bad}" in the es pack`).not.toMatch(
|
||||
new RegExp(`\\b${bad}\\b`),
|
||||
)
|
||||
}
|
||||
// And the accent it is read aloud in. Six of Piper's nine Spanish voices
|
||||
// are es_ES, so the wrong country is the easy default here — the pt-PT
|
||||
// trap, not the fr non-question.
|
||||
expect(es.locale).toBe('es-MX')
|
||||
})
|
||||
|
||||
// Spanish opens its questions and exclamations, and the easiest place to
|
||||
// forget is exactly where a reviewer's eye slides past: inside a Line's
|
||||
// native half, and inside an interpolated template. Every opening mark in the
|
||||
// pack is deliberate; a missing one is a typo the type system cannot see.
|
||||
it('opens every question and exclamation it closes', () => {
|
||||
const lines: { native: string; where: string }[] = []
|
||||
const walk = (node: unknown, path: string) => {
|
||||
if (typeof node === 'function') return walk((node as (...a: unknown[]) => unknown)(1, 'x'), path)
|
||||
if (!node || typeof node !== 'object') return
|
||||
const rec = node as Record<string, unknown>
|
||||
// A Line is the one shape whose `native` is pure Spanish — the flat
|
||||
// "Spanish · English" strings carry English punctuation too, so they are
|
||||
// asserted by hand below rather than by rule.
|
||||
if (typeof rec.native === 'string' && typeof rec.en === 'string') {
|
||||
lines.push({ native: rec.native, where: path })
|
||||
return
|
||||
}
|
||||
for (const [k, v] of Object.entries(rec)) walk(v, path ? `${path}.${k}` : k)
|
||||
}
|
||||
walk(es, '')
|
||||
expect(lines.length).toBeGreaterThan(40)
|
||||
for (const { native, where } of lines) {
|
||||
if (native.includes('?')) expect(native, `${where} closes ? without ¿`).toContain('¿')
|
||||
if (native.includes('!')) expect(native, `${where} closes ! without ¡`).toContain('¡')
|
||||
}
|
||||
// An exclamative opening with Qué/Cómo/Cuánto is the case that slips past a
|
||||
// reader, because it carries no closing "!" to look wrong against — the
|
||||
// whole pair is simply absent. The quorum review caught exactly one of
|
||||
// these ("Qué linda elección de palabra"), and only one reviewer of four
|
||||
// saw it, which is the argument for asserting it instead of re-reviewing it.
|
||||
for (const { native, where } of lines) {
|
||||
expect(native, `${where} opens an exclamative without ¡`).not.toMatch(
|
||||
/^(Qué|Cómo|Cuánto|Cuánta)\b/,
|
||||
)
|
||||
}
|
||||
// And the two-language strings, by hand: both halves punctuate their own way.
|
||||
expect(es.garden.promptRecognition).toBe('¿Qué significa? · What does this mean?')
|
||||
expect(es.garden.promptProduction).toContain('¿Cuál es la palabra en inglés?')
|
||||
})
|
||||
|
||||
it('renders its interpolated lines with the value in place', () => {
|
||||
expect(es.app.duplicateTitle('Primavera')).toBe('Primavera (copia)')
|
||||
expect(es.companion.milestone(300).native).toContain('300 palabras')
|
||||
// Spanish agreement is the pack's business; the call site only ever passes
|
||||
// a number. `flor`/`flores` is the irregular one — it takes -es, not -s.
|
||||
expect(es.garden.reviewDue(1)).toContain('1 palabra ·')
|
||||
expect(es.garden.reviewDue(4)).toContain('4 palabras ·')
|
||||
expect(es.garden.growing(1)).toContain('1 flor en el jardín')
|
||||
expect(es.garden.growing(3)).toContain('3 flores en el jardín')
|
||||
expect(es.journal.kept(1)).toContain('1 cosa que te llevaste')
|
||||
expect(es.journal.kept(5)).toContain('5 cosas que te llevaste')
|
||||
expect(es.status.petalsToPolish(1).native).toContain('1 pétalo por pulir')
|
||||
expect(es.status.petalsToPolish(2).native).toContain('2 pétalos por pulir')
|
||||
})
|
||||
|
||||
it('says the collision line, which this pair meets constantly', () => {
|
||||
// real, red, once, pie, sin, pan, mayor, sale, ropa — Spanish and English
|
||||
// collide about as often as French and English do.
|
||||
expect(es.editor.alsoIn).toBeTruthy()
|
||||
expect(es.editor.alsoIn).not.toBe(zh.editor.alsoIn)
|
||||
expect(es.editor.alsoIn).not.toBe(fr.editor.alsoIn)
|
||||
expect(es.editor.alsoIn).not.toBe(ptPT.editor.alsoIn)
|
||||
})
|
||||
})
|
||||
|
||||
// False friends are a per-pair dataset rather than copy: the Latin pairs carry
|
||||
// the traps their writers actually fall into, and the zh pair legitimately has
|
||||
// none. Both halves of that are worth pinning.
|
||||
@@ -391,6 +485,21 @@ describe('false friends', () => {
|
||||
expect(Object.keys(fr.falseFriends).length).toBeGreaterThan(10)
|
||||
})
|
||||
|
||||
it('the es pair carries the ones that cost most', () => {
|
||||
// "embarrassed" is the reason this feature exists at all: *embarazada* is
|
||||
// "pregnant", and it is the single false friend most likely to be said out
|
||||
// loud to a room. "molest" is the other one that has to be here, because
|
||||
// *molestar* is an everyday word and the English is not.
|
||||
for (const word of ['embarrassed', 'molest', 'actually', 'realize', 'exit', 'carpet']) {
|
||||
expect(es.falseFriends[word], word).toBeDefined()
|
||||
}
|
||||
// Spanish shares more Latin with English than either of the other Latin
|
||||
// pairs, so this list is the longest of the four and should stay that way.
|
||||
expect(Object.keys(es.falseFriends).length).toBeGreaterThan(
|
||||
Object.keys(fr.falseFriends).length,
|
||||
)
|
||||
})
|
||||
|
||||
it('is keyed by the lowercase English word, so a lookup can find it', () => {
|
||||
for (const p of PACKS) {
|
||||
for (const key of Object.keys(p.falseFriends)) {
|
||||
|
||||
@@ -18,12 +18,15 @@ import type { Pack, PairLang } from './types'
|
||||
import { zh } from './packs/zh'
|
||||
import { ptPT } from './packs/pt-PT'
|
||||
import { fr } from './packs/fr'
|
||||
import { es } from './packs/es'
|
||||
|
||||
export type { Pack, PairLang, Line } from './types'
|
||||
|
||||
// Every pack Petal ships. es is the same two lines when its copy is written —
|
||||
// TypeScript names every string a new pack still owes.
|
||||
const PACKS: Partial<Record<PairLang, Pack>> = { zh, 'pt-PT': ptPT, fr }
|
||||
// Every pack Petal ships — and now every pair PairLang names, so this map is
|
||||
// no longer Partial by necessity. It stays Partial anyway: the next pair will
|
||||
// be declared in the type before its copy exists, exactly as es was, and the
|
||||
// gap between the two is the point.
|
||||
const PACKS: Partial<Record<PairLang, Pack>> = { zh, 'pt-PT': ptPT, fr, es }
|
||||
|
||||
const DEFAULT_LANG: PairLang = 'zh'
|
||||
|
||||
|
||||
@@ -0,0 +1,550 @@
|
||||
// The Spanish pack — the fourth pair, and the second written straight into the
|
||||
// groove Phase 24 cut.
|
||||
//
|
||||
// ⚠️ 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. That has still not happened. What has
|
||||
// happened (2026-07-28) is the same interim pass the fr and pt-PT packs got —
|
||||
// four models read this file independently as Latin American Spanish speakers,
|
||||
// and only findings at least two of them reached on their own were applied,
|
||||
// listed in BUILD_PLAN Phase 25. A quorum of models agreeing is agreement, not
|
||||
// authority: it can catch a verb form no one says and a register that slips into
|
||||
// Spain, and it cannot catch a line that is correct and lifeless. Treat this as a
|
||||
// better-checked draft.
|
||||
//
|
||||
// The choices this file makes, and why:
|
||||
//
|
||||
// * **Latin American neutral, not peninsular.** Chosen deliberately (user,
|
||||
// 2026-07-28) over es-ES: it is the Spanish far more people write, and the
|
||||
// "neutral" register is a real thing that Spanish-language publishing and
|
||||
// dubbing have spent decades stabilising. So: *tú* for the singular,
|
||||
// **ustedes** for the plural and no *vosotros* anywhere, and the pan-American
|
||||
// half of every vocabulary split — *computadora*, *celular*, *carro*, *jugo*,
|
||||
// *papa*, *departamento*, *lentes*, *boleto*. A vitest greps this file for the
|
||||
// peninsular twins the way the fr pack is grepped for québécismes, because a
|
||||
// stray *ordenador* is invisible to everyone reviewing the diff.
|
||||
// * **The dictionary makes the opposite choice on purpose, and that is not a
|
||||
// contradiction.** This copy is Latin American; the spelling dictionary
|
||||
// behind it accepts *every* variety of Spanish, peninsular and voseante
|
||||
// alike (RLA's generic build — see web/public/dictionaries/es/LICENSE). The
|
||||
// two answer different questions: the copy is Petal *speaking*, where a
|
||||
// register has to be chosen, and the dictionary is Petal *listening*, where
|
||||
// the only available action is to underline something. Choosing a register
|
||||
// to write in costs a reader nothing; choosing one to accept would tell her
|
||||
// that her own conjugation is a typo.
|
||||
// * **Tuteo.** Petal is a companion in someone's private notebook, and *usted*
|
||||
// would put a desk between them — the same call the pt-PT pack made about
|
||||
// *tu* over *você* and the fr pack about *tu* over *vous*.
|
||||
// * **Tuteo here, voseo accepted there.** This copy says *tú*, because neutral
|
||||
// Latin American is tuteo and something had to be chosen. The dictionary
|
||||
// nonetheless accepts *vení* and *tenés*, so a Rioplatense writer is never
|
||||
// told her own present tense is a misspelling — she simply reads a companion
|
||||
// that speaks a slightly different Spanish than she writes, which is true of
|
||||
// every Spanish speaker reading anything.
|
||||
// * **¿Inverted marks, siempre!** Spanish opens questions and exclamations and
|
||||
// this file does too — including inside interpolated lines, where it is
|
||||
// easiest to forget. It is also the one punctuation habit that costs her
|
||||
// nothing in English: unlike the French space before « ! », there is no
|
||||
// Spanish mark to carry across by accident, so no prose note has to warn
|
||||
// about it.
|
||||
// * Quotation marks are the curly “ ” rather than « », which is the American
|
||||
// convention and the commoner one in Spanish outside Spain.
|
||||
//
|
||||
// Spanish 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 es: Pack = {
|
||||
code: 'es',
|
||||
nativeName: 'Español',
|
||||
// Mexican Spanish is the standard "neutral" broadcast variety and the one
|
||||
// Piper has a Latin American voice for (es_MX-ald-medium). The peninsular
|
||||
// es_ES-davefx-medium the plan originally named would have read this copy in
|
||||
// the accent it was written to avoid.
|
||||
locale: 'es-MX',
|
||||
|
||||
app: {
|
||||
duplicateTitle: (title) => `${title} (copia)`,
|
||||
garden: 'Jardín de palabras',
|
||||
history: 'Historial',
|
||||
},
|
||||
|
||||
auth: {
|
||||
title: 'Vuelve a entrar',
|
||||
titleEn: 'Please sign in again',
|
||||
bodyWithDraft:
|
||||
'Lo que acabas de escribir está guardado en este dispositivo — vuelve a entrar y se guardará solo.',
|
||||
bodyWithDraftEn: "What you just wrote is safe on this device — it'll save itself once you're back in.",
|
||||
bodyPlain: 'Tu sesión expiró. Todo lo que escribiste ya está guardado.',
|
||||
bodyPlainEn: 'Your session expired. Everything you wrote is already saved.',
|
||||
signIn: 'Iniciar sesión · Sign in',
|
||||
},
|
||||
|
||||
companion: {
|
||||
choose: 'Elige un compañero · Choose a companion',
|
||||
|
||||
encouragements: [
|
||||
{ native: '¡Eso! Esa oración fluye mucho mejor 🌸', en: 'Lovely — that reads so much smoother now.' },
|
||||
{ native: 'Cada vez escribes mejor ✨', en: "You're getting better and better." },
|
||||
{ native: 'Me gusta mucho ese cambio 💕', en: 'I really like that change.' },
|
||||
{ native: '¡Sigue así, lo estás logrando!', en: 'Keep going — you’ve got this!' },
|
||||
{ native: 'Mmm, así queda mucho más claro 👍', en: 'Mm, that’s much clearer.' },
|
||||
{ native: '¡Qué linda elección de palabra! 🌷', en: 'That’s such a good word choice.' },
|
||||
{ native: 'Ay, ese párrafo se lee solito ☁️', en: 'Ooh, that paragraph flows so nicely.' },
|
||||
{ native: 'Me encanta verte escribir con más confianza 💛', en: 'I love watching you write with more confidence.' },
|
||||
{ native: 'Cada avance cuenta, por chiquito que sea 🌱', en: 'Every little bit of progress counts.' },
|
||||
{ native: 'Hoy tus palabras están brillando ✨', en: 'Your words are sparkling today.' },
|
||||
],
|
||||
|
||||
tips: [
|
||||
{ native: 'Consejo: en inglés, las oraciones cortas se leen mejor.', en: 'Tip: shorter English sentences often read clearer.' },
|
||||
{ native: 'No olvides los artículos “the” y “a”.', en: "Don't forget articles like “the” and “a”." },
|
||||
{ native: 'Para el pasado, usa el pretérito: go → went.', en: 'For the past, use past tense: go → went.' },
|
||||
{ native: 'Leer en voz alta ayuda a notar lo que suena raro.', en: 'Reading aloud helps you catch awkward spots.' },
|
||||
{ native: 'Una idea por párrafo y todo queda clarito.', en: 'One idea per paragraph keeps it tidy.' },
|
||||
{ native: '¿Tienes una duda? Pregúntame ✨', en: 'Not sure about something? Just ask me. ✨' },
|
||||
{ native: 'El plural lleva “s”: two apples 🍎', en: 'Plurals take an “s”: two apples 🍎' },
|
||||
// Two tips the zh pack has no use for. Spanish and English share so much
|
||||
// Latin vocabulary that the false friends are a daily hazard, and the
|
||||
// subject pronoun is the habit Spanish speakers drop most often.
|
||||
{ native: 'Cuidado con los falsos amigos: “actually” no significa *actualmente*.', en: 'Careful with false friends — “actually” means *in fact*.' },
|
||||
{ native: 'En inglés el sujeto casi nunca se omite: “it is raining”, no “is raining”.', en: 'English almost always needs a subject: “it is raining”, not “is raining”.' },
|
||||
],
|
||||
|
||||
breaks: [
|
||||
{ native: 'Llevas rato escribiendo — estírate y descansa la vista 🍵', en: "You've been writing a while — stretch and rest your eyes. 🍵" },
|
||||
{ native: '¿Un vaso de agua y cinco minutos de pausa?', en: 'Sip some water and take five?' },
|
||||
{ native: 'Mira a lo lejos un momento, la vista te lo agradece 🌿', 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 Spanish line leads gently into it, exactly as
|
||||
// the Mandarin, Portuguese and French ones do.
|
||||
bedtime: [
|
||||
{ native: 'Tu cama ha de estar preguntándose dónde andas 🛏️', en: 'I bet your bed is missing you right now.' },
|
||||
{ native: 'Cansada, escribes mal — ve a descansar 🌙', en: 'A tired writer is a bad writer — get some rest.' },
|
||||
{ native: 'Mejor consúltalo con la almohada ✨', en: 'Sleep is a wondrous enabler.' },
|
||||
{ native: '¿Oyes? No… porque todos están dormidos, y tú deberías estarlo también 😴', en: "Hear that? No… you don't, because everyone is sleeping and you should be too." },
|
||||
// Spanish sayings about sleep and haste, in place of the French and
|
||||
// Portuguese ones — a pack is not a translation of another pack.
|
||||
{ native: 'Dormir es el mejor remedio.', en: 'Sleep is the best medicine.' },
|
||||
{ native: 'A quien madruga, Dios lo ayuda.', en: 'The early riser gets a hand from above.' },
|
||||
{ native: 'No por mucho madrugar amanece más temprano.', en: 'Rising earlier will not make the sun come up sooner.' },
|
||||
],
|
||||
|
||||
greeting: { native: '¡Hola! Aquí te hago compañía 🐱', en: "Hi! I'm right here keeping you company. 🐱" },
|
||||
welcomeBack: { native: '¡Volviste! ✨ Sigamos', en: 'Welcome back ✨ let’s keep going!' },
|
||||
|
||||
errors: [
|
||||
{ native: 'Uy — un tropiezo chiquito, pero tus palabras están a salvo.', en: 'Oops — a little hiccup, but your words are safe.' },
|
||||
{ native: 'Ay, me enredé un segundo — ya vuelvo.', en: 'Haiya, I got stuck for a sec — back in a moment.' },
|
||||
{ native: 'No te preocupes, lo intentamos de nuevo en un ratito 🍵', en: "Don't worry — let's try again in a bit. 🍵" },
|
||||
],
|
||||
|
||||
milestone: (words: number) => ({
|
||||
native: `¡Guau! Ya llevas ${words} palabras 🎉`,
|
||||
en: `Wow — ${words} words already! Amazing. 🎉`,
|
||||
}),
|
||||
|
||||
// Algo pequeño que escribir, ofrecido una vez al día a una página en blanco.
|
||||
// Recuerdos y opiniones, nunca ejercicios: aquí no hay nada que se pueda
|
||||
// reprobar, y esa es justamente la intención.
|
||||
invitations: [
|
||||
{ native: 'Escribe 50 palabras: algo pequeño que te hizo sonreír hoy 🌸', en: 'Write 50 words: one small thing that made you smile today.' },
|
||||
{ native: 'Escribe 50 palabras: lo más rico que comiste hoy', en: 'Write 50 words: the best thing you ate today.' },
|
||||
{ native: 'Escribe 50 palabras: lo que ves por tu ventana en este momento', en: 'Write 50 words: what you can see out of your window right now.' },
|
||||
{ native: 'Escribe 50 palabras: un lugar al que volverías con gusto', en: 'Write 50 words: somewhere you would happily go back to.' },
|
||||
{ native: 'Escribe 50 palabras: algo que aprendiste esta semana', en: 'Write 50 words: one thing you learned this week.' },
|
||||
{ native: 'Escribe 50 palabras: un mensaje para ti misma dentro de un año', en: 'Write 50 words: something to tell yourself a year from now.' },
|
||||
{ native: 'Escribe 50 palabras: una canción que no has parado de escuchar estos días', en: 'Write 50 words: a song you have had on lately.' },
|
||||
{ native: 'Escribe 50 palabras: alguien a quien te gustaría agradecerle hoy', en: 'Write 50 words: someone you would like to thank today.' },
|
||||
],
|
||||
inviteAccept: 'Vamos · Let’s write',
|
||||
inviteDecline: 'Hoy no · Not today',
|
||||
declined: { native: 'Está bien, me regreso a dormir 😴', en: 'Fair enough — back to my nap. 😴' },
|
||||
|
||||
names: {
|
||||
cat: 'Gato dormilón',
|
||||
dog: 'Perro alegre',
|
||||
'wiggle-dog': 'Perro meneacola',
|
||||
butterfly: 'Mariposa',
|
||||
parrot: 'Loro',
|
||||
},
|
||||
},
|
||||
|
||||
prose: {
|
||||
longSentence: 'Esta oración quedó un poco larga — partirla en dos o tres la hace más clara 🌸',
|
||||
commaSplice: 'Aquí hay dos oraciones unidas solo por una coma. Pon un punto, o únelas con “and / but”.',
|
||||
vagueThis: (word) => `No queda claro a qué se refiere “${word}” — precísalo (por ejemplo “${word} idea / change…”).`,
|
||||
oxfordComma: 'En una lista de tres o más elementos, una coma antes de “and / or” ayuda a leer (la coma de Oxford).',
|
||||
transitionComma: (word) => `Después de un conector al inicio de la oración va una coma: “${word}, …”.`,
|
||||
capitalizeSentence: 'Empieza cada oración con mayúscula.',
|
||||
repeatedWord: (word) => `Parece que “${word}” quedó escrito dos veces — échale un ojo.`,
|
||||
capitalizeI: 'En inglés, “I” (yo) siempre va con mayúscula.',
|
||||
spaceBeforePunct: 'En inglés no se deja espacio antes de la puntuación: la coma y el punto van pegados a la palabra, igual que en español.',
|
||||
spaceAfterPunct: 'Después de una coma o un punto, deja un espacio antes de la siguiente palabra.',
|
||||
articleAn: (word) => `Antes de un sonido de vocal se usa “an”: “an ${word}”.`,
|
||||
articleA: (word) => `Antes de un sonido de consonante se usa “a”: “a ${word}”.`,
|
||||
uncountable: (word, singular) => `“${word}” es incontable en inglés — no lleva s, basta con “${singular}”.`,
|
||||
capitalizeProper: (fixed) => `En inglés, los idiomas, las nacionalidades, los días y los meses van con mayúscula: “${fixed}”.`,
|
||||
thirdPersonS: (subject, verb) => `Con he/she/it, el verbo lleva -s: “${subject} ${verb}”.`,
|
||||
pluralAfter: (determiner, noun) => `Después de “${determiner}”, el sustantivo va en plural: “${determiner} ${noun}s”.`,
|
||||
doubleDeterminer: (first, second) => `“${first} ${second}” lleva dos determinantes — deja solo uno (quita “${first}”, por ejemplo).`,
|
||||
thereArePlural: (noun) => `En plural se dice “there are”: “there are ${noun}…”.`,
|
||||
itsOwn: '“it’s” = “it is”. Para decir “su”, es “its” — o sea “its own”.',
|
||||
itsIs: (rest) => `Aquí va “it’s ${rest}” (it is); “its” es el posesivo.`,
|
||||
thanNotThen: (word) => `En una comparación se escribe “than”, no “then”: “${word} than”.`,
|
||||
preposition: (wrong, right) => `En inglés se dice “${right}”, no “${wrong}” — esa preposición es fija.`,
|
||||
collocation: (wrong, right) => `En inglés estas palabras van juntas así: “${right}”, y no “${wrong}”.`,
|
||||
doubleComparative: (lead, word) => `“${word}” ya es el comparativo — no necesita “${lead}”: con “${word}” basta.`,
|
||||
peopleArePlural: (verb) => `“People” es plural en inglés: “people ${verb}”.`,
|
||||
// Interferencia del español. Las tres primeras son las que de verdad se ven
|
||||
// todos los días; el resto las tiene el pack aunque este par no las corra.
|
||||
ageIsNotHave: (years) => `En inglés la edad se dice con *to be*, no con *tener*: “I am ${years} years old”.`,
|
||||
agreeIsAVerb: '“Agree” ya es el verbo — no lleva *to be* delante: se dice “I agree”, no “I am agree”.',
|
||||
forNotSince: (duration) => `Para una duración se usa “for”: “for ${duration}”. “Since” marca el punto de partida (since 2020).`,
|
||||
veryBeforeVerb: (verb) => `“Very” solo acompaña adjetivos, no verbos: “really ${verb}”, o “${verb}… very much”.`,
|
||||
turnOnNotOpen: (thing, on) => `En inglés los aparatos no se abren, se encienden: “turn ${on ? 'on' : 'off'} the ${thing}”.`,
|
||||
althoughOrBut: (word) => `En inglés se pone “${word}” o “but”, nunca los dos en la misma oración.`,
|
||||
},
|
||||
|
||||
// Los falsos amigos entre el español y el inglés — la trampa que hace sentir
|
||||
// ridícula en vez de simplemente corregida. Por eso son solo un aviso: Petal
|
||||
// nunca cambia la palabra, porque “actually” bien pudo ser la que quería.
|
||||
//
|
||||
// El español comparte tanto latín con el inglés que esta lista es la más larga
|
||||
// de los cuatro packs, y *embarrassed* es la razón por la que existe la función.
|
||||
falseFriends: {
|
||||
embarrassed: {
|
||||
native: '“Embarrassed” significa *apenada, avergonzada*. *Embarazada* se dice “pregnant”.',
|
||||
en: '“Embarrassed” means ashamed; the Spanish *embarazada* is “pregnant”.',
|
||||
},
|
||||
actually: {
|
||||
native: '“Actually” significa *en realidad*, no *actualmente*. Para *actualmente* se dice “currently” o “nowadays”.',
|
||||
en: '“Actually” means *in fact*. For the Spanish *actualmente*, English uses “currently”.',
|
||||
},
|
||||
eventually: {
|
||||
native: '“Eventually” significa *al final, tarde o temprano* — no *eventualmente*. Para eso: “possibly” o “if necessary”.',
|
||||
en: '“Eventually” means *in the end*, not *possibly*.',
|
||||
},
|
||||
realize: {
|
||||
native: '“Realize” significa *darse cuenta*. Para *realizar* (llevar a cabo) se dice “carry out” o “do”.',
|
||||
en: '“Realize” means to become aware; *realizar* is “to carry out”.',
|
||||
},
|
||||
assist: {
|
||||
native: '“Assist” significa *ayudar*. Para *asistir* (ir a algo) se dice “attend”.',
|
||||
en: '“Assist” means to help; *asistir a* is “to attend”.',
|
||||
},
|
||||
attend: {
|
||||
native: '“Attend” significa *asistir a*. Para *atender* (a alguien) se dice “serve” o “take care of”.',
|
||||
en: '“Attend” means to go to something; *atender* is “to serve”.',
|
||||
},
|
||||
support: {
|
||||
native: '“Support” significa *apoyar*. Para *soportar* (aguantar algo molesto) se dice “put up with” o “bear”.',
|
||||
en: '“Support” means to back someone up; *soportar* is “to put up with”.',
|
||||
},
|
||||
sensible: {
|
||||
native: '“Sensible” significa *sensato*. Para *sensible* se dice “sensitive”.',
|
||||
en: '“Sensible” means level-headed; the Spanish *sensible* is “sensitive”.',
|
||||
},
|
||||
sympathetic: {
|
||||
native: '“Sympathetic” significa *comprensivo, solidario*. Para *simpático* se dice “nice” o “friendly”.',
|
||||
en: '“Sympathetic” means understanding; *simpático* is “nice”.',
|
||||
},
|
||||
library: {
|
||||
native: '“Library” es la *biblioteca*. La *librería* se dice “bookshop” o “bookstore”.',
|
||||
en: '“Library” is where books are lent; a shop that sells them is a “bookstore”.',
|
||||
},
|
||||
exit: {
|
||||
native: '“Exit” es la *salida*. El *éxito* se dice “success”.',
|
||||
en: '“Exit” is the way out; *éxito* is “success”.',
|
||||
},
|
||||
success: {
|
||||
native: '“Success” es el *éxito*. Un *suceso* se dice “event”.',
|
||||
en: '“Success” is achievement; a Spanish *suceso* is an “event”.',
|
||||
},
|
||||
carpet: {
|
||||
native: '“Carpet” es la *alfombra*. Una *carpeta* se dice “folder”.',
|
||||
en: '“Carpet” covers a floor; a *carpeta* is a “folder”.',
|
||||
},
|
||||
discussion: {
|
||||
native: '“Discussion” es una *conversación*, sin pelea. Una *discusión* (riña) se dice “argument”.',
|
||||
en: '“Discussion” is calm; a Spanish *discusión* is an “argument”.',
|
||||
},
|
||||
argument: {
|
||||
native: '“Argument” es una *discusión* o *pelea*. El *argumento* de una historia se dice “plot”.',
|
||||
en: '“Argument” is a quarrel; the *argumento* of a story is its “plot”.',
|
||||
},
|
||||
introduce: {
|
||||
native: '“Introduce” es *presentar* a alguien. Para *introducir* (meter) se dice “insert” o “put in”.',
|
||||
en: '“Introduce” is to present someone; *introducir* is “to insert”.',
|
||||
},
|
||||
molest: {
|
||||
native: '“Molest” significa *abusar sexualmente* — nunca se usa por *molestar*. Para eso: “bother” o “annoy”.',
|
||||
en: '“Molest” means to abuse; the everyday *molestar* is “to bother”.',
|
||||
},
|
||||
constipated: {
|
||||
native: '“Constipated” significa *estreñida*. Para *constipada* (resfriada) se dice “to have a cold”.',
|
||||
en: '“Constipated” is a bowel problem; *constipado* is “a cold”.',
|
||||
},
|
||||
large: {
|
||||
native: '“Large” significa *grande*. Para *largo* se dice “long”.',
|
||||
en: '“Large” means big; *largo* is “long”.',
|
||||
},
|
||||
lecture: {
|
||||
native: '“Lecture” es una *conferencia* o *clase*. La *lectura* se dice “reading”.',
|
||||
en: '“Lecture” is a talk; *lectura* is “reading”.',
|
||||
},
|
||||
parents: {
|
||||
native: '“Parents” son los *padres*. Los *parientes* se dicen “relatives”.',
|
||||
en: '“Parents” are your mother and father; *parientes* are “relatives”.',
|
||||
},
|
||||
record: {
|
||||
native: '“Record” significa *grabar* o *registrar*. Para *recordar* se dice “remember”.',
|
||||
en: '“Record” means to register; *recordar* is “to remember”.',
|
||||
},
|
||||
remove: {
|
||||
native: '“Remove” significa *quitar*. Para *remover* (revolver) se dice “stir”.',
|
||||
en: '“Remove” means to take away; *remover* is “to stir”.',
|
||||
},
|
||||
rope: {
|
||||
native: '“Rope” es la *cuerda*. La *ropa* se dice “clothes”.',
|
||||
en: '“Rope” is cord; *ropa* is “clothes”.',
|
||||
},
|
||||
once: {
|
||||
native: '“Once” significa *una vez*. El número *once* se dice “eleven”.',
|
||||
en: '“Once” means one time; the Spanish *once* is “eleven”.',
|
||||
},
|
||||
question: {
|
||||
native: '“Question” es una *pregunta*. Una *cuestión* (asunto) se dice “matter” o “issue”.',
|
||||
en: '“Question” is something you ask; a *cuestión* is a “matter”.',
|
||||
},
|
||||
compromise: {
|
||||
native: '“Compromise” es un *acuerdo con concesiones*. Un *compromiso* (obligación) se dice “commitment”.',
|
||||
en: '“Compromise” is meeting halfway; a *compromiso* is a “commitment”.',
|
||||
},
|
||||
career: {
|
||||
native: '“Career” es la *trayectoria profesional*. La *carrera* que se estudia se dice “degree” o “major”.',
|
||||
en: '“Career” is your working life; a university *carrera* is a “degree”.',
|
||||
},
|
||||
ultimately: {
|
||||
native: '“Ultimately” significa *a fin de cuentas*. Para *últimamente* se dice “lately”.',
|
||||
en: '“Ultimately” means in the end; *últimamente* is “lately”.',
|
||||
},
|
||||
idiom: {
|
||||
native: '“Idiom” es una *expresión hecha*. El *idioma* se dice “language”.',
|
||||
en: '“Idiom” is a set phrase; *idioma* is “language”.',
|
||||
},
|
||||
deception: {
|
||||
native: '“Deception” significa *engaño*. La *decepción* se dice “disappointment”.',
|
||||
en: '“Deception” means being misled; *decepción* is “disappointment”.',
|
||||
},
|
||||
pretend: {
|
||||
native: '“Pretend” significa *fingir*. Para *pretender* (aspirar a) se dice “intend” o “claim”.',
|
||||
en: '“Pretend” means to fake; *pretender* is “to intend”.',
|
||||
},
|
||||
},
|
||||
|
||||
docs: {
|
||||
sortRecent: 'Recientes · Recent',
|
||||
sortTitle: 'Título · Title',
|
||||
sortLongest: 'Los más largos · Longest',
|
||||
backUpAll: 'Respaldar todo · Back up all:',
|
||||
signOut: 'Cerrar sesión · Sign out',
|
||||
duplicate: 'Duplicar · Duplicate',
|
||||
searchPlaceholder: 'Buscar · Search',
|
||||
searching: 'Buscando… · Searching…',
|
||||
noMatches: 'Sin resultados · No matches',
|
||||
tags: 'Etiquetas · Tags',
|
||||
newTagPlaceholder: 'Nueva etiqueta · New tag',
|
||||
language: 'Idioma · Language',
|
||||
languageFailed: 'No se pudo cambiar el idioma — sigue igual · Couldn’t switch',
|
||||
},
|
||||
|
||||
editor: {
|
||||
askPlaceholder: 'Ask why… / Pregunta por qué…',
|
||||
chatFailed: 'No logré responder — vuelve a preguntarme, por favor. 🌸\n\nI had trouble answering just now — please ask me again. 🌸',
|
||||
findPlaceholder: 'Buscar · Find',
|
||||
findNone: 'Nada · 0',
|
||||
matchCase: 'Match case · Distinguir mayúsculas',
|
||||
close: 'Close · Cerrar',
|
||||
replacePlaceholder: 'Reemplazar por · Replace',
|
||||
replace: 'Reemplazar',
|
||||
replaceAll: 'Todo',
|
||||
translateLabel: 'Traducción · Translate',
|
||||
spelling: 'Ortografía · Spelling',
|
||||
noSuggestions: 'Sin sugerencias · No suggestions',
|
||||
addToDictionary: 'Agregar al diccionario · Add to dictionary',
|
||||
readSelection: 'Leer la selección en voz alta · Read selection aloud',
|
||||
rewrite: 'Reescribir · Rewrite',
|
||||
rewriting: 'Reescribiendo… · Rewriting…',
|
||||
rewriteFailed: 'No se pudo reescribir — inténtalo otra vez · Couldn’t rewrite',
|
||||
cancel: 'Cancelar · Cancel',
|
||||
retry: 'Reintentar · Retry',
|
||||
useThis: 'Usar esta · Use this',
|
||||
word: 'Palabra · Word',
|
||||
inGarden: 'Ya está en el jardín · In your garden (tap to remove)',
|
||||
saveToGarden: 'Guardar en el jardín · Save to garden',
|
||||
readAloud: 'Leer en voz alta · Read aloud',
|
||||
readSlowly: 'Leer despacio · Read slowly',
|
||||
readAloudNative: 'Leer en español · Read in Spanish',
|
||||
lookingUp: 'Buscando… · Looking up…',
|
||||
definition: 'Definición · Definition',
|
||||
synonyms: 'Sinónimos · Synonyms',
|
||||
tapToSwap: 'toca para cambiar · tap to swap',
|
||||
nothingFound: 'No encontré esta palabra · Nothing found for this word',
|
||||
origin: 'Origen · Origin',
|
||||
// El par español ve esto seguido: inglés y español comparten tanto latín que
|
||||
// los choques son la regla y no la excepción — real, red, once, pie, sin,
|
||||
// pan, mayor, sale, ropa.
|
||||
alsoIn: 'También es una palabra en español · Also a word in Spanish',
|
||||
wordBands: {
|
||||
simple: { native: 'De todos los días', en: 'Everyday word' },
|
||||
standard: { native: 'Común', en: 'Standard' },
|
||||
advanced: { native: 'Avanzada', en: 'Advanced' },
|
||||
},
|
||||
},
|
||||
|
||||
styles: {
|
||||
natural: { native: 'Más natural', en: 'Natural' },
|
||||
academic: { native: 'Académico', en: 'Academic' },
|
||||
professional: { native: 'Profesional', en: 'Professional' },
|
||||
casual: { native: 'Informal', en: 'Casual' },
|
||||
humorous: { native: 'Divertido', en: 'Humorous' },
|
||||
creative: { native: 'Creativo', en: 'Creative' },
|
||||
persuasive: { native: 'Persuasivo', en: 'Persuasive' },
|
||||
},
|
||||
|
||||
tones: {
|
||||
general: { native: 'General', en: 'General' },
|
||||
academic: { native: 'Académico', en: 'Academic' },
|
||||
professional: { native: 'Profesional', en: 'Professional' },
|
||||
casual: { native: 'Informal', en: 'Casual' },
|
||||
humorous: { native: 'Divertido', en: 'Humorous' },
|
||||
creative: { native: 'Creativo', en: 'Creative' },
|
||||
persuasive: { native: 'Persuasivo', en: 'Persuasive' },
|
||||
},
|
||||
|
||||
exports: {
|
||||
label: 'Exportar',
|
||||
print: 'Imprimir / PDF',
|
||||
formats: {
|
||||
md: { native: 'Markdown', en: 'Markdown (.md)' },
|
||||
docx: { native: 'Documento de Word', en: 'Word (.docx)' },
|
||||
html: { native: 'Página web', en: 'Web page (.html)' },
|
||||
txt: { native: 'Texto sin formato', en: 'Plain text (.txt)' },
|
||||
},
|
||||
},
|
||||
|
||||
garden: {
|
||||
title: 'Jardín de palabras · Vocabulary Garden',
|
||||
titleWithFlower: '🌷 Jardín de palabras · Vocabulary Garden',
|
||||
reviewing: 'Repaso · Reviewing — recall, then grade yourself',
|
||||
subtitle: 'Words you looked up, blooming as you learn them',
|
||||
reviewDue: (n) => `Repasar ${n} palabra${n === 1 ? '' : 's'} · Review ${n} due 🌸`,
|
||||
emptyLead: 'Tu jardín todavía está vacío.',
|
||||
emptyHint: 'Haz clic derecho en una palabra en inglés para buscarla — y aquí brotará.',
|
||||
due: 'por repasar · due',
|
||||
seen: (reps, intervalDays) => `repasada ${reps}× · seen ${reps}× · intervalo ${intervalDays} d`,
|
||||
readAloud: '🔊 Leer',
|
||||
readSlowly: '🐢 Despacio',
|
||||
source: '📄 Fuente',
|
||||
remove: '🗑 Quitar',
|
||||
growing: (n) => `🐱💤 ${n} flor${n === 1 ? '' : 'es'} en el jardín · ${n} blossom${n > 1 ? 's' : ''} growing`,
|
||||
end: 'Terminar · End',
|
||||
promptProduction: '¿Cuál es la palabra en inglés? · Which English word?',
|
||||
promptRecognition: '¿Qué significa? · What does this mean?',
|
||||
showAnswer: 'Ver la respuesta · Show answer',
|
||||
gradeAgain: { native: 'Repetir', en: 'Again' },
|
||||
gradeGood: { native: 'La recuerdo', en: 'Good' },
|
||||
gradeEasy: { native: 'Fácil', en: 'Easy' },
|
||||
},
|
||||
|
||||
journal: {
|
||||
tabGarden: '🌷 Jardín · Garden',
|
||||
tabJournal: '🌱 Avances · Growth',
|
||||
subtitle: 'Your own writing, month by month — only ever you and your past self',
|
||||
empty: 'Sigue escribiendo un poco más — esta página crece a partir de tu propio trabajo. · Keep writing; this page grows out of your own work.',
|
||||
keptHead: 'Este mes · This month',
|
||||
kept: (n) => `${n} cosa${n === 1 ? '' : 's'} que te llevaste · ${n} thing${n === 1 ? '' : 's'} you took on board`,
|
||||
keptBefore: (n) => `${n} el mes pasado · ${n} the month before`,
|
||||
stuckHead: 'Se te quedó · Stayed with you',
|
||||
stuck: (phrase, docs) =>
|
||||
`“${phrase}” — ya la escribes sola, en ${docs} de tus textos · now in ${docs} of your pieces`,
|
||||
fadedHead: 'Ya no necesitas corregir esto · You stopped needing this',
|
||||
faded: (pattern, times) =>
|
||||
`“${pattern}” — ${times}× antes, ninguna este mes · ${times}× back then, none this month`,
|
||||
cheerStuck: (phrase) => ({
|
||||
native: `¡Ya usas “${phrase}” tú solita! 🌱`,
|
||||
en: `You’re using “${phrase}” on your own now! 🌱`,
|
||||
}),
|
||||
cheerFaded: (pattern) => ({
|
||||
native: `Hace rato que “${pattern}” no necesita corrección 😌`,
|
||||
en: `“${pattern}” hasn’t needed fixing in a while 😌`,
|
||||
}),
|
||||
},
|
||||
|
||||
history: {
|
||||
title: 'Historial · History',
|
||||
kinds: {
|
||||
manual: { native: 'Punto guardado', en: 'Saved point' },
|
||||
auto: { native: 'Automático', en: 'Auto' },
|
||||
pre_restore: { native: 'Antes de restaurar', en: 'Before restore' },
|
||||
},
|
||||
justNow: 'ahora mismo · just now',
|
||||
minutesAgo: (n) => `hace ${n} min · ${n} min ago`,
|
||||
hoursAgo: (n) => `hace ${n} h · ${n} hr ago`,
|
||||
daysAgo: (n) => `hace ${n} día${n > 1 ? 's' : ''} · ${n} day${n > 1 ? 's' : ''} ago`,
|
||||
preview: 'Vista previa · Preview',
|
||||
restoring: 'Restaurando… · Restoring…',
|
||||
restoreThis: 'Restaurar esta versión · Restore this version',
|
||||
passport: '📜 Pasaporte de escritura · Writing passport',
|
||||
keepFullHistory: 'Guardar todo el historial · Keep full history',
|
||||
},
|
||||
|
||||
status: {
|
||||
savedLocally: 'Guardado en este dispositivo · Kept on this device',
|
||||
helperRestingNative: 'El ayudante está descansando',
|
||||
helperRestingEn: "· Petal's helper is resting · tu texto está guardado",
|
||||
petalsToPolish: (n) => ({
|
||||
native: `${n} ${n === 1 ? 'pétalo' : 'pétalos'} por pulir`,
|
||||
en: `${n} ${n === 1 ? 'petal' : 'petals'} to polish`,
|
||||
}),
|
||||
soundsOn: 'Sonidos activados · Sounds on',
|
||||
soundsOff: 'Sonidos desactivados · Sounds off',
|
||||
petalsOn: 'Pétalos activados · Petals on',
|
||||
petalsOff: 'Pétalos desactivados · Petals off',
|
||||
statsTitle: 'Estadísticas · Writing stats',
|
||||
stats: {
|
||||
words: { native: 'Palabras', en: 'Words' },
|
||||
characters: { native: 'Caracteres', en: 'Characters' },
|
||||
sentences: { native: 'Oraciones', en: 'Sentences' },
|
||||
paragraphs: { native: 'Párrafos', en: 'Paragraphs' },
|
||||
pages: { native: 'Páginas', en: 'Pages' },
|
||||
readingTime: { native: 'Tiempo de lectura', en: 'Reading time' },
|
||||
avgWordLength: { native: 'Longitud promedio', en: 'Avg word length' },
|
||||
variety: { native: 'Variedad de vocabulario', en: 'Word variety' },
|
||||
readability: { native: 'Nivel de lectura', en: 'Reading level' },
|
||||
},
|
||||
readability: {
|
||||
easy: { native: 'Fácil', en: 'Easy' },
|
||||
standard: { native: 'Común', en: 'Standard' },
|
||||
fairlyHard: { native: 'Algo difícil', en: 'Fairly hard' },
|
||||
advanced: { native: 'Avanzado', en: 'Advanced' },
|
||||
},
|
||||
},
|
||||
|
||||
toolbar: {
|
||||
untitledHeading: '(sin título)',
|
||||
outline: 'Esquema · Outline',
|
||||
outlineHint: 'Usa H1/H2/H3 para crear títulos, y el esquema aparecerá aquí.',
|
||||
},
|
||||
|
||||
update: {
|
||||
available: 'Hay una versión nueva disponible',
|
||||
refresh: 'Actualizar · Refresh',
|
||||
dismiss: 'Más tarde · Dismiss',
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user