fix(i18n): locale-aware date/number formatting in loyalty factories
Some checks failed
Some checks failed
Dates rendered in English even when the dashboard language was set to French (or any other locale). The 5 shared loyalty Alpine factories hardcoded 'en-US' in every toLocaleDateString / toLocaleString / Intl.NumberFormat call, ignoring the user's selected language. - Add `I18n.locale` getter to static/shared/js/i18n.js that returns the current dashboard language code (en/fr/de/lb). Falls back to 'en' if I18n isn't initialised yet. - Replace 'en-US' with I18n.locale in 5 loyalty shared factories: loyalty-cards-list, loyalty-card-detail-view, loyalty-transactions- list, loyalty-pins-list, loyalty-devices-list. - Also fix a latent bug in loyalty-transactions-list.formatDateTime that called toLocaleDateString with hour/minute opts (silently ignored — same bug previously fixed in loyalty-card-detail-view). Scoped to loyalty per session decision; other modules with the same hardcoded 'en-US' pattern (catalog, billing, etc.) are tracked as a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -177,13 +177,13 @@ function loyaltyCardDetailView(config) {
|
|||||||
|
|
||||||
// Formatting helpers
|
// Formatting helpers
|
||||||
formatNumber(num) {
|
formatNumber(num) {
|
||||||
return num == null ? '0' : new Intl.NumberFormat('en-US').format(num);
|
return num == null ? '0' : new Intl.NumberFormat(I18n.locale).format(num);
|
||||||
},
|
},
|
||||||
|
|
||||||
formatDate(dateString) {
|
formatDate(dateString) {
|
||||||
if (!dateString) return 'Never';
|
if (!dateString) return 'Never';
|
||||||
try {
|
try {
|
||||||
return new Date(dateString).toLocaleDateString('en-US', {
|
return new Date(dateString).toLocaleDateString(I18n.locale, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
day: 'numeric'
|
day: 'numeric'
|
||||||
@@ -196,7 +196,7 @@ function loyaltyCardDetailView(config) {
|
|||||||
formatDateTime(dateString) {
|
formatDateTime(dateString) {
|
||||||
if (!dateString) return 'Never';
|
if (!dateString) return 'Never';
|
||||||
try {
|
try {
|
||||||
return new Date(dateString).toLocaleString('en-US', {
|
return new Date(dateString).toLocaleString(I18n.locale, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
|
|||||||
@@ -223,13 +223,13 @@ function loyaltyCardsList(config) {
|
|||||||
|
|
||||||
// Formatting helpers
|
// Formatting helpers
|
||||||
formatNumber(num) {
|
formatNumber(num) {
|
||||||
return num == null ? '0' : new Intl.NumberFormat('en-US').format(num);
|
return num == null ? '0' : new Intl.NumberFormat(I18n.locale).format(num);
|
||||||
},
|
},
|
||||||
|
|
||||||
formatDate(dateString) {
|
formatDate(dateString) {
|
||||||
if (!dateString) return 'Never';
|
if (!dateString) return 'Never';
|
||||||
try {
|
try {
|
||||||
return new Date(dateString).toLocaleDateString('en-US', {
|
return new Date(dateString).toLocaleDateString(I18n.locale, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
day: 'numeric'
|
day: 'numeric'
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ function loyaltyDevicesList(config) {
|
|||||||
formatDate(value) {
|
formatDate(value) {
|
||||||
if (!value) return '-';
|
if (!value) return '-';
|
||||||
try {
|
try {
|
||||||
return new Date(value).toLocaleString();
|
return new Date(value).toLocaleString(I18n.locale);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ function loyaltyPinsList(config) {
|
|||||||
formatDate(dateString) {
|
formatDate(dateString) {
|
||||||
if (!dateString) return 'Never';
|
if (!dateString) return 'Never';
|
||||||
try {
|
try {
|
||||||
return new Date(dateString).toLocaleDateString('en-US', {
|
return new Date(dateString).toLocaleDateString(I18n.locale, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
day: 'numeric'
|
day: 'numeric'
|
||||||
@@ -330,7 +330,7 @@ function loyaltyPinsList(config) {
|
|||||||
formatDateTime(dateString) {
|
formatDateTime(dateString) {
|
||||||
if (!dateString) return 'Never';
|
if (!dateString) return 'Never';
|
||||||
try {
|
try {
|
||||||
return new Date(dateString).toLocaleDateString('en-US', {
|
return new Date(dateString).toLocaleString(I18n.locale, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
|
|||||||
@@ -209,13 +209,13 @@ function loyaltyTransactionsList(config) {
|
|||||||
|
|
||||||
// Formatting helpers
|
// Formatting helpers
|
||||||
formatNumber(num) {
|
formatNumber(num) {
|
||||||
return num == null ? '0' : new Intl.NumberFormat('en-US').format(num);
|
return num == null ? '0' : new Intl.NumberFormat(I18n.locale).format(num);
|
||||||
},
|
},
|
||||||
|
|
||||||
formatDate(dateString) {
|
formatDate(dateString) {
|
||||||
if (!dateString) return 'Never';
|
if (!dateString) return 'Never';
|
||||||
try {
|
try {
|
||||||
return new Date(dateString).toLocaleDateString('en-US', {
|
return new Date(dateString).toLocaleDateString(I18n.locale, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
day: 'numeric'
|
day: 'numeric'
|
||||||
@@ -228,7 +228,7 @@ function loyaltyTransactionsList(config) {
|
|||||||
formatDateTime(dateString) {
|
formatDateTime(dateString) {
|
||||||
if (!dateString) return 'Never';
|
if (!dateString) return 'Never';
|
||||||
try {
|
try {
|
||||||
return new Date(dateString).toLocaleDateString('en-US', {
|
return new Date(dateString).toLocaleString(I18n.locale, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
|
|||||||
@@ -170,6 +170,16 @@ const I18n = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BCP-47 locale tag for the current dashboard language.
|
||||||
|
* Use as the first arg to Intl.* / toLocale* APIs so dates and numbers
|
||||||
|
* render in the user's language instead of the browser default.
|
||||||
|
* Falls back to 'en' (which is what the dashboards default to).
|
||||||
|
*/
|
||||||
|
get locale() {
|
||||||
|
return this._language || 'en';
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify Alpine (and other listeners) that translations are ready.
|
* Notify Alpine (and other listeners) that translations are ready.
|
||||||
* Bumps the Alpine store version so reactive $t() bindings re-evaluate.
|
* Bumps the Alpine store version so reactive $t() bindings re-evaluate.
|
||||||
|
|||||||
Reference in New Issue
Block a user