diff --git a/app/admin/controller/Channel.php b/app/admin/controller/Channel.php index 2fd711c..a7d4b68 100644 --- a/app/admin/controller/Channel.php +++ b/app/admin/controller/Channel.php @@ -574,7 +574,7 @@ class Channel extends Backend } $rowsRaw = $request->post('list', []); if (!is_array($rowsRaw) || $rowsRaw === []) { - return $this->error('请至少配置一条分配记录'); + return $this->error(__('Please configure at least one share record')); } $adminIds = Db::name('admin') @@ -585,7 +585,7 @@ class Channel extends Backend $adminIdSet[(int) $adminId] = true; } if ($adminIdSet === []) { - return $this->error('该渠道下暂无管理员,无法配置分配比例'); + return $this->error(__('There are no admins under this channel; cannot configure share ratios')); } $enabledSum = '0.00'; @@ -602,7 +602,7 @@ class Channel extends Backend $shareRaw = $line['share_rate'] ?? null; $shareRate = self::normalizeAmountScale($shareRaw === null ? '0' : (string) $shareRaw, 2); if (bccomp($shareRate, '0', 2) < 0 || bccomp($shareRate, '100', 2) > 0) { - return $this->error('分配比例必须在0到100之间'); + return $this->error(__('Share ratio must be between 0 and 100')); } if ($status === 1) { $enabledSum = bcadd($enabledSum, $shareRate, 2); @@ -617,10 +617,10 @@ class Channel extends Backend ]; } if ($insertRows === []) { - return $this->error('请至少配置一条有效分配记录'); + return $this->error(__('Please configure at least one valid share record')); } if (bccomp($enabledSum, '100.00', 2) !== 0) { - return $this->error('启用的分配比例总和必须等于100'); + return $this->error(__('Sum of enabled share ratios must equal 100')); } Db::startTrans(); @@ -633,7 +633,7 @@ class Channel extends Backend return $this->error($e->getMessage()); } - return $this->success('分配比例保存成功'); + return $this->success(__('Share ratios saved successfully')); } /** @@ -646,7 +646,7 @@ class Channel extends Backend return $response; } if (!$this->auth->isSuperAdmin()) { - return $this->error('仅超管可执行结算,结算后系统会自动发放至管理员钱包'); + return $this->error(__('Only super admin can settle; after settlement, commissions will be automatically paid to admin wallets')); } $id = (int) ($request->post('id', $request->get('id', 0))); @@ -665,9 +665,9 @@ class Channel extends Backend $res = ChannelSettlementService::settleBySuperAdmin((int) $row['id'], intval($this->auth->id), $remark, false); if (($res['ok'] ?? false) !== true) { - return $this->error((string) ($res['msg'] ?? '结算失败')); + return $this->error((string) ($res['msg'] ?? __('Settlement failed'))); } - return $this->success('超管结算完成,已按分配比例自动发放给管理员'); + return $this->success(__('Super admin settlement completed; paid automatically by share ratios')); } /** @@ -684,7 +684,7 @@ class Channel extends Backend } // 批量按钮语义:手动触发“待结算渠道”结算,不受结算周期到点限制。 $res = ChannelSettlementService::settleAllDueChannels(intval($this->auth->id), false); - return $this->success('批量结算完成', $res); + return $this->success(__('Batch settlement completed'), $res); } /** @@ -738,7 +738,7 @@ class Channel extends Backend { $channelId = (int) ($row['id'] ?? 0); if ($channelId <= 0) { - return '渠道数据异常'; + return (string) __('Invalid channel data'); } $endTs = time(); @@ -751,7 +751,7 @@ class Channel extends Backend } if ($periodStartTs >= $endTs) { - return '结算区间无效(开始时间不早于当前)'; + return (string) __('Invalid settlement period (start time is not earlier than now)'); } $stats = $this->aggregateBetOrderForChannel($channelId, $periodStartTs, $lastEnd !== null, $endTs); @@ -864,7 +864,7 @@ class Channel extends Backend if ($mode === 'turnover') { $ratePercent = $row['turnover_share_rate'] ?? null; if ($ratePercent === null || $ratePercent === '') { - return '普通返水代理未配置返水分红比例'; + return (string) __('Turnover agent commission rate is not configured'); } $rateDec = bcdiv((string) $ratePercent, '100', 2); $amount = bcmul($totalBet, $rateDec, 2); @@ -879,11 +879,11 @@ class Channel extends Backend $fee = $row['affiliate_fee_rate'] ?? null; $rulesRaw = $row['affiliate_ladder_rules'] ?? null; if ($fee === null || $fee === '') { - return '联营代理未配置成本扣除比例'; + return (string) __('Affiliate agent fee rate is not configured'); } $rules = $this->normalizeLadderRulesForSettlement($rulesRaw); if ($rules === []) { - return '联营阶梯规则无效或为空'; + return (string) __('Affiliate ladder rules are empty or invalid'); } if (bccomp($platformProfit, '0', 2) <= 0) { @@ -915,7 +915,7 @@ class Channel extends Backend ]; } - return '未知的代理模式'; + return (string) __('Unknown agent mode'); } /** @@ -1169,20 +1169,20 @@ class Channel extends Backend { $cycle = isset($data['settle_cycle']) ? trim((string) $data['settle_cycle']) : 'weekly'; if (!in_array($cycle, ['daily', 'weekly', 'monthly'], true)) { - return '结算周期不合法'; + return (string) __('Invalid settlement cycle'); } $data['settle_cycle'] = $cycle; $settleTime = isset($data['settle_time']) ? trim((string) $data['settle_time']) : '02:00:00'; if (!preg_match('/^\d{2}:\d{2}:\d{2}$/', $settleTime)) { - return '结算时间格式不正确(HH:mm:ss)'; + return (string) __('Invalid settlement time format (HH:mm:ss)'); } $data['settle_time'] = $settleTime; if ($cycle === 'weekly') { $weekday = isset($data['settle_weekday']) ? (int) $data['settle_weekday'] : 1; if ($weekday < 1 || $weekday > 7) { - return '周结必须选择周一到周日'; + return (string) __('Weekly settlement must select Monday to Sunday'); } $data['settle_weekday'] = $weekday; } else { @@ -1192,7 +1192,7 @@ class Channel extends Backend if ($cycle === 'monthly') { $monthday = isset($data['settle_monthday']) ? (int) $data['settle_monthday'] : 1; if ($monthday < 1 || $monthday > 31) { - return '月结日期必须在1到31之间'; + return (string) __('Monthly settlement day must be between 1 and 31'); } $data['settle_monthday'] = $monthday; } else { @@ -1204,7 +1204,7 @@ class Channel extends Backend if (isset($data['turnover_share_rate']) && $data['turnover_share_rate'] !== '' && $data['turnover_share_rate'] !== null) { $num = (float) $data['turnover_share_rate']; if ($num < 0 || $num > 100) { - return '返水分红比例必须在0到100之间'; + return (string) __('Turnover commission rate must be between 0 and 100'); } } return null; @@ -1213,11 +1213,11 @@ class Channel extends Backend if ($mode === 'affiliate') { foreach (['affiliate_share_rate' => '联营占成比例', 'affiliate_fee_rate' => '联营成本扣除比例'] as $field => $label) { if (!isset($data[$field]) || $data[$field] === '' || $data[$field] === null) { - return $label . '不能为空'; + return (string) __('Affiliate share/fee rates are required'); } $num = (float) $data[$field]; if ($num < 0 || $num > 1) { - return $label . '必须在0到1之间'; + return (string) __('Affiliate share/fee rates must be between 0 and 1'); } } $ladderErr = $this->validateLadderRulesField($data); @@ -1262,45 +1262,45 @@ class Channel extends Backend { $rulesRaw = $data['affiliate_ladder_rules'] ?? null; if ($rulesRaw === null || $rulesRaw === '') { - return '联营阶梯规则不能为空'; + return (string) __('Affiliate ladder rules are required'); } if (is_string($rulesRaw)) { $decoded = json_decode($rulesRaw, true); if (!is_array($decoded)) { - return '联营阶梯规则必须是有效JSON数组'; + return (string) __('Affiliate ladder rules must be a valid JSON array'); } $rulesRaw = $decoded; } if (!is_array($rulesRaw) || $rulesRaw === []) { - return '联营阶梯规则至少需要一条'; + return (string) __('Affiliate ladder rules must contain at least one row'); } $normalized = []; $prevMinLoss = null; foreach ($rulesRaw as $idx => $rule) { if (!is_array($rule)) { - return '联营阶梯规则第' . ($idx + 1) . '行格式错误'; + return (string) __('Affiliate ladder rules row format error') . ' #' . ($idx + 1); } $minLoss = $rule['minLoss'] ?? ($rule['min_loss'] ?? null); $shareRate = $rule['shareRate'] ?? ($rule['share_rate'] ?? null); if ($minLoss === null || $minLoss === '' || !is_numeric((string) $minLoss)) { - return '联营阶梯规则第' . ($idx + 1) . '行起始客损格式错误'; + return (string) __('Affiliate ladder rules minLoss format error') . ' #' . ($idx + 1); } if ($shareRate === null || $shareRate === '' || !is_numeric((string) $shareRate)) { - return '联营阶梯规则第' . ($idx + 1) . '行占成比例格式错误'; + return (string) __('Affiliate ladder rules shareRate format error') . ' #' . ($idx + 1); } $minLossNum = (float) $minLoss; $shareRateNum = (float) $shareRate; if ($minLossNum < 0) { - return '联营阶梯规则第' . ($idx + 1) . '行起始客损不能为负'; + return (string) __('Affiliate ladder rules minLoss cannot be negative') . ' #' . ($idx + 1); } if ($shareRateNum < 0 || $shareRateNum > 1) { - return '联营阶梯规则第' . ($idx + 1) . '行占成比例必须在0到1之间'; + return (string) __('Affiliate ladder rules shareRate must be between 0 and 1') . ' #' . ($idx + 1); } if ($prevMinLoss !== null && $minLossNum <= $prevMinLoss) { - return '联营阶梯规则需按起始客损递增'; + return (string) __('Affiliate ladder rules must be strictly increasing by minLoss'); } $prevMinLoss = $minLossNum; $normalized[] = [ diff --git a/app/admin/controller/admin/AdminWallet.php b/app/admin/controller/admin/AdminWallet.php index 779dc31..66c0755 100644 --- a/app/admin/controller/admin/AdminWallet.php +++ b/app/admin/controller/admin/AdminWallet.php @@ -81,17 +81,17 @@ class AdminWallet extends Backend protected function _add(): Response { - return $this->error('管理员钱包不允许手动新增'); + return $this->error(__('Admin wallet does not allow manual creation')); } protected function _edit(): Response { - return $this->error('管理员钱包不允许手动编辑'); + return $this->error(__('Admin wallet does not allow manual editing')); } protected function _del(): Response { - return $this->error('管理员钱包不允许删除'); + return $this->error(__('Admin wallet does not allow deletion')); } } diff --git a/app/admin/controller/admin/AdminWalletRecord.php b/app/admin/controller/admin/AdminWalletRecord.php index e7968df..ccacc14 100644 --- a/app/admin/controller/admin/AdminWalletRecord.php +++ b/app/admin/controller/admin/AdminWalletRecord.php @@ -63,17 +63,17 @@ class AdminWalletRecord extends Backend protected function _add(): Response { - return $this->error('管理员钱包流水不允许手动新增'); + return $this->error(__('Admin wallet records do not allow manual creation')); } protected function _edit(): Response { - return $this->error('管理员钱包流水不允许手动编辑'); + return $this->error(__('Admin wallet records do not allow manual editing')); } protected function _del(): Response { - return $this->error('管理员钱包流水不允许删除'); + return $this->error(__('Admin wallet records do not allow deletion')); } } diff --git a/app/admin/controller/auth/Admin.php b/app/admin/controller/auth/Admin.php index 77591e9..d5aa039 100644 --- a/app/admin/controller/auth/Admin.php +++ b/app/admin/controller/auth/Admin.php @@ -152,7 +152,7 @@ class Admin extends Backend } $data = $this->normalizeSingleGroup($data); if (!$this->hasSingleGroup($data['group_arr'] ?? null)) { - return $this->error('请选择且仅选择一个角色组'); + return $this->error(__('Please select exactly one role group')); } if ($this->modelValidate) { @@ -184,10 +184,10 @@ class Admin extends Backend return $this->error(__('You have no permission')); } if ($groupChannelId === null || $groupChannelId === '') { - return $this->error('所选角色组未绑定渠道'); + return $this->error(__('Selected role group is not bound to a channel')); } if ((string) $groupChannelId !== (string) $creatorChannelId) { - return $this->error('所选角色组渠道与当前账号不一致'); + return $this->error(__('Selected role group channel does not match current account')); } $data['channel_id'] = $creatorChannelId; $data['parent_admin_id'] = $this->auth->id; @@ -255,7 +255,7 @@ class Admin extends Backend } $data = $this->normalizeSingleGroup($data); if (!$this->hasSingleGroup($data['group_arr'] ?? null)) { - return $this->error('请选择且仅选择一个角色组'); + return $this->error(__('Please select exactly one role group')); } $postedGroups = array_map('intval', $data['group_arr'] ?? []); @@ -331,10 +331,10 @@ class Admin extends Backend return $this->error(__('You have no permission')); } if ($groupChannelId === null || $groupChannelId === '') { - return $this->error('所选角色组未绑定渠道'); + return $this->error(__('Selected role group is not bound to a channel')); } if ((string) $groupChannelId !== (string) $creatorChannelId) { - return $this->error('所选角色组渠道与当前账号不一致'); + return $this->error(__('Selected role group channel does not match current account')); } $data['channel_id'] = $creatorChannelId; } else { diff --git a/app/admin/controller/config/DepositChannel.php b/app/admin/controller/config/DepositChannel.php index badd05f..039320f 100644 --- a/app/admin/controller/config/DepositChannel.php +++ b/app/admin/controller/config/DepositChannel.php @@ -231,7 +231,7 @@ class DepositChannel extends Backend } $items = $payload['items'] ?? null; if (!is_array($items)) { - return $this->error('items 必须为数组'); + return $this->error(__('Items must be an array')); } return $this->persistChannelList($items); @@ -250,7 +250,7 @@ class DepositChannel extends Backend $got = array_column($clean, 'code'); sort($got); if ($expectedCodes !== $got) { - return $this->error('请保存全部已注册渠道行(不可缺行)'); + return $this->error(__('Please save all registered channel rows (no missing rows)')); } $json = DepositChannelLib::encodeForDb($clean); } catch (InvalidArgumentException $e) { @@ -261,7 +261,7 @@ class DepositChannel extends Backend $resourceKey = GameHotDataLock::safeResourceKeyForConfig(DepositChannelLib::CONFIG_KEY); $lock = GameHotDataLock::tryAcquire(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey); if (!$lock['acquired']) { - return $this->error('该配置正在被其他操作占用,请稍后再试'); + return $this->error(__('This config is locked by another operation, please try again later')); } try { try { diff --git a/app/admin/controller/config/DepositTier.php b/app/admin/controller/config/DepositTier.php index 364442e..86f86e4 100644 --- a/app/admin/controller/config/DepositTier.php +++ b/app/admin/controller/config/DepositTier.php @@ -264,7 +264,7 @@ class DepositTier extends Backend } $rid = $it['id'] ?? ''; if (is_string($rid) && $rid === $newId) { - return $this->error('档位 ID 已存在'); + return $this->error(__('Tier ID already exists')); } } $items[] = $this->normalizeFormRow($payload, $newId); @@ -342,7 +342,7 @@ class DepositTier extends Backend } $items = $payload['items'] ?? null; if (!is_array($items)) { - return $this->error('items 必须为数组'); + return $this->error(__('Items must be an array')); } return $this->persistTierList($items); @@ -364,7 +364,7 @@ class DepositTier extends Backend $resourceKey = GameHotDataLock::safeResourceKeyForConfig(DepositTierLib::CONFIG_KEY); $lock = GameHotDataLock::tryAcquire(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey); if (!$lock['acquired']) { - return $this->error('该配置正在被其他操作占用,请稍后再试'); + return $this->error(__('This config is locked by another operation, please try again later')); } try { try { diff --git a/app/admin/controller/config/FinanceCashierConfig.php b/app/admin/controller/config/FinanceCashierConfig.php index c1ad7a6..22611e6 100644 --- a/app/admin/controller/config/FinanceCashierConfig.php +++ b/app/admin/controller/config/FinanceCashierConfig.php @@ -119,7 +119,7 @@ class FinanceCashierConfig extends Backend $resourceKey = GameHotDataLock::safeResourceKeyForConfig(FinanceCashierConfigLib::CONFIG_KEY); $lock = GameHotDataLock::tryAcquire(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey); if (!$lock['acquired']) { - return $this->error('该配置正在被其他操作占用,请稍后再试'); + return $this->error(__('This config is locked by another operation, please try again later')); } try { try { diff --git a/app/admin/controller/config/StreakWinReward.php b/app/admin/controller/config/StreakWinReward.php index e16bf7a..d423563 100644 --- a/app/admin/controller/config/StreakWinReward.php +++ b/app/admin/controller/config/StreakWinReward.php @@ -88,14 +88,14 @@ class StreakWinReward extends Backend } $payload = $request->post('rows'); if (!is_array($payload)) { - return $this->error('参数错误'); + return $this->error(__('Invalid parameters')); } $encoded = StreakWinRewardLib::encodeForDb($payload); $now = time(); $resourceKey = GameHotDataLock::safeResourceKeyForConfig(StreakWinRewardLib::CONFIG_KEY); $lock = GameHotDataLock::tryAcquire(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey); if (!$lock['acquired']) { - return $this->error('该配置正在被其他操作占用,请稍后再试'); + return $this->error(__('This config is locked by another operation, please try again later')); } try { Db::startTrans(); @@ -125,7 +125,7 @@ class StreakWinReward extends Backend StreakWinRewardLib::clearCache(); GameHotDataCoordinator::afterGameConfigKeyCommitted(StreakWinRewardLib::CONFIG_KEY); - return $this->success('保存成功'); + return $this->success(__('Saved successfully')); } finally { GameHotDataLock::release(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey, $lock['token'], $lock['redis_lock']); } diff --git a/app/admin/controller/config/ZiHuaDictionary.php b/app/admin/controller/config/ZiHuaDictionary.php index 740d65b..86ff5d6 100644 --- a/app/admin/controller/config/ZiHuaDictionary.php +++ b/app/admin/controller/config/ZiHuaDictionary.php @@ -95,7 +95,7 @@ class ZiHuaDictionary extends Backend } $items = $payload['items'] ?? null; if (!is_array($items)) { - return $this->error('items 必须为数组'); + return $this->error(__('Items must be an array')); } try { $clean = ZiHuaDictionaryLib::prepareItemsForSave($items); @@ -108,7 +108,7 @@ class ZiHuaDictionary extends Backend $resourceKey = GameHotDataLock::safeResourceKeyForConfig(ZiHuaDictionaryLib::CONFIG_KEY); $lock = GameHotDataLock::tryAcquire(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey); if (!$lock['acquired']) { - return $this->error('该配置正在被其他操作占用,请稍后再试'); + return $this->error(__('This config is locked by another operation, please try again later')); } try { try { diff --git a/app/admin/controller/game/PlayRecord.php b/app/admin/controller/game/PlayRecord.php index 335d8b1..785f059 100644 --- a/app/admin/controller/game/PlayRecord.php +++ b/app/admin/controller/game/PlayRecord.php @@ -35,7 +35,7 @@ class PlayRecord extends Backend if ($response !== null) { return $response; } - return $this->error('游玩记录由游戏接口生成,禁止后台手工新增'); + return $this->error(__('Play record is generated by game API; manual creation is not allowed')); } public function edit(WebmanRequest $request): Response @@ -44,7 +44,7 @@ class PlayRecord extends Backend if ($response !== null) { return $response; } - return $this->error('游玩记录不可编辑'); + return $this->error(__('Play record cannot be edited')); } public function del(WebmanRequest $request): Response @@ -53,7 +53,7 @@ class PlayRecord extends Backend if ($response !== null) { return $response; } - return $this->error('游玩记录不可删除'); + return $this->error(__('Play record cannot be deleted')); } public function sortable(WebmanRequest $request): Response @@ -62,7 +62,7 @@ class PlayRecord extends Backend if ($response !== null) { return $response; } - return $this->error('不支持排序'); + return $this->error(__('Sorting is not supported')); } protected function _index(): Response diff --git a/app/admin/controller/game/Record.php b/app/admin/controller/game/Record.php index 8f8a3b6..7bcc8d5 100644 --- a/app/admin/controller/game/Record.php +++ b/app/admin/controller/game/Record.php @@ -38,7 +38,7 @@ class Record extends Backend if ($response !== null) { return $response; } - return $this->error('游戏对局记录由系统自动生成,禁止后台手工新增'); + return $this->error(__('Game record is generated by system; manual creation is not allowed')); } public function edit(WebmanRequest $request): Response @@ -48,7 +48,7 @@ class Record extends Backend return $response; } if ($request->method() === 'POST') { - return $this->error('游戏对局记录不可编辑'); + return $this->error(__('Game record cannot be edited')); } $pk = $this->model->getPk(); $id = $request->get($pk); @@ -65,7 +65,7 @@ class Record extends Backend if ($response !== null) { return $response; } - return $this->error('游戏对局记录不可删除'); + return $this->error(__('Game record cannot be deleted')); } public function abnormalList(WebmanRequest $request): Response diff --git a/app/admin/controller/game/ZiHuaDictionary.php b/app/admin/controller/game/ZiHuaDictionary.php index c145648..bcbe0d6 100644 --- a/app/admin/controller/game/ZiHuaDictionary.php +++ b/app/admin/controller/game/ZiHuaDictionary.php @@ -81,7 +81,7 @@ class ZiHuaDictionary extends Backend } $items = $payload['items'] ?? null; if (!is_array($items)) { - return $this->error('items 必须为数组'); + return $this->error(__('Items must be an array')); } try { $clean = ZiHuaDictionaryLib::prepareItemsForSave($items); @@ -94,7 +94,7 @@ class ZiHuaDictionary extends Backend $resourceKey = GameHotDataLock::safeResourceKeyForConfig(ZiHuaDictionaryLib::CONFIG_KEY); $lock = GameHotDataLock::tryAcquire(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey); if (!$lock['acquired']) { - return $this->error('该配置正在被其他操作占用,请稍后再试'); + return $this->error(__('This config is locked by another operation, please try again later')); } try { try { diff --git a/app/admin/controller/order/AdminWithdrawOrder.php b/app/admin/controller/order/AdminWithdrawOrder.php index 804c80a..971335f 100644 --- a/app/admin/controller/order/AdminWithdrawOrder.php +++ b/app/admin/controller/order/AdminWithdrawOrder.php @@ -78,7 +78,7 @@ class AdminWithdrawOrder extends Backend return $this->error(__('Parameter error')); } if ($this->request && $this->request->method() === 'POST') { - return $this->error('请使用通过/拒绝按钮审核'); + return $this->error(__('Please use approve/reject buttons to review')); } $row = $this->loadWithRelations(intval(strval($id))); if (!$row) { @@ -111,7 +111,7 @@ class AdminWithdrawOrder extends Backend return $this->error(__('You have no permission')); } if (intval($order['status'] ?? 0) !== 0) { - return $this->error('该提现订单已审核'); + return $this->error(__('This withdraw order has already been reviewed')); } $remark = trim((string) $request->post('remark', '')); Db::startTrans(); @@ -122,7 +122,7 @@ class AdminWithdrawOrder extends Backend Db::rollback(); return $this->error($e->getMessage()); } - return $this->success('审核通过'); + return $this->success(__('Approved')); } public function reject(WebmanRequest $request): Response @@ -140,7 +140,7 @@ class AdminWithdrawOrder extends Backend } $remark = trim((string) $request->post('remark', '')); if ($remark === '') { - return $this->error('请填写拒绝原因'); + return $this->error(__('Please provide reject reason')); } $order = Db::name('admin_withdraw_order')->where('id', $id)->find(); if (!is_array($order)) { @@ -150,7 +150,7 @@ class AdminWithdrawOrder extends Backend return $this->error(__('You have no permission')); } if (intval($order['status'] ?? 0) !== 0) { - return $this->error('该提现订单已审核'); + return $this->error(__('This withdraw order has already been reviewed')); } Db::startTrans(); try { @@ -160,7 +160,7 @@ class AdminWithdrawOrder extends Backend Db::rollback(); return $this->error($e->getMessage()); } - return $this->success('审核拒绝完成'); + return $this->success(__('Rejected')); } public function stats(WebmanRequest $request): Response diff --git a/app/admin/controller/order/BetOrder.php b/app/admin/controller/order/BetOrder.php index 2ff9a19..c27643f 100644 --- a/app/admin/controller/order/BetOrder.php +++ b/app/admin/controller/order/BetOrder.php @@ -35,7 +35,7 @@ class BetOrder extends Backend if ($response !== null) { return $response; } - return $this->error('注单由游戏接口生成,禁止后台手工新增'); + return $this->error(__('Bet order is generated by game API; manual creation is not allowed')); } public function edit(WebmanRequest $request): Response @@ -44,7 +44,7 @@ class BetOrder extends Backend if ($response !== null) { return $response; } - return $this->error('注单不可编辑'); + return $this->error(__('Bet order cannot be edited')); } public function del(WebmanRequest $request): Response @@ -53,7 +53,7 @@ class BetOrder extends Backend if ($response !== null) { return $response; } - return $this->error('注单不可删除'); + return $this->error(__('Bet order cannot be deleted')); } public function sortable(WebmanRequest $request): Response @@ -62,7 +62,7 @@ class BetOrder extends Backend if ($response !== null) { return $response; } - return $this->error('不支持排序'); + return $this->error(__('Sorting is not supported')); } /** diff --git a/app/admin/controller/order/DepositOrder.php b/app/admin/controller/order/DepositOrder.php index 048e1ff..30e411a 100644 --- a/app/admin/controller/order/DepositOrder.php +++ b/app/admin/controller/order/DepositOrder.php @@ -93,7 +93,7 @@ class DepositOrder extends Backend } if ($this->request && $this->request->method() === 'POST') { - return $this->error('充值订单为自动入账,禁止直接修改,如需补单请走专用工具'); + return $this->error(__('Deposit orders are auto-settled; direct modification is not allowed. Use the dedicated tool for manual adjustment.')); } $row = $this->loadWithRelations(intval(strval($id))); diff --git a/app/admin/controller/order/WithdrawOrder.php b/app/admin/controller/order/WithdrawOrder.php index d94badf..00a8eca 100644 --- a/app/admin/controller/order/WithdrawOrder.php +++ b/app/admin/controller/order/WithdrawOrder.php @@ -84,7 +84,7 @@ class WithdrawOrder extends Backend if ($this->request && $this->request->method() === 'POST') { // 历史 CRUD 的 POST 编辑已被 approve/reject 替代,这里阻止直接改金额绕过审核流程 - return $this->error('请使用通过/拒绝按钮完成审核'); + return $this->error(__('Please use approve/reject buttons to complete the review')); } $row = $this->loadWithRelations(intval(strval($id))); @@ -119,13 +119,13 @@ class WithdrawOrder extends Backend $newAmount = $this->decimalParam($request->post('amount'), '0'); $newFee = $this->decimalParam($request->post('fee'), '0'); if (bccomp($newAmount, '0', 2) <= 0) { - return $this->error('申请金额必须大于 0'); + return $this->error(__('Apply amount must be greater than 0')); } if (bccomp($newFee, '0', 2) < 0) { - return $this->error('手续费不能为负'); + return $this->error(__('Fee cannot be negative')); } if (bccomp($newFee, $newAmount, 2) > 0) { - return $this->error('手续费不能大于申请金额'); + return $this->error(__('Fee cannot be greater than apply amount')); } $newActual = bcsub($newAmount, $newFee, 2); @@ -141,12 +141,12 @@ class WithdrawOrder extends Backend } $currentStatus = $this->intParam($order['status'] ?? 0); if ($currentStatus !== 0) { - return $this->error('该订单已审核,无需重复操作'); + return $this->error(__('This order has already been reviewed')); } $userId = $this->intParam($order['user_id'] ?? 0); if ($userId <= 0) { - return $this->error('订单缺少用户信息'); + return $this->error(__('Order is missing user info')); } $oldAmount = bcadd(strval($order['amount'] ?? '0'), '0', 2); $diff = bcsub($newAmount, $oldAmount, 2); @@ -173,12 +173,12 @@ class WithdrawOrder extends Backend $userRow = Db::name('user')->where('id', $userId)->find(); if (!$userRow) { Db::rollback(); - return $this->error('关联用户不存在'); + return $this->error(__('Related user does not exist')); } $beforeCoin = bcadd(strval($userRow['coin'] ?? '0'), '0', 2); if (bccomp($beforeCoin, $diff, 2) < 0) { Db::rollback(); - return $this->error('用户余额不足以补扣调整差额'); + return $this->error(__('User balance is insufficient to cover the adjustment difference')); } $afterCoin = bcsub($beforeCoin, $diff, 2); Db::name('user')->where('id', $userId)->update([ @@ -208,7 +208,7 @@ class WithdrawOrder extends Backend $userRow = Db::name('user')->where('id', $userId)->find(); if (!$userRow) { Db::rollback(); - return $this->error('关联用户不存在'); + return $this->error(__('Related user does not exist')); } $beforeCoin = bcadd(strval($userRow['coin'] ?? '0'), '0', 2); $afterCoin = bcadd($beforeCoin, $abs, 2); @@ -251,7 +251,7 @@ class WithdrawOrder extends Backend return $this->error($e->getMessage()); } - return $this->success('审核通过', [ + return $this->success(__('Approved'), [ 'id' => $id, 'amount' => $newAmount, 'fee' => $newFee, @@ -281,7 +281,7 @@ class WithdrawOrder extends Backend $remarkRaw = $request->post('remark'); $remark = is_string($remarkRaw) ? trim($remarkRaw) : ''; if ($remark === '') { - return $this->error('请填写拒绝原因'); + return $this->error(__('Please provide reject reason')); } $order = Db::name('withdraw_order')->where('id', $id)->find(); @@ -293,12 +293,12 @@ class WithdrawOrder extends Backend } $currentStatus = $this->intParam($order['status'] ?? 0); if ($currentStatus !== 0) { - return $this->error('该订单已审核,无需重复操作'); + return $this->error(__('This order has already been reviewed')); } $userId = $this->intParam($order['user_id'] ?? 0); if ($userId <= 0) { - return $this->error('订单缺少用户信息'); + return $this->error(__('Order is missing user info')); } $amount = bcadd(strval($order['amount'] ?? '0'), '0', 2); $channelIdRaw = $order['channel_id'] ?? null; @@ -315,7 +315,7 @@ class WithdrawOrder extends Backend $userRow = Db::name('user')->where('id', $userId)->find(); if (!$userRow) { Db::rollback(); - return $this->error('关联用户不存在'); + return $this->error(__('Related user does not exist')); } $beforeCoin = bcadd(strval($userRow['coin'] ?? '0'), '0', 2); $afterCoin = bcadd($beforeCoin, $amount, 2); @@ -355,7 +355,7 @@ class WithdrawOrder extends Backend return $this->error($e->getMessage()); } - return $this->success('审核已拒绝', [ + return $this->success(__('Rejected'), [ 'id' => $id, 'status' => 2, 'remark' => $remark, diff --git a/app/admin/controller/routine/AdminInfo.php b/app/admin/controller/routine/AdminInfo.php index ce69e7e..a2dc98b 100644 --- a/app/admin/controller/routine/AdminInfo.php +++ b/app/admin/controller/routine/AdminInfo.php @@ -164,18 +164,18 @@ class AdminInfo extends Backend $receiveType = trim(is_string($request->post('receive_type', '')) ? $request->post('receive_type', '') : ''); $idempotencyKey = trim(is_string($request->post('idempotency_key', '')) ? $request->post('idempotency_key', '') : ''); if ($withdrawCoin === '' || $receiveAccount === '' || $receiveType === '' || $idempotencyKey === '') { - return $this->error('参数缺失'); + return $this->error(__('Missing required parameters')); } if (mb_strlen($idempotencyKey) > 64) { - return $this->error('幂等键过长'); + return $this->error(__('Idempotency key is too long')); } if (!is_numeric($withdrawCoin) || bccomp($withdrawCoin, '0', 2) <= 0) { - return $this->error('提现金额必须大于0'); + return $this->error(__('Withdraw amount must be greater than 0')); } $withdrawCoin = bcadd($withdrawCoin, '0', 2); $allowedReceiveTypes = ['bank', 'ewallet', 'crypto']; if (!in_array($receiveType, $allowedReceiveTypes, true)) { - return $this->error('收款类型不合法,仅支持 bank/ewallet/crypto'); + return $this->error(__('Invalid receive type; only bank/ewallet/crypto are supported')); } $remark = trim((string) $request->post('remark', '')); $admin = Db::name('admin')->field(['id', 'channel_id'])->where('id', $adminId)->find(); @@ -185,14 +185,14 @@ class AdminInfo extends Backend $res = AdminWalletService::applyWithdraw($adminId, $channelId, $withdrawCoin, $receiveType, $receiveAccount, $idempotencyKey, $remark); if (($res['ok'] ?? false) !== true) { Db::rollback(); - return $this->error(strval($res['msg'] ?? '提现申请失败')); + return $this->error(strval($res['msg'] ?? __('Withdraw apply failed'))); } Db::commit(); } catch (Throwable $e) { Db::rollback(); return $this->error($e->getMessage()); } - return $this->success('提现申请已提交,待渠道超管审核', [ + return $this->success(__('Withdraw request submitted; pending channel super admin review'), [ 'order_id' => intval($res['order_id'] ?? 0), 'order_no' => strval($res['order_no'] ?? ''), 'idempotent_hit' => !empty($res['idempotent_hit']), diff --git a/app/admin/controller/user/User.php b/app/admin/controller/user/User.php index 4ef282a..84030dd 100644 --- a/app/admin/controller/user/User.php +++ b/app/admin/controller/user/User.php @@ -234,16 +234,16 @@ class User extends Backend $opRaw = $request->post('op'); $op = is_string($opRaw) ? trim($opRaw) : ''; if (!in_array($op, ['credit', 'deduct'], true)) { - return $this->error('操作类型不正确'); + return $this->error(__('Invalid operation type')); } $amountRaw = $request->post('amount'); $amountText = is_string($amountRaw) || is_numeric($amountRaw) ? trim(strval($amountRaw)) : ''; if ($amountText === '' || !is_numeric($amountText)) { - return $this->error('金额格式不正确'); + return $this->error(__('Invalid amount format')); } if (bccomp($amountText, '0', 2) <= 0) { - return $this->error('金额必须大于0'); + return $this->error(__('Amount must be greater than 0')); } $remarkRaw = $request->post('remark'); @@ -257,7 +257,7 @@ class User extends Backend $lock = GameHotDataRedis::userAdminMutationLockTry($userId); if (!$lock['acquired']) { - return $this->error('该用户正在被其他管理员操作(钱包/并发保存),请稍后再试'); + return $this->error(__('This user is being operated by another admin (wallet/concurrent save); please try again later')); } try { @@ -284,7 +284,7 @@ class User extends Backend $direction = 1; } else { if (bccomp($before, $delta, 2) < 0) { - return $this->error('余额不足,扣点失败'); + return $this->error(__('Insufficient balance; deduction failed')); } $after = bcsub($before, $delta, 2); $bizType = 'admin_deduct'; @@ -306,7 +306,7 @@ class User extends Backend ]); if ($affected !== 1) { Db::rollback(); - return $this->error('保存失败:该用户余额已被其他请求修改(如下注、派彩或其他管理员已保存),请刷新后重试'); + return $this->error(__('Save failed: user balance changed by another request; please refresh and retry')); } Db::name('user_wallet_record')->insert([ @@ -332,7 +332,7 @@ class User extends Backend GameHotDataCoordinator::afterUserCommitted($userId); - return $this->success('钱包调整成功', [ + return $this->success(__('Wallet adjusted successfully'), [ 'user_id' => $userId, 'coin_before' => self::formatAmountForDisplay($before), 'coin_after' => self::formatAmountForDisplay($after), diff --git a/app/admin/controller/user/UserWalletRecord.php b/app/admin/controller/user/UserWalletRecord.php index f4cd866..9f76bf9 100644 --- a/app/admin/controller/user/UserWalletRecord.php +++ b/app/admin/controller/user/UserWalletRecord.php @@ -35,7 +35,7 @@ class UserWalletRecord extends Backend if ($response !== null) { return $response; } - return $this->error('钱包流水仅允许业务入账,禁止后台手工新增'); + return $this->error(__('Wallet records are business-generated; manual creation is not allowed')); } public function edit(WebmanRequest $request): Response @@ -44,7 +44,7 @@ class UserWalletRecord extends Backend if ($response !== null) { return $response; } - return $this->error('钱包流水不可编辑'); + return $this->error(__('Wallet record cannot be edited')); } public function del(WebmanRequest $request): Response @@ -53,7 +53,7 @@ class UserWalletRecord extends Backend if ($response !== null) { return $response; } - return $this->error('钱包流水不可删除'); + return $this->error(__('Wallet record cannot be deleted')); } public function sortable(WebmanRequest $request): Response @@ -62,7 +62,7 @@ class UserWalletRecord extends Backend if ($response !== null) { return $response; } - return $this->error('不支持排序'); + return $this->error(__('Sorting is not supported')); } /** diff --git a/app/api/controller/Finance.php b/app/api/controller/Finance.php index dfe1eb4..a1797ad 100644 --- a/app/api/controller/Finance.php +++ b/app/api/controller/Finance.php @@ -304,7 +304,8 @@ class Finance extends MobileBase } $msgEsc = htmlspecialchars($msg, ENT_QUOTES, 'UTF-8'); - return response('充值

' . $msgEsc . '

', 200, [ + $title = htmlspecialchars((string) __('Deposit'), ENT_QUOTES, 'UTF-8'); + return response('' . $title . '

' . $msgEsc . '

', 200, [ 'Content-Type' => 'text/html; charset=utf-8', ]); } @@ -313,16 +314,27 @@ class Finance extends MobileBase $noEsc = htmlspecialchars($orderNo, ENT_QUOTES, 'UTF-8'); $signEsc = htmlspecialchars($sign, ENT_QUOTES, 'UTF-8'); $payChannel = is_string($order->pay_channel) ? htmlspecialchars($order->pay_channel, ENT_QUOTES, 'UTF-8') : ''; - $html = '模拟支付'; - $html .= '

模拟第三方收银台

'; - $html .= '

订单号:' . $noEsc . '

'; - $html .= '

支付渠道:' . $payChannel . '

'; - $html .= '

金额(法币/标价):' . htmlspecialchars($amount, ENT_QUOTES, 'UTF-8') . ' + 赠送 ' . htmlspecialchars($bonus, ENT_QUOTES, 'UTF-8') . '(币)

'; - $html .= '

点击下方按钮即视为第三方支付成功,服务端会回调并到账。

'; + $tMockPay = htmlspecialchars((string) __('Mock payment'), ENT_QUOTES, 'UTF-8'); + $tCashier = htmlspecialchars((string) __('Mock third-party cashier'), ENT_QUOTES, 'UTF-8'); + $tOrderNo = htmlspecialchars((string) __('Order No'), ENT_QUOTES, 'UTF-8'); + $tPayChannel = htmlspecialchars((string) __('Pay channel'), ENT_QUOTES, 'UTF-8'); + $tAmountLabel = htmlspecialchars((string) __('Amount (fiat/pricing)'), ENT_QUOTES, 'UTF-8'); + $tBonus = htmlspecialchars((string) __('Bonus'), ENT_QUOTES, 'UTF-8'); + $tCoin = htmlspecialchars((string) __('coin'), ENT_QUOTES, 'UTF-8'); + $tHint = (string) __('Click the button below to simulate successful third-party payment; the server will callback and settle the deposit.'); + $tHintEsc = htmlspecialchars($tHint, ENT_QUOTES, 'UTF-8'); + $tConfirm = htmlspecialchars((string) __('Confirm payment (simulate success)'), ENT_QUOTES, 'UTF-8'); + + $html = '' . $tMockPay . ''; + $html .= '

' . $tCashier . '

'; + $html .= '

' . $tOrderNo . ': ' . $noEsc . '

'; + $html .= '

' . $tPayChannel . ': ' . $payChannel . '

'; + $html .= '

' . $tAmountLabel . ': ' . htmlspecialchars($amount, ENT_QUOTES, 'UTF-8') . ' + ' . $tBonus . ' ' . htmlspecialchars($bonus, ENT_QUOTES, 'UTF-8') . ' (' . $tCoin . ')

'; + $html .= '

' . $tHintEsc . '

'; $html .= '
'; $html .= ''; $html .= ''; - $html .= ''; + $html .= ''; $html .= '
'; return response($html, 200, [ @@ -373,7 +385,7 @@ class Finance extends MobileBase 'channel_code=' . $pc ); } catch (Throwable $e) { - return $this->mobileError(2000, $e->getMessage()); + return $this->mobileError(2000, (string) __($e->getMessage())); } $fresh = DepositOrder::where('order_no', $orderNo)->find(); if (!$fresh) { diff --git a/app/api/controller/Game.php b/app/api/controller/Game.php index 61db76f..dc13020 100644 --- a/app/api/controller/Game.php +++ b/app/api/controller/Game.php @@ -186,7 +186,7 @@ class Game extends MobileBase $lock = GameHotDataRedis::userAdminMutationLockTry($userId); if (!$lock['acquired']) { - return $this->mobileError(5000, '该用户正在被其他管理员操作(钱包/并发保存),请稍后再试'); + return $this->mobileError(5000, (string) __('This user is being operated by another admin (wallet/concurrent save); please try again later')); } try { @@ -223,7 +223,7 @@ class Game extends MobileBase ]); if ($affected !== 1) { Db::rollback(); - return $this->mobileError(5000, '扣款失败:该用户余额已被其他请求修改(如下注、派彩或其他管理员已保存),请刷新后重试'); + return $this->mobileError(5000, (string) __('Debit failed: user balance changed by another request; please refresh and retry')); } UserWalletRecord::create([ diff --git a/app/common/lang/en/service.php b/app/common/lang/en/service.php new file mode 100644 index 0000000..eb1b262 --- /dev/null +++ b/app/common/lang/en/service.php @@ -0,0 +1,186 @@ + 'Channel not found', + 'Settlement number conflict, please retry' => 'Settlement number conflict, please retry', + 'No available admin share ratios under this channel; cannot settle' => 'No available admin share ratios under this channel; cannot settle', + 'This flow pays commissions automatically after super admin settlement; channel admin does not need to settle again' => 'This flow pays commissions automatically after super admin settlement; channel admin does not need to settle again', + 'Invalid channel data' => 'Invalid channel data', + 'Invalid settlement period (start time is not earlier than now)' => 'Invalid settlement period (start time is not earlier than now)', + 'Turnover agent commission rate is not configured' => 'Turnover agent commission rate is not configured', + 'Affiliate agent fee rate is not configured' => 'Affiliate agent fee rate is not configured', + 'Affiliate ladder rules are empty or invalid' => 'Affiliate ladder rules are empty or invalid', + 'Unknown agent mode' => 'Unknown agent mode', + + 'Manual create next round is disabled' => 'Manual create next round is disabled', + 'There is an unfinished round; cannot create a new one' => 'There is an unfinished round; cannot create a new one', + 'New round created' => 'New round created', + + 'Idempotency key conflict' => 'Idempotency key conflict', + 'Insufficient wallet balance' => 'Insufficient wallet balance', + + 'Game record is generated by system; manual creation is not allowed' => 'Game record is generated by system; manual creation is not allowed', + 'Game record cannot be edited' => 'Game record cannot be edited', + 'Game record cannot be deleted' => 'Game record cannot be deleted', + + 'Bet order is generated by game API; manual creation is not allowed' => 'Bet order is generated by game API; manual creation is not allowed', + 'Bet order cannot be edited' => 'Bet order cannot be edited', + 'Bet order cannot be deleted' => 'Bet order cannot be deleted', + 'Sorting is not supported' => 'Sorting is not supported', + + 'Play record is generated by game API; manual creation is not allowed' => 'Play record is generated by game API; manual creation is not allowed', + 'Play record cannot be edited' => 'Play record cannot be edited', + 'Play record cannot be deleted' => 'Play record cannot be deleted', + + 'Wallet records are business-generated; manual creation is not allowed' => 'Wallet records are business-generated; manual creation is not allowed', + 'Wallet record cannot be edited' => 'Wallet record cannot be edited', + 'Wallet record cannot be deleted' => 'Wallet record cannot be deleted', + + 'Admin wallet does not allow manual creation' => 'Admin wallet does not allow manual creation', + 'Admin wallet does not allow manual editing' => 'Admin wallet does not allow manual editing', + 'Admin wallet does not allow deletion' => 'Admin wallet does not allow deletion', + + 'Admin wallet records do not allow manual creation' => 'Admin wallet records do not allow manual creation', + 'Admin wallet records do not allow manual editing' => 'Admin wallet records do not allow manual editing', + 'Admin wallet records do not allow deletion' => 'Admin wallet records do not allow deletion', + + 'Invalid parameters' => 'Invalid parameters', + 'This config is locked by another operation, please try again later' => 'This config is locked by another operation, please try again later', + 'Saved successfully' => 'Saved successfully', + + 'Please use approve/reject buttons to review' => 'Please use approve/reject buttons to review', + 'This withdraw order has already been reviewed' => 'This withdraw order has already been reviewed', + 'Approved' => 'Approved', + 'Please provide reject reason' => 'Please provide reject reason', + 'Rejected' => 'Rejected', + + 'Deposit orders are auto-settled; direct modification is not allowed. Use the dedicated tool for manual adjustment.' => 'Deposit orders are auto-settled; direct modification is not allowed. Use the dedicated tool for manual adjustment.', + + 'Missing required parameters' => 'Missing required parameters', + 'Idempotency key is too long' => 'Idempotency key is too long', + 'Withdraw amount must be greater than 0' => 'Withdraw amount must be greater than 0', + 'Invalid receive type; only bank/ewallet/crypto are supported' => 'Invalid receive type; only bank/ewallet/crypto are supported', + 'Withdraw request submitted; pending channel super admin review' => 'Withdraw request submitted; pending channel super admin review', + + 'Tier ID already exists' => 'Tier ID already exists', + 'Items must be an array' => 'Items must be an array', + 'Please save all registered channel rows (no missing rows)' => 'Please save all registered channel rows (no missing rows)', + + 'Please use approve/reject buttons to complete the review' => 'Please use approve/reject buttons to complete the review', + 'Apply amount must be greater than 0' => 'Apply amount must be greater than 0', + 'Fee cannot be negative' => 'Fee cannot be negative', + 'Fee cannot be greater than apply amount' => 'Fee cannot be greater than apply amount', + 'This order has already been reviewed' => 'This order has already been reviewed', + 'Order is missing user info' => 'Order is missing user info', + 'Related user does not exist' => 'Related user does not exist', + 'User balance is insufficient to cover the adjustment difference' => 'User balance is insufficient to cover the adjustment difference', + + 'Please select exactly one role group' => 'Please select exactly one role group', + 'Selected role group is not bound to a channel' => 'Selected role group is not bound to a channel', + 'Selected role group channel does not match current account' => 'Selected role group channel does not match current account', + + 'Invalid operation type' => 'Invalid operation type', + 'Invalid amount format' => 'Invalid amount format', + 'Amount must be greater than 0' => 'Amount must be greater than 0', + 'This user is being operated by another admin (wallet/concurrent save); please try again later' => 'This user is being operated by another admin (wallet/concurrent save); please try again later', + 'Insufficient balance; deduction failed' => 'Insufficient balance; deduction failed', + 'Save failed: user balance changed by another request; please refresh and retry' => 'Save failed: user balance changed by another request; please refresh and retry', + 'Wallet adjusted successfully' => 'Wallet adjusted successfully', + + 'Please configure at least one share record' => 'Please configure at least one share record', + 'There are no admins under this channel; cannot configure share ratios' => 'There are no admins under this channel; cannot configure share ratios', + 'Share ratio must be between 0 and 100' => 'Share ratio must be between 0 and 100', + 'Please configure at least one valid share record' => 'Please configure at least one valid share record', + 'Sum of enabled share ratios must equal 100' => 'Sum of enabled share ratios must equal 100', + 'Share ratios saved successfully' => 'Share ratios saved successfully', + 'Only super admin can settle; after settlement, commissions will be automatically paid to admin wallets' => 'Only super admin can settle; after settlement, commissions will be automatically paid to admin wallets', + 'Settlement failed' => 'Settlement failed', + 'Super admin settlement completed; paid automatically by share ratios' => 'Super admin settlement completed; paid automatically by share ratios', + 'Batch settlement completed' => 'Batch settlement completed', + + 'Invalid settlement cycle' => 'Invalid settlement cycle', + 'Invalid settlement time format (HH:mm:ss)' => 'Invalid settlement time format (HH:mm:ss)', + 'Weekly settlement must select Monday to Sunday' => 'Weekly settlement must select Monday to Sunday', + 'Monthly settlement day must be between 1 and 31' => 'Monthly settlement day must be between 1 and 31', + 'Turnover commission rate must be between 0 and 100' => 'Turnover commission rate must be between 0 and 100', + 'Affiliate share/fee rates are required' => 'Affiliate share/fee rates are required', + 'Affiliate share/fee rates must be between 0 and 1' => 'Affiliate share/fee rates must be between 0 and 1', + 'Affiliate ladder rules are required' => 'Affiliate ladder rules are required', + 'Affiliate ladder rules must be a valid JSON array' => 'Affiliate ladder rules must be a valid JSON array', + 'Affiliate ladder rules must contain at least one row' => 'Affiliate ladder rules must contain at least one row', + 'Affiliate ladder rules row format error' => 'Affiliate ladder rules row format error', + 'Affiliate ladder rules minLoss format error' => 'Affiliate ladder rules minLoss format error', + 'Affiliate ladder rules shareRate format error' => 'Affiliate ladder rules shareRate format error', + 'Affiliate ladder rules minLoss cannot be negative' => 'Affiliate ladder rules minLoss cannot be negative', + 'Affiliate ladder rules shareRate must be between 0 and 1' => 'Affiliate ladder rules shareRate must be between 0 and 1', + 'Affiliate ladder rules must be strictly increasing by minLoss' => 'Affiliate ladder rules must be strictly increasing by minLoss', + + 'Withdraw apply failed' => 'Withdraw apply failed', + + 'Debit failed: user balance changed by another request; please refresh and retry' => 'Debit failed: user balance changed by another request; please refresh and retry', + + 'Deposit' => 'Deposit', + 'Mock payment' => 'Mock payment', + 'Mock third-party cashier' => 'Mock third-party cashier', + 'Order No' => 'Order No', + 'Pay channel' => 'Pay channel', + 'Amount (fiat/pricing)' => 'Amount (fiat/pricing)', + 'Bonus' => 'Bonus', + 'coin' => 'coin', + 'Click the button below to simulate successful third-party payment; the server will callback and settle the deposit.' => 'Click the button below to simulate successful third-party payment; the server will callback and settle the deposit.', + 'Confirm payment (simulate success)' => 'Confirm payment (simulate success)', + + 'Order id is invalid' => 'Order id is invalid', + 'Order does not exist' => 'Order does not exist', + 'Order number is empty' => 'Order number is empty', + 'Order status does not allow settlement' => 'Order status does not allow settlement', + 'Order amount is invalid' => 'Order amount is invalid', + 'Order user is invalid' => 'Order user is invalid', + 'User does not exist' => 'User does not exist', + 'Order state changed, please refresh and retry' => 'Order state changed, please refresh and retry', + + 'Row format error' => 'Row format error', + 'Channel code is not registered' => 'Channel code is not registered', + 'Duplicate channel code' => 'Duplicate channel code', + 'Invalid channel row data' => 'Invalid channel row data', + 'JSON encode failed' => 'JSON encode failed', + + 'Tier id is invalid' => 'Tier id is invalid', + 'Duplicate tier id' => 'Duplicate tier id', + 'Tier title (zh) is required' => 'Tier title (zh) is required', + 'Tier title (zh) is too long' => 'Tier title (zh) is too long', + 'Tier title (en) is too long' => 'Tier title (en) is too long', + 'Currency is required' => 'Currency is required', + 'Pay amount must be greater than 0' => 'Pay amount must be greater than 0', + 'Base credit amount must be greater than 0' => 'Base credit amount must be greater than 0', + 'Bonus amount cannot be negative' => 'Bonus amount cannot be negative', + 'Description (zh) is too long' => 'Description (zh) is too long', + 'Description (en) is too long' => 'Description (en) is too long', + + 'platform_coin format error' => 'platform_coin format error', + 'Platform coin labels (zh/en) are required' => 'Platform coin labels (zh/en) are required', + 'At least one currency is required' => 'At least one currency is required', + 'Currency row format error' => 'Currency row format error', + 'Currency code is invalid' => 'Currency code is invalid', + 'Duplicate currency code' => 'Duplicate currency code', + 'Deposit rate must be a number greater than 0' => 'Deposit rate must be a number greater than 0', + 'Withdraw rate must be a number greater than 0' => 'Withdraw rate must be a number greater than 0', + 'Bank row format error' => 'Bank row format error', + 'Bank code is invalid' => 'Bank code is invalid', + 'Duplicate bank code' => 'Duplicate bank code', + 'Withdraw min limit must be a number not less than 0' => 'Withdraw min limit must be a number not less than 0', + 'Please configure deposit channels' => 'Please configure deposit channels', + + 'Must be exactly 36 items' => 'Must be exactly 36 items', + 'No must be numeric' => 'No must be numeric', + 'No must be between 1 and 36' => 'No must be between 1 and 36', + 'Duplicate no' => 'Duplicate no', + 'Name is required' => 'Name is required', + 'Category is invalid' => 'Category is invalid', + 'Missing no' => 'Missing no', + + 'Failed to generate commission rows' => 'Failed to generate commission rows', +]; + diff --git a/app/common/lang/zh-cn/service.php b/app/common/lang/zh-cn/service.php new file mode 100644 index 0000000..393c605 --- /dev/null +++ b/app/common/lang/zh-cn/service.php @@ -0,0 +1,186 @@ + '渠道不存在', + 'Settlement number conflict, please retry' => '结算单号冲突,请重试', + 'No available admin share ratios under this channel; cannot settle' => '渠道下无可用管理员分配比例,无法结算', + 'This flow pays commissions automatically after super admin settlement; channel admin does not need to settle again' => '当前流程为超管结算后自动发放,渠道管理员无需二次结算', + 'Invalid channel data' => '渠道数据异常', + 'Invalid settlement period (start time is not earlier than now)' => '结算区间无效(开始时间不早于当前)', + 'Turnover agent commission rate is not configured' => '普通返水代理未配置返水分红比例', + 'Affiliate agent fee rate is not configured' => '联营代理未配置成本扣除比例', + 'Affiliate ladder rules are empty or invalid' => '联营阶梯规则无效或为空', + 'Unknown agent mode' => '未知的代理模式', + + 'Manual create next round is disabled' => '未开启「手动创建下一局」开关', + 'There is an unfinished round; cannot create a new one' => '存在未结束对局,无法新建', + 'New round created' => '已创建新对局', + + 'Idempotency key conflict' => '幂等键冲突', + 'Insufficient wallet balance' => '钱包余额不足', + + 'Game record is generated by system; manual creation is not allowed' => '游戏对局记录由系统自动生成,禁止后台手工新增', + 'Game record cannot be edited' => '游戏对局记录不可编辑', + 'Game record cannot be deleted' => '游戏对局记录不可删除', + + 'Bet order is generated by game API; manual creation is not allowed' => '注单由游戏接口生成,禁止后台手工新增', + 'Bet order cannot be edited' => '注单不可编辑', + 'Bet order cannot be deleted' => '注单不可删除', + 'Sorting is not supported' => '不支持排序', + + 'Play record is generated by game API; manual creation is not allowed' => '游玩记录由游戏接口生成,禁止后台手工新增', + 'Play record cannot be edited' => '游玩记录不可编辑', + 'Play record cannot be deleted' => '游玩记录不可删除', + + 'Wallet records are business-generated; manual creation is not allowed' => '钱包流水仅允许业务入账,禁止后台手工新增', + 'Wallet record cannot be edited' => '钱包流水不可编辑', + 'Wallet record cannot be deleted' => '钱包流水不可删除', + + 'Admin wallet does not allow manual creation' => '管理员钱包不允许手动新增', + 'Admin wallet does not allow manual editing' => '管理员钱包不允许手动编辑', + 'Admin wallet does not allow deletion' => '管理员钱包不允许删除', + + 'Admin wallet records do not allow manual creation' => '管理员钱包流水不允许手动新增', + 'Admin wallet records do not allow manual editing' => '管理员钱包流水不允许手动编辑', + 'Admin wallet records do not allow deletion' => '管理员钱包流水不允许删除', + + 'Invalid parameters' => '参数错误', + 'This config is locked by another operation, please try again later' => '该配置正在被其他操作占用,请稍后再试', + 'Saved successfully' => '保存成功', + + 'Please use approve/reject buttons to review' => '请使用通过/拒绝按钮审核', + 'This withdraw order has already been reviewed' => '该提现订单已审核', + 'Approved' => '审核通过', + 'Please provide reject reason' => '请填写拒绝原因', + 'Rejected' => '审核拒绝完成', + + 'Deposit orders are auto-settled; direct modification is not allowed. Use the dedicated tool for manual adjustment.' => '充值订单为自动入账,禁止直接修改,如需补单请走专用工具', + + 'Missing required parameters' => '参数缺失', + 'Idempotency key is too long' => '幂等键过长', + 'Withdraw amount must be greater than 0' => '提现金额必须大于0', + 'Invalid receive type; only bank/ewallet/crypto are supported' => '收款类型不合法,仅支持 bank/ewallet/crypto', + 'Withdraw request submitted; pending channel super admin review' => '提现申请已提交,待渠道超管审核', + + 'Tier ID already exists' => '档位 ID 已存在', + 'Items must be an array' => 'items 必须为数组', + 'Please save all registered channel rows (no missing rows)' => '请保存全部已注册渠道行(不可缺行)', + + 'Please use approve/reject buttons to complete the review' => '请使用通过/拒绝按钮完成审核', + 'Apply amount must be greater than 0' => '申请金额必须大于 0', + 'Fee cannot be negative' => '手续费不能为负', + 'Fee cannot be greater than apply amount' => '手续费不能大于申请金额', + 'This order has already been reviewed' => '该订单已审核,无需重复操作', + 'Order is missing user info' => '订单缺少用户信息', + 'Related user does not exist' => '关联用户不存在', + 'User balance is insufficient to cover the adjustment difference' => '用户余额不足以补扣调整差额', + + 'Please select exactly one role group' => '请选择且仅选择一个角色组', + 'Selected role group is not bound to a channel' => '所选角色组未绑定渠道', + 'Selected role group channel does not match current account' => '所选角色组渠道与当前账号不一致', + + 'Invalid operation type' => '操作类型不正确', + 'Invalid amount format' => '金额格式不正确', + 'Amount must be greater than 0' => '金额必须大于0', + 'This user is being operated by another admin (wallet/concurrent save); please try again later' => '该用户正在被其他管理员操作(钱包/并发保存),请稍后再试', + 'Insufficient balance; deduction failed' => '余额不足,扣点失败', + 'Save failed: user balance changed by another request; please refresh and retry' => '保存失败:该用户余额已被其他请求修改(如下注、派彩或其他管理员已保存),请刷新后重试', + 'Wallet adjusted successfully' => '钱包调整成功', + + 'Please configure at least one share record' => '请至少配置一条分配记录', + 'There are no admins under this channel; cannot configure share ratios' => '该渠道下暂无管理员,无法配置分配比例', + 'Share ratio must be between 0 and 100' => '分配比例必须在0到100之间', + 'Please configure at least one valid share record' => '请至少配置一条有效分配记录', + 'Sum of enabled share ratios must equal 100' => '启用的分配比例总和必须等于100', + 'Share ratios saved successfully' => '分配比例保存成功', + 'Only super admin can settle; after settlement, commissions will be automatically paid to admin wallets' => '仅超管可执行结算,结算后系统会自动发放至管理员钱包', + 'Settlement failed' => '结算失败', + 'Super admin settlement completed; paid automatically by share ratios' => '超管结算完成,已按分配比例自动发放给管理员', + 'Batch settlement completed' => '批量结算完成', + + 'Invalid settlement cycle' => '结算周期不合法', + 'Invalid settlement time format (HH:mm:ss)' => '结算时间格式不正确(HH:mm:ss)', + 'Weekly settlement must select Monday to Sunday' => '周结必须选择周一到周日', + 'Monthly settlement day must be between 1 and 31' => '月结日期必须在1到31之间', + 'Turnover commission rate must be between 0 and 100' => '返水分红比例必须在0到100之间', + 'Affiliate share/fee rates are required' => '联营占成比例不能为空', + 'Affiliate share/fee rates must be between 0 and 1' => '联营占成比例必须在0到1之间', + 'Affiliate ladder rules are required' => '联营阶梯规则不能为空', + 'Affiliate ladder rules must be a valid JSON array' => '联营阶梯规则必须是有效JSON数组', + 'Affiliate ladder rules must contain at least one row' => '联营阶梯规则至少需要一条', + 'Affiliate ladder rules row format error' => '联营阶梯规则行格式错误', + 'Affiliate ladder rules minLoss format error' => '联营阶梯规则起始客损格式错误', + 'Affiliate ladder rules shareRate format error' => '联营阶梯规则占成比例格式错误', + 'Affiliate ladder rules minLoss cannot be negative' => '联营阶梯规则起始客损不能为负', + 'Affiliate ladder rules shareRate must be between 0 and 1' => '联营阶梯规则占成比例必须在0到1之间', + 'Affiliate ladder rules must be strictly increasing by minLoss' => '联营阶梯规则需按起始客损递增', + + 'Withdraw apply failed' => '提现申请失败', + + 'Debit failed: user balance changed by another request; please refresh and retry' => '扣款失败:该用户余额已被其他请求修改(如下注、派彩或其他管理员已保存),请刷新后重试', + + 'Deposit' => '充值', + 'Mock payment' => '模拟支付', + 'Mock third-party cashier' => '模拟第三方收银台', + 'Order No' => '订单号', + 'Pay channel' => '支付渠道', + 'Amount (fiat/pricing)' => '金额(法币/标价)', + 'Bonus' => '赠送', + 'coin' => '币', + 'Click the button below to simulate successful third-party payment; the server will callback and settle the deposit.' => '点击下方按钮即视为第三方支付成功,服务端会回调并到账。', + 'Confirm payment (simulate success)' => '确认支付(模拟成功)', + + 'Order id is invalid' => '订单 ID 非法', + 'Order does not exist' => '订单不存在', + 'Order number is empty' => '订单号为空', + 'Order status does not allow settlement' => '订单状态不允许结算', + 'Order amount is invalid' => '订单金额异常', + 'Order user is invalid' => '订单所属玩家无效', + 'User does not exist' => '玩家不存在', + 'Order state changed, please refresh and retry' => '订单状态已变更,请刷新后重试', + + 'Row format error' => '行格式错误', + 'Channel code is not registered' => '渠道 code 未注册', + 'Duplicate channel code' => '渠道 code 重复', + 'Invalid channel row data' => '渠道数据无效', + 'JSON encode failed' => 'JSON 编码失败', + + 'Tier id is invalid' => '档位 ID 非法', + 'Duplicate tier id' => '档位 ID 重复', + 'Tier title (zh) is required' => '中文充值名称不能为空', + 'Tier title (zh) is too long' => '中文充值名称过长', + 'Tier title (en) is too long' => '英文充值名称过长', + 'Currency is required' => '支付货币不能为空', + 'Pay amount must be greater than 0' => '支付货币额度必须大于 0', + 'Base credit amount must be greater than 0' => '基础平台币到账必须大于 0', + 'Bonus amount cannot be negative' => '赠送金额不能为负数', + 'Description (zh) is too long' => '中文描述过长', + 'Description (en) is too long' => '英文描述过长', + + 'platform_coin format error' => 'platform_coin 格式错误', + 'Platform coin labels (zh/en) are required' => '请填写平台币中英文名称', + 'At least one currency is required' => '至少保留一条货币', + 'Currency row format error' => '货币列表行格式错误', + 'Currency code is invalid' => '货币代码非法', + 'Duplicate currency code' => '货币代码不能重复', + 'Deposit rate must be a number greater than 0' => '充值汇率须为大于 0 的数字', + 'Withdraw rate must be a number greater than 0' => '提现汇率须为大于 0 的数字', + 'Bank row format error' => '银行行格式错误', + 'Bank code is invalid' => '银行代码非法', + 'Duplicate bank code' => '银行代码重复', + 'Withdraw min limit must be a number not less than 0' => '提现最低限额须为不小于 0 的数字', + 'Please configure deposit channels' => '请配置充值渠道', + + 'Must be exactly 36 items' => '必须恰好 36 条', + 'No must be numeric' => '编号必须为数字', + 'No must be between 1 and 36' => '编号必须在 1–36', + 'Duplicate no' => '编号重复', + 'Name is required' => '名称不能为空', + 'Category is invalid' => '类型无效', + 'Missing no' => '缺少编号', + + 'Failed to generate commission rows' => '生成待分红记录失败', +]; + diff --git a/app/common/library/finance/DepositSettlement.php b/app/common/library/finance/DepositSettlement.php index 15df6d3..707ab62 100644 --- a/app/common/library/finance/DepositSettlement.php +++ b/app/common/library/finance/DepositSettlement.php @@ -57,17 +57,17 @@ final class DepositSettlement ?string $extraRemark = null ): array { if ($orderId <= 0) { - throw new RuntimeException('订单 ID 非法'); + throw new RuntimeException('Order id is invalid'); } $order = Db::name('deposit_order')->where('id', $orderId)->find(); if (!$order) { - throw new RuntimeException('订单不存在'); + throw new RuntimeException('Order does not exist'); } $orderNo = is_string($order['order_no']) ? $order['order_no'] : strval($order['order_no']); if ($orderNo === '') { - throw new RuntimeException('订单号为空'); + throw new RuntimeException('Order number is empty'); } $statusRaw = $order['status'] ?? 0; @@ -97,12 +97,12 @@ final class DepositSettlement } if ($status !== 0) { - throw new RuntimeException('订单状态不允许结算'); + throw new RuntimeException('Order status does not allow settlement'); } $amount = self::amountString($order['amount'] ?? '0'); if (bccomp($amount, '0', 2) <= 0) { - throw new RuntimeException('订单金额异常'); + throw new RuntimeException('Order amount is invalid'); } $bonus = self::amountString($order['bonus_amount'] ?? '0'); if (bccomp($bonus, '0', 2) < 0) { @@ -112,12 +112,12 @@ final class DepositSettlement $userId = is_numeric($order['user_id'] ?? null) ? intval($order['user_id']) : 0; if ($userId <= 0) { - throw new RuntimeException('订单所属玩家无效'); + throw new RuntimeException('Order user is invalid'); } $user = Db::name('user')->where('id', $userId)->find(); if (!$user) { - throw new RuntimeException('玩家不存在'); + throw new RuntimeException('User does not exist'); } $channelId = is_numeric($order['channel_id'] ?? null) ? intval($order['channel_id']) : null; @@ -149,7 +149,7 @@ final class DepositSettlement 'update_time' => $now, ]); if ($affected <= 0) { - throw new RuntimeException('订单状态已变更,请刷新后重试'); + throw new RuntimeException('Order state changed, please refresh and retry'); } Db::name('user')->where('id', $userId)->update([ diff --git a/app/common/library/game/DepositChannel.php b/app/common/library/game/DepositChannel.php index cd0c39e..07fd92a 100644 --- a/app/common/library/game/DepositChannel.php +++ b/app/common/library/game/DepositChannel.php @@ -334,19 +334,19 @@ final class DepositChannel $out = []; foreach ($items as $idx => $row) { if (!is_array($row)) { - throw new InvalidArgumentException('第 ' . ($idx + 1) . ' 行格式错误'); + throw new InvalidArgumentException('Row format error'); } $code = isset($row['code']) && is_string($row['code']) ? strtolower(trim($row['code'])) : ''; if ($code === '' || !isset($registry[$code])) { - throw new InvalidArgumentException('第 ' . ($idx + 1) . ' 行渠道 code 未注册'); + throw new InvalidArgumentException('Channel code is not registered'); } if (isset($seen[$code])) { - throw new InvalidArgumentException('渠道 code 重复:' . $code); + throw new InvalidArgumentException('Duplicate channel code'); } $seen[$code] = true; $norm = self::normalizeOverrides([array_merge($row, ['code' => $code])]); if ($norm === []) { - throw new InvalidArgumentException('第 ' . ($idx + 1) . ' 行渠道数据无效'); + throw new InvalidArgumentException('Invalid channel row data'); } $out[] = $norm[0]; } @@ -369,7 +369,7 @@ final class DepositChannel $wrapped = ['channels' => $items]; $encoded = json_encode($wrapped, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); if ($encoded === false) { - throw new InvalidArgumentException('JSON 编码失败'); + throw new InvalidArgumentException('JSON encode failed'); } return $encoded; diff --git a/app/common/library/game/DepositTier.php b/app/common/library/game/DepositTier.php index 4adc881..f373740 100644 --- a/app/common/library/game/DepositTier.php +++ b/app/common/library/game/DepositTier.php @@ -149,7 +149,7 @@ final class DepositTier foreach ($items as $idx => $row) { $no = $idx + 1; if (!is_array($row)) { - throw new InvalidArgumentException('第 ' . $no . ' 行格式错误'); + throw new InvalidArgumentException('Row format error'); } $id = isset($row['id']) && is_string($row['id']) ? trim($row['id']) : ''; @@ -157,10 +157,10 @@ final class DepositTier $id = self::generateId(); } if (!preg_match('/^[a-zA-Z0-9_\-]{1,32}$/', $id)) { - throw new InvalidArgumentException('第 ' . $no . ' 行 ID 非法'); + throw new InvalidArgumentException('Tier id is invalid'); } if (isset($seenId[$id])) { - throw new InvalidArgumentException('档位 ID 重复:' . $id); + throw new InvalidArgumentException('Duplicate tier id'); } $seenId[$id] = true; @@ -170,45 +170,45 @@ final class DepositTier $title = self::stringField($row, 'name'); } if ($title === '') { - throw new InvalidArgumentException('第 ' . $no . ' 行中文充值名称不能为空'); + throw new InvalidArgumentException('Tier title (zh) is required'); } if (mb_strlen($title) > 64) { - throw new InvalidArgumentException('第 ' . $no . ' 行中文充值名称过长'); + throw new InvalidArgumentException('Tier title (zh) is too long'); } $titleEn = self::stringField($row, 'title_en'); if (mb_strlen($titleEn) > 64) { - throw new InvalidArgumentException('第 ' . $no . ' 行英文充值名称过长'); + throw new InvalidArgumentException('Tier title (en) is too long'); } $currency = self::normalizeCurrency($row['currency'] ?? ''); if ($currency === '') { - throw new InvalidArgumentException('第 ' . $no . ' 行支付货币不能为空'); + throw new InvalidArgumentException('Currency is required'); } $payAmount = self::normalizeAmount($row['pay_amount'] ?? ''); if (bccomp($payAmount, '0', 2) <= 0) { - throw new InvalidArgumentException('第 ' . $no . ' 行支付货币额度必须大于 0'); + throw new InvalidArgumentException('Pay amount must be greater than 0'); } $amount = self::normalizeAmount($row['amount'] ?? ''); if (bccomp($amount, '0', 2) <= 0) { - throw new InvalidArgumentException('第 ' . $no . ' 行基础平台币到账必须大于 0'); + throw new InvalidArgumentException('Base credit amount must be greater than 0'); } $bonus = self::normalizeAmount($row['bonus_amount'] ?? '0'); if (bccomp($bonus, '0', 2) < 0) { - throw new InvalidArgumentException('第 ' . $no . ' 行赠送金额不能为负数'); + throw new InvalidArgumentException('Bonus amount cannot be negative'); } $desc = self::stringField($row, 'desc'); if (mb_strlen($desc) > 255) { - throw new InvalidArgumentException('第 ' . $no . ' 行中文描述过长'); + throw new InvalidArgumentException('Description (zh) is too long'); } $descEn = self::stringField($row, 'desc_en'); if (mb_strlen($descEn) > 255) { - throw new InvalidArgumentException('第 ' . $no . ' 行英文描述过长'); + throw new InvalidArgumentException('Description (en) is too long'); } $sort = isset($row['sort']) && is_numeric($row['sort']) ? intval($row['sort']) : 0; @@ -248,7 +248,7 @@ final class DepositTier { $encoded = json_encode($items, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); if ($encoded === false) { - throw new InvalidArgumentException('JSON 编码失败'); + throw new InvalidArgumentException('JSON encode failed'); } return $encoded; } diff --git a/app/common/library/game/FinanceCashierConfig.php b/app/common/library/game/FinanceCashierConfig.php index a57c1ca..2da32ab 100644 --- a/app/common/library/game/FinanceCashierConfig.php +++ b/app/common/library/game/FinanceCashierConfig.php @@ -328,50 +328,50 @@ final class FinanceCashierConfig private static function validate(array $p): void { if (!isset($p['platform_coin']) || !is_array($p['platform_coin'])) { - throw new InvalidArgumentException('platform_coin 格式错误'); + throw new InvalidArgumentException('platform_coin format error'); } $lz = $p['platform_coin']['label_zh'] ?? ''; $le = $p['platform_coin']['label_en'] ?? ''; if (!is_string($lz) || trim($lz) === '' || !is_string($le) || trim($le) === '') { - throw new InvalidArgumentException('请填写平台币中英文名称'); + throw new InvalidArgumentException('Platform coin labels (zh/en) are required'); } if (!isset($p['currencies']) || !is_array($p['currencies']) || $p['currencies'] === []) { - throw new InvalidArgumentException('至少保留一条货币'); + throw new InvalidArgumentException('At least one currency is required'); } $seenCodes = []; foreach ($p['currencies'] as $idx => $row) { if (!is_array($row)) { - throw new InvalidArgumentException('货币列表第 ' . ($idx + 1) . ' 行格式错误'); + throw new InvalidArgumentException('Currency row format error'); } $code = $row['code'] ?? ''; if (!is_string($code) || !preg_match('/^[A-Z0-9]{2,12}$/', $code)) { - throw new InvalidArgumentException('货币代码非法:' . (is_string($code) ? $code : '')); + throw new InvalidArgumentException('Currency code is invalid'); } if (isset($seenCodes[$code])) { - throw new InvalidArgumentException('货币代码不能重复:' . $code); + throw new InvalidArgumentException('Duplicate currency code'); } $seenCodes[$code] = true; $dep = $row['deposit_coins_per_fiat'] ?? ''; $wdr = $row['withdraw_coins_per_fiat'] ?? ''; if (!is_string($dep) || $dep === '' || !is_numeric($dep) || bccomp($dep, '0', 2) <= 0) { - throw new InvalidArgumentException('第 ' . ($idx + 1) . ' 行:充值汇率须为大于 0 的数字'); + throw new InvalidArgumentException('Deposit rate must be a number greater than 0'); } if (!is_string($wdr) || $wdr === '' || !is_numeric($wdr) || bccomp($wdr, '0', 2) <= 0) { - throw new InvalidArgumentException('第 ' . ($idx + 1) . ' 行:提现汇率须为大于 0 的数字'); + throw new InvalidArgumentException('Withdraw rate must be a number greater than 0'); } } if (isset($p['withdraw_banks']) && is_array($p['withdraw_banks'])) { $seen = []; foreach ($p['withdraw_banks'] as $idx => $row) { if (!is_array($row)) { - throw new InvalidArgumentException('银行第 ' . ($idx + 1) . ' 行格式错误'); + throw new InvalidArgumentException('Bank row format error'); } $code = $row['code'] ?? ''; if (!is_string($code) || !preg_match('/^[a-z0-9][a-z0-9_\-]{0,31}$/', $code)) { - throw new InvalidArgumentException('银行代码非法'); + throw new InvalidArgumentException('Bank code is invalid'); } if (isset($seen[$code])) { - throw new InvalidArgumentException('银行代码重复:' . $code); + throw new InvalidArgumentException('Duplicate bank code'); } $seen[$code] = true; } @@ -380,13 +380,13 @@ final class FinanceCashierConfig foreach (['min_ewallet', 'min_bank'] as $k) { $v = $p['withdraw_limits'][$k] ?? '0'; if (!is_string($v) || !is_numeric($v) || bccomp($v, '0', 2) < 0) { - throw new InvalidArgumentException('提现最低限额须为不小于 0 的数字'); + throw new InvalidArgumentException('Withdraw min limit must be a number not less than 0'); } } } $reg = DepositChannel::codeRegistry(); if ($reg !== [] && (!isset($p['channels']) || !is_array($p['channels']) || $p['channels'] === [])) { - throw new InvalidArgumentException('请配置充值渠道'); + throw new InvalidArgumentException('Please configure deposit channels'); } } } diff --git a/app/common/library/game/ZiHuaDictionary.php b/app/common/library/game/ZiHuaDictionary.php index 5d9da1d..060a736 100644 --- a/app/common/library/game/ZiHuaDictionary.php +++ b/app/common/library/game/ZiHuaDictionary.php @@ -168,43 +168,43 @@ final class ZiHuaDictionary public static function prepareItemsForSave(array $items): array { if (count($items) !== 36) { - throw new InvalidArgumentException('必须恰好 36 条'); + throw new InvalidArgumentException('Must be exactly 36 items'); } $nos = []; $out = []; foreach ($items as $idx => $row) { if (!is_array($row)) { - throw new InvalidArgumentException('第 ' . ($idx + 1) . ' 行格式错误'); + throw new InvalidArgumentException('Row format error'); } $no = $row['no'] ?? null; if (!is_numeric($no)) { - throw new InvalidArgumentException('编号必须为数字'); + throw new InvalidArgumentException('No must be numeric'); } $n = intval($no, 10); if ($n < 1 || $n > 36) { - throw new InvalidArgumentException('编号必须在 1–36'); + throw new InvalidArgumentException('No must be between 1 and 36'); } if (isset($nos[$n])) { - throw new InvalidArgumentException('编号重复:' . $n); + throw new InvalidArgumentException('Duplicate no'); } $nos[$n] = true; $name = $row['name'] ?? ''; if (!is_string($name) || trim($name) === '') { - throw new InvalidArgumentException('编号 ' . $n . ' 名称不能为空'); + throw new InvalidArgumentException('Name is required'); } $cat = $row['category'] ?? ''; $catTrim = is_string($cat) ? trim($cat) : ''; if (!in_array($catTrim, self::CATEGORIES, true)) { - throw new InvalidArgumentException('编号 ' . $n . ' 类型无效'); + throw new InvalidArgumentException('Category is invalid'); } $out[] = ['no' => $n, 'name' => trim($name), 'category' => $catTrim]; } for ($i = 1; $i <= 36; $i++) { if (!isset($nos[$i])) { - throw new InvalidArgumentException('缺少编号:' . $i); + throw new InvalidArgumentException('Missing no'); } } usort($out, static fn (array $a, array $b): int => $a['no'] <=> $b['no']); @@ -219,7 +219,7 @@ final class ZiHuaDictionary usort($items, static fn (array $a, array $b): int => $a['no'] <=> $b['no']); $encoded = json_encode($items, JSON_UNESCAPED_UNICODE); if ($encoded === false) { - throw new InvalidArgumentException('JSON 编码失败'); + throw new InvalidArgumentException('JSON encode failed'); } return $encoded; } diff --git a/app/common/service/AdminWalletService.php b/app/common/service/AdminWalletService.php index 3376d43..d128d23 100644 --- a/app/common/service/AdminWalletService.php +++ b/app/common/service/AdminWalletService.php @@ -77,7 +77,7 @@ class AdminWalletService if (is_array($existing)) { $existAdminId = intval($existing['admin_id'] ?? 0); if ($existAdminId !== $adminId) { - return ['ok' => false, 'msg' => 'Idempotency key conflict']; + return ['ok' => false, 'msg' => __('Idempotency key conflict')]; } return [ 'ok' => true, @@ -90,7 +90,7 @@ class AdminWalletService $wallet = self::ensureWallet($adminId); $before = strval($wallet['balance'] ?? '0.00'); if (bccomp($before, $withdrawCoin, 2) < 0) { - return ['ok' => false, 'msg' => '钱包余额不足']; + return ['ok' => false, 'msg' => __('Insufficient wallet balance')]; } $after = bcsub($before, $withdrawCoin, 2); $beforeFrozen = strval($wallet['frozen_balance'] ?? '0.00'); diff --git a/app/common/service/ChannelSettlementService.php b/app/common/service/ChannelSettlementService.php index dae2b58..1449f63 100644 --- a/app/common/service/ChannelSettlementService.php +++ b/app/common/service/ChannelSettlementService.php @@ -13,7 +13,7 @@ class ChannelSettlementService { $channel = Db::name('channel')->where('id', $channelId)->find(); if (!is_array($channel)) { - return ['ok' => false, 'msg' => '渠道不存在']; + return ['ok' => false, 'msg' => __('Channel not found')]; } $payload = self::buildSettlePayload($channel); if (is_string($payload)) { @@ -21,11 +21,11 @@ class ChannelSettlementService } $settlementNo = self::generateAgentSettlementNo($auto ? 'A' : 'M', $channelId, intval($payload['period_end_ts'])); if (Db::name('agent_settlement_period')->where('settlement_no', $settlementNo)->value('id')) { - return ['ok' => false, 'msg' => '结算单号冲突,请重试']; + return ['ok' => false, 'msg' => __('Settlement number conflict, please retry')]; } $shareRows = self::resolveCommissionSharesForChannel($channelId); if ($shareRows === []) { - return ['ok' => false, 'msg' => '渠道下无可用管理员分配比例,无法结算']; + return ['ok' => false, 'msg' => __('No available admin share ratios under this channel; cannot settle')]; } $now = time(); Db::startTrans(); @@ -52,7 +52,7 @@ class ChannelSettlementService $now ); if ($rows === []) { - throw new \RuntimeException('生成待分红记录失败'); + throw new \RuntimeException('Failed to generate commission rows'); } foreach ($rows as $row) { $adminId = intval($row['admin_id'] ?? 0); @@ -92,7 +92,7 @@ class ChannelSettlementService public static function settleDividendByChannelAdmin(int $channelId, int $operatorAdminId, string $remark = ''): array { - return ['ok' => false, 'msg' => '当前流程为超管结算后自动发放,渠道管理员无需二次结算']; + return ['ok' => false, 'msg' => __('This flow pays commissions automatically after super admin settlement; channel admin does not need to settle again')]; } public static function settleAllDueChannels(int $operatorAdminId, bool $respectCycle = true): array @@ -159,14 +159,14 @@ class ChannelSettlementService { $channelId = intval($row['id'] ?? 0); if ($channelId <= 0) { - return '渠道数据异常'; + return (string) __('Invalid channel data'); } $endTs = time(); $lastEnd = self::getLastSettlementEndForChannel($channelId); $channelCreateTs = intval($row['create_time'] ?? 0); $periodStartTs = $lastEnd === null ? ($channelCreateTs > 0 ? $channelCreateTs : 0) : $lastEnd; if ($periodStartTs >= $endTs) { - return '结算区间无效(开始时间不早于当前)'; + return (string) __('Invalid settlement period (start time is not earlier than now)'); } $stats = self::aggregateBetOrderForChannel($channelId, $periodStartTs, $lastEnd !== null, $endTs); $totalBet = $stats['total_bet']; @@ -234,7 +234,7 @@ class ChannelSettlementService if ($mode === 'turnover') { $ratePercent = $row['turnover_share_rate'] ?? null; if ($ratePercent === null || $ratePercent === '') { - return '普通返水代理未配置返水分红比例'; + return (string) __('Turnover agent commission rate is not configured'); } $rateDec = bcdiv(strval($ratePercent), '100', 4); return [ @@ -247,11 +247,11 @@ class ChannelSettlementService $fee = $row['affiliate_fee_rate'] ?? null; $rulesRaw = $row['affiliate_ladder_rules'] ?? null; if ($fee === null || $fee === '') { - return '联营代理未配置成本扣除比例'; + return (string) __('Affiliate agent fee rate is not configured'); } $rules = self::normalizeLadderRulesForSettlement($rulesRaw); if ($rules === []) { - return '联营阶梯规则无效或为空'; + return (string) __('Affiliate ladder rules are empty or invalid'); } if (bccomp($platformProfit, '0', 2) <= 0) { return ['commission_rate' => '0.0000', 'calc_base_amount' => '0.00', 'commission_amount' => '0.00']; @@ -268,7 +268,7 @@ class ChannelSettlementService 'commission_amount' => bcmul($afterFee, $rateDec, 2), ]; } - return '未知的代理模式'; + return (string) __('Unknown agent mode'); } private static function normalizeLadderRulesForSettlement(mixed $rulesRaw): array diff --git a/app/common/service/GameRecordService.php b/app/common/service/GameRecordService.php index b7bce30..9d4845b 100644 --- a/app/common/service/GameRecordService.php +++ b/app/common/service/GameRecordService.php @@ -71,14 +71,14 @@ final class GameRecordService public static function createNextRecordForManual(): array { if (!self::getConfigBool(self::KEY_MANUAL_CREATE)) { - return ['ok' => false, 'msg' => '未开启「手动创建下一局」开关']; + return ['ok' => false, 'msg' => __('Manual create next round is disabled')]; } if (self::hasActiveRecord()) { - return ['ok' => false, 'msg' => '存在未结束对局,无法新建']; + return ['ok' => false, 'msg' => __('There is an unfinished round; cannot create a new one')]; } try { $periodNo = self::createNextRecordRow(); - return ['ok' => true, 'msg' => '已创建新对局', 'period_no' => $periodNo]; + return ['ok' => true, 'msg' => __('New round created'), 'period_no' => $periodNo]; } catch (Throwable $e) { return ['ok' => false, 'msg' => $e->getMessage()]; } diff --git a/app/support/BaseController.php b/app/support/BaseController.php index 3309bf4..eb83636 100644 --- a/app/support/BaseController.php +++ b/app/support/BaseController.php @@ -76,6 +76,14 @@ abstract class BaseController */ protected function result(string $msg, mixed $data = null, int $code = 0, array $header = []): Response { + // 统一对返回 msg 做多语言翻译:若 $msg 为语言 key(英文),则按请求语言输出; + // 若无对应翻译,则保持原样返回。 + if ($msg !== '' && function_exists('__')) { + $translated = __($msg); + if (is_string($translated) && $translated !== '') { + $msg = $translated; + } + } $body = [ 'code' => $code, 'msg' => $msg,