✨ feat(payment): Add bank card payment
This commit is contained in:
parent
70d6a38a29
commit
7fa3a57df4
@ -1,5 +1,5 @@
|
||||
// @ts-ignore
|
||||
|
||||
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as ads from './ads';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// @ts-ignore
|
||||
|
||||
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as auth from './auth';
|
||||
|
||||
@ -106,7 +106,7 @@ export default function Page() {
|
||||
<dl className='grid gap-3'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<dt className='text-muted-foreground'>
|
||||
{data?.method && <Badge>{t(`methods.${data?.method}`)}</Badge>}
|
||||
{data?.method && <Badge>{data?.method}</Badge>}
|
||||
</dt>
|
||||
</div>
|
||||
</dl>
|
||||
@ -223,19 +223,19 @@ export default function Page() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{data?.status === 1 && payment?.type === 'stripe' && (
|
||||
{data?.status === 1 && payment?.type === 'Stripe' && (
|
||||
<div className='flex flex-col items-center gap-8 text-center'>
|
||||
<h3 className='text-2xl font-bold tracking-tight'>{t('scanToPay')}</h3>
|
||||
<h3 className='text-2xl font-bold tracking-tight'>{t('waitingForPayment')}</h3>
|
||||
<p className='flex items-center text-3xl font-bold'>{countdownDisplay}</p>
|
||||
{payment.stripe && <StripePayment {...payment.stripe} />}
|
||||
<div className='flex gap-4'>
|
||||
{/* <div className='flex gap-4'>
|
||||
<Button asChild>
|
||||
<Link href='/subscribe'>{t('productList')}</Link>
|
||||
</Button>
|
||||
<Button asChild variant='outline'>
|
||||
<Link href='/order'>{t('orderList')}</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@ -1,5 +1,23 @@
|
||||
import { Elements, useStripe } from '@stripe/react-stripe-js';
|
||||
import { loadStripe, PaymentIntentResult } from '@stripe/stripe-js';
|
||||
import {
|
||||
CardCvcElement,
|
||||
CardExpiryElement,
|
||||
CardNumberElement,
|
||||
Elements,
|
||||
useElements,
|
||||
useStripe,
|
||||
} from '@stripe/react-stripe-js';
|
||||
import {
|
||||
loadStripe,
|
||||
PaymentIntentResult,
|
||||
StripeCardNumberElementOptions,
|
||||
StripeElementStyle,
|
||||
} from '@stripe/stripe-js';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import { Input } from '@workspace/ui/components/input';
|
||||
import { Label } from '@workspace/ui/components/label';
|
||||
import { CheckCircle } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { QRCodeCanvas } from 'qrcode.react';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
@ -9,6 +27,196 @@ interface StripePaymentProps {
|
||||
publishable_key: string;
|
||||
}
|
||||
|
||||
interface CardPaymentFormProps {
|
||||
clientSecret: string;
|
||||
onError: (message: string) => void;
|
||||
}
|
||||
|
||||
const CardPaymentForm: React.FC<CardPaymentFormProps> = ({ clientSecret, onError }) => {
|
||||
const stripe = useStripe();
|
||||
const { theme, systemTheme } = useTheme();
|
||||
const elements = useElements();
|
||||
const [processing, setProcessing] = useState(false);
|
||||
const [succeeded, setSucceeded] = useState(false);
|
||||
const [errors, setErrors] = useState<{
|
||||
cardNumber?: string;
|
||||
cardExpiry?: string;
|
||||
cardCvc?: string;
|
||||
name?: string;
|
||||
}>({});
|
||||
const [cardholderName, setCardholderName] = useState('');
|
||||
const t = useTranslations('payment.stripe.card');
|
||||
|
||||
const currentTheme = theme === 'system' ? systemTheme : theme;
|
||||
const elementStyle: StripeElementStyle = {
|
||||
base: {
|
||||
'fontSize': '16px',
|
||||
'color': currentTheme === 'dark' ? '#fff' : '#000',
|
||||
'::placeholder': {
|
||||
color: '#aab7c4',
|
||||
},
|
||||
},
|
||||
invalid: {
|
||||
color: '#EF4444',
|
||||
iconColor: '#EF4444',
|
||||
},
|
||||
};
|
||||
|
||||
const elementOptions: StripeCardNumberElementOptions = {
|
||||
style: elementStyle,
|
||||
showIcon: true,
|
||||
};
|
||||
|
||||
const handleChange = (event: any, field: keyof typeof errors) => {
|
||||
if (event.error) {
|
||||
setErrors((prev) => ({ ...prev, [field]: event.error.message }));
|
||||
} else {
|
||||
setErrors((prev) => ({ ...prev, [field]: undefined }));
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (!stripe || !elements) {
|
||||
onError(t('loading'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cardholderName.trim()) {
|
||||
setErrors((prev) => ({ ...prev, name: t('name_required') }));
|
||||
return;
|
||||
}
|
||||
|
||||
setProcessing(true);
|
||||
|
||||
const cardNumber = elements.getElement(CardNumberElement);
|
||||
const cardExpiry = elements.getElement(CardExpiryElement);
|
||||
const cardCvc = elements.getElement(CardCvcElement);
|
||||
|
||||
if (!cardNumber || !cardExpiry || !cardCvc) {
|
||||
onError(t('element_error'));
|
||||
setProcessing(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const { error, paymentIntent } = await stripe.confirmCardPayment(clientSecret, {
|
||||
payment_method: {
|
||||
card: cardNumber,
|
||||
billing_details: {
|
||||
name: cardholderName,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (error) {
|
||||
onError(error.message || t('payment_failed'));
|
||||
setProcessing(false);
|
||||
} else if (paymentIntent && paymentIntent.status === 'succeeded') {
|
||||
setSucceeded(true);
|
||||
setProcessing(false);
|
||||
} else {
|
||||
onError(t('processing'));
|
||||
setProcessing(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
{succeeded ? (
|
||||
<div className='py-6 text-center'>
|
||||
<div className='mb-4 flex justify-center'>
|
||||
<CheckCircle className='h-12 w-12 text-green-500' />
|
||||
</div>
|
||||
<p className='text-xl font-medium'>{t('success_title')}</p>
|
||||
<p className='text-muted-foreground mt-2'>{t('success_message')}</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className='space-y-4'>
|
||||
{/* Cardholder Name */}
|
||||
<div className='space-y-1'>
|
||||
<Label htmlFor='cardholderName' className='text-sm font-medium'>
|
||||
{t('card_name')}
|
||||
</Label>
|
||||
<Input
|
||||
id='cardholderName'
|
||||
type='text'
|
||||
value={cardholderName}
|
||||
onChange={(e) => setCardholderName(e.target.value)}
|
||||
placeholder={t('name_placeholder')}
|
||||
className={errors.name ? 'border-red-500' : ''}
|
||||
/>
|
||||
{errors.name && <p className='text-xs text-red-500'>{errors.name}</p>}
|
||||
</div>
|
||||
|
||||
{/* Card Number */}
|
||||
<div className='space-y-1'>
|
||||
<Label htmlFor='cardNumber' className='text-sm font-medium'>
|
||||
{t('card_number')}
|
||||
</Label>
|
||||
<div className='relative'>
|
||||
<div
|
||||
className={`focus-within:border-primary focus-within:ring-primary rounded-md border p-3 focus-within:ring-1 ${errors.cardNumber ? 'border-red-500' : ''}`}
|
||||
>
|
||||
<CardNumberElement
|
||||
id='cardNumber'
|
||||
options={elementOptions}
|
||||
onChange={(e) => handleChange(e, 'cardNumber')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{errors.cardNumber && <p className='text-xs text-red-500'>{errors.cardNumber}</p>}
|
||||
</div>
|
||||
|
||||
<div className='grid grid-cols-2 gap-4'>
|
||||
{/* Expiry Date */}
|
||||
<div className='space-y-1'>
|
||||
<Label htmlFor='cardExpiry' className='text-sm font-medium'>
|
||||
{t('expiry_date')}
|
||||
</Label>
|
||||
<div
|
||||
className={`focus-within:border-primary focus-within:ring-primary rounded-md border p-3 focus-within:ring-1 ${errors.cardExpiry ? 'border-red-500' : ''}`}
|
||||
>
|
||||
<CardExpiryElement
|
||||
id='cardExpiry'
|
||||
options={{ style: elementStyle }}
|
||||
onChange={(e) => handleChange(e, 'cardExpiry')}
|
||||
/>
|
||||
</div>
|
||||
{errors.cardExpiry && <p className='text-xs text-red-500'>{errors.cardExpiry}</p>}
|
||||
</div>
|
||||
|
||||
{/* Security Code */}
|
||||
<div className='space-y-1'>
|
||||
<Label htmlFor='cardCvc' className='text-sm font-medium'>
|
||||
{t('security_code')}
|
||||
</Label>
|
||||
<div
|
||||
className={`focus-within:border-primary focus-within:ring-primary rounded-md border p-3 focus-within:ring-1 ${errors.cardCvc ? 'border-red-500' : ''}`}
|
||||
>
|
||||
<CardCvcElement
|
||||
id='cardCvc'
|
||||
options={{ style: elementStyle }}
|
||||
onChange={(e) => handleChange(e, 'cardCvc')}
|
||||
/>
|
||||
</div>
|
||||
{errors.cardCvc && <p className='text-xs text-red-500'>{errors.cardCvc}</p>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-6 flex flex-col space-y-4'>
|
||||
<Button type='submit' disabled={processing || !stripe || !elements} className='w-full'>
|
||||
{processing ? t('processing_button') : t('pay_button')}
|
||||
</Button>
|
||||
<p className='text-muted-foreground text-center text-xs'>{t('secure_notice')}</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
const StripePayment: React.FC<StripePaymentProps> = ({
|
||||
method,
|
||||
client_secret,
|
||||
@ -31,6 +239,7 @@ const CheckoutForm: React.FC<Omit<StripePaymentProps, 'publishable_key'>> = ({
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);
|
||||
const [isSubmitted, setIsSubmitted] = useState(false);
|
||||
const t = useTranslations('payment.stripe');
|
||||
|
||||
const handleError = useCallback((message: string) => {
|
||||
setErrorMessage(message);
|
||||
@ -39,7 +248,7 @@ const CheckoutForm: React.FC<Omit<StripePaymentProps, 'publishable_key'>> = ({
|
||||
|
||||
const confirmPayment = useCallback(async (): Promise<PaymentIntentResult | null> => {
|
||||
if (!stripe) {
|
||||
handleError('Stripe.js is not loaded.');
|
||||
handleError(t('card.loading'));
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -50,18 +259,20 @@ const CheckoutForm: React.FC<Omit<StripePaymentProps, 'publishable_key'>> = ({
|
||||
{ handleActions: false },
|
||||
);
|
||||
}
|
||||
|
||||
return await stripe.confirmWechatPayPayment(
|
||||
client_secret,
|
||||
{
|
||||
payment_method_options: { wechat_pay: { client: 'web' } },
|
||||
},
|
||||
{ handleActions: false },
|
||||
);
|
||||
}, [client_secret, method, stripe, handleError]);
|
||||
if (method === 'wechat_pay') {
|
||||
return await stripe.confirmWechatPayPayment(
|
||||
client_secret,
|
||||
{
|
||||
payment_method_options: { wechat_pay: { client: 'web' } },
|
||||
},
|
||||
{ handleActions: false },
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}, [client_secret, method, stripe, handleError, t]);
|
||||
|
||||
const autoSubmit = useCallback(async () => {
|
||||
if (isSubmitted) return;
|
||||
if (isSubmitted || method === 'card') return;
|
||||
|
||||
setIsSubmitted(true);
|
||||
|
||||
@ -82,25 +293,32 @@ const CheckoutForm: React.FC<Omit<StripePaymentProps, 'publishable_key'>> = ({
|
||||
setQrCodeUrl(qrUrl || null);
|
||||
}
|
||||
} catch (error) {
|
||||
handleError('An unexpected error occurred');
|
||||
handleError(t('error'));
|
||||
}
|
||||
}, [confirmPayment, isSubmitted, handleError, method]);
|
||||
}, [confirmPayment, isSubmitted, handleError, method, t]);
|
||||
|
||||
useEffect(() => {
|
||||
autoSubmit();
|
||||
}, [autoSubmit]);
|
||||
|
||||
return qrCodeUrl ? (
|
||||
<QRCodeCanvas
|
||||
value={qrCodeUrl}
|
||||
size={208}
|
||||
imageSettings={{
|
||||
src: `/payment/${method}.svg`,
|
||||
width: 24,
|
||||
height: 24,
|
||||
excavate: true,
|
||||
}}
|
||||
/>
|
||||
return method === 'card' ? (
|
||||
<div className='min-w-80 text-left'>
|
||||
<CardPaymentForm clientSecret={client_secret} onError={handleError} />
|
||||
</div>
|
||||
) : qrCodeUrl ? (
|
||||
<>
|
||||
<QRCodeCanvas
|
||||
value={qrCodeUrl}
|
||||
size={208}
|
||||
imageSettings={{
|
||||
src: `/payment/${method}.svg`,
|
||||
width: 24,
|
||||
height: 24,
|
||||
excavate: true,
|
||||
}}
|
||||
/>
|
||||
<p className='text-muted-foreground mt-4 text-center'>{t(`qrcode.${method}`)}</p>
|
||||
</>
|
||||
) : (
|
||||
errorMessage
|
||||
);
|
||||
|
||||
@ -4,6 +4,7 @@ import { getAvailablePaymentMethods } from '@/services/user/portal';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Label } from '@workspace/ui/components/label';
|
||||
import { RadioGroup, RadioGroupItem } from '@workspace/ui/components/radio-group';
|
||||
import { cn } from '@workspace/ui/lib/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import Image from 'next/image';
|
||||
import React, { memo } from 'react';
|
||||
@ -33,14 +34,24 @@ const PaymentMethods: React.FC<PaymentMethodsProps> = ({ value, onChange, balanc
|
||||
<RadioGroup
|
||||
className='grid grid-cols-2 gap-2 md:grid-cols-5'
|
||||
value={String(value)}
|
||||
onValueChange={(val) => onChange(Number(val))}
|
||||
onValueChange={(val) => {
|
||||
console.log(val);
|
||||
onChange(Number(val));
|
||||
}}
|
||||
>
|
||||
{data?.map((item) => (
|
||||
<div key={item.id}>
|
||||
<RadioGroupItem value={String(item.id)} id={String(item.id)} className='peer sr-only' />
|
||||
<div key={item.id} className='relative'>
|
||||
<RadioGroupItem
|
||||
value={String(item.id)}
|
||||
id={String(item.id)}
|
||||
className='absolute inset-0 z-10 h-full w-full cursor-pointer opacity-0'
|
||||
/>
|
||||
<Label
|
||||
htmlFor={String(item.id)}
|
||||
className='border-muted bg-popover hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary flex flex-col items-center justify-between rounded-md border-2 py-2'
|
||||
className={cn(
|
||||
'border-muted bg-popover hover:bg-accent hover:text-accent-foreground flex flex-col items-center justify-between rounded-md border-2 py-2',
|
||||
String(value) === String(item.id) ? 'border-primary' : '',
|
||||
)}
|
||||
>
|
||||
<div className='mb-3 size-12'>
|
||||
<Image
|
||||
|
||||
26
apps/user/locales/cs-CZ/payment.json
Normal file
26
apps/user/locales/cs-CZ/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Jméno držitele karty",
|
||||
"card_number": "Číslo karty",
|
||||
"element_error": "Nelze získat prvek karty.",
|
||||
"expiry_date": "Datum expirace",
|
||||
"loading": "Stripe.js není načten. Zkuste to prosím znovu později.",
|
||||
"name_placeholder": "Zadejte jméno držitele karty",
|
||||
"name_required": "Jméno držitele karty je povinné",
|
||||
"pay_button": "Zaplatit nyní",
|
||||
"payment_failed": "Platba se nezdařila, zkuste to prosím znovu.",
|
||||
"processing": "Platba se zpracovává, prosím zkontrolujte výsledek později.",
|
||||
"processing_button": "Zpracovává se...",
|
||||
"secure_notice": "Vaše platební informace jsou bezpečně šifrovány",
|
||||
"security_code": "Bezpečnostní kód",
|
||||
"success_message": "Děkujeme za vaši platbu!",
|
||||
"success_title": "Platba byla úspěšná"
|
||||
},
|
||||
"error": "Došlo k neočekávané chybě",
|
||||
"qrcode": {
|
||||
"alipay": "Naskenujte pomocí Alipay pro platbu",
|
||||
"wechat_pay": "Naskenujte pomocí WeChat pro platbu"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/de-DE/payment.json
Normal file
26
apps/user/locales/de-DE/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Karteninhabername",
|
||||
"card_number": "Kartennummer",
|
||||
"element_error": "Konnte das Kartenelement nicht abrufen.",
|
||||
"expiry_date": "Ablaufdatum",
|
||||
"loading": "Stripe.js ist nicht geladen. Bitte versuchen Sie es später erneut.",
|
||||
"name_placeholder": "Geben Sie den Namen des Karteninhabers ein",
|
||||
"name_required": "Der Name des Karteninhabers ist erforderlich",
|
||||
"pay_button": "Jetzt bezahlen",
|
||||
"payment_failed": "Zahlung fehlgeschlagen, bitte versuchen Sie es erneut.",
|
||||
"processing": "Zahlung wird verarbeitet, bitte überprüfen Sie das Ergebnis später.",
|
||||
"processing_button": "Wird verarbeitet...",
|
||||
"secure_notice": "Ihre Zahlungsinformationen sind sicher verschlüsselt",
|
||||
"security_code": "Sicherheitscode",
|
||||
"success_message": "Vielen Dank für Ihre Zahlung!",
|
||||
"success_title": "Zahlung Erfolgreich"
|
||||
},
|
||||
"error": "Ein unerwarteter Fehler ist aufgetreten",
|
||||
"qrcode": {
|
||||
"alipay": "Mit Alipay scannen, um zu bezahlen",
|
||||
"wechat_pay": "Mit WeChat scannen, um zu bezahlen"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/en-US/payment.json
Normal file
26
apps/user/locales/en-US/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Cardholder Name",
|
||||
"card_number": "Card Number",
|
||||
"element_error": "Unable to get card element.",
|
||||
"expiry_date": "Expiry Date",
|
||||
"loading": "Stripe.js is not loaded. Please try again later.",
|
||||
"name_placeholder": "Enter cardholder name",
|
||||
"name_required": "Cardholder name is required",
|
||||
"pay_button": "Pay Now",
|
||||
"payment_failed": "Payment failed, please try again.",
|
||||
"processing": "Payment processing, please check the result later.",
|
||||
"processing_button": "Processing...",
|
||||
"secure_notice": "Your payment information is securely encrypted",
|
||||
"security_code": "Security Code",
|
||||
"success_message": "Thank you for your payment!",
|
||||
"success_title": "Payment Successful"
|
||||
},
|
||||
"error": "An unexpected error occurred",
|
||||
"qrcode": {
|
||||
"alipay": "Scan with Alipay to pay",
|
||||
"wechat_pay": "Scan with WeChat to pay"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/es-ES/payment.json
Normal file
26
apps/user/locales/es-ES/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Nombre del titular de la tarjeta",
|
||||
"card_number": "Número de tarjeta",
|
||||
"element_error": "No se pudo obtener el elemento de la tarjeta.",
|
||||
"expiry_date": "Fecha de caducidad",
|
||||
"loading": "Stripe.js no está cargado. Por favor, inténtalo de nuevo más tarde.",
|
||||
"name_placeholder": "Introduce el nombre del titular de la tarjeta",
|
||||
"name_required": "Se requiere el nombre del titular de la tarjeta",
|
||||
"pay_button": "Pagar Ahora",
|
||||
"payment_failed": "El pago ha fallado, por favor inténtalo de nuevo.",
|
||||
"processing": "Procesando el pago, por favor verifica el resultado más tarde.",
|
||||
"processing_button": "Procesando...",
|
||||
"secure_notice": "Tu información de pago está encriptada de forma segura",
|
||||
"security_code": "Código de seguridad",
|
||||
"success_message": "¡Gracias por tu pago!",
|
||||
"success_title": "Pago Exitoso"
|
||||
},
|
||||
"error": "Ocurrió un error inesperado",
|
||||
"qrcode": {
|
||||
"alipay": "Escanea con Alipay para pagar",
|
||||
"wechat_pay": "Escanea con WeChat para pagar"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/es-MX/payment.json
Normal file
26
apps/user/locales/es-MX/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Nombre del titular de la tarjeta",
|
||||
"card_number": "Número de tarjeta",
|
||||
"element_error": "No se pudo obtener el elemento de la tarjeta.",
|
||||
"expiry_date": "Fecha de expiración",
|
||||
"loading": "Stripe.js no se ha cargado. Por favor, inténtalo de nuevo más tarde.",
|
||||
"name_placeholder": "Ingresa el nombre del titular de la tarjeta",
|
||||
"name_required": "Se requiere el nombre del titular de la tarjeta",
|
||||
"pay_button": "Pagar Ahora",
|
||||
"payment_failed": "El pago falló, por favor inténtalo de nuevo.",
|
||||
"processing": "Procesando el pago, por favor verifica el resultado más tarde.",
|
||||
"processing_button": "Procesando...",
|
||||
"secure_notice": "Tu información de pago está encriptada de forma segura",
|
||||
"security_code": "Código de seguridad",
|
||||
"success_message": "¡Gracias por tu pago!",
|
||||
"success_title": "Pago Exitoso"
|
||||
},
|
||||
"error": "Ocurrió un error inesperado",
|
||||
"qrcode": {
|
||||
"alipay": "Escanea con Alipay para pagar",
|
||||
"wechat_pay": "Escanea con WeChat para pagar"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/fa-IR/payment.json
Normal file
26
apps/user/locales/fa-IR/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "نام دارنده کارت",
|
||||
"card_number": "شماره کارت",
|
||||
"element_error": "عدم توانایی در دریافت عنصر کارت.",
|
||||
"expiry_date": "تاریخ انقضا",
|
||||
"loading": "Stripe.js بارگذاری نشده است. لطفاً بعداً دوباره تلاش کنید.",
|
||||
"name_placeholder": "نام دارنده کارت را وارد کنید",
|
||||
"name_required": "نام دارنده کارت الزامی است",
|
||||
"pay_button": "همین حالا پرداخت کنید",
|
||||
"payment_failed": "پرداخت ناموفق بود، لطفاً دوباره تلاش کنید.",
|
||||
"processing": "پرداخت در حال پردازش است، لطفاً نتیجه را بعداً بررسی کنید.",
|
||||
"processing_button": "در حال پردازش...",
|
||||
"secure_notice": "اطلاعات پرداخت شما به صورت ایمن رمزگذاری شده است",
|
||||
"security_code": "کد امنیتی",
|
||||
"success_message": "از پرداخت شما متشکریم!",
|
||||
"success_title": "پرداخت موفق"
|
||||
},
|
||||
"error": "یک خطای غیرمنتظره رخ داده است",
|
||||
"qrcode": {
|
||||
"alipay": "برای پرداخت با Alipay اسکن کنید",
|
||||
"wechat_pay": "برای پرداخت با WeChat اسکن کنید"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/fi-FI/payment.json
Normal file
26
apps/user/locales/fi-FI/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Kortinhaltijan nimi",
|
||||
"card_number": "Korttinumero",
|
||||
"element_error": "Korttielementtiä ei voitu saada.",
|
||||
"expiry_date": "Voimassaoloaika",
|
||||
"loading": "Stripe.js ei ole ladattu. Yritä myöhemmin uudelleen.",
|
||||
"name_placeholder": "Syötä kortinhaltijan nimi",
|
||||
"name_required": "Kortinhaltijan nimi on pakollinen",
|
||||
"pay_button": "Maksa nyt",
|
||||
"payment_failed": "Maksu epäonnistui, yritä uudelleen.",
|
||||
"processing": "Maksua käsitellään, tarkista tulos myöhemmin.",
|
||||
"processing_button": "Käsitellään...",
|
||||
"secure_notice": "Maksutietosi on salattu turvallisesti",
|
||||
"security_code": "Turvakoodi",
|
||||
"success_message": "Kiitos maksustasi!",
|
||||
"success_title": "Maksu onnistui"
|
||||
},
|
||||
"error": "Odottamaton virhe tapahtui",
|
||||
"qrcode": {
|
||||
"alipay": "Skannaa Alipaylla maksamista varten",
|
||||
"wechat_pay": "Skannaa WeChatilla maksamista varten"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/fr-FR/payment.json
Normal file
26
apps/user/locales/fr-FR/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Nom du titulaire de la carte",
|
||||
"card_number": "Numéro de la carte",
|
||||
"element_error": "Impossible d'obtenir l'élément de carte.",
|
||||
"expiry_date": "Date d'expiration",
|
||||
"loading": "Stripe.js n'est pas chargé. Veuillez réessayer plus tard.",
|
||||
"name_placeholder": "Entrez le nom du titulaire de la carte",
|
||||
"name_required": "Le nom du titulaire de la carte est requis",
|
||||
"pay_button": "Payer maintenant",
|
||||
"payment_failed": "Le paiement a échoué, veuillez réessayer.",
|
||||
"processing": "Traitement du paiement, veuillez vérifier le résultat plus tard.",
|
||||
"processing_button": "Traitement...",
|
||||
"secure_notice": "Vos informations de paiement sont cryptées de manière sécurisée",
|
||||
"security_code": "Code de sécurité",
|
||||
"success_message": "Merci pour votre paiement !",
|
||||
"success_title": "Paiement réussi"
|
||||
},
|
||||
"error": "Une erreur inattendue est survenue",
|
||||
"qrcode": {
|
||||
"alipay": "Scannez avec Alipay pour payer",
|
||||
"wechat_pay": "Scannez avec WeChat pour payer"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/hi-IN/payment.json
Normal file
26
apps/user/locales/hi-IN/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "कार्डधारक का नाम",
|
||||
"card_number": "कार्ड नंबर",
|
||||
"element_error": "कार्ड तत्व प्राप्त करने में असमर्थ।",
|
||||
"expiry_date": "समाप्ति तिथि",
|
||||
"loading": "Stripe.js लोड नहीं हुआ है। कृपया बाद में पुनः प्रयास करें।",
|
||||
"name_placeholder": "कार्डधारक का नाम दर्ज करें",
|
||||
"name_required": "कार्डधारक का नाम आवश्यक है",
|
||||
"pay_button": "अभी भुगतान करें",
|
||||
"payment_failed": "भुगतान विफल, कृपया पुनः प्रयास करें।",
|
||||
"processing": "भुगतान प्रक्रिया में है, कृपया बाद में परिणाम जांचें।",
|
||||
"processing_button": "प्रसंस्करण हो रहा है...",
|
||||
"secure_notice": "आपकी भुगतान जानकारी सुरक्षित रूप से एन्क्रिप्ट की गई है",
|
||||
"security_code": "सुरक्षा कोड",
|
||||
"success_message": "आपके भुगतान के लिए धन्यवाद!",
|
||||
"success_title": "भुगतान सफल"
|
||||
},
|
||||
"error": "एक अप्रत्याशित त्रुटि हुई",
|
||||
"qrcode": {
|
||||
"alipay": "भुगतान करने के लिए Alipay के साथ स्कैन करें",
|
||||
"wechat_pay": "भुगतान करने के लिए WeChat के साथ स्कैन करें"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/hu-HU/payment.json
Normal file
26
apps/user/locales/hu-HU/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Kártyabirtokos neve",
|
||||
"card_number": "Kártyaszám",
|
||||
"element_error": "Nem sikerült megszerezni a kártya elemet.",
|
||||
"expiry_date": "Lejárati dátum",
|
||||
"loading": "A Stripe.js nem töltődött be. Kérjük, próbálja újra később.",
|
||||
"name_placeholder": "Írd be a kártyabirtokos nevét",
|
||||
"name_required": "A kártyabirtokos neve kötelező",
|
||||
"pay_button": "Fizetés most",
|
||||
"payment_failed": "A fizetés meghiúsult, kérjük, próbálja újra.",
|
||||
"processing": "Fizetés feldolgozása, kérjük, ellenőrizze az eredményt később.",
|
||||
"processing_button": "Feldolgozás...",
|
||||
"secure_notice": "A fizetési információi biztonságosan titkosítva vannak",
|
||||
"security_code": "Biztonsági kód",
|
||||
"success_message": "Köszönjük a fizetését!",
|
||||
"success_title": "Fizetés Sikeres"
|
||||
},
|
||||
"error": "Váratlan hiba történt",
|
||||
"qrcode": {
|
||||
"alipay": "Fizesd a Alipay segítségével",
|
||||
"wechat_pay": "Fizesd a WeChat segítségével"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/ja-JP/payment.json
Normal file
26
apps/user/locales/ja-JP/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "カード名義人",
|
||||
"card_number": "カード番号",
|
||||
"element_error": "カード要素を取得できませんでした。",
|
||||
"expiry_date": "有効期限",
|
||||
"loading": "Stripe.jsが読み込まれていません。後でもう一度お試しください。",
|
||||
"name_placeholder": "カード名義人を入力してください",
|
||||
"name_required": "カード名義人は必須です",
|
||||
"pay_button": "今すぐ支払う",
|
||||
"payment_failed": "支払いに失敗しました。もう一度お試しください。",
|
||||
"processing": "支払い処理中です。結果を後で確認してください。",
|
||||
"processing_button": "処理中...",
|
||||
"secure_notice": "お支払い情報は安全に暗号化されています",
|
||||
"security_code": "セキュリティコード",
|
||||
"success_message": "お支払いありがとうございます!",
|
||||
"success_title": "支払い成功"
|
||||
},
|
||||
"error": "予期しないエラーが発生しました",
|
||||
"qrcode": {
|
||||
"alipay": "Alipayで支払うにはスキャンしてください",
|
||||
"wechat_pay": "WeChatで支払うにはスキャンしてください"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/ko-KR/payment.json
Normal file
26
apps/user/locales/ko-KR/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "카드 소지자 이름",
|
||||
"card_number": "카드 번호",
|
||||
"element_error": "카드 요소를 가져올 수 없습니다.",
|
||||
"expiry_date": "유효 기간",
|
||||
"loading": "Stripe.js가 로드되지 않았습니다. 나중에 다시 시도해 주세요.",
|
||||
"name_placeholder": "카드 소지자 이름을 입력하세요",
|
||||
"name_required": "카드 소지자 이름은 필수입니다",
|
||||
"pay_button": "지금 결제하기",
|
||||
"payment_failed": "결제에 실패했습니다. 다시 시도해 주세요.",
|
||||
"processing": "결제 처리 중입니다. 결과를 나중에 확인해 주세요.",
|
||||
"processing_button": "처리 중...",
|
||||
"secure_notice": "귀하의 결제 정보는 안전하게 암호화됩니다.",
|
||||
"security_code": "보안 코드",
|
||||
"success_message": "결제해 주셔서 감사합니다!",
|
||||
"success_title": "결제 성공"
|
||||
},
|
||||
"error": "예기치 않은 오류가 발생했습니다.",
|
||||
"qrcode": {
|
||||
"alipay": "Alipay로 스캔하여 결제하세요",
|
||||
"wechat_pay": "WeChat으로 스캔하여 결제하세요"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/no-NO/payment.json
Normal file
26
apps/user/locales/no-NO/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Kortholderens navn",
|
||||
"card_number": "Kortnummer",
|
||||
"element_error": "Kunne ikke hente kortelement.",
|
||||
"expiry_date": "Utløpsdato",
|
||||
"loading": "Stripe.js er ikke lastet inn. Vennligst prøv igjen senere.",
|
||||
"name_placeholder": "Skriv inn kortholderens navn",
|
||||
"name_required": "Kortholderens navn er påkrevd",
|
||||
"pay_button": "Betal Nå",
|
||||
"payment_failed": "Betaling mislyktes, vennligst prøv igjen.",
|
||||
"processing": "Betaling behandles, vennligst sjekk resultatet senere.",
|
||||
"processing_button": "Behandler...",
|
||||
"secure_notice": "Din betalingsinformasjon er sikkert kryptert",
|
||||
"security_code": "Sikkerhetskode",
|
||||
"success_message": "Takk for betalingen!",
|
||||
"success_title": "Betaling Vel Lykket"
|
||||
},
|
||||
"error": "En uventet feil oppstod",
|
||||
"qrcode": {
|
||||
"alipay": "Skann med Alipay for å betale",
|
||||
"wechat_pay": "Skann med WeChat for å betale"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/pl-PL/payment.json
Normal file
26
apps/user/locales/pl-PL/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Imię i nazwisko posiadacza karty",
|
||||
"card_number": "Numer karty",
|
||||
"element_error": "Nie można uzyskać elementu karty.",
|
||||
"expiry_date": "Data ważności",
|
||||
"loading": "Stripe.js nie został załadowany. Proszę spróbować ponownie później.",
|
||||
"name_placeholder": "Wprowadź imię i nazwisko posiadacza karty",
|
||||
"name_required": "Imię i nazwisko posiadacza karty jest wymagane",
|
||||
"pay_button": "Zapłać teraz",
|
||||
"payment_failed": "Płatność nie powiodła się, proszę spróbować ponownie.",
|
||||
"processing": "Przetwarzanie płatności, proszę sprawdzić wynik później.",
|
||||
"processing_button": "Przetwarzanie...",
|
||||
"secure_notice": "Twoje dane płatnicze są bezpiecznie szyfrowane",
|
||||
"security_code": "Kod zabezpieczający",
|
||||
"success_message": "Dziękujemy za dokonanie płatności!",
|
||||
"success_title": "Płatność zakończona sukcesem"
|
||||
},
|
||||
"error": "Wystąpił nieoczekiwany błąd",
|
||||
"qrcode": {
|
||||
"alipay": "Skanuj z Alipay, aby zapłacić",
|
||||
"wechat_pay": "Skanuj z WeChat, aby zapłacić"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/pt-BR/payment.json
Normal file
26
apps/user/locales/pt-BR/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Nome do Titular",
|
||||
"card_number": "Número do Cartão",
|
||||
"element_error": "Não foi possível obter o elemento do cartão.",
|
||||
"expiry_date": "Data de Validade",
|
||||
"loading": "Stripe.js não está carregado. Por favor, tente novamente mais tarde.",
|
||||
"name_placeholder": "Digite o nome do titular",
|
||||
"name_required": "O nome do titular é obrigatório",
|
||||
"pay_button": "Pagar Agora",
|
||||
"payment_failed": "Pagamento falhou, por favor tente novamente.",
|
||||
"processing": "Processando pagamento, por favor verifique o resultado mais tarde.",
|
||||
"processing_button": "Processando...",
|
||||
"secure_notice": "Suas informações de pagamento estão criptografadas com segurança",
|
||||
"security_code": "Código de Segurança",
|
||||
"success_message": "Obrigado pelo seu pagamento!",
|
||||
"success_title": "Pagamento Bem-Sucedido"
|
||||
},
|
||||
"error": "Ocorreu um erro inesperado",
|
||||
"qrcode": {
|
||||
"alipay": "Escaneie com Alipay para pagar",
|
||||
"wechat_pay": "Escaneie com WeChat para pagar"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -19,6 +19,7 @@ export default getRequestConfig(async () => {
|
||||
profile: (await import(`./${locale}/profile.json`)).default,
|
||||
subscribe: (await import(`./${locale}/subscribe.json`)).default,
|
||||
order: (await import(`./${locale}/order.json`)).default,
|
||||
payment: (await import(`./${locale}/payment.json`)).default,
|
||||
wallet: (await import(`./${locale}/wallet.json`)).default,
|
||||
ticket: (await import(`./${locale}/ticket.json`)).default,
|
||||
document: (await import(`./${locale}/document.json`)).default,
|
||||
|
||||
26
apps/user/locales/ro-RO/payment.json
Normal file
26
apps/user/locales/ro-RO/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Numele titularului cardului",
|
||||
"card_number": "Numărul cardului",
|
||||
"element_error": "Nu s-a putut obține elementul cardului.",
|
||||
"expiry_date": "Data expirării",
|
||||
"loading": "Stripe.js nu este încărcat. Vă rugăm să încercați din nou mai târziu.",
|
||||
"name_placeholder": "Introduceți numele titularului cardului",
|
||||
"name_required": "Numele titularului cardului este necesar",
|
||||
"pay_button": "Plătește acum",
|
||||
"payment_failed": "Plata a eșuat, vă rugăm să încercați din nou.",
|
||||
"processing": "Plata este în procesare, vă rugăm să verificați rezultatul mai târziu.",
|
||||
"processing_button": "Se procesează...",
|
||||
"secure_notice": "Informațiile dumneavoastră de plată sunt criptate în siguranță",
|
||||
"security_code": "Cod de securitate",
|
||||
"success_message": "Vă mulțumim pentru plata dumneavoastră!",
|
||||
"success_title": "Plata a fost efectuată cu succes"
|
||||
},
|
||||
"error": "A apărut o eroare neașteptată",
|
||||
"qrcode": {
|
||||
"alipay": "Scanați cu Alipay pentru a plăti",
|
||||
"wechat_pay": "Scanați cu WeChat pentru a plăti"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/ru-RU/payment.json
Normal file
26
apps/user/locales/ru-RU/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Имя держателя карты",
|
||||
"card_number": "Номер карты",
|
||||
"element_error": "Не удалось получить элемент карты.",
|
||||
"expiry_date": "Срок действия",
|
||||
"loading": "Stripe.js не загружен. Пожалуйста, попробуйте позже.",
|
||||
"name_placeholder": "Введите имя держателя карты",
|
||||
"name_required": "Имя держателя карты обязательно",
|
||||
"pay_button": "Оплатить сейчас",
|
||||
"payment_failed": "Платеж не удался, пожалуйста, попробуйте снова.",
|
||||
"processing": "Обработка платежа, пожалуйста, проверьте результат позже.",
|
||||
"processing_button": "Обработка...",
|
||||
"secure_notice": "Ваша платежная информация надежно зашифрована",
|
||||
"security_code": "Код безопасности",
|
||||
"success_message": "Спасибо за ваш платеж!",
|
||||
"success_title": "Платеж успешен"
|
||||
},
|
||||
"error": "Произошла неожиданная ошибка",
|
||||
"qrcode": {
|
||||
"alipay": "Сканируйте с помощью Alipay для оплаты",
|
||||
"wechat_pay": "Сканируйте с помощью WeChat для оплаты"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/th-TH/payment.json
Normal file
26
apps/user/locales/th-TH/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "ชื่อผู้ถือบัตร",
|
||||
"card_number": "หมายเลขบัตร",
|
||||
"element_error": "ไม่สามารถดึงข้อมูลองค์ประกอบบัตรได้.",
|
||||
"expiry_date": "วันหมดอายุ",
|
||||
"loading": "ไม่สามารถโหลด Stripe.js ได้ กรุณาลองใหม่ในภายหลัง.",
|
||||
"name_placeholder": "กรอกชื่อผู้ถือบัตร",
|
||||
"name_required": "ชื่อผู้ถือบัตรเป็นสิ่งจำเป็น",
|
||||
"pay_button": "ชำระเงินตอนนี้",
|
||||
"payment_failed": "การชำระเงินล้มเหลว กรุณาลองใหม่อีกครั้ง.",
|
||||
"processing": "กำลังประมวลผลการชำระเงิน กรุณาตรวจสอบผลในภายหลัง.",
|
||||
"processing_button": "กำลังประมวลผล...",
|
||||
"secure_notice": "ข้อมูลการชำระเงินของคุณถูกเข้ารหัสอย่างปลอดภัย",
|
||||
"security_code": "รหัสความปลอดภัย",
|
||||
"success_message": "ขอบคุณสำหรับการชำระเงินของคุณ!",
|
||||
"success_title": "การชำระเงินสำเร็จ"
|
||||
},
|
||||
"error": "เกิดข้อผิดพลาดที่ไม่คาดคิด",
|
||||
"qrcode": {
|
||||
"alipay": "สแกนด้วย Alipay เพื่อชำระเงิน",
|
||||
"wechat_pay": "สแกนด้วย WeChat เพื่อชำระเงิน"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/tr-TR/payment.json
Normal file
26
apps/user/locales/tr-TR/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Kart Sahibi Adı",
|
||||
"card_number": "Kart Numarası",
|
||||
"element_error": "Kart öğesi alınamadı.",
|
||||
"expiry_date": "Son Kullanma Tarihi",
|
||||
"loading": "Stripe.js yüklenmedi. Lütfen daha sonra tekrar deneyin.",
|
||||
"name_placeholder": "Kart sahibi adını girin",
|
||||
"name_required": "Kart sahibi adı gereklidir",
|
||||
"pay_button": "Şimdi Öde",
|
||||
"payment_failed": "Ödeme başarısız oldu, lütfen tekrar deneyin.",
|
||||
"processing": "Ödeme işleniyor, lütfen sonucu daha sonra kontrol edin.",
|
||||
"processing_button": "İşleniyor...",
|
||||
"secure_notice": "Ödeme bilgileriniz güvenli bir şekilde şifrelenmiştir.",
|
||||
"security_code": "Güvenlik Kodu",
|
||||
"success_message": "Ödemeniz için teşekkür ederiz!",
|
||||
"success_title": "Ödeme Başarılı"
|
||||
},
|
||||
"error": "Beklenmedik bir hata oluştu.",
|
||||
"qrcode": {
|
||||
"alipay": "Ödemek için Alipay ile tara",
|
||||
"wechat_pay": "Ödemek için WeChat ile tara"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/uk-UA/payment.json
Normal file
26
apps/user/locales/uk-UA/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Ім'я власника картки",
|
||||
"card_number": "Номер картки",
|
||||
"element_error": "Не вдалося отримати елемент картки.",
|
||||
"expiry_date": "Термін дії",
|
||||
"loading": "Stripe.js не завантажено. Будь ласка, спробуйте ще раз пізніше.",
|
||||
"name_placeholder": "Введіть ім'я власника картки",
|
||||
"name_required": "Ім'я власника картки обов'язкове",
|
||||
"pay_button": "Оплатити зараз",
|
||||
"payment_failed": "Платіж не вдався, будь ласка, спробуйте ще раз.",
|
||||
"processing": "Обробка платежу, будь ласка, перевірте результат пізніше.",
|
||||
"processing_button": "Обробка...",
|
||||
"secure_notice": "Ваша платіжна інформація надійно зашифрована",
|
||||
"security_code": "Код безпеки",
|
||||
"success_message": "Дякуємо за ваш платіж!",
|
||||
"success_title": "Платіж успішний"
|
||||
},
|
||||
"error": "Сталася несподівана помилка",
|
||||
"qrcode": {
|
||||
"alipay": "Скануйте з Alipay для оплати",
|
||||
"wechat_pay": "Скануйте з WeChat для оплати"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/vi-VN/payment.json
Normal file
26
apps/user/locales/vi-VN/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "Tên chủ thẻ",
|
||||
"card_number": "Số thẻ",
|
||||
"element_error": "Không thể lấy phần tử thẻ.",
|
||||
"expiry_date": "Ngày hết hạn",
|
||||
"loading": "Stripe.js chưa được tải. Vui lòng thử lại sau.",
|
||||
"name_placeholder": "Nhập tên chủ thẻ",
|
||||
"name_required": "Tên chủ thẻ là bắt buộc",
|
||||
"pay_button": "Thanh toán ngay",
|
||||
"payment_failed": "Thanh toán không thành công, vui lòng thử lại.",
|
||||
"processing": "Đang xử lý thanh toán, vui lòng kiểm tra kết quả sau.",
|
||||
"processing_button": "Đang xử lý...",
|
||||
"secure_notice": "Thông tin thanh toán của bạn được mã hóa an toàn",
|
||||
"security_code": "Mã bảo mật",
|
||||
"success_message": "Cảm ơn bạn đã thanh toán!",
|
||||
"success_title": "Thanh toán thành công"
|
||||
},
|
||||
"error": "Đã xảy ra lỗi không mong muốn",
|
||||
"qrcode": {
|
||||
"alipay": "Quét với Alipay để thanh toán",
|
||||
"wechat_pay": "Quét với WeChat để thanh toán"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/zh-CN/payment.json
Normal file
26
apps/user/locales/zh-CN/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "持卡人姓名",
|
||||
"card_number": "卡号",
|
||||
"element_error": "无法获取卡片元素。",
|
||||
"expiry_date": "有效期",
|
||||
"loading": "Stripe.js 未加载完成,请稍后再试。",
|
||||
"name_placeholder": "输入持卡人姓名",
|
||||
"name_required": "持卡人姓名为必填项",
|
||||
"pay_button": "立即支付",
|
||||
"payment_failed": "支付失败,请重试。",
|
||||
"processing": "支付处理中,请稍后查看结果。",
|
||||
"processing_button": "处理中...",
|
||||
"secure_notice": "您的支付信息已安全加密",
|
||||
"security_code": "安全码",
|
||||
"success_message": "感谢您的付款!",
|
||||
"success_title": "支付成功"
|
||||
},
|
||||
"error": "发生意外错误",
|
||||
"qrcode": {
|
||||
"alipay": "使用支付宝扫描支付",
|
||||
"wechat_pay": "使用微信扫描支付"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/user/locales/zh-HK/payment.json
Normal file
26
apps/user/locales/zh-HK/payment.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"stripe": {
|
||||
"card": {
|
||||
"card_name": "持卡人姓名",
|
||||
"card_number": "卡號",
|
||||
"element_error": "無法獲取卡片元素。",
|
||||
"expiry_date": "到期日",
|
||||
"loading": "Stripe.js 尚未加載。請稍後再試。",
|
||||
"name_placeholder": "請輸入持卡人姓名",
|
||||
"name_required": "持卡人姓名為必填項",
|
||||
"pay_button": "立即付款",
|
||||
"payment_failed": "付款失敗,請再試一次。",
|
||||
"processing": "付款處理中,請稍後查看結果。",
|
||||
"processing_button": "處理中...",
|
||||
"secure_notice": "您的付款信息已安全加密",
|
||||
"security_code": "安全碼",
|
||||
"success_message": "感謝您的付款!",
|
||||
"success_title": "付款成功"
|
||||
},
|
||||
"error": "發生意外錯誤",
|
||||
"qrcode": {
|
||||
"alipay": "用 Alipay 掃描付款",
|
||||
"wechat_pay": "用 WeChat 掃描付款"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
// @ts-ignore
|
||||
|
||||
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as auth from './auth';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// @ts-ignore
|
||||
|
||||
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as announcement from './announcement';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user