Date formats are hard-coded and cannot be localized
Tested against FluentCart 1.6.1 and FluentCart Pro 1.6.1 on a German store
(WordPress locale de_DE, date format "j. F Y", time format "H:i", timezone
Europe/Berlin).
This is not about missing strings. The month and weekday names are already
translatable and work fine. What cannot be reached is the format: the order
of day and month, and the 12-hour clock. Both are literals in the source, so no
translation and no filter can change them.
In German, "Aug 16, 2026 03:30 PM" is wrong three times over: the month name is
English, day and month are in the wrong order, and nobody writes AM/PM. Our
customers see it in transactional e-mails, on the thank-you page and in their
account dashboard.
1 PHP: DateTime::format() with a hard-coded pattern
PHP's DateTime::format() has no locale at all, so "M" always returns "Aug",
even with a German site language. These call sites are therefore impossible to
localize:
app/Views/emails/order/reminder/due/admin.php:10 'M d, Y h:i A'
app/Views/emails/order/reminder/due/customer.php:10 'M d, Y h:i A'
app/Views/emails/order/reminder/overdue/admin.php:10 'M d, Y h:i A'
app/Views/emails/order/reminder/overdue/customer.php:10 'M d, Y h:i A'
app/Views/emails/subscription/reminder/admin.php:11 'M d, Y h:i A'
app/Views/emails/subscription/reminder/customer.php:11 'M d, Y h:i A'
app/Views/emails/subscription/trial_end/admin.php:13 'M d, Y h:i A'
app/Views/emails/subscription/trial_end/customer.php:13 'M d, Y h:i A'
app/Views/emails/subscription/canceled/admin.php:12 'M d, Y'
app/Views/emails/subscription/canceled/customer.php:13 'M d, Y'
app/Views/emails/subscription/renewal/admin.php:34 'd M Y, H:i'
app/Views/invoice/parts/subscription_items.php:39 'M d, Y h:i A'
app/Services/Renderer/Receipt/ThankYouRender.php:625 'M d, Y h:i A'
app/Services/ShortCodeParser/Parsers/SubscriptionParser.php:43,55````app/Services/ShortCodeParser/Parsers/LicenseParser.php:42````date('M j, Y', strtotime(...))
app/Modules/Integrations/FluentPlugins/FluentCRMDeepIntegration.php:607,611,664````gmdate('M j, Y', strtotime(...))
Suggested fix: wp_date(get_option('date_format'), $timestamp), plus
get_option('time_format') where a time is shown. That is what
ReceiptRenderer.php:246 and :813 already do, and the receipt is the one place
where the date comes out right on our store. Making the rest match it would fix
this class of issue completely.
Two of the three date() calls have a second problem: date() and gmdate() use
the PHP default timezone, not the store timezone, so the shortcodes
{{subscription.next_billing_date}}, {{subscription.expire_at}} and
{{license.expiration_date}} can be a day off around midnight.
2 JavaScript: the dayjs format string is a default parameter
Every date in the admin SPA and in the customer dashboard goes through one
helper per bundle:
chunks/Utils.js function S(e, r = "MMM DD") { ... .format(r) }
Start.js function j(e, s = "MMM DD") { ... .format(s) }
The month and weekday names come from window.fluentcart_admin_vars.datei18 at
call time, so those are translatable. The pattern is not: it is a default
parameter inside the module. Concrete results with a fully translated catalog:
ConvertedTime (orders, customers, subscriptions, activity log)
"MMM DD" in the current year, "MMM DD, YYYY" otherwise,
"+ h:mm A" when a time is shown,
and the title attribute always "MMM DD, YYYY h:mm A"
reports and charts
"MMMM D, YYYY", "MMM YYYY"
Because the names are translated but the order is not, a German store ends up
with the worst of both: "August 16, 2026".
The bundle is an ES module, so there is nothing a site can override from the
outside: no window.dayjs, no global formatter, no filter.
Suggested fix: send a display pattern along with the names, for example
'datei18' => [
'weekdays' => [...], 'months' => [...],
'formats' => [
'date' => 'MMM DD, YYYY',
'dateShort' => 'MMM DD',
'time' => 'h:mm A',
],
]
derived from get_option('date_format') / get_option('time_format') (there are
small, well-known converters from PHP date format to dayjs tokens), and have
the helpers fall back to their current literals when the key is absent. That
would keep every existing installation identical and let localized stores use
their own format.
3 TransStrings::dateTimeStrings() has no filter
Every other map in app/Services/Translations/TransStrings.php passes through a
filter: fluent_cart/admin_translations, fluent_cart/blocks_translations,
fluent_cart/customer_profile_translations, fluent_cart/checkout_translations,
fluent_cart/payments_translations. dateTimeStrings() does not. Adding
return apply_filters('fluent_cart/date_time_strings', $strings);
would at least give sites a way to correct the names, and it would be the
natural place to inject the formats from point 2.
4 Small note on monthsShort
dayjs resolves MMM as
monthsShort && (monthsShort[index] || monthsShort(instance, format))
|| months[index].slice(0, 3)
If a translation ever yields an empty string for one of the twelve entries, the
falsy branch calls the array as a function and throws. gettext returns the msgid
for an untranslated string, so this cannot happen today, but it is worth a
guard if the array is ever built programmatically.
Happy to test a patch on our staging install.
Thank you for FluentCart and for constantly improving and developing it!
Weβve prepared an implementation that makes the displayed dates follow the storeβs WordPress date, time, locale, and timezone settings. If youβre interested in testing the beta version, please open a ticket through our support portal and mention this community report: https://fluentcart.com/account/support/
Our team will help you access the beta.
Amimul Ihsan Mahdi, done (ticket opened).