fix(loyalty): translate transaction types + notes on card detail page
Some checks failed
CI / ruff (push) Successful in 17s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has been cancelled

Card detail transaction history now shows translated transaction type
labels and system-generated notes. Uses server-rendered labels object
(same pattern as terminal) to avoid async i18n flicker.

- Transaction types: server-rendered txLabels lookup (all 11 types)
- Notes: txNotes lookup maps English DB strings to translated text
  (e.g., "Welcome bonus on enrollment" → "Bonus de bienvenue...")
- Added welcome_bonus_note key to all 4 locales

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-27 22:23:02 +02:00
parent 3fa159ff2a
commit 4f70290af5
6 changed files with 33 additions and 6 deletions

View File

@@ -190,7 +190,8 @@
"points_adjustment": "Punkte angepasst", "points_adjustment": "Punkte angepasst",
"points_expired": "Punkte verfallen", "points_expired": "Punkte verfallen",
"card_deactivated": "Deaktiviert", "card_deactivated": "Deaktiviert",
"reward_redeemed": "Prämie eingelöst" "reward_redeemed": "Prämie eingelöst",
"welcome_bonus_note": "Willkommensbonus bei Anmeldung"
}, },
"shared": { "shared": {
"analytics": { "analytics": {

View File

@@ -194,7 +194,8 @@
"points_adjustment": "Points Adjusted", "points_adjustment": "Points Adjusted",
"points_expired": "Points Expired", "points_expired": "Points Expired",
"card_deactivated": "Deactivated", "card_deactivated": "Deactivated",
"reward_redeemed": "Reward Redeemed" "reward_redeemed": "Reward Redeemed",
"welcome_bonus_note": "Welcome bonus on enrollment"
}, },
"shared": { "shared": {
"analytics": { "analytics": {

View File

@@ -190,7 +190,8 @@
"points_adjustment": "Points ajustés", "points_adjustment": "Points ajustés",
"points_expired": "Points expirés", "points_expired": "Points expirés",
"card_deactivated": "Désactivé", "card_deactivated": "Désactivé",
"reward_redeemed": "Récompense échangée" "reward_redeemed": "Récompense échangée",
"welcome_bonus_note": "Bonus de bienvenue à l'inscription"
}, },
"shared": { "shared": {
"analytics": { "analytics": {

View File

@@ -190,7 +190,8 @@
"points_adjustment": "Punkten ugepasst", "points_adjustment": "Punkten ugepasst",
"points_expired": "Punkten ofgelaf", "points_expired": "Punkten ofgelaf",
"card_deactivated": "Deaktivéiert", "card_deactivated": "Deaktivéiert",
"reward_redeemed": "Belounung agelées" "reward_redeemed": "Belounung agelées",
"welcome_bonus_note": "Wëllkommsbonus bei der Umeldung"
}, },
"shared": { "shared": {
"analytics": { "analytics": {

View File

@@ -12,6 +12,8 @@ function storeLoyaltyCardDetail() {
card: null, card: null,
transactions: [], transactions: [],
pagination: { page: 1, per_page: 20, total: 0 }, pagination: { page: 1, per_page: 20, total: 0 },
txLabels: window._cardDetailLabels?.txLabels || {},
txNotes: window._cardDetailLabels?.txNotes || {},
loading: false, loading: false,
error: null, error: null,

View File

@@ -161,13 +161,13 @@
'text-green-700 bg-green-100 dark:bg-green-700 dark:text-green-100': tx.points_delta > 0, 'text-green-700 bg-green-100 dark:bg-green-700 dark:text-green-100': tx.points_delta > 0,
'text-orange-700 bg-orange-100 dark:bg-orange-700 dark:text-orange-100': tx.points_delta < 0 'text-orange-700 bg-orange-100 dark:bg-orange-700 dark:text-orange-100': tx.points_delta < 0
}" }"
x-text="tx.transaction_type.replace(/_/g, ' ')"></span> x-text="txLabels[tx.transaction_type] || tx.transaction_type.replace(/_/g, ' ')"></span>
</td> </td>
<td class="px-4 py-3 text-sm font-medium" <td class="px-4 py-3 text-sm font-medium"
:class="tx.points_delta > 0 ? 'text-green-600' : 'text-orange-600'" :class="tx.points_delta > 0 ? 'text-green-600' : 'text-orange-600'"
x-text="(tx.points_delta > 0 ? '+' : '') + formatNumber(tx.points_delta)"></td> x-text="(tx.points_delta > 0 ? '+' : '') + formatNumber(tx.points_delta)"></td>
<td class="px-4 py-3 text-sm" x-text="tx.store_name || '-'"></td> <td class="px-4 py-3 text-sm" x-text="tx.store_name || '-'"></td>
<td class="px-4 py-3 text-sm text-gray-500" x-text="tx.notes || '-'"></td> <td class="px-4 py-3 text-sm text-gray-500" x-text="txNotes[tx.notes] || tx.notes || '-'"></td>
</tr> </tr>
</template> </template>
</tbody> </tbody>
@@ -179,5 +179,26 @@
{% endblock %} {% endblock %}
{% block extra_scripts %} {% block extra_scripts %}
<script>
// Server-rendered transaction type labels + system note translations
window._cardDetailLabels = {
txLabels: {
card_created: {{ _('loyalty.transactions.card_created')|tojson }},
welcome_bonus: {{ _('loyalty.transactions.welcome_bonus')|tojson }},
stamp_earned: {{ _('loyalty.transactions.stamp_earned')|tojson }},
stamp_redeemed: {{ _('loyalty.transactions.stamp_redeemed')|tojson }},
stamp_voided: {{ _('loyalty.transactions.stamp_voided')|tojson }},
points_earned: {{ _('loyalty.transactions.points_earned')|tojson }},
points_redeemed: {{ _('loyalty.transactions.points_redeemed')|tojson }},
points_voided: {{ _('loyalty.transactions.points_voided')|tojson }},
points_adjustment: {{ _('loyalty.transactions.points_adjustment')|tojson }},
points_expired: {{ _('loyalty.transactions.points_expired')|tojson }},
reward_redeemed: {{ _('loyalty.transactions.reward_redeemed')|tojson }},
},
txNotes: {
"Welcome bonus on enrollment": {{ _('loyalty.transactions.welcome_bonus_note')|tojson }},
}
};
</script>
<script defer src="{{ url_for('loyalty_static', path='store/js/loyalty-card-detail.js') }}"></script> <script defer src="{{ url_for('loyalty_static', path='store/js/loyalty-card-detail.js') }}"></script>
{% endblock %} {% endblock %}