feat(payment): i18n payment error codes and label localization
Pairs with the backend structured payment errors (reason + metadata). The
frontend now maps reason codes to localized messages with metadata as
interpolation variables, and automatically localizes raw config-field names
(e.g. "certSerial" → "证书序列号") using the existing UI-label i18n
namespace.
- frontend/src/utils/apiError.ts
- extractApiErrorCode now prefers the string `reason` over the numeric HTTP
`code`; reason is granular enough to drive i18n lookup, HTTP code is not.
- New extractApiErrorMetadata to pull interpolation params off the error.
- New extractI18nErrorMessage(err, t, namespace, fallback): looks up
`<namespace>.<REASON>` in i18n and substitutes metadata. Before
substitution, `metadata.key` and `metadata.keys` (slash-joined) are
re-translated through `admin.settings.payment.field_<key>` so users see
"缺少必填项:证书序列号" instead of "缺少必填项:certSerial".
- frontend/src/i18n/locales/{zh,en}.ts
- Add payment.errors entries for every structured reason code returned by
the backend (PAYMENT_DISABLED, INVALID_AMOUNT, TOO_MANY_PENDING,
DAILY_LIMIT_EXCEEDED, NO_AVAILABLE_INSTANCE, PAYMENT_PROVIDER_MISCONFIGURED,
WXPAY_CONFIG_MISSING_KEY / INVALID_KEY_LENGTH / INVALID_KEY, NOT_FOUND,
FORBIDDEN, CONFLICT, INVALID_ORDER_TYPE, INVALID_STATUS,
BALANCE_NOT_ENOUGH, REFUND_AMOUNT_EXCEEDED, REFUND_FAILED, and more),
with placeholders for template variables.
- 13 payment-related Vue files
- Migrate catch-block error reporting from extractApiErrorMessage to
extractI18nErrorMessage(err, t, 'payment.errors', fallback).
- Remove the ad-hoc paymentErrorMap computed in SettingsView.vue, which the
new helper supersedes (it reads i18n directly via t).
- frontend/src/components/payment/providerConfig.ts
- wxpay: publicKey and publicKeyId are now required (was optional), matching
the pubkey-only verifier direction; certSerial is already required.
This PR is drop-in safe: reason-preferring extractApiErrorCode is backward
compatible with callers that pass their own i18nMap, and error codes missing
from i18n fall back to the existing message-based path.
This commit is contained in:
@@ -5432,7 +5432,33 @@ export default {
|
||||
errors: {
|
||||
tooManyPending: 'Too many pending orders (max {max}). Please complete or cancel existing orders first.',
|
||||
cancelRateLimited: 'Too many cancellations. Please try again later.',
|
||||
// Structured error codes (reason strings from backend ApplicationError)
|
||||
PAYMENT_DISABLED: 'Payment system is disabled.',
|
||||
USER_INACTIVE: 'Your account is disabled.',
|
||||
BALANCE_PAYMENT_DISABLED: 'Balance recharge has been disabled.',
|
||||
INVALID_AMOUNT: 'Invalid amount.',
|
||||
INVALID_INPUT: 'Invalid request.',
|
||||
PLAN_NOT_AVAILABLE: 'Plan not found or no longer available.',
|
||||
GROUP_NOT_FOUND: 'Subscription group is no longer available.',
|
||||
GROUP_TYPE_MISMATCH: 'Group is not a subscription type.',
|
||||
TOO_MANY_PENDING: 'Too many pending orders (max {max}). Please complete or cancel existing orders first.',
|
||||
DAILY_LIMIT_EXCEEDED: 'Daily recharge limit reached. Remaining: {remaining}.',
|
||||
PAYMENT_GATEWAY_ERROR: 'Payment method is unavailable.',
|
||||
NO_AVAILABLE_INSTANCE: 'No payment channel available right now.',
|
||||
PAYMENT_PROVIDER_MISCONFIGURED: 'Payment provider misconfigured. Please contact an administrator.',
|
||||
WXPAY_CONFIG_MISSING_KEY: 'WeChat Pay config missing required key: {key}.',
|
||||
WXPAY_CONFIG_INVALID_KEY_LENGTH: 'WeChat Pay {key} length is invalid (expected {expected} bytes, got {actual}).',
|
||||
WXPAY_CONFIG_INVALID_KEY: 'WeChat Pay {key} is malformed. Make sure you copied the full PEM content.',
|
||||
PENDING_ORDERS: 'This provider has pending orders. Please wait for them to complete before making changes.',
|
||||
CANCEL_RATE_LIMITED: 'Too many cancellations. Please try again later.',
|
||||
NOT_FOUND: 'Order not found.',
|
||||
FORBIDDEN: 'No permission for this order.',
|
||||
CONFLICT: 'Order status has changed. Please refresh.',
|
||||
INVALID_ORDER_TYPE: 'Only balance orders can request a refund.',
|
||||
INVALID_STATUS: 'The current order status does not allow this operation.',
|
||||
BALANCE_NOT_ENOUGH: 'Refund amount exceeds balance.',
|
||||
REFUND_AMOUNT_EXCEEDED: 'Refund amount exceeds the recharge amount.',
|
||||
REFUND_FAILED: 'Refund failed.',
|
||||
},
|
||||
stripePay: 'Pay Now',
|
||||
stripeSuccessProcessing: 'Payment successful, processing your order...',
|
||||
|
||||
Reference in New Issue
Block a user