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:
@@ -56,7 +56,7 @@
|
||||
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { extractApiErrorMessage } from '@/utils/apiError'
|
||||
import { extractI18nErrorMessage } from '@/utils/apiError'
|
||||
import { isMobileDevice } from '@/utils/device'
|
||||
|
||||
interface StripeWithWechatPay {
|
||||
@@ -143,7 +143,7 @@ async function initStripe(clientSecret: string, publishableKey: string) {
|
||||
}
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
error.value = extractApiErrorMessage(err, t('payment.stripeLoadFailed'))
|
||||
error.value = extractI18nErrorMessage(err, t, 'payment.errors', t('payment.stripeLoadFailed'))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user