From 88b3a26e5aeae3af795bde4cfd65f9d9ce0b9379 Mon Sep 17 00:00:00 2001 From: Tomas Vondracek Date: Fri, 9 Oct 2026 10:29:43 +0200 Subject: [PATCH 1/3] fix(admin): show dates in the backend locale Dates in the admin UI ignored the backend locale. Relative labels such as "7 days ago" and the Vue listing dates are formatted by Luxon, which was never given a locale and used the browser's. Their tooltips are rendered by the localdate filter, which without a locale falls back to the current content locale. Admin locales that are not content locales, like cs, got English. - locale.js sets Luxon's default locale from , converting Bolt codes like pt_BR to BCP 47. An invalid locale would make Luxon throw on every date it formats, so those keep the browser's locale. - uses app.request.locale, the locale the backend is translated into, instead of the user's saved locale, and outputs it as a valid language tag (pt-BR). - The relative_datetime macro and value-only date fields (media edit page) pass app.request.locale to localdate. A locale passed by the caller still takes precedence. --- assets/js/bolt.js | 1 + assets/js/locale.js | 16 ++++++++++++++++ templates/_base/layout.html.twig | 2 +- templates/_macro/_macro.html.twig | 2 +- templates/_partials/fields/date.html.twig | 2 +- 5 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 assets/js/locale.js diff --git a/assets/js/bolt.js b/assets/js/bolt.js index 11750ce904..b6f4fed7d5 100644 --- a/assets/js/bolt.js +++ b/assets/js/bolt.js @@ -7,6 +7,7 @@ Axios.defaults.headers.common = { accept: 'application/vnd.api+json', }; +import './locale'; import './jquery'; import './codemirror'; import './filters'; diff --git a/assets/js/locale.js b/assets/js/locale.js new file mode 100644 index 0000000000..ee4855768f --- /dev/null +++ b/assets/js/locale.js @@ -0,0 +1,16 @@ +import { Settings } from 'luxon'; + +/* + ** Make Luxon format dates (incl. relative ones like "7 days ago") in the locale of the Bolt admin UI, + ** instead of the browser's locale. Bolt uses locale codes like 'pt_BR', while Intl expects 'pt-BR'. + ** An invalid locale would make Luxon throw on every date it formats, so those keep the browser's locale. + */ +const locale = document.documentElement.lang.replace(/_/g, '-'); + +if (locale) { + try { + Settings.defaultLocale = Intl.getCanonicalLocales(locale)[0]; + } catch { + // Keep the browser's locale + } +} diff --git a/templates/_base/layout.html.twig b/templates/_base/layout.html.twig index f9ccf7e2c2..c0863e6394 100644 --- a/templates/_base/layout.html.twig +++ b/templates/_base/layout.html.twig @@ -1,7 +1,7 @@ {# Check if aside has value and set hasAside variable #} {% set hasAside = block('aside')|trim is not empty ? true : false %} - + diff --git a/templates/_macro/_macro.html.twig b/templates/_macro/_macro.html.twig index 6eb1993271..defb00e1a8 100644 --- a/templates/_macro/_macro.html.twig +++ b/templates/_macro/_macro.html.twig @@ -94,7 +94,7 @@ {% macro relative_datetime(datetime) %}{% apply spaceless %} - + {{- datetime|date('c') -}} {% endapply %}{% endmacro %} diff --git a/templates/_partials/fields/date.html.twig b/templates/_partials/fields/date.html.twig index b77cdd758e..ed1f649812 100644 --- a/templates/_partials/fields/date.html.twig +++ b/templates/_partials/fields/date.html.twig @@ -41,7 +41,7 @@ :errormessage='{{ errormessage|json_encode }}' > {% else %} - {{ value|localdate(format|default(null), locale|default(null)) }} + {{ value|localdate(format|default(null), locale|default(app.request.locale|default(null))) }} ({{ macro.relative_datetime(value) }}) {% endif %} From c236173b34472c94e8ac520dc3c7051153ad4fba Mon Sep 17 00:00:00 2001 From: Tomas Vondracek Date: Sun, 25 Oct 2026 19:42:48 +0100 Subject: [PATCH 2/3] refactor(admin): drop the redundant locale replace in locale.js The layout already outputs as a valid language tag, so the JavaScript no longer needs to convert underscores to hyphens. --- assets/js/locale.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/js/locale.js b/assets/js/locale.js index ee4855768f..360e0dd547 100644 --- a/assets/js/locale.js +++ b/assets/js/locale.js @@ -2,10 +2,10 @@ import { Settings } from 'luxon'; /* ** Make Luxon format dates (incl. relative ones like "7 days ago") in the locale of the Bolt admin UI, - ** instead of the browser's locale. Bolt uses locale codes like 'pt_BR', while Intl expects 'pt-BR'. + ** instead of the browser's locale. The layout already outputs a valid language tag (e.g. 'pt-BR'). ** An invalid locale would make Luxon throw on every date it formats, so those keep the browser's locale. */ -const locale = document.documentElement.lang.replace(/_/g, '-'); +const locale = document.documentElement.lang; if (locale) { try { From cf274b694f1536d2c86b501fa82b3bf19baeb083 Mon Sep 17 00:00:00 2001 From: Tomas Vondracek Date: Sun, 25 Oct 2026 19:56:47 +0100 Subject: [PATCH 3/3] fix(admin): use the backend locale for the content summary dates The created and modified dates in the content edit summary passed app.user.locale to the date field, bypassing the app.request.locale fallback. When the user has no locale set, they fell back to the content locale instead of the backend locale. --- templates/content/_fields_aside_summary.html.twig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/content/_fields_aside_summary.html.twig b/templates/content/_fields_aside_summary.html.twig index c2ebcd045d..09a228a3f7 100644 --- a/templates/content/_fields_aside_summary.html.twig +++ b/templates/content/_fields_aside_summary.html.twig @@ -7,7 +7,7 @@ 'name' : 'createdAt', 'value' : record.createdAt, 'valueonly' : true, - 'locale': app.user.locale + 'locale': app.request.locale } %} @@ -17,7 +17,7 @@ 'name' : 'modifiedAt', 'value' : record.modifiedAt, 'valueonly' : true, - 'locale': app.user.locale + 'locale': app.request.locale } %} @@ -27,7 +27,7 @@ 'name' : 'id', 'value' : record.id, 'valueonly' : true, - 'locale': app.user.locale + 'locale': app.request.locale } %}