Files
36-character-flower/src/locales/en-US.ts
JiaJun b6168301fe fix(withdraw): 优化提现功能的文本提示和样式
- 更新多语言文案,改进提现成功提示信息
- 调整移动端提现模态框的布局间距样式
- 修复移动端提现输入框的字体大小显示问题
- 简化提现提交钩子中的国际化处理逻辑
- 移除冗余的数字格式化和多语言参数配置
2026-06-05 17:48:20 +08:00

660 lines
22 KiB
TypeScript

/* 以下为多语言中重复出现的文案,统一声明一次后在下方各 key 复用,避免同一文案多处声明。 */
/** @description 登录的统一文案。 */
const TEXT_LOGIN = 'Login'
/** @description 注册的统一文案。 */
const TEXT_REGISTER = 'Register'
/** @description “是”的统一文案。 */
const TEXT_YES = 'Yes'
/** @description “否”的统一文案。 */
const TEXT_NO = 'No'
/** @description “查看”的统一文案。 */
const TEXT_VIEW = 'View'
/** @description 自动托管的统一文案。 */
const TEXT_AUTO_HOSTING = 'Auto Spin'
/** @description 钱包流水的统一文案。 */
const TEXT_WALLET_RECORDS = 'Wallet Records'
/** @description 站内消息的统一文案。 */
const TEXT_SITE_MESSAGES = 'Messages'
/** @description 分页“第x页/共x条”的统一文案。 */
const TEXT_PAGE_INDICATOR = 'Page {{page}} / {{total}} total'
/** @description 上一页的统一文案。 */
const TEXT_PREV_PAGE = 'Previous'
/** @description 下一页的统一文案。 */
const TEXT_NEXT_PAGE = 'Next'
/** @description “时间”的统一文案。 */
const TEXT_TIME = 'Time'
/** @description 超过单次投注限额的统一文案。 */
const TEXT_BET_LIMIT_EXCEEDED = 'Single bet limit exceeded'
/** @description “提交中...”的统一文案。 */
const TEXT_SUBMITTING = 'Submitting...'
/** @description 手机号字段标签的统一文案。 */
const TEXT_MOBILE_LABEL = 'Mobile:'
/** @description 手机号输入占位的统一文案。 */
const TEXT_MOBILE_PLACEHOLDER = 'Enter mobile number'
/** @description 密码字段标签的统一文案。 */
const TEXT_PASSWORD_LABEL = 'Password:'
/** @description 密码输入占位的统一文案。 */
const TEXT_PASSWORD_PLACEHOLDER = 'Enter password'
/** @description “确认”按钮的统一文案。 */
const TEXT_CONFIRM = 'Confirm'
/** @description “加载中...”的统一文案。 */
const TEXT_LOADING = 'Loading...'
/** @description 货币类型的统一文案。 */
const TEXT_CURRENCY_TYPE = 'Currency Type'
/** @description 支付渠道的统一文案。 */
const TEXT_PAYMENT_CHANNEL = 'Payment Channel'
/** @description “已封盘”的统一文案。 */
const TEXT_LOCKED = 'Locked'
/** @description “已结算”的统一文案。 */
const TEXT_SETTLED = 'Settled'
export default {
nav: {
home: 'Home',
game: 'Game',
},
shell: {
eyebrow: '36 Character Flower',
subtitle: 'Real-time draw game frontend for mobile and desktop',
},
notFound: {
eyebrow: '404',
title: 'The page you requested could not be found.',
description: 'This route does not exist. Return to the scaffold home page.',
home: 'Back home',
},
home: {
eyebrow: 'Game shell in progress',
title:
'The 36-character-flower dual-device game framework is now being built.',
description:
'The project has moved past the generic scaffold stage. It is now being structured around a shared game route, shared state, and split mobile and desktop views for the real-time betting experience.',
cards: {
routingMode: 'Routing',
dataLayer: 'State model',
transport: 'Realtime',
auth: 'Product',
metadata: 'Current focus',
},
values: {
routingMode: 'Shared URL + split device views',
dataLayer: 'Round / Bet / User / UI / Connection',
transport: 'HTTP + WebSocket',
auth: '36-grid live draw gameplay',
metadata: 'Scaffold the structure before state machine polish',
},
footnote:
'Next up: the main game route, shared business model, and dedicated mobile and desktop page shells.',
primaryAction: 'Enter game lobby',
secondaryAction: 'View project structure',
},
language: {
label: 'Language',
zhCN: '中文',
enUS: 'English',
msMY: 'Melayu',
idID: 'Indonesia',
},
game: {
metaTitle: 'Game Lobby',
metaDescription: '36-character-flower live game lobby.',
lobbyTitle: '36 Character Flower Lobby',
lobbySubtitle:
'Under one shared business route, mobile and desktop mount different views on top of the same game data and state.',
status: {
roundState: 'Round state',
currentRound: 'Current round {{id}}',
tablePool: 'Table pool',
onlineCount: '{{count}} online',
activeChip: 'Active chip',
announcementsRead: '{{read}}/{{total}} announcements read',
connection: 'Connection',
connectionHealthy: 'Live sync stable',
connectionRecovering: 'Waiting to recover',
synced: 'Synced',
degraded: 'Degraded',
},
board: {
historyTitle: 'Round history',
historySubtitle: 'Recent draw and payout trace',
trendTitle: 'Trend radar',
trendSubtitle: 'Momentum and miss streak snapshot',
stageTitle: 'Draw stage',
stageSubtitle:
'This stage holds the main board and control structure before the full state machine and animation pass.',
currentPhase: 'Current phase',
selectedBet: 'Bet {{amount}}',
hitCount: '{{count}} hits',
hitBadge: '{{count}}x',
badgeWin: 'Win',
badgeBet: 'Bet',
cellLabel: 'Cell {{id}}',
winningCell: 'Winning cell {{id}}',
missedRounds: 'Missed {{count}} rounds',
rising: 'Rising',
falling: 'Falling',
steady: 'Steady',
hitTotal: '{{count}} hits',
},
phases: {
betting: 'Betting',
locked: TEXT_LOCKED,
settled: TEXT_SETTLED,
},
roundBettingStart: {
title: 'Round {{roundId}}',
action: 'Start Betting',
},
actions: {
unifiedBetHint: 'Unified bet',
totalBet: 'Total bet',
canBet: 'Can bet',
yes: TEXT_YES,
no: TEXT_NO,
quickBet: 'Quick bet 08',
clearPending: 'Clear pending',
autoModeDemo: 'Auto mode demo',
stopAuto: 'Stop auto',
},
modals: {
login: {
title: TEXT_LOGIN,
},
register: {
title: TEXT_REGISTER,
},
notice: {
title: 'Event Notice',
content:
'This area will later load the real event announcement body, rich media, and a longer scrollable message. The current version focuses on shared multilingual modal wiring.',
check: TEXT_VIEW,
},
entryNotice: {
title: 'Site Notice',
subtitle:
'Please read the following notices and confirm before entering the game.',
loading: 'Loading notices...',
loadFailed: 'Failed to load notices. Please try again.',
retry: 'Reload',
agreement: 'I have read and agree.',
enterGame: 'Enter Game',
},
rules: {
title: 'Game Rules',
content:
'1. Basic Gameplay\n1) After each round starts, players may select one or more numbers on the board to place bets.\n2) After betting closes, the system enters the draw phase and settles rewards based on the round result.\n3) Different chip levels correspond to different bet amounts, subject to the current table limits and configuration.\n\n2. Betting Notes\n1) Bets can only be submitted during the betting phase.\n2) Before confirming, please verify your selected numbers, chip amount, and total bet.\n3) If your balance is insufficient, the round is no longer valid, or betting has closed, the request will be rejected.\n\n3. Draw and Settlement\n1) The final displayed draw result is the valid outcome.\n2) Hit rules, odds, payouts, and streak performance are settled in real time according to the current room configuration.\n3) In case of network fluctuation, please refer to the re-synced official data.\n\n4. Additional Notes\n1) Please manage your play time responsibly.\n2) Any abnormal behavior intended to interfere with the system, exploit rewards, or bypass risk control is strictly prohibited.\n3) The platform reserves the right to review orders, payouts, and account status in exceptional situations.',
confirm: 'Understood',
},
procedures: {
title: 'Top Up / Withdraw',
contentPlaceholder: 'Choose the action you want to continue with',
withdraw: 'Withdraw',
topup: 'Top Up',
},
autoSetting: {
title: TEXT_AUTO_HOSTING,
startAutoSpin: 'Start Auto Spin',
rows: {
stopIfBalanceLowerThan: 'Stop if balance is lower than',
stopIfSingleWinExceeds: 'Stop if a single win exceeds',
stopOnAnyJackpot: 'Stop on any jackpot',
},
},
userInfo: {
title: 'User Info',
tabs: {
profile: 'Profile',
financeRecords: 'Top Up / Withdraw Records',
walletRecords: TEXT_WALLET_RECORDS,
message: TEXT_SITE_MESSAGES,
},
profile: {
name: 'Name',
tel: 'Phone',
registeredAt: 'Registered at',
copyInviteLink: 'Copy invite link',
logout: 'Log out',
loggingOut: 'Logging out...',
signature:
'My signature is as unique as my personality. This area will later display the real profile summary.',
},
message: {
title: TEXT_SITE_MESSAGES,
back: 'Back',
loading: 'Loading messages...',
loadFailed: 'Failed to load messages. Please try again later.',
empty: 'No messages yet',
read: 'Read',
unread: 'Unread',
eventBonus:
'[Top-up Bonus Event] From October 1 to October 7, 2026, claim your rebate rewards...',
check: TEXT_VIEW,
deleteRecords: 'Delete records',
},
financeRecords: {
deposit: 'Top-up Records',
withdraw: 'Withdrawal Records',
orderNo: 'Order No.',
amount: 'Amount',
bonusAmount: 'Bonus Amount',
loading: 'Loading records...',
loadFailed: 'Failed to load records. Please try again later.',
empty: 'No records yet',
page: TEXT_PAGE_INDICATOR,
previous: TEXT_PREV_PAGE,
next: TEXT_NEXT_PAGE,
},
walletRecords: {
amount: 'Amount',
balanceAfter: 'After',
balanceBefore: 'Before',
empty: 'No wallet records yet',
loadFailed: 'Failed to load wallet records. Please try again later.',
loading: 'Loading wallet records...',
next: TEXT_NEXT_PAGE,
page: TEXT_PAGE_INDICATOR,
previous: TEXT_PREV_PAGE,
remark: 'Remark',
time: TEXT_TIME,
type: TEXT_WALLET_RECORDS,
},
},
withdrawTopup: {
applyWithdraw: 'Apply for Withdrawal',
applyTopup: 'Apply for Top Up',
},
},
autoSpin: {
eyebrow: 'Auto spin',
title: 'Auto spin running',
description:
'Auto mode will cover the board while preserving target cell focus and progress.',
runningRounds: 'Auto spin running, {{count}} rounds completed',
trailingLabel: 'Manual input locked',
},
footer: {
implementationTitle: 'Current implementation',
implementationSubtitle:
'This iteration prioritizes the dual-device shell, shared model, and business wiring.',
implementationBody:
'Next steps are the real API, WebSocket, full UI store, and round lifecycle state machine.',
limitsTitle: 'Table limits',
limitsSubtitle: 'Derived from the current lobby data',
minBet: 'Min bet',
maxBet: 'Max bet',
},
},
commonUi: {
dialog: {
close: 'Close alert',
confirm: 'OK',
no: TEXT_NO,
yes: TEXT_YES,
},
modal: {
close: 'Close modal',
defaultAriaLabel: 'Modal',
},
boot: {
loading: 'Loading resources',
syncing: 'Syncing the flower deck and game interface',
},
support: {
title: 'Live Support',
connecting: 'Connecting to support',
},
toast: {
lobbyInitFailed: 'Failed to load the game lobby',
loginRequired: 'Please log in before entering the game',
loginSuccess: 'Login successful',
logoutSuccess: 'Logged out',
logoutLocalOnly: 'Logout request failed. Local session was cleared.',
registerSuccess: 'Registration successful',
inviteLinkCopied: 'Invite link copied',
inviteLinkCopyFailed:
'Failed to copy invite link. Please copy it manually.',
insufficientBalance: 'Insufficient balance. Please adjust your bet.',
betLimitExceeded: TEXT_BET_LIMIT_EXCEEDED,
betUnavailable: 'Betting is not available for this round',
betPlaced: 'Bet placed successfully',
noRecentSuccessfulBet:
'No successful bet from the previous round was found',
repeatSelectionsRestored:
'Selections from the last successful round have been restored',
betRejected: 'Bet was not accepted',
betPlaceFailed: 'Failed to place the bet. Please try again.',
selectNumbersBeforeAutoHosting: 'Please select numbers first',
autoHostingStarted: 'Auto spin started',
autoHostingStopped: 'Auto spin stopped',
autoHostingStoppedBalance:
'Balance condition reached. Auto spin has stopped.',
autoHostingStoppedBetLimit:
'Single bet limit exceeded. Auto spin has stopped.',
autoHostingStoppedWin:
'Single-win condition reached. Auto spin has stopped.',
autoHostingStoppedJackpot: 'Jackpot reached. Auto spin has stopped.',
autoHostingSubmitFailed: 'Auto spin bet failed. Auto spin has stopped.',
},
},
auth: {
common: {
arrowIconAlt: 'Arrow',
actions: {
submitting: TEXT_SUBMITTING,
},
passwordVisibility: {
hide: 'Hide password',
show: 'Show password',
},
},
login: {
actions: {
submit: 'Log In',
},
fields: {
username: {
label: TEXT_MOBILE_LABEL,
placeholder: TEXT_MOBILE_PLACEHOLDER,
},
password: {
label: TEXT_PASSWORD_LABEL,
placeholder: TEXT_PASSWORD_PLACEHOLDER,
},
},
footer: {
registerAccount: 'Create account',
forgotPassword: 'Forgot password',
},
errors: {
submitFailed: 'Login failed. Please try again later.',
invalidCredentials: 'Incorrect account or password.',
},
},
register: {
actions: {
submit: TEXT_REGISTER,
},
fields: {
mobile: {
label: TEXT_MOBILE_LABEL,
placeholder: TEXT_MOBILE_PLACEHOLDER,
},
captcha: {
label: 'Code:',
placeholder: 'Enter verification code',
},
password: {
label: TEXT_PASSWORD_LABEL,
placeholder: TEXT_PASSWORD_PLACEHOLDER,
},
confirmPassword: {
label: 'Confirm Password:',
placeholder: 'Re-enter password',
},
inviteCode: {
label: 'Invite Code:',
placeholder: 'Enter invite code',
},
},
footer: {
alreadyHaveAccount: 'Already have an account',
needHelp: 'Need help',
},
errors: {
submitFailed: 'Registration failed. Please try again later.',
unauthorized: 'Registration is not authorized. Please try again later.',
},
sms: {
countdown: '{{seconds}}s',
errors: {
submitFailed: 'Failed to send code. Please try again later.',
},
send: 'Get code',
sending: 'Sending...',
success: 'Verification code sent.',
},
},
validation: {
captcha: {
required: 'Please enter the verification code.',
},
username: {
required: 'Please enter your mobile number.',
invalidPhone: 'Please enter a valid mobile number.',
},
password: {
min: 'Password must be at least 6 characters.',
max: 'Password must be at most 32 characters.',
},
inviteCode: {
required: 'Please enter the invite code.',
max: 'Invite code must be at most 32 characters.',
},
confirmPassword: {
mismatch: 'The two passwords do not match.',
},
},
errors: {
requestFailed: 'Request failed. Please try again later.',
authTokenConfigMissing:
'Authentication configuration is missing. Please contact support.',
timeout: 'Request timed out. Please try again later.',
serviceUnavailable:
'Service is temporarily unavailable. Please try again later.',
},
},
gameDesktop: {
header: {
systemTime: 'System Time',
rules: 'Rules',
message: 'Message',
bgm: 'BGM',
id: 'ID',
fullscreen: 'Full Screen',
login: TEXT_LOGIN,
register: TEXT_REGISTER,
},
control: {
trend: 'Trend',
map: 'Map',
selected: 'Selected',
totalBet: 'Total Bet',
confirm: TEXT_CONFIRM,
selectNumbers: 'Select Numbers',
insufficientBalance: 'Insufficient Balance',
betLimitExceeded: 'Limit Exceeded',
submitting: TEXT_SUBMITTING,
actions: {
clear: 'Clear',
repeat: 'Repeat',
'auto-spin': TEXT_AUTO_HOSTING,
},
},
status: {
odds: 'Odds',
streak: 'Streak',
limit: 'Limit',
roundId: 'Round',
phase: {
betting: {
label: 'Open',
description: '(Accepting Bets)',
},
locked: {
label: TEXT_LOCKED,
description: '(Betting Closed)',
},
revealing: {
label: 'Drawing',
description: '(Revealing Result)',
},
settled: {
label: 'Drawing',
description: '(Round Complete)',
},
waiting: {
label: 'Waiting',
description: '(Waiting for Next Round)',
},
},
},
title: {
announcement: 'Announcement',
},
animal: {
insufficientBalanceRecharge: 'Insufficient balance, please top up',
betLimitExceeded: TEXT_BET_LIMIT_EXCEEDED,
loading: 'Loading',
selectionLimitReached: 'Selection limit exceeded',
tapToEnter: 'Tap To Enter',
getStart: 'Get Start',
noBet: 'No Bet',
},
history: {
title: 'History',
pending: 'PENDING',
win: 'WIN',
lost: 'LOST',
orderNo: 'Order No.',
roundId: 'Round ID',
numbers: 'Bet Numbers',
createdAt: TEXT_TIME,
settledAt: 'Settled At',
totalPoolAmount: 'Bet Amount',
winningResult: 'Winning Result',
payout: 'Win Amount',
empty: 'No history yet',
end: 'No more records',
loading: TEXT_LOADING,
settled: TEXT_SETTLED,
},
periodHistory: {
title: 'Draw Result History',
close: 'Close draw result history',
empty: 'No draw results yet',
failed: 'Failed to load draw results',
loading: TEXT_LOADING,
retry: 'Retry',
},
topup: {
title: 'Top-up Config',
platformCoinLabel: 'Platform Coin',
currencyLabel: TEXT_CURRENCY_TYPE,
channelLabel: TEXT_PAYMENT_CHANNEL,
rateHint:
'Exchange rates are for reference only. The final amount follows the top-up-time rate.',
tier: {
bonus: 'Bonus',
coins: 'Credited Coins',
createSuccess: 'Deposit order created',
empty: 'No deposit tiers',
failed: 'Failed to load deposit tiers',
loading: 'Loading deposit tiers...',
missingPayUrl: 'Payment link is missing. Please try again later.',
openPayUrlFailed:
'Failed to open the payment page. Check your browser popup settings.',
source: 'Deposit tier endpoint',
title: 'Deposit Tiers',
},
preview: {
title: 'Top-up Preview',
depositTitle: 'Select a top-up currency and payment channel',
depositRate: 'Top-up Rate ({{currency}})',
depositRateValue: '1 {{currency}} = {{coins}} {{platformCoinLabel}}',
amount: 'Sample Credit',
},
},
mobile: {
placeholder: 'Mobile entry is under construction',
},
withdraw: {
availableBalance: 'Available balance: {{amount}}',
currencySelection: 'Currency type selection',
selectCurrency: 'Select currency type',
referenceRateNotice:
'Exchange rates are for reference only. The final payout follows the withdrawal-time rate.',
eWallet: 'E-wallet',
bank: 'Bank',
minimumAmount: 'Minimum {{currency}} {{amount}}',
processingTime: 'Processing time',
arrivalTimeValue: 'Arrives in 30s',
notice: 'Note',
feeNotice:
'Transactions between RM10 and RM99.99 will be charged a minimum withdrawal fee of RM 1.',
cancel: 'Cancel',
confirm: TEXT_CONFIRM,
submitSuccess: 'Withdrawal request submitted successfully',
withdrawal: 'Withdrawal',
fields: {
diamondAmount: 'Withdrawal Diamond Amount',
currencyType: TEXT_CURRENCY_TYPE,
paymentChannel: TEXT_PAYMENT_CHANNEL,
bankCode: 'Bank Code',
cardHolderName: 'Card Holder Name',
bankAccountNumber: 'Bank Account Number',
receiverEmail: 'Receiver Email',
receiverPhone: 'Receiver Phone',
},
placeholders: {
bankCode: 'Select bank code',
cardHolderName: 'Enter card holder name',
bankAccountNumber: 'Enter bank account number',
receiverEmail: 'Enter receiver email',
receiverPhone: 'Enter receiver phone number',
},
errors: {
amountRequired: 'Please enter the withdrawal diamond amount.',
amountBelowMinimum:
'The withdrawal amount cannot be lower than the minimum amount ({{currency}} {{amount}} / {{diamonds}} diamonds).',
bankCodeRequired: 'Please select a bank code.',
bankCodeUnavailable: 'No bank code is currently available.',
cardHolderNameRequired: 'Please enter the card holder name.',
bankAccountRequired: 'Please enter the bank account number.',
paymentChannelRequired: 'Please select a payment channel.',
paymentChannelUnavailable: 'No payment channel is currently available.',
receiverEmailInvalid: 'Please enter a valid email address.',
receiverPhoneInvalid: 'Please enter a valid phone number.',
amountExceedsBalance:
'The withdrawal amount cannot exceed the current balance.',
},
success: {
orderNo: 'Order No: {{orderNo}}',
actualArrivalCoin: 'Actual arrival diamonds: {{amount}}',
feeCoin: 'Fee diamonds: {{amount}}',
reviewRequired: 'Risk review required: {{value}}',
},
preview: {
title: 'Exchange Preview',
diamondAmount: 'Diamond Amount',
exchangeRate: 'Exchange Rate ({{currency}})',
exchangeRateValue: '{{coins}} {{platformCoinLabel}} = 1 {{currency}}',
convertible: 'Convertible {{currency}}',
fixedExchangeDiamondAmount: 'Fixed Exchange Diamond Amount',
},
},
},
} as const