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}}

+
+ +
+

+ {{t "Go to the front page →"}} +

+
+ +
+ +
+ +{{!-- 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}}

+
+ +
+

+ {{t "Go to the front page →"}} +

+
+ + {{#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}}