• erio's avatar
    feat(payment): i18n payment error codes and label localization · 40d4e167
    erio authored
    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.
    40d4e167
apiError.ts 5.15 KB