feat: 国际化处理
This commit is contained in:
parent
0d3b63c2fc
commit
01ac12c171
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@ -1,4 +1,7 @@
|
||||
{
|
||||
"chat.editor.fontSize": 16,
|
||||
"debug.console.fontSize": 14,
|
||||
"editor.fontSize": 16,
|
||||
"eslint.workingDirectories": [
|
||||
{
|
||||
"mode": "auto"
|
||||
@ -11,5 +14,7 @@
|
||||
"*.jsx": "${capture}.js",
|
||||
"*.tsx": "${capture}.ts",
|
||||
"README.md": "*.md, LICENSE"
|
||||
}
|
||||
},
|
||||
"scm.inputFontSize": 13,
|
||||
"terminal.integrated.fontSize": 12
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
DialogTitle,
|
||||
} from '@workspace/airo-ui/components/dialog';
|
||||
import { Pagination } from '@workspace/airo-ui/custom-components/pro-table/pagination';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useImperativeHandle, useRef, useState } from 'react';
|
||||
import { Popup, PopupData, PopupRef } from './Popup';
|
||||
|
||||
@ -37,6 +38,7 @@ interface DialogProps {
|
||||
}
|
||||
|
||||
export const AnnouncementDialog = ({ ref }: DialogProps) => {
|
||||
const t = useTranslations('dashboard');
|
||||
const [open, setOpen] = useState(false);
|
||||
const [pagination, setPagination] = useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
@ -101,12 +103,14 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => {
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent className='flex flex-col sm:grid sm:max-w-[600px]'>
|
||||
<DialogHeader>
|
||||
<DialogTitle className={'text-left text-2xl sm:text-4xl'}>网站公告</DialogTitle>
|
||||
<DialogTitle className={'text-left text-2xl sm:text-4xl'}>
|
||||
{t('announcementTitle')}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className='space-y-4'>
|
||||
{isLoading ? (
|
||||
<div className='py-8 text-center'>加载中...</div>
|
||||
<div className='py-8 text-center'>{t('loading')}</div>
|
||||
) : (
|
||||
<>
|
||||
{announcementData?.list?.map((item: AnnouncementItem) => {
|
||||
@ -116,7 +120,7 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => {
|
||||
className='flex items-center rounded-[20px] bg-[#B5C9E2] px-4 py-2 sm:p-4'
|
||||
>
|
||||
<p className='line-clamp-2 flex-1 text-[10px] text-[#225BA9] sm:text-sm'>
|
||||
{item.pinned && '【置顶公告】'}{' '}
|
||||
{item.pinned && t('pinnedAnnouncement')}{' '}
|
||||
<span className={`${item.pinned ? 'text-white' : 'text-[#4D4D4D]'}`}>
|
||||
{item.content}
|
||||
</span>
|
||||
@ -126,7 +130,7 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => {
|
||||
className='cursor-pointer text-xs text-[#225BA9] sm:text-sm'
|
||||
onClick={() => handleOpenPopup(item)}
|
||||
>
|
||||
查看详情
|
||||
{t('viewDetails')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -139,9 +143,9 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => {
|
||||
<Pagination
|
||||
table={table}
|
||||
text={{
|
||||
textRowsPerPage: '每页显示',
|
||||
textRowsPerPage: t('rowsPerPage'),
|
||||
textPageOf: (pageIndex, pageCount) =>
|
||||
`第 ${pageIndex} 页,共 ${pageCount} 页`,
|
||||
t('pageOf', { pageIndex: pageIndex, pageCount: pageCount }),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -111,7 +111,9 @@ export default function Content() {
|
||||
if (data && userSubscribe?.length > 0 && !userSubscribeProtocol.length) {
|
||||
const list = getUserSubscribe(userSubscribe[0]?.token, data.protocol);
|
||||
setUserSubscribeProtocol(list);
|
||||
setUserSubscribeProtocolCurrent(list[0]);
|
||||
if (list.length > 0) {
|
||||
setUserSubscribeProtocolCurrent(list[0]);
|
||||
}
|
||||
}
|
||||
}, [data, userSubscribe, userSubscribeProtocol.length]);
|
||||
|
||||
@ -129,7 +131,7 @@ export default function Content() {
|
||||
const currentIndex = userSubscribeProtocol.findIndex(
|
||||
(url) => url === userSubscribeProtocolCurrent,
|
||||
);
|
||||
return currentIndex !== -1 ? `${t('subscriptionUrl')}${currentIndex + 1}` : '地址1';
|
||||
return currentIndex !== -1 ? `${t('subscriptionUrl')}${currentIndex + 1}` : t('address1');
|
||||
};
|
||||
|
||||
const popupRef = useRef<PopupRef>(null);
|
||||
@ -140,19 +142,23 @@ export default function Content() {
|
||||
{/* 账户概况 Card */}
|
||||
<Card className='rounded-[20px] border border-[#D9D9D9] p-6 shadow-[0px_0px_52.6px_1px_rgba(15,44,83,0.05)]'>
|
||||
<div className='mb-1 sm:mb-4'>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>账户概况</h3>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>
|
||||
{t('accountOverview')}
|
||||
</h3>
|
||||
<p className='mt-1 text-xs text-[#666666] sm:text-sm'>
|
||||
{user?.auth_methods?.[0]?.auth_identifier}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='mb-3 sm:mb-6'>
|
||||
<span className='text-2xl font-medium text-[#091B33] sm:text-3xl'>年度套餐用户</span>
|
||||
<span className='text-2xl font-medium text-[#091B33] sm:text-3xl'>
|
||||
{t('annualPlanUser')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] px-4 py-[10px]'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<span className='text-sm font-light text-[#666666]'>账户余额</span>
|
||||
<span className='text-sm font-light text-[#666666]'>{t('accountBalance')}</span>
|
||||
<Recharge
|
||||
className={
|
||||
'border-0 bg-transparent p-0 text-sm font-normal text-[#225BA9] shadow-none outline-0 hover:bg-transparent'
|
||||
@ -170,21 +176,22 @@ export default function Content() {
|
||||
<div className='mb-4'>
|
||||
<h3 className='flex items-center justify-between text-[#666666]'>
|
||||
<div className={'flex items-center justify-between'}>
|
||||
<span className={'text-base font-medium sm:text-xl'}>套餐状态</span>
|
||||
<span className={'text-base font-medium sm:text-xl'}>{t('planStatus')}</span>
|
||||
<span className={'ml-2.5 rounded-full bg-[#A8D4ED] px-2 text-[8px] text-white'}>
|
||||
生效中
|
||||
{t('inEffect')}
|
||||
</span>
|
||||
</div>
|
||||
<ResetTraffic
|
||||
className={
|
||||
'border-0 bg-transparent p-0 text-sm font-normal text-[#225BA9] shadow-none outline-0 hover:bg-transparent'
|
||||
}
|
||||
id={userSubscribe?.[0]?.id}
|
||||
id={userSubscribe?.[0]?.id || 0}
|
||||
replacement={userSubscribe?.[0]?.subscribe.replacement}
|
||||
/>
|
||||
</h3>
|
||||
<div className='mb-2 text-sm text-[#666666] sm:mb-[22px] sm:mt-1'>
|
||||
套餐到期时间:{formatDate(userSubscribe?.[0]?.expire_time, false)}
|
||||
{t('planExpirationTime')}
|
||||
{formatDate(userSubscribe?.[0]?.expire_time, false)}
|
||||
</div>
|
||||
<div className='mb-3 sm:mb-6'>
|
||||
<span className='text-2xl font-medium text-[#091B33] sm:text-3xl'>
|
||||
@ -195,7 +202,7 @@ export default function Content() {
|
||||
|
||||
<div className='mb-4 flex items-center justify-between'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<span className='text-xs sm:text-sm'>可用设备</span>
|
||||
<span className='text-xs sm:text-sm'>{t('availableDevices')}</span>
|
||||
<div className='flex gap-2'>
|
||||
<div className='h-4 w-4 rounded-full bg-[#225BA9]'></div>
|
||||
<div className='h-4 w-4 rounded-full bg-[#D9D9D9]'></div>
|
||||
@ -206,13 +213,14 @@ export default function Content() {
|
||||
</div>
|
||||
</div>
|
||||
<span className='text-xs sm:text-sm'>
|
||||
在线:uu/{userSubscribe?.[0]?.subscribe.device_limit}
|
||||
{t('online')}
|
||||
{userSubscribe?.[0]?.subscribe.device_limit}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div className='mb-1 flex items-center justify-between'>
|
||||
<span className='text-xs sm:text-sm'>
|
||||
已使用流量/总流量:
|
||||
{t('usedTrafficTotalTraffic')}
|
||||
<Display
|
||||
type='traffic'
|
||||
value={userSubscribe?.[0]?.upload + userSubscribe?.[0]?.download}
|
||||
@ -226,20 +234,21 @@ export default function Content() {
|
||||
/>
|
||||
</span>
|
||||
<span className='text-xs sm:text-sm'>
|
||||
剩余:
|
||||
{t('remaining')}
|
||||
{100 -
|
||||
(
|
||||
(userSubscribe?.[0]?.upload + userSubscribe?.[0]?.download) /
|
||||
userSubscribe?.[0]?.traffic
|
||||
).toFixed(0)}
|
||||
Math.round(
|
||||
(((userSubscribe?.[0]?.upload || 0) + (userSubscribe?.[0]?.download || 0)) /
|
||||
(userSubscribe?.[0]?.traffic || 1)) *
|
||||
100,
|
||||
)}
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
<div className='flex h-5 w-full items-center rounded-[20px] bg-[#EAEAEA] p-0.5'>
|
||||
<div
|
||||
className='h-full rounded-[20px] bg-[#225BA9]'
|
||||
className={'h-full rounded-[20px] bg-[#225BA9]'}
|
||||
style={{
|
||||
width: `${((userSubscribe?.[0]?.upload + userSubscribe?.[0]?.download) / userSubscribe?.[0]?.traffic).toFixed(0)}%`,
|
||||
width: `${Math.round((((userSubscribe?.[0]?.upload || 0) + (userSubscribe?.[0]?.download || 0)) / (userSubscribe?.[0]?.traffic || 1)) * 100)}%`,
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
@ -251,13 +260,15 @@ export default function Content() {
|
||||
className={'absolute bottom-0 left-0 right-0 h-[60px] bg-white/30 backdrop-blur-[1px]'}
|
||||
></div>
|
||||
<div className='mb-3 flex items-center justify-between sm:mb-4'>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>网站公告</h3>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>
|
||||
{t('siteAnnouncements')}
|
||||
</h3>
|
||||
{announcementData?.length ? (
|
||||
<Button
|
||||
className='border-0 bg-transparent p-0 text-sm font-normal text-[#225BA9] shadow-none outline-0 hover:bg-transparent'
|
||||
onClick={() => dialogRef.current.open()}
|
||||
onClick={() => dialogRef.current?.open()}
|
||||
>
|
||||
更多
|
||||
{t('more')}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
@ -268,7 +279,7 @@ export default function Content() {
|
||||
return (
|
||||
<div className='flex items-center rounded-[20px] bg-[#B5C9E2] px-4 py-2 sm:p-4'>
|
||||
<p className='line-clamp-2 flex-1 text-[10px] text-[#225BA9] sm:text-sm'>
|
||||
{item.pinned && '【置顶公告】'}{' '}
|
||||
{item.pinned && t('pinnedAnnouncement')}{' '}
|
||||
<span className={`${item.pinned ? 'text-white' : 'text-[#4D4D4D]'}`}>
|
||||
{item.content}
|
||||
</span>
|
||||
@ -276,9 +287,9 @@ export default function Content() {
|
||||
<div className='ml-2 w-[65px] text-right'>
|
||||
<span
|
||||
className='cursor-pointer text-xs text-[#225BA9] sm:text-sm'
|
||||
onClick={() => popupRef.current.open(item)}
|
||||
onClick={() => popupRef.current?.open(item)}
|
||||
>
|
||||
查看详情
|
||||
{t('viewDetails')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -292,26 +303,30 @@ export default function Content() {
|
||||
{/* 我的订阅 Card */}
|
||||
<Card className='rounded-[20px] border border-[#D9D9D9] p-6 shadow-[0px_0px_52.6px_1px_rgba(15,44,83,0.05)]'>
|
||||
<div className='flex items-center justify-between sm:mb-4'>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>我的订阅</h3>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>
|
||||
{t('mySubscription')}
|
||||
</h3>
|
||||
<Link
|
||||
href={'/document'}
|
||||
className='border-0 bg-transparent p-0 text-sm font-semibold text-[#225BA9] shadow-none outline-0 hover:bg-transparent sm:font-normal'
|
||||
>
|
||||
新手教程
|
||||
{t('beginnerTutorial')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{userSubscribe?.[0] && data.protocol ? (
|
||||
<div className='space-y-2 sm:space-y-4'>
|
||||
<p className='text-xs font-light text-[#666666] sm:text-sm sm:font-normal'>
|
||||
复制订阅链接或点击二维码按钮扫码
|
||||
{t('copySubscriptionLinkOrScanQrCode')}
|
||||
</p>
|
||||
|
||||
{/* 统计信息 */}
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] p-4'>
|
||||
<div className='grid grid-cols-3 gap-4 text-center'>
|
||||
<div>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-xs'>总流量</p>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-xs'>
|
||||
{t('totalTraffic')}
|
||||
</p>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-lg'>
|
||||
<Display
|
||||
type='traffic'
|
||||
@ -430,7 +445,9 @@ export default function Content() {
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className='w-auto rounded-xl p-4' align='end'>
|
||||
<div className='flex flex-col items-center gap-2'>
|
||||
<p className='text-muted-foreground text-center text-xs'>扫描码订阅</p>
|
||||
<p className='text-muted-foreground text-center text-xs'>
|
||||
{t('scanCodeToSubscribe')}
|
||||
</p>
|
||||
<QRCodeCanvas
|
||||
value={userSubscribeProtocolCurrent}
|
||||
size={120}
|
||||
@ -466,7 +483,7 @@ export default function Content() {
|
||||
<AlertDialogAction
|
||||
onClick={async () => {
|
||||
await resetUserSubscribeToken({
|
||||
user_subscribe_id: userSubscribe?.[0]?.id,
|
||||
user_subscribe_id: userSubscribe?.[0]?.id || 0,
|
||||
});
|
||||
await refetch();
|
||||
toast.success(t('resetSuccess'));
|
||||
|
||||
@ -62,10 +62,8 @@ export default function Page() {
|
||||
|
||||
{TutorialList && TutorialList?.length > 0 && (
|
||||
<div className='rounded-[46px] bg-[#EAEAEA] px-[23px] py-[19px] sm:px-[34px] sm:py-[28px]'>
|
||||
<div className='font-semibold text-[#666]'>新手教程</div>
|
||||
<div className={'mb-2.5 text-xs text-[#666] sm:text-sm'}>
|
||||
选择对应操作系统,查看对应软件配置教程
|
||||
</div>
|
||||
<div className='font-semibold text-[#666]'>{t('tutorialTitle')}</div>
|
||||
<div className={'mb-2.5 text-xs text-[#666] sm:text-sm'}>{t('tutorialDescription')}</div>
|
||||
<Tabs defaultValue={TutorialList?.[0]?.title}>
|
||||
<TabsList className='h-full flex-wrap justify-start gap-1 bg-transparent'>
|
||||
{TutorialList?.map((tutorial) => (
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import Announcement from '@/components/announcement';
|
||||
import LanguageSwitch from '@/components/language-switch';
|
||||
import { SidebarInset, SidebarProvider } from '@workspace/airo-ui/components/sidebar';
|
||||
import { cookies } from 'next/headers';
|
||||
import { Header } from './Header';
|
||||
@ -12,8 +13,8 @@ export default async function DashboardLayout({ children }: { children: React.Re
|
||||
<SidebarProvider className='' defaultOpen={defaultOpen}>
|
||||
<SidebarLeft className='w-[288px] border-r-0 bg-transparent lg:flex' />
|
||||
<SidebarInset className='relative flex-grow overflow-hidden'>
|
||||
<LanguageSwitch />
|
||||
<div className='h-[calc(100vh-56px)] flex-grow gap-4 overflow-auto p-4'>
|
||||
{' '}
|
||||
<Header />
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@ -15,13 +15,13 @@ interface OrderDetailDialogProps {
|
||||
orderNo?: string;
|
||||
}
|
||||
|
||||
interface OrderDetailDialogRef {
|
||||
export interface OrderDetailDialogRef {
|
||||
show: (orderNo: string) => void;
|
||||
hide: () => void;
|
||||
}
|
||||
|
||||
const OrderDetailDialog = forwardRef<OrderDetailDialogRef, OrderDetailDialogProps>((props, ref) => {
|
||||
const t = useTranslations('subscribe');
|
||||
const t = useTranslations('order');
|
||||
const { getUserInfo } = useGlobalStore();
|
||||
const router = useRouter();
|
||||
const [open, setOpen] = useState(false);
|
||||
@ -65,17 +65,17 @@ const OrderDetailDialog = forwardRef<OrderDetailDialogRef, OrderDetailDialogProp
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent className='sm:w-[675px]'>
|
||||
<div className='text-4xl font-bold text-[#0F2C53] sm:mb-8 sm:text-center sm:text-4xl'>
|
||||
订单详情
|
||||
{t('orderDetail')}
|
||||
</div>
|
||||
|
||||
<div className='text-[16px] font-bold text-[#666]'>
|
||||
<div>订单号</div>
|
||||
<div>{t('orderNo')}</div>
|
||||
<div className='text-[12px] font-light text-[#4D4D4D]'>{orderNo}</div>
|
||||
</div>
|
||||
<Separator className='mb-3 mt-2 h-[2px] bg-[#225BA9]' />
|
||||
<div className='text-[15px] text-[#225BA9]'>
|
||||
<div>支付方式</div>
|
||||
<div className='font-light text-[#666]'>钱包余额</div>
|
||||
<div>{t('paymentMethod')}</div>
|
||||
<div className='font-light text-[#666]'>{t('walletBalance')}</div>
|
||||
</div>
|
||||
<Separator className='mb-3 mt-4 bg-[#225BA9]' />
|
||||
<div>
|
||||
|
||||
@ -45,7 +45,7 @@ export default function Page() {
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
>
|
||||
取消订单
|
||||
{t('cancelOrder')}
|
||||
</Button>
|
||||
<Button className='ml-3 min-w-[150px] rounded-full border-[#A8D4ED] bg-[#A8D4ED] px-[35px] py-[9px] text-center text-xl font-bold hover:border-[#225BA9] hover:bg-[#225BA9] hover:text-white'>
|
||||
{t('payment')}
|
||||
|
||||
@ -46,10 +46,10 @@ export default function ChangePassword() {
|
||||
'h-[32px] w-[110px] rounded-[50px] border-0 border-[#0F2C53] bg-[#0F2C53] text-center text-base font-medium leading-[32px] text-white transition hover:bg-[#225BA9] hover:text-white sm:hidden'
|
||||
}
|
||||
>
|
||||
保存
|
||||
{t('save')}
|
||||
</Button>
|
||||
</div>
|
||||
<div className={'text-xs font-light sm:text-[15px]'}>修改登录密码</div>
|
||||
<div className={'text-xs font-light sm:text-[15px]'}>{t('description')}</div>
|
||||
</div>
|
||||
<Form {...form}>
|
||||
<form id='password-form' onSubmit={form.handleSubmit(onSubmit)} className='space-y-4'>
|
||||
@ -102,7 +102,7 @@ export default function ChangePassword() {
|
||||
'h-full rounded-[50px] border-0 border-[#0F2C53] bg-[#0F2C53] px-[55px] py-[9px] text-xl font-bold text-white transition hover:bg-[#225BA9] hover:text-white'
|
||||
}
|
||||
>
|
||||
保存
|
||||
{t('save')}
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@ -51,10 +51,10 @@ export default function NotifySettings() {
|
||||
'h-[32px] w-[110px] rounded-[50px] border-0 border-[#0F2C53] bg-[#0F2C53] text-center text-base font-medium leading-[32px] text-white transition hover:bg-[#225BA9] hover:text-white sm:hidden'
|
||||
}
|
||||
>
|
||||
保存
|
||||
{t('notify.save')}
|
||||
</Button>
|
||||
</div>
|
||||
<div className={'text-xs font-light sm:text-[15px]'}>是否邮箱通知推送</div>
|
||||
<div className={'text-xs font-light sm:text-[15px]'}>{t('notify.description')}</div>
|
||||
</div>
|
||||
<Form {...form}>
|
||||
<form
|
||||
@ -104,7 +104,7 @@ export default function NotifySettings() {
|
||||
'h-full rounded-[50px] border-0 border-[#0F2C53] bg-[#0F2C53] px-[55px] py-[9px] text-xl font-bold text-white transition hover:bg-[#225BA9] hover:text-white'
|
||||
}
|
||||
>
|
||||
保存
|
||||
{t('notify.save')}
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@ -245,13 +245,13 @@ export default function ThirdPartyAccounts() {
|
||||
'h-[32px] w-[110px] rounded-full bg-[#D9D9D9] text-center font-medium leading-[32px] text-white sm:hidden'
|
||||
}
|
||||
>
|
||||
保存
|
||||
{t('save')}
|
||||
</div>
|
||||
</div>
|
||||
<div className='mb-2 text-xs text-[#666666] sm:mb-4 sm:mt-1 sm:text-sm'>
|
||||
{user?.auth_methods?.[0]?.auth_identifier}
|
||||
</div>
|
||||
<div className={'mb-1 sm:mb-3'}>Email</div>
|
||||
<div className={'mb-1 sm:mb-3'}>{t('emailLabel')}</div>
|
||||
<div className={'flex items-center gap-2'}>
|
||||
<div
|
||||
className={
|
||||
@ -265,7 +265,7 @@ export default function ThirdPartyAccounts() {
|
||||
'hidden h-[32px] w-[110px] rounded-full bg-[#D9D9D9] text-center text-[16px] font-medium leading-[32px] text-white sm:block'
|
||||
}
|
||||
>
|
||||
保存
|
||||
{t('save')}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@ -76,14 +76,14 @@ export default function Page() {
|
||||
'hidden text-4xl font-bold text-[#0F2C53] sm:block md:mb-4 md:text-center md:text-5xl'
|
||||
}
|
||||
>
|
||||
选择套餐
|
||||
{t('title')}
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
'-mt-5 text-right text-lg font-bold text-[#666666] sm:mt-0 sm:text-center sm:font-medium'
|
||||
}
|
||||
>
|
||||
选择最适合您的服务套餐
|
||||
{t('description')}
|
||||
</div>
|
||||
<div>
|
||||
<Tabs
|
||||
@ -115,7 +115,7 @@ export default function Page() {
|
||||
}
|
||||
value='year'
|
||||
>
|
||||
年付套餐
|
||||
{t('yearlyPlan')}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
className={
|
||||
@ -123,7 +123,7 @@ export default function Page() {
|
||||
}
|
||||
value='month'
|
||||
>
|
||||
月付套餐
|
||||
{t('monthlyPlan')}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
|
||||
@ -38,7 +38,7 @@ export default function Page() {
|
||||
<div className='mb-4'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<div>
|
||||
<p className='text-sm font-light text-[#666]'>总资产</p>
|
||||
<p className='text-sm font-light text-[#666]'>{t('totalAssets')}</p>
|
||||
<p className='text-2xl font-bold sm:text-[32px]'>
|
||||
<Display type='currency' value={totalAssets} />
|
||||
</p>
|
||||
@ -47,7 +47,9 @@ export default function Page() {
|
||||
</div>
|
||||
<div className='grid grid-cols-2 gap-2 sm:grid-cols-2 sm:gap-6 md:grid-cols-4'>
|
||||
<div className='col-span-2 rounded-[20px] bg-[#EAEAEA] p-4 shadow-sm transition-all duration-300 hover:shadow-md sm:col-span-1'>
|
||||
<p className='text-sm font-medium text-[#666] opacity-80 sm:mb-3'>账户余额</p>
|
||||
<p className='text-sm font-medium text-[#666] opacity-80 sm:mb-3'>
|
||||
{t('accountBalance')}
|
||||
</p>
|
||||
<p className='text-xl font-bold text-[#225BA9] sm:text-2xl'>
|
||||
<Display type='currency' value={user?.balance} />
|
||||
</p>
|
||||
@ -70,9 +72,9 @@ export default function Page() {
|
||||
</div>
|
||||
<div className='col-span-2 rounded-[20px] border-2 border-[#D9D9D9] p-4 shadow-sm transition-all duration-300 hover:shadow-md sm:col-span-1'>
|
||||
<p className='mb-1 flex justify-between text-sm font-medium text-[#666] opacity-80 sm:mb-3'>
|
||||
<span>返佣邀请码</span>
|
||||
<span>{t('referralCode')}</span>
|
||||
<Link href='/affiliate' className={'text-[#225BA9]'}>
|
||||
返佣详情
|
||||
{t('referralDetails')}
|
||||
</Link>
|
||||
</p>
|
||||
<p className='flex justify-between text-base font-bold text-[#225BA9] sm:text-2xl'>
|
||||
|
||||
@ -57,11 +57,11 @@ export const AffiliateDialog = ({ ref }: AffiliateDialogProps) => {
|
||||
return (
|
||||
<div className='flex flex-wrap justify-between gap-2 rounded-[20px] bg-white px-6 py-2 text-[10px] sm:text-base'>
|
||||
<div>
|
||||
<div className={'text-[#225BA9]'}>用户识别代码</div>
|
||||
<div className={'text-[#225BA9]'}>{t('userIdentifier')}</div>
|
||||
<div className={'font-bold text-[#091B33]'}>{invite.identifier}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className={'text-[#225BA9]'}>时间</div>
|
||||
<div className={'text-[#225BA9]'}>{t('time')}</div>
|
||||
<div className={'font-bold text-[#091B33]'}>
|
||||
{formatDate(invite.registered_at)}
|
||||
</div>
|
||||
|
||||
@ -52,23 +52,23 @@ export default function Affiliate() {
|
||||
<CardContent className={'p-0 text-[#666]'}>
|
||||
<div className={'sm:mb-6'}>
|
||||
<div className={'font-bold sm:text-xl'}>{t('totalCommission')}</div>
|
||||
<div className={'text-xs font-light sm:text-[15px]'}>
|
||||
佣金金额,邀请成功后自动转入钱包余额
|
||||
</div>
|
||||
<div className={'text-xs font-light sm:text-[15px]'}>{t('commissionInfo')}</div>
|
||||
</div>
|
||||
<div className={'mb-3 text-xl font-bold text-[#091B33] sm:text-[32px]'}>
|
||||
历史推荐用户:7
|
||||
{t('historicalRecommendedUsers')}
|
||||
</div>
|
||||
<div className={'grid grid-cols-2 gap-[10px] sm:grid-cols-1 sm:gap-5 lg:grid-cols-2'}>
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] px-4 py-2 shadow-sm transition-all duration-300 hover:shadow-md sm:py-4'>
|
||||
<p className='font-medium text-[#666] opacity-80 sm:mb-3 sm:text-sm'>佣金总额</p>
|
||||
<p className='font-medium text-[#666] opacity-80 sm:mb-3 sm:text-sm'>
|
||||
{t('totalCommission')}
|
||||
</p>
|
||||
<p className='text-xl font-bold text-[#225BA9] sm:text-2xl'>
|
||||
<Display type='currency' value={data?.total_commission} />
|
||||
</p>
|
||||
</div>
|
||||
<div className='rounded-[20px] border-2 border-[#D9D9D9] px-4 py-2 shadow-sm transition-all duration-300 hover:shadow-md sm:py-4'>
|
||||
<p className='flex justify-between font-medium text-[#666] opacity-80 sm:mb-3 sm:text-sm'>
|
||||
返佣邀请码
|
||||
{t('commissionInviteCode')}
|
||||
<CopyToClipboard
|
||||
text={`${location?.origin}/?invite=${user?.refer_code}`}
|
||||
onCopy={(text, result) => {
|
||||
@ -111,12 +111,12 @@ export default function Affiliate() {
|
||||
</Card>
|
||||
<Card className='order-2 rounded-[20px] border border-[#EAEAEA] bg-gradient-to-b from-white to-[#EAEAEA] p-6 md:order-none'>
|
||||
<div className='mb-4 flex items-center justify-between'>
|
||||
<h3 className='font-medium text-[#666666] sm:text-xl'>邀请记录</h3>
|
||||
<h3 className='font-medium text-[#666666] sm:text-xl'>{t('inviteRecords')}</h3>
|
||||
<span
|
||||
className='cursor-pointer text-sm text-[#225BA9]'
|
||||
onClick={() => dialogRef.current.open()}
|
||||
onClick={() => dialogRef.current?.open()}
|
||||
>
|
||||
更多
|
||||
{t('more')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@ -132,11 +132,11 @@ export default function Affiliate() {
|
||||
return (
|
||||
<div className='flex flex-wrap justify-between gap-2 rounded-[20px] bg-white px-6 py-2 text-[10px] sm:text-base'>
|
||||
<div>
|
||||
<div className={'text-[#225BA9]'}>用户识别代码</div>
|
||||
<div className={'text-[#225BA9]'}>{t('userIdentifier')}</div>
|
||||
<div className={'font-bold text-[#091B33]'}>{invite.identifier}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className={'text-[#225BA9]'}>时间</div>
|
||||
<div className={'text-[#225BA9]'}>{t('time')}</div>
|
||||
<div className={'font-bold text-[#091B33]'}>
|
||||
{formatDate(invite.registered_at)}
|
||||
</div>
|
||||
@ -152,15 +152,16 @@ export default function Affiliate() {
|
||||
</Card>
|
||||
<Card className='min-w-[322px] rounded-[20px] border border-[#EAEAEA] bg-[#EAEAEA] p-6 text-[12px] sm:text-[16px] md:min-w-[496px]'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<h3 className='text-[15px] font-medium text-[#0F2C53] sm:text-xl'>佣金计算</h3>
|
||||
<h3 className='text-[15px] font-medium text-[#0F2C53] sm:text-xl'>
|
||||
{t('commissionCalculation')}
|
||||
</h3>
|
||||
</div>
|
||||
<div className={'mb-4 text-[10px] font-light text-[#0F2C53] sm:text-base'}>
|
||||
在下方填入对应邀请用户数量,即可计算不同比例返佣金额 *该表以Pro
|
||||
Plan计算,其它套餐比例不变,以实际金额计算为准
|
||||
{t('commissionCalculationInfo')}
|
||||
</div>
|
||||
|
||||
{(() => {
|
||||
// 假设以 Pro 计划计算:$60/月,$576/年
|
||||
// Pro plan: $60/month, $576/year
|
||||
const MONTHLY_PRICE = 60;
|
||||
const YEARLY_PRICE = 576;
|
||||
|
||||
@ -174,20 +175,20 @@ export default function Affiliate() {
|
||||
|
||||
return (
|
||||
<div className='space-y-4'>
|
||||
{/* 计算面板容器 */}
|
||||
{/* Calculator panel container */}
|
||||
<div className='grid grid-cols-[1.5fr_2.5fr_3fr] items-stretch rounded-[34px] bg-white/10 px-5 pb-6 shadow-[inset_0_0_15.7px_0_rgba(0,0,0,0.25)]'>
|
||||
{/* 左:行表头(月付套餐 / 年付套餐) */}
|
||||
{/* Left: row headers (Monthly Plan / Yearly Plan) */}
|
||||
<div className='flex flex-col justify-stretch font-semibold text-[#0F2C53]'>
|
||||
<div className='flex h-[56px] items-center justify-center border-b-[3px] border-white'></div>
|
||||
<div className='flex h-[81px] items-center justify-center border-b-[3px] border-white'>
|
||||
月付套餐
|
||||
{t('monthlyPackage')}
|
||||
</div>
|
||||
<div className='flex h-[81px] items-center justify-center border-b-[3px] border-white'>
|
||||
年付套餐
|
||||
{t('annualPackage')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 中:首充用户(双层圆角 + 三行) */}
|
||||
{/* Middle: First-time top-up users (double rounded corners + three rows) */}
|
||||
<div className='relative'>
|
||||
<div
|
||||
className={
|
||||
@ -195,11 +196,11 @@ export default function Affiliate() {
|
||||
}
|
||||
></div>
|
||||
<div className={'absolute bottom-0 z-0 h-[3px] w-full bg-white'}></div>
|
||||
<div className='absolute z-20 w-full'>
|
||||
<div className={'absolute z-20 w-full'}>
|
||||
<div className='overflow-hidden rounded-[14px] text-center text-[#0F2C53]'>
|
||||
<div className={'rounded-t-[14px] bg-[#A8D4ED] px-1 sm:px-4'}>
|
||||
<div className='mt-3 flex h-[44px] items-center justify-center border-b-[3px] border-white font-bold'>
|
||||
首充用户
|
||||
{t('firstTimeTopUpUser')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -231,14 +232,14 @@ export default function Affiliate() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 蓝色投影块 */}
|
||||
{/* Blue shadow block */}
|
||||
<div className='pointer-events-none absolute inset-0 -z-10 translate-x-2 translate-y-2 rounded-[20px] bg-[#225BA9]' />
|
||||
</div>
|
||||
|
||||
{/* 右:再次充值用户(灰卡 + 三行) */}
|
||||
{/* Right: Repeat top-up users (gray card + three rows) */}
|
||||
<div className='text-center text-[#0F2C53]'>
|
||||
<div className='flex h-[56px] items-center justify-center border-b-[3px] border-white pt-3 font-bold'>
|
||||
再次充值用户
|
||||
{t('repeatTopUpUser')}
|
||||
</div>
|
||||
|
||||
<div className='grid h-[81px] grid-cols-1 grid-rows-2 items-center justify-center border-b-[3px] border-white'>
|
||||
@ -250,7 +251,7 @@ export default function Affiliate() {
|
||||
<span className='font-semibold'>
|
||||
<Display type='currency' value={recurMonth} />
|
||||
</span>{' '}
|
||||
/ 月
|
||||
{t('perMonth')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -263,12 +264,12 @@ export default function Affiliate() {
|
||||
<span className='font-semibold'>
|
||||
<Display type='currency' value={recurYear} />
|
||||
</span>{' '}
|
||||
/ 年
|
||||
{t('perYear')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 用户数调节 */}
|
||||
{/* User count adjustment */}
|
||||
<div className='flex items-center justify-center gap-4'>
|
||||
<Button
|
||||
variant='secondary'
|
||||
@ -285,7 +286,7 @@ export default function Affiliate() {
|
||||
className='h-6 border-0 p-0 text-center text-sm focus-visible:ring-0 sm:h-8'
|
||||
style={{ width: `${Math.max(3, String(count).length + 1)}ch` }}
|
||||
/>
|
||||
<span className='text-sm'>Users</span>
|
||||
<span className='text-sm'>{t('users')}</span>
|
||||
</div>
|
||||
<Button
|
||||
variant='secondary'
|
||||
|
||||
@ -31,7 +31,7 @@ interface PurchaseProps {
|
||||
}
|
||||
|
||||
interface PurchaseDialogRef {
|
||||
show: (subscribe: API.Subscribe) => void;
|
||||
show: (subscribe: API.Subscribe, tabValue: string) => void;
|
||||
hide: () => void;
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@ const Purchase = forwardRef<PurchaseDialogRef, PurchaseProps>((props, ref) => {
|
||||
</DialogHeader>
|
||||
<div>
|
||||
<div className='pl-4 text-4xl font-bold text-[#0F2C53] sm:mb-8 sm:pl-0 sm:text-center sm:text-4xl'>
|
||||
购买套餐
|
||||
{t('purchaseTitle')}
|
||||
</div>
|
||||
<div>
|
||||
<Tabs
|
||||
@ -142,7 +142,7 @@ const Purchase = forwardRef<PurchaseDialogRef, PurchaseProps>((props, ref) => {
|
||||
<TabsList className='relative mb-8 h-[74px] flex-wrap rounded-full bg-[#EAEAEA] p-2.5'>
|
||||
{tabValue === 'year' ? (
|
||||
<span className='absolute -top-8 left-16 z-10 rounded-md bg-[#E22C2E] px-2 py-0.5 text-[10px] font-bold leading-none text-white shadow sm:text-xs'>
|
||||
-20%
|
||||
{t('discount20')}
|
||||
{/* 小三角箭头 */}
|
||||
{/* <span className="
|
||||
absolute right-0 top-full
|
||||
@ -160,13 +160,13 @@ const Purchase = forwardRef<PurchaseDialogRef, PurchaseProps>((props, ref) => {
|
||||
className='rounded-full px-10 py-3.5 text-xl data-[state=active]:bg-[#0F2C53] data-[state=active]:text-white md:px-12'
|
||||
value='year'
|
||||
>
|
||||
年付套餐
|
||||
{t('yearlyPlan')}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
className='rounded-full px-10 py-3.5 text-xl data-[state=active]:bg-[#0F2C53] data-[state=active]:text-white md:px-12'
|
||||
value='month'
|
||||
>
|
||||
月付套餐
|
||||
{t('monthlyPlan')}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
@ -188,8 +188,8 @@ const Purchase = forwardRef<PurchaseDialogRef, PurchaseProps>((props, ref) => {
|
||||
/>
|
||||
<Separator className='mb-3 mt-4 bg-[#225BA9]' />
|
||||
<div className='flex items-center justify-between text-[15px] text-[#225BA9]'>
|
||||
<div>支付方式</div>
|
||||
<div className='font-light text-[#666]'>钱包余额</div>
|
||||
<div>{t('paymentMethod')}</div>
|
||||
<div className='font-light text-[#666]'>{t('walletBalance')}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-8 flex items-center justify-center'>
|
||||
|
||||
@ -36,7 +36,7 @@ export default function Recharge(props: Readonly<ButtonProps>) {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button {...props}>钱包充值</Button>
|
||||
<Button {...props}>{t('walletRecharge')}</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className='flex h-full flex-col overflow-hidden md:h-auto'>
|
||||
<DialogHeader>
|
||||
|
||||
@ -103,7 +103,7 @@ export default function Renewal({ id, subscribe, className }: Readonly<RenewalPr
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button size='sm' className={className}>
|
||||
续订套餐
|
||||
{t('renewPlan')}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className='flex h-full max-w-screen-lg flex-col overflow-hidden md:h-auto'>
|
||||
|
||||
@ -1,11 +1,24 @@
|
||||
{
|
||||
"commissionInfo": "Statistics of the commission, automatically transferred to balance",
|
||||
"annualPackage": "Annual Package",
|
||||
"commissionCalculation": "Commission Calculation",
|
||||
"commissionCalculationInfo": "Fill in the corresponding number of invited users below to calculate the commission amount at different ratios. *This table is calculated based on the Pro Plan. The ratios for other plans remain unchanged, and the calculation is based on the actual amount.",
|
||||
"commissionInfo": "Commission amount, which is automatically transferred to the wallet balance after a successful invitation.",
|
||||
"commissionInviteCode": "Commission Invite Code",
|
||||
"commissionRate": "Commission Rate",
|
||||
"copyInviteLink": "Copy Invite Link",
|
||||
"copySuccess": "Copied Successfully",
|
||||
"firstTimeTopUpUser": "First-time Top-up User",
|
||||
"historicalRecommendedUsers": "Historical Recommended Users: 7",
|
||||
"inviteCode": "Invite Code",
|
||||
"inviteRecords": "Invite Records",
|
||||
"monthlyPackage": "Monthly Package",
|
||||
"more": "More",
|
||||
"perMonth": "/ Month",
|
||||
"perYear": "/ Year",
|
||||
"registrationTime": "Registration Time",
|
||||
"repeatTopUpUser": "Repeat Top-up User",
|
||||
"time": "Time",
|
||||
"totalCommission": "Total Commission",
|
||||
"userIdentifier": "User Identifier"
|
||||
"userIdentifier": "User Identifier",
|
||||
"users": "Users"
|
||||
}
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
{
|
||||
"accountBalance": "Account Balance",
|
||||
"accountOverview": "Account Overview",
|
||||
"address1": "Address 1",
|
||||
"announcementTitle": "Site Announcements",
|
||||
"annualPlanUser": "Annual Plan User",
|
||||
"availableDevices": "Available Devices",
|
||||
"beginnerTutorial": "Beginner Tutorial",
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"confirmResetSubscription": "Are you sure you want to reset the subscription address?",
|
||||
"copy": "Copy",
|
||||
"copyFailure": "Copy failed, please copy manually",
|
||||
"copySubscriptionLinkOrScanQrCode": "Copy subscription link or click the QR code button to scan",
|
||||
"copySuccess": "Copy successful",
|
||||
"deducted": "Canceled",
|
||||
"download": "Download",
|
||||
@ -11,20 +19,35 @@
|
||||
"expired": "Expired",
|
||||
"finished": "Traffic exhausted",
|
||||
"import": "Import",
|
||||
"inEffect": "In Effect",
|
||||
"latestAnnouncement": "Latest Announcement",
|
||||
"loading": "Loading...",
|
||||
"manualImportMessage": "This app does not support activation. Please import manually. The subscription address has been copied.",
|
||||
"more": "More",
|
||||
"mySubscription": "My Subscription",
|
||||
"mySubscriptions": "My Subscriptions",
|
||||
"nextResetDays": "Next Reset in Days",
|
||||
"noLimit": "No Limit",
|
||||
"noReset": "No Reset",
|
||||
"online": "Online: ",
|
||||
"pageOf": "Page {pageIndex} of {pageCount}",
|
||||
"pinnedAnnouncement": "[Pinned]",
|
||||
"planExpirationTime": "Plan Expiration Time: ",
|
||||
"planStatus": "Plan Status",
|
||||
"prompt": "Prompt",
|
||||
"purchaseSubscription": "Purchase Subscription",
|
||||
"qrCode": "QR Code",
|
||||
"remaining": "Remaining: ",
|
||||
"resetSubscription": "Reset Subscription Address",
|
||||
"resetSuccess": "Reset successful",
|
||||
"rowsPerPage": "Rows per page",
|
||||
"scanCodeToSubscribe": "Scan code to subscribe",
|
||||
"scanToSubscribe": "Scan to Subscribe",
|
||||
"siteAnnouncements": "Site Announcements",
|
||||
"subscriptionUrl": "Subscription URL",
|
||||
"totalTraffic": "Total Traffic",
|
||||
"unknown": "Unknown",
|
||||
"used": "Used"
|
||||
"used": "Used",
|
||||
"usedTrafficTotalTraffic": "Used Traffic/Total Traffic: ",
|
||||
"viewDetails": "View Details"
|
||||
}
|
||||
|
||||
@ -2,5 +2,7 @@
|
||||
"all": "All",
|
||||
"document": "Document",
|
||||
"read": "Read",
|
||||
"tutorial": "Tutorial"
|
||||
"tutorial": "Tutorial",
|
||||
"tutorialDescription": "Select the corresponding operating system to view the corresponding software configuration tutorial",
|
||||
"tutorialTitle": "Beginner Tutorial"
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{
|
||||
"balanceRecharge": "Balance Recharge",
|
||||
"cancel": "Cancel",
|
||||
"cancelOrder": "Cancel Order",
|
||||
"createdAt": "Created At",
|
||||
"detail": "Detail",
|
||||
"goToPayment": "Go to Payment",
|
||||
@ -13,6 +14,7 @@
|
||||
},
|
||||
"name": "Name",
|
||||
"orderClosed": "Order Closed",
|
||||
"orderDetail": "Order Detail",
|
||||
"orderList": "Order List",
|
||||
"orderNo": "Order Number",
|
||||
"orderNumber": "Order Number",
|
||||
@ -43,5 +45,6 @@
|
||||
"4": "Recharge"
|
||||
},
|
||||
"viewDocument": "View Document",
|
||||
"waitingForPayment": "Waiting for Payment"
|
||||
"waitingForPayment": "Waiting for Payment",
|
||||
"walletBalance": "Wallet Balance"
|
||||
}
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
"passwordMismatch": "Passwords do not match",
|
||||
"repeatNewPassword": "Repeat New Password",
|
||||
"updatePassword": "Update Password",
|
||||
"updateSuccess": "Update Successful"
|
||||
"updateSuccess": "Update Successful",
|
||||
"save": "Save",
|
||||
"description": "Change login password"
|
||||
},
|
||||
"notify": {
|
||||
"balanceChange": "Balance Change",
|
||||
@ -16,7 +18,8 @@
|
||||
"notificationTypes": "Notification Types",
|
||||
"save": "Save Changes",
|
||||
"subscribe": "Subscribe",
|
||||
"updateSuccess": "Update Successful"
|
||||
"updateSuccess": "Update Successful",
|
||||
"description": "Enable or disable email notifications"
|
||||
},
|
||||
"thirdParty": {
|
||||
"apple": {
|
||||
@ -37,6 +40,7 @@
|
||||
"placeholder": "Enter your email address",
|
||||
"title": "Change Email"
|
||||
},
|
||||
"emailLabel": "Email",
|
||||
"facebook": {
|
||||
"description": "Sign in with Facebook"
|
||||
},
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
"buySubscription": "Buy Subscription",
|
||||
"category": "Category",
|
||||
"coupon": "Coupon",
|
||||
"description": "Choose the service plan that suits you best",
|
||||
"detail": {
|
||||
"availableTraffic": "Available Traffic",
|
||||
"connectedDevices": "Connected Devices",
|
||||
@ -29,6 +30,7 @@
|
||||
"productDetail": "Product Details"
|
||||
},
|
||||
"discount": "Discount",
|
||||
"discount20": "-20%",
|
||||
"discountInfo": "Discount Info",
|
||||
"enterAmount": "Enter recharge amount",
|
||||
"enterCoupon": "Enter Coupon Code",
|
||||
@ -39,20 +41,24 @@
|
||||
"stripe_alipay": "Stripe (Alipay)",
|
||||
"stripe_wechat_pay": "Stripe (WeChat)"
|
||||
},
|
||||
"monthlyPlan": "Monthly Plan",
|
||||
"paymentMethod": "Payment Method",
|
||||
"productDescription": "Product Description",
|
||||
"products": "Products",
|
||||
"purchaseDuration": "Purchase Duration",
|
||||
"purchaseTitle": "Purchase Plan",
|
||||
"recharge": "Recharge",
|
||||
"rechargeAmount": "Recharge Amount",
|
||||
"rechargeDescription": "One-click recharge, easy to handle",
|
||||
"rechargeNow": "Recharge Now",
|
||||
"renew": "Renew",
|
||||
"renewPlan": "Renew Plan",
|
||||
"renewSubscription": "Renew Subscription",
|
||||
"resetPrice": "Reset Price",
|
||||
"resetTraffic": "Reset Traffic",
|
||||
"resetTrafficDescription": "Reset traffic to zero, and start a new billing cycle",
|
||||
"resetTrafficTitle": "Reset Traffic",
|
||||
"title": "Choose a Plan",
|
||||
"unsubscribe": {
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
@ -63,5 +69,8 @@
|
||||
"success": "You have been unsubscribed successfully.",
|
||||
"unsubscribe": "Unsubscribe",
|
||||
"unsubscribeDescription": "Please note: If you unsubscribe now, the remaining value of the subscription will be refunded to your account balance, which can be used for your next subscription purchase or renewal."
|
||||
}
|
||||
},
|
||||
"walletBalance": "Wallet Balance",
|
||||
"walletRecharge": "Wallet Recharge",
|
||||
"yearlyPlan": "Yearly Plan"
|
||||
}
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
{
|
||||
"accountBalance": "Account Balance",
|
||||
"amount": "Amount",
|
||||
"assetOverview": "Asset Overview",
|
||||
"balance": "Balance",
|
||||
"commission": "Commission",
|
||||
"createdAt": "Time",
|
||||
"giftAmount": "Girt Amount",
|
||||
"referralCode": "Referral Code",
|
||||
"referralDetails": "Referral Details",
|
||||
"totalAssets": "Total Assets",
|
||||
"type": {
|
||||
"0": "Type",
|
||||
|
||||
@ -1,11 +1,24 @@
|
||||
{
|
||||
"commissionInfo": "统计金额,邀请佣金自动转入余额",
|
||||
"annualPackage": "年付套餐",
|
||||
"commissionCalculation": "佣金计算",
|
||||
"commissionCalculationInfo": "在下方填入对应邀请用户数量,即可计算不同比例返佣金额 *该表以Pro Plan计算,其它套餐比例不变,以实际金额计算为准",
|
||||
"commissionInfo": "佣金金额,邀请成功后自动转入钱包余额",
|
||||
"commissionInviteCode": "返佣邀请码",
|
||||
"commissionRate": "佣金比例",
|
||||
"copyInviteLink": "复制邀请链接",
|
||||
"copySuccess": "复制成功",
|
||||
"firstTimeTopUpUser": "首充用户",
|
||||
"historicalRecommendedUsers": "历史推荐用户:7",
|
||||
"inviteCode": "邀请码",
|
||||
"inviteRecords": "邀请记录",
|
||||
"monthlyPackage": "月付套餐",
|
||||
"more": "更多",
|
||||
"perMonth": "/ 月",
|
||||
"perYear": "/ 年",
|
||||
"registrationTime": "注册时间",
|
||||
"repeatTopUpUser": "再次充值用户",
|
||||
"time": "时间",
|
||||
"totalCommission": "佣金总额",
|
||||
"userIdentifier": "用户标识符"
|
||||
"userIdentifier": "用户识别代码",
|
||||
"users": "用户"
|
||||
}
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
{
|
||||
"accountBalance": "账户余额",
|
||||
"accountOverview": "账户概况",
|
||||
"address1": "地址1",
|
||||
"announcementTitle": "网站公告",
|
||||
"annualPlanUser": "年度套餐用户",
|
||||
"availableDevices": "可用设备",
|
||||
"beginnerTutorial": "新手教程",
|
||||
"cancel": "取消",
|
||||
"confirm": "确认",
|
||||
"confirmResetSubscription": "是否确认重置订阅地址?",
|
||||
"copy": "复制",
|
||||
"copyFailure": "复制失败,请手动复制",
|
||||
"copySubscriptionLinkOrScanQrCode": "复制订阅链接或点击二维码按钮扫码",
|
||||
"copySuccess": "复制成功",
|
||||
"deducted": "已取消",
|
||||
"download": "下载",
|
||||
@ -11,20 +19,35 @@
|
||||
"expired": "已过期",
|
||||
"finished": "流量已用尽",
|
||||
"import": "导入",
|
||||
"inEffect": "生效中",
|
||||
"latestAnnouncement": "最新公告",
|
||||
"loading": "加载中...",
|
||||
"manualImportMessage": "该应用暂不支持唤起,请手动导入,已自动复制订阅地址",
|
||||
"more": "更多",
|
||||
"mySubscription": "我的订阅",
|
||||
"mySubscriptions": "我的订阅",
|
||||
"nextResetDays": "下次重置/天",
|
||||
"noLimit": "无限制",
|
||||
"noReset": "不重置",
|
||||
"online": "在线:",
|
||||
"pageOf": "第 {pageIndex} 页,共 {pageCount} 页",
|
||||
"pinnedAnnouncement": "【置顶公告】",
|
||||
"planExpirationTime": "套餐到期时间:",
|
||||
"planStatus": "套餐状态",
|
||||
"prompt": "提示",
|
||||
"purchaseSubscription": "购买订阅",
|
||||
"qrCode": "二维码",
|
||||
"remaining": "剩余:",
|
||||
"resetSubscription": "重置订阅地址",
|
||||
"resetSuccess": "重置成功",
|
||||
"rowsPerPage": "每页显示",
|
||||
"scanCodeToSubscribe": "扫描码订阅",
|
||||
"scanToSubscribe": "扫描订阅",
|
||||
"siteAnnouncements": "网站公告",
|
||||
"subscriptionUrl": "订阅地址",
|
||||
"totalTraffic": "总流量",
|
||||
"unknown": "未知",
|
||||
"used": "已用"
|
||||
"used": "已用",
|
||||
"usedTrafficTotalTraffic": "已使用流量/总流量:",
|
||||
"viewDetails": "查看详情"
|
||||
}
|
||||
|
||||
@ -2,5 +2,7 @@
|
||||
"all": "全部",
|
||||
"document": "文档",
|
||||
"read": "阅读",
|
||||
"tutorial": "教程"
|
||||
"tutorial": "教程",
|
||||
"tutorialDescription": "选择对应操作系统,查看对应软件配置教程",
|
||||
"tutorialTitle": "新手教程"
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{
|
||||
"balanceRecharge": "余额充值",
|
||||
"cancel": "取消",
|
||||
"cancelOrder": "取消订单",
|
||||
"createdAt": "创建时间",
|
||||
"detail": "详情",
|
||||
"goToPayment": "前往支付",
|
||||
@ -13,6 +14,7 @@
|
||||
},
|
||||
"name": "名称",
|
||||
"orderClosed": "订单已关闭",
|
||||
"orderDetail": "订单详情",
|
||||
"orderList": "订单列表",
|
||||
"orderNo": "订单号",
|
||||
"orderNumber": "订单编号",
|
||||
@ -43,5 +45,6 @@
|
||||
"4": "充值"
|
||||
},
|
||||
"viewDocument": "查看文档",
|
||||
"waitingForPayment": "等待支付"
|
||||
"waitingForPayment": "等待支付",
|
||||
"walletBalance": "钱包余额"
|
||||
}
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
"passwordMismatch": "两次密码不一致",
|
||||
"repeatNewPassword": "重复新密码",
|
||||
"updatePassword": "更新密码",
|
||||
"updateSuccess": "更新成功"
|
||||
"updateSuccess": "更新成功",
|
||||
"save": "保存",
|
||||
"description": "修改登录密码"
|
||||
},
|
||||
"notify": {
|
||||
"balanceChange": "余额变动",
|
||||
@ -16,7 +18,8 @@
|
||||
"notificationTypes": "通知类型",
|
||||
"save": "保存更改",
|
||||
"subscribe": "订阅",
|
||||
"updateSuccess": "更新成功"
|
||||
"updateSuccess": "更新成功",
|
||||
"description": "是否邮箱通知推送"
|
||||
},
|
||||
"thirdParty": {
|
||||
"apple": {
|
||||
@ -37,6 +40,7 @@
|
||||
"placeholder": "输入邮箱地址",
|
||||
"title": "更改邮箱"
|
||||
},
|
||||
"emailLabel": "邮箱",
|
||||
"facebook": {
|
||||
"description": "使用 Facebook 登录"
|
||||
},
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
"buySubscription": "购买订阅",
|
||||
"category": "类别",
|
||||
"coupon": "优惠券",
|
||||
"description": "选择最适合您的服务套餐",
|
||||
"detail": {
|
||||
"availableTraffic": "可用流量",
|
||||
"connectedDevices": "同时连接 IP 数",
|
||||
@ -29,6 +30,7 @@
|
||||
"productDetail": "商品详情"
|
||||
},
|
||||
"discount": "折扣",
|
||||
"discount20": "-20%",
|
||||
"discountInfo": "折扣信息",
|
||||
"enterAmount": "输入充值金额",
|
||||
"enterCoupon": "输入优惠券代码",
|
||||
@ -39,20 +41,24 @@
|
||||
"stripe_alipay": "Stripe(支付宝)",
|
||||
"stripe_wechat_pay": "Stripe(微信)"
|
||||
},
|
||||
"monthlyPlan": "月付套餐",
|
||||
"paymentMethod": "支付方式",
|
||||
"productDescription": "商品描述",
|
||||
"products": "商品",
|
||||
"purchaseDuration": "购买时长",
|
||||
"purchaseTitle": "购买套餐",
|
||||
"recharge": "充值",
|
||||
"rechargeAmount": "充值金额",
|
||||
"rechargeDescription": "一键充值,轻松处理",
|
||||
"rechargeNow": "立即充值",
|
||||
"renew": "续订",
|
||||
"renewPlan": "续订套餐",
|
||||
"renewSubscription": "续订",
|
||||
"resetPrice": "重置价格",
|
||||
"resetTraffic": "重置流量",
|
||||
"resetTrafficDescription": "将流量重置为零,并开始新的计费周期",
|
||||
"resetTrafficTitle": "重置流量",
|
||||
"title": "选择套餐",
|
||||
"unsubscribe": {
|
||||
"cancel": "取消",
|
||||
"confirm": "确认",
|
||||
@ -63,5 +69,8 @@
|
||||
"success": "您已成功取消订阅。",
|
||||
"unsubscribe": "取消订阅",
|
||||
"unsubscribeDescription": "请注意:如果您现在取消订阅,订阅的剩余价值将退还到您的账户余额中,可用于您下次的订阅购买或续订。"
|
||||
}
|
||||
},
|
||||
"walletBalance": "钱包余额",
|
||||
"walletRecharge": "钱包充值",
|
||||
"yearlyPlan": "年付套餐"
|
||||
}
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
{
|
||||
"accountBalance": "账户余额",
|
||||
"amount": "金额",
|
||||
"assetOverview": "资产概览",
|
||||
"balance": "余额",
|
||||
"commission": "佣金",
|
||||
"createdAt": "时间",
|
||||
"giftAmount": "赠送金额",
|
||||
"referralCode": "返佣邀请码",
|
||||
"referralDetails": "返佣详情",
|
||||
"totalAssets": "资产概览",
|
||||
"type": {
|
||||
"0": "类型",
|
||||
|
||||
@ -6,6 +6,9 @@ const withNextIntl = createNextIntlPlugin('./locales/request.ts');
|
||||
const nextConfig: NextConfig = {
|
||||
transpilePackages: ['@workspace/ui', '@workspace/airo-ui'],
|
||||
output: 'standalone',
|
||||
typescript: {
|
||||
ignoreBuildErrors: true, // 禁用 TypeScript 构建时的类型检查
|
||||
},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user