From b9d85f1f39fa9156bcfcc203bfef2f75d1cc57d6 Mon Sep 17 00:00:00 2001
From: Bastien <57838962+bst1n@users.noreply.github.com>
Date: Sun, 24 May 2026 17:43:40 +0200
Subject: [PATCH 1/3] Add default error.hbs and error-404.hbs templates
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Source currently doesn't ship any error templates, so Ghost falls back
to an unbranded default. This adds two minimal, on-brand error pages
following the same convention as Casper:
- error.hbs (standalone, lightweight): handles all non-404 errors (500,
etc.). No partials or API calls so it stays renderable when something
on the server is degraded.
- error-404.hbs (extends default.hbs): keeps the visitor inside the
theme chrome and suggests 3 recent posts to help them re-engage.
Both templates use only existing translation keys ('Go to the front
page →', 'Recent posts', 'Theme errors'), so no locale changes are
required.
---
error-404.hbs | 42 ++++++++++++++++++++++++++++++++
error.hbs | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+)
create mode 100644 error-404.hbs
create mode 100644 error.hbs
diff --git a/error-404.hbs b/error-404.hbs
new file mode 100644
index 00000000..d5bc5bf0
--- /dev/null
+++ b/error-404.hbs
@@ -0,0 +1,42 @@
+{{!< default}}
+
+{{!--
+ 404 page. Inherits the default layout so visitors keep the theme's
+ navigation, footer, and overall look while they figure out where to go.
+--}}
+
+
+
+
+
+
+ {{statusCode}}
+ {{message}}
+
+
+
+
+
+
+
+
+{{!-- Visitors landing here didn't find what they were looking for.
+ Suggest a few recent posts to help them re-engage. --}}
+{{#get "posts" include="authors" limit="3" as |suggested|}}
+ {{#if suggested}}
+
+
+
{{t "Recent posts"}}
+
+ {{#foreach suggested}}
+ {{> "post-card" lazyLoad=true}}
+ {{/foreach}}
+
+
+
+ {{/if}}
+{{/get}}
diff --git a/error.hbs b/error.hbs
new file mode 100644
index 00000000..843d3637
--- /dev/null
+++ b/error.hbs
@@ -0,0 +1,66 @@
+{{!--
+ Generic error template — handles all non-404 errors (500, etc.).
+ Standalone (doesn't extend default.hbs) and kept lightweight on
+ purpose: minimal dependencies, no partials, no API calls.
+
+ The reasoning mirrors Casper's: 500 errors usually happen when
+ something on the server is struggling, so we don't want the error
+ page itself to compound the issue. Keep this template as
+ self-contained as possible.
+--}}
+
+
+
+
+ {{meta_title}}
+
+
+
+
+ {{ghost_head}}
+
+
+
+
+
+
+
+
+ {{statusCode}}
+ {{message}}
+
+
+
+
+ {{#if errorDetails}}
+
+ {{t "Theme errors"}}
+
+ {{#foreach errorDetails}}
+
+ {{rule}}
+ {{#foreach failures}}
+ {{ref}}: {{message}}
+ {{/foreach}}
+
+ {{/foreach}}
+
+
+ {{/if}}
+
+
+
+
+
+ {{ghost_foot}}
+
+
+
From 7d8c9c37b30fb4d07410d18fd80a88fd93af6a4e Mon Sep 17 00:00:00 2001
From: Bastien <57838962+bst1n@users.noreply.github.com>
Date: Sun, 24 May 2026 17:54:24 +0200
Subject: [PATCH 2/3] Use translatable 'Page not found' string instead of
Ghost's raw message
The {{message}} helper outputs Ghost's internal English error message,
which doesn't get translated. For the 404 case the message is always
roughly 'Page not found', so we replace it with a properly i18n-able
{{t "Page not found"}} string and register the key across all locale
files (with the French translation included).
---
error-404.hbs | 2 +-
locales/context.json | 1 +
locales/de-CH.json | 1 +
locales/de.json | 1 +
locales/en.json | 1 +
locales/fr.json | 1 +
locales/ga.json | 1 +
locales/gd.json | 1 +
locales/nl.json | 1 +
locales/pt-BR.json | 1 +
locales/sv.json | 1 +
locales/tr.json | 1 +
locales/uk.json | 1 +
locales/zh-Hant.json | 1 +
locales/zh.json | 1 +
15 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/error-404.hbs b/error-404.hbs
index d5bc5bf0..be8e10fc 100644
--- a/error-404.hbs
+++ b/error-404.hbs
@@ -11,7 +11,7 @@
{{statusCode}}
- {{message}}
+ {{t "Page not found"}}
diff --git a/locales/context.json b/locales/context.json
index 0630061f..bbe95c3f 100644
--- a/locales/context.json
+++ b/locales/context.json
@@ -58,6 +58,7 @@
"Next →": "solo/post.hbs",
"Older Posts": "ghost-tpl/pagination.hbs",
"Page {page} of {totalPages}": "alto/partials/pagination.hbs, ghost-tpl/pagination.hbs",
+ "Page not found": "Friendly message shown on 404 pages",
"Paid": "solo/partials/loop.hbs",
"Paid-members only": "casper/partials/post-card.hbs",
"Please enter a valid email address": "ghost-private/private.hbs",
diff --git a/locales/de-CH.json b/locales/de-CH.json
index cf025445..14026b91 100644
--- a/locales/de-CH.json
+++ b/locales/de-CH.json
@@ -58,6 +58,7 @@
"Next →": "",
"Older Posts": "",
"Page {page} of {totalPages}": "",
+ "Page not found": "",
"Paid": "",
"Paid-members only": "",
"Please enter a valid email address": "",
diff --git a/locales/de.json b/locales/de.json
index 9c9370fb..fded86e0 100644
--- a/locales/de.json
+++ b/locales/de.json
@@ -58,6 +58,7 @@
"Next →": "Weiter →",
"Older Posts": "Ältere Beiträge",
"Page {page} of {totalPages}": "Seite {page} von {totalPages}",
+ "Page not found": "",
"Paid": "Kostenpflichtig",
"Paid-members only": "Nur für zahlende Mitglieder",
"Please enter a valid email address": "",
diff --git a/locales/en.json b/locales/en.json
index 7f4988ef..4e628098 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -58,6 +58,7 @@
"Next →": "",
"Older Posts": "",
"Page {page} of {totalPages}": "",
+ "Page not found": "",
"Paid": "",
"Paid-members only": "",
"Please enter a valid email address": "",
diff --git a/locales/fr.json b/locales/fr.json
index eed05db6..aae346c7 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -58,6 +58,7 @@
"Next →": "Suivant →",
"Older Posts": "Publications plus anciennes",
"Page {page} of {totalPages}": "Page {page} sur {totalPages}",
+ "Page not found": "Page introuvable",
"Paid": "Payant",
"Paid-members only": "Réservé aux abonnés payants",
"Please enter a valid email address": "",
diff --git a/locales/ga.json b/locales/ga.json
index ac3edaa3..550f0bfe 100644
--- a/locales/ga.json
+++ b/locales/ga.json
@@ -58,6 +58,7 @@
"Next →": "",
"Older Posts": "",
"Page {page} of {totalPages}": "",
+ "Page not found": "",
"Paid": "",
"Paid-members only": "",
"Please enter a valid email address": "",
diff --git a/locales/gd.json b/locales/gd.json
index 32d1a200..6c20bdbc 100644
--- a/locales/gd.json
+++ b/locales/gd.json
@@ -58,6 +58,7 @@
"Next →": "",
"Older Posts": "",
"Page {page} of {totalPages}": "",
+ "Page not found": "",
"Paid": "",
"Paid-members only": "",
"Please enter a valid email address": "",
diff --git a/locales/nl.json b/locales/nl.json
index f30deca2..a7cfbba6 100644
--- a/locales/nl.json
+++ b/locales/nl.json
@@ -58,6 +58,7 @@
"Next →": "",
"Older Posts": "",
"Page {page} of {totalPages}": "",
+ "Page not found": "",
"Paid": "",
"Paid-members only": "",
"Please enter a valid email address": "",
diff --git a/locales/pt-BR.json b/locales/pt-BR.json
index 1a4c0e73..2c3884e6 100644
--- a/locales/pt-BR.json
+++ b/locales/pt-BR.json
@@ -58,6 +58,7 @@
"Next →": "",
"Older Posts": "",
"Page {page} of {totalPages}": "",
+ "Page not found": "",
"Paid": "",
"Paid-members only": "",
"Please enter a valid email address": "",
diff --git a/locales/sv.json b/locales/sv.json
index 69c63ba6..1e5797a5 100644
--- a/locales/sv.json
+++ b/locales/sv.json
@@ -58,6 +58,7 @@
"Next →": "",
"Older Posts": "",
"Page {page} of {totalPages}": "",
+ "Page not found": "",
"Paid": "",
"Paid-members only": "",
"Please enter a valid email address": "",
diff --git a/locales/tr.json b/locales/tr.json
index cb2bc85b..6dc9f1fc 100644
--- a/locales/tr.json
+++ b/locales/tr.json
@@ -58,6 +58,7 @@
"Next →": "Sonraki →",
"Older Posts": "Daha Eski Yazılar",
"Page {page} of {totalPages}": "Sayfa {page} / {totalPages}",
+ "Page not found": "",
"Paid": "Ücretli",
"Paid-members only": "Ücretli üyelere özel",
"Please enter a valid email address": "",
diff --git a/locales/uk.json b/locales/uk.json
index bd6af472..d223eefc 100644
--- a/locales/uk.json
+++ b/locales/uk.json
@@ -58,6 +58,7 @@
"Next →": "Далі →",
"Older Posts": "Старіші дописи",
"Page {page} of {totalPages}": "Сторінка {page} з {totalPages}",
+ "Page not found": "",
"Paid": "Платний",
"Paid-members only": "Тільки за платною підпискою",
"Please enter a valid email address": "",
diff --git a/locales/zh-Hant.json b/locales/zh-Hant.json
index edf56df0..995ae711 100644
--- a/locales/zh-Hant.json
+++ b/locales/zh-Hant.json
@@ -58,6 +58,7 @@
"Next →": "",
"Older Posts": "",
"Page {page} of {totalPages}": "",
+ "Page not found": "",
"Paid": "",
"Paid-members only": "付費會員限定",
"Please enter a valid email address": "",
diff --git a/locales/zh.json b/locales/zh.json
index 7dc0e533..cfd0be6b 100644
--- a/locales/zh.json
+++ b/locales/zh.json
@@ -58,6 +58,7 @@
"Next →": "",
"Older Posts": "",
"Page {page} of {totalPages}": "",
+ "Page not found": "",
"Paid": "",
"Paid-members only": "",
"Please enter a valid email address": "",
From 968ad85bc3256f02877ff33a0fba6c21b9261b6e Mon Sep 17 00:00:00 2001
From: Bastien <57838962+bst1n@users.noreply.github.com>
Date: Sun, 24 May 2026 18:00:16 +0200
Subject: [PATCH 3/3] Fix grid layout of recent posts section on 404 page
The .gh-feed needs to be wrapped in so it
inherits the proper grid-column placement (3 / span 12) inside the
16-column .gh-container-inner grid. This mirrors how the post-list
partial structures the same section.
---
error-404.hbs | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/error-404.hbs b/error-404.hbs
index be8e10fc..080bfe11 100644
--- a/error-404.hbs
+++ b/error-404.hbs
@@ -31,11 +31,13 @@
{{t "Recent posts"}}
-
- {{#foreach suggested}}
- {{> "post-card" lazyLoad=true}}
- {{/foreach}}
-
+
+
+ {{#foreach suggested}}
+ {{> "post-card" lazyLoad=true}}
+ {{/foreach}}
+
+
{{/if}}