Site en anglais : accueil, aide, vie privée, guides et modèles sous /en/

Accueil prérendu en deux langues, huit pages statiques traduites avec hreflang
des deux côtés, captures de l'aide refaites dans l'app anglaise, modèles PDF
générés en français et en anglais, sitemap. Test des liens internes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
IliesAllaliandClaude Opus 5.5 committed 2026-09-29 16:01:16 +02:00
1 parent 6f28918dde
commit 2d8ac66372
47 files changed
+1996 -186

No files matched your search

+3
View File
@@ -10,6 +10,9 @@
<title>Parenthèse : l'arbre généalogique vivant de votre famille</title>
<meta name="description" content="Créez l'arbre généalogique de votre famille en ligne, avec photos, vidéos et voix. Partagez-le en un lien : la famille consulte sans compte et contribue avec un mot de passe." />
<link rel="canonical" href="https://parenthese.io/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/" />
<!-- Open Graph -->
<meta property="og:type" content="website" />
+94 -44
View File
@@ -22,6 +22,55 @@ const LOGO_RATIO = 7.541
const esc = (s) => String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;')
const n = (v) => Math.round(v * 100) / 100
// Libellés imprimés sur les modèles, par langue (fr = page /arbre-genealogique-a-remplir/,
// en = page /en/printable-family-tree/)
export const TEXTES = {
fr: {
titre: ['Arbre ', 'généalogique'],
famille: 'de la famille',
pied: 'Modèle gratuit à imprimer et à remplir',
photo: 'Photo',
roles: [
['Moi'],
['Père', 'Mère'],
['Grand-père paternel', 'Grand-mère paternelle', 'Grand-père maternel', 'Grand-mère maternelle'],
['Arrière-grand-père', 'Arrière-grand-mère'],
],
champs: ['Prénom', 'Nom', 'Né(e) le', 'à', 'Décès'],
legendes: [['Moi'], ['Parents'], ['Grands-', 'parents'], ['Arrière-grands-', 'parents'], ['Trisaïeuls']],
sosa: "Numérotation Sosa. Le père d'une personne porte le double de son numéro, la mère le double plus un.",
tags: {
g3: '3 générations',
g4: '4 générations',
photos: '3 générations avec photos',
eventail: '5 générations en éventail',
dessine: '3 générations, arbre dessiné',
},
},
en: {
titre: ['Family ', 'tree'],
famille: 'of the family',
pied: 'Free template to print and fill in',
photo: 'Photo',
roles: [
['Me'],
['Father', 'Mother'],
['Paternal grandfather', 'Paternal grandmother', 'Maternal grandfather', 'Maternal grandmother'],
['Great-grandfather', 'Great-grandmother'],
],
champs: ['First name', 'Last name', 'Born on', 'in', 'Died'],
legendes: [['Me'], ['Parents'], ['Grand-', 'parents'], ['Great-', 'grandparents'], ['Great-great-', 'grandparents']],
sosa: "Ahnentafel (Sosa) numbering. A person's father has double their number, their mother double plus one.",
tags: {
g3: '3 generations',
g4: '4 generations',
photos: '3 generations with photos',
eventail: '5-generation fan chart',
dessine: '3 generations, drawn tree',
},
},
}
const STYLE = `
.titre { font-family: 'Newsreader', serif; font-size: 9px; fill: ${C.encre}; }
.titre-i { font-family: 'Newsreader', serif; font-style: italic; font-size: 9px; fill: ${C.a700}; }
@@ -40,10 +89,10 @@ const STYLE = `
.photo { fill: #fff; stroke: ${C.encre}; stroke-opacity: .28; stroke-width: .2; stroke-dasharray: .8 .8; }
`
function page({ W, H, body, titre = 'modèle' }) {
function page({ W, H, body, titre = 'modèle', lang = 'fr' }) {
const orient = W > H ? 'landscape' : 'portrait'
return `<!doctype html>
<html lang="fr"><head><meta charset="utf-8"><title>${esc(titre)}</title>
<html lang="${lang}"><head><meta charset="utf-8"><title>${esc(titre)}</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,500&family=Newsreader:ital,opsz,wght@0,6..72,400;1,6..72,400&display=block" rel="stylesheet">
@@ -65,35 +114,31 @@ function champ(x, xEnd, y, label) {
return `<g class="f"><text class="lab" x="${n(x)}" y="${n(y)}">${esc(label)}</text><line class="wl" x1="${n(x + 8)}" y1="${n(y + 0.45)}" x2="${n(xEnd)}" y2="${n(y + 0.45)}"/></g>`
}
function entete({ W, margin, tag, top = 14 }) {
function entete({ W, margin, tag, t, top = 14 }) {
const y = top + 9
return `
<text class="titre" x="${margin}" y="${y}">Arbre <tspan class="titre-i">généalogique</tspan></text>
<g class="f"><text class="sous" x="${margin}" y="${y + 8}">de la famille</text><line class="wl" x1="${margin + 20}" y1="${y + 8.5}" x2="${margin + 100}" y2="${y + 8.5}"/></g>
<text class="titre" x="${margin}" y="${y}">${esc(t.titre[0])}<tspan class="titre-i">${esc(t.titre[1])}</tspan></text>
<g class="f"><text class="sous" x="${margin}" y="${y + 8}">${esc(t.famille)}</text><line class="wl" x1="${margin + 20}" y1="${y + 8.5}" x2="${margin + 100}" y2="${y + 8.5}"/></g>
<text class="tag" x="${W - margin}" y="${y}" text-anchor="end">${esc(tag)}</text>
<line class="regle" x1="${margin}" y1="${y + 13}" x2="${W - margin}" y2="${y + 13}"/>`
}
function pied({ W, H, margin, texte = 'Modèle gratuit à imprimer et à remplir' }) {
function pied({ W, H, margin, t }) {
const h = 3.4
const w = h * LOGO_RATIO
const y = H - 8
return `
<svg x="${margin}" y="${n(y - h + 0.5)}" width="${n(w)}" height="${h}" viewBox="${LOGO_VIEWBOX}">${LOGO_INNER}</svg>
<text class="pied" x="${W - margin}" y="${y}" text-anchor="end">${esc(texte)}, parenthese.io</text>`
<text class="pied" x="${W - margin}" y="${y}" text-anchor="end">${esc(t.pied)}, parenthese.io</text>`
}
const ROLES = [
['Moi'],
['Père', 'Mère'],
['Grand-père paternel', 'Grand-mère paternelle', 'Grand-père maternel', 'Grand-mère maternelle'],
Array.from({ length: 8 }, (_, i) => (i % 2 ? 'Arrière-grand-mère' : 'Arrière-grand-père')),
]
// Rôle de chaque case, génération par génération (les arrière-grands-parents alternent père, mère)
const rolesDe = (t) => [t.roles[0], t.roles[1], t.roles[2], Array.from({ length: 8 }, (_, i) => t.roles[3][i % 2])]
const CHAMPS = ['Prénom', 'Nom', 'Né(e) le', 'à', 'Décès']
const NB_CHAMPS = 5
// Boîte de personne : rôle + numéro Sosa en tête, photo optionnelle, puis les champs
function boite({ x, y, w, h, role, sosa, ls, photo }) {
function boite({ x, y, w, h, role, sosa, ls, photo, t }) {
const pad = 2.4
let out = `<rect class="bx" x="${n(x)}" y="${n(y)}" width="${n(w)}" height="${n(h)}" rx="1.6"/>`
out += `<text class="role" x="${n(x + pad)}" y="${n(y + 4.3)}">${esc(role)}</text>`
@@ -104,21 +149,23 @@ function boite({ x, y, w, h, role, sosa, ls, photo }) {
const ph = photo.h
const px = x + (w - pw) / 2
out += `<rect class="photo" x="${n(px)}" y="${n(cy + 0.6)}" width="${pw}" height="${ph}" rx="1"/>`
out += `<text class="photo-lab" x="${n(x + w / 2)}" y="${n(cy + 0.6 + ph / 2 + 0.8)}" text-anchor="middle">Photo</text>`
out += `<text class="photo-lab" x="${n(x + w / 2)}" y="${n(cy + 0.6 + ph / 2 + 0.8)}" text-anchor="middle">${esc(t.photo)}</text>`
cy += ph + 1.6
}
CHAMPS.forEach((label, k) => {
t.champs.forEach((label, k) => {
out += champ(x + pad, x + w - pad, cy + (k + 1) * ls - 0.9, label)
})
return out
}
function hauteurBoite(ls, photo) {
return 6 + (photo ? photo.h + 1.6 : 0) + CHAMPS.length * ls + 1.4
return 6 + (photo ? photo.h + 1.6 : 0) + NB_CHAMPS * ls + 1.4
}
// Arbre ascendant vertical : « Moi » en bas, les ancêtres au-dessus, côté paternel à gauche
function arbre({ W, H, margin, top, bottom, gens, gap, maxW, ls, photo, tag, texte }) {
function arbre({ W, H, margin, top, bottom, gens, gap, maxW, ls, photo, tag, lang }) {
const t = TEXTES[lang]
const ROLES = rolesDe(t)
const boxH = hauteurBoite(ls, photo)
const vgap = (bottom - top - gens * boxH) / (gens - 1)
const rowY = (g) => bottom - boxH - g * (boxH + vgap)
@@ -131,7 +178,7 @@ function arbre({ W, H, margin, top, bottom, gens, gap, maxW, ls, photo, tag, tex
const slot = availW / count
const w = Math.min(slot - gap, maxW[g])
for (let i = 0; i < count; i++) {
boites += boite({ x: cx(g, i) - w / 2, y: rowY(g), w, h: boxH, role: ROLES[g][i], sosa: count + i, ls, photo })
boites += boite({ x: cx(g, i) - w / 2, y: rowY(g), w, h: boxH, role: ROLES[g][i], sosa: count + i, ls, photo, t })
if (g < gens - 1) {
const yb = rowY(g + 1) + boxH
const yt = rowY(g)
@@ -142,27 +189,27 @@ function arbre({ W, H, margin, top, bottom, gens, gap, maxW, ls, photo, tag, tex
}
}
}
return page({ W, H, body: entete({ W, margin, tag }) + traits + boites + pied({ W, H, margin, texte }) })
return page({ W, H, lang, body: entete({ W, margin, tag: t.tags[tag], t }) + traits + boites + pied({ W, H, margin, t }) })
}
export function troisGenerations() {
export function troisGenerations(lang = 'fr') {
return arbre({
W: 210, H: 297, margin: 14, top: 50, bottom: 276, gens: 3, gap: 4,
maxW: [84, 66, 42], ls: 8.2, tag: '3 générations',
maxW: [84, 66, 42], ls: 8.2, tag: 'g3', lang,
})
}
export function quatreGenerations() {
export function quatreGenerations(lang = 'fr') {
return arbre({
W: 297, H: 210, margin: 12, top: 47, bottom: 193, gens: 4, gap: 2.6,
maxW: [76, 64, 56, 32], ls: 5.3, tag: '4 générations',
maxW: [76, 64, 56, 32], ls: 5.3, tag: 'g4', lang,
})
}
export function troisGenerationsPhotos() {
export function troisGenerationsPhotos(lang = 'fr') {
return arbre({
W: 210, H: 297, margin: 14, top: 46, bottom: 280, gens: 3, gap: 4,
maxW: [84, 66, 42], ls: 6.2, photo: { w: 23, h: 28 }, tag: '3 générations avec photos',
maxW: [84, 66, 42], ls: 6.2, photo: { w: 23, h: 28 }, tag: 'photos', lang,
})
}
@@ -187,14 +234,15 @@ function arc(cx, cy, r, d0, d1) {
return `M${n(x0)} ${n(y0)} A${r} ${r} 0 0 1 ${n(x1)} ${n(y1)}`
}
export function cinqGenerationsEventail() {
export function cinqGenerationsEventail(lang = 'fr') {
const t = TEXTES[lang]
const W = 297
const H = 210
const margin = 12
const cx = W / 2
const cy = 188
const R = [0, 26, 55, 82, 108, 134]
const LEGENDES = [['Moi'], ['Parents'], ['Grands-', 'parents'], ['Arrière-grands-', 'parents'], ['Trisaïeuls']]
const LEGENDES = t.legendes
let body = ''
// anneaux de la génération 2 à 5 (Sosa 2 à 31), du père (gauche) à la mère (droite)
for (let g = 1; g <= 4; g++) {
@@ -240,13 +288,13 @@ export function cinqGenerationsEventail() {
const mid = g === 0 ? 0 : (R[g] + R[g + 1]) / 2
const xs = g === 0 ? [cx] : [cx - mid, cx + mid]
xs.forEach((x) => {
lines.forEach((t, k) => {
body += `<text class="role" x="${n(x)}" y="${n(cy + 4.4 + k * 2.7)}" text-anchor="middle">${esc(t)}</text>`
lines.forEach((ligne, k) => {
body += `<text class="role" x="${n(x)}" y="${n(cy + 4.4 + k * 2.7)}" text-anchor="middle">${esc(ligne)}</text>`
})
})
})
body += `<text class="lab" x="${W - margin}" y="${31}" text-anchor="end">Numérotation Sosa. Le père d'une personne porte le double de son numéro, la mère le double plus un.</text>`
return page({ W, H, body: entete({ W, margin, tag: '5 générations en éventail' }) + body + pied({ W, H, margin }) })
body += `<text class="lab" x="${W - margin}" y="${31}" text-anchor="end">${esc(t.sosa)}</text>`
return page({ W, H, lang, body: entete({ W, margin, tag: t.tags.eventail, t }) + body + pied({ W, H, margin, t }) })
}
// ─── Arbre dessiné, 3 générations ───────────────────────────────────────────
@@ -276,7 +324,8 @@ function feuille(x, y, angle, s) {
return `<path d="M0 0 C${n(s * 0.35)} ${n(-s * 0.32)} ${n(s * 0.75)} ${n(-s * 0.3)} ${s} 0 C${n(s * 0.75)} ${n(s * 0.3)} ${n(s * 0.35)} ${n(s * 0.32)} 0 0 Z" transform="translate(${n(x)} ${n(y)}) rotate(${n(angle)})"/>`
}
export function arbreDessine() {
export function arbreDessine(lang = 'fr') {
const t = TEXTES[lang]
const W = 210
const H = 297
const margin = 14
@@ -322,23 +371,24 @@ export function arbreDessine() {
// sol
dessin += `<path d="M62 283 C88 280 122 280 148 283" stroke="${C.a500}" stroke-width=".35" fill="none" stroke-linecap="round"/>`
let boites = ''
const roles = [ROLES[0], ROLES[1], ROLES[2]]
const roles = rolesDe(t)
;[[moi], parents, gps].forEach((row, g) => {
row.forEach((b, i) => {
boites += boite({ x: b.x - b.w / 2, y: b.y, w: b.w, h: bh, role: roles[g][i], sosa: 2 ** g + i, ls })
boites += boite({ x: b.x - b.w / 2, y: b.y, w: b.w, h: bh, role: roles[g][i], sosa: 2 ** g + i, ls, t })
})
})
// teintes opaques (a300 à 55 % et a500 à 50 % sur blanc) pour éviter les surimpressions aux jonctions
const body = entete({ W, margin, tag: '3 générations, arbre dessiné' })
const body = entete({ W, margin, tag: t.tags.dessine, t })
+ `<g fill="#f5d7cd">${dessin}</g><g fill="#e9b4a5">${feuillage}</g>`
+ boites + pied({ W, H, margin })
return page({ W, H, body })
+ boites + pied({ W, H, margin, t })
return page({ W, H, lang, body })
}
// slug = nom des fichiers français, en = nom des fichiers anglais
export const MODELES = [
{ slug: 'arbre-genealogique-3-generations', build: troisGenerations, portrait: true },
{ slug: 'arbre-genealogique-4-generations', build: quatreGenerations, portrait: false },
{ slug: 'arbre-genealogique-5-generations-eventail', build: cinqGenerationsEventail, portrait: false },
{ slug: 'arbre-genealogique-avec-photos', build: troisGenerationsPhotos, portrait: true },
{ slug: 'arbre-genealogique-dessine', build: arbreDessine, portrait: true },
{ slug: 'arbre-genealogique-3-generations', en: 'family-tree-3-generations', build: troisGenerations, portrait: true },
{ slug: 'arbre-genealogique-4-generations', en: 'family-tree-4-generations', build: quatreGenerations, portrait: false },
{ slug: 'arbre-genealogique-5-generations-eventail', en: 'family-tree-5-generation-fan-chart', build: cinqGenerationsEventail, portrait: false },
{ slug: 'arbre-genealogique-avec-photos', en: 'family-tree-with-photos', build: troisGenerationsPhotos, portrait: true },
{ slug: 'arbre-genealogique-dessine', en: 'family-tree-drawn', build: arbreDessine, portrait: true },
]
+18 -11
View File
@@ -1,6 +1,8 @@
// Génère les modèles PDF A4 et leurs aperçus WebP pour /arbre-genealogique-a-remplir/.
// Génère les modèles PDF A4 et leurs aperçus WebP pour /arbre-genealogique-a-remplir/ (français)
// et /en/printable-family-tree/ (anglais).
//
// node modeles/generer.mjs (depuis landing/)
// node modeles/generer.mjs (depuis landing/, les deux langues)
// node modeles/generer.mjs dessine (seulement les modèles dont le nom de fichier contient « dessine »)
//
// Playwright n'est pas une dépendance de la landing : le script le cherche dans node_modules,
// puis dans le dossier indiqué par PLAYWRIGHT_DIR (ex. D:/Commercial/tools/web-qa/node_modules).
@@ -22,7 +24,11 @@ function chargerPlaywright() {
throw new Error('Playwright introuvable. Définir PLAYWRIGHT_DIR vers un node_modules qui le contient.')
}
const OUT = fileURLToPath(new URL('../public/arbre-genealogique-a-remplir/', import.meta.url))
// Une sortie par langue : dossier de la page et nom de fichier de chaque modèle
const LANGUES = [
{ lang: 'fr', out: fileURLToPath(new URL('../public/arbre-genealogique-a-remplir/', import.meta.url)), nom: (m) => m.slug },
{ lang: 'en', out: fileURLToPath(new URL('../public/en/printable-family-tree/', import.meta.url)), nom: (m) => m.en },
]
const APERCU_LARGEUR = 720
// Recale chaque trait d'écriture juste après son libellé, une fois les polices chargées
@@ -37,16 +43,17 @@ function ajusterTraits() {
async function main() {
const { chromium } = chargerPlaywright()
mkdirSync(OUT, { recursive: true })
const browser = await chromium.launch({ channel: 'chrome' })
const ctx = await browser.newContext({ deviceScaleFactor: 2 })
const page = await ctx.newPage()
const convert = await ctx.newPage()
const seul = process.argv[2]
for (const m of MODELES) {
if (seul && !m.slug.includes(seul)) continue
const html = m.build()
for (const { lang, out, nom } of LANGUES) for (const m of MODELES) {
const slug = nom(m)
if (seul && !slug.includes(seul)) continue
mkdirSync(out, { recursive: true })
const html = m.build(lang)
const [wmm, hmm] = m.portrait ? [210, 297] : [297, 210]
await page.setViewportSize({ width: Math.ceil(wmm * 96 / 25.4), height: Math.ceil(hmm * 96 / 25.4) })
await page.setContent(html, { waitUntil: 'networkidle' })
@@ -60,10 +67,10 @@ async function main() {
await document.fonts.ready
return document.fonts.check('400 12px "DM Sans"') && document.fonts.check('400 12px "Newsreader"')
})
if (!ok) throw new Error(`Polices non chargées pour ${m.slug}`)
if (!ok) throw new Error(`Polices non chargées pour ${slug}`)
await page.evaluate(ajusterTraits)
const pdf = `${OUT}${m.slug}.pdf`
const pdf = `${out}${slug}.pdf`
await page.pdf({ path: pdf, preferCSSPageSize: true, printBackground: true })
// Aperçu : capture de la feuille, réduite et encodée en WebP par le canvas de Chromium
@@ -81,8 +88,8 @@ async function main() {
return { url: c.toDataURL('image/webp', 0.86), w: c.width, h: c.height }
}, { b64: png.toString('base64'), largeur: APERCU_LARGEUR })
const webp = Buffer.from(dataUrl.url.split(',')[1], 'base64')
writeFileSync(`${OUT}${m.slug}.webp`, webp)
console.log(`${m.slug} pdf ok apercu ${dataUrl.w}x${dataUrl.h} ${Math.round(webp.length / 1024)} Ko`)
writeFileSync(`${out}${slug}.webp`, webp)
console.log(`${lang} ${slug} pdf ok apercu ${dataUrl.w}x${dataUrl.h} ${Math.round(webp.length / 1024)} Ko`)
}
await browser.close()
}
+4 -1
View File
@@ -7,6 +7,9 @@
<title>Vous avez reçu le lien de l'arbre de votre famille, le mode d'emploi</title>
<meta name="description" content="Ouvrir l'arbre avec le mot de passe, regarder les photos, ajouter un souvenir ou une personne qui manque. Le mode d'emploi pas à pas, sur téléphone comme sur ordinateur." />
<link rel="canonical" href="https://parenthese.io/aide/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/aide/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/help/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/aide/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="fr_FR" />
@@ -156,7 +159,7 @@
</main>
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/">parenthese.io</a></span>
<span>Parenthèse · <a href="/">parenthese.io</a> · <a href="/en/help/" hreflang="en" lang="en">English</a></span>
<nav aria-label="Guides">
<a href="/comment-faire-un-arbre-genealogique/">Comment faire un arbre généalogique</a>
<a href="/arbre-genealogique-a-remplir/">Arbre généalogique à remplir</a>
@@ -7,6 +7,9 @@
<title>Quelle application d'arbre généalogique choisir ? Geneanet, MyHeritage, Filae, Parenthèse</title>
<meta name="description" content="Rechercher des ancêtres et partager la mémoire de sa famille ne demandent pas les mêmes outils. Comparatif honnête de Geneanet, MyHeritage, Filae, FamilySearch, des modèles à imprimer et de Parenthèse." />
<link rel="canonical" href="https://parenthese.io/application-arbre-genealogique/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/application-arbre-genealogique/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/family-tree-app/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/application-arbre-genealogique/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="fr_FR" />
@@ -149,7 +152,7 @@
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/">parenthese.io</a></span>
<span>Parenthèse · <a href="/">parenthese.io</a> · <a href="/en/family-tree-app/" hreflang="en" lang="en">English</a></span>
<nav aria-label="Guides">
<a href="/comment-faire-un-arbre-genealogique/">Comment faire un arbre généalogique</a>
<a href="/arbre-genealogique-a-remplir/">Arbre généalogique à remplir</a>
@@ -7,6 +7,9 @@
<title>Arbre généalogique à remplir, modèles vierges gratuits</title>
<meta name="description" content="Cinq modèles d'arbre généalogique vierges en PDF A4, de 3 à 5 générations, avec cases photo ou arbre dessiné. Gratuits, sans inscription." />
<link rel="canonical" href="https://parenthese.io/arbre-genealogique-a-remplir/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/arbre-genealogique-a-remplir/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/printable-family-tree/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/arbre-genealogique-a-remplir/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="fr_FR" />
@@ -197,7 +200,7 @@
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/">parenthese.io</a></span>
<span>Parenthèse · <a href="/">parenthese.io</a> · <a href="/en/printable-family-tree/" hreflang="en" lang="en">English</a></span>
<nav aria-label="Guides">
<a href="/comment-faire-un-arbre-genealogique/">Comment faire un arbre généalogique</a>
<a href="/application-arbre-genealogique/">Quelle application choisir</a>
@@ -7,6 +7,9 @@
<title>Faire un arbre généalogique avec photos, vidéos et voix</title>
<meta name="description" content="Comment faire un arbre généalogique avec des photos. Lesquelles choisir, comment les numériser, où les mettre pour que la famille les voie, et comment y ajouter les vidéos et les voix." />
<link rel="canonical" href="https://parenthese.io/arbre-genealogique-avec-photos/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/arbre-genealogique-avec-photos/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/family-tree-with-photos/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/arbre-genealogique-avec-photos/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="fr_FR" />
@@ -115,7 +118,7 @@
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/">parenthese.io</a></span>
<span>Parenthèse · <a href="/">parenthese.io</a> · <a href="/en/family-tree-with-photos/" hreflang="en" lang="en">English</a></span>
<nav aria-label="Guides">
<a href="/comment-faire-un-arbre-genealogique/">Comment faire un arbre généalogique</a>
<a href="/arbre-genealogique-a-remplir/">Arbre généalogique à remplir</a>
@@ -7,6 +7,9 @@
<title>Comment faire un arbre généalogique, le guide pas à pas</title>
<meta name="description" content="Faire son arbre généalogique soi-même et gratuitement. Par qui commencer, où trouver les actes, papier ou en ligne, et comment faire compléter la famille." />
<link rel="canonical" href="https://parenthese.io/comment-faire-un-arbre-genealogique/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/comment-faire-un-arbre-genealogique/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/how-to-make-a-family-tree/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/comment-faire-un-arbre-genealogique/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="fr_FR" />
@@ -181,7 +184,7 @@
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/">parenthese.io</a></span>
<span>Parenthèse · <a href="/">parenthese.io</a> · <a href="/en/how-to-make-a-family-tree/" hreflang="en" lang="en">English</a></span>
<nav aria-label="Guides">
<a href="/arbre-genealogique-a-remplir/">Arbre généalogique à remplir</a>
<a href="/application-arbre-genealogique/">Quelle application choisir</a>
+4 -1
View File
@@ -7,6 +7,9 @@
<title>Organiser une cousinade, méthode, budget et activités</title>
<meta name="description" content="Organiser une cousinade sans y passer six mois. Qui inviter, quel budget, quelles activités, quel repas, et comment garder les photos et les souvenirs de la journée." />
<link rel="canonical" href="https://parenthese.io/cousinade/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/cousinade/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/family-reunion/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/cousinade/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="fr_FR" />
@@ -138,7 +141,7 @@
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/">parenthese.io</a></span>
<span>Parenthèse · <a href="/">parenthese.io</a> · <a href="/en/family-reunion/" hreflang="en" lang="en">English</a></span>
<nav aria-label="Guides">
<a href="/comment-faire-un-arbre-genealogique/">Comment faire un arbre généalogique</a>
<a href="/arbre-genealogique-a-remplir/">Arbre généalogique à remplir</a>
@@ -7,6 +7,9 @@
<title>Données et vie privée, ce que Parenthèse enregistre et pourquoi</title>
<meta name="description" content="Ce que Parenthèse enregistre quand vous créez un compte et un arbre familial, qui peut le voir, où c'est hébergé, ce qui est mesuré, et comment exporter ou supprimer vos données." />
<link rel="canonical" href="https://parenthese.io/donnees-et-vie-privee/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/donnees-et-vie-privee/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/privacy/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/donnees-et-vie-privee/" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="fr_FR" />
@@ -115,7 +118,7 @@
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/">parenthese.io</a></span>
<span>Parenthèse · <a href="/">parenthese.io</a> · <a href="/en/privacy/" hreflang="en" lang="en">English</a></span>
<nav aria-label="Guides">
<a href="/comment-faire-un-arbre-genealogique/">Comment faire un arbre généalogique</a>
<a href="/arbre-genealogique-a-remplir/">Arbre généalogique à remplir</a>
+149
View File
@@ -0,0 +1,149 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#FBFAF7" />
<title>How to plan a family reunion, budget, food and activities</title>
<meta name="description" content="Plan a large family reunion without spending six months on it. Who to invite, what budget, which activities, what to eat, and how to keep the photos and memories of the day." />
<link rel="canonical" href="https://parenthese.io/en/family-reunion/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/cousinade/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/family-reunion/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/cousinade/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://parenthese.io/en/family-reunion/" />
<meta property="og:title" content="How to plan a family reunion, budget, food and activities" />
<meta property="og:description" content="Track down every branch, set the date, share the budget, plan the day, collect the memories." />
<meta property="og:image" content="https://parenthese.io/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300&family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/guides.css" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "HowTo",
"name": "How to plan a family reunion",
"inLanguage": "en",
"step": [
{ "@type": "HowToStep", "name": "Track down the family", "text": "Build the list of branches and people to invite, starting from the family tree." },
{ "@type": "HowToStep", "name": "Set the date and the place", "text": "Six months ahead, a weekend in spring or early summer, a venue with space and a plan for rain." },
{ "@type": "HowToStep", "name": "Share the budget", "text": "A set contribution per adult, announced with the date, rather than one organizer who pays for everything up front." },
{ "@type": "HowToStep", "name": "Keep the program light", "text": "A shared meal, a moment when the elders tell their stories, a group photo for each branch." },
{ "@type": "HowToStep", "name": "Collect the memories", "text": "Ask everyone to bring a photo and a story, and record them on the day." },
{ "@type": "HowToStep", "name": "Keep a record", "text": "Gather photos, videos and stories in a shared family tree that the whole family can open from a link." }
]
},
{
"@type": "FAQPage",
"mainEntity": [
{ "@type": "Question", "name": "What is a cousinade?", "acceptedAnswer": { "@type": "Answer", "text": "The French word for a large family reunion, the descendants of the same ancestral couple, often across several branches and generations, gathered for a day or a weekend." } },
{ "@type": "Question", "name": "How far in advance should you plan a family reunion?", "acceptedAnswer": { "@type": "Answer", "text": "Six months for about thirty people, a year for more than a hundred. The hard part is not the venue, it is finding and reaching every branch." } },
{ "@type": "Question", "name": "How do you find all the cousins to invite?", "acceptedAnswer": { "@type": "Answer", "text": "Start from the family tree. Each known branch leads to someone who knows the next one. A shared online tree, which everyone fills in, does this work in a few weeks." } },
{ "@type": "Question", "name": "Who do you invite to a family reunion?", "acceptedAnswer": { "@type": "Answer", "text": "All the descendants of the same ancestral couple, with their partners and children. Pick the starting couple based on the size you want. Grandparents give about thirty people, great-grandparents often more than a hundred."} } ,
{ "@type": "Question", "name": "How much does a family reunion cost?", "acceptedAnswer": { "@type": "Answer", "text": "A contribution per adult covers the venue and the meal. Ask for the price of the venue and the caterer, divide by the number of adults expected, and add a small margin for last-minute no-shows. A town hall or community hall costs far less than a group vacation rental booked for the weekend. Children pay little or nothing."} } ,
{ "@type": "Question", "name": "What food should you serve at a family reunion?", "acceptedAnswer": { "@type": "Answer", "text": "A potluck where each branch brings a dish, the simplest to organize, or a caterer for the main course if the group is over fifty people. Ask each branch to bring the family recipe, the one you only eat at their house. Set up long tables rather than round ones, so the branches mix."} } ,
{ "@type": "Question", "name": "What activities should you plan for a family reunion?", "acceptedAnswer": { "@type": "Answer", "text": "Few, and ones that get people talking. A large tree on the wall where everyone finds their place, a moment when the oldest tell their stories, a group photo for each branch, a guessing game with the childhood photos everyone brought. For the children, a space of their own and one adult per age group."} }
]
}
]
}
</script>
</head>
<body>
<header class="top">
<div class="wrap">
<a class="brand" href="/en/" aria-label="Parenthèse, home">
<img src="/logo.svg" alt="" width="166" height="22" />
</a>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;source=guide-cousinade&amp;lang=en">Start your tree</a>
</div>
</header>
<main>
<article class="wrap">
<span class="eyebrow">Guide</span>
<h1>How to plan a family reunion</h1>
<p class="lead">A family reunion lasts one day. What takes time is before, finding every branch. And what has value is after, what is left once everyone has gone home.</p>
<h2>What a large family reunion really is</h2>
<p>The descendants of the same ancestral couple, gathered for a day or a weekend. Not the thirty people at Christmas, more like the hundred and fifty who descend from the great-grandparents, half of whom have never met. In France this has its own name, a <em lang="fr">cousinade</em>, a gathering of cousins. The word comes from the southwest of France, the custom is everywhere.</p>
<h2>1. Track down the family</h2>
<p>This is the step that decides everything, and the one people underestimate. Nobody has the full list. Each branch knows its own branch, and vaguely knows there are "the cousins in Nantes".</p>
<p>Start from the tree. Put down the ancestral couple and their children, then ask one person per branch to fill in theirs. A shared online tree does this work on its own in a few weeks. Everyone adds their people, corrects a date, finds an address. You get the guest list and, as a bonus, the shared memory that was missing.</p>
<h2>2. Set the date and the place</h2>
<p>Six months ahead for about thirty people, a year for more than a hundred. A Saturday in May, June or early September, outside school vacations and long weekends. A place with outdoor space, shelter from the rain, restrooms, and easy access for the oldest guests. The community hall of a family village, a group rental, the garden of whoever has a big one.</p>
<h2>3. Share the budget</h2>
<p>A contribution per adult, announced at the same time as the date, covers the venue and the meal. An organizer who pays for everything and "gets paid back later" ends up covering the difference. An online money pool settles the question in one message.</p>
<h2>4. Keep the program light</h2>
<p>The program of a family reunion is to let people talk to each other. Three things are enough, a meal where everyone brings something, a moment when the oldest tell their stories in front of everyone, and a group photo for each branch, then one with everyone. A name tag with the first name and the branch saves the first twenty minutes of "and whose son are you?"</p>
<h2>5. Collect the memories on the day</h2>
<p>In the invitation, ask everyone to bring an old photo and a story. On the day, one person holds a phone. They photograph the photos people brought, record three minutes of each elder telling a story, film the moment of the cake. It is the only day of the year when everyone who knows is in the same room.</p>
<div class="note">
<p><strong>The question that gets people talking.</strong> "How did your parents meet?" Nobody ever asks it, everybody has an answer.</p>
</div>
<h2>6. Keep a record everyone can find</h2>
<p>The reunion's WhatsApp group dies within three weeks, with the photos inside it. Instead, gather what was collected in the shared tree. Each photo on the person it shows, each recording on the person speaking, the group photo on everyone. The link sent after the reunion is what the cousins will still open in five years, and what will make them want to do the next one.</p>
<p>Parenthèse is made for this. It is a family tree where each person carries their photos, their videos and their voice. The family views it through the link without an account, and contributes with a password. You stay in control of what gets published.</p>
<h2>Frequently asked questions</h2>
<div class="faq">
<details>
<summary>How far in advance should you plan a family reunion?</summary>
<p>Six months for about thirty people, a year for more than a hundred. The hard part is not the venue, it is finding and reaching every branch.</p>
</details>
<details>
<summary>How do you find all the cousins to invite?</summary>
<p>Start from the family tree. Each known branch leads to someone who knows the next one. A shared online tree that everyone fills in does this work in a few weeks.</p>
</details>
<details>
<summary>What do you do with the photos after the reunion?</summary>
<p>Put them on the people they show in a shared family tree, with the recordings and videos from the day. A messaging group loses them within a few weeks.</p>
</details>
<details>
<summary>Who do you invite to a family reunion?</summary>
<p>All the descendants of the same ancestral couple, with their partners and children. Pick the starting couple based on the size you want. Grandparents give about thirty people, great-grandparents often more than a hundred.</p>
</details>
<details>
<summary>How much does a family reunion cost?</summary>
<p>A contribution per adult covers the venue and the meal. Ask for the price of the venue and the caterer, divide by the number of adults expected, and add a small margin for last-minute no-shows. A town hall or community hall costs far less than a group vacation rental booked for the weekend. Children pay little or nothing.</p>
</details>
<details>
<summary>What food should you serve at a family reunion?</summary>
<p>A potluck where each branch brings a dish, the simplest to organize, or a caterer for the main course if the group is over fifty people. Ask each branch to bring the family recipe, the one you only eat at their house. Set up long tables rather than round ones, so the branches mix.</p>
</details>
<details>
<summary>What activities should you plan for a family reunion?</summary>
<p>Few, and ones that get people talking. A large tree on the wall where everyone finds their place, a moment when the oldest tell their stories, a group photo for each branch, a guessing game with the childhood photos everyone brought. For the children, a space of their own and one adult per age group.</p>
</details>
</div>
<section class="cta">
<h2>Start with the tree, the guest list will follow</h2>
<p>An account, a family name, and each branch fills in its own through a link.</p>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;source=guide-cousinade&amp;lang=en">Start your tree</a>
</section>
</article>
</main>
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/en/">parenthese.io</a> · <a href="/cousinade/" hreflang="fr" lang="fr">Français</a></span>
<nav aria-label="Guides"><a href="/en/how-to-make-a-family-tree/">How to make a family tree</a> <a href="/en/printable-family-tree/">Printable family tree</a> <a href="/en/family-tree-app/">Choosing a family tree app</a> <a href="/en/family-tree-with-photos/">Family tree with photos</a> <a href="/en/tell-your-family-story/">Telling your family's story</a> <a href="/en/privacy/">Data and privacy</a></nav>
</div>
</footer>
</body>
</html>
@@ -0,0 +1,167 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#FBFAF7" />
<title>Which family tree app should you choose? Geneanet, MyHeritage, Filae, Parenthèse</title>
<meta name="description" content="Researching ancestors and sharing your family's memories don't call for the same tools. An honest comparison of Geneanet, MyHeritage, Filae, FamilySearch, printable templates and Parenthèse." />
<link rel="canonical" href="https://parenthese.io/en/family-tree-app/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/application-arbre-genealogique/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/family-tree-app/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/application-arbre-genealogique/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://parenthese.io/en/family-tree-app/" />
<meta property="og:title" content="Which family tree app should you choose?" />
<meta property="og:description" content="Researching ancestors and sharing your family's memories don't call for the same tools. A comparison of Geneanet, MyHeritage, Filae, FamilySearch and Parenthèse." />
<meta property="og:image" content="https://parenthese.io/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300&family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/guides.css" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Article",
"headline": "Which family tree app should you choose?",
"inLanguage": "en",
"datePublished": "2026-09-14",
"dateModified": "2026-09-25",
"author": { "@type": "Person", "name": "Ilies Allali", "url": "https://iliesallali.design/" },
"publisher": { "@id": "https://parenthese.io/#organization" },
"mainEntityOfPage": "https://parenthese.io/en/family-tree-app/"
},
{
"@type": "FAQPage",
"mainEntity": [
{ "@type": "Question", "name": "What is the best family tree app?", "acceptedAnswer": { "@type": "Answer", "text": "There isn't just one. To find ancestors in the archives, Geneanet, Filae or FamilySearch. To gather and share the photos, videos and memories of a living family, Parenthèse. Many families use both." } },
{ "@type": "Question", "name": "Where can I make a family tree for free?", "acceptedAnswer": { "@type": "Answer", "text": "Geneanet and FamilySearch offer a free, research-oriented tree. Parenthèse is free, and will stay free. The tree can be viewed without an account, with a simple link." } },
{ "@type": "Question", "name": "Is Geneanet free?", "acceptedAnswer": { "@type": "Answer", "text": "Yes, for the tree. Free registration lets you host a tree with no size limit, back it up, browse other members' trees and the collaborative collections (graves, transcriptions, registers, postcards), with 1 GB for private photos and documents. The Premium subscription, from €4.13 per month, adds advanced search (spouse, parents, spelling variants, nearby places), indexed archive transcriptions, the Genealogy Library, automatic hints and alerts, and 10 GB of storage." } },
{ "@type": "Question", "name": "Is MyHeritage free?", "acceptedAnswer": { "@type": "Answer", "text": "Partly. Registration is free and gives you a Basic family site, with a tree limited to 250 people. Searching the archives is free, but viewing some documents requires a Data subscription. The paid plans (Premium, PremiumPlus, Data, Complete, Omni) are billed yearly. Premium, the cheapest, is listed at €99 per year on the French pricing page (€65 for the first year) and raises the tree limit to 2,500 people. PremiumPlus makes it unlimited." } },
{ "@type": "Question", "name": "Do I need desktop software to make a family tree?", "acceptedAnswer": { "@type": "Answer", "text": "No. Software like Heredis is still useful for people researching their ancestors who want to keep everything on their computer, but an online tree can be shared with the family without installing anything." } }
]
}
]
}
</script>
</head>
<body>
<header class="top">
<div class="wrap">
<a class="brand" href="/en/" aria-label="Parenthèse, home">
<img src="/logo.svg" alt="" width="166" height="22" />
</a>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;lang=en&amp;source=guide-application">Create my tree</a>
</div>
</header>
<main>
<article class="wrap">
<span class="eyebrow">Guide</span>
<h1>Which family tree app should you choose?</h1>
<p class="lead">The question hides two different needs. Finding ancestors in the archives, or gathering what your family still knows about itself before it gets lost. The right tools aren't the same.</p>
<h2>Start by naming what you need</h2>
<p><strong>You're looking for ancestors.</strong> Civil records, censuses, parish registers, matches with other genealogists. You need a tool connected to archives, with millions of trees already entered. That's what Geneanet, Filae, MyHeritage and FamilySearch do.</p>
<p><strong>You want to keep your family's memories.</strong> The photos in shoeboxes, a grandmother's voice telling a story, wedding videos, the stories only one uncle knows. You need a space the whole family can open without fighting with software, and add to without a complicated password. That's what Parenthèse does.</p>
<p>Many families need both, in that order. First the living memory, because it disappears fast, then the research, which can wait.</p>
<h2>The tools, one by one</h2>
<h3>Geneanet</h3>
<p>The French reference for research. A free online tree, digitized archives, a huge community that has already entered millions of ancestors. If your grandfather was born in France before 1900, someone has probably already found his parents on Geneanet. The interface is dense, designed for searching, not for browsing as a family on a Sunday. The tree and access to the collaborative collections are free, and the Premium subscription is mostly for searching faster (advanced search, indexed archive transcriptions, automatic hints).</p>
<h3>Filae</h3>
<p>A specialist in French civil records indexed by name. The service is paid and its strength is searching for records. The tree itself is a research aid, not an album.</p>
<h3>MyHeritage</h3>
<p>An Israeli company with a strong presence worldwide, known for its DNA tests and its automatic matches between trees. Freemium model. The free tree stops at 250 people, and a yearly subscription is needed to go beyond that or to view some of the archive documents. Lots of sales emails.</p>
<h3>FamilySearch</h3>
<p>Free, funded by The Church of Jesus Christ of Latter-day Saints. A single shared worldwide tree that anyone can edit. Excellent for research, disconcerting when a stranger corrects your great-grandmother.</p>
<h3>Heredis and desktop software</h3>
<p>For people who want to keep everything on their computer and produce books and reports. Powerful, but the tree lives on a single machine, and sharing it with the family takes exports.</p>
<h3>Canva and printable templates</h3>
<p>A drawn tree, nice on the wall, frozen the day you print it. Perfect as a gift, no use for keeping a memory alive that keeps growing.</p>
<h3>Parenthèse</h3>
<p>A tree where each person carries their photos, videos, voice and stories. You share it with a link, and the family views it without creating an account. With a contribution password, they suggest additions and corrections that you approve, or that go through directly if you choose. No archives, no ancestor search. Parenthèse starts where the others stop, with living people and what they know.</p>
<h2>At a glance</h2>
<table>
<thead><tr><th>Tool</th><th>Made for</th><th>Photos, videos, voice</th><th>Sharing with family</th></tr></thead>
<tbody>
<tr><td>Geneanet</td><td>Research&shy;ing ancestors</td><td>Photos on profiles</td><td>Public or private tree, account required to contribute</td></tr>
<tr><td>Filae</td><td>French civil records</td><td>Limited</td><td>Researcher-oriented</td></tr>
<tr><td>MyHeritage</td><td>Research and DNA</td><td>Photos, automatic enhance&shy;ment</td><td>Invitations, subscription to go further</td></tr>
<tr><td>FamilySearch</td><td>Research, free</td><td>Photos and stories</td><td>Worldwide tree, editable by anyone</td></tr>
<tr><td>Heredis</td><td>Working on your computer</td><td>Yes, locally</td><td>By export</td></tr>
<tr><td>Printable templates</td><td>Decorating, gifting</td><td>One photo per box</td><td>An object, not a space</td></tr>
<tr><td>Parenthèse</td><td>Keeping and sharing living memory</td><td>Photos, videos, audio, stories, drawings</td><td>A link, viewing without an account, approved contri&shy;butions</td></tr>
</tbody>
</table>
<div class="note">
<p><strong>A criterion nobody looks at.</strong> Who will open the tree in ten years? Software installed on a computer that won't exist anymore, a canceled subscription, or a link the whole family already knows. Choose the tool your children will be able to open.</p>
</div>
<h2>Frequently asked questions</h2>
<div class="faq">
<details>
<summary>What is the best family tree app?</summary>
<p>There isn't just one. To find ancestors in the archives, Geneanet, Filae or FamilySearch. To gather and share the photos, videos and memories of a living family, Parenthèse. Many families use both.</p>
</details>
<details>
<summary>Where can I make a family tree for free?</summary>
<p>Geneanet and FamilySearch offer a free, research-oriented tree. Parenthèse is free, and will stay free. The tree can be viewed without an account, with a simple link.</p>
</details>
<details>
<summary>Is Geneanet free?</summary>
<p>Yes, for the tree. Free registration lets you host a tree with no size limit, back it up, browse other members' trees and the collaborative collections (graves, transcriptions, registers, postcards), with 1 GB for private photos and documents. The Premium subscription, from €4.13 per month, adds advanced search (spouse, parents, spelling variants, nearby places), indexed archive transcriptions, the Genealogy Library, automatic hints and alerts, and 10 GB of storage.</p>
</details>
<details>
<summary>Is MyHeritage free?</summary>
<p>Partly. Registration is free and gives you a Basic family site, with a tree limited to 250 people. Searching the archives is free, but viewing some documents requires a Data subscription. The paid plans (Premium, PremiumPlus, Data, Complete, Omni) are billed yearly. Premium, the cheapest, is listed at €99 per year on the French pricing page (€65 for the first year) and raises the tree limit to 2,500 people. PremiumPlus makes it unlimited.</p>
</details>
<details>
<summary>Do I need desktop software?</summary>
<p>No. Software like Heredis is still useful for people researching their ancestors who want to keep everything on their computer. An online tree can be shared with the family without installing anything, on a phone as well as a computer.</p>
</details>
<details>
<summary>Can I move from one to another?</summary>
<p>Yes, with the GEDCOM format, which all these tools read and write. Parenthèse imports and exports GEDCOM, so you can start from a Geneanet tree and add the living memory to it, or the other way around.</p>
</details>
</div>
<section class="cta">
<h2>Start with what disappears first</h2>
<p>An account, a family name, and you invite your family with a link.</p>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;lang=en&amp;source=guide-application">Create my tree</a>
</section>
</article>
</main>
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/en/">parenthese.io</a> · <a href="/application-arbre-genealogique/" hreflang="fr" lang="fr">Français</a></span>
<nav aria-label="Guides">
<a href="/en/how-to-make-a-family-tree/">How to make a family tree</a>
<a href="/en/printable-family-tree/">Printable family tree</a>
<a href="/en/family-tree-app/">Choosing a family tree app</a>
<a href="/en/family-tree-with-photos/">Family tree with photos</a>
<a href="/en/tell-your-family-story/">Telling your family's story</a>
<a href="/en/privacy/">Data and privacy</a>
</nav>
</div>
</footer>
</body>
</html>
@@ -0,0 +1,133 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#FBFAF7" />
<title>How to make a family tree with photos, videos and voices</title>
<meta name="description" content="How to make a family tree with photos. Which ones to choose, how to digitize them, where to put them so the family sees them, and how to add videos and voices." />
<link rel="canonical" href="https://parenthese.io/en/family-tree-with-photos/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/arbre-genealogique-avec-photos/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/family-tree-with-photos/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/arbre-genealogique-avec-photos/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://parenthese.io/en/family-tree-with-photos/" />
<meta property="og:title" content="How to make a family tree with photos, videos and voices" />
<meta property="og:description" content="Which ones to choose, how to digitize them, where to put them so the family sees them." />
<meta property="og:image" content="https://parenthese.io/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300&family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/guides.css" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "HowTo",
"name": "Make a family tree with photos",
"inLanguage": "en",
"step": [
{ "@type": "HowToStep", "name": "Gather", "text": "Collect the existing photos, on paper and digital, and note who is in each one while someone still knows." },
{ "@type": "HowToStep", "name": "Digitize", "text": "Photograph or scan paper prints flat, in daylight, without flash, at 300 dpi with a scanner." },
{ "@type": "HowToStep", "name": "Name and date", "text": "A photo with no name or date loses its value within a generation. Write both down when you add it." },
{ "@type": "HowToStep", "name": "Put each photo on the right person", "text": "In a digital tree, each person carries their own photos, videos and recordings." },
{ "@type": "HowToStep", "name": "Share", "text": "Send the link to the family so they can fill in, correct and add their own pictures." }
]
},
{
"@type": "FAQPage",
"mainEntity": [
{ "@type": "Question", "name": "How do I make a family tree with photos?", "acceptedAnswer": { "@type": "Answer", "text": "Gather the photos, digitize the prints, name and date each one, then put them on the right person's page in a digital tree the family can open with a link. A printable template only holds one photo per box and is frozen the day it's printed." } },
{ "@type": "Question", "name": "Where can I make a family tree with photos for free?", "acceptedAnswer": { "@type": "Answer", "text": "Parenthèse is free, and will stay free. Each person in the tree can carry several photos, videos and audio recordings, and the tree is shared with a link." } }
]
}
]
}
</script>
</head>
<body>
<header class="top">
<div class="wrap">
<a class="brand" href="/en/" aria-label="Parenthèse, home">
<img src="/logo.svg" alt="" width="166" height="22" />
</a>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;lang=en&amp;source=guide-photos">Create my tree</a>
</div>
</header>
<main>
<article class="wrap">
<span class="eyebrow">Guide</span>
<h1>How to make a family tree with photos</h1>
<p class="lead">A tree without faces is a list of names. With photos, videos and voices, it becomes what the family actually looks at. Here's how to go about it, from the shoeboxes to the shared link.</p>
<h2>1. Gather before you sort</h2>
<p>The photos are spread across several houses, several phones, several generations. Ask everyone to send you what they have, without sorting. Sorting comes later, and it goes better when you can see everything.</p>
<p>Do it quickly for the older relatives' paper prints. The question that matters isn't "is it a nice photo" but "who still knows who's in it". Sit down with the person who knows, and write on the back or on a sheet of paper the names, the place, the approximate year, what was happening that day.</p>
<h2>2. Digitize without special equipment</h2>
<p>A phone is enough. Lay the photo flat near a window, without flash, the phone parallel to the print, and frame the shot a little wider than the photo so you can crop it afterward. Scanning apps (Google PhotoScan, Notes on iPhone, Adobe Scan) remove glare by combining several shots.</p>
<p>With a scanner, 300 dpi is enough for a 4 × 6 print (10 × 15 cm). Go up to 600 dpi for small old prints you'll want to enlarge. Keep the original scan as is, and do your retouching on a copy.</p>
<h2>3. Name and date right away</h2>
<p>A photo with no name or date loses its value within a generation. It's the one rule with no exceptions. When you add a picture to the tree, write who's in it, where, when, and a line of context. Thirty seconds now, or a puzzle for your grandchildren.</p>
<h2>4. One photo per box, or a whole life per person?</h2>
<p>Printable family tree templates, wall frames and custom posters hold one photo per person. It's a lovely gift, and it's frozen the day it's printed. Nothing gets added to it.</p>
<p>In a digital tree, each person carries everything that's known about them, several photos at different ages, a wedding video, a recording of their voice, a story told by a cousin. And the tree keeps growing as the family adds their own.</p>
<div class="note">
<p><strong>The two go together.</strong> Make the digital tree first, it will be the source for printing a nice wall version the day you want to give it as a gift.</p>
</div>
<h2>5. Add videos and voices</h2>
<p>The voice is what goes missing first. A grandmother telling how she met her husband, recorded for three minutes with a phone on the table, is worth more than ten photos. Ask a simple question, let her talk, don't interrupt. Videos of family gatherings, even shaky ones, are just as valuable, they hold the gestures and the laughter nobody can describe.</p>
<p>In Parenthèse, each person can carry photos, videos, audio recordings, documents and quotes. They surround the person's portrait in the tree, and open with a click.</p>
<h2>6. Share, so the others can fill it in</h2>
<p>A tree only you add to stops at what you know. Send the link to the family. With Parenthèse, they view it without creating an account. With the contribution password, they suggest their photos and corrections, and you approve them, or let them through directly if you prefer. Distant cousins are often the ones who have the missing photo.</p>
<h2>Frequently asked questions</h2>
<div class="faq">
<details>
<summary>How do I make a family tree with photos?</summary>
<p>Gather, digitize, name and date, then put each photo on the right person's page in a digital tree the family opens with a link. A printable template only holds one photo per box.</p>
</details>
<details>
<summary>Where can I make a family tree with photos for free?</summary>
<p>Parenthèse is free, and will stay free. Each person can carry several photos, videos and recordings, and the tree can be viewed without an account.</p>
</details>
<details>
<summary>What format and size should photos be?</summary>
<p>JPEG or HEIC, straight from the phone, with no extra compression. Parenthèse resizes them itself for display and keeps the original in high quality for enlarging.</p>
</details>
</div>
<section class="cta">
<h2>Start with the faces</h2>
<p>An account, a family name, and you invite your family with a link.</p>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;lang=en&amp;source=guide-photos">Create my tree</a>
</section>
</article>
</main>
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/en/">parenthese.io</a> · <a href="/arbre-genealogique-avec-photos/" hreflang="fr" lang="fr">Français</a></span>
<nav aria-label="Guides">
<a href="/en/how-to-make-a-family-tree/">How to make a family tree</a>
<a href="/en/printable-family-tree/">Printable family tree</a>
<a href="/en/family-tree-app/">Choosing a family tree app</a>
<a href="/en/family-tree-with-photos/">Family tree with photos</a>
<a href="/en/tell-your-family-story/">Telling your family's story</a>
<a href="/en/privacy/">Data and privacy</a>
</nav>
</div>
</footer>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

