1020 lines
53 KiB
TypeScript
1020 lines
53 KiB
TypeScript
const adminPages: Record<string, string> = {
|
||
'common.detail': 'Details',
|
||
'common.create': 'Create',
|
||
'common.create_btn': '+ New',
|
||
'common.save': 'Save',
|
||
'common.close': 'Close',
|
||
'common.import': 'Import',
|
||
'common.publish': 'Publish',
|
||
'common.topup': 'Top up',
|
||
'common.adjust_credit': 'Adjust credit',
|
||
'common.freeze': 'Freeze',
|
||
'common.unfreeze': 'Unfreeze',
|
||
'common.settle': 'Settle',
|
||
'common.resettle': 'Resettle',
|
||
'common.close_betting': 'Close',
|
||
'common.reopen_betting': 'Reopen betting',
|
||
'common.never_login': 'Never signed in',
|
||
'common.optional': 'Optional',
|
||
'common.to': 'To',
|
||
'common.module': 'Module',
|
||
'common.col_id': 'ID',
|
||
'common.times': 'times',
|
||
'common.bets_count_unit': 'bets',
|
||
|
||
'user.create_btn': '+ New player',
|
||
'user.filter.username_ph': 'Username',
|
||
'user.filter.agent': 'Agent',
|
||
'user.filter.agent_ph': 'All',
|
||
'user.col.username': 'Username',
|
||
'user.col.agent': 'Agent',
|
||
'user.col.agent_cashback': 'Agent cashback',
|
||
'user.col.player_cashback': 'Player cashback',
|
||
'user.col.invite_code': 'Invite code',
|
||
'user.col.balance': 'Available / Frozen',
|
||
'user.col.bets': 'Bets',
|
||
'user.col.stake_payout': 'Stake / Payout',
|
||
'user.col.last_login': 'Last login',
|
||
'user.col.created': 'Registered',
|
||
'user.status.ACTIVE': 'Active',
|
||
'user.status.SUSPENDED': 'Suspended',
|
||
'user.dialog.create': 'New player',
|
||
'user.dialog.edit': 'Edit player',
|
||
'user.dialog.deposit': 'Top up player',
|
||
'user.dialog.detail': 'Player details',
|
||
'user.field.password': 'Password',
|
||
'user.field.confirm_password': 'Confirm password',
|
||
'user.field.initial_balance': 'Initial balance',
|
||
'user.field.deposit_remark': 'Top-up note',
|
||
'user.field.initial_deposit_kind': 'Ledger note',
|
||
'user.initial_deposit_kind.daily': 'Regular top-up',
|
||
'user.initial_deposit_kind.opening_bonus': 'Opening bonus',
|
||
'user.initial_deposit_kind.custom': 'Custom',
|
||
'user.ph.initial_deposit_custom': 'Enter ledger note (min. 2 characters)',
|
||
'user.field.amount': 'Amount',
|
||
'user.field.remark': 'Note',
|
||
'user.field.account_status': 'Account status',
|
||
'user.field.available': 'Available balance',
|
||
'user.field.frozen_balance': 'Frozen balance',
|
||
'user.field.bets_summary': 'Bets / stake',
|
||
'user.field.total_payout': 'Total payout',
|
||
'user.field.login_fail': 'Failed logins',
|
||
'user.field.phone': 'Phone',
|
||
'user.field.email': 'Email',
|
||
'user.field.allow_password_change': 'Allow player password change',
|
||
'user.field.allow_username_change': 'Allow player username change',
|
||
'user.field.view_password': 'Login password',
|
||
'user.field.reset_password': 'Reset password',
|
||
'user.password_not_stored': 'Not stored (player changed it or never saved)',
|
||
'user.btn.show_password': 'Show',
|
||
'user.btn.hide_password': 'Hide',
|
||
'user.ph.reset_password': 'Leave empty to keep; new value will be viewable',
|
||
'user.ph.reset_password_short': 'Leave empty to keep',
|
||
'user.page_settings': 'Global settings',
|
||
'user.global_settings': 'Password & account (global)',
|
||
'user.global_settings_hint': 'Controls whether all players can change password or username in the app',
|
||
'user.reset_database': 'Reset database',
|
||
'user.reset_database_hint': 'Wipes all business data and restores initial demo seed (users, matches, bets, ledger, etc.). This cannot be undone.',
|
||
'user.reset_database_confirm_label': 'Type RESET to confirm',
|
||
'user.reset_database_confirm_ph': 'RESET',
|
||
'user.reset_database_btn': 'Reset to initial data',
|
||
'user.reset_database_disabled_prod': 'Disabled in production unless ALLOW_DB_RESET=true is set on the server',
|
||
'user.reset_database_success': 'Database reset complete. Sign in again with demo accounts.',
|
||
'user.reset_database_accounts': 'Demo accounts',
|
||
'user.section.basic_info': 'Basic info',
|
||
'user.section.affiliation': 'Affiliation',
|
||
'user.section.contact': 'Contact',
|
||
'user.section.account_overview': 'Account overview',
|
||
'user.section.password_mgmt': 'Password management',
|
||
'user.field.current_password': 'Current password',
|
||
'user.msg.created_with_password': 'Player created. Login password: {password}',
|
||
'user.msg.password_saved': 'Password updated. Viewable password: {password}',
|
||
'user.hint.password_reset_to_view': 'No stored password. Set one below under Reset password and save to view it here.',
|
||
'user.ph.username_unique': 'Unique login username',
|
||
'user.ph.username_player': 'Letters and digits, 3–32 chars',
|
||
'user.hint.username_player': 'English letters and digits only; no Chinese or special characters',
|
||
'user.ph.no_agent': 'None (platform direct)',
|
||
'user.hint.no_agent': 'Leave empty for platform-managed player',
|
||
'user.hint.platform_direct_player': 'This player belongs to the platform (admin direct).',
|
||
'user.hint.initial_balance': 'Auto top-up on create; 0 = no initial top-up',
|
||
'user.hint.deposit_remark': 'Written to ledger when initial balance > 0',
|
||
'user.hint.freeze_in_list': 'Freeze/unfreeze from the list actions',
|
||
'user.hint.agent_change': 'Empty = platform direct; changes recalc agent credit',
|
||
'user.hint.agent_readonly': 'Agent assignment cannot be changed after creation',
|
||
'user.hint.allow_password_change': 'When off, no player can change password in the app',
|
||
'user.hint.allow_username_change': 'When on, all players can change login username in profile',
|
||
'user.hint.view_password': 'Only passwords set on create/reset; cleared after player self-change',
|
||
'user.hint.reset_password': 'Takes effect immediately and updates viewable password above',
|
||
'user.btn.create': 'Create',
|
||
'user.btn.save_profile': 'Save',
|
||
'user.btn.confirm_deposit': 'Confirm top-up',
|
||
'user.deposit_remark_default': 'Admin top-up',
|
||
'user.withdraw_remark_default': 'Admin withdraw',
|
||
'user.field.account_type': 'Account type',
|
||
'user.type.player': 'Player',
|
||
'user.type.tier1_agent': 'Tier-1 agent',
|
||
'user.type.sub_agent': 'Tier-2 agent',
|
||
'user.hint.account_type': 'Agents use credit limits; players can belong to an agent and receive top-ups',
|
||
|
||
'agent.create_btn': '+ New tier-1 agent',
|
||
'agent.create_sub_btn': '+ New tier-2 agent',
|
||
'agent.create_sub': 'Create tier-2 agent',
|
||
'agent.create_child_btn': '+ New sub-agent',
|
||
'agent.dialog.create_child_agent': 'New sub-agent',
|
||
'agent.create_level_agent': 'Create L{level} agent',
|
||
'agent.create_level_agent_btn': '+ New L{level} agent',
|
||
'agent.level_name': 'Tier-{level} agent',
|
||
'agent.level_tab': 'L{level} agents',
|
||
'agent.dialog.create_level_agent': 'New L{level} agent',
|
||
'agent.hint.select_parent_for_level': 'Select a level-{level} agent as parent',
|
||
'agent.err.parent_level_mismatch': 'Invalid parent level for creating a level-{level} agent',
|
||
'agent.hint.creating_under_agent': 'Create account under this agent',
|
||
'agent.filter.username_ph': 'Username',
|
||
'agent_mgr.tab.players': 'Players',
|
||
'agent_mgr.tab.agents': 'Agents',
|
||
'agent.col.level': 'Level',
|
||
'agent.col.credit': 'Limit / Used / Available',
|
||
'agent.col.direct_players': 'Direct players',
|
||
'agent.direct_players_title': 'Direct players · {name}',
|
||
'agent.platform_row_name': 'Platform',
|
||
'agent.col.sub_agents': 'Sub-agents',
|
||
'agent.col.cashback': 'Cashback rate',
|
||
'agent.col.phone': 'Phone',
|
||
'agent.col.created': 'Created',
|
||
'agent.dialog.create': 'New tier-1 agent',
|
||
'agent.dialog.edit': 'Edit agent',
|
||
'agent.dialog.credit': 'Adjust credit limit',
|
||
'agent.field.agent_id': 'Agent ID',
|
||
'agent.dialog.detail': 'Agent details',
|
||
'agent.field.credit_limit': 'Credit limit',
|
||
'agent.field.cashback_rate': 'Cashback rate',
|
||
'agent.field.adjust_amount': 'Adjustment',
|
||
'agent.field.used_credit': 'Used credit',
|
||
'agent.field.available_credit': 'Available credit',
|
||
'agent.field.player_liability': 'Player liability',
|
||
'agent.field.sub_agent_exposure': 'Sub-agent exposure',
|
||
'agent.hint.credit_limit': 'Max total top-up capacity for direct players',
|
||
'agent.hint.cashback_example': 'e.g. enter 1 for 1%',
|
||
'agent.field.max_single_deposit': 'Max single top-up',
|
||
'agent.field.max_daily_deposit': 'Max daily top-up',
|
||
'agent.hint.deposit_limit_empty': '0 = unlimited; sub-agents cannot exceed parent limits',
|
||
'agent.hint.credit_adjust': 'Positive increases, negative decreases',
|
||
'agent.hint.credit_remark': 'Optional, written to credit ledger',
|
||
'agent.section.credit_log': 'Recent credit changes',
|
||
'agent.credit.increase': 'Increase',
|
||
'agent.credit.decrease': 'Decrease',
|
||
'agent.col.credit_type': 'Type',
|
||
'agent.col.credit_change': 'Change',
|
||
'agent.col.credit_before': 'Before',
|
||
'agent.col.credit_after': 'After',
|
||
'agent.credit_tx.filter_agent_ph': 'Agent username',
|
||
'agent.credit_tx.filter_agent_id': 'Agent ID',
|
||
'agent.credit_tx.filter_agent_id_ph': 'User ID',
|
||
'agent.credit_tx.col.operator': 'Operator',
|
||
'agent.credit_tx.view_all': 'View all credit ledger',
|
||
'finance.tab.credit': 'Credit ledger',
|
||
'finance.tab.transfer': 'Transfer ledger',
|
||
'finance.tab.wallet': 'Wallet ledger',
|
||
'finance.filter.type_category': 'Transaction type',
|
||
'finance.filter.type_category_all': 'All',
|
||
'finance.filter.type_category_deposit': 'Transfers',
|
||
'finance.filter.type_category_bet': 'Bets',
|
||
'finance.filter.type_category_cashback': 'Cashback',
|
||
'finance.col.frozen_before': 'Frozen before',
|
||
'finance.col.frozen_after': 'Frozen after',
|
||
'finance.col.reference': 'Related bet',
|
||
'finance.tx.adjust': 'Balance adjustment',
|
||
'finance.tx.bet_freeze': 'Bet freeze',
|
||
'finance.tx.bet_deduct': 'Bet deduct',
|
||
'finance.tx.bet_win': 'Bet payout',
|
||
'finance.tx.bet_lose': 'Bet settlement',
|
||
'finance.tx.bet_push': 'Push refund',
|
||
'finance.tx.bet_refund': 'Bet refund',
|
||
'finance.tx.bet_void': 'Bet void',
|
||
'finance.tx.cashback': 'Cashback',
|
||
'finance.tx.resettle': 'Resettlement',
|
||
'user.action.view_wallet_ledger': 'View wallet ledger',
|
||
'user.action.ledger_short': 'Ledger',
|
||
'user.wallet_ledger_dialog_title': 'Wallet ledger — {name}',
|
||
'agent.hierarchy.settings_title': 'Agent hierarchy',
|
||
'agent.hierarchy.settings_hint': '0 means unlimited levels. Agents at the cap cannot create sub-agents.',
|
||
'agent.hierarchy.max_level': 'Max agent level',
|
||
'agent.hierarchy.default_sub_credit_ratio': 'Default sub-agent credit ratio',
|
||
'agent.hierarchy.default_sub_credit_ratio_hint': 'When creating a sub-agent, pre-fill credit as parent available × this ratio',
|
||
'agent.hierarchy.create_credit_default_hint': 'Default {ratio}% ({amount}), capped by parent available credit; adjustable',
|
||
'agent.hierarchy.create_credit_quick_hint': 'Parent available {amount} — click a ratio to fill',
|
||
'agent.hierarchy.create_level_hint': 'Will be created as level {n} agent',
|
||
'agent.field.parent_agent': 'Parent agent',
|
||
'agent.col.parent_chain': 'Parent chain',
|
||
'role.agent_level': 'Level {n} agent',
|
||
'finance.filter.date_range': 'Date range',
|
||
'finance.filter.player_ph': 'Player username',
|
||
'finance.filter.parent_agent_ph': 'Parent agent username or ID',
|
||
'finance.filter.operator_ph': 'Operator username',
|
||
'finance.col.player': 'Player',
|
||
'finance.col.parent_agent': 'Parent agent',
|
||
'finance.col.tx_id': 'Transaction ID',
|
||
'finance.col.balance_change': 'Balance change',
|
||
'finance.col.balance_before': 'Balance before',
|
||
'finance.col.balance_after': 'Balance after',
|
||
'finance.col.tx_type': 'Type',
|
||
'finance.col.deposit_method': 'Deposit method',
|
||
'finance.deposit_method.manual_admin': 'Admin manual deposit',
|
||
'finance.deposit_method.manual_agent': 'Agent manual deposit',
|
||
'finance.deposit_method.manual': 'Manual deposit',
|
||
'finance.tx.deposit': 'Deposit',
|
||
'finance.tx.admin_deposit': 'Admin top-up',
|
||
'finance.tx.agent_deposit': 'Agent top-up',
|
||
'finance.tx.player_deposit': 'Self deposit',
|
||
'finance.tx.withdraw': 'Withdraw',
|
||
'finance.tx.admin_withdraw': 'Admin withdraw',
|
||
'finance.tx.agent_withdraw': 'Agent withdraw',
|
||
'finance.tx.request_id': 'Request ID',
|
||
'finance.remark.agent_deposit': 'Agent deposit',
|
||
'finance.remark.agent_withdraw': 'Agent withdraw',
|
||
'finance.remark.admin_deposit': 'Admin deposit',
|
||
'finance.remark.admin_withdraw': 'Admin withdraw',
|
||
'finance.remark.initial_balance': 'Initial account balance',
|
||
'agent.col.no_records': 'No records',
|
||
'agent.btn.confirm_adjust': 'Confirm',
|
||
'agent.field.select_user': 'Select user',
|
||
'agent.ph.select_user': 'Search player username',
|
||
'agent.hint.select_user': 'Pick an existing player account to promote to tier-1 agent (no new login)',
|
||
'agent.freeze.confirm_freeze_title': 'Confirm suspend agent',
|
||
'agent.freeze.confirm_freeze_body': 'Suspend agent "{name}"? They will not be able to sign in to the agent portal.',
|
||
'agent.freeze.confirm_unfreeze_body': 'Restore agent "{name}" to active status?',
|
||
'agent.freeze.opt_freeze_direct_players': 'Also freeze direct players',
|
||
'agent.freeze.opt_block_player_login': 'Block direct player login',
|
||
'agent.unfreeze.confirm_title': 'Confirm restore agent',
|
||
'agent.unfreeze.opt_unfreeze_direct_players': 'Also unfreeze direct players',
|
||
'agent.msg.cascade_freeze_done': 'Agent suspended and direct players frozen',
|
||
'agent.msg.cascade_unfreeze_done': 'Agent restored and direct players unfrozen',
|
||
'agent.msg.freeze_done': '{action} completed',
|
||
|
||
'match.create_btn': '+ New league',
|
||
'match.create_fixture_btn': '+ Add match',
|
||
'match.btn.markets': 'Markets',
|
||
'match.filter.keyword_ph': 'Tournament / team code',
|
||
'match.filter.status_hint': 'Filters fixtures inside a league and the fixture count column; empty leagues stay visible',
|
||
'match.col.league': 'Tournament',
|
||
'match.col.league_en': 'League (EN)',
|
||
'match.col.fixture_count': 'Fixtures',
|
||
'match.col.bet_count': 'Bets',
|
||
'match.col.total_stake': 'Total stake',
|
||
'match.col.pending_bets': 'Pending',
|
||
'match.col.league_code': 'Code',
|
||
'match.col.matchup': 'Matchup',
|
||
'match.col.kickoff': 'Kickoff',
|
||
'match.dialog.create_league': 'New tournament',
|
||
'match.dialog.edit_league': 'Edit tournament',
|
||
'match.dialog.create_fixture': 'New fixture',
|
||
'match.dialog.create': 'New fixture',
|
||
'match.dialog.edit': 'Edit fixture',
|
||
'match.dialog.import': 'Import matches',
|
||
'match.field.league_en': 'League (EN)',
|
||
'match.field.league_zh': 'League (ZH)',
|
||
'match.field.league_ms': 'League (MS)',
|
||
'match.field.league_logo': 'Tournament logo',
|
||
'match.field.lang_zh': 'ZH',
|
||
'match.field.lang_en': 'EN',
|
||
'match.field.lang_ms': 'MS',
|
||
'match.field.kickoff': 'Kickoff time',
|
||
'match.timezone.platform_hint': 'Saved as Malaysia time (UTC+8)',
|
||
'match.field.home_team': 'Home team',
|
||
'match.field.away_team': 'Away team',
|
||
'match.field.home_en': 'Home (EN)',
|
||
'match.field.home_zh': 'Home (ZH)',
|
||
'match.field.home_ms': 'Home (MS)',
|
||
'match.field.away_en': 'Away (EN)',
|
||
'match.field.away_zh': 'Away (ZH)',
|
||
'match.field.away_ms': 'Away (MS)',
|
||
'match.field.featured': 'Featured',
|
||
'match.hint.create_draft': 'Saved as draft; expand the tournament and publish each fixture to open markets.',
|
||
'match.hint.create_league': 'New tournaments are unpublished by default; use Publish in the list for player visibility, then expand to add fixtures.',
|
||
'league.status.PUBLISHED': 'Published',
|
||
'league.status.UNPUBLISHED': 'Unpublished',
|
||
'league.btn.unpublish': 'Unpublish',
|
||
'league.confirm_unpublish': 'Players will no longer see this tournament; you can still edit and republish in admin. Continue?',
|
||
'msg.league_published': 'Tournament published',
|
||
'msg.league_unpublished': 'Tournament unpublished',
|
||
'match.btn.unpublish': 'Unpublish',
|
||
'match.confirm_unpublish': 'The fixture will return to draft: hidden from players and no new bets; existing unsettled bets remain. Continue?',
|
||
'msg.match_unpublished': 'Fixture unpublished',
|
||
'match.hint.edit_published': 'Published: edit kickoff, featured, display names; closed/settled are locked.',
|
||
'match.expand_league_hint': 'Expand a league to manage fixtures; use Outright odds for winner markets.',
|
||
'match.expand_outright_hint': 'Expand a league to edit winner odds; fixture teams sync automatically, and you can add teams not yet on the schedule.',
|
||
'outright.odds_only_hint': 'Teams from fixtures are added automatically; add extra teams manually and edit winner odds here. Outright follows league publish—no separate publish step.',
|
||
'outright.league_unpublished_hint': 'League is not published yet. Set the league to Published on this page to open outright betting automatically.',
|
||
'outright.unsettled_fixtures_hint': '{n} fixture(s) in this league are still unsettled. Settle them before settling the outright market.',
|
||
'outright.btn.reopen': 'Reopen betting',
|
||
'outright.confirm_reopen': 'Reopening will accept new outright bets again. Continue?',
|
||
'outright.fixture_sync_added': '{n} team(s) synced automatically from fixtures',
|
||
'outright.col.teams_from_fixtures': 'Teams (from fixtures)',
|
||
'outright.col.teams_total': 'Outright teams',
|
||
'outright.empty_no_teams': 'No teams yet — add fixtures under Fixtures or click Add team.',
|
||
'match.outright.setup': 'Set up',
|
||
'match.outright.section_hint': 'Winner market for this league; fixtures are listed below',
|
||
'match.expand_markets_hint': 'Click Markets on a fixture to open the dedicated markets page.',
|
||
'match.no_fixtures': 'No fixtures under this tournament yet.',
|
||
'match.ph.league_ms': 'World Cup 2027',
|
||
|
||
'bet.filter.keyword_ph': 'Bet no. / username',
|
||
'bet.filter.date_from': 'Placed from',
|
||
'bet.filter.date_start_ph': 'Start',
|
||
'bet.filter.date_end_ph': 'End',
|
||
'bet.col.serial': 'No.',
|
||
'bet.col.bet_no': 'Bet no.',
|
||
'bet.col.player': 'Player',
|
||
'bet.col.agent': 'Agent',
|
||
'bet.col.selection': 'Pick',
|
||
'bet.col.content': 'Selections',
|
||
'bet.content.bet_counts': '{singles} single · {parlays} parlay',
|
||
'bet.col.match': 'Match',
|
||
'bet.legs_more': '+{n} more…',
|
||
'bet.col.selection_count': 'Legs',
|
||
'bet.col.stake': 'Stake',
|
||
'bet.col.odds': 'Odds',
|
||
'bet.col.payout': 'Payout',
|
||
'bet.col.placed_at': 'Placed at',
|
||
'bet.col.cashbacked': 'Cashbacked',
|
||
'bet.dialog.detail': 'Bet details',
|
||
'bet.field.total_odds': 'Total odds',
|
||
'bet.field.currency': 'Currency',
|
||
'bet.field.potential_win': 'Potential win',
|
||
'bet.field.actual_payout': 'Actual payout',
|
||
'bet.field.bet_status': 'Bet status',
|
||
'bet.field.settlement_status': 'Settlement',
|
||
'bet.field.settled_at': 'Settled at',
|
||
'bet.field.request_id': 'Request ID',
|
||
'bet.selections_title': 'Selections ({n})',
|
||
'bet.col.market': 'Market',
|
||
'bet.col.period': 'Period',
|
||
'bet.col.line': 'Line',
|
||
'bet.col.result': 'Result',
|
||
|
||
'audit.module_ph': 'e.g. USERS, AGENTS',
|
||
'audit.col.action': 'Action',
|
||
'audit.col.module': 'Module',
|
||
'audit.col.target_id': 'Target ID',
|
||
'audit.col.time': 'Time',
|
||
'audit.action.CREATE_PLAYER': 'Create player',
|
||
'audit.action.UPDATE_PLAYER': 'Update player',
|
||
'audit.action.RESET_DATABASE': 'Reset database',
|
||
'audit.action.CREATE_AGENT': 'Create agent',
|
||
'audit.action.UPDATE_AGENT': 'Update agent',
|
||
'audit.action.UPDATE_PLAYER_ACCOUNT_SETTINGS': 'Update player account settings',
|
||
'audit.action.UPDATE_AGENT_SUSPEND_SETTINGS': 'Update agent suspend settings',
|
||
'audit.action.UPDATE_BETTING_LIMITS': 'Update betting limits',
|
||
'audit.action.CONFIRM_SETTLEMENT': 'Confirm settlement',
|
||
'audit.action.CONFIRM_RESETTLE': 'Confirm resettlement',
|
||
'audit.action.CONFIRM_CASHBACK': 'Confirm cashback payout',
|
||
'audit.action.CANCEL_CASHBACK': 'Cancel cashback batch',
|
||
'audit.module.USERS': 'Players',
|
||
'audit.module.AGENTS': 'Agents',
|
||
'audit.module.SYSTEM': 'System',
|
||
'audit.module.SETTINGS': 'Settings',
|
||
'audit.module.SETTLEMENT': 'Settlement',
|
||
'audit.module.CASHBACK': 'Cashback',
|
||
|
||
'cashback.start_date': 'Start date',
|
||
'cashback.end_date': 'End date',
|
||
'cashback.preview_btn': 'Preview',
|
||
'cashback.preview_title': 'Cashback preview',
|
||
'cashback.stat.players': 'Players',
|
||
'cashback.stat.total': 'Total cashback',
|
||
'cashback.stat.lines': 'Line items',
|
||
'cashback.stat.effective_stake': 'Total effective stake',
|
||
'cashback.stat.bet_count': 'Eligible bets',
|
||
'cashback.stat.avg_rate': 'Average rate',
|
||
'cashback.batch_no': 'Batch no.',
|
||
'cashback.history_title': 'Cashback history',
|
||
'cashback.history_empty': 'No cashback batches yet',
|
||
'cashback.filter_status': 'Status',
|
||
'cashback.status.PREVIEW': 'Pending',
|
||
'cashback.status.CONFIRMED': 'Paid out',
|
||
'cashback.col.period': 'Period',
|
||
'cashback.col.status': 'Status',
|
||
'cashback.col.bet_count': 'Bets',
|
||
'cashback.col.created_at': 'Created',
|
||
'cashback.col.confirmed_at': 'Paid at',
|
||
'cashback.col.operator': 'Operator',
|
||
'cashback.view_detail': 'Details',
|
||
'cashback.detail_title': 'Batch breakdown',
|
||
'cashback.detail_summary': 'Batch summary',
|
||
'cashback.table_title': 'Player cashback breakdown',
|
||
'cashback.table_total': 'Total',
|
||
'cashback.empty_items': 'No eligible cashback in this period',
|
||
'cashback.col.index': '#',
|
||
'cashback.col.player': 'Player',
|
||
'cashback.col.agent': 'Agent',
|
||
'cashback.col.balance': 'Balance',
|
||
'cashback.col.effective_stake': 'Effective stake',
|
||
'cashback.col.rate': 'Rate',
|
||
'cashback.col.amount': 'Cashback',
|
||
'cashback.confirm_issue': 'Confirm payout',
|
||
'cashback.cancel_issue': 'Void',
|
||
'cashback.confirm_prompt': 'Pay out this cashback batch to player wallets? Cashback is credited by the platform directly and is not deducted from agents. This cannot be undone.',
|
||
'cashback.cancel_prompt': 'Void this pending batch? No wallet credit will be made; you can preview again.',
|
||
'cashback.status.CANCELLED': 'Voided',
|
||
'cashback.rules_title': 'Cashback rules',
|
||
'cashback.rule_period': 'Pick a date range. Bets are included by settlement time within that period.',
|
||
'cashback.rule_eligible': 'Included: settled bets with result WON or LOST (singles by stake; parlays counted once by parlay stake). Excluded: pending, cancelled, void, push, zero-rate bets, and bets already paid cashback.',
|
||
'cashback.rule_formula': 'Per bet: stake × applicable cashback rate. Amounts are summed per player into one line item.',
|
||
'cashback.rule_rate': 'Rate priority: player rule > agent rule > global rule > default rate (agent-line players use their agent default; platform-direct players use the rate under Global settings; override per player in player management). Enter as percent, e.g. 1 = 1%.',
|
||
'cashback.rule_flow': 'Flow: preview (one pending batch per period) → review → confirm payout; void if not needed. Paid periods cannot be previewed again.',
|
||
'cashback.rule_platform': 'Payout: cashback is credited to player cash balance by the platform; it is not deducted from agent credit or balance.',
|
||
'cashback.rule_note_zero': 'If preview is 0, check for settled WON/LOST bets in the period and a cashback rate above 0 (including platform-direct default in Global settings and per-player/agent overrides).',
|
||
'cashback.use_custom_rate': 'Custom cashback rate',
|
||
'cashback.use_default_rate': 'Use default rate {rate}',
|
||
'cashback.settings_title': 'Cashback settings',
|
||
'cashback.platform_direct_default_rate': 'Platform-direct default cashback rate',
|
||
'cashback.admin_invite_default_rate': 'Admin invite cashback rate',
|
||
'cashback.admin_invite_default_hint': 'Used when players register with an admin invite code; defaults to platform-direct rate. Agent invites use the rate set for that agent under Agent management.',
|
||
'cashback.platform_direct_default_hint': 'Used for self-registration without an invite code unless overridden per player.',
|
||
|
||
'user.field.player_id': 'Player ID',
|
||
'user.field.bet_count': 'Bet count',
|
||
'user.field.total_stake': 'Total stake',
|
||
'user.field.registered_at': 'Registered',
|
||
'user.ph.remark_initial': 'Ledger note when initial balance > 0',
|
||
'user.bets_edit_value': '{n} bets / {stake}',
|
||
'user.login_fail_value': '{n} times',
|
||
|
||
'match.import_hint': 'Paste JSON with matches array. Imports as draft; publish from the list.',
|
||
'match.import_start': 'Import',
|
||
'match.import_json_ph': '{"matches":[...]}',
|
||
'match.delete_confirm_title': 'Delete match',
|
||
'match.delete_confirm_body': 'Delete "{title}"? Draft with no bets only.',
|
||
'archive.match_title': 'Delete match',
|
||
'archive.league_title': 'Delete league',
|
||
'archive.target': 'Match: {title}',
|
||
'archive.league_target': 'League: {name}',
|
||
'archive.soft_delete_hint': 'Soft delete: data remains, hidden from admin and player lists.',
|
||
'archive.pending_summary': '{count} pending bet(s), stake {stake}',
|
||
'archive.refund_pending': 'Refund pending bet stakes',
|
||
'archive.parlay_void_hint': 'Parlay slips touching this match are voided in full.',
|
||
'archive.force_delete': 'Force delete',
|
||
'archive.msg_done': 'Deleted',
|
||
'archive.msg_done_refund': 'Deleted; refunded {n} bet(s)',
|
||
'archive.league_hint': 'League can be deleted only when all fixtures and outrights are settled with no pending bets.',
|
||
'archive.league_blocked': 'Unsettled fixtures or pending bets remain under this league.',
|
||
'archive.league_ready': 'This league can be deleted; all child events will be hidden.',
|
||
'archive.league_confirm': 'Delete league',
|
||
'archive.league_done': 'League deleted',
|
||
'archive.warning.PENDING_BETS': 'Pending bets exist',
|
||
'archive.warning.UNSETTLED_MATCH': 'Match is not in a terminal state',
|
||
'archive.warning.PREVIEW_BATCH': 'A settlement preview batch is pending',
|
||
'match.ph.league_en': 'FIFA World Cup 2026',
|
||
'match.ph.league_zh': '2026 World Cup',
|
||
'match.ph.kickoff': '2026-06-11T19:00:00Z',
|
||
'match.ph.home_en': 'Mexico',
|
||
'match.ph.home_zh': 'Mexico',
|
||
'match.ph.home_ms': 'Mexico',
|
||
'match.ph.away_en': 'South Africa',
|
||
'match.ph.away_zh': 'South Africa',
|
||
'match.ph.away_ms': 'Afrika Selatan',
|
||
|
||
'matchEditor.manage_btn': 'Basic info',
|
||
'matchEditor.back': 'Back to list',
|
||
'matchEditor.title': 'Edit basic info',
|
||
'matchEditor.section_info': 'Basic info',
|
||
'matchEditor.section_markets': 'Markets & odds',
|
||
'matchEditor.field.league_logo': 'Logo',
|
||
'matchEditor.field.home_logo': 'Logo',
|
||
'matchEditor.field.away_logo': 'Logo',
|
||
'matchEditor.field.pick_flag': 'Pick flag',
|
||
'matchEditor.field.custom_logo_url': 'Custom image URL',
|
||
'matchEditor.ph.logo_url': 'https://...',
|
||
'matchEditor.field.match_name': 'Display name',
|
||
'matchEditor.field.stage': 'Stage',
|
||
'matchEditor.field.group': 'Group',
|
||
'matchEditor.field.display_order': 'Sort order',
|
||
'matchEditor.field.promo_label': 'Promo label',
|
||
'matchEditor.field.promo_label_optional': 'Promo label (optional)',
|
||
'matchEditor.field.line_value': 'Line',
|
||
'matchEditor.field.player_visible': 'Show on player',
|
||
'matchEditor.ph.kickoff': 'Select kickoff date & time (Malaysia time)',
|
||
'matchEditor.group.league': 'League',
|
||
'matchEditor.hint.league_readonly': 'Edit league name and logo from the tournament list; shown here read-only.',
|
||
'matchEditor.group.home': 'Home team',
|
||
'matchEditor.group.away': 'Away team',
|
||
'matchEditor.group.schedule': 'Schedule & display',
|
||
'matchEditor.save_info': 'Save info',
|
||
'matchEditor.save_market': 'Save market',
|
||
'matchEditor.save_odds': 'Save odds',
|
||
'matchEditor.generate_templates': 'Generate templates',
|
||
'matchEditor.templates_generated': 'Market templates created',
|
||
'matchEditor.no_markets': 'No markets yet — publish the match or generate templates.',
|
||
'matchEditor.market.FT_1X2': 'FT 1X2',
|
||
'matchEditor.market.FT_HANDICAP': 'FT handicap',
|
||
'matchEditor.market.FT_OVER_UNDER': 'FT O/U',
|
||
'matchEditor.market.FT_ODD_EVEN': 'FT odd/even',
|
||
'matchEditor.market.HT_1X2': 'HT 1X2',
|
||
'matchEditor.market.HT_HANDICAP': 'HT handicap',
|
||
'matchEditor.market.HT_OVER_UNDER': 'HT O/U',
|
||
'matchEditor.market.FT_CORRECT_SCORE': 'FT correct score',
|
||
'matchEditor.market.HT_CORRECT_SCORE': '1H correct score',
|
||
'matchEditor.market.SH_CORRECT_SCORE': '2H correct score',
|
||
'matchEditor.period.FT': 'Full time',
|
||
'matchEditor.period.HT': 'Half time',
|
||
'matchEditor.period.SH': 'Second half',
|
||
'matchEditor.period.OUTRIGHT': 'Outright',
|
||
'matchEditor.selection.HOME': 'Home',
|
||
'matchEditor.selection.DRAW': 'Draw',
|
||
'matchEditor.selection.AWAY': 'Away',
|
||
'matchEditor.selection.OVER': 'Over',
|
||
'matchEditor.selection.UNDER': 'Under',
|
||
'matchEditor.selection.ODD': 'Odd',
|
||
'matchEditor.selection.EVEN': 'Even',
|
||
'matchEditor.selection.OTHER_DRAW': 'Draw (other score)',
|
||
'matchEditor.selection.OTHER_HOME': 'Home win (other score)',
|
||
'matchEditor.selection.OTHER_AWAY': 'Away win (other score)',
|
||
'matchEditor.col.selection_code': 'Option',
|
||
'matchEditor.col.selection_name': 'Display name',
|
||
'matchEditor.col.odds': 'Odds',
|
||
'matchEditor.ph.selection_name': 'Name shown to players',
|
||
|
||
'err.username_required': 'Username is required',
|
||
'err.username_player_invalid': 'Player username must be 3–32 English letters or digits only',
|
||
'err.password_min': 'Password must be at least 8 characters',
|
||
'err.password_mismatch': 'Passwords do not match',
|
||
'err.credit_negative': 'Credit limit cannot be negative',
|
||
'err.insufficient_credit': 'Insufficient available credit. Reduce the amount or request a limit increase.',
|
||
'err.kickoff_required': 'Kickoff time is required',
|
||
'err.team_country_required': 'Select home and away teams',
|
||
'err.teams_required': 'Enter home and away team names (ZH or EN)',
|
||
'err.teams_same': 'Home and away teams must be different',
|
||
'err.league_required': 'League name is required',
|
||
'err.user_required': 'Please select a user',
|
||
'err.agent_no_parent': 'Tier-1 agents cannot have a parent player',
|
||
'err.agent_no_initial_deposit': 'Do not set initial player balance when creating an agent',
|
||
'err.initial_deposit_kind_required': 'Select a ledger note when initial balance > 0',
|
||
'err.initial_deposit_custom_required': 'Custom ledger note must be at least 2 characters',
|
||
|
||
'settlement.back': 'Back to matches',
|
||
'settlement.kickoff': 'Kick-off',
|
||
'settlement.stats_title': 'Betting statistics',
|
||
'settlement.stats_total_bets': 'Bets',
|
||
'settlement.stats_single': 'Singles',
|
||
'settlement.stats_parlay': 'Parlays',
|
||
'settlement.stats_total_stake': 'Total stake',
|
||
'settlement.stats_potential': 'Max potential win',
|
||
'settlement.chart.bet_type': 'Single vs parlay',
|
||
'settlement.chart.status': 'Bet status mix',
|
||
'settlement.chart.stake_by_selection': 'Top selections by single stake',
|
||
'settlement.stats_by_market': 'By market / selection',
|
||
'settlement.bet_list': 'Related bets',
|
||
'settlement.bet_list_hint': 'Grouped by bet; same-match parlays show ×legs',
|
||
'settlement.no_bets': 'No bets on this match',
|
||
'settlement.col.market': 'Market',
|
||
'settlement.col.selection': 'Selection',
|
||
'settlement.col.legs': 'Legs',
|
||
'settlement.col.single_stake': 'Single stake',
|
||
'settlement.col.parlay_legs': 'Parlay legs',
|
||
'settlement.ht_score': 'Half-time score',
|
||
'settlement.ft_score': 'Full-time score',
|
||
'settlement.stats_facts': 'Match facts',
|
||
'settlement.corners': 'Corners',
|
||
'settlement.cards': 'Cards',
|
||
'settlement.yellow_cards': 'Yellow cards',
|
||
'settlement.red_cards': 'Red cards',
|
||
'settlement.home_stat': 'Home',
|
||
'settlement.away_stat': 'Away',
|
||
'settlement.record_score': 'Save score',
|
||
'settlement.preview_hint': 'Preview moves the match to pending settlement and calculates payouts (scores are saved on confirm; you can reopen betting before confirming)',
|
||
'settlement.preview_btn': 'Preview settlement',
|
||
'settlement.preview_failed': 'Failed to generate settlement preview',
|
||
'settlement.err_score_not_recorded': 'Enter half-time and full-time scores before preview',
|
||
'settlement.must_close_first': 'Close betting before settlement',
|
||
'settlement.outright.page_title': 'Outright settlement',
|
||
'settlement.outright.title': 'Outright winner',
|
||
'settlement.outright.winner': 'Winning team',
|
||
'settlement.outright.winner_ph': 'Select champion',
|
||
'settlement.outright.preview_hint': 'Select the winner, preview payouts, then confirm settlement',
|
||
'settlement.outright.winner_required': 'Please select the winning team first',
|
||
'settlement.preview_title': 'Settlement preview',
|
||
'settlement.single_count': 'Single bets',
|
||
'settlement.preview_pending_bets': 'Pending bets',
|
||
'settlement.preview_bet_mix': 'Single / parlay',
|
||
'settlement.preview_items_title': 'Per-bet preview ({n})',
|
||
'settlement.preview_items_scroll_hint': 'Scroll when the list is long',
|
||
'settlement.preview_col.result': 'Match result',
|
||
'settlement.preview_zero_parlay_hint':
|
||
'Est. payout is 0: {pending} cross-match parlay bet(s) must wait for every fixture before final settlement.',
|
||
'settlement.preview_zero_lost_hint':
|
||
'Est. payout is 0: {count} parlay(s) are ready for final settlement and lost; other bets did not win here either.',
|
||
'settlement.preview_zero_default_hint':
|
||
'Est. payout is 0: no winning or refundable outcome on this match yet.',
|
||
'settlement.preview.result.WIN': 'Win',
|
||
'settlement.preview.result.LOSE': 'Lose',
|
||
'settlement.preview.result.LOST': 'Parlay lost',
|
||
'settlement.preview.result.WON': 'Parlay won',
|
||
'settlement.preview.result.PUSH': 'Push',
|
||
'settlement.preview.result.PENDING_OTHER_MATCHES': 'Awaiting other matches',
|
||
'settlement.est_payout': 'Est. payout',
|
||
'settlement.refund_amount': 'Refund amount',
|
||
'settlement.confirm_btn': 'Confirm settlement',
|
||
'settlement.resettle_reason': 'Resettle reason',
|
||
'settlement.resettle_preview': 'Resettle preview',
|
||
'settlement.resettle_preview_title': 'Resettle preview',
|
||
'settlement.resettle_affected': 'Affected bets',
|
||
'settlement.resettle_topup': 'Top-up required',
|
||
'settlement.resettle_clawback': 'Clawback required',
|
||
'settlement.resettle_confirm': 'Confirm resettle',
|
||
'user.betting_limits': 'Betting limits',
|
||
'user.betting_limits_hint': 'Global stake/payout/daily limits for player bets',
|
||
'user.limit.min_stake': 'Min stake',
|
||
'user.limit.max_stake_single': 'Max single stake',
|
||
'user.limit.max_stake_parlay': 'Max parlay stake',
|
||
'user.limit.max_payout_single': 'Max single payout',
|
||
'user.limit.max_payout_parlay': 'Max parlay payout',
|
||
'user.limit.daily_stake': 'Daily stake limit',
|
||
'settlement.smart.btn': 'Smart score',
|
||
'settlement.smart.title': 'Smart score suggestions',
|
||
'settlement.smart.hint': 'Enumerates valid scores from pending single bets and estimates payout. Parlays are excluded. Click a card to apply.',
|
||
'settlement.smart.target_hold': 'Target house hold',
|
||
'settlement.smart.recalc': 'Recalculate',
|
||
'settlement.smart.apply': 'Apply score',
|
||
'settlement.smart.applied': 'Score applied',
|
||
'settlement.smart.no_bets': 'No pending single bets',
|
||
'settlement.smart.empty': 'No suggestion found',
|
||
'settlement.smart.meta': 'Singles {singles}, parlays {parlays} skipped, {n} scores compared',
|
||
'settlement.smart.hold': 'Hold',
|
||
'settlement.smart.payout': 'Payout',
|
||
'settlement.smart.win_stake': 'Win stake %',
|
||
'settlement.smart.wl': 'W/L bets',
|
||
'settlement.smart.strategy.MIN_PAYOUT': 'Max house hold (min payout)',
|
||
'settlement.smart.strategy.MAX_PAYOUT': 'Max player payout',
|
||
'settlement.smart.strategy.BALANCED': 'Balanced (~50% win stake)',
|
||
'settlement.smart.strategy.TARGET_HOLD': 'Target hold rate',
|
||
'msg.score_recorded': 'Score saved',
|
||
'msg.settlement_confirmed': 'Settlement confirmed',
|
||
'msg.resettle_confirmed': 'Resettle confirmed',
|
||
|
||
'agent_portal.create_player_section': 'Create player',
|
||
'agent_portal.deposit_section': 'Top up',
|
||
'agent_portal.create_player_btn': '+ New player',
|
||
'agent_portal.create_tier2_btn': '+ New tier-2 agent',
|
||
'agent_portal.username_ph': 'Enter username',
|
||
'agent_portal.agent_username_ph': 'Agent username',
|
||
'agent_portal.player_id_ph': 'Player ID',
|
||
'agent_portal.withdraw_btn': 'Withdraw {amount}',
|
||
'agent_portal.withdraw_btn_label': 'Withdraw',
|
||
'agent_portal.transfer_title_deposit': 'Top up {name}',
|
||
'agent_portal.transfer_title_withdraw': 'Withdraw from {name}',
|
||
'transfer.context.player_section': 'Player balance',
|
||
'transfer.context.agent_section': 'Credit agent · {name} (L{level})',
|
||
'transfer.context.withdrawable': 'Withdrawable',
|
||
'transfer.context.deposit_cap': 'Max top-up this time',
|
||
'transfer.context.daily_used': 'Topped up today',
|
||
'transfer.context.unlimited': 'No limit',
|
||
'transfer.context.no_agent': 'Platform-direct player — not limited by agent credit',
|
||
'transfer.context.admin_credit_only': 'Admin top-up is capped by parent available credit only (not single/daily limits)',
|
||
'transfer.context.withdraw_exceed': 'Withdrawal cannot exceed player available balance',
|
||
'credit.context.target_section': 'Target agent credit',
|
||
'credit.context.parent_section': 'Parent agent · {name}',
|
||
'credit.context.max_increase': 'Max increase',
|
||
'credit.context.no_parent': 'Tier-1 agents are platform-managed; increases are not capped by a parent',
|
||
'credit.context.after_adjust': 'Credit limit after adjustment',
|
||
'credit.context.direct_liability': 'Direct player exposure',
|
||
'credit.context.child_exposure': 'Sub-agent exposure',
|
||
'credit.context.acting_agent': 'Current agent',
|
||
'agent_portal.create_player_dialog': 'New direct player',
|
||
'agent_portal.edit_player_dialog': 'Edit direct player',
|
||
'agent_portal.my_cashback_rate': 'Cashback rate',
|
||
'agent_portal.credit_available_hint': 'Available credit: {amount} (top-ups deduct from your limit)',
|
||
'agent_portal.sub_agent_players_readonly': 'Players under this sub-agent are read-only here. Account opening and top-ups are handled by the sub-agent.',
|
||
'agent_portal.sub_agent_downline_readonly': 'All subordinate agents and players below this sub-agent are read-only. You may only operate direct sub-agents; account opening and top-ups are handled by each level.',
|
||
'agent_portal.sub_agent_downline_readonly_level': 'All agents and players below this L{level} agent are read-only. You may only operate direct sub-agents; account opening and top-ups are handled by each level.',
|
||
'agent_portal.downline_agents_title': 'Subordinate agents',
|
||
'agent_portal.downline_players_title': 'Subordinate players',
|
||
'agent_portal.no_downline_agents': 'No subordinate agents',
|
||
'agent_portal.no_downline_players': 'No subordinate players',
|
||
'agent_portal.initial_deposit_hint': 'Optional. Initial top-up from your credit at account creation',
|
||
'agent_portal.search_player_ph': 'Username or ID',
|
||
'agent_portal.no_players': 'No direct players yet. Use the button above to create one.',
|
||
'invite.title': 'Invitation code & register link',
|
||
'invite.menu_btn': 'Invite',
|
||
'invite.dialog_title': 'Invitations',
|
||
'invite.tab_generate': 'Generate',
|
||
'invite.tab_history': 'History',
|
||
'invite.hint': 'Generate an invite code and register link. Players may enter the code to register; blank registers as platform-direct.',
|
||
'invite.generate_btn': 'Generate code / link',
|
||
'invite.regenerate_btn': 'Regenerate',
|
||
'invite.generate_ok': 'Invitation code generated',
|
||
'invite.generate_failed': 'Failed to generate — please retry',
|
||
'invite.not_generated': 'No invitation code yet',
|
||
'invite.code': 'Code',
|
||
'invite.cashback_rate': 'Cashback rate',
|
||
'invite.cashback_rate_hint': 'Players registering with this code use this rate. Defaults to the global admin-invite cashback rate.',
|
||
'invite.link': 'Register link',
|
||
'invite.copy_code': 'Copy code',
|
||
'invite.copy_code_short': 'Copy',
|
||
'invite.copy_link': 'Copy register link',
|
||
'invite.copy_link_short': 'Copy link',
|
||
'invite.copy_code_ok': 'Invitation code copied',
|
||
'invite.copy_link_ok': 'Register link copied',
|
||
'invite.copy_failed': 'Copy failed — please copy manually',
|
||
'invite.unavailable': 'Invitation code unavailable',
|
||
'invite.history_title': 'Invitation history',
|
||
'invite.view_history': 'View history',
|
||
'invite.history_hint': 'Admins see all codes; agents see their own and sub-agents’ codes.',
|
||
'invite.page_desc': 'View all invitation codes, status, and registration counts.',
|
||
'invite.history_load_failed': 'Failed to load invitation history',
|
||
'invite.filter_status': 'Status',
|
||
'invite.filter_sponsor': 'Sponsor',
|
||
'invite.filter_code': 'Code',
|
||
'invite.filter_code_ph': 'Enter code',
|
||
'invite.col_status': 'Status',
|
||
'invite.col_sponsor': 'Sponsor',
|
||
'invite.col_registrant': 'Registrant',
|
||
'invite.not_registered': 'Not registered',
|
||
'invite.col_cashback_rate': 'Cashback',
|
||
'invite.col_created': 'Created',
|
||
'invite.col_revoked': 'Revoked',
|
||
'invite.status.ACTIVE': 'Active',
|
||
'invite.status.USED': 'Used',
|
||
'invite.status.REVOKED': 'Revoked',
|
||
'invite.revoke_btn': 'Revoke',
|
||
'invite.revoke_title': 'Revoke invitation code',
|
||
'invite.revoke_confirm': 'Revoke code {code}? It will no longer work for registration.',
|
||
'invite.revoke_ok': 'Invitation code revoked',
|
||
'invite.revoke_failed': 'Failed to revoke — please retry',
|
||
'invite.delete_title': 'Delete invitation record',
|
||
'invite.delete_confirm': 'Delete history for code {code}? This cannot be undone.',
|
||
'invite.delete_ok': 'Invitation record deleted',
|
||
'invite.delete_failed': 'Failed to delete — please retry',
|
||
'agent_portal.search_sub_agent_ph': 'Username or ID',
|
||
'agent_portal.no_sub_agents': 'No tier-2 agents yet. Use the button above to create one.',
|
||
'agent_portal.no_sub_agents_level': 'No L{level} agents yet. Use the button above to create one.',
|
||
'agent_portal.sub_agent_players_readonly_level': 'Direct players under this L{level} agent are read-only here. Account opening and top-ups are handled by that agent.',
|
||
'agent_portal.create_sub_agent_dialog': 'New tier-2 agent',
|
||
'agent_portal.sub_agent_credit_hint': 'Initial credit is allocated from your available limit',
|
||
'agent_portal.adjust_credit_dialog': 'Adjust credit for {name}',
|
||
'agent_portal.credit_adjust_hint': 'Positive to increase, negative to decrease',
|
||
'msg.agent_sub_created': 'Sub-agent created',
|
||
'msg.withdraw_ok': 'Withdrawal successful',
|
||
|
||
'msg.form_invalid': 'Please check the form',
|
||
'msg.player_created': 'Player created',
|
||
'msg.agent_created': 'Agent created',
|
||
'msg.create_failed': 'Create failed',
|
||
'msg.saved': 'Saved',
|
||
'msg.save_failed': 'Save failed',
|
||
'msg.deleted': 'Deleted',
|
||
'msg.delete_failed': 'Delete failed',
|
||
'msg.league_created': 'Tournament created',
|
||
'msg.league_updated': 'Tournament updated',
|
||
'msg.match_created_draft': 'Fixture created (draft)',
|
||
'msg.published': 'Published with markets',
|
||
'msg.closed': 'Betting closed',
|
||
'msg.reopened': 'Betting reopened',
|
||
'match.reopen_kickoff_title': 'Set new kickoff time',
|
||
'match.reopen_kickoff_hint': 'Kickoff has passed. Choose a new future start time before reopening.',
|
||
'match.reopen_kickoff_invalid': 'Please choose a future kickoff time',
|
||
'msg.invalid_json': 'Invalid JSON',
|
||
'msg.import_failed': 'Import failed',
|
||
'msg.import_done': 'Import: {imported} ok, {skipped} skipped, {failed} failed / {total} total',
|
||
'msg.topup_ok': 'Top-up successful',
|
||
'msg.topup_failed': 'Top-up failed',
|
||
'msg.transfer_failed': 'Operation failed',
|
||
'msg.amount_gt_zero': 'Amount must be greater than 0',
|
||
'msg.credit_zero': 'Adjustment cannot be 0',
|
||
'msg.credit_adjusted': 'Credit updated',
|
||
'msg.credit_adjust_failed': 'Adjustment failed',
|
||
'msg.outright_no_edit': 'Outright cannot be edited here',
|
||
'msg.outright_odds_saved': 'Outright odds saved',
|
||
'msg.load_failed': 'Load failed',
|
||
|
||
'content.btn.create': 'New content',
|
||
'content.btn.enable': 'Enable',
|
||
'content.btn.disable': 'Disable',
|
||
'content.dialog.create': 'New public content',
|
||
'content.dialog.edit': 'Edit public content',
|
||
'content.confirm_delete': 'Delete "{title}"?',
|
||
'content.type.BANNER': 'Home banners',
|
||
'content.type.ANNOUNCEMENT': 'Announcements',
|
||
'content.hint.announcement': 'Shown in the player top marquee; fill title or body (body recommended)',
|
||
'content.status.DRAFT': 'Draft',
|
||
'content.status.ACTIVE': 'Active',
|
||
'content.status.INACTIVE': 'Inactive',
|
||
'content.col.sort': 'Sort',
|
||
'content.col.preview': 'Preview',
|
||
'content.col.title': 'Title / summary',
|
||
'content.col.player_visible': 'Player visible',
|
||
'content.col.schedule': 'Schedule',
|
||
'content.col.link': 'Link',
|
||
'content.field.link_type': 'Link type',
|
||
'content.field.link_target': 'Link target',
|
||
'content.field.start_time': 'Start time',
|
||
'content.field.end_time': 'End time',
|
||
'content.field.title': 'Title',
|
||
'content.field.title_ph': 'Optional; can match body',
|
||
'content.field.body': 'Body',
|
||
'content.field.announce_text': 'Marquee text',
|
||
'content.field.image_url': 'Image URL',
|
||
'content.upload.upload_btn': 'Upload Image',
|
||
'content.upload.uploading': 'Uploading…',
|
||
'content.upload.success': 'Image uploaded',
|
||
'content.upload.failed': 'Upload failed',
|
||
'content.upload.size_error': 'Image must be under 5 MB',
|
||
'content.upload.remove': 'Remove image',
|
||
'content.upload.pick_media': 'Pick from library',
|
||
'content.upload.pick_media_title': 'Select Banner Image',
|
||
'content.upload.no_media': 'No banner images in library — upload one first',
|
||
'content.upload.url_placeholder': 'Or paste image URL',
|
||
'content.upload.recommended_size': 'Recommended size: 860 x 360 px, or any 43:18 image. The player carousel keeps the full image visible and fills extra space.',
|
||
'content.link.none': 'No link',
|
||
'content.locale.zh-CN': 'Chinese (Simplified)',
|
||
'content.locale.en-US': 'English',
|
||
'content.locale.ms-MY': 'Malay',
|
||
'content.hidden_reason.NOT_ACTIVE': 'Not active or draft',
|
||
'content.hidden_reason.NOT_STARTED': 'Not started yet',
|
||
'content.hidden_reason.EXPIRED': 'Expired',
|
||
'content.hidden_reason.INCOMPLETE': 'Incomplete translations',
|
||
'content.batch.selected': '{n} selected',
|
||
'content.batch.enable': 'Enable selected',
|
||
'content.batch.disable': 'Disable selected',
|
||
'content.batch.delete': 'Delete selected',
|
||
'content.confirm_batch_enable': 'Enable {n} selected item(s)?',
|
||
'content.confirm_batch_disable': 'Disable {n} selected item(s)?',
|
||
'content.confirm_batch_delete': 'Delete {n} selected item(s)?',
|
||
'content.batch.all_ok': '{n} item(s) processed',
|
||
'content.batch.partial': '{ok} succeeded, {fail} failed',
|
||
|
||
'page.outrights.title': 'Outrights',
|
||
'page.outrights.desc': 'Create and edit any winner market; WC 2026 has one-click baseline import',
|
||
'outright.col.rank': 'Rank',
|
||
'outright.col.team_zh': 'Team (ZH)',
|
||
'outright.col.team_en': 'Team (EN)',
|
||
'outright.col.code': 'Code',
|
||
'outright.col.country': 'Country',
|
||
'outright.col.odds': 'Winner odds',
|
||
'outright.country_ph': 'Search or select country',
|
||
'teamLogo.kind.flag': 'Flag',
|
||
'teamLogo.kind.crest': 'Crest',
|
||
'outright.err_country': 'Please select a country',
|
||
'outright.btn.save_odds': 'Save all odds',
|
||
'outright.btn.close': 'Close betting',
|
||
'outright.btn.settle': 'Settle',
|
||
'outright.confirm_close': 'Closing will stop new outright bets. Continue?',
|
||
'outright.btn.save_meta': 'Save event info',
|
||
'outright.btn.publish': 'Publish',
|
||
'outright.btn.unpublish': 'Unpublish',
|
||
'outright.back_list': 'Back to list',
|
||
'outright.section.edit': 'Edit outright',
|
||
'outright.col.teams': 'Teams',
|
||
'outright.col.player_visible': 'Player',
|
||
'outright.col.league_en': 'League (EN)',
|
||
'outright.expand_no_teams': 'No teams — open Edit to add',
|
||
'outright.fixtures_sync_hint': 'Teams come from league fixtures; adjust odds and publish status only.',
|
||
'outright.empty_no_fixtures': 'No fixtures in this league — add matches under Fixtures first.',
|
||
'outright.btn.add_team': 'Add team',
|
||
'outright.add.filter_fixture': 'From fixtures',
|
||
'outright.add.filter_all': 'All built-in',
|
||
'outright.add.filter_custom': 'Custom',
|
||
'outright.add.custom_hint': 'Enter team code and Chinese/English names; logo via upload or URL.',
|
||
'outright.add.field_code': 'Team code',
|
||
'outright.add.field_logo': 'Logo',
|
||
'outright.add.ph_code': 'e.g. TEAM01',
|
||
'outright.add.ph_name_zh': 'Chinese name',
|
||
'outright.add.ph_name_en': 'English name',
|
||
'outright.add.err_code_required': 'Team code is required',
|
||
'outright.add.err_name_required': 'Enter at least Chinese or English name',
|
||
'outright.add.err_duplicate': 'This team code is already on the outright market',
|
||
'outright.add.select_all': 'Select all',
|
||
'outright.add.clear_selection': 'Clear selection',
|
||
'outright.add.selected_count': '{n} selected',
|
||
'outright.add.empty_fixture': 'No fixture teams to add (teams in matches but not yet on the outright market)',
|
||
'outright.add.empty_all': 'All built-in teams are already on the outright market',
|
||
'outright.add.default_odds': 'Default odds',
|
||
'outright.add.search_ph': 'Search name or code',
|
||
'outright.add.err_none': 'Select at least one team',
|
||
'outright.batch.mode': 'Batch manage',
|
||
'outright.batch.exit': 'Exit batch',
|
||
'outright.batch.apply_odds': 'Apply odds',
|
||
'outright.batch.remove': 'Remove selected',
|
||
'outright.batch.confirm_remove': 'Remove {n} selected team(s)?',
|
||
'outright.batch.err_none': 'Select teams first',
|
||
'outright.batch.apply_ok': 'Updated odds for {n} team(s) — click Save all odds',
|
||
'outright.batch.remove_ok': 'Removed {n} team(s)',
|
||
'outright.batch.remove_partial': '{ok} removed, {fail} failed',
|
||
'outright.sort.label': 'Sort',
|
||
'outright.sort.rank': 'Rank',
|
||
'outright.sort.name': 'Team name',
|
||
'outright.sort.code': 'Code',
|
||
'outright.sort.odds': 'Odds (current)',
|
||
'outright.sort.saved_odds': 'Odds (saved)',
|
||
'outright.sort.asc': 'Ascending',
|
||
'outright.sort.desc': 'Descending',
|
||
'msg.outright_teams_added': 'Added {n} team(s) ({skipped} skipped)',
|
||
'outright.btn.create_event': 'New outright event',
|
||
'outright.btn.import_wc2026': 'Import WC 2026 (48)',
|
||
'outright.btn.apply_canonical': 'Apply WC baseline',
|
||
'outright.field.league': 'League',
|
||
'outright.section.settings': 'Event settings',
|
||
'outright.section.teams': 'Teams & odds',
|
||
'outright.field.title': 'Event title',
|
||
'outright.field.title_placeholder': 'Title shown on player outright tab',
|
||
'outright.field.title_zh': 'Title (ZH)',
|
||
'outright.field.title_en': 'Title (EN)',
|
||
'outright.field.title_ms': 'Title (MS)',
|
||
'outright.field.status': 'Status',
|
||
'outright.status.draft': 'Draft',
|
||
'outright.status.published': 'Published',
|
||
'msg.outright_canonical_applied': '48-team winner odds applied from baseline',
|
||
'outright.team_count': '{n} / {total} teams',
|
||
'outright.team_count_open': '{n} teams',
|
||
'outright.empty_events': 'No outright events',
|
||
'outright.empty_hint': 'Create an event or import WC 2026 baseline',
|
||
'outright.err_odds_min': 'Odds must be greater than 1.00',
|
||
'outright.err_team_code': 'Team code required',
|
||
'outright.err_league': 'Select a league',
|
||
'outright.confirm_remove': 'Remove "{name}"? (closes selection)',
|
||
'outright.not_on_player': 'Hidden on player',
|
||
'outright.player_hidden_title': 'Not visible on player app yet',
|
||
'outright.hidden_reason.NOT_PUBLISHED': 'Set status to Published and save event info.',
|
||
'outright.hidden_reason.NO_SELECTIONS': 'Add at least one open team selection.',
|
||
'outright.hidden_reason.MARKET_CLOSED': 'Winner market is not open.',
|
||
'msg.load_matches_failed': 'Failed to load matches',
|
||
'msg.cashback_issued': 'Cashback issued',
|
||
'msg.cashback_cancelled': 'Cashback batch voided',
|
||
'msg.cashback_preview_ready': 'Preview ready — review and confirm payout',
|
||
'msg.cashback_preview_replaced': 'Replaced {n} older preview(s) for this period',
|
||
'msg.freeze_confirm_title': '{action} account',
|
||
'msg.freeze_confirm_body': '{action} player "{name}"?{extra}',
|
||
'msg.freeze_extra': ' They will not be able to sign in.',
|
||
'msg.freeze_done': '{action} completed',
|
||
'msg.freeze_failed': '{action} failed',
|
||
|
||
'smoke.intro': 'Run automated smoke tests from the admin console: settlement, betting rules, agent credit logic, cashback rules, read-only DB probes, and bet→settle→wallet integration.',
|
||
'smoke.intro_rule': 'Rule cases reuse the same logic as Jest unit tests; no business data is written.',
|
||
'smoke.intro_db': 'The Database suite only checks connectivity and config (read-only).',
|
||
'smoke.intro_bet_flow': 'The Bet-flow suite creates temporary matches/players, verifies freeze/payout/agent credit, then cleans up.',
|
||
'smoke.intro_note': 'Covers most UAT regression; spot-check cashback payout manually if needed.',
|
||
'smoke.field.suites': 'Suites',
|
||
'smoke.ph.suites': 'Select suites to run',
|
||
'smoke.btn.run': 'Run tests',
|
||
'smoke.last_run': 'Last run',
|
||
'smoke.results_title': 'Case results',
|
||
'smoke.empty': 'No run yet. Click Run tests.',
|
||
'smoke.stat.pass': 'Pass',
|
||
'smoke.stat.fail': 'Fail',
|
||
'smoke.stat.total': 'Total',
|
||
'smoke.col.id': 'ID',
|
||
'smoke.col.suite': 'Suite',
|
||
'smoke.col.name': 'Case',
|
||
'smoke.col.uat': 'UAT',
|
||
'smoke.col.duration': 'Duration',
|
||
'smoke.col.steps': 'Steps',
|
||
'smoke.col.message': 'Message',
|
||
'smoke.no_steps': 'No step details',
|
||
'smoke.status.PASS': 'Pass',
|
||
'smoke.status.FAIL': 'Fail',
|
||
'smoke.status.SKIP': 'Skip',
|
||
'smoke.msg.all_passed': 'All passed ({n})',
|
||
'smoke.msg.has_failures': '{n} case(s) failed — see details',
|
||
'smoke.msg.run_failed': 'Failed to run tests',
|
||
'smoke.log_title': 'Detailed log',
|
||
'smoke.btn.copy_all': 'Copy full log',
|
||
'smoke.btn.copy_one': 'Copy',
|
||
'smoke.msg.copy_ok': 'Copied to clipboard',
|
||
'smoke.msg.copy_failed': 'Copy failed — select the log manually',
|
||
'audit.action.RUN_SMOKE_TESTS': 'Run smoke tests',
|
||
|
||
'media.title': 'Media Library',
|
||
'media.upload_btn': 'Upload File',
|
||
'media.category.all': 'All',
|
||
'media.category.banners': 'Banners',
|
||
'media.category.teams': 'Team Logos',
|
||
'media.category.contents': 'Content Images',
|
||
'media.col.preview': 'Preview',
|
||
'media.col.filename': 'Filename',
|
||
'media.col.category': 'Category',
|
||
'media.col.size': 'Size',
|
||
'media.col.status': 'Status',
|
||
'media.col.uploaded': 'Uploaded',
|
||
'media.col.actions': 'Actions',
|
||
'media.status.used': 'In Use',
|
||
'media.status.unused': 'Unused',
|
||
'media.purge_btn': 'Purge Unused',
|
||
'media.purge_confirm': 'Delete {n} unused file(s)? This cannot be undone.',
|
||
'media.purge_none': 'No unused files',
|
||
'media.purge_success': '{n} file(s) deleted',
|
||
'media.delete_confirm': 'Delete this file?',
|
||
'media.delete_success': 'Deleted',
|
||
'media.upload_success': 'Upload successful',
|
||
'media.upload_failed': 'Upload failed',
|
||
'media.copy_url': 'Copy URL',
|
||
'media.url_copied': 'URL copied',
|
||
'media.upload_dialog': 'Upload File',
|
||
'media.upload_hint': 'PNG, JPG, WEBP, GIF, SVG — max 5 MB',
|
||
'media.upload_category': 'Category',
|
||
'media.drop_hint': 'Drop file here or click to select',
|
||
'media.no_files': 'No files yet',
|
||
'media.refresh': 'Refresh',
|
||
'media.unused_count': '{n} unused',
|
||
};
|
||
|
||
export default adminPages;
|