+174
View File
@@ -0,0 +1,174 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#FBFAF7" />
<title>You received the link to your family tree, here is how it works</title>
<meta name="description" content="Open the tree with the password, look at the photos, add a memory or a missing relative. A step-by-step guide, on a phone or a computer." />
<link rel="canonical" href="https://parenthese.io/en/help/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/aide/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/help/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/aide/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://parenthese.io/en/help/" />
<meta property="og:title" content="You received the link to your family tree" />
<meta property="og:description" content="Open the tree, look around, add a memory or a person. A step-by-step guide." />
<meta property="og:image" content="https://parenthese.io/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300&family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/guides.css" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "HowTo",
"name": "Open your family tree and add a memory to it",
"inLanguage": "en-US",
"totalTime": "PT5M",
"estimatedCost": { "@type": "MonetaryAmount", "currency": "EUR", "value": "0" },
"step": [
{ "@type": "HowToStep", "position": 1, "name": "Open the tree", "text": "Tap the link you received, type the password that came with it, then tap “Open the tree”." },
{ "@type": "HowToStep", "position": 2, "name": "Look around", "text": "Drag the tree with your finger, spread two fingers to zoom in, and tap a portrait to open that person's profile." },
{ "@type": "HowToStep", "position": 3, "name": "Add a memory", "text": "Tap “Add a memory”, choose the person, pick a photo from your phone, write your first name, then tap “Add this memory”." },
{ "@type": "HowToStep", "position": 4, "name": "Add a missing person", "text": "Tap “Add a person”, write their first and last name, say who they are related to, then send." },
{ "@type": "HowToStep", "position": 5, "name": "Wait for the review", "text": "The person who manages the tree reviews what was sent, then adds it for the whole family." }
]
},
{
"@type": "FAQPage",
"mainEntity": [
{ "@type": "Question", "name": "I lost the tree's password, what should I do?", "acceptedAnswer": { "@type": "Answer", "text": "Ask the person who sent you the link. They can find it in the tree, in the sharing panel." } },
{ "@type": "Question", "name": "Do I need to create an account?", "acceptedAnswer": { "@type": "Answer", "text": "No. The link and the password are enough to view the tree and add memories to it. An account only lets you get back to the tree without typing the password again." } },
{ "@type": "Question", "name": "Who can see the tree?", "acceptedAnswer": { "@type": "Answer", "text": "Only people who have the link and the password. The tree does not show up in search engines." } }
]
}
]
}
</script>
</head>
<body>
<header class="top">
<div class="wrap">
<a class="brand" href="/en/" aria-label="Parenthèse, home">
<img src="/logo.svg" alt="" width="166" height="22" />
</a>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;lang=en&amp;source=aide">Start your tree</a>
</div>
</header>
<main>
<article class="wrap">
<span class="eyebrow">How it works</span>
<h1>You received the link to your family tree</h1>
<p class="lead">Someone in your family made a tree on Parenthèse and is inviting you to look at it and add to it. There is nothing to install and no account to create. Here is how it works, step by step, on a phone or a computer.</p>
<h2>1. Open the tree</h2>
<p>Tap the link you received by email, text message or WhatsApp. A page opens with the name of the tree.</p>
<p>Type the password that came with the link, with the capital letters exactly as given, then tap “Open the tree”. Keep the message with the link and the password, you will need it to come back.</p>
<div class="shots">
<figure><img src="/en/help/ouvrir.webp" alt="The page asking for the password, with the Open the tree button" width="600" height="1022" loading="lazy" /></figure>
</div>
<h2>2. Look around</h2>
<p>The first time, a short welcome note appears. Tap “View the tree” to close it.</p>
<p>Each portrait is a person in the family. To move around, drag the tree with your finger. To zoom in, spread two fingers apart on the screen, and pinch them together to see more. The magnifying glass, at the top right, finds someone by their first name.</p>
<p>Tap a portrait to open that person's profile, with their photos, memories and dates. The cross at the top of the profile closes it.</p>
<div class="shots">
<figure><img src="/en/help/arbre.webp" alt="The tree with the family portraits, and at the bottom the Add a memory, Add a person and More buttons" width="600" height="1022" loading="lazy" /></figure>
<figure><img src="/en/help/fiche.webp" alt="A person's profile, opened by tapping their portrait" width="600" height="1022" loading="lazy" /></figure>
</div>
<h2>3. Add a memory</h2>
<p>A memory can be a photo, a video, a voice recording, something she or he used to say, or a document like a letter or an announcement card.</p>
<ol>
<li>Tap “Add a memory”, at the bottom of the screen.</li>
<li>Type the first few letters of the person's first name, then tap their portrait.</li>
<li>Choose what you are adding, for example Photo, then tap “Choose a file”. Your phone shows you your photos, tap the one you want.</li>
<li>If you like, write a caption (the year, the place, who is in the photo). Also write your first name, so the family knows who shared it.</li>
<li>Tap “Add this memory”. A message confirms it has been sent.</li>
</ol>
<div class="shots">
<figure><img src="/en/help/pour-qui.webp" alt="Choosing the person by typing the first letters of their first name" width="600" height="1022" loading="lazy" /></figure>
<figure><img src="/en/help/souvenir.webp" alt="Choosing a photo, writing a caption and your first name, then Add this memory" width="600" height="1022" loading="lazy" /></figure>
</div>
<div class="note">
<p>You can also start from the profile. Tap the person's portrait, then “Add a memory”, below their photos.</p>
</div>
<h2>4. Add a missing person</h2>
<ol>
<li>Tap “Add a person”, at the bottom of the screen.</li>
<li>Write their first and last name, and their dates if you know them.</li>
<li>Say who they are related to. Choose Parent, Child, Spouse or Sibling, then type the first name of the person already in the tree and tap them in the list.</li>
<li>Tap “Add this person”. A window opens with your first name and a box for a note, if you want to explain. Tap “Send my contributions”.</li>
</ol>
<div class="shots">
<figure><img src="/en/help/personne.webp" alt="Saying who the new person is related to, here a child of Philippe" width="600" height="1022" loading="lazy" /></figure>
<figure><img src="/en/help/envoi.webp" alt="The sending window, with your first name and a note to go with it" width="600" height="1022" loading="lazy" /></figure>
</div>
<h2>5. What happens next</h2>
<p>The person who manages the tree receives what you sent, reviews it, then adds it. Your photos, your memories and the people you added then appear for the whole family. There is nothing else for you to do.</p>
<p>If you see a wrong date or a misspelled name, the simplest thing is to tell the person who sent you the link.</p>
<div class="shots">
<figure><img src="/en/help/merci.webp" alt="The confirmation message after sending" width="600" height="1022" loading="lazy" /></figure>
</div>
<h2>Frequently asked questions</h2>
<div class="faq">
<details>
<summary>I lost the password</summary>
<p>Ask the person who sent you the link. They can find it in the tree, in the sharing panel.</p>
</details>
<details>
<summary>The password is not accepted</summary>
<p>Check the capital letters and make sure there is no extra space before or after it. If it is still not accepted, it may have been changed. Ask the person who manages the tree for the new one.</p>
</details>
<details>
<summary>Do I need to create an account?</summary>
<p>No. The link and the password are enough to view the tree and add memories to it. An account only lets you get back to the tree without typing the password again.</p>
</details>
<details>
<summary>Does it work on a computer?</summary>
<p>Yes. The same buttons are at the bottom right of the screen. To zoom in on the tree, turn the mouse wheel, and click a portrait to open that person's profile.</p>
</details>
<details>
<summary>My photo won't upload</summary>
<p>A photo can be up to 5 MB and a video up to 20 MB. If it is rejected, send a smaller version, or ask someone in the family to add it for you.</p>
</details>
<details>
<summary>Who can see the tree?</summary>
<p>Only people who have the link and the password. The tree does not show up in search engines. The details are on the <a href="/en/privacy/">data and privacy</a> page.</p>
</details>
</div>
<section class="cta">
<h2>Make your own family tree</h2>
<p>It's free, and your family adds to it through a link, just like you did.</p>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;lang=en&amp;source=aide">Start your tree</a>
</section>
</article>
</main>
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/en/">parenthese.io</a> · <a href="/aide/" hreflang="fr" lang="fr">Français</a></span>
<nav aria-label="Guides">
<a href="/en/how-to-make-a-family-tree/">How to make a family tree</a>
<a href="/en/printable-family-tree/">Printable family tree</a>
<a href="/en/family-tree-app/">Choosing a family tree app</a>
<a href="/en/family-tree-with-photos/">Family tree with photos</a>
<a href="/en/tell-your-family-story/">Telling your family's story</a>
<a href="/en/privacy/">Data and privacy</a>
</nav>
</div>
</footer>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@@ -0,0 +1,199 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#FBFAF7" />
<title>How to make a family tree, a step-by-step guide</title>
<meta name="description" content="Make your family tree yourself, for free. Who to start with, where to find records, paper or online, and how to get the family to fill in the rest." />
<link rel="canonical" href="https://parenthese.io/en/how-to-make-a-family-tree/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/comment-faire-un-arbre-genealogique/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/how-to-make-a-family-tree/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/comment-faire-un-arbre-genealogique/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://parenthese.io/en/how-to-make-a-family-tree/" />
<meta property="og:title" content="How to make a family tree, step by step" />
<meta property="og:description" content="Who to start with, where to find records for free, which format to choose, and how to get the family to fill in the rest." />
<meta property="og:image" content="https://parenthese.io/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300&family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/guides.css" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Article",
"headline": "How to make a family tree, step by step",
"inLanguage": "en",
"datePublished": "2026-09-25",
"dateModified": "2026-09-25",
"author": { "@type": "Person", "name": "Ilies Allali", "url": "https://iliesallali.design/" },
"publisher": { "@id": "https://parenthese.io/#organization" },
"mainEntityOfPage": "https://parenthese.io/en/how-to-make-a-family-tree/"
},
{
"@type": "HowTo",
"name": "Make your family tree",
"inLanguage": "en",
"totalTime": "PT2H",
"estimatedCost": { "@type": "MonetaryAmount", "currency": "EUR", "value": "0" },
"step": [
{ "@type": "HowToStep", "position": 1, "name": "Start with yourself", "text": "Write down what you already know about yourself, your parents, your grandparents and your great-grandparents. Names, first names, birth name, dates and places of birth, marriage and death. Anything you are not sure of goes in pencil." },
{ "@type": "HowToStep", "position": 2, "name": "Talk to the family, oldest first", "text": "Ask the older relatives for names, approximate dates and above all towns. Record the conversation rather than taking notes." },
{ "@type": "HowToStep", "position": 3, "name": "Gather papers and photos", "text": "Family record books, announcements, military booklets, notarial deeds, postcards, photos labeled on the back. Photograph each document and note who owns it." },
{ "@type": "HowToStep", "position": 4, "name": "Request recent records from the town hall", "text": "In France, a descendant can obtain at any time the full copy of an ancestor's birth or marriage record, from the town hall where the record was made or online on service-public.gouv.fr. The request is free. Anyone can request a death record." },
{ "@type": "HowToStep", "position": 5, "name": "Go further back in the departmental archives", "text": "In France, registers more than 75 years old are kept in the departmental or municipal archives, and those more than 100 years old can generally be viewed online for free. Search by town, then by date, using the ten-year indexes kept since 1792." },
{ "@type": "HowToStep", "position": 6, "name": "Choose a format", "text": "A paper template to get started or to give as a gift, desktop software to keep everything on your computer, an online tree to share it." },
{ "@type": "HowToStep", "position": 7, "name": "Share it so the family can fill it in", "text": "Send the tree to the family with a link so they can correct dates and add the photos and memories only they know." }
]
},
{
"@type": "FAQPage",
"mainEntity": [
{ "@type": "Question", "name": "How do I make my own family tree?", "acceptedAnswer": { "@type": "Answer", "text": "Start with yourself, your parents and your grandparents, using what you already know. Then talk to the oldest members of the family, gather the papers, and look for the missing records at the town hall and in the archives (in France, the departmental archives). You don't need to be an expert. What matters most is noting where each piece of information comes from." } },
{ "@type": "Question", "name": "How can I make a family tree for free?", "acceptedAnswer": { "@type": "Answer", "text": "Every step can be free. In France, requesting records from the town hall costs nothing, the digitized registers of the departmental archives can be viewed online for free, and several tools offer a free tree, such as Geneanet, FamilySearch, or Parenthèse for keeping photos, voices and memories." } },
{ "@type": "Question", "name": "How much does a family tree cost?", "acceptedAnswer": { "@type": "Answer", "text": "Done yourself, it costs nothing. Possible expenses are a subscription to a research site to access paid indexes, hiring a professional researcher, who works on a quote, or printing a decorative tree." } },
{ "@type": "Question", "name": "How do I make a family tree on a computer?", "acceptedAnswer": { "@type": "Answer", "text": "Two options. Desktop software keeps everything on your machine and suits long-term research. An online tree opens from any computer or phone and can be shared with the family. The GEDCOM format lets you move from one to the other." } },
{ "@type": "Question", "name": "How can I find my ancestors online for free?", "acceptedAnswer": { "@type": "Answer", "text": "For French ancestors, on the website of the departmental archives where they lived, which have digitized the parish and civil registers, and on the FranceArchives name database, which compiles the censuses from 1836 to 1936 and the military service registers from 1867 to 1925. Geneanet and FamilySearch also offer trees and indexes you can browse for free." } }
]
}
]
}
</script>
</head>
<body>
<header class="top">
<div class="wrap">
<a class="brand" href="/en/" aria-label="Parenthèse, home">
<img src="/logo.svg" alt="" width="166" height="22" />
</a>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;lang=en&amp;source=guide-comment-faire">Create my tree</a>
</div>
</header>
<main>
<article class="wrap">
<span class="eyebrow">Guide</span>
<h1>How to make a family tree</h1>
<p class="lead">You can make your tree yourself, without paying anything, starting from what you already know. Here are the steps in the order that pays off most, from your own name all the way back to 19th-century registers.</p>
<h2>1. Start with yourself</h2>
<p>Take a sheet of paper or a <a href="/en/printable-family-tree/">printable family tree template</a>, and put yourself at the bottom. Above you, your two parents, then your four grandparents, then your eight great-grandparents. Four generations, fifteen people, that's a complete first tree.</p>
<p>For each person, write down what you already know.</p>
<ul>
<li>Last name and first names, with the birth name for married women.</li>
<li>Date and town of birth, even approximate.</li>
<li>Date and town of marriage.</li>
<li>Date and town of death, if applicable.</li>
</ul>
<p>Write what you're sure of in pen and what you're not sure of in pencil. And note where each piece of information comes from ("told by my mother", "family record book"). Six months from now, that's what will save you from searching twice.</p>
<p>The most useful detail for what comes next isn't the date, it's the town. Records are filed by town, and without it you don't know where to look.</p>
<h2>2. Talk to the family, oldest first</h2>
<p>Older relatives know things that aren't written down anywhere. A great-grandmother's maiden name, the village a grandfather came from, a second marriage nobody talks about. Start with them, the registers will still be there.</p>
<p>Go see them with your half-filled sheet. Showing the gaps gets people talking more easily than a general question. Ask above all for places and years, even to within ten years. Put a phone on the table and record, you'll listen better than if you take notes, and the voice will stay. The guide <a href="/en/tell-your-family-story/">telling your family's story</a> has questions that work.</p>
<h2>3. Gather the papers and photos</h2>
<p>Every household in the family keeps a box or a drawer. Ask to see what's inside. The documents that move you forward most are often these.</p>
<ul>
<li>The family record book (in France, the livret de famille), which gives the names, dates and places of birth of the spouses and the births of the children.</li>
<li>Birth, marriage and death announcements, and obituaries cut out of the newspaper.</li>
<li>Military booklets, which give the date and place of birth and often the parents' names.</li>
<li>Notarial deeds (estates, sales, marriage contracts), which name a whole set of siblings at once.</li>
<li>Postcards and letters, for addresses and first names.</li>
<li>Photos, especially those with a name or a date on the back.</li>
</ul>
<p>You don't need to take the originals. Photograph each document flat, in daylight, and note whose house it's in. For photos, the guide <a href="/en/family-tree-with-photos/">family tree with photos</a> explains how to digitize and caption them.</p>
<h2>4. Request recent records from the town hall</h2>
<p>In France, civil records (état civil) for grandparents and great-grandparents are often still held at the town hall (mairie). Birth and marriage registers only become open to everyone 75 years after they are closed. But a descendant doesn't have to wait.</p>
<ul>
<li>You can obtain at any time the full copy of the birth or marriage record of your parents, grandparents and great-grandparents, because you are their descendant.</li>
<li>A death record can be requested by anyone, without giving a reason.</li>
<li>The request goes to the town hall of the town where the record was made, in person, by mail or online on <a href="https://www.service-public.gouv.fr/particuliers/vosdroits/F1427">service-public.gouv.fr</a>.</li>
</ul>
<div class="note">
<p><strong>Requesting a record is free.</strong> Private websites offer to do it for a fee. The French administration points out that there is no reason to go through them.</p>
</div>
<p>Always ask for the full copy (copie intégrale) rather than an extract. It's the one that gives the parents' names, and so the next generation.</p>
<h2>5. Go further back in the departmental archives</h2>
<p>After 75 years, French registers leave the town halls for the departmental or municipal archives. Almost every département has digitized them, and registers more than 100 years old can be viewed online, for free, on the website of the département's archives. FranceArchives keeps the <a href="https://francearchives.gouv.fr/fr/article/38170">list of civil registration collections online</a>.</p>
<p>There is no national search engine by name. Registers are filed by town, then by year. Hence the importance of the town you noted in step 1.</p>
<ul>
<li>Start with the ten-year indexes (tables décennales), lists of names drawn up every ten years since 1792 for each town. They give the exact date of the record.</li>
<li>Then open the register for that year, at the date given.</li>
<li>The marriage record is the richest. It gives the age or date of birth of the spouses, where they came from and the names of their parents. With it, you gain a whole generation at once.</li>
<li>Before 1792, there are the parish registers (baptisms, marriages, burials), kept by the priest. They rarely come with indexes, so you have to read year by year.</li>
</ul>
<p>Two resources complement the records. The <a href="https://francearchives.gouv.fr/fr/basedenoms">FranceArchives name database</a> compiles the censuses from 1836 to 1936 and the military service registers from 1867 to 1925, with a search by name. And the trees already published on Geneanet or FamilySearch, free to browse, where someone may already have traced a branch. Check against the record before copying.</p>
<h2>6. Choose a format, paper, software or online</h2>
<p>Each format has its use, and many families combine two.</p>
<p><strong>Paper.</strong> A <a href="/en/printable-family-tree/">printable template</a> is perfect to get started, to work with an older relative around a table, or to give as a gift. It doesn't hold up well beyond four or five generations, and it isn't easy to correct.</p>
<p><strong>Desktop software.</strong> It keeps everything on your computer, handles thousands of people and produces printable reports. It's the tool for people who research for a long time. To share it, you have to export.</p>
<p><strong>An online tree.</strong> It opens from any device and can be shared with the family. Some tools are built to search for ancestors in the archives, others to keep what the family knows about itself. The comparison <a href="/en/family-tree-app/">which family tree app to choose</a> goes through them one by one.</p>
<p>The GEDCOM format, read by most of these tools, lets you move from one to another without typing everything in again.</p>
<h2>7. Share it, so the family can fill it in</h2>
<p>A tree made alone stops at what you know. Send it out. A cousin will correct a date, an aunt will find the missing photo, an uncle will remember the name of the village. The sooner the tree gets around, the faster it fills up.</p>
<p>It's also the moment to go beyond dates. For grandchildren, a name and two years say very little. Add photos and recordings as they come in, on the right person's page.</p>
<h2>Where Parenthèse fits in</h2>
<p>Parenthèse doesn't search for records in the archives. It's for keeping what you gathered in steps 2, 3 and 7. Each person in the tree carries their photos, their videos, recordings of their voice and the stories people tell about them.</p>
<p>You share the tree with a link, and the family views it without creating an account. With the contribution password, they suggest additions and corrections, which you approve. Parenthèse is free, and it imports and exports GEDCOM, so you can start from a tree begun somewhere else.</p>
<h2>Frequently asked questions</h2>
<div class="faq">
<details>
<summary>How do I make my own family tree?</summary>
<p>Start with yourself, your parents and your grandparents, using what you already know. Then talk to the oldest members of the family, gather the papers, and look for the missing records at the town hall and in the archives (in France, the departmental archives). You don't need to be an expert. What matters most is noting where each piece of information comes from.</p>
</details>
<details>
<summary>How can I make a family tree for free?</summary>
<p>Every step can be free. In France, requesting records from the town hall costs nothing, the digitized registers of the departmental archives can be viewed online for free, and several tools offer a free tree, such as Geneanet, FamilySearch, or Parenthèse for keeping photos, voices and memories.</p>
</details>
<details>
<summary>How much does a family tree cost?</summary>
<p>Done yourself, it costs nothing. Possible expenses are a subscription to a research site to access paid indexes, hiring a professional researcher, who works on a quote, or printing a decorative tree.</p>
</details>
<details>
<summary>How do I make a family tree on a computer?</summary>
<p>Two options. Desktop software keeps everything on your machine and suits long-term research. An online tree opens from any computer or phone and can be shared with the family. The GEDCOM format lets you move from one to the other.</p>
</details>
<details>
<summary>How can I find my ancestors online for free?</summary>
<p>For French ancestors, on the website of the departmental archives where they lived, which have digitized the parish and civil registers, and on the FranceArchives name database, which compiles the censuses from 1836 to 1936 and the military service registers from 1867 to 1925. Geneanet and FamilySearch also offer trees and indexes you can browse for free.</p>
</details>
</div>
<section class="cta">
<h2>Start with what you know</h2>
<p>An account, your name, your parents' names. The family will add the rest through the link.</p>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;lang=en&amp;source=guide-comment-faire">Create my tree</a>
</section>
</article>
</main>
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/en/">parenthese.io</a> · <a href="/comment-faire-un-arbre-genealogique/" hreflang="fr" lang="fr">Français</a></span>
<nav aria-label="Guides">
<a href="/en/how-to-make-a-family-tree/">How to make a family tree</a>
<a href="/en/printable-family-tree/">Printable family tree</a>
<a href="/en/family-tree-app/">Choosing a family tree app</a>
<a href="/en/family-tree-with-photos/">Family tree with photos</a>
<a href="/en/tell-your-family-story/">Telling your family's story</a>
<a href="/en/privacy/">Data and privacy</a>
</nav>
</div>
</footer>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@@ -0,0 +1,208 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#FBFAF7" />
<title>Printable family tree templates, free blank PDFs to fill in</title>
<meta name="description" content="Five free blank family tree templates as A4 PDFs, from 3 to 5 generations, with photo frames or a drawn tree. Free to download, no sign-up." />
<link rel="canonical" href="https://parenthese.io/en/printable-family-tree/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/arbre-genealogique-a-remplir/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/printable-family-tree/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/arbre-genealogique-a-remplir/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://parenthese.io/en/printable-family-tree/" />
<meta property="og:title" content="Printable family tree templates, free blank PDFs to fill in" />
<meta property="og:description" content="Five templates to print on A4, from 3 to 5 generations, with photo frames or a drawn tree." />
<meta property="og:image" content="https://parenthese.io/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300&family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/guides.css" />
<style>
/* Template grid, specific to this page. Tokens from guides.css, with fallback values. */
.modeles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; margin: 24px 0 8px; }
.modele { display: flex; flex-direction: column; border: 1px solid var(--trait, #ebe6df); border-radius: 18px; background: var(--papier, #fff); overflow: hidden; }
.modele .apercu { display: flex; align-items: center; justify-content: center; aspect-ratio: 1 / 1; padding: 22px; background: var(--a50, #fcf3ef); }
.modele .apercu img { display: block; max-width: 100%; max-height: 100%; width: auto; height: auto; background: #fff; box-shadow: 0 1px 2px rgba(42,38,34,.06), 0 8px 22px rgba(42,38,34,.09); }
.modele .corps { display: flex; flex-direction: column; flex: 1; padding: 18px 20px 20px; }
.modele h3 { margin: 0 0 6px; }
.modele p { margin: 0 0 16px; font-size: 16px; }
.modele .bas { margin-top: auto; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }
.modele .poids { font-size: 13px; color: var(--doux, #6b645d); }
@media (max-width: 600px) { .modeles { grid-template-columns: 1fr; } .modele .apercu { aspect-ratio: 4 / 3; padding: 18px; } }
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "HowTo",
"name": "How to fill in a printable family tree",
"inLanguage": "en",
"tool": [{ "@type": "HowToTool", "name": "Blank family tree template, A4 PDF" }],
"step": [
{ "@type": "HowToStep", "name": "Start with yourself", "text": "Fill in box 1 with your birth name and your exact date and place of birth." },
{ "@type": "HowToStep", "name": "Go back one generation at a time", "text": "Parents, then grandparents, without skipping a box. For women, write their maiden name." },
{ "@type": "HowToStep", "name": "Ask the oldest relatives", "text": "Grandparents, great-uncles and great-aunts know what is written nowhere. Family records give the exact dates." },
{ "@type": "HowToStep", "name": "Note what is missing", "text": "Write an approximate date followed by a question mark rather than leaving the box empty, then check it in the archives." }
]
},
{
"@type": "FAQPage",
"mainEntity": [
{ "@type": "Question", "name": "How many generations should a family tree have?", "acceptedAnswer": { "@type": "Answer", "text": "Three for a first tree or a school project, four if you know your great-grandparents, five in a fan chart to go back to your great-great-grandparents. Each generation doubles the number of boxes, so 2, 4, 8, then 16 people." } },
{ "@type": "Question", "name": "How do you make a family tree yourself?", "acceptedAnswer": { "@type": "Answer", "text": "Print a blank template, fill in your own box, then those of your parents and grandparents by asking the family. Family records give the exact dates, and online archives give the older records. In France, that means the livret de famille and the departmental archives." } },
{ "@type": "Question", "name": "Are the family tree templates free?", "acceptedAnswer": { "@type": "Answer", "text": "Yes. All five templates download without sign-up or email address, and you can print and share them as much as you like." } },
{ "@type": "Question", "name": "How do you print a family tree on A3?", "acceptedAnswer": { "@type": "Answer", "text": "Open the PDF, choose A3 in the print dialog and the \"fit to page\" option. The template scales up without losing sharpness, which gives more room to write, especially on the five-generation fan chart." } }
]
}
]
}
</script>
</head>
<body>
<header class="top">
<div class="wrap">
<a class="brand" href="/en/" aria-label="Parenthèse, home">
<img src="/logo.svg" alt="" width="166" height="22" />
</a>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;source=guide-modele&amp;lang=en">Start your tree</a>
</div>
</header>
<main>
<article class="wrap">
<span class="eyebrow">Free templates</span>
<h1>Printable family tree templates, free and blank</h1>
<p class="lead">Five templates to print on A4, from three to five generations. Download the PDF, print it, fill it in by hand with the family. Free, no sign-up.</p>
<h2>The templates to download</h2>
<div class="modeles">
<section class="modele">
<div class="apercu"><img src="/en/printable-family-tree/family-tree-3-generations.webp" width="720" height="1018" alt="Blank family tree template with 3 generations, seven boxes to fill in, from the child to the four grandparents" loading="lazy" decoding="async" /></div>
<div class="corps">
<h3>3 generations</h3>
<p>You, your parents, your four grandparents. The template to start with, with room to write.</p>
<div class="bas">
<a class="btn" href="/en/printable-family-tree/family-tree-3-generations.pdf" download>Download the PDF</a>
<span class="poids">A4 portrait</span>
</div>
</div>
</section>
<section class="modele">
<div class="apercu"><img src="/en/printable-family-tree/family-tree-with-photos.webp" width="720" height="1018" alt="Printable family tree template with a photo frame in each box, over 3 generations" loading="lazy" decoding="async" /></div>
<div class="corps">
<h3>3 generations with photos</h3>
<p>The same seven boxes, each with a frame to glue a passport photo or draw a portrait.</p>
<div class="bas">
<a class="btn" href="/en/printable-family-tree/family-tree-with-photos.pdf" download>Download the PDF</a>
<span class="poids">A4 portrait</span>
</div>
</div>
</section>
<section class="modele">
<div class="apercu"><img src="/en/printable-family-tree/family-tree-4-generations.webp" width="720" height="509" alt="Blank 4-generation family tree template in landscape format, fifteen boxes up to the great-grandparents" loading="lazy" decoding="async" /></div>
<div class="corps">
<h3>4 generations</h3>
<p>Up to the eight great-grandparents, in landscape. Fifteen numbered boxes.</p>
<div class="bas">
<a class="btn" href="/en/printable-family-tree/family-tree-4-generations.pdf" download>Download the PDF</a>
<span class="poids">A4 landscape</span>
</div>
</div>
</section>
<section class="modele">
<div class="apercu"><img src="/en/printable-family-tree/family-tree-5-generation-fan-chart.webp" width="720" height="509" alt="5-generation fan chart family tree template, thirty-one numbered boxes in a half circle" loading="lazy" decoding="async" /></div>
<div class="corps">
<h3>5-generation fan chart</h3>
<p>Thirty-one people on one page, back to the great-great-grandparents. The densest format, to enlarge to A3 if you write big.</p>
<div class="bas">
<a class="btn" href="/en/printable-family-tree/family-tree-5-generation-fan-chart.pdf" download>Download the PDF</a>
<span class="poids">A4 landscape</span>
</div>
</div>
</section>
<section class="modele">
<div class="apercu"><img src="/en/printable-family-tree/family-tree-drawn.webp" width="720" height="1018" alt="Drawing of a family tree to fill in, a trunk and branches connecting seven boxes over 3 generations" loading="lazy" decoding="async" /></div>
<div class="corps">
<h3>Drawn tree, 3 generations</h3>
<p>A trunk and branches connect the boxes. For a tree to hang on the wall, to give as a gift, or to hand in at school.</p>
<div class="bas">
<a class="btn" href="/en/printable-family-tree/family-tree-drawn.pdf" download>Download the PDF</a>
<span class="poids">A4 portrait</span>
</div>
</div>
</section>
</div>
<div class="note">
<p><strong>The numbers in the boxes</strong> follow Ahnentafel numbering, also called Sosa numbering, the same in every family tree. You are 1, your father 2, your mother 3. A person's father has double their number, their mother double plus one.</p>
</div>
<h2>How to fill in a family tree</h2>
<h3>1. Start with yourself</h3>
<p>Fill in box 1 with what you know without looking anything up. Birth name, exact date and place, as they appear on your birth certificate. It is the only box that needs no questions.</p>
<h3>2. Go back one generation at a time</h3>
<p>Your parents, then your grandparents, then theirs. Don't skip a box, each generation helps you find the next. For women, write their maiden name rather than their married name, it is the one that leads to their family.</p>
<h3>3. Ask the oldest relatives first</h3>
<p>Grandparents, great-uncles and great-aunts know what is written nowhere. Bring the printed template, show them the empty boxes, and ask who is missing. Family record books (in France, the <em lang="fr">livret de famille</em>), birth and funeral announcements, and the backs of old photos often give the exact dates.</p>
<h3>4. When a date is missing</h3>
<p>Write what you know, "around 1920" or "before 1945", followed by a question mark. A flagged estimate is better than an empty box, it can be corrected later. For French ancestors, old civil registration records are digitized and free to browse on the website of the departmental archives (<em lang="fr">archives départementales</em>) in most departments. Birth and marriage records there are open to the public after 75 years.</p>
<h3>5. Pencil first</h3>
<p>Fill in a first version in pencil, while the dates get confirmed. Then copy it out neatly on a second print. To print, choose "actual size" in the print dialog, not "fit", so the margins stay intact. The templates are A4. On US Letter paper, which is shorter, choose "fit" instead so nothing gets cut off at the bottom.</p>
<h2>The same thing online, with photos and voices</h2>
<p>A sheet of paper stops at the edge of the page and at whoever has it in front of them. Parenthèse is a free online family tree where each person carries their photos, recordings of their voice, videos and the stories told about them.</p>
<p>Brothers, sisters, uncles, aunts and cousins all have their place, over as many generations as you know. You send a link, the family views the tree without creating an account, and those with the contribution password fill in what is missing. For photos, the guide <a href="/en/family-tree-with-photos/">making a family tree with photos</a> explains how to scan and organize them.</p>
<section class="cta">
<h2>Your tree, online and shared</h2>
<p>An account, a family name, and you invite your relatives with a link.</p>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;source=guide-modele&amp;lang=en">Start your tree</a>
</section>
<h2>Frequently asked questions</h2>
<div class="faq">
<details>
<summary>How many generations should a family tree have?</summary>
<p>Three for a first tree or a school project, four if you know your great-grandparents, five in a fan chart to go back to your great-great-grandparents. Each generation doubles the number of boxes, so 2, 4, 8, then 16 people.</p>
</details>
<details>
<summary>How do you make a family tree yourself?</summary>
<p>Print a blank template, fill in your own box, then those of your parents and grandparents by asking the family. Family records give the exact dates, and online archives give the older records. In France, that means the <em lang="fr">livret de famille</em> and the departmental archives.</p>
</details>
<details>
<summary>Are the family tree templates free?</summary>
<p>Yes. All five templates download without sign-up or email address, and you can print and share them as much as you like.</p>
</details>
<details>
<summary>How do you print a family tree on A3?</summary>
<p>Open the PDF, choose A3 in the print dialog and the "fit to page" option. The template scales up without losing sharpness, which gives more room to write, especially on the five-generation fan chart.</p>
</details>
</div>
</article>
</main>
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/en/">parenthese.io</a> · <a href="/arbre-genealogique-a-remplir/" hreflang="fr" lang="fr">Français</a></span>
<nav aria-label="Guides"><a href="/en/how-to-make-a-family-tree/">How to make a family tree</a> <a href="/en/printable-family-tree/">Printable family tree</a> <a href="/en/family-tree-app/">Choosing a family tree app</a> <a href="/en/family-tree-with-photos/">Family tree with photos</a> <a href="/en/tell-your-family-story/">Telling your family's story</a> <a href="/en/privacy/">Data and privacy</a></nav>
</div>
</footer>
</body>
</html>
+133
View File
@@ -0,0 +1,133 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#FBFAF7" />
<title>Data and privacy, what Parenthèse stores and why</title>
<meta name="description" content="What Parenthèse stores when you create an account and a family tree, who can see it, where it is hosted, what is measured, and how to export or delete your data." />
<link rel="canonical" href="https://parenthese.io/en/privacy/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/donnees-et-vie-privee/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/privacy/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/donnees-et-vie-privee/" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://parenthese.io/en/privacy/" />
<meta property="og:title" content="Data and privacy, what Parenthèse stores and why" />
<meta property="og:description" content="What Parenthèse stores, who can see it, where it is hosted, and how to export or delete your data." />
<meta property="og:image" content="https://parenthese.io/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300&family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/guides.css" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebPage",
"name": "Data and privacy",
"url": "https://parenthese.io/en/privacy/",
"inLanguage": "en-US",
"dateModified": "2026-09-14",
"description": "What Parenthèse stores, who can see it, where it is hosted, and how to export or delete your data.",
"isPartOf": { "@type": "WebSite", "name": "Parenthèse", "url": "https://parenthese.io/en/" },
"publisher": { "@type": "Person", "name": "Ilies Allali", "email": "pro.allali.ilies@gmail.com" }
}
</script>
</head>
<body>
<header class="top">
<div class="wrap">
<a class="brand" href="/en/" aria-label="Parenthèse, home">
<img src="/logo.svg" alt="" width="166" height="22" />
</a>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;lang=en&amp;source=page-vie-privee">Start your tree</a>
</div>
</header>
<main>
<article class="wrap">
<span class="eyebrow">Data and privacy</span>
<h1>Your data, in plain words</h1>
<p class="lead">Parenthèse is free, has no ads, and sells nothing. This page explains what the app stores, why, who can see it, and how to get your data back or erase it. It is written from the code, not from a privacy policy template.</p>
<h2>Who is responsible</h2>
<p>Ilies Allali, who designs and hosts Parenthèse. For any question or request about your data, just send an email to <a href="mailto:pro.allali.ilies@gmail.com">pro.allali.ilies@gmail.com</a>.</p>
<h2>What Parenthèse stores</h2>
<p><strong>Your account.</strong> Your email address and your password, stored as a hash (bcrypt), so no one can read it back, including me. The date the account was created and the last tree you opened, to take you back to it when you log in. The first name asked for at sign-up is not sent to the server, it stays in your browser.</p>
<p><strong>Your trees.</strong> The name, the description, the sharing address, the settings, and the two access passwords (visitor and contributor), which are also hashed.</p>
<p><strong>The people.</strong> What you enter for each of them (first name, last name, birth name, dates and places of birth and death, occupation, region, nationality, sex, notes, portrait). And the unions and parent-child links that connect them.</p>
<p><strong>The media.</strong> Photos, videos, audio recordings, documents, GPS tracks, quotes and YouTube links attached to a person, with their caption and source. A photo can be up to 5 MB, any other file up to 20 MB. On top of that come the annotations placed on the tree itself, such as text, drawings, stickers and photos.</p>
<p><strong>Contributions.</strong> When someone suggests a change, Parenthèse keeps the suggestion, the state before and after, who submitted it (a member's email address, or “Contributor” for access by password) and the decision made.</p>
<p><strong>The tree's log.</strong> Every creation, change and deletion is dated and attributed to an account or to an access by password. The owner can view it. It is there to know who changed what.</p>
<p><strong>Visits.</strong> Each time a tree is opened, it is recorded with the date, the type of device (phone, tablet or computer), the account if there is one, and the first name if the person gave it when opening the tree. The IP address is not kept. Only a fingerprint that cannot be reversed is used to count distinct visitors. The owner of the tree can see these visits. They are erased after one year.</p>
<p><strong>Technical logs.</strong> Like any web server, the Parenthèse server records the requests it receives (IP address, page requested, errors) to run and troubleshoot the service.</p>
<h2>Why</h2>
<p>To make the tree work, and nothing else. No profiling, no advertising, no reselling, no sharing with third parties other than the two technical service providers named on this page. Viewing a shared tree does not require an account, the link and a password are enough.</p>
<h2>Who can see what</h2>
<p>A tree is never public. The app blocks search engines from indexing it, and none of its content is visible without the link and a password.</p>
<ul>
<li><strong>The owner</strong>, the account that created the tree, sees and edits everything. They set the passwords, approve contributions, view the log and the visits, and export and delete the tree.</li>
<li><strong>A contributor</strong> has received the link and the contributor password. They can view everything and suggest changes. By default, those changes wait for the owner's approval before they appear.</li>
<li><strong>A visitor</strong> has received the link and the visitor password. They can view, without changing anything.</li>
</ul>
<div class="note">
<p><strong>One detail.</strong> Even before typing the password, the person who opens the link sees the tree's name and its description, nothing else, and nothing about the owner. So don't put anything in the description that you don't want to show to whoever has the link.</p>
</div>
<p>An access password opens a 24-hour session. An account session lasts 7 days, or less if you log out.</p>
<h2>Where it is hosted, and for how long</h2>
<p>On a server rented from Hostinger, which I manage. The database (PostgreSQL) and the media files are stored there. The files sit in a folder outside the web, and are only served to someone with a valid access session for the tree. Traffic between you and the site and the app goes over HTTPS.</p>
<p>Backups of the database and the media are kept for 14 days, then deleted. Data you erase in the app can therefore still exist in a backup for two weeks.</p>
<p>Your data is kept for as long as your account exists.</p>
<h2>Audience measurement</h2>
<p>Parenthèse uses PostHog to count visits and see what gets used. PostHog is hosted in the United States, and the usage data described here is sent there.</p>
<p>Here is what is measured, and nothing more. On the website, page views, scrolling, clicks on the “Start your tree” buttons, with where they came from (previous page, mobile or computer). In the app, opening the account screen, creating an account or a tree, and for shared trees, opening them, the time spent and the type of content viewed (text, photo, video), with the role, visitor or contributor. The tree is identified there by a scrambled code, never by its name.</p>
<p>There is no automatic capture of clicks or pages. No tree content (name, person, photo) is sent. When you are logged in to your account, a technical account identifier (never your email address) links your visits together. A cookie is set on parenthese.io and its subdomains to recognize the same visit across the site and the app.</p>
<h2>Your rights</h2>
<ul>
<li><strong>View.</strong> Everything Parenthèse knows about your tree is in the app.</li>
<li><strong>Export.</strong> Tree settings, Data section, “Download .ged” button. GEDCOM is a standard file format that other family tree software can read. It contains the people and their links, not the media files.</li>
<li><strong>Delete a tree.</strong> Tree settings, Advanced tab, “Delete this tree”. The tree disappears right away for everyone, the owner included. It is permanently erased (people, links, media, contributions and log) from the database as well as from the disk. Only the backups still hold it, for 14 days at most.</li>
<li><strong>Delete your account.</strong> “My account” screen, “Delete my account” button, then your password to confirm. Your account and the trees you created are permanently erased, along with their media. Other families' trees that you had access to stay with their owners. Your contributions to them are kept, but your email address is removed from them and replaced with “Contributor”. All your sessions are closed, on all your devices.</li>
<li><strong>Waiting list.</strong> It is closed. If you signed up before the launch, your email, your first name and the page you signed up from are still stored in the database and at Resend, the service provider that sent the confirmation. Just send an email to have them removed.</li>
<li><strong>Complaints.</strong> If you believe your rights are not being respected, you can file a complaint with the <a href="https://www.cnil.fr/" rel="noopener">CNIL</a>, France's data protection authority.</li>
</ul>
<h2>Keeping your data at home</h2>
<p>The code of Parenthèse is public, under the PolyForm Noncommercial 1.0.0 license. A family that would rather not entrust anything to anyone can install Parenthèse on its own server. It then has everything (database, files and backups) without going through me. The code and the instructions are on <a href="https://github.com/IliesAllali/parenthese">github.com/IliesAllali/parenthese</a>.</p>
<h2>Last updated</h2>
<p>September 14, 2026. This page changes when the code changes.</p>
<section class="cta">
<h2>A tree your family views through a link</h2>
<p>One account, one family name, two passwords. You stay in control of who sees what.</p>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;lang=en&amp;source=page-vie-privee">Start your tree</a>
</section>
</article>
</main>
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/en/">parenthese.io</a> · <a href="/donnees-et-vie-privee/" hreflang="fr" lang="fr">Français</a></span>
<nav aria-label="Guides">
<a href="/en/how-to-make-a-family-tree/">How to make a family tree</a>
<a href="/en/printable-family-tree/">Printable family tree</a>
<a href="/en/family-tree-app/">Choosing a family tree app</a>
<a href="/en/family-tree-with-photos/">Family tree with photos</a>
<a href="/en/tell-your-family-story/">Telling your family's story</a>
<a href="/en/privacy/">Data and privacy</a>
</nav>
</div>
</footer>
</body>
</html>
@@ -0,0 +1,139 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#FBFAF7" />
<title>How to tell your family story, where to start</title>
<meta name="description" content="Tell your family history without being a writer. Who to start with, the questions that get people talking, how to record them, and where to keep it all so it gets passed down." />
<link rel="canonical" href="https://parenthese.io/en/tell-your-family-story/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/raconter-histoire-de-famille/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/tell-your-family-story/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/raconter-histoire-de-famille/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://parenthese.io/en/tell-your-family-story/" />
<meta property="og:title" content="How to tell your family story" />
<meta property="og:description" content="Who to start with, the questions that get people talking, how to record them, and where to keep it all so it gets passed down." />
<meta property="og:image" content="https://parenthese.io/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300&family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/guides.css" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Article",
"headline": "How to tell your family story",
"inLanguage": "en",
"datePublished": "2026-09-29",
"dateModified": "2026-09-29",
"author": { "@type": "Person", "name": "Ilies Allali", "url": "https://iliesallali.design/" },
"publisher": { "@id": "https://parenthese.io/#organization" },
"mainEntityOfPage": "https://parenthese.io/en/tell-your-family-story/"
},
{
"@type": "FAQPage",
"mainEntity": [
{ "@type": "Question", "name": "How do you learn your family history?", "acceptedAnswer": { "@type": "Answer", "text": "By asking the oldest members of the family while they are still here, with concrete questions about their childhood, their parents and the places they lived, by recording their answers, then by gathering what you learn with the family photos and papers in one place the whole family can open." } },
{ "@type": "Question", "name": "Who should you start with to tell your family story?", "acceptedAnswer": { "@type": "Answer", "text": "With the oldest person who still wants to talk, and with what they lived through themselves, not with distant ancestors. Firsthand memories disappear with them, the archives will wait." } },
{ "@type": "Question", "name": "Do you need to write a book to tell your family story?", "acceptedAnswer": { "@type": "Answer", "text": "No. A book is a fine result but it freezes everything and takes months. A living tree, where each person carries their photos, their voice and their stories, takes an hour to start and grows as the family contributes." } }
]
}
]
}
</script>
</head>
<body>
<header class="top">
<div class="wrap">
<a class="brand" href="/en/" aria-label="Parenthèse, home">
<img src="/logo.svg" alt="" width="166" height="22" />
</a>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;source=guide-histoire&amp;lang=en">Start your tree</a>
</div>
</header>
<main>
<article class="wrap">
<span class="eyebrow">Guide</span>
<h1>How to tell your family story</h1>
<p class="lead">You don't need to be a writer or a genealogist. You need one person who still remembers, another who asks the questions, and a place where what gets said is not lost.</p>
<h2>What "telling your family story" means</h2>
<p>It is not the list of births and marriages, it is what the archives don't hold. How two people met, why a family left a village, what a grandfather did with his Sundays, the phrase a grandmother kept repeating. None of this is written down anywhere. It lives in three or four heads, and it leaves with them.</p>
<h2>Who to start with</h2>
<p>With the oldest person who still wants to talk. Not with ancestors from the 18th century, the archives are waiting for them and will not move. Firsthand memories have an expiry date nobody knows.</p>
<p>Start with what they lived through themselves, not with what they know about their own grandparents. People tell best what they saw.</p>
<h2>The questions that get people talking</h2>
<p>Broad questions ("tell me about your life") shut people down. Concrete questions open them up. Here are a few that work every time.</p>
<ul>
<li>How did your parents meet?</li>
<li>What was the house you grew up in like? Who slept where?</li>
<li>What did you eat on Sundays?</li>
<li>What is the first world event you remember?</li>
<li>What did your parents never tell you that you understood later?</li>
<li>What are you proudest of?</li>
<li>What would you like your grandchildren to know about you?</li>
</ul>
<p>One question, then silence. Don't fill the gaps, that is where the real answers come.</p>
<h2>Record instead of writing</h2>
<p>Taking notes while someone talks breaks the conversation. Put a phone on the table, start an audio recording, and listen. Three minutes of voice are worth pages. The tone, the accent, the pauses, the laugh in the middle of a sentence. That is what the grandchildren will want to hear.</p>
<p>Video if the person is comfortable with it, otherwise audio is enough and is forgotten faster.</p>
<h2>Bring out the photos while you talk</h2>
<p>A photo triggers memories no question can reach. Take the box of photos with you and ask for the names of the faces, the places, the years. Write them down right away, on the scanned photo or next to it. A photo whose names nobody remembers is lost within a generation.</p>
<h2>Where to keep what you collect</h2>
<p>This is where most projects die. The recordings stay on a phone, the notes in a notebook, the photos in a folder. There are three formats for bringing it all together.</p>
<p><strong>The life story or family book.</strong> A fine result, often made with the help of a biographer. It freezes everything at the moment of printing, and it takes months.</p>
<p><strong>The classic family tree.</strong> It puts names and dates in order, it does not carry the voice.</p>
<p><strong>The living tree.</strong> Each person in the family carries their photos, recordings, videos and stories. It takes an hour to start, you add to it each time you learn something, and the whole family contributes through a link. This is what Parenthèse does, a tree anyone can view without an account, where memories surround each portrait.</p>
<div class="note">
<p><strong>The right order.</strong> The living tree first, because it collects. The book later, if one day you want to give it as a gift. Each one feeds the other.</p>
</div>
<h2>Get the family to contribute</h2>
<p>One person collecting on their own stops at what they know. Send the link to the tree. A cousin adds the missing photo, an aunt corrects a date, a nephew records his grandfather on his side. In Parenthèse, the family views the tree without an account and contributes with a password. You approve what goes into the tree, or you let it go straight in.</p>
<h2>Frequently asked questions</h2>
<div class="faq">
<details>
<summary>How do you learn your family history?</summary>
<p>By asking the oldest members of the family while they are still here, with concrete questions, by recording their answers, then by gathering what you learn with the family photos and papers in one place the whole family can open.</p>
</details>
<details>
<summary>Who should you start with?</summary>
<p>With the oldest person who still wants to talk, and with what they lived through themselves. The archives will wait, firsthand memories won't.</p>
</details>
<details>
<summary>Do you need to write a book?</summary>
<p>No. A book is a fine result, but it freezes everything and takes months. A living tree takes an hour to start and grows as the family contributes. The book can come later, from what the tree has collected.</p>
</details>
</div>
<section class="cta">
<h2>Start with a voice</h2>
<p>An account, a family name, a first recording. The rest comes with the family.</p>
<a class="btn" href="https://app.parenthese.io/?account=register&amp;source=guide-histoire&amp;lang=en">Start your tree</a>
</section>
</article>
</main>
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/en/">parenthese.io</a> · <a href="/raconter-histoire-de-famille/" hreflang="fr" lang="fr">Français</a></span>
<nav aria-label="Guides"><a href="/en/how-to-make-a-family-tree/">How to make a family tree</a> <a href="/en/printable-family-tree/">Printable family tree</a> <a href="/en/family-tree-app/">Choosing a family tree app</a> <a href="/en/family-tree-with-photos/">Family tree with photos</a> <a href="/en/tell-your-family-story/">Telling your family's story</a> <a href="/en/privacy/">Data and privacy</a></nav>
</div>
</footer>
</body>
</html>
@@ -7,6 +7,9 @@
<title>Comment raconter l'histoire de sa famille, par où commencer</title>
<meta name="description" content="Raconter l'histoire de sa famille sans être écrivain. Par qui commencer, les questions qui font parler, comment enregistrer, et où garder le tout pour que ça se transmette." />
<link rel="canonical" href="https://parenthese.io/raconter-histoire-de-famille/" />
<link rel="alternate" hreflang="fr" href="https://parenthese.io/raconter-histoire-de-famille/" />
<link rel="alternate" hreflang="en" href="https://parenthese.io/en/tell-your-family-story/" />
<link rel="alternate" hreflang="x-default" href="https://parenthese.io/raconter-histoire-de-famille/" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Parenthèse" />
<meta property="og:locale" content="fr_FR" />
@@ -128,7 +131,7 @@
<footer>
<div class="wrap">
<span>Parenthèse · <a href="/">parenthese.io</a></span>
<span>Parenthèse · <a href="/">parenthese.io</a> · <a href="/en/tell-your-family-story/" hreflang="en" lang="en">English</a></span>
<nav aria-label="Guides">
<a href="/comment-faire-un-arbre-genealogique/">Comment faire un arbre généalogique</a>
<a href="/arbre-genealogique-a-remplir/">Arbre généalogique à remplir</a>
+54
View File
@@ -6,6 +6,12 @@
<changefreq>monthly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://parenthese.io/en/</loc>
<lastmod>2026-09-29</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://parenthese.io/comment-faire-un-arbre-genealogique/</loc>
<lastmod>2026-09-25</lastmod>
@@ -54,4 +60,52 @@
<changefreq>monthly</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://parenthese.io/en/how-to-make-a-family-tree/</loc>
<lastmod>2026-09-29</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://parenthese.io/en/family-tree-app/</loc>
<lastmod>2026-09-29</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://parenthese.io/en/family-tree-with-photos/</loc>
<lastmod>2026-09-29</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://parenthese.io/en/family-reunion/</loc>
<lastmod>2026-09-29</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://parenthese.io/en/printable-family-tree/</loc>
<lastmod>2026-09-29</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://parenthese.io/en/tell-your-family-story/</loc>
<lastmod>2026-09-29</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://parenthese.io/en/privacy/</loc>
<lastmod>2026-09-29</lastmod>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
<url>
<loc>https://parenthese.io/en/help/</loc>
<lastmod>2026-09-29</lastmod>
<changefreq>monthly</changefreq>
<priority>0.6</priority>
</url>
</urlset>
+31
View File
@@ -0,0 +1,31 @@
// Réécrit les balises de langue du <head> de index.html (écrit en français) pour une autre langue :
// lang, title, description, canonical, Open Graph, Twitter et JSON-LD. Utilisé par scripts/prerender.mjs.
// Chaque remplacement doit trouver sa cible, sinon erreur : un head à moitié traduit ne part pas en prod.
const escapeAttr = (value) => value.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;')
const escapeText = (value) => value.replace(/&/g, '&amp;').replace(/</g, '&lt;')
const escapeJson = (value) => JSON.stringify(value).slice(1, -1)
export function localizeHead(html, meta) {
const rules = [
[/<html lang="[^"]*">/, `<html lang="${meta.lang}">`],
[/<title>[^<]*<\/title>/, `<title>${escapeText(meta.title)}</title>`],
[/(<meta name="description" content=")[^"]*(")/, `$1${escapeAttr(meta.description)}$2`],
[/(<link rel="canonical" href=")[^"]*(")/, `$1${meta.url}$2`],
[/(<meta property="og:locale"\s+content=")[^"]*(")/, `$1${meta.ogLocale}$2`],
[/(<meta property="og:url"\s+content=")[^"]*(")/, `$1${meta.url}$2`],
[/(<meta property="og:title"\s+content=")[^"]*(")/, `$1${escapeAttr(meta.title)}$2`],
[/(<meta property="og:description"\s+content=")[^"]*(")/, `$1${escapeAttr(meta.socialDescription)}$2`],
[/(<meta property="og:image:alt"\s+content=")[^"]*(")/, `$1${escapeAttr(meta.imageAlt)}$2`],
[/(<meta name="twitter:title"\s+content=")[^"]*(")/, `$1${escapeAttr(meta.title)}$2`],
[/(<meta name="twitter:description"\s+content=")[^"]*(")/, `$1${escapeAttr(meta.socialDescription)}$2`],
[/("inLanguage": ")[^"]*(")/g, `$1${meta.schemaLanguage}$2`],
[/("applicationCategory"[\s\S]*?"description": ")[^"]*(")/, `$1${escapeJson(meta.appDescription)}$2`],
]
return rules.reduce((out, [pattern, replacement]) => {
if (!pattern.test(out)) throw new Error(`Balise introuvable dans le head : ${pattern}`)
pattern.lastIndex = 0
return out.replace(pattern, replacement)
}, html)
}
+21 -8
View File
@@ -1,21 +1,34 @@
// Injecte le HTML de la landing, rendu par React à la compilation, dans dist/index.html.
// Injecte le HTML de la landing, rendu par React à la compilation, dans dist/index.html (français)
// et dist/en/index.html (anglais, head réécrit par localize-head.mjs).
// Lancé par `npm run build` après le build client (dist/) et le build SSR (dist-ssr/).
import { readFile, rm, writeFile } from 'node:fs/promises'
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
import { fileURLToPath, pathToFileURL } from 'node:url'
import { COPY } from '../src/i18n.js'
import { localizeHead } from './localize-head.mjs'
const root = fileURLToPath(new URL('..', import.meta.url))
const indexPath = `${root}dist/index.html`
const ssrDir = `${root}dist-ssr`
const MARKER = '<div id="root"></div>'
const { render } = await import(pathToFileURL(`${ssrDir}/entry-server.js`).href)
const appHtml = render()
if (!appHtml || !appHtml.includes('<h1')) throw new Error('Prérendu vide ou sans H1')
// Langue -> fichier de sortie. Le français garde le head de index.html tel quel.
const PAGES = [
{ locale: 'fr', out: indexPath },
{ locale: 'en', out: `${root}dist/en/index.html`, dir: `${root}dist/en` },
]
const { render } = await import(pathToFileURL(`${ssrDir}/entry-server.js`).href)
const template = await readFile(indexPath, 'utf8')
if (!template.includes(MARKER)) throw new Error(`${MARKER} introuvable dans dist/index.html`)
await writeFile(indexPath, template.replace(MARKER, `<div id="root">${appHtml}</div>`))
await rm(ssrDir, { recursive: true, force: true })
for (const { locale, out, dir } of PAGES) {
const appHtml = render(locale)
if (!appHtml || !appHtml.includes('<h1')) throw new Error(`Prérendu ${locale} vide ou sans H1`)
console.log(`Prérendu injecté dans dist/index.html (${Math.round(appHtml.length / 1024)} Ko de HTML)`)
const head = locale === 'fr' ? template : localizeHead(template, COPY[locale].meta)
if (dir) await mkdir(dir, { recursive: true })
await writeFile(out, head.replace(MARKER, `<div id="root">${appHtml}</div>`))
console.log(`Prérendu ${locale} injecté dans ${out.slice(root.length)} (${Math.round(appHtml.length / 1024)} Ko de HTML)`)
}
await rm(ssrDir, { recursive: true, force: true })
+78 -111
View File
@@ -3,6 +3,7 @@ import { analytics } from './analytics.js'
import { getEntranceProgress, seededFloat } from './heroGraphMath.js'
import PzMark from './PzMark.jsx'
import LogoLockup from './LogoLockup.jsx'
import { COPY, withAppQuery } from './i18n.js'
// ─── Design atoms ─────────────────────────────────────────────────────────────
@@ -18,7 +19,7 @@ const WAVE = [38, 62, 48, 80, 56, 92, 70, 44, 66, 86, 52, 74, 40, 60, 90, 58, 46
// ─── Mini graphe hero (noeuds interactifs) ───────────────────────────────────
function HeroGraph({ className = '' }) {
function HeroGraph({ className = '', label }) {
const canvasRef = useRef(null)
const containerRef = useRef(null)
@@ -760,7 +761,7 @@ function HeroGraph({ className = '' }) {
<canvas
ref={canvasRef}
className="block w-full h-[40svh] sm:h-[clamp(420px,92vw,560px)] lg:h-[clamp(480px,36vw,560px)]"
aria-label="Arbre de famille animé"
aria-label={label}
/>
</div>
)
@@ -768,17 +769,17 @@ function HeroGraph({ className = '' }) {
// ─── Header ───────────────────────────────────────────────────────────────────
function Header({ onCta, elevated }) {
function Header({ t, onCta, elevated }) {
return (
<header className={`site-nav${elevated ? ' is-elevated' : ''}`}>
<div className="wrap nav-in">
<a href="/" aria-label="Parenthèse, accueil"><LogoLockup height={22} /></a>
<a href={t.home} aria-label={t.logoHome}><LogoLockup height={22} /></a>
<nav aria-label="Sections">
<a href="#comment">Comment ça marche</a>
<a href="#demo">Un exemple</a>
<a href="/donnees-et-vie-privee/">Vie privée</a>
<a href="#comment">{t.nav.how}</a>
<a href="#demo">{t.nav.demo}</a>
{t.nav.privacy && <a href={t.privacyHref}>{t.nav.privacy}</a>}
</nav>
<button type="button" onClick={onCta} className="btn p sm">Créer mon arbre</button>
<button type="button" onClick={onCta} className="btn p sm">{t.cta}</button>
</div>
</header>
)
@@ -786,7 +787,7 @@ function Header({ onCta, elevated }) {
// ─── Démo inline ──────────────────────────────────────────────────────────────
function InlineDemo() {
function InlineDemo({ t, locale }) {
const [active, setActive] = useState(false)
const [loaded, setLoaded] = useState(false)
const [shouldLoad, setShouldLoad] = useState(false)
@@ -826,9 +827,9 @@ function InlineDemo() {
<section id="demo" ref={sectionRef} className="sec sec-demo">
<div className="wrap sec-in">
<div className="head c" data-reveal>
<span className="eyebrow">Un exemple</span>
<h2 className="t-d2">Un arbre généalogique <em className="s">avec photos, à explorer</em></h2>
<p className="lede">Cliquez sur un visage pour ouvrir sa fiche. C'est un arbre de démonstration, sans compte à créer.</p>
<span className="eyebrow">{t.demo.eyebrow}</span>
<h2 className="t-d2">{t.demo.title[0]}<em className="s">{t.demo.title[1]}</em></h2>
<p className="lede">{t.demo.lede}</p>
</div>
<div className="demo-frame" data-reveal>
@@ -841,13 +842,13 @@ function InlineDemo() {
{!loaded && (
<div className="demo-wait" role="status">
<PzMark state={shouldLoad ? 'loading' : 'rest'} />
<span className={shouldLoad ? 'sr-only' : undefined}>{shouldLoad ? 'Chargement de la démo' : 'Démo interactive'}</span>
<span className={shouldLoad ? 'sr-only' : undefined}>{shouldLoad ? t.demo.loading : t.demo.idle}</span>
</div>
)}
<iframe
src={shouldLoad ? 'https://app.parenthese.io/?embed' : undefined}
title="Démo Parenthèse"
src={shouldLoad ? withAppQuery('https://app.parenthese.io/?embed', locale) : undefined}
title={t.demo.frameTitle}
loading="lazy"
className="w-full h-full border-0"
sandbox="allow-scripts allow-same-origin"
@@ -870,9 +871,9 @@ function InlineDemo() {
onClick={() => setActive(true)}
onKeyDown={(e) => e.key === 'Enter' && setActive(true)}
className="demo-enter"
aria-label="Entrer dans la démo"
aria-label={t.demo.enter}
>
<span className="btn w">Entrer dans la démo</span>
<span className="btn w">{t.demo.enter}</span>
</div>
)}
</div>
@@ -887,42 +888,11 @@ function InlineDemo() {
// Les CTA mènent à la création de compte dans l'app
const APP_SIGNUP_URL = 'https://app.parenthese.io/?account=register&source=landing'
const GUIDES = [
{
href: '/comment-faire-un-arbre-genealogique/',
title: 'Comment faire un arbre généalogique',
text: "Partir de soi, interroger les aînés, trouver les actes gratuitement en mairie et aux archives, puis faire compléter la famille.",
},
{
href: '/application-arbre-genealogique/',
title: "Quelle application d'arbre généalogique choisir ?",
text: 'Geneanet, MyHeritage, Filae, FamilySearch, Parenthèse. Rechercher des ancêtres et garder une mémoire vivante ne sont pas le même besoin.',
},
{
href: '/arbre-genealogique-avec-photos/',
title: 'Faire un arbre généalogique avec des photos',
text: 'Rassembler, numériser avec un téléphone, nommer et dater, puis ajouter les vidéos et les voix.',
},
{
href: '/cousinade/',
title: 'Organiser une cousinade',
text: 'Retrouver toutes les branches, fixer la date, collecter les souvenirs le jour même, et garder une trace que tout le monde retrouve.',
},
{
href: '/raconter-histoire-de-famille/',
title: "Raconter l'histoire de sa famille",
text: "Par qui commencer, les questions qui font parler, enregistrer plutôt qu'écrire, et où garder ce qu'on a recueilli.",
},
{
href: '/arbre-genealogique-a-remplir/',
title: 'Arbre généalogique à remplir',
text: "Cinq modèles vierges à imprimer en PDF, de trois à cinq générations, avec cases photo ou arbre dessiné. Et comment les remplir.",
},
]
const readSource = () => new URLSearchParams(window.location.search).get('source') || 'direct'
export default function App() {
export default function App({ locale = 'fr' }) {
const t = COPY[locale]
const [headerElevated, setHeaderElevated] = useState(false)
const [sharedReturnUrl, setSharedReturnUrl] = useState('')
const scrollMilestonesRef = useRef({ half: false, full: false })
@@ -936,6 +906,7 @@ export default function App() {
source: readSource(),
referrer: document.referrer || 'none',
viewport: window.innerWidth < 768 ? 'mobile' : 'desktop',
lang: locale,
...extra,
})
@@ -1008,51 +979,46 @@ export default function App() {
const goToSignup = (placement = 'hero') => {
analytics.capture('hero_cta_clicked', buildEventProps({ placement }))
analytics.capture('signup_cta_clicked', buildEventProps({ placement }))
window.location.assign(APP_SIGNUP_URL)
window.location.assign(withAppQuery(APP_SIGNUP_URL, locale))
}
return (
<div className="min-h-screen">
<Header onCta={() => goToSignup('header')} elevated={headerElevated} />
<Header t={t} onCta={() => goToSignup('header')} elevated={headerElevated} />
<main>
{/* ─── HERO ────────────────────────────────────────────────────── */}
<section className="hero">
<div className="wrap hero-in">
<HeroGraph className="order-1 lg:order-2" />
<HeroGraph className="order-1 lg:order-2" label={t.heroCanvas} />
<div className="hero-txt order-2 lg:order-1">
<span className="pill rise"><i />Arbre généalogique gratuit, en ligne</span>
<span className="pill rise"><i />{t.hero.pill}</span>
<h1 className="t-d1 rise" style={{ animationDelay: '80ms' }}>
L'histoire de votre famille, racontée par ceux qui <em className="s">l'ont vécue</em>
{t.hero.title[0]}<em className="s">{t.hero.title[1]}</em>
</h1>
<p className="lede rise" style={{ animationDelay: '160ms' }}>
{source === 'app-shared'
? "Vous venez de découvrir Parenthèse à travers le lien d'une famille. Créez la vôtre en quelques minutes."
: "Créez l'arbre généalogique de votre famille en ligne, avec des photos, des voix et des souvenirs. Un lien suffit pour que toute la famille le consulte."}
{source === 'app-shared' ? t.hero.ledeShared : t.hero.lede}
</p>
<div className="ctas rise" style={{ animationDelay: '240ms' }}>
<button type="button" onClick={() => goToSignup('hero')} className="btn p">Créer mon arbre</button>
<a href="#demo" className="btn s">Voir un arbre</a>
<button type="button" onClick={() => goToSignup('hero')} className="btn p">{t.cta}</button>
<a href="#demo" className="btn s">{t.hero.secondary}</a>
</div>
</div>
</div>
</section>
<div className="trust">
<span>Gratuit, et le restera</span>
<span>Lecture par lien, sans compte</span>
<span>Code ouvert</span>
<span>Vos données restent les vôtres</span>
{t.trust.map((item) => <span key={item}>{item}</span>)}
</div>
{/* ─── COMMENT ÇA MARCHE ─────────────────────────────────────── */}
<section id="comment" className="sec">
<div className="wrap sec-in">
<div className="head c" data-reveal>
<span className="eyebrow">Comment ça marche</span>
<h2 className="t-d2">Créer un arbre généalogique, <em className="s">en trois gestes</em></h2>
<span className="eyebrow">{t.how.eyebrow}</span>
<h2 className="t-d2">{t.how.title[0]}<em className="s">{t.how.title[1]}</em></h2>
</div>
<div className="steps" data-reveal>
<div className="card step">
@@ -1064,8 +1030,8 @@ export default function App() {
<span className="yr">1941</span>
</div>
</div>
<h3 className="t-h3">Ajoutez un visage</h3>
<p className="t-small">Un prénom, une photo si vous en avez une. Le reste peut attendre.</p>
<h3 className="t-h3">{t.how.steps[0].title}</h3>
<p className="t-small">{t.how.steps[0].text}</p>
</div>
<div className="card step">
<span className="num">2</span>
@@ -1078,76 +1044,76 @@ export default function App() {
<span>1:42</span>
</div>
</div>
<h3 className="t-h3">Racontez</h3>
<p className="t-small">Une anecdote, une photo de vacances, sa voix au téléphone. Chacun ajoute ce qu'il sait.</p>
<h3 className="t-h3">{t.how.steps[1].title}</h3>
<p className="t-small">{t.how.steps[1].text}</p>
</div>
<div className="card step">
<span className="num">3</span>
<div className="vis">
<div className="toast"><b style={{ backgroundImage: 'url(/hero/photos/marc-56.webp)' }} />Marc a ouvert l'arbre</div>
<div className="toast"><b style={{ backgroundImage: 'url(/hero/photos/marc-56.webp)' }} />{t.how.toast}</div>
</div>
<h3 className="t-h3">Partagez le lien</h3>
<p className="t-small">La famille ouvre l'arbre depuis un message. Pas de compte, pas d'appli à installer.</p>
<h3 className="t-h3">{t.how.steps[2].title}</h3>
<p className="t-small">{t.how.steps[2].text}</p>
</div>
</div>
</div>
</section>
{/* ─── DÉMO INLINE ────────────────────────────────────────────── */}
<InlineDemo />
<InlineDemo t={t} locale={locale} />
{/* ─── POUR QUI ───────────────────────────────────────────────── */}
<section className="sec">
<div className="wrap sec-in">
<div className="quote" data-reveal>
<div className="head">
<span className="eyebrow">Pour qui</span>
<h2 className="t-d2">Du petit-fils de 8 ans <em className="s">à la grand-mère de 80</em></h2>
<p className="lede">Parenthèse se lit comme un album de famille. On reconnaît un visage, on clique, on écoute.</p>
<span className="eyebrow">{t.who.eyebrow}</span>
<h2 className="t-d2">{t.who.title[0]}<em className="s">{t.who.title[1]}</em></h2>
<p className="lede">{t.who.lede}</p>
</div>
<div className="gens" aria-hidden="true">
<figure><div className="ph" style={{ '--s': 74, backgroundImage: 'url(/hero/photos/lya-14.webp)' }} /><figcaption>Lya, 14 ans</figcaption></figure>
<figure><div className="ph" style={{ '--s': 96, backgroundImage: 'url(/hero/photos/women-44.webp)' }} /><figcaption>Camille, 39 ans</figcaption></figure>
<figure><div className="ph" style={{ '--s': 118, backgroundImage: 'url(/hero/photos/marc-56.webp)' }} /><figcaption>Marc, 56 ans</figcaption></figure>
<figure><div className="ph" style={{ '--s': 140, backgroundImage: 'url(/hero/photos/jeanne-85.webp)' }} /><figcaption>Jeanne, 85 ans</figcaption></figure>
<figure><div className="ph" style={{ '--s': 74, backgroundImage: 'url(/hero/photos/lya-14.webp)' }} /><figcaption>{t.who.captions[0]}</figcaption></figure>
<figure><div className="ph" style={{ '--s': 96, backgroundImage: 'url(/hero/photos/women-44.webp)' }} /><figcaption>{t.who.captions[1]}</figcaption></figure>
<figure><div className="ph" style={{ '--s': 118, backgroundImage: 'url(/hero/photos/marc-56.webp)' }} /><figcaption>{t.who.captions[2]}</figcaption></figure>
<figure><div className="ph" style={{ '--s': 140, backgroundImage: 'url(/hero/photos/jeanne-85.webp)' }} /><figcaption>{t.who.captions[3]}</figcaption></figure>
</div>
</div>
<div className="promise" data-reveal>
<div className="card"><span className="eyebrow">Gratuit</span><h3 className="t-h2">Et ça le restera</h3><p className="t-small">Pas d'abonnement, pas de version payante qui bloque vos souvenirs.</p></div>
<div className="card"><span className="eyebrow">Code ouvert</span><h3 className="t-h2">Vérifiable par tous</h3><p className="t-small">Le code est public. Une famille peut même héberger son propre Parenthèse.</p></div>
<div className="card"><span className="eyebrow">Vos données</span><h3 className="t-h2">Supprimables à tout moment</h3><p className="t-small">L'arbre et le compte se suppriment depuis l'app. Rien n'est revendu.</p></div>
</div>
</div>
</section>
{/* ─── GUIDES ─────────────────────────────────────────────────── */}
<section id="guides" className="sec" style={{ paddingTop: 0 }}>
<div className="wrap sec-in">
<div className="head c" data-reveal>
<span className="eyebrow">Guides</span>
<h2 className="t-d2">Guides pour faire <em className="s">son arbre généalogique</em></h2>
</div>
<div className="guides" data-reveal>
{GUIDES.map(({ href, title, text }) => (
<a key={href} href={href} className="card guide">
<h3 className="t-h2">{title}</h3>
<p className="t-small">{text}</p>
<span className="more">Lire le guide</span>
</a>
{t.promise.map(({ eyebrow, title, text }) => (
<div key={eyebrow} className="card"><span className="eyebrow">{eyebrow}</span><h3 className="t-h2">{title}</h3><p className="t-small">{text}</p></div>
))}
</div>
</div>
</section>
{/* ─── GUIDES ─────────────────────────────────────────────────── */}
{t.guides && <section id="guides" className="sec" style={{ paddingTop: 0 }}>
<div className="wrap sec-in">
<div className="head c" data-reveal>
<span className="eyebrow">{t.guides.eyebrow}</span>
<h2 className="t-d2">{t.guides.title[0]}<em className="s">{t.guides.title[1]}</em></h2>
</div>
<div className="guides" data-reveal>
{t.guides.items.map(({ href, title, text }) => (
<a key={href} href={href} className="card guide">
<h3 className="t-h2">{title}</h3>
<p className="t-small">{text}</p>
<span className="more">{t.guides.more}</span>
</a>
))}
</div>
</div>
</section>}
{/* ─── CRÉER SON ARBRE ─────────────────────────────────────────── */}
<section id="signup" className="final">
<div className="wrap" data-reveal>
<h2 className="t-d2">Commencez par <em className="s">un seul visage</em></h2>
<p className="lede">Le vôtre, ou celui de quelqu'un que vous aimeriez garder.</p>
<button type="button" onClick={() => goToSignup('footer')} className="btn p">Créer mon arbre</button>
<h2 className="t-d2">{t.final.title[0]}<em className="s">{t.final.title[1]}</em></h2>
<p className="lede">{t.final.lede}</p>
<button type="button" onClick={() => goToSignup('footer')} className="btn p">{t.cta}</button>
{source === 'app-shared' && sharedReturnUrl && (
<a href={sharedReturnUrl} className="back">Ou retourner explorer l'arbre partagé</a>
<a href={sharedReturnUrl} className="back">{t.final.back}</a>
)}
</div>
</section>
@@ -1157,11 +1123,12 @@ export default function App() {
{/* ─── FOOTER ─────────────────────────────────────────────────── */}
<footer className="wrap foot">
<Logo height={18} />
<nav aria-label="Pied de page">
<a href="#guides">Guides</a>
<a href="/donnees-et-vie-privee/">Vie privée</a>
<a href="https://github.com/IliesAllali/parenthese" rel="noopener noreferrer">Code source</a>
<a href="https://iliesallali.design/">Fait par Ilies Allali</a>
<nav aria-label={t.footer.label}>
{t.footer.guides && <a href="#guides">{t.footer.guides}</a>}
<a href={t.privacyHref}>{t.footer.privacy}</a>
<a href="https://github.com/IliesAllali/parenthese" rel="noopener noreferrer">{t.footer.source}</a>
<a href="https://iliesallali.design/">{t.footer.madeBy}</a>
<a href={t.otherLang.href} hrefLang={t.otherLang.hrefLang} lang={t.otherLang.hrefLang} title={t.otherLang.title}>{t.otherLang.label}</a>
</nav>
</footer>
</div>
+4 -3
View File
@@ -2,11 +2,12 @@ import { StrictMode } from 'react'
import { renderToString } from 'react-dom/server'
import App from './App.jsx'
// Rendu de la landing à la compilation (npm run build), injecté dans dist/index.html par scripts/prerender.mjs
export function render() {
// Rendu de la landing à la compilation (npm run build), une fois par langue,
// injecté dans dist/index.html (fr) et dist/en/index.html (en) par scripts/prerender.mjs
export function render(locale = 'fr') {
return renderToString(
<StrictMode>
<App />
<App locale={locale} />
</StrictMode>,
)
}
+240
View File
@@ -0,0 +1,240 @@
// Textes de la landing, une entrée par langue. Le français est servi à /, l'anglais à /en/.
// Les titres en deux morceaux [début, fin] : la fin est rendue en italique (<em className="s">).
// Fichier sans JSX : lu par l'app (App.jsx), par le prérendu (scripts/prerender.mjs) et par les tests.
export const LOCALES = ['fr', 'en']
// /en et /en/... servent l'anglais, tout le reste le français
export function localeFromPath(pathname = '/') {
return /^\/en(\/|$)/.test(pathname) ? 'en' : 'fr'
}
const SITE = 'https://parenthese.io'
export const COPY = {
fr: {
home: '/',
meta: {
lang: 'fr',
url: `${SITE}/`,
ogLocale: 'fr_FR',
title: "Parenthèse : l'arbre généalogique vivant de votre famille",
description: "Créez l'arbre généalogique de votre famille en ligne, avec photos, vidéos et voix. Partagez-le en un lien : la famille consulte sans compte et contribue avec un mot de passe.",
socialDescription: "L'arbre généalogique de votre famille en ligne, avec photos, voix et souvenirs. Partageable en un lien, sans compte.",
imageAlt: 'Parenthèse, votre histoire familiale, vivante et partagée',
schemaLanguage: 'fr-FR',
appDescription: "Web app pour créer l'arbre généalogique d'une famille en ligne, avec photos, anecdotes, vidéos et voix, partageable en un lien sans compte.",
},
// Paramètres ajoutés aux liens vers l'app (vide en français : l'app suit la langue du navigateur)
appQuery: '',
otherLang: { href: '/en/', hrefLang: 'en', label: 'EN', title: 'English version' },
logoHome: 'Parenthèse, accueil',
nav: { how: 'Comment ça marche', demo: 'Un exemple', privacy: 'Vie privée' },
privacyHref: '/donnees-et-vie-privee/',
cta: 'Créer mon arbre',
heroCanvas: 'Arbre de famille animé',
hero: {
pill: 'Arbre généalogique gratuit, en ligne',
title: ["L'histoire de votre famille, racontée par ceux qui ", "l'ont vécue"],
lede: "Créez l'arbre généalogique de votre famille en ligne, avec des photos, des voix et des souvenirs. Un lien suffit pour que toute la famille le consulte.",
ledeShared: "Vous venez de découvrir Parenthèse à travers le lien d'une famille. Créez la vôtre en quelques minutes.",
secondary: 'Voir un arbre',
},
trust: ['Gratuit, et le restera', 'Lecture par lien, sans compte', 'Code ouvert', 'Vos données restent les vôtres'],
how: {
eyebrow: 'Comment ça marche',
title: ['Créer un arbre généalogique, ', 'en trois gestes'],
steps: [
{ title: 'Ajoutez un visage', text: 'Un prénom, une photo si vous en avez une. Le reste peut attendre.' },
{ title: 'Racontez', text: "Une anecdote, une photo de vacances, sa voix au téléphone. Chacun ajoute ce qu'il sait." },
{ title: 'Partagez le lien', text: "La famille ouvre l'arbre depuis un message. Pas de compte, pas d'appli à installer." },
],
toast: "Marc a ouvert l'arbre",
},
demo: {
eyebrow: 'Un exemple',
title: ['Un arbre généalogique ', 'avec photos, à explorer'],
lede: "Cliquez sur un visage pour ouvrir sa fiche. C'est un arbre de démonstration, sans compte à créer.",
loading: 'Chargement de la démo',
idle: 'Démo interactive',
frameTitle: 'Démo Parenthèse',
enter: 'Entrer dans la démo',
},
who: {
eyebrow: 'Pour qui',
title: ['Du petit-fils de 8 ans ', 'à la grand-mère de 80'],
lede: 'Parenthèse se lit comme un album de famille. On reconnaît un visage, on clique, on écoute.',
captions: ['Lya, 14 ans', 'Camille, 39 ans', 'Marc, 56 ans', 'Jeanne, 85 ans'],
},
promise: [
{ eyebrow: 'Gratuit', title: 'Et ça le restera', text: "Pas d'abonnement, pas de version payante qui bloque vos souvenirs." },
{ eyebrow: 'Code ouvert', title: 'Vérifiable par tous', text: 'Le code est public. Une famille peut même héberger son propre Parenthèse.' },
{ eyebrow: 'Vos données', title: 'Supprimables à tout moment', text: "L'arbre et le compte se suppriment depuis l'app. Rien n'est revendu." },
],
guides: {
eyebrow: 'Guides',
title: ['Guides pour faire ', 'son arbre généalogique'],
more: 'Lire le guide',
items: [
{
href: '/comment-faire-un-arbre-genealogique/',
title: 'Comment faire un arbre généalogique',
text: "Partir de soi, interroger les aînés, trouver les actes gratuitement en mairie et aux archives, puis faire compléter la famille.",
},
{
href: '/application-arbre-genealogique/',
title: "Quelle application d'arbre généalogique choisir ?",
text: 'Geneanet, MyHeritage, Filae, FamilySearch, Parenthèse. Rechercher des ancêtres et garder une mémoire vivante ne sont pas le même besoin.',
},
{
href: '/arbre-genealogique-avec-photos/',
title: 'Faire un arbre généalogique avec des photos',
text: 'Rassembler, numériser avec un téléphone, nommer et dater, puis ajouter les vidéos et les voix.',
},
{
href: '/cousinade/',
title: 'Organiser une cousinade',
text: 'Retrouver toutes les branches, fixer la date, collecter les souvenirs le jour même, et garder une trace que tout le monde retrouve.',
},
{
href: '/raconter-histoire-de-famille/',
title: "Raconter l'histoire de sa famille",
text: "Par qui commencer, les questions qui font parler, enregistrer plutôt qu'écrire, et où garder ce qu'on a recueilli.",
},
{
href: '/arbre-genealogique-a-remplir/',
title: 'Arbre généalogique à remplir',
text: "Cinq modèles vierges à imprimer en PDF, de trois à cinq générations, avec cases photo ou arbre dessiné. Et comment les remplir.",
},
],
},
final: {
title: ['Commencez par ', 'un seul visage'],
lede: "Le vôtre, ou celui de quelqu'un que vous aimeriez garder.",
back: "Ou retourner explorer l'arbre partagé",
},
footer: {
label: 'Pied de page',
guides: 'Guides',
privacy: 'Vie privée',
source: 'Code source',
madeBy: 'Fait par Ilies Allali',
},
},
en: {
home: '/en/',
meta: {
lang: 'en',
url: `${SITE}/en/`,
ogLocale: 'en_US',
title: 'Parenthèse: your family tree, with photos, voices and stories',
description: 'Build your family tree online, with photos, videos and voices. Share it with one link: relatives view it without an account and contribute with a password.',
socialDescription: 'Your family tree online, with photos, voices and memories. Shareable with one link, no account needed.',
imageAlt: 'Parenthèse, your family story, alive and shared',
schemaLanguage: 'en',
appDescription: 'Web app to build a family tree online, with photos, stories, videos and voices, shareable with one link and no account.',
},
appQuery: 'lang=en',
otherLang: { href: '/', hrefLang: 'fr', label: 'FR', title: 'Version française' },
logoHome: 'Parenthèse, home',
nav: { how: 'How it works', demo: 'An example', privacy: 'Privacy' },
privacyHref: '/en/privacy/',
cta: 'Start your tree',
heroCanvas: 'Animated family tree',
hero: {
pill: 'Free family tree, online',
title: ["Your family's story, told by the people who ", 'lived it'],
lede: 'Build your family tree online, with photos, voices and memories. One link is all your family needs to explore it.',
ledeShared: "You just discovered Parenthèse through another family's link. Start your own in a few minutes.",
secondary: 'See a tree',
},
trust: ['Free, and it will stay free', 'View by link, no account', 'Source-available', 'Your data stays yours'],
how: {
eyebrow: 'How it works',
title: ['Build a family tree ', 'in three steps'],
steps: [
{ title: 'Add a face', text: 'A first name, and a photo if you have one. The rest can wait.' },
{ title: 'Tell the story', text: 'A story, a vacation photo, their voice on the phone. Everyone adds what they know.' },
{ title: 'Share the link', text: 'Your family opens the tree from a message. No account, no app to install.' },
],
toast: 'Marc opened the tree',
},
demo: {
eyebrow: 'An example',
title: ['A family tree ', 'with photos, to explore'],
lede: 'Click a face to open their profile. This is a demo tree, no account needed.',
loading: 'Loading the demo',
idle: 'Interactive demo',
frameTitle: 'Parenthèse demo',
enter: 'Enter the demo',
},
who: {
eyebrow: "Who it's for",
title: ['From a grandson of 8 ', 'to a grandmother of 80'],
lede: 'Parenthèse reads like a family album. You recognize a face, you click, you listen.',
captions: ['Lya, 14', 'Camille, 39', 'Marc, 56', 'Jeanne, 85'],
},
promise: [
{ eyebrow: 'Free', title: 'And it will stay that way', text: 'No subscription, no paid tier that locks your memories away.' },
{ eyebrow: 'Source-available', title: 'Anyone can check it', text: 'The code is public. A family can even host its own Parenthèse.' },
{ eyebrow: 'Your data', title: 'Delete it anytime', text: 'The tree and the account can be deleted from the app. Nothing is sold.' },
],
guides: {
eyebrow: 'Guides',
title: ['Guides to make ', 'your family tree'],
more: 'Read the guide',
items: [
{
href: '/en/how-to-make-a-family-tree/',
title: 'How to make a family tree',
text: 'Start with yourself, talk to the elders, find records for free at town halls and archives, then let the family fill in the rest.',
},
{
href: '/en/family-tree-app/',
title: 'Which family tree app should you choose?',
text: 'Geneanet, MyHeritage, Filae, FamilySearch, Parenthèse. Researching ancestors and keeping a living memory are not the same need.',
},
{
href: '/en/family-tree-with-photos/',
title: 'Making a family tree with photos',
text: 'Gather, scan with a phone, name and date, then add the videos and the voices.',
},
{
href: '/en/family-reunion/',
title: 'Organizing a family reunion',
text: 'Find every branch, set the date, collect memories on the day, and keep a record everyone can find.',
},
{
href: '/en/tell-your-family-story/',
title: "Telling your family's story",
text: "Who to start with, the questions that get people talking, recording rather than writing, and where to keep what you've gathered.",
},
{
href: '/en/printable-family-tree/',
title: 'Printable family tree',
text: 'Five blank templates to print as PDF, from three to five generations, with photo boxes or a drawn tree. And how to fill them in.',
},
],
},
final: {
title: ['Start with ', 'a single face'],
lede: "Yours, or the face of someone you'd like to keep close.",
back: 'Or go back to the shared tree',
},
footer: {
label: 'Footer',
guides: 'Guides',
privacy: 'Privacy',
source: 'Source code',
madeBy: 'Made by Ilies Allali',
},
},
}
// Ajoute les paramètres de langue à une adresse de l'app (https://app.parenthese.io/?...)
export function withAppQuery(url, locale) {
const query = COPY[locale].appQuery
if (!query) return url
return url + (url.includes('?') ? '&' : '?') + query
}
+2 -1
View File
@@ -3,6 +3,7 @@ import { createRoot, hydrateRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import { analytics } from './analytics.js'
import { localeFromPath } from './i18n.js'
// PostHog après le premier rendu : les événements émis avant sont mis en file et envoyés à l'init
const deferInit = () => analytics.init()
@@ -12,7 +13,7 @@ else window.setTimeout(deferInit, 1500)
const container = document.getElementById('root')
const app = (
<StrictMode>
<App />
<App locale={localeFromPath(window.location.pathname)} />
</StrictMode>
)
+71
View File
@@ -0,0 +1,71 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { existsSync, readFileSync } from 'node:fs'
import { COPY, LOCALES, localeFromPath, withAppQuery } from '../src/i18n.js'
import { localizeHead } from '../scripts/localize-head.mjs'
const landing = new URL('..', import.meta.url)
const read = (path) => readFileSync(new URL(path, landing), 'utf8')
// Clés présentes dans une langue et absentes de l'autre (null compte comme présent : section retirée exprès)
function missingKeys(a, b, prefix = '') {
return Object.keys(a).flatMap((key) => {
const path = `${prefix}${key}`
if (!(key in b)) return [path]
if (a[key] && b[key] && typeof a[key] === 'object' && typeof b[key] === 'object') return missingKeys(a[key], b[key], `${path}.`)
return []
})
}
test('fr and en copy have the same keys', () => {
assert.deepEqual(missingKeys(COPY.fr, COPY.en), [])
assert.deepEqual(missingKeys(COPY.en, COPY.fr), [])
})
test('english copy follows the wording rules', () => {
const text = JSON.stringify(COPY.en)
assert.doesNotMatch(text, /open.?source/i)
assert.doesNotMatch(text, /—/)
})
test('localeFromPath serves english under /en only', () => {
assert.equal(localeFromPath('/'), 'fr')
assert.equal(localeFromPath('/en'), 'en')
assert.equal(localeFromPath('/en/'), 'en')
assert.equal(localeFromPath('/enfance/'), 'fr')
assert.equal(localeFromPath('/cousinade/'), 'fr')
})
test('app links carry lang=en on the english page only', () => {
assert.equal(withAppQuery('https://app.parenthese.io/?embed', 'fr'), 'https://app.parenthese.io/?embed')
assert.equal(withAppQuery('https://app.parenthese.io/?embed', 'en'), 'https://app.parenthese.io/?embed&lang=en')
})
test('localizeHead rewrites the french head for english', () => {
const html = localizeHead(read('index.html'), COPY.en.meta)
assert.match(html, /<html lang="en">/)
assert.match(html, /<link rel="canonical" href="https:\/\/parenthese.io\/en\/" \/>/)
assert.match(html, /<meta property="og:url"\s+content="https:\/\/parenthese.io\/en\/"/)
assert.match(html, /<meta property="og:locale"\s+content="en_US"/)
assert.ok(html.includes(`<title>${COPY.en.meta.title}</title>`))
assert.doesNotMatch(html, /"inLanguage": "fr-FR"/)
})
test('both pages declare the same hreflang alternates', () => {
const html = read('index.html')
assert.match(html, /hreflang="fr" href="https:\/\/parenthese.io\/"/)
assert.match(html, /hreflang="en" href="https:\/\/parenthese.io\/en\/"/)
assert.match(html, /hreflang="x-default" href="https:\/\/parenthese.io\/"/)
})
// Après `npm run build` seulement (la CI lance les tests avant le build)
const built = existsSync(new URL('dist/en/index.html', landing))
test('built pages are prerendered in their language', { skip: !built && 'dist absent, lancer npm run build' }, () => {
for (const locale of LOCALES) {
const html = read(locale === 'fr' ? 'dist/index.html' : 'dist/en/index.html')
assert.match(html, new RegExp(`<html lang="${locale}">`))
assert.match(html, /<div id="root">[\s\S]*<h1[\s\S]*<\/h1>/)
assert.match(html, /hreflang="x-default"/)
assert.ok(html.includes(COPY[locale].meta.url), `canonical ${locale}`)
}
})
+46
View File
@@ -0,0 +1,46 @@
// Chaque lien interne des pages statiques et de l'accueil mène à une page qui existe dans public/.
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { COPY } from '../src/i18n.js'
const PUBLIC = fileURLToPath(new URL('../public/', import.meta.url))
// Pages rendues par React, absentes de public/.
const HOMES = new Set(['/', '/en/'])
function exists(href) {
const path = href.split('#')[0].split('?')[0]
if (HOMES.has(path)) return true
const target = join(PUBLIC, path)
return existsSync(path.endsWith('/') ? join(target, 'index.html') : target)
}
function htmlPages(dir) {
return readdirSync(dir).flatMap((name) => {
const path = join(dir, name)
if (statSync(path).isDirectory()) return htmlPages(path)
return name === 'index.html' ? [path] : []
})
}
test("les liens de l'accueil, dans les deux langues, mènent à une page existante", () => {
const broken = []
for (const [locale, copy] of Object.entries(COPY)) {
const hrefs = [copy.privacyHref, ...(copy.guides?.items ?? []).map((item) => item.href)]
for (const href of hrefs) if (!exists(href)) broken.push(`${locale} : ${href}`)
}
assert.deepEqual(broken, [])
})
test('les liens internes des pages statiques mènent à une page existante', () => {
const broken = []
for (const file of htmlPages(PUBLIC)) {
const html = readFileSync(file, 'utf8')
for (const [, href] of html.matchAll(/href="(\/[^"]*)"/g)) {
if (!exists(href)) broken.push(`${file.slice(PUBLIC.length)} : ${href}`)
}
}
assert.deepEqual(broken, [])
})