From 3cdb6a5eb9649e0f852763fdf56a5daa8d5e788f Mon Sep 17 00:00:00 2001 From: hailin Date: Thu, 12 Feb 2026 03:45:37 -0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=85=A8=E9=83=A8=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=AE=8C=E6=88=90=E5=9B=BD=E9=99=85=E5=8C=96?= =?UTF-8?q?(i18n)=EF=BC=8C=E6=94=AF=E6=8C=81=E4=B8=AD/=E8=8B=B1/=E6=97=A5?= =?UTF-8?q?=E4=B8=89=E8=AF=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - miniapp (Taro/React): 11个页面/组件,~300翻译键 - admin-app (Flutter): 19个页面,475翻译键 (zh_CN/en_US/ja_JP) - admin-web (Next.js): 25个视图+布局,2000+翻译键 - mobile (Flutter): 33+页面/组件,686翻译键 (zh_CN/zh_TW/en/ja) Co-Authored-By: Claude Opus 4.6 --- .../lib/app/i18n/app_localizations.dart | 1858 ++++++++++++--- .../admin-app/lib/app/issuer_main_shell.dart | 33 +- .../presentation/pages/ai_agent_page.dart | 39 +- .../presentation/pages/issuer_login_page.dart | 37 +- .../pages/batch_operations_page.dart | 105 +- .../pages/coupon_detail_page.dart | 97 +- .../presentation/pages/coupon_list_page.dart | 35 +- .../pages/create_coupon_page.dart | 110 +- .../presentation/pages/credit_page.dart | 63 +- .../pages/quota_management_page.dart | 69 +- .../pages/issuer_dashboard_page.dart | 81 +- .../pages/user_portrait_page.dart | 77 +- .../presentation/pages/finance_page.dart | 71 +- .../pages/financing_analysis_page.dart | 117 +- .../pages/reconciliation_page.dart | 89 +- .../presentation/pages/onboarding_page.dart | 90 +- .../presentation/pages/redemption_page.dart | 45 +- .../presentation/pages/settings_page.dart | 49 +- .../pages/store_management_page.dart | 17 +- frontend/admin-app/lib/main.dart | 14 + .../shared/widgets/ai_suggestion_card.dart | 7 +- frontend/admin-app/pubspec.yaml | 2 + frontend/admin-web/src/i18n/locales.ts | 2056 ++++++++++++++--- .../admin-web/src/layouts/AdminLayout.tsx | 87 +- .../src/views/agent/AgentPanelPage.tsx | 21 +- .../analytics/ConsumerProtectionPage.tsx | 83 +- .../views/analytics/CouponAnalyticsPage.tsx | 35 +- .../src/views/analytics/MarketMakerPage.tsx | 51 +- .../src/views/analytics/UserAnalyticsPage.tsx | 31 +- .../src/views/chain/ChainMonitorPage.tsx | 13 +- .../src/views/compliance/CompliancePage.tsx | 67 +- .../src/views/compliance/IpoReadinessPage.tsx | 59 +- .../compliance/LicenseManagementPage.tsx | 65 +- .../src/views/compliance/SecFilingPage.tsx | 51 +- .../views/compliance/SoxCompliancePage.tsx | 123 +- .../views/compliance/TaxCompliancePage.tsx | 99 +- .../views/coupons/CouponManagementPage.tsx | 21 +- .../src/views/dashboard/DashboardPage.tsx | 47 +- .../src/views/disputes/DisputePage.tsx | 39 +- .../views/finance/FinanceManagementPage.tsx | 29 +- .../src/views/insurance/InsurancePage.tsx | 31 +- .../views/issuers/IssuerManagementPage.tsx | 27 +- .../views/merchant/MerchantRedemptionPage.tsx | 17 +- .../src/views/reports/ReportsPage.tsx | 49 +- .../src/views/risk/RiskCenterPage.tsx | 33 +- .../src/views/system/SystemManagementPage.tsx | 55 +- .../src/views/trading/TradingMonitorPage.tsx | 23 +- .../src/views/users/UserManagementPage.tsx | 13 +- .../miniapp/src/components/ai-guide/index.tsx | 3 +- .../src/components/share-card/index.tsx | 7 +- frontend/miniapp/src/i18n/index.ts | 372 +++ frontend/miniapp/src/pages/detail/index.tsx | 27 +- .../miniapp/src/pages/h5-activity/index.tsx | 41 +- .../miniapp/src/pages/h5-register/index.tsx | 51 +- frontend/miniapp/src/pages/h5-share/index.tsx | 39 +- frontend/miniapp/src/pages/home/index.tsx | 35 +- frontend/miniapp/src/pages/login/index.tsx | 23 +- .../miniapp/src/pages/my-coupons/index.tsx | 9 +- frontend/miniapp/src/pages/profile/index.tsx | 43 +- frontend/miniapp/src/pages/redeem/index.tsx | 11 +- .../lib/app/i18n/app_localizations.dart | 342 +-- frontend/mobile/lib/app/i18n/strings/en.dart | 686 ++++++ frontend/mobile/lib/app/i18n/strings/ja.dart | 686 ++++++ .../mobile/lib/app/i18n/strings/zh_cn.dart | 686 ++++++ .../mobile/lib/app/i18n/strings/zh_tw.dart | 686 ++++++ frontend/mobile/lib/app/main_shell.dart | 11 +- .../presentation/pages/agent_chat_page.dart | 38 +- .../ai_agent/presentation/widgets/ai_fab.dart | 21 +- .../pages/forgot_password_page.dart | 41 +- .../auth/presentation/pages/login_page.dart | 33 +- .../presentation/pages/register_page.dart | 43 +- .../auth/presentation/pages/welcome_page.dart | 15 +- .../pages/coupon_detail_page.dart | 67 +- .../coupons/presentation/pages/home_page.dart | 55 +- .../presentation/pages/market_page.dart | 30 +- .../pages/my_coupon_detail_page.dart | 39 +- .../presentation/pages/my_coupons_page.dart | 44 +- .../pages/order_confirm_page.dart | 31 +- .../presentation/pages/payment_page.dart | 19 +- .../pages/payment_success_page.dart | 17 +- .../presentation/pages/redeem_qr_page.dart | 11 +- .../presentation/pages/search_page.dart | 19 +- .../presentation/pages/issuer_main_page.dart | 159 +- .../pages/merchant_ai_assistant_page.dart | 241 +- .../pages/merchant_home_page.dart | 93 +- .../pages/message_detail_page.dart | 44 +- .../presentation/pages/message_page.dart | 39 +- .../profile/presentation/pages/kyc_page.dart | 39 +- .../pages/payment_management_page.dart | 25 +- .../presentation/pages/pro_mode_page.dart | 66 +- .../presentation/pages/profile_page.dart | 47 +- .../presentation/pages/settings_page.dart | 51 +- .../presentation/pages/sell_order_page.dart | 33 +- .../presentation/pages/trading_page.dart | 25 +- .../presentation/pages/transfer_page.dart | 29 +- .../presentation/pages/deposit_page.dart | 15 +- .../pages/transaction_records_page.dart | 35 +- .../presentation/pages/wallet_page.dart | 37 +- .../presentation/pages/withdraw_page.dart | 23 +- frontend/mobile/lib/main.dart | 28 + .../lib/shared/widgets/ai_confirm_dialog.dart | 37 +- .../lib/shared/widgets/coupon_card.dart | 33 +- .../lib/shared/widgets/empty_state.dart | 35 +- .../mobile/lib/shared/widgets/status_tag.dart | 19 +- frontend/mobile/pubspec.yaml | 2 + 105 files changed, 8740 insertions(+), 3026 deletions(-) create mode 100644 frontend/mobile/lib/app/i18n/strings/en.dart create mode 100644 frontend/mobile/lib/app/i18n/strings/ja.dart create mode 100644 frontend/mobile/lib/app/i18n/strings/zh_cn.dart create mode 100644 frontend/mobile/lib/app/i18n/strings/zh_tw.dart diff --git a/frontend/admin-app/lib/app/i18n/app_localizations.dart b/frontend/admin-app/lib/app/i18n/app_localizations.dart index 17017a1..ecdf82f 100644 --- a/frontend/admin-app/lib/app/i18n/app_localizations.dart +++ b/frontend/admin-app/lib/app/i18n/app_localizations.dart @@ -1,38 +1,42 @@ -/// Genex Admin App (Issuer) - i18n 多语言支持 +import 'package:flutter/material.dart'; + +/// Genex Admin App (Issuer Console) - i18n 多语言支持 /// -/// 支持语言: zh-CN (默认), en-US, ja-JP -/// 使用方式: AppLocalizations.of(context).translate('key') -/// 包含: 通用键 + 发行方专用键 - +/// 使用方式: context.t('key') 或 AppLocalizations.of(context).get('key') +/// 支持语言: zh_CN(默认), en_US, ja_JP class AppLocalizations { - final String locale; + final Locale locale; + late final Map _strings; - AppLocalizations(this.locale); + AppLocalizations(this.locale) { + final key = locale.countryCode != null && locale.countryCode!.isNotEmpty + ? '${locale.languageCode}_${locale.countryCode}' + : locale.languageCode; - static AppLocalizations of(dynamic context) { - // In production, obtain from InheritedWidget / Provider - return AppLocalizations('zh-CN'); + _strings = _allStrings[key] ?? _allStrings[locale.languageCode] ?? _zhCN; } - String translate(String key) { - return _localizedValues[locale]?[key] ?? - _localizedValues['zh-CN']?[key] ?? - key; + static AppLocalizations of(BuildContext context) { + return Localizations.of(context, AppLocalizations)!; } - // Shorthand - String t(String key) => translate(key); + /// 获取翻译字符串,找不到时 fallback 到中文,再找不到返回 key + String get(String key) => _strings[key] ?? _zhCN[key] ?? key; - static const supportedLocales = ['zh-CN', 'en-US', 'ja-JP']; - - static const Map> _localizedValues = { - 'zh-CN': _zhCN, - 'en-US': _enUS, - 'ja-JP': _jaJP, + static const Map> _allStrings = { + 'zh': _zhCN, + 'zh_CN': _zhCN, + 'en': _enUS, + 'en_US': _enUS, + 'ja': _jaJP, + 'ja_JP': _jaJP, }; + // ================================================================ + // 中文 (简体) + // ================================================================ static const Map _zhCN = { - // Common + // ── Common ── 'app_name': 'Genex', 'confirm': '确认', 'cancel': '取消', @@ -48,133 +52,511 @@ class AppLocalizations { 'close': '关闭', 'more': '更多', 'all': '全部', + 'yes': '是', + 'no': '否', + 'export': '导出', + 'view': '查看', + 'submit': '提交', + 'prev_step': '上一步', + 'view_all': '查看全部', - // Tabs - 'tab_home': '首页', - 'tab_market': '市场', - 'tab_wallet': '钱包', - 'tab_profile': '我的', + // ── Tabs (bottom nav) ── + 'tab_dashboard': '数据概览', + 'tab_coupons': '券管理', + 'tab_redemption': '核销', + 'tab_finance': '财务', + 'tab_mine': '我的', - // Home - 'home_greeting': '你好', - 'home_search_hint': '搜索券、品牌...', - 'home_recommended': 'AI推荐', - 'home_hot': '热门券', - 'home_new': '新上架', - 'home_categories': '分类浏览', + // ── Login ── + 'login_title': 'Genex 发行方控制台', + 'login_subtitle': '登录您的企业账号管理券发行', + 'login_phone': '手机号', + 'login_phone_hint': '请输入企业管理员手机号', + 'login_code': '验证码', + 'login_get_code': '获取验证码', + 'login_agree_prefix': '我已阅读并同意', + 'login_agreement': '《发行方服务协议》', + 'login_button': '登录', + 'login_register': '还没有账号?申请入驻', - // Coupon - 'coupon_buy': '购买', - 'coupon_sell': '出售', - 'coupon_transfer': '转赠', - 'coupon_use': '使用', - 'coupon_detail': '券详情', + // ── Onboarding ── + 'onboarding_title': '企业入驻', + 'onboarding_step_company': '企业信息', + 'onboarding_step_documents': '资质上传', + 'onboarding_step_contact': '联系人', + 'onboarding_step_review': '审核中', + 'onboarding_submit_review': '提交审核', + 'onboarding_company_title': '企业基本信息', + 'onboarding_company_subtitle': '请填写真实的企业信息,用于入驻审核', + 'onboarding_company_name': '企业名称', + 'onboarding_company_name_hint': '请输入企业全称', + 'onboarding_credit_code': '统一社会信用代码', + 'onboarding_credit_code_hint': '请输入18位信用代码', + 'onboarding_company_type': '企业类型', + 'onboarding_type_restaurant': '餐饮企业', + 'onboarding_type_retail': '零售企业', + 'onboarding_type_entertainment': '娱乐/文旅', + 'onboarding_type_other': '其他', + 'onboarding_company_address': '企业地址', + 'onboarding_company_address_hint': '请输入企业注册地址', + 'onboarding_ai_compliance': 'AI 合规助手', + 'onboarding_ai_compliance_desc': '填写信息后,AI将自动检查合规要求', + 'onboarding_doc_title': '资质文件上传', + 'onboarding_doc_subtitle': '请上传清晰的企业资质文件', + 'onboarding_doc_license': '营业执照', + 'onboarding_doc_id': '法人身份证(正反面)', + 'onboarding_doc_cert': '行业资质证书(可选)', + 'onboarding_required': '*必填', + 'onboarding_upload': '点击上传', + 'onboarding_contact_title': '联系人信息', + 'onboarding_contact_name': '联系人姓名', + 'onboarding_contact_phone': '联系人手机号', + 'onboarding_contact_email': '企业邮箱', + 'onboarding_contact_role': '职位/角色', + 'onboarding_review_title': '审核中', + 'onboarding_review_desc': '您的入驻申请已提交,预计1-3个工作日内完成审核', + 'onboarding_back_login': '返回登录', + 'onboarding_approved_title': '审核通过', + 'onboarding_approved_desc': '恭喜!您已获得白银级初始额度', + 'onboarding_enter_console': '进入控制台', + 'onboarding_rejected_title': '审核未通过', + 'onboarding_rejected_desc': '原因:资质文件不清晰,请重新上传', + 'onboarding_resubmit': '重新提交', + + // ── Dashboard ── + 'dashboard_title': '数据概览', + 'dashboard_gold_issuer': '黄金发行方', + 'dashboard_total_issued': '总发行量', + 'dashboard_redemption_rate': '核销率', + 'dashboard_sales_revenue': '销售收入', + 'dashboard_withdrawable': '可提现', + 'dashboard_ai_insight': 'AI 洞察', + 'dashboard_ai_insight_content': '您的餐饮券本周销量下降15%,建议周末推出限时折扣活动提升销量。', + 'dashboard_dismiss': '忽略', + 'dashboard_accept': '采纳建议', + 'dashboard_credit_rating': '信用等级 AA', + 'dashboard_credit_gap': '距离 AAA 还差 12 分', + 'dashboard_improve_suggestion': '提升建议', + 'dashboard_issue_quota': '发行额度', + 'dashboard_used_percent': '已用 76%', + 'dashboard_sales_trend': '销售趋势', + 'dashboard_last_7_days': '近7天', + 'dashboard_sales_chart': '销售趋势图表', + 'dashboard_recent_activity': '最近动态', + + // ── User Portrait ── + 'user_portrait_title': '用户画像', + 'user_portrait_export': '导出', + 'user_portrait_total_buyers': '总购买用户', + 'user_portrait_mau': '月活用户', + 'user_portrait_avg_price': '平均客单价', + 'user_portrait_repurchase_rate': '复购率', + 'user_portrait_age_dist': '年龄分布', + 'user_portrait_geo_dist': '地域分布 (Top 5)', + 'user_portrait_other': '其他', + 'user_portrait_preference': '消费偏好', + 'user_portrait_dining': '餐饮', + 'user_portrait_shopping': '购物', + 'user_portrait_entertainment': '娱乐', + 'user_portrait_travel': '旅行', + 'user_portrait_repurchase_funnel': '复购漏斗', + 'user_portrait_first_purchase': '首次购买', + 'user_portrait_2nd_purchase': '2次购买', + 'user_portrait_3_5_purchase': '3-5次', + 'user_portrait_6_10_purchase': '6-10次', + 'user_portrait_10_plus_purchase': '10次以上', + 'user_portrait_ai_insight': 'AI 用户洞察', + 'user_portrait_core_users': '核心用户群体', + 'user_portrait_repurchase_advice': '复购提升建议', + 'user_portrait_geo_opportunity': '地域扩展机会', + 'user_portrait_churn_warning': '流失预警', + 'user_portrait_core_users_desc': '25-34岁女性用户占比38%,贡献42%的消费额,建议针对此群体推出专属优惠', + 'user_portrait_repurchase_advice_desc': '复购率34.2%低于行业45%,建议设置阶梯折扣或会员积分计划', + 'user_portrait_geo_opportunity_desc': '德克萨斯州增长率最高(+25%),建议加大该区域推广投入', + 'user_portrait_churn_warning_desc': '过去30天有856名用户未活跃,建议通过推送券提醒唤回', + + // ── Coupon List ── + 'coupon_list_title': '券管理', + 'coupon_list_fab': '发券', + 'coupon_list_ai_suggestion': '建议:周末发行餐饮券销量通常提升30%', + 'coupon_filter_all': '全部', + 'coupon_filter_on_sale': '在售中', + 'coupon_filter_sold_out': '已售罄', + 'coupon_filter_pending': '待审核', + 'coupon_filter_delisted': '已下架', + 'coupon_stat_issued': '发行量', + 'coupon_stat_sold': '已售', + 'coupon_stat_redeemed': '已核销', + 'coupon_stat_rate': '核销率', 'coupon_face_value': '面值', - 'coupon_price': '价格', - 'coupon_discount': '折扣', - 'coupon_valid_until': '有效期至', - 'coupon_brand': '品牌', - 'coupon_category': '类别', - 'coupon_my_coupons': '我的券', - 'coupon_available': '可用', - 'coupon_used': '已使用', - 'coupon_expired': '已过期', - // Trading - 'trade_buy_order': '买单', - 'trade_sell_order': '卖单', - 'trade_price_input': '输入价格', - 'trade_quantity': '数量', - 'trade_total': '合计', - 'trade_history': '交易记录', - 'trade_pending': '待成交', - 'trade_completed': '已完成', + // ── Create Coupon ── + 'create_coupon_title': '发行新券', + 'create_coupon_save_draft': '存为草稿', + 'create_coupon_step_template': '选择模板', + 'create_coupon_step_info': '基本信息', + 'create_coupon_step_rules': '规则设置', + 'create_coupon_step_preview': '预览确认', + 'create_coupon_select_template': '选择券模板', + 'create_coupon_select_template_desc': '选择适合您业务场景的券类型', + 'create_coupon_tpl_discount': '折扣券', + 'create_coupon_tpl_discount_desc': '按比例打折', + 'create_coupon_tpl_voucher': '代金券', + 'create_coupon_tpl_voucher_desc': '抵扣固定金额', + 'create_coupon_tpl_gift': '礼品卡', + 'create_coupon_tpl_gift_desc': '可充值消费', + 'create_coupon_tpl_stored': '储值券', + 'create_coupon_tpl_stored_desc': '预存金额消费', + 'create_coupon_basic_info': '基本信息', + 'create_coupon_name': '券名称', + 'create_coupon_name_hint': '如:¥25 星巴克礼品卡', + 'create_coupon_face_value': '面值 (\$)', + 'create_coupon_face_value_hint': '输入面值金额', + 'create_coupon_issue_price': '发行价 (\$)', + 'create_coupon_issue_price_hint': '通常低于面值', + 'create_coupon_quantity': '发行数量', + 'create_coupon_quantity_hint': '本次发行总量', + 'create_coupon_expiry': '有效期截止日(最长12个月)', + 'create_coupon_description': '券描述(可选)', + 'create_coupon_description_hint': '详细描述使用规则', + 'create_coupon_rules': '规则设置', + 'create_coupon_transferable': '允许转让', + 'create_coupon_transferable_desc': '消费者可在二级市场转售此券', + 'create_coupon_max_resale': '最大转售次数', + 'create_coupon_refund_policy': '退款策略', + 'create_coupon_refund_window': '退款窗口(天)', + 'create_coupon_auto_refund': '允许自动退款', + 'create_coupon_auto_refund_desc': '窗口期内用户可直接退款无需审核', + 'create_coupon_stackable': '可叠加使用', + 'create_coupon_stackable_desc': '同一订单可使用多张此券', + 'create_coupon_min_purchase': '最低消费金额 (\$,可选)', + 'create_coupon_store_limit': '限定门店(可选)', + 'create_coupon_store_limit_hint': '留空则全部门店可用', + 'create_coupon_preview': '预览确认', + 'create_coupon_preview_desc': '请确认以下信息,提交后将进入审核流程', + 'create_coupon_template_label': '模板', + 'create_coupon_detail_transferable': '可转让', + 'create_coupon_detail_refund_window': '退款窗口', + 'create_coupon_detail_auto_refund': '自动退款', + 'create_coupon_review_notice': '提交后将自动进入平台审核,审核通过后券将自动上架销售', + 'create_coupon_submit_success': '提交成功', + 'create_coupon_submit_desc': '您的券已提交审核,预计1-2个工作日内完成。', + 'create_coupon_ok': '确定', + 'create_coupon_day_unit': ' 天', + 'create_coupon_ai_price_suggestion': 'AI建议:同类券发行价通常为面值的85%,建议定价 \$21.25', + 'create_coupon_face_value_short': '面值', + 'create_coupon_issue_price_short': '发行价', + 'create_coupon_quantity_short': '数量', + 'create_coupon_max_times': '最多', + 'create_coupon_times': '次', - // Wallet - 'wallet_balance': '余额', - 'wallet_deposit': '充值', - 'wallet_withdraw': '提现', - 'wallet_transactions': '交易记录', + // ── Coupon Detail ── + 'coupon_detail_title': '券详情', + 'coupon_detail_edit': '编辑信息', + 'coupon_detail_reissue': '增发', + 'coupon_detail_delist': '下架', + 'coupon_detail_recall_unsold': '召回未售出', + 'coupon_detail_status_on_sale': '在售中', + 'coupon_detail_sales_data': '销售数据', + 'coupon_detail_sales_income': '销售收入', + 'coupon_detail_breakage_income': 'Breakage收入(过期券)', + 'coupon_detail_platform_fee': '平台手续费', + 'coupon_detail_net_income': '净收入', + 'coupon_detail_daily_trend': '日销量趋势', + 'coupon_detail_secondary_market': '二级市场分析', + 'coupon_detail_listing_count': '挂单数', + 'coupon_detail_avg_resale_price': '平均转售价', + 'coupon_detail_avg_discount_rate': '平均折扣率', + 'coupon_detail_resale_volume': '转售成交量', + 'coupon_detail_resale_amount': '转售成交额', + 'coupon_detail_price_chart': '价格走势K线', + 'coupon_detail_financing_effect': '融资效果', + 'coupon_detail_cash_advance': '现金提前回笼', + 'coupon_detail_avg_advance_days': '平均提前回笼天数', + 'coupon_detail_financing_cost': '融资成本', + 'coupon_detail_equiv_annual_rate': '等效年利率', + 'coupon_detail_recent_redemptions': '最近核销记录', + 'coupon_detail_recall_title': '召回未售出券', + 'coupon_detail_recall_desc': '确认召回所有未售出的券?此操作不可逆。', + 'coupon_detail_confirm_recall': '确认召回', + 'coupon_detail_delist_title': '紧急下架', + 'coupon_detail_delist_desc': '确认下架此券?下架后消费者将无法购买。', + 'coupon_detail_delist_reason': '下架原因', + 'coupon_detail_confirm_delist': '确认下架', - // Profile - 'profile_settings': '设置', - 'profile_kyc': '身份认证', - 'profile_kyc_l0': '未认证', - 'profile_kyc_l1': 'L1 基础认证', - 'profile_kyc_l2': 'L2 身份认证', - 'profile_kyc_l3': 'L3 高级认证', - 'profile_language': '语言', - 'profile_currency': '货币', - 'profile_help': '帮助中心', - 'profile_about': '关于', - 'profile_logout': '退出登录', - 'profile_pro_mode': '高级模式', + // ── Batch Operations ── + 'batch_title': '批量操作', + 'batch_history_tooltip': '操作历史', + 'batch_tab_issue': '批量发行', + 'batch_tab_recall': '批量召回', + 'batch_tab_price': '批量调价', + 'batch_progress_label': '批量操作进行中...', + 'batch_select_template': '选择券模板', + 'batch_issue_quantity': '发行数量', + 'batch_validity_range': '有效期范围', + 'batch_custom_quantity_hint': '输入自定义数量', + 'batch_custom_quantity': '自定义数量', + 'batch_date_range_hint': '点击选择有效期范围', + 'batch_preview': '发行预览', + 'batch_preview_template': '券模板', + 'batch_preview_quantity': '发行数量', + 'batch_preview_validity': '有效期', + 'batch_preview_total_value': '预估总面值', + 'batch_not_selected': '未选择', + 'batch_not_set': '未设置', + 'batch_unit_sheets': ' 张', + 'batch_confirm_issue': '确认批量发行', + 'batch_confirm_issue_desc': '将发行 {count} 张 {template},确认执行?', + 'batch_filter_category': '按类别筛选', + 'batch_filter_status': '按状态筛选', + 'batch_matching_coupons': '符合条件的券', + 'batch_select_all': '全选', + 'batch_deselect_all': '取消全选', + 'batch_remaining': '剩余', + 'batch_recall_reason': '召回原因', + 'batch_recall_reason_hint': '请输入批量召回原因(必填)', + 'batch_confirm_recall': '确认召回', + 'batch_confirm_recall_title': '确认批量召回', + 'batch_confirm_recall_desc': '将召回 {count} 张券,此操作不可撤销。', + 'batch_recall_reason_label': '原因', + 'batch_price_adjust_ratio': '价格调整比例', + 'batch_affected_coupons': '受影响的券', + 'batch_current_price': '当前价', + 'batch_price_decrease_hint': '降价 {pct}% 预计可提升销量 {impact}%', + 'batch_price_increase_hint': '涨价 {pct}% 预计利润提升 {impact}%', + 'batch_price_no_change': '当前价格不变', + 'batch_confirm_price': '确认批量调价', + 'batch_confirm_price_desc': '将对 4 种券批量调价 {pct}%,确认执行?', + 'batch_operation_history': '操作历史', + 'batch_operation_complete': '批量操作完成', + 'batch_status_on_sale': '在售中', + 'batch_status_sold': '已售出', + 'batch_status_expired': '已过期', - // Payment - 'payment_method': '支付方式', - 'payment_confirm': '确认支付', - 'payment_success': '支付成功', + // ── Redemption ── + 'redemption_title': '核销管理', + 'redemption_tab_scan': '扫码核销', + 'redemption_tab_history': '核销记录', + 'redemption_scan_hint': '将券码对准扫描框', + 'redemption_manual_hint': '手动输入券码', + 'redemption_redeem': '核销', + 'redemption_batch': '批量核销', + 'redemption_today_title': '今日核销', + 'redemption_today_count': '核销次数', + 'redemption_today_amount': '核销金额', + 'redemption_today_stores': '门店数', + 'redemption_confirm_title': '核销确认', + 'redemption_confirm_button': '确认核销', + 'redemption_batch_title': '批量核销', + 'redemption_batch_desc': '输入多个券码,每行一个', + 'redemption_batch_hint': '粘贴券码列表...', - // AI - 'ai_assistant': 'AI助手', - 'ai_ask': '问我任何问题...', - 'ai_suggestion': 'AI建议', + // ── Finance ── + 'finance_title': '财务管理', + 'finance_tab_overview': '概览', + 'finance_tab_transactions': '交易明细', + 'finance_tab_reconciliation': '对账报表', + 'finance_export_title': '导出数据', + 'finance_export_csv': '导出 CSV', + 'finance_export_excel': '导出 Excel', + 'finance_export_pdf': '导出 PDF', + 'finance_withdrawable': '可提现余额', + 'finance_withdraw': '提现', + 'finance_sales_income': '销售收入', + 'finance_breakage_income': 'Breakage收入', + 'finance_platform_fee': '平台手续费', + 'finance_pending_settlement': '待结算', + 'finance_withdrawn': '已提现', + 'finance_total_income': '总收入', + 'finance_guarantee_title': '保证金与冻结款', + 'finance_guarantee_deposit': '已缴纳保证金', + 'finance_frozen_sales': '冻结销售款', + 'finance_frozen_ratio': '冻结比例', + 'finance_auto_freeze': '自动冻结销售款', + 'finance_auto_freeze_desc': '开启后自动冻结20%销售额以提升信用', + 'finance_revenue_trend': '收入趋势', + 'finance_revenue_chart': '月度收入趋势图', + 'finance_generate_report': '生成新对账单', - // ── Issuer-specific ── - 'issuer_dashboard': '数据概览', - 'issuer_coupons': '券管理', - 'issuer_redeem': '核销', - 'issuer_finance': '财务', - 'issuer_profile': '我的', - 'issuer_onboarding': '入驻申请', - 'issuer_credit': '信用评级', - 'batch_issue': '批量发行', - 'batch_recall': '批量召回', - 'reconciliation': '对账', - 'store_management': '门店管理', + // ── Reconciliation ── + 'reconciliation_title': '对账与结算', + 'reconciliation_export_tooltip': '导出报表', + 'reconciliation_period_day': '日', + 'reconciliation_period_week': '周', + 'reconciliation_period_month': '月', + 'reconciliation_period_quarter': '季度', + 'reconciliation_expected': '应结金额', + 'reconciliation_settled': '已结金额', + 'reconciliation_pending': '待结金额', + 'reconciliation_discrepancy_amount': '差异金额', + 'reconciliation_auto_title': '自动对账', + 'reconciliation_auto_last_run': '上次运行: 今天 06:00', + 'reconciliation_auto_running': '运行中', + 'reconciliation_match_rate': '匹配率', + 'reconciliation_matched': '已匹配', + 'reconciliation_to_check': '待核查', + 'reconciliation_has_diff': '有差异', + 'reconciliation_detail_title': '对账明细', + 'reconciliation_col_period': '期间', + 'reconciliation_col_expected': '应结', + 'reconciliation_col_actual': '实结', + 'reconciliation_col_diff': '差异', + 'reconciliation_col_status': '状态', + 'reconciliation_status_done': '已对账', + 'reconciliation_status_diff': '有差异', + 'reconciliation_status_pending': '待对账', + 'reconciliation_discrepancy_title': '差异调查', + 'reconciliation_pending_items': '项待处理', + 'reconciliation_discrepancy_investigating': '调查中', + 'reconciliation_discrepancy_resolved': '已解决', + 'reconciliation_discrepancy_amount_label': '差异金额', + 'reconciliation_export_title': '导出报表', + 'reconciliation_export_dialog_title': '导出对账报表', - // Issuer Dashboard - 'issuer_total_issued': '已发行总量', - 'issuer_total_redeemed': '已核销总量', - 'issuer_active_coupons': '流通中', - 'issuer_revenue': '收入', - 'issuer_today_stats': '今日数据', - 'issuer_weekly_stats': '本周数据', - 'issuer_monthly_stats': '本月数据', + // ── Financing Analysis ── + 'financing_title': '融资效果分析', + 'financing_refresh_tooltip': '刷新数据', + 'financing_export_tooltip': '导出报告', + 'financing_total_amount': '融资总额', + 'financing_avg_rate': '平均利率', + 'financing_count': '融资笔数', + 'financing_utilization': '资金利用率', + 'financing_lifecycle': '融资生命周期', + 'financing_stage_submitted': '申请提交', + 'financing_stage_approved': '审批通过', + 'financing_stage_funded': '资金到账', + 'financing_stage_in_use': '使用中', + 'financing_stage_repayment': '还款期', + 'financing_stage_settled': '结清', + 'financing_stage_tbd': '待定', + 'financing_cost_benefit': '成本效益分析', + 'financing_interest_cost': '利息成本', + 'financing_annual_rate': '年化', + 'financing_generated_income': '产生收入', + 'financing_income_from_financing': '利用融资收入', + 'financing_net_benefit': '净收益', + 'financing_roi': '投资回报率 (ROI)', + 'financing_cost_ratio': '收益/成本比', + 'financing_liquidity': '流动性指标', + 'financing_quick_ratio': '速动比率 (Quick Ratio)', + 'financing_current_ratio': '流动比率 (Current Ratio)', + 'financing_status_healthy': '健康', + 'financing_status_good': '良好', + 'financing_cashflow_forecast': '现金流预测', + 'financing_this_month_inflow': '本月预计流入', + 'financing_this_month_outflow': '本月预计流出', + 'financing_net_cashflow': '净现金流', + 'financing_next_month_inflow': '下月预计流入', + 'financing_next_month_outflow': '下月预计流出', + 'financing_next_month_net': '下月净现金流', + 'financing_risk_title': '风险指标', + 'financing_default_rate': '违约率', + 'financing_overdue_rate': '逾期率', + 'financing_concentration': '集中度', + 'financing_default_detail': '违约率 (Default Rate)', + 'financing_default_desc': '低于行业平均 1.5%', + 'financing_overdue_detail': '逾期率 (Overdue Rate)', + 'financing_overdue_desc': '接近预警线 3.0%,需关注', + 'financing_concentration_detail': '集中度风险 (Concentration)', + 'financing_concentration_desc': '最大单笔占比 35%,建议分散', + 'financing_ai_title': 'AI 融资策略建议', + 'financing_ai_subtitle': '基于您的经营数据智能分析', + 'financing_priority_high': '高优先', + 'financing_priority_medium': '中优先', + 'financing_get_detail_plan': '获取详细融资方案', - // Coupon Management - 'issuer_create_coupon': '创建券', - 'issuer_coupon_template': '券模板', - 'issuer_coupon_status': '券状态', - 'issuer_coupon_active': '生效中', - 'issuer_coupon_paused': '已暂停', - 'issuer_coupon_recalled': '已召回', + // ── Credit ── + 'credit_title': '信用评级', + 'credit_score_label': '信用等级 AA', + 'credit_gap_label': '距离 AAA 等级还差 8 分', + 'credit_factors': '评分因子', + 'credit_factor_redemption': '核销率', + 'credit_factor_breakage': '沉淀控制', + 'credit_factor_market': '市场存续', + 'credit_factor_satisfaction': '用户满意度', + 'credit_tier_title': '发行方层级', + 'credit_tier_silver': '白银', + 'credit_tier_gold': '黄金', + 'credit_tier_platinum': '铂金', + 'credit_tier_diamond': '钻石', + 'credit_tier_progress': '当前:黄金 → 铂金需月发行量达500万', + 'credit_ai_title': 'AI 信用提升建议', + 'credit_history_title': '信用变动记录', - // Redemption - 'issuer_scan_qr': '扫码核销', - 'issuer_manual_redeem': '手动核销', - 'issuer_redeem_history': '核销记录', - 'issuer_redeem_success': '核销成功', - 'issuer_redeem_failed': '核销失败', + // ── Quota Management ── + 'quota_title': '配额管理', + 'quota_apply_increase': '申请提额', + 'quota_current': '当前配额', + 'quota_gold_tier': '黄金层级', + 'quota_used': '已使用', + 'quota_monthly_limit': '月发行限额', + 'quota_remaining': '剩余', + 'quota_breakdown': '配额分配明细', + 'quota_usage_records': '使用记录', + 'quota_period_month': '本月', + 'quota_period_quarter': '本季', + 'quota_period_year': '本年', + 'quota_tier_and_quota': '层级与配额', + 'quota_current_badge': '当前', + 'quota_monthly_quota': '月发行配额', + 'quota_upgrade_hint': '距铂金升级: 信用分达90+ 且 月发行量连续3月 ≥\$10M', + 'quota_request_title': '提额申请记录', + 'quota_request_reviewing': '审核中', + 'quota_request_rejected': '已驳回', + 'quota_request_approved': '已批准', + 'quota_submit_new': '提交新申请', - // Store Management - 'store_add': '添加门店', - 'store_edit': '编辑门店', - 'store_name': '门店名称', - 'store_address': '门店地址', - 'store_staff': '员工管理', - 'store_device': '设备管理', + // ── AI Agent ── + 'ai_agent_title': 'AI 助手', + 'ai_agent_welcome': '您好!我是 Genex AI 助手,可以帮您分析销售数据、优化定价策略、提升信用评级。有什么可以帮您的吗?', + 'ai_agent_input_hint': '输入问题...', + 'ai_agent_action_sales': '分析本月销售数据', + 'ai_agent_action_timing': '推荐最优发券时间', + 'ai_agent_action_credit': '如何提升信用评级?', + 'ai_agent_action_quota': '额度使用情况分析', - // Finance - 'finance_settlement': '结算', - 'finance_settlement_pending': '待结算', - 'finance_settlement_completed': '已结算', - 'finance_invoice': '发票', - 'finance_report': '财务报表', + // ── Store Management ── + 'store_title': '门店管理', + 'store_tab_list': '门店列表', + 'store_tab_employees': '员工管理', + 'store_status_open': '营业中', + 'store_status_closed': '休息中', + 'store_people_unit': '人', + 'store_emp_edit': '编辑', + 'store_emp_remove': '移除', + + // ── Settings ── + 'settings_title': '我的', + 'settings_admin': '管理员', + 'settings_gold_issuer': '黄金发行方', + 'settings_upgrade': '升级', + 'settings_group_company': '企业管理', + 'settings_company_info': '企业信息', + 'settings_store_mgmt': '门店管理', + 'settings_employee_mgmt': '员工管理', + 'settings_permissions': '权限设置', + 'settings_group_support': '服务支持', + 'settings_ai_assistant': 'AI 助手', + 'settings_customer_service': '专属客服', + 'settings_help_center': '帮助中心', + 'settings_feedback': '意见反馈', + 'settings_group_security': '安全与账号', + 'settings_change_password': '修改密码', + 'settings_operation_log': '操作日志', + 'settings_about': '关于 Genex', + 'settings_logout': '退出登录', + + // ── AI Suggestion Card ── + 'ai_suggestion_label': 'AI 建议', + 'ai_suggestion_dismiss': '忽略', + 'ai_suggestion_accept': '采纳', }; + // ================================================================ + // English (US) + // ================================================================ static const Map _enUS = { - // Common + // ── Common ── 'app_name': 'Genex', 'confirm': 'Confirm', 'cancel': 'Cancel', @@ -190,133 +572,511 @@ class AppLocalizations { 'close': 'Close', 'more': 'More', 'all': 'All', + 'yes': 'Yes', + 'no': 'No', + 'export': 'Export', + 'view': 'View', + 'submit': 'Submit', + 'prev_step': 'Previous', + 'view_all': 'View All', - // Tabs - 'tab_home': 'Home', - 'tab_market': 'Market', - 'tab_wallet': 'Wallet', - 'tab_profile': 'Profile', + // ── Tabs ── + 'tab_dashboard': 'Dashboard', + 'tab_coupons': 'Coupons', + 'tab_redemption': 'Redeem', + 'tab_finance': 'Finance', + 'tab_mine': 'Settings', - // Home - 'home_greeting': 'Hello', - 'home_search_hint': 'Search coupons, brands...', - 'home_recommended': 'AI Picks', - 'home_hot': 'Trending', - 'home_new': 'New Arrivals', - 'home_categories': 'Categories', + // ── Login ── + 'login_title': 'Genex Issuer Console', + 'login_subtitle': 'Sign in to manage your coupon issuance', + 'login_phone': 'Phone Number', + 'login_phone_hint': 'Enter admin phone number', + 'login_code': 'Verification Code', + 'login_get_code': 'Get Code', + 'login_agree_prefix': 'I have read and agree to the ', + 'login_agreement': 'Issuer Service Agreement', + 'login_button': 'Sign In', + 'login_register': 'No account? Apply to join', - // Coupon - 'coupon_buy': 'Buy', - 'coupon_sell': 'Sell', - 'coupon_transfer': 'Gift', - 'coupon_use': 'Redeem', - 'coupon_detail': 'Coupon Details', + // ── Onboarding ── + 'onboarding_title': 'Business Onboarding', + 'onboarding_step_company': 'Company', + 'onboarding_step_documents': 'Documents', + 'onboarding_step_contact': 'Contact', + 'onboarding_step_review': 'Review', + 'onboarding_submit_review': 'Submit for Review', + 'onboarding_company_title': 'Company Information', + 'onboarding_company_subtitle': 'Please provide accurate company details for review', + 'onboarding_company_name': 'Company Name', + 'onboarding_company_name_hint': 'Enter full company name', + 'onboarding_credit_code': 'Business Registration Number', + 'onboarding_credit_code_hint': 'Enter 18-digit code', + 'onboarding_company_type': 'Company Type', + 'onboarding_type_restaurant': 'Restaurant / F&B', + 'onboarding_type_retail': 'Retail', + 'onboarding_type_entertainment': 'Entertainment / Tourism', + 'onboarding_type_other': 'Other', + 'onboarding_company_address': 'Company Address', + 'onboarding_company_address_hint': 'Enter registered address', + 'onboarding_ai_compliance': 'AI Compliance Assistant', + 'onboarding_ai_compliance_desc': 'AI will auto-check compliance after you fill in the info', + 'onboarding_doc_title': 'Upload Documents', + 'onboarding_doc_subtitle': 'Please upload clear copies of business documents', + 'onboarding_doc_license': 'Business License', + 'onboarding_doc_id': 'Legal Representative ID (front & back)', + 'onboarding_doc_cert': 'Industry Certificate (optional)', + 'onboarding_required': '*Required', + 'onboarding_upload': 'Upload', + 'onboarding_contact_title': 'Contact Information', + 'onboarding_contact_name': 'Contact Name', + 'onboarding_contact_phone': 'Contact Phone', + 'onboarding_contact_email': 'Business Email', + 'onboarding_contact_role': 'Position / Role', + 'onboarding_review_title': 'Under Review', + 'onboarding_review_desc': 'Your application has been submitted. Review takes 1-3 business days.', + 'onboarding_back_login': 'Back to Login', + 'onboarding_approved_title': 'Approved', + 'onboarding_approved_desc': 'Congratulations! You have received a Silver-tier initial quota.', + 'onboarding_enter_console': 'Enter Console', + 'onboarding_rejected_title': 'Not Approved', + 'onboarding_rejected_desc': 'Reason: Documents unclear, please re-upload.', + 'onboarding_resubmit': 'Resubmit', + + // ── Dashboard ── + 'dashboard_title': 'Dashboard', + 'dashboard_gold_issuer': 'Gold Issuer', + 'dashboard_total_issued': 'Total Issued', + 'dashboard_redemption_rate': 'Redemption Rate', + 'dashboard_sales_revenue': 'Sales Revenue', + 'dashboard_withdrawable': 'Withdrawable', + 'dashboard_ai_insight': 'AI Insights', + 'dashboard_ai_insight_content': 'Your dining coupon sales dropped 15% this week. Consider a limited-time weekend discount to boost sales.', + 'dashboard_dismiss': 'Dismiss', + 'dashboard_accept': 'Accept', + 'dashboard_credit_rating': 'Credit Rating AA', + 'dashboard_credit_gap': '12 points to AAA', + 'dashboard_improve_suggestion': 'Tips', + 'dashboard_issue_quota': 'Issue Quota', + 'dashboard_used_percent': '76% Used', + 'dashboard_sales_trend': 'Sales Trend', + 'dashboard_last_7_days': 'Last 7 Days', + 'dashboard_sales_chart': 'Sales Trend Chart', + 'dashboard_recent_activity': 'Recent Activity', + + // ── User Portrait ── + 'user_portrait_title': 'User Insights', + 'user_portrait_export': 'Export', + 'user_portrait_total_buyers': 'Total Buyers', + 'user_portrait_mau': 'Monthly Active', + 'user_portrait_avg_price': 'Avg. Order', + 'user_portrait_repurchase_rate': 'Repurchase', + 'user_portrait_age_dist': 'Age Distribution', + 'user_portrait_geo_dist': 'Region Distribution (Top 5)', + 'user_portrait_other': 'Other', + 'user_portrait_preference': 'Purchase Preference', + 'user_portrait_dining': 'Dining', + 'user_portrait_shopping': 'Shopping', + 'user_portrait_entertainment': 'Entertainment', + 'user_portrait_travel': 'Travel', + 'user_portrait_repurchase_funnel': 'Repurchase Funnel', + 'user_portrait_first_purchase': 'First Purchase', + 'user_portrait_2nd_purchase': '2nd Purchase', + 'user_portrait_3_5_purchase': '3-5 Times', + 'user_portrait_6_10_purchase': '6-10 Times', + 'user_portrait_10_plus_purchase': '10+ Times', + 'user_portrait_ai_insight': 'AI User Insights', + 'user_portrait_core_users': 'Core User Group', + 'user_portrait_repurchase_advice': 'Repurchase Advice', + 'user_portrait_geo_opportunity': 'Geographic Opportunity', + 'user_portrait_churn_warning': 'Churn Warning', + 'user_portrait_core_users_desc': 'Female users aged 25-34 account for 38%, contributing 42% of spending. Consider exclusive offers for this group.', + 'user_portrait_repurchase_advice_desc': 'Repurchase rate 34.2% is below the industry avg 45%. Consider tiered discounts or loyalty programs.', + 'user_portrait_geo_opportunity_desc': 'Texas has the highest growth rate (+25%). Consider increasing promotion in that region.', + 'user_portrait_churn_warning_desc': '856 users have been inactive for 30 days. Consider push notifications with coupons to re-engage.', + + // ── Coupon List ── + 'coupon_list_title': 'Coupon Management', + 'coupon_list_fab': 'Issue', + 'coupon_list_ai_suggestion': 'Tip: Weekend dining coupons typically boost sales 30%', + 'coupon_filter_all': 'All', + 'coupon_filter_on_sale': 'On Sale', + 'coupon_filter_sold_out': 'Sold Out', + 'coupon_filter_pending': 'Pending', + 'coupon_filter_delisted': 'Delisted', + 'coupon_stat_issued': 'Issued', + 'coupon_stat_sold': 'Sold', + 'coupon_stat_redeemed': 'Redeemed', + 'coupon_stat_rate': 'Rate', 'coupon_face_value': 'Face Value', - 'coupon_price': 'Price', - 'coupon_discount': 'Discount', - 'coupon_valid_until': 'Valid Until', - 'coupon_brand': 'Brand', - 'coupon_category': 'Category', - 'coupon_my_coupons': 'My Coupons', - 'coupon_available': 'Available', - 'coupon_used': 'Used', - 'coupon_expired': 'Expired', - // Trading - 'trade_buy_order': 'Buy Order', - 'trade_sell_order': 'Sell Order', - 'trade_price_input': 'Enter Price', - 'trade_quantity': 'Quantity', - 'trade_total': 'Total', - 'trade_history': 'Trade History', - 'trade_pending': 'Pending', - 'trade_completed': 'Completed', + // ── Create Coupon ── + 'create_coupon_title': 'Issue New Coupon', + 'create_coupon_save_draft': 'Save Draft', + 'create_coupon_step_template': 'Template', + 'create_coupon_step_info': 'Details', + 'create_coupon_step_rules': 'Rules', + 'create_coupon_step_preview': 'Preview', + 'create_coupon_select_template': 'Select Template', + 'create_coupon_select_template_desc': 'Choose the coupon type that fits your business', + 'create_coupon_tpl_discount': 'Discount Coupon', + 'create_coupon_tpl_discount_desc': 'Percentage discount', + 'create_coupon_tpl_voucher': 'Cash Voucher', + 'create_coupon_tpl_voucher_desc': 'Fixed amount off', + 'create_coupon_tpl_gift': 'Gift Card', + 'create_coupon_tpl_gift_desc': 'Reloadable spending', + 'create_coupon_tpl_stored': 'Stored Value', + 'create_coupon_tpl_stored_desc': 'Pre-paid balance', + 'create_coupon_basic_info': 'Basic Info', + 'create_coupon_name': 'Coupon Name', + 'create_coupon_name_hint': 'e.g. \$25 Starbucks Gift Card', + 'create_coupon_face_value': 'Face Value (\$)', + 'create_coupon_face_value_hint': 'Enter face value', + 'create_coupon_issue_price': 'Issue Price (\$)', + 'create_coupon_issue_price_hint': 'Usually below face value', + 'create_coupon_quantity': 'Issue Quantity', + 'create_coupon_quantity_hint': 'Total for this batch', + 'create_coupon_expiry': 'Expiry Date (max 12 months)', + 'create_coupon_description': 'Description (optional)', + 'create_coupon_description_hint': 'Describe usage rules', + 'create_coupon_rules': 'Rules', + 'create_coupon_transferable': 'Transferable', + 'create_coupon_transferable_desc': 'Consumers can resell on secondary market', + 'create_coupon_max_resale': 'Max Resale Count', + 'create_coupon_refund_policy': 'Refund Policy', + 'create_coupon_refund_window': 'Refund Window (days)', + 'create_coupon_auto_refund': 'Auto Refund', + 'create_coupon_auto_refund_desc': 'Users can refund directly within the window', + 'create_coupon_stackable': 'Stackable', + 'create_coupon_stackable_desc': 'Multiple coupons per order', + 'create_coupon_min_purchase': 'Minimum Purchase (\$, optional)', + 'create_coupon_store_limit': 'Store Restriction (optional)', + 'create_coupon_store_limit_hint': 'Leave empty for all stores', + 'create_coupon_preview': 'Preview & Confirm', + 'create_coupon_preview_desc': 'Please confirm the details. Once submitted, it goes to review.', + 'create_coupon_template_label': 'Template', + 'create_coupon_detail_transferable': 'Transferable', + 'create_coupon_detail_refund_window': 'Refund Window', + 'create_coupon_detail_auto_refund': 'Auto Refund', + 'create_coupon_review_notice': 'After submission, the coupon enters platform review and is listed automatically upon approval.', + 'create_coupon_submit_success': 'Submitted', + 'create_coupon_submit_desc': 'Your coupon is under review. Expected 1-2 business days.', + 'create_coupon_ok': 'OK', + 'create_coupon_day_unit': ' days', + 'create_coupon_ai_price_suggestion': 'AI Tip: Similar coupons are typically priced at 85% of face value. Suggested price: \$21.25', + 'create_coupon_face_value_short': 'Face Value', + 'create_coupon_issue_price_short': 'Issue Price', + 'create_coupon_quantity_short': 'Quantity', + 'create_coupon_max_times': 'Max ', + 'create_coupon_times': ' times', - // Wallet - 'wallet_balance': 'Balance', - 'wallet_deposit': 'Deposit', - 'wallet_withdraw': 'Withdraw', - 'wallet_transactions': 'Transactions', + // ── Coupon Detail ── + 'coupon_detail_title': 'Coupon Detail', + 'coupon_detail_edit': 'Edit', + 'coupon_detail_reissue': 'Reissue', + 'coupon_detail_delist': 'Delist', + 'coupon_detail_recall_unsold': 'Recall Unsold', + 'coupon_detail_status_on_sale': 'On Sale', + 'coupon_detail_sales_data': 'Sales Data', + 'coupon_detail_sales_income': 'Sales Revenue', + 'coupon_detail_breakage_income': 'Breakage Revenue (expired)', + 'coupon_detail_platform_fee': 'Platform Fee', + 'coupon_detail_net_income': 'Net Revenue', + 'coupon_detail_daily_trend': 'Daily Sales Trend', + 'coupon_detail_secondary_market': 'Secondary Market', + 'coupon_detail_listing_count': 'Listings', + 'coupon_detail_avg_resale_price': 'Avg. Resale Price', + 'coupon_detail_avg_discount_rate': 'Avg. Discount Rate', + 'coupon_detail_resale_volume': 'Resale Volume', + 'coupon_detail_resale_amount': 'Resale Amount', + 'coupon_detail_price_chart': 'Price Chart', + 'coupon_detail_financing_effect': 'Financing Effect', + 'coupon_detail_cash_advance': 'Cash Advance', + 'coupon_detail_avg_advance_days': 'Avg. Advance Days', + 'coupon_detail_financing_cost': 'Financing Cost', + 'coupon_detail_equiv_annual_rate': 'Equiv. Annual Rate', + 'coupon_detail_recent_redemptions': 'Recent Redemptions', + 'coupon_detail_recall_title': 'Recall Unsold Coupons', + 'coupon_detail_recall_desc': 'Recall all unsold coupons? This cannot be undone.', + 'coupon_detail_confirm_recall': 'Confirm Recall', + 'coupon_detail_delist_title': 'Emergency Delist', + 'coupon_detail_delist_desc': 'Delist this coupon? Consumers will no longer be able to purchase.', + 'coupon_detail_delist_reason': 'Delist Reason', + 'coupon_detail_confirm_delist': 'Confirm Delist', - // Profile - 'profile_settings': 'Settings', - 'profile_kyc': 'Verification', - 'profile_kyc_l0': 'Unverified', - 'profile_kyc_l1': 'L1 Basic', - 'profile_kyc_l2': 'L2 Identity', - 'profile_kyc_l3': 'L3 Advanced', - 'profile_language': 'Language', - 'profile_currency': 'Currency', - 'profile_help': 'Help Center', - 'profile_about': 'About', - 'profile_logout': 'Log Out', - 'profile_pro_mode': 'Pro Mode', + // ── Batch Operations ── + 'batch_title': 'Batch Operations', + 'batch_history_tooltip': 'History', + 'batch_tab_issue': 'Batch Issue', + 'batch_tab_recall': 'Batch Recall', + 'batch_tab_price': 'Batch Pricing', + 'batch_progress_label': 'Batch operation in progress...', + 'batch_select_template': 'Select Template', + 'batch_issue_quantity': 'Issue Quantity', + 'batch_validity_range': 'Validity Period', + 'batch_custom_quantity_hint': 'Enter custom quantity', + 'batch_custom_quantity': 'Custom Quantity', + 'batch_date_range_hint': 'Select validity range', + 'batch_preview': 'Issue Preview', + 'batch_preview_template': 'Template', + 'batch_preview_quantity': 'Quantity', + 'batch_preview_validity': 'Validity', + 'batch_preview_total_value': 'Est. Total Value', + 'batch_not_selected': 'Not Selected', + 'batch_not_set': 'Not Set', + 'batch_unit_sheets': ' pcs', + 'batch_confirm_issue': 'Confirm Batch Issue', + 'batch_confirm_issue_desc': 'Issue {count} {template}. Proceed?', + 'batch_filter_category': 'Filter by Category', + 'batch_filter_status': 'Filter by Status', + 'batch_matching_coupons': 'Matching Coupons', + 'batch_select_all': 'Select All', + 'batch_deselect_all': 'Deselect All', + 'batch_remaining': 'Remaining', + 'batch_recall_reason': 'Recall Reason', + 'batch_recall_reason_hint': 'Enter recall reason (required)', + 'batch_confirm_recall': 'Confirm Recall', + 'batch_confirm_recall_title': 'Confirm Batch Recall', + 'batch_confirm_recall_desc': 'Recall {count} coupons? This cannot be undone.', + 'batch_recall_reason_label': 'Reason', + 'batch_price_adjust_ratio': 'Price Adjustment', + 'batch_affected_coupons': 'Affected Coupons', + 'batch_current_price': 'Current Price', + 'batch_price_decrease_hint': '{pct}% discount may boost sales by {impact}%', + 'batch_price_increase_hint': '{pct}% increase may boost profit by {impact}%', + 'batch_price_no_change': 'No price change', + 'batch_confirm_price': 'Confirm Price Adjustment', + 'batch_confirm_price_desc': 'Adjust prices for 4 coupons by {pct}%. Proceed?', + 'batch_operation_history': 'Operation History', + 'batch_operation_complete': 'Batch operation complete', + 'batch_status_on_sale': 'On Sale', + 'batch_status_sold': 'Sold', + 'batch_status_expired': 'Expired', - // Payment - 'payment_method': 'Payment Method', - 'payment_confirm': 'Confirm Payment', - 'payment_success': 'Payment Successful', + // ── Redemption ── + 'redemption_title': 'Redemption', + 'redemption_tab_scan': 'Scan & Redeem', + 'redemption_tab_history': 'History', + 'redemption_scan_hint': 'Point the coupon code at the scanner', + 'redemption_manual_hint': 'Enter coupon code manually', + 'redemption_redeem': 'Redeem', + 'redemption_batch': 'Batch Redeem', + 'redemption_today_title': 'Today\'s Redemptions', + 'redemption_today_count': 'Count', + 'redemption_today_amount': 'Amount', + 'redemption_today_stores': 'Stores', + 'redemption_confirm_title': 'Confirm Redemption', + 'redemption_confirm_button': 'Confirm', + 'redemption_batch_title': 'Batch Redeem', + 'redemption_batch_desc': 'Enter multiple codes, one per line', + 'redemption_batch_hint': 'Paste coupon codes...', - // AI - 'ai_assistant': 'AI Assistant', - 'ai_ask': 'Ask me anything...', - 'ai_suggestion': 'AI Suggestion', + // ── Finance ── + 'finance_title': 'Finance', + 'finance_tab_overview': 'Overview', + 'finance_tab_transactions': 'Transactions', + 'finance_tab_reconciliation': 'Reports', + 'finance_export_title': 'Export Data', + 'finance_export_csv': 'Export CSV', + 'finance_export_excel': 'Export Excel', + 'finance_export_pdf': 'Export PDF', + 'finance_withdrawable': 'Withdrawable Balance', + 'finance_withdraw': 'Withdraw', + 'finance_sales_income': 'Sales Revenue', + 'finance_breakage_income': 'Breakage Revenue', + 'finance_platform_fee': 'Platform Fee', + 'finance_pending_settlement': 'Pending', + 'finance_withdrawn': 'Withdrawn', + 'finance_total_income': 'Total Revenue', + 'finance_guarantee_title': 'Deposit & Frozen Funds', + 'finance_guarantee_deposit': 'Deposit Paid', + 'finance_frozen_sales': 'Frozen Sales', + 'finance_frozen_ratio': 'Freeze Ratio', + 'finance_auto_freeze': 'Auto Freeze Sales', + 'finance_auto_freeze_desc': 'Freeze 20% of sales to improve credit', + 'finance_revenue_trend': 'Revenue Trend', + 'finance_revenue_chart': 'Monthly Revenue Chart', + 'finance_generate_report': 'Generate New Report', - // ── Issuer-specific ── - 'issuer_dashboard': 'Dashboard', - 'issuer_coupons': 'Coupon Management', - 'issuer_redeem': 'Redemption', - 'issuer_finance': 'Finance', - 'issuer_profile': 'My Profile', - 'issuer_onboarding': 'Onboarding', - 'issuer_credit': 'Credit Rating', - 'batch_issue': 'Batch Issue', - 'batch_recall': 'Batch Recall', - 'reconciliation': 'Reconciliation', - 'store_management': 'Store Management', + // ── Reconciliation ── + 'reconciliation_title': 'Reconciliation', + 'reconciliation_export_tooltip': 'Export Report', + 'reconciliation_period_day': 'Day', + 'reconciliation_period_week': 'Week', + 'reconciliation_period_month': 'Month', + 'reconciliation_period_quarter': 'Quarter', + 'reconciliation_expected': 'Expected', + 'reconciliation_settled': 'Settled', + 'reconciliation_pending': 'Pending', + 'reconciliation_discrepancy_amount': 'Discrepancy', + 'reconciliation_auto_title': 'Auto Reconciliation', + 'reconciliation_auto_last_run': 'Last run: Today 06:00', + 'reconciliation_auto_running': 'Running', + 'reconciliation_match_rate': 'Match Rate', + 'reconciliation_matched': 'Matched', + 'reconciliation_to_check': 'To Check', + 'reconciliation_has_diff': 'Discrepancy', + 'reconciliation_detail_title': 'Details', + 'reconciliation_col_period': 'Period', + 'reconciliation_col_expected': 'Expected', + 'reconciliation_col_actual': 'Actual', + 'reconciliation_col_diff': 'Diff', + 'reconciliation_col_status': 'Status', + 'reconciliation_status_done': 'Reconciled', + 'reconciliation_status_diff': 'Discrepancy', + 'reconciliation_status_pending': 'Pending', + 'reconciliation_discrepancy_title': 'Discrepancy Investigation', + 'reconciliation_pending_items': ' items pending', + 'reconciliation_discrepancy_investigating': 'Investigating', + 'reconciliation_discrepancy_resolved': 'Resolved', + 'reconciliation_discrepancy_amount_label': 'Discrepancy Amount', + 'reconciliation_export_title': 'Export Report', + 'reconciliation_export_dialog_title': 'Export Reconciliation Report', - // Issuer Dashboard - 'issuer_total_issued': 'Total Issued', - 'issuer_total_redeemed': 'Total Redeemed', - 'issuer_active_coupons': 'In Circulation', - 'issuer_revenue': 'Revenue', - 'issuer_today_stats': 'Today', - 'issuer_weekly_stats': 'This Week', - 'issuer_monthly_stats': 'This Month', + // ── Financing Analysis ── + 'financing_title': 'Financing Analysis', + 'financing_refresh_tooltip': 'Refresh', + 'financing_export_tooltip': 'Export Report', + 'financing_total_amount': 'Total Financed', + 'financing_avg_rate': 'Avg. Rate', + 'financing_count': 'Transactions', + 'financing_utilization': 'Utilization', + 'financing_lifecycle': 'Financing Lifecycle', + 'financing_stage_submitted': 'Submitted', + 'financing_stage_approved': 'Approved', + 'financing_stage_funded': 'Funded', + 'financing_stage_in_use': 'In Use', + 'financing_stage_repayment': 'Repayment', + 'financing_stage_settled': 'Settled', + 'financing_stage_tbd': 'TBD', + 'financing_cost_benefit': 'Cost-Benefit Analysis', + 'financing_interest_cost': 'Interest Cost', + 'financing_annual_rate': 'Annual', + 'financing_generated_income': 'Generated Income', + 'financing_income_from_financing': 'From financing', + 'financing_net_benefit': 'Net Benefit', + 'financing_roi': 'ROI', + 'financing_cost_ratio': 'Benefit/Cost Ratio', + 'financing_liquidity': 'Liquidity Metrics', + 'financing_quick_ratio': 'Quick Ratio', + 'financing_current_ratio': 'Current Ratio', + 'financing_status_healthy': 'Healthy', + 'financing_status_good': 'Good', + 'financing_cashflow_forecast': 'Cash Flow Forecast', + 'financing_this_month_inflow': 'This Month Inflow', + 'financing_this_month_outflow': 'This Month Outflow', + 'financing_net_cashflow': 'Net Cash Flow', + 'financing_next_month_inflow': 'Next Month Inflow', + 'financing_next_month_outflow': 'Next Month Outflow', + 'financing_next_month_net': 'Next Month Net', + 'financing_risk_title': 'Risk Indicators', + 'financing_default_rate': 'Default', + 'financing_overdue_rate': 'Overdue', + 'financing_concentration': 'Concentration', + 'financing_default_detail': 'Default Rate', + 'financing_default_desc': 'Below industry avg 1.5%', + 'financing_overdue_detail': 'Overdue Rate', + 'financing_overdue_desc': 'Near warning line 3.0%, monitor needed', + 'financing_concentration_detail': 'Concentration Risk', + 'financing_concentration_desc': 'Largest single exposure 35%, diversify recommended', + 'financing_ai_title': 'AI Financing Strategy', + 'financing_ai_subtitle': 'Smart analysis based on your data', + 'financing_priority_high': 'High', + 'financing_priority_medium': 'Medium', + 'financing_get_detail_plan': 'Get Detailed Plan', - // Coupon Management - 'issuer_create_coupon': 'Create Coupon', - 'issuer_coupon_template': 'Coupon Template', - 'issuer_coupon_status': 'Coupon Status', - 'issuer_coupon_active': 'Active', - 'issuer_coupon_paused': 'Paused', - 'issuer_coupon_recalled': 'Recalled', + // ── Credit ── + 'credit_title': 'Credit Rating', + 'credit_score_label': 'Credit Rating AA', + 'credit_gap_label': '8 points to AAA', + 'credit_factors': 'Rating Factors', + 'credit_factor_redemption': 'Redemption Rate', + 'credit_factor_breakage': 'Breakage Control', + 'credit_factor_market': 'Market Presence', + 'credit_factor_satisfaction': 'User Satisfaction', + 'credit_tier_title': 'Issuer Tier', + 'credit_tier_silver': 'Silver', + 'credit_tier_gold': 'Gold', + 'credit_tier_platinum': 'Platinum', + 'credit_tier_diamond': 'Diamond', + 'credit_tier_progress': 'Current: Gold -> Platinum requires 5M monthly issuance', + 'credit_ai_title': 'AI Credit Improvement Tips', + 'credit_history_title': 'Credit History', - // Redemption - 'issuer_scan_qr': 'Scan QR Code', - 'issuer_manual_redeem': 'Manual Redemption', - 'issuer_redeem_history': 'Redemption History', - 'issuer_redeem_success': 'Redemption Successful', - 'issuer_redeem_failed': 'Redemption Failed', + // ── Quota Management ── + 'quota_title': 'Quota Management', + 'quota_apply_increase': 'Request Increase', + 'quota_current': 'Current Quota', + 'quota_gold_tier': 'Gold Tier', + 'quota_used': 'Used', + 'quota_monthly_limit': 'Monthly Limit', + 'quota_remaining': 'Remaining', + 'quota_breakdown': 'Quota Breakdown', + 'quota_usage_records': 'Usage Records', + 'quota_period_month': 'This Month', + 'quota_period_quarter': 'This Quarter', + 'quota_period_year': 'This Year', + 'quota_tier_and_quota': 'Tier & Quota', + 'quota_current_badge': 'Current', + 'quota_monthly_quota': 'Monthly Quota', + 'quota_upgrade_hint': 'Platinum: Credit score 90+ and 3 consecutive months >= \$10M issuance', + 'quota_request_title': 'Quota Requests', + 'quota_request_reviewing': 'Under Review', + 'quota_request_rejected': 'Rejected', + 'quota_request_approved': 'Approved', + 'quota_submit_new': 'Submit New Request', - // Store Management - 'store_add': 'Add Store', - 'store_edit': 'Edit Store', - 'store_name': 'Store Name', - 'store_address': 'Store Address', - 'store_staff': 'Staff Management', - 'store_device': 'Device Management', + // ── AI Agent ── + 'ai_agent_title': 'AI Assistant', + 'ai_agent_welcome': 'Hello! I\'m the Genex AI Assistant. I can help analyze sales data, optimize pricing, and improve your credit rating. How can I help?', + 'ai_agent_input_hint': 'Ask a question...', + 'ai_agent_action_sales': 'Analyze monthly sales', + 'ai_agent_action_timing': 'Best time to issue coupons', + 'ai_agent_action_credit': 'How to improve credit?', + 'ai_agent_action_quota': 'Quota usage analysis', - // Finance - 'finance_settlement': 'Settlement', - 'finance_settlement_pending': 'Pending Settlement', - 'finance_settlement_completed': 'Settled', - 'finance_invoice': 'Invoice', - 'finance_report': 'Financial Report', + // ── Store Management ── + 'store_title': 'Store Management', + 'store_tab_list': 'Stores', + 'store_tab_employees': 'Employees', + 'store_status_open': 'Open', + 'store_status_closed': 'Closed', + 'store_people_unit': ' staff', + 'store_emp_edit': 'Edit', + 'store_emp_remove': 'Remove', + + // ── Settings ── + 'settings_title': 'Settings', + 'settings_admin': 'Admin', + 'settings_gold_issuer': 'Gold Issuer', + 'settings_upgrade': 'Upgrade', + 'settings_group_company': 'Company', + 'settings_company_info': 'Company Info', + 'settings_store_mgmt': 'Store Management', + 'settings_employee_mgmt': 'Employee Management', + 'settings_permissions': 'Permissions', + 'settings_group_support': 'Support', + 'settings_ai_assistant': 'AI Assistant', + 'settings_customer_service': 'Customer Service', + 'settings_help_center': 'Help Center', + 'settings_feedback': 'Feedback', + 'settings_group_security': 'Security & Account', + 'settings_change_password': 'Change Password', + 'settings_operation_log': 'Activity Log', + 'settings_about': 'About Genex', + 'settings_logout': 'Sign Out', + + // ── AI Suggestion Card ── + 'ai_suggestion_label': 'AI Suggestion', + 'ai_suggestion_dismiss': 'Dismiss', + 'ai_suggestion_accept': 'Accept', }; + // ================================================================ + // Japanese + // ================================================================ static const Map _jaJP = { - // Common + // ── Common ── 'app_name': 'Genex', 'confirm': '確認', 'cancel': 'キャンセル', @@ -332,128 +1092,528 @@ class AppLocalizations { 'close': '閉じる', 'more': 'もっと見る', 'all': 'すべて', + 'yes': 'はい', + 'no': 'いいえ', + 'export': 'エクスポート', + 'view': '表示', + 'submit': '提出', + 'prev_step': '前へ', + 'view_all': 'すべて表示', - // Tabs - 'tab_home': 'ホーム', - 'tab_market': 'マーケット', - 'tab_wallet': 'ウォレット', - 'tab_profile': 'マイページ', + // ── Tabs ── + 'tab_dashboard': 'ダッシュボード', + 'tab_coupons': 'クーポン管理', + 'tab_redemption': '検証', + 'tab_finance': '財務', + 'tab_mine': '設定', - // Home - 'home_greeting': 'こんにちは', - 'home_search_hint': 'クーポン、ブランドを検索...', - 'home_recommended': 'AIおすすめ', - 'home_hot': '人気', - 'home_new': '新着', - 'home_categories': 'カテゴリー', + // ── Login ── + 'login_title': 'Genex 発行者コンソール', + 'login_subtitle': '企業アカウントでログインしてクーポン発行を管理', + 'login_phone': '電話番号', + 'login_phone_hint': '管理者の電話番号を入力', + 'login_code': '認証コード', + 'login_get_code': 'コード取得', + 'login_agree_prefix': '以下に同意します:', + 'login_agreement': '発行者サービス規約', + 'login_button': 'ログイン', + 'login_register': 'アカウントがない場合は申請', - // Coupon - 'coupon_buy': '購入', - 'coupon_sell': '売却', - 'coupon_transfer': '贈与', - 'coupon_use': '使用', - 'coupon_detail': 'クーポン詳細', + // ── Onboarding ── + 'onboarding_title': '企業登録', + 'onboarding_step_company': '企業情報', + 'onboarding_step_documents': '書類', + 'onboarding_step_contact': '連絡先', + 'onboarding_step_review': '審査中', + 'onboarding_submit_review': '審査を提出', + 'onboarding_company_title': '企業基本情報', + 'onboarding_company_subtitle': '審査のために正確な企業情報をご記入ください', + 'onboarding_company_name': '企業名', + 'onboarding_company_name_hint': '企業正式名称を入力', + 'onboarding_credit_code': '法人番号', + 'onboarding_credit_code_hint': '18桁のコードを入力', + 'onboarding_company_type': '企業タイプ', + 'onboarding_type_restaurant': '飲食業', + 'onboarding_type_retail': '小売業', + 'onboarding_type_entertainment': 'エンタメ/観光', + 'onboarding_type_other': 'その他', + 'onboarding_company_address': '企業住所', + 'onboarding_company_address_hint': '登記住所を入力', + 'onboarding_ai_compliance': 'AI コンプライアンス', + 'onboarding_ai_compliance_desc': '入力後、AIが自動的にコンプライアンスを確認します', + 'onboarding_doc_title': '書類アップロード', + 'onboarding_doc_subtitle': '鮮明な企業書類をアップロードしてください', + 'onboarding_doc_license': '営業許可証', + 'onboarding_doc_id': '代表者身分証明書(表裏)', + 'onboarding_doc_cert': '業界資格証明書(任意)', + 'onboarding_required': '*必須', + 'onboarding_upload': 'アップロード', + 'onboarding_contact_title': '連絡先情報', + 'onboarding_contact_name': '担当者名', + 'onboarding_contact_phone': '担当者電話番号', + 'onboarding_contact_email': '企業メール', + 'onboarding_contact_role': '役職', + 'onboarding_review_title': '審査中', + 'onboarding_review_desc': '申請が提出されました。審査には1-3営業日かかります。', + 'onboarding_back_login': 'ログインに戻る', + 'onboarding_approved_title': '承認済み', + 'onboarding_approved_desc': 'おめでとうございます!シルバーティアの初期クォータを獲得しました。', + 'onboarding_enter_console': 'コンソールへ', + 'onboarding_rejected_title': '審査不合格', + 'onboarding_rejected_desc': '理由:書類が不鮮明です。再アップロードしてください。', + 'onboarding_resubmit': '再提出', + + // ── Dashboard ── + 'dashboard_title': 'ダッシュボード', + 'dashboard_gold_issuer': 'ゴールド発行者', + 'dashboard_total_issued': '総発行数', + 'dashboard_redemption_rate': '検証率', + 'dashboard_sales_revenue': '売上収入', + 'dashboard_withdrawable': '出金可能', + 'dashboard_ai_insight': 'AI インサイト', + 'dashboard_ai_insight_content': '今週の飲食クーポンの売上が15%減少しました。週末に期間限定割引を実施して売上を向上させましょう。', + 'dashboard_dismiss': '無視', + 'dashboard_accept': '採用', + 'dashboard_credit_rating': '信用等級 AA', + 'dashboard_credit_gap': 'AAAまであと12ポイント', + 'dashboard_improve_suggestion': '改善提案', + 'dashboard_issue_quota': '発行クォータ', + 'dashboard_used_percent': '76% 使用済み', + 'dashboard_sales_trend': '販売トレンド', + 'dashboard_last_7_days': '過去7日間', + 'dashboard_sales_chart': '販売トレンドチャート', + 'dashboard_recent_activity': '最近のアクティビティ', + + // ── User Portrait ── + 'user_portrait_title': 'ユーザー分析', + 'user_portrait_export': 'エクスポート', + 'user_portrait_total_buyers': '総購入者', + 'user_portrait_mau': '月間アクティブ', + 'user_portrait_avg_price': '平均注文額', + 'user_portrait_repurchase_rate': 'リピート率', + 'user_portrait_age_dist': '年齢分布', + 'user_portrait_geo_dist': '地域分布 (Top 5)', + 'user_portrait_other': 'その他', + 'user_portrait_preference': '購入嗜好', + 'user_portrait_dining': '飲食', + 'user_portrait_shopping': 'ショッピング', + 'user_portrait_entertainment': 'エンタメ', + 'user_portrait_travel': '旅行', + 'user_portrait_repurchase_funnel': 'リピートファネル', + 'user_portrait_first_purchase': '初回購入', + 'user_portrait_2nd_purchase': '2回目', + 'user_portrait_3_5_purchase': '3-5回', + 'user_portrait_6_10_purchase': '6-10回', + 'user_portrait_10_plus_purchase': '10回以上', + 'user_portrait_ai_insight': 'AI ユーザーインサイト', + 'user_portrait_core_users': 'コアユーザー', + 'user_portrait_repurchase_advice': 'リピート改善提案', + 'user_portrait_geo_opportunity': '地域拡大機会', + 'user_portrait_churn_warning': '離脱警告', + 'user_portrait_core_users_desc': '25〜34歳の女性ユーザーが38%を占め、消費額の42%に貢献。このグループ向けの限定特典を検討してください。', + 'user_portrait_repurchase_advice_desc': 'リピート率34.2%は業界平均45%を下回っています。段階割引やポイントプログラムをご検討ください。', + 'user_portrait_geo_opportunity_desc': 'テキサス州の成長率が最高(+25%)です。同地域のプロモーション強化を検討してください。', + 'user_portrait_churn_warning_desc': '856名のユーザーが30日間非アクティブです。クーポン付きプッシュ通知で呼び戻しを検討してください。', + + // ── Coupon List ── + 'coupon_list_title': 'クーポン管理', + 'coupon_list_fab': '発行', + 'coupon_list_ai_suggestion': '提案:週末の飲食クーポンは通常30%売上向上', + 'coupon_filter_all': 'すべて', + 'coupon_filter_on_sale': '販売中', + 'coupon_filter_sold_out': '完売', + 'coupon_filter_pending': '審査中', + 'coupon_filter_delisted': '非公開', + 'coupon_stat_issued': '発行数', + 'coupon_stat_sold': '販売数', + 'coupon_stat_redeemed': '検証数', + 'coupon_stat_rate': '検証率', 'coupon_face_value': '額面', - 'coupon_price': '価格', - 'coupon_discount': '割引', - 'coupon_valid_until': '有効期限', - 'coupon_brand': 'ブランド', - 'coupon_category': 'カテゴリー', - 'coupon_my_coupons': 'マイクーポン', - 'coupon_available': '利用可能', - 'coupon_used': '使用済み', - 'coupon_expired': '期限切れ', - // Trading - 'trade_buy_order': '買い注文', - 'trade_sell_order': '売り注文', - 'trade_price_input': '価格を入力', - 'trade_quantity': '数量', - 'trade_total': '合計', - 'trade_history': '取引履歴', - 'trade_pending': '未約定', - 'trade_completed': '約定済み', + // ── Create Coupon ── + 'create_coupon_title': '新規クーポン発行', + 'create_coupon_save_draft': '下書き保存', + 'create_coupon_step_template': 'テンプレート', + 'create_coupon_step_info': '基本情報', + 'create_coupon_step_rules': 'ルール', + 'create_coupon_step_preview': 'プレビュー', + 'create_coupon_select_template': 'テンプレート選択', + 'create_coupon_select_template_desc': 'ビジネスに合ったクーポンタイプを選択', + 'create_coupon_tpl_discount': '割引クーポン', + 'create_coupon_tpl_discount_desc': '割合割引', + 'create_coupon_tpl_voucher': '金券', + 'create_coupon_tpl_voucher_desc': '固定額割引', + 'create_coupon_tpl_gift': 'ギフトカード', + 'create_coupon_tpl_gift_desc': 'チャージ可能', + 'create_coupon_tpl_stored': 'プリペイド券', + 'create_coupon_tpl_stored_desc': '前払い残高', + 'create_coupon_basic_info': '基本情報', + 'create_coupon_name': 'クーポン名', + 'create_coupon_name_hint': '例:¥25 スタバギフトカード', + 'create_coupon_face_value': '額面 (\$)', + 'create_coupon_face_value_hint': '額面を入力', + 'create_coupon_issue_price': '発行価格 (\$)', + 'create_coupon_issue_price_hint': '通常は額面より低い', + 'create_coupon_quantity': '発行数量', + 'create_coupon_quantity_hint': '今回の総数', + 'create_coupon_expiry': '有効期限(最長12ヶ月)', + 'create_coupon_description': '説明(任意)', + 'create_coupon_description_hint': '利用ルールを詳しく記載', + 'create_coupon_rules': 'ルール設定', + 'create_coupon_transferable': '譲渡可能', + 'create_coupon_transferable_desc': '二次市場での転売が可能', + 'create_coupon_max_resale': '最大転売回数', + 'create_coupon_refund_policy': '返金ポリシー', + 'create_coupon_refund_window': '返金期間(日)', + 'create_coupon_auto_refund': '自動返金', + 'create_coupon_auto_refund_desc': '期間内はユーザーが直接返金可能', + 'create_coupon_stackable': '併用可能', + 'create_coupon_stackable_desc': '1注文で複数枚使用可能', + 'create_coupon_min_purchase': '最低購入金額(\$、任意)', + 'create_coupon_store_limit': '利用店舗制限(任意)', + 'create_coupon_store_limit_hint': '空欄で全店舗利用可', + 'create_coupon_preview': 'プレビュー確認', + 'create_coupon_preview_desc': '内容をご確認ください。提出後は審査に入ります。', + 'create_coupon_template_label': 'テンプレート', + 'create_coupon_detail_transferable': '譲渡可能', + 'create_coupon_detail_refund_window': '返金期間', + 'create_coupon_detail_auto_refund': '自動返金', + 'create_coupon_review_notice': '提出後、プラットフォーム審査を経て自動的に販売開始されます。', + 'create_coupon_submit_success': '提出完了', + 'create_coupon_submit_desc': 'クーポンは審査中です。1-2営業日で完了予定。', + 'create_coupon_ok': 'OK', + 'create_coupon_day_unit': ' 日', + 'create_coupon_ai_price_suggestion': 'AIアドバイス:同種のクーポンは額面の85%が一般的です。推奨価格:\$21.25', + 'create_coupon_face_value_short': '額面', + 'create_coupon_issue_price_short': '発行価格', + 'create_coupon_quantity_short': '数量', + 'create_coupon_max_times': '最大', + 'create_coupon_times': '回', - // Wallet - 'wallet_balance': '残高', - 'wallet_deposit': '入金', - 'wallet_withdraw': '出金', - 'wallet_transactions': '取引履歴', + // ── Coupon Detail ── + 'coupon_detail_title': 'クーポン詳細', + 'coupon_detail_edit': '編集', + 'coupon_detail_reissue': '追加発行', + 'coupon_detail_delist': '非公開', + 'coupon_detail_recall_unsold': '未販売回収', + 'coupon_detail_status_on_sale': '販売中', + 'coupon_detail_sales_data': '販売データ', + 'coupon_detail_sales_income': '売上収入', + 'coupon_detail_breakage_income': 'Breakage収入(期限切れ)', + 'coupon_detail_platform_fee': 'プラットフォーム手数料', + 'coupon_detail_net_income': '純収入', + 'coupon_detail_daily_trend': '日次販売トレンド', + 'coupon_detail_secondary_market': '二次市場分析', + 'coupon_detail_listing_count': '出品数', + 'coupon_detail_avg_resale_price': '平均転売価格', + 'coupon_detail_avg_discount_rate': '平均割引率', + 'coupon_detail_resale_volume': '転売成約数', + 'coupon_detail_resale_amount': '転売成約額', + 'coupon_detail_price_chart': '価格チャート', + 'coupon_detail_financing_effect': '融資効果', + 'coupon_detail_cash_advance': '前倒し回収', + 'coupon_detail_avg_advance_days': '平均前倒し日数', + 'coupon_detail_financing_cost': '融資コスト', + 'coupon_detail_equiv_annual_rate': '年利換算', + 'coupon_detail_recent_redemptions': '最近の検証記録', + 'coupon_detail_recall_title': '未販売クーポン回収', + 'coupon_detail_recall_desc': '未販売のクーポンをすべて回収しますか?元に戻せません。', + 'coupon_detail_confirm_recall': '回収確認', + 'coupon_detail_delist_title': '緊急非公開', + 'coupon_detail_delist_desc': 'このクーポンを非公開にしますか?消費者は購入できなくなります。', + 'coupon_detail_delist_reason': '非公開理由', + 'coupon_detail_confirm_delist': '非公開確認', - // Profile - 'profile_settings': '設定', - 'profile_kyc': '本人確認', - 'profile_kyc_l0': '未確認', - 'profile_kyc_l1': 'L1 基本認証', - 'profile_kyc_l2': 'L2 身分認証', - 'profile_kyc_l3': 'L3 高度認証', - 'profile_language': '言語', - 'profile_currency': '通貨', - 'profile_help': 'ヘルプ', - 'profile_about': 'アプリについて', - 'profile_logout': 'ログアウト', - 'profile_pro_mode': 'プロモード', + // ── Batch Operations ── + 'batch_title': '一括操作', + 'batch_history_tooltip': '操作履歴', + 'batch_tab_issue': '一括発行', + 'batch_tab_recall': '一括回収', + 'batch_tab_price': '一括価格変更', + 'batch_progress_label': '一括操作実行中...', + 'batch_select_template': 'テンプレート選択', + 'batch_issue_quantity': '発行数量', + 'batch_validity_range': '有効期間', + 'batch_custom_quantity_hint': 'カスタム数量を入力', + 'batch_custom_quantity': 'カスタム数量', + 'batch_date_range_hint': '有効期間を選択', + 'batch_preview': '発行プレビュー', + 'batch_preview_template': 'テンプレート', + 'batch_preview_quantity': '数量', + 'batch_preview_validity': '有効期間', + 'batch_preview_total_value': '推定総額面', + 'batch_not_selected': '未選択', + 'batch_not_set': '未設定', + 'batch_unit_sheets': ' 枚', + 'batch_confirm_issue': '一括発行確認', + 'batch_confirm_issue_desc': '{count} 枚の {template} を発行します。実行しますか?', + 'batch_filter_category': 'カテゴリで絞込', + 'batch_filter_status': 'ステータスで絞込', + 'batch_matching_coupons': '該当クーポン', + 'batch_select_all': '全選択', + 'batch_deselect_all': '全解除', + 'batch_remaining': '残り', + 'batch_recall_reason': '回収理由', + 'batch_recall_reason_hint': '回収理由を入力(必須)', + 'batch_confirm_recall': '回収確認', + 'batch_confirm_recall_title': '一括回収確認', + 'batch_confirm_recall_desc': '{count} 枚を回収します。元に戻せません。', + 'batch_recall_reason_label': '理由', + 'batch_price_adjust_ratio': '価格調整比率', + 'batch_affected_coupons': '対象クーポン', + 'batch_current_price': '現在価格', + 'batch_price_decrease_hint': '{pct}% 値下げで売上 {impact}% 向上見込み', + 'batch_price_increase_hint': '{pct}% 値上げで利益 {impact}% 向上見込み', + 'batch_price_no_change': '価格変更なし', + 'batch_confirm_price': '一括価格変更確認', + 'batch_confirm_price_desc': '4種のクーポンを {pct}% 調整します。実行しますか?', + 'batch_operation_history': '操作履歴', + 'batch_operation_complete': '一括操作完了', + 'batch_status_on_sale': '販売中', + 'batch_status_sold': '販売済', + 'batch_status_expired': '期限切れ', - // Payment - 'payment_method': '支払い方法', - 'payment_confirm': '支払いを確認', - 'payment_success': '支払い完了', + // ── Redemption ── + 'redemption_title': '検証管理', + 'redemption_tab_scan': 'スキャン検証', + 'redemption_tab_history': '検証履歴', + 'redemption_scan_hint': 'クーポンコードをスキャナーに向けてください', + 'redemption_manual_hint': 'クーポンコードを手動入力', + 'redemption_redeem': '検証', + 'redemption_batch': '一括検証', + 'redemption_today_title': '本日の検証', + 'redemption_today_count': '検証回数', + 'redemption_today_amount': '検証金額', + 'redemption_today_stores': '店舗数', + 'redemption_confirm_title': '検証確認', + 'redemption_confirm_button': '検証実行', + 'redemption_batch_title': '一括検証', + 'redemption_batch_desc': '複数コードを入力(1行1コード)', + 'redemption_batch_hint': 'コードを貼り付け...', - // AI - 'ai_assistant': 'AIアシスタント', - 'ai_ask': '何でも聞いてください...', - 'ai_suggestion': 'AIの提案', + // ── Finance ── + 'finance_title': '財務管理', + 'finance_tab_overview': '概要', + 'finance_tab_transactions': '取引明細', + 'finance_tab_reconciliation': '照合レポート', + 'finance_export_title': 'データエクスポート', + 'finance_export_csv': 'CSV エクスポート', + 'finance_export_excel': 'Excel エクスポート', + 'finance_export_pdf': 'PDF エクスポート', + 'finance_withdrawable': '出金可能残高', + 'finance_withdraw': '出金', + 'finance_sales_income': '売上収入', + 'finance_breakage_income': 'Breakage収入', + 'finance_platform_fee': 'プラットフォーム手数料', + 'finance_pending_settlement': '未決済', + 'finance_withdrawn': '出金済み', + 'finance_total_income': '総収入', + 'finance_guarantee_title': '保証金と凍結金', + 'finance_guarantee_deposit': '納入済み保証金', + 'finance_frozen_sales': '凍結売上', + 'finance_frozen_ratio': '凍結比率', + 'finance_auto_freeze': '売上自動凍結', + 'finance_auto_freeze_desc': '信用向上のため売上の20%を自動凍結', + 'finance_revenue_trend': '収入トレンド', + 'finance_revenue_chart': '月次収入チャート', + 'finance_generate_report': '新規レポート作成', - // ── Issuer-specific ── - 'issuer_dashboard': 'ダッシュボード', - 'issuer_coupons': 'クーポン管理', - 'issuer_redeem': '検証', - 'issuer_finance': '財務', - 'issuer_profile': 'マイページ', - 'issuer_onboarding': '申請', - 'issuer_credit': '信用格付け', - 'batch_issue': '一括発行', - 'batch_recall': '一括リコール', - 'reconciliation': '照合', - 'store_management': '店舗管理', + // ── Reconciliation ── + 'reconciliation_title': '照合と決済', + 'reconciliation_export_tooltip': 'レポートエクスポート', + 'reconciliation_period_day': '日', + 'reconciliation_period_week': '週', + 'reconciliation_period_month': '月', + 'reconciliation_period_quarter': '四半期', + 'reconciliation_expected': '予定金額', + 'reconciliation_settled': '決済済み', + 'reconciliation_pending': '未決済', + 'reconciliation_discrepancy_amount': '差異金額', + 'reconciliation_auto_title': '自動照合', + 'reconciliation_auto_last_run': '前回実行: 本日 06:00', + 'reconciliation_auto_running': '実行中', + 'reconciliation_match_rate': '一致率', + 'reconciliation_matched': '一致済み', + 'reconciliation_to_check': '要確認', + 'reconciliation_has_diff': '差異あり', + 'reconciliation_detail_title': '照合明細', + 'reconciliation_col_period': '期間', + 'reconciliation_col_expected': '予定', + 'reconciliation_col_actual': '実績', + 'reconciliation_col_diff': '差異', + 'reconciliation_col_status': 'ステータス', + 'reconciliation_status_done': '照合済み', + 'reconciliation_status_diff': '差異あり', + 'reconciliation_status_pending': '未照合', + 'reconciliation_discrepancy_title': '差異調査', + 'reconciliation_pending_items': ' 件処理待ち', + 'reconciliation_discrepancy_investigating': '調査中', + 'reconciliation_discrepancy_resolved': '解決済み', + 'reconciliation_discrepancy_amount_label': '差異金額', + 'reconciliation_export_title': 'レポートエクスポート', + 'reconciliation_export_dialog_title': '照合レポートエクスポート', - // Issuer Dashboard - 'issuer_total_issued': '発行総数', - 'issuer_total_redeemed': '検証総数', - 'issuer_active_coupons': '流通中', - 'issuer_revenue': '収益', - 'issuer_today_stats': '本日', - 'issuer_weekly_stats': '今週', - 'issuer_monthly_stats': '今月', + // ── Financing Analysis ── + 'financing_title': '融資効果分析', + 'financing_refresh_tooltip': 'データ更新', + 'financing_export_tooltip': 'レポートエクスポート', + 'financing_total_amount': '融資総額', + 'financing_avg_rate': '平均金利', + 'financing_count': '融資件数', + 'financing_utilization': '資金利用率', + 'financing_lifecycle': '融資ライフサイクル', + 'financing_stage_submitted': '申請提出', + 'financing_stage_approved': '承認', + 'financing_stage_funded': '入金', + 'financing_stage_in_use': '利用中', + 'financing_stage_repayment': '返済期', + 'financing_stage_settled': '完済', + 'financing_stage_tbd': '未定', + 'financing_cost_benefit': 'コスト効果分析', + 'financing_interest_cost': '利息コスト', + 'financing_annual_rate': '年率', + 'financing_generated_income': '生成収入', + 'financing_income_from_financing': '融資活用収入', + 'financing_net_benefit': '純利益', + 'financing_roi': '投資収益率 (ROI)', + 'financing_cost_ratio': '収益/コスト比', + 'financing_liquidity': '流動性指標', + 'financing_quick_ratio': '当座比率', + 'financing_current_ratio': '流動比率', + 'financing_status_healthy': '健全', + 'financing_status_good': '良好', + 'financing_cashflow_forecast': 'キャッシュフロー予測', + 'financing_this_month_inflow': '今月予定流入', + 'financing_this_month_outflow': '今月予定流出', + 'financing_net_cashflow': '純キャッシュフロー', + 'financing_next_month_inflow': '来月予定流入', + 'financing_next_month_outflow': '来月予定流出', + 'financing_next_month_net': '来月純キャッシュフロー', + 'financing_risk_title': 'リスク指標', + 'financing_default_rate': 'デフォルト率', + 'financing_overdue_rate': '延滞率', + 'financing_concentration': '集中度', + 'financing_default_detail': 'デフォルト率', + 'financing_default_desc': '業界平均1.5%を下回る', + 'financing_overdue_detail': '延滞率', + 'financing_overdue_desc': '警戒ライン3.0%に接近、要注意', + 'financing_concentration_detail': '集中度リスク', + 'financing_concentration_desc': '最大単一エクスポージャー35%、分散推奨', + 'financing_ai_title': 'AI 融資戦略提案', + 'financing_ai_subtitle': '経営データに基づくスマート分析', + 'financing_priority_high': '高優先', + 'financing_priority_medium': '中優先', + 'financing_get_detail_plan': '詳細プランを取得', - // Coupon Management - 'issuer_create_coupon': 'クーポン作成', - 'issuer_coupon_template': 'クーポンテンプレート', - 'issuer_coupon_status': 'クーポンステータス', - 'issuer_coupon_active': '有効', - 'issuer_coupon_paused': '一時停止', - 'issuer_coupon_recalled': 'リコール済み', + // ── Credit ── + 'credit_title': '信用格付け', + 'credit_score_label': '信用等級 AA', + 'credit_gap_label': 'AAAまであと8ポイント', + 'credit_factors': '評価因子', + 'credit_factor_redemption': '検証率', + 'credit_factor_breakage': '沈殿制御', + 'credit_factor_market': '市場存続', + 'credit_factor_satisfaction': 'ユーザー満足度', + 'credit_tier_title': '発行者ティア', + 'credit_tier_silver': 'シルバー', + 'credit_tier_gold': 'ゴールド', + 'credit_tier_platinum': 'プラチナ', + 'credit_tier_diamond': 'ダイヤモンド', + 'credit_tier_progress': '現在:ゴールド → プラチナには月間発行500万が必要', + 'credit_ai_title': 'AI 信用改善提案', + 'credit_history_title': '信用変動履歴', - // Redemption - 'issuer_scan_qr': 'QRコードスキャン', - 'issuer_manual_redeem': '手動検証', - 'issuer_redeem_history': '検証履歴', - 'issuer_redeem_success': '検証成功', - 'issuer_redeem_failed': '検証失敗', + // ── Quota Management ── + 'quota_title': 'クォータ管理', + 'quota_apply_increase': '増額申請', + 'quota_current': '現在のクォータ', + 'quota_gold_tier': 'ゴールドティア', + 'quota_used': '使用済み', + 'quota_monthly_limit': '月間発行限度', + 'quota_remaining': '残り', + 'quota_breakdown': 'クォータ内訳', + 'quota_usage_records': '使用記録', + 'quota_period_month': '今月', + 'quota_period_quarter': '今四半期', + 'quota_period_year': '今年', + 'quota_tier_and_quota': 'ティアとクォータ', + 'quota_current_badge': '現在', + 'quota_monthly_quota': '月間クォータ', + 'quota_upgrade_hint': 'プラチナ:信用スコア90+ かつ 3ヶ月連続 ≥\$10M発行', + 'quota_request_title': '増額申請履歴', + 'quota_request_reviewing': '審査中', + 'quota_request_rejected': '却下', + 'quota_request_approved': '承認済み', + 'quota_submit_new': '新規申請', - // Store Management - 'store_add': '店舗追加', - 'store_edit': '店舗編集', - 'store_name': '店舗名', - 'store_address': '店舗住所', - 'store_staff': 'スタッフ管理', - 'store_device': 'デバイス管理', + // ── AI Agent ── + 'ai_agent_title': 'AI アシスタント', + 'ai_agent_welcome': 'こんにちは!Genex AIアシスタントです。販売データ分析、価格最適化、信用格付け向上のお手伝いができます。何かお手伝いしましょうか?', + 'ai_agent_input_hint': '質問を入力...', + 'ai_agent_action_sales': '今月の売上を分析', + 'ai_agent_action_timing': '最適な発行タイミング', + 'ai_agent_action_credit': '信用格付けの改善方法', + 'ai_agent_action_quota': 'クォータ使用状況分析', - // Finance - 'finance_settlement': '決済', - 'finance_settlement_pending': '未決済', - 'finance_settlement_completed': '決済済み', - 'finance_invoice': '請求書', - 'finance_report': '財務レポート', + // ── Store Management ── + 'store_title': '店舗管理', + 'store_tab_list': '店舗一覧', + 'store_tab_employees': 'スタッフ管理', + 'store_status_open': '営業中', + 'store_status_closed': '休業中', + 'store_people_unit': '名', + 'store_emp_edit': '編集', + 'store_emp_remove': '削除', + + // ── Settings ── + 'settings_title': '設定', + 'settings_admin': '管理者', + 'settings_gold_issuer': 'ゴールド発行者', + 'settings_upgrade': 'アップグレード', + 'settings_group_company': '企業管理', + 'settings_company_info': '企業情報', + 'settings_store_mgmt': '店舗管理', + 'settings_employee_mgmt': 'スタッフ管理', + 'settings_permissions': '権限設定', + 'settings_group_support': 'サポート', + 'settings_ai_assistant': 'AI アシスタント', + 'settings_customer_service': '専属カスタマーサービス', + 'settings_help_center': 'ヘルプセンター', + 'settings_feedback': 'フィードバック', + 'settings_group_security': 'セキュリティとアカウント', + 'settings_change_password': 'パスワード変更', + 'settings_operation_log': '操作ログ', + 'settings_about': 'Genex について', + 'settings_logout': 'ログアウト', + + // ── AI Suggestion Card ── + 'ai_suggestion_label': 'AI 提案', + 'ai_suggestion_dismiss': '無視', + 'ai_suggestion_accept': '採用', }; } + +/// LocalizationsDelegate +class AppLocalizationsDelegate extends LocalizationsDelegate { + const AppLocalizationsDelegate(); + + @override + bool isSupported(Locale locale) { + return ['zh', 'en', 'ja'].contains(locale.languageCode); + } + + @override + Future load(Locale locale) async { + return AppLocalizations(locale); + } + + @override + bool shouldReload(covariant LocalizationsDelegate old) => + false; +} + +/// BuildContext 扩展,快捷访问翻译 +extension AppLocalizationsExtension on BuildContext { + /// 快捷翻译: context.t('key') + String t(String key) => AppLocalizations.of(this).get(key); +} diff --git a/frontend/admin-app/lib/app/issuer_main_shell.dart b/frontend/admin-app/lib/app/issuer_main_shell.dart index 9e3e4b1..54e895c 100644 --- a/frontend/admin-app/lib/app/issuer_main_shell.dart +++ b/frontend/admin-app/lib/app/issuer_main_shell.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'theme/app_colors.dart'; +import 'i18n/app_localizations.dart'; import '../features/dashboard/presentation/pages/issuer_dashboard_page.dart'; import '../features/coupon_management/presentation/pages/coupon_list_page.dart'; import '../features/redemption/presentation/pages/redemption_page.dart'; @@ -39,31 +40,31 @@ class _IssuerMainShellState extends State { onDestinationSelected: (index) { setState(() => _currentIndex = index); }, - destinations: const [ + destinations: [ NavigationDestination( - icon: Icon(Icons.dashboard_outlined), - selectedIcon: Icon(Icons.dashboard_rounded), - label: '数据概览', + icon: const Icon(Icons.dashboard_outlined), + selectedIcon: const Icon(Icons.dashboard_rounded), + label: context.t('tab_dashboard'), ), NavigationDestination( - icon: Icon(Icons.confirmation_number_outlined), - selectedIcon: Icon(Icons.confirmation_number_rounded), - label: '券管理', + icon: const Icon(Icons.confirmation_number_outlined), + selectedIcon: const Icon(Icons.confirmation_number_rounded), + label: context.t('tab_coupons'), ), NavigationDestination( - icon: Icon(Icons.qr_code_scanner_outlined), - selectedIcon: Icon(Icons.qr_code_scanner_rounded), - label: '核销', + icon: const Icon(Icons.qr_code_scanner_outlined), + selectedIcon: const Icon(Icons.qr_code_scanner_rounded), + label: context.t('tab_redemption'), ), NavigationDestination( - icon: Icon(Icons.account_balance_wallet_outlined), - selectedIcon: Icon(Icons.account_balance_wallet_rounded), - label: '财务', + icon: const Icon(Icons.account_balance_wallet_outlined), + selectedIcon: const Icon(Icons.account_balance_wallet_rounded), + label: context.t('tab_finance'), ), NavigationDestination( - icon: Icon(Icons.settings_outlined), - selectedIcon: Icon(Icons.settings_rounded), - label: '我的', + icon: const Icon(Icons.settings_outlined), + selectedIcon: const Icon(Icons.settings_rounded), + label: context.t('tab_mine'), ), ], ), diff --git a/frontend/admin-app/lib/features/ai_agent/presentation/pages/ai_agent_page.dart b/frontend/admin-app/lib/features/ai_agent/presentation/pages/ai_agent_page.dart index 5842faf..f9b0545 100644 --- a/frontend/admin-app/lib/features/ai_agent/presentation/pages/ai_agent_page.dart +++ b/frontend/admin-app/lib/features/ai_agent/presentation/pages/ai_agent_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 发行方AI Agent对话页面 /// @@ -15,30 +16,33 @@ class _AiAgentPageState extends State { final _messageController = TextEditingController(); final _scrollController = ScrollController(); - final List<_ChatMessage> _messages = [ - _ChatMessage( - isAi: true, - text: '您好!我是 Genex AI 助手,可以帮您分析销售数据、优化定价策略、提升信用评级。有什么可以帮您的吗?', - ), - ]; + final List<_ChatMessage> _messages = []; + bool _initialized = false; - final _quickActions = [ - '分析本月销售数据', - '推荐最优发券时间', - '如何提升信用评级?', - '额度使用情况分析', + final _quickActionKeys = [ + 'ai_agent_action_sales', + 'ai_agent_action_timing', + 'ai_agent_action_credit', + 'ai_agent_action_quota', ]; @override Widget build(BuildContext context) { + if (!_initialized) { + _messages.add(_ChatMessage( + isAi: true, + text: context.t('ai_agent_welcome'), + )); + _initialized = true; + } return Scaffold( appBar: AppBar( - title: const Row( + title: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), - SizedBox(width: 8), - Text('AI 助手'), + const Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), + const SizedBox(width: 8), + Text(context.t('ai_agent_title')), ], ), ), @@ -60,7 +64,8 @@ class _AiAgentPageState extends State { scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( - children: _quickActions.map((action) { + children: _quickActionKeys.map((key) { + final action = context.t(key); return Padding( padding: const EdgeInsets.only(right: 8), child: ActionChip( @@ -87,7 +92,7 @@ class _AiAgentPageState extends State { child: TextField( controller: _messageController, decoration: InputDecoration( - hintText: '输入问题...', + hintText: context.t('ai_agent_input_hint'), border: OutlineInputBorder( borderRadius: BorderRadius.circular(24), borderSide: const BorderSide(color: AppColors.borderLight), diff --git a/frontend/admin-app/lib/features/auth/presentation/pages/issuer_login_page.dart b/frontend/admin-app/lib/features/auth/presentation/pages/issuer_login_page.dart index 546d144..5d69144 100644 --- a/frontend/admin-app/lib/features/auth/presentation/pages/issuer_login_page.dart +++ b/frontend/admin-app/lib/features/auth/presentation/pages/issuer_login_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/router.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 发行方登录页 /// @@ -42,14 +43,14 @@ class _IssuerLoginPageState extends State { const SizedBox(height: 24), // Title - const Text( - 'Genex 发行方控制台', - style: TextStyle(fontSize: 28, fontWeight: FontWeight.w700, color: AppColors.textPrimary), + Text( + context.t('login_title'), + style: const TextStyle(fontSize: 28, fontWeight: FontWeight.w700, color: AppColors.textPrimary), ), const SizedBox(height: 8), - const Text( - '登录您的企业账号管理券发行', - style: TextStyle(fontSize: 15, color: AppColors.textSecondary), + Text( + context.t('login_subtitle'), + style: const TextStyle(fontSize: 15, color: AppColors.textSecondary), ), const SizedBox(height: 40), @@ -57,10 +58,10 @@ class _IssuerLoginPageState extends State { TextField( controller: _phoneController, keyboardType: TextInputType.phone, - decoration: const InputDecoration( - labelText: '手机号', - prefixIcon: Icon(Icons.phone_outlined), - hintText: '请输入企业管理员手机号', + decoration: InputDecoration( + labelText: context.t('login_phone'), + prefixIcon: const Icon(Icons.phone_outlined), + hintText: context.t('login_phone_hint'), ), ), const SizedBox(height: 16), @@ -72,9 +73,9 @@ class _IssuerLoginPageState extends State { child: TextField( controller: _codeController, keyboardType: TextInputType.number, - decoration: const InputDecoration( - labelText: '验证码', - prefixIcon: Icon(Icons.lock_outline_rounded), + decoration: InputDecoration( + labelText: context.t('login_code'), + prefixIcon: const Icon(Icons.lock_outline_rounded), ), ), ), @@ -85,7 +86,7 @@ class _IssuerLoginPageState extends State { onPressed: () { // TODO: Send verification code to phone number }, - child: const Text('获取验证码'), + child: Text(context.t('login_get_code')), ), ), ], @@ -103,11 +104,11 @@ class _IssuerLoginPageState extends State { Expanded( child: Text.rich( TextSpan( - text: '我已阅读并同意', + text: context.t('login_agree_prefix'), style: const TextStyle(fontSize: 13, color: AppColors.textSecondary), children: [ TextSpan( - text: '《发行方服务协议》', + text: context.t('login_agreement'), style: const TextStyle(color: AppColors.primary), ), ], @@ -126,7 +127,7 @@ class _IssuerLoginPageState extends State { onPressed: _agreedToTerms ? () => Navigator.pushReplacementNamed(context, AppRouter.main) : null, - child: const Text('登录', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)), + child: Text(context.t('login_button'), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600)), ), ), const SizedBox(height: 16), @@ -135,7 +136,7 @@ class _IssuerLoginPageState extends State { Center( child: TextButton( onPressed: () => Navigator.pushNamed(context, AppRouter.onboarding), - child: const Text('还没有账号?申请入驻'), + child: Text(context.t('login_register')), ), ), ], diff --git a/frontend/admin-app/lib/features/coupon_management/presentation/pages/batch_operations_page.dart b/frontend/admin-app/lib/features/coupon_management/presentation/pages/batch_operations_page.dart index 793d231..64ec4a0 100644 --- a/frontend/admin-app/lib/features/coupon_management/presentation/pages/batch_operations_page.dart +++ b/frontend/admin-app/lib/features/coupon_management/presentation/pages/batch_operations_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 批量操作页面 /// @@ -58,22 +59,22 @@ class _BatchOperationsPageState extends State Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('批量操作'), + title: Text(context.t('batch_title')), actions: [ IconButton( icon: const Icon(Icons.history_rounded), onPressed: () { // TODO: Navigate to full operation history page }, - tooltip: '操作历史', + tooltip: context.t('batch_history_tooltip'), ), ], bottom: TabBar( controller: _tabController, - tabs: const [ - Tab(text: '批量发行'), - Tab(text: '批量召回'), - Tab(text: '批量调价'), + tabs: [ + Tab(text: context.t('batch_tab_issue')), + Tab(text: context.t('batch_tab_recall')), + Tab(text: context.t('batch_tab_price')), ], ), ), @@ -122,7 +123,7 @@ class _BatchOperationsPageState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '批量操作进行中...', + context.t('batch_progress_label'), style: AppTypography.labelMedium.copyWith(color: AppColors.primary), ), const SizedBox(height: 4), @@ -159,19 +160,19 @@ class _BatchOperationsPageState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ // Template Selector - _buildSectionTitle('选择券模板'), + _buildSectionTitle(context.t('batch_select_template')), const SizedBox(height: 12), _buildTemplateSelector(), const SizedBox(height: 24), // Quantity Input - _buildSectionTitle('发行数量'), + _buildSectionTitle(context.t('batch_issue_quantity')), const SizedBox(height: 12), _buildQuantitySelector(), const SizedBox(height: 24), // Date Range Picker - _buildSectionTitle('有效期范围'), + _buildSectionTitle(context.t('batch_validity_range')), const SizedBox(height: 12), _buildDateRangePicker(), const SizedBox(height: 24), @@ -185,7 +186,7 @@ class _BatchOperationsPageState extends State width: double.infinity, child: ElevatedButton( onPressed: _selectedTemplate != null ? _executeBatchIssue : null, - child: const Text('确认批量发行'), + child: Text(context.t('batch_confirm_issue')), ), ), const SizedBox(height: 32), @@ -312,7 +313,7 @@ class _BatchOperationsPageState extends State keyboardType: TextInputType.number, autofocus: true, decoration: const InputDecoration( - hintText: '输入自定义数量', + hintText: context.t('batch_custom_quantity_hint'), border: InputBorder.none, isDense: true, contentPadding: EdgeInsets.zero, @@ -327,7 +328,7 @@ class _BatchOperationsPageState extends State ) : Center( child: Text( - '自定义数量', + context.t('batch_custom_quantity'), style: AppTypography.labelMedium.copyWith( color: AppColors.textSecondary, ), @@ -376,7 +377,7 @@ class _BatchOperationsPageState extends State child: Text( _dateRange != null ? '${_formatDate(_dateRange!.start)} ~ ${_formatDate(_dateRange!.end)}' - : '点击选择有效期范围', + : context.t('batch_date_range_hint'), style: AppTypography.bodyMedium.copyWith( color: _dateRange != null ? AppColors.textPrimary : AppColors.textTertiary, ), @@ -403,20 +404,20 @@ class _BatchOperationsPageState extends State children: [ const Icon(Icons.preview_rounded, color: AppColors.primary, size: 18), const SizedBox(width: 8), - Text('发行预览', style: AppTypography.labelMedium.copyWith(color: AppColors.primary)), + Text(context.t('batch_preview'), style: AppTypography.labelMedium.copyWith(color: AppColors.primary)), ], ), const SizedBox(height: 12), - _buildSummaryRow('券模板', _selectedTemplate ?? '未选择'), - _buildSummaryRow('发行数量', '$_issueQuantity 张'), + _buildSummaryRow(context.t('batch_preview_template'), _selectedTemplate ?? context.t('batch_not_selected')), + _buildSummaryRow(context.t('batch_preview_quantity'), '$_issueQuantity ${context.t('batch_unit_sheets')}'), _buildSummaryRow( - '有效期', + context.t('batch_preview_validity'), _dateRange != null ? '${_formatDate(_dateRange!.start)} ~ ${_formatDate(_dateRange!.end)}' - : '未设置', + : context.t('batch_not_set'), ), _buildSummaryRow( - '预估总面值', + context.t('batch_preview_total_value'), _selectedTemplate != null ? '\$${(_issueQuantity * 25).toStringAsFixed(0)}' : '--', ), ], @@ -444,19 +445,19 @@ class _BatchOperationsPageState extends State showDialog( context: context, builder: (ctx) => AlertDialog( - title: const Text('确认批量发行'), - content: Text('将发行 $_issueQuantity 张 $_selectedTemplate,确认执行?'), + title: Text(context.t('batch_confirm_issue')), + content: Text(context.t('batch_confirm_issue_desc').replaceAll('{count}', '$_issueQuantity').replaceAll('{template}', _selectedTemplate ?? '')), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), - child: const Text('取消'), + child: Text(context.t('cancel')), ), ElevatedButton( onPressed: () { Navigator.pop(ctx); _startOperation(); }, - child: const Text('确认'), + child: Text(context.t('confirm')), ), ], ), @@ -477,7 +478,7 @@ class _BatchOperationsPageState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ // Filter by category - _buildSectionTitle('按类别筛选'), + _buildSectionTitle(context.t('batch_filter_category')), const SizedBox(height: 12), SingleChildScrollView( scrollDirection: Axis.horizontal, @@ -500,7 +501,7 @@ class _BatchOperationsPageState extends State const SizedBox(height: 16), // Filter by status - _buildSectionTitle('按状态筛选'), + _buildSectionTitle(context.t('batch_filter_status')), const SizedBox(height: 12), SingleChildScrollView( scrollDirection: Axis.horizontal, @@ -526,7 +527,7 @@ class _BatchOperationsPageState extends State Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('符合条件的券 (${_mockRecallCoupons.length})', style: AppTypography.labelMedium), + Text('${context.t('batch_matching_coupons')} (${_mockRecallCoupons.length})', style: AppTypography.labelMedium), Row( children: [ TextButton( @@ -536,14 +537,14 @@ class _BatchOperationsPageState extends State List.generate(_mockRecallCoupons.length, (i) => i), ); }), - child: const Text('全选'), + child: Text(context.t('batch_select_all')), ), TextButton( onPressed: () => setState(() { _selectAll = false; _selectedRecallItems.clear(); }), - child: const Text('取消全选'), + child: Text(context.t('batch_deselect_all')), ), ], ), @@ -586,7 +587,7 @@ class _BatchOperationsPageState extends State Text(coupon.name, style: AppTypography.labelMedium), const SizedBox(height: 2), Text( - '${coupon.category} · 剩余 ${coupon.remaining} 张', + '${coupon.category} · ${context.t('batch_remaining')} ${coupon.remaining}${context.t('batch_unit_sheets')}', style: AppTypography.bodySmall, ), ], @@ -600,13 +601,13 @@ class _BatchOperationsPageState extends State const SizedBox(height: 20), // Reason input - _buildSectionTitle('召回原因'), + _buildSectionTitle(context.t('batch_recall_reason')), const SizedBox(height: 12), TextField( controller: _recallReasonController, maxLines: 3, - decoration: const InputDecoration( - hintText: '请输入批量召回原因(必填)', + decoration: InputDecoration( + hintText: context.t('batch_recall_reason_hint'), ), ), const SizedBox(height: 20), @@ -623,7 +624,7 @@ class _BatchOperationsPageState extends State backgroundColor: AppColors.error, foregroundColor: Colors.white, ), - child: Text('确认召回 (${_selectedRecallItems.length} 张)'), + child: Text('${context.t('batch_confirm_recall')} (${_selectedRecallItems.length} ${context.t('batch_unit_sheets')})'), ), ), const SizedBox(height: 32), @@ -643,16 +644,16 @@ class _BatchOperationsPageState extends State children: [ Icon(Icons.warning_rounded, color: AppColors.error, size: 22), const SizedBox(width: 8), - const Text('确认批量召回'), + Text(context.t('batch_confirm_recall_title')), ], ), content: Text( - '将召回 ${_selectedRecallItems.length} 张券,此操作不可撤销。\n\n原因:${_recallReasonController.text}', + '${context.t('batch_confirm_recall_desc').replaceAll('{count}', '${_selectedRecallItems.length}')}\n\n${context.t('batch_recall_reason_label')}:${_recallReasonController.text}', ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), - child: const Text('取消'), + child: Text(context.t('cancel')), ), ElevatedButton( onPressed: () { @@ -663,7 +664,7 @@ class _BatchOperationsPageState extends State backgroundColor: AppColors.error, foregroundColor: Colors.white, ), - child: const Text('确认召回'), + child: Text(context.t('batch_confirm_recall')), ), ], ), @@ -681,7 +682,7 @@ class _BatchOperationsPageState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ // Percentage adjustment slider - _buildSectionTitle('价格调整比例'), + _buildSectionTitle(context.t('batch_price_adjust_ratio')), const SizedBox(height: 16), Container( padding: const EdgeInsets.all(20), @@ -734,7 +735,7 @@ class _BatchOperationsPageState extends State const SizedBox(height: 24), // Affected coupons preview - _buildSectionTitle('受影响的券'), + _buildSectionTitle(context.t('batch_affected_coupons')), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(16), @@ -777,10 +778,10 @@ class _BatchOperationsPageState extends State Expanded( child: Text( _priceAdjustment < 0 - ? '降价 ${_priceAdjustment.abs().toStringAsFixed(0)}% 预计可提升销量 ${(_priceAdjustment.abs() * 1.5).toStringAsFixed(0)}%' + ? context.t('batch_price_decrease_hint').replaceAll('{pct}', _priceAdjustment.abs().toStringAsFixed(0)).replaceAll('{impact}', (_priceAdjustment.abs() * 1.5).toStringAsFixed(0)) : _priceAdjustment > 0 - ? '涨价 ${_priceAdjustment.toStringAsFixed(0)}% 预计利润提升 ${(_priceAdjustment * 0.8).toStringAsFixed(0)}%' - : '当前价格不变', + ? context.t('batch_price_increase_hint').replaceAll('{pct}', _priceAdjustment.toStringAsFixed(0)).replaceAll('{impact}', (_priceAdjustment * 0.8).toStringAsFixed(0)) + : context.t('batch_price_no_change'), style: AppTypography.bodySmall.copyWith( color: _priceAdjustment < 0 ? AppColors.warning : AppColors.success, ), @@ -796,7 +797,7 @@ class _BatchOperationsPageState extends State width: double.infinity, child: ElevatedButton( onPressed: _priceAdjustment != 0 ? _executeBatchPriceAdjust : null, - child: const Text('确认批量调价'), + child: Text(context.t('batch_confirm_price')), ), ), const SizedBox(height: 32), @@ -819,7 +820,7 @@ class _BatchOperationsPageState extends State children: [ Text(name, style: AppTypography.labelMedium), const SizedBox(height: 2), - Text('当前价: \$${currentPrice.toStringAsFixed(2)}', style: AppTypography.bodySmall), + Text('${context.t('batch_current_price')}: \$${currentPrice.toStringAsFixed(2)}', style: AppTypography.bodySmall), ], ), ), @@ -856,21 +857,21 @@ class _BatchOperationsPageState extends State showDialog( context: context, builder: (ctx) => AlertDialog( - title: const Text('确认批量调价'), + title: Text(context.t('batch_confirm_price')), content: Text( '将对 4 种券批量调价 ${_priceAdjustment > 0 ? '+' : ''}${_priceAdjustment.toStringAsFixed(0)}%,确认执行?', ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), - child: const Text('取消'), + child: Text(context.t('cancel')), ), ElevatedButton( onPressed: () { Navigator.pop(ctx); _startOperation(); }, - child: const Text('确认'), + child: Text(context.t('confirm')), ), ], ), @@ -888,12 +889,12 @@ class _BatchOperationsPageState extends State Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('操作历史', style: AppTypography.h3), + Text(context.t('batch_operation_history'), style: AppTypography.h3), TextButton( onPressed: () { // TODO: Navigate to full operation history page }, - child: const Text('查看全部'), + child: Text(context.t('view_all')), ), ], ), @@ -1011,8 +1012,8 @@ class _BatchOperationsPageState extends State }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('批量操作完成'), + SnackBar( + content: Text(context.t('batch_operation_complete')), backgroundColor: AppColors.success, ), ); diff --git a/frontend/admin-app/lib/features/coupon_management/presentation/pages/coupon_detail_page.dart b/frontend/admin-app/lib/features/coupon_management/presentation/pages/coupon_detail_page.dart index ba5e667..2c73c0c 100644 --- a/frontend/admin-app/lib/features/coupon_management/presentation/pages/coupon_detail_page.dart +++ b/frontend/admin-app/lib/features/coupon_management/presentation/pages/coupon_detail_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 发行方券详情页 /// @@ -12,7 +13,7 @@ class IssuerCouponDetailPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('券详情'), + title: Text(context.t('coupon_detail_title')), actions: [ PopupMenuButton( onSelected: (value) { @@ -20,10 +21,10 @@ class IssuerCouponDetailPage extends StatelessWidget { if (value == 'delist') _showDelistDialog(context); }, itemBuilder: (ctx) => [ - const PopupMenuItem(value: 'edit', child: Text('编辑信息')), - const PopupMenuItem(value: 'reissue', child: Text('增发')), - const PopupMenuItem(value: 'delist', child: Text('下架')), - const PopupMenuItem(value: 'recall', child: Text('召回未售出')), + PopupMenuItem(value: 'edit', child: Text(context.t('coupon_detail_edit'))), + PopupMenuItem(value: 'reissue', child: Text(context.t('coupon_detail_reissue'))), + PopupMenuItem(value: 'delist', child: Text(context.t('coupon_detail_delist'))), + PopupMenuItem(value: 'recall', child: Text(context.t('coupon_detail_recall_unsold'))), ], ), ], @@ -34,30 +35,30 @@ class IssuerCouponDetailPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Card - _buildHeaderCard(), + _buildHeaderCard(context), const SizedBox(height: 20), // Sales Data - _buildSalesDataCard(), + _buildSalesDataCard(context), const SizedBox(height: 20), // Secondary Market Analysis - _buildSecondaryMarketCard(), + _buildSecondaryMarketCard(context), const SizedBox(height: 20), // Financing Effect - _buildFinancingEffectCard(), + _buildFinancingEffectCard(context), const SizedBox(height: 20), // Redemption Timeline - _buildRedemptionTimeline(), + _buildRedemptionTimeline(context), ], ), ), ); } - Widget _buildHeaderCard() { + Widget _buildHeaderCard(BuildContext context) { return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( @@ -81,7 +82,7 @@ class IssuerCouponDetailPage extends StatelessWidget { color: Colors.white.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(999), ), - child: const Text('在售中', style: TextStyle(fontSize: 12, color: Colors.white, fontWeight: FontWeight.w600)), + child: Text(context.t('coupon_detail_status_on_sale'), style: const TextStyle(fontSize: 12, color: Colors.white, fontWeight: FontWeight.w600)), ), ], ), @@ -94,10 +95,10 @@ class IssuerCouponDetailPage extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _buildHeaderStat('发行量', '5,000'), - _buildHeaderStat('已售', '4,200'), - _buildHeaderStat('已核销', '3,300'), - _buildHeaderStat('核销率', '78.5%'), + _buildHeaderStat(context.t('coupon_stat_issued'), '5,000'), + _buildHeaderStat(context.t('coupon_stat_sold'), '4,200'), + _buildHeaderStat(context.t('coupon_stat_redeemed'), '3,300'), + _buildHeaderStat(context.t('coupon_stat_rate'), '78.5%'), ], ), ], @@ -115,7 +116,7 @@ class IssuerCouponDetailPage extends StatelessWidget { ); } - Widget _buildSalesDataCard() { + Widget _buildSalesDataCard(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -126,13 +127,13 @@ class IssuerCouponDetailPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('销售数据', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('coupon_detail_sales_data'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 16), - _buildDataRow('销售收入', '\$89,250'), - _buildDataRow('Breakage收入(过期券)', '\$3,400'), - _buildDataRow('平台手续费', '-\$1,070'), + _buildDataRow(context.t('coupon_detail_sales_income'), '\$89,250'), + _buildDataRow(context.t('coupon_detail_breakage_income'), '\$3,400'), + _buildDataRow(context.t('coupon_detail_platform_fee'), '-\$1,070'), const Divider(height: 24), - _buildDataRow('净收入', '\$91,580', bold: true), + _buildDataRow(context.t('coupon_detail_net_income'), '\$91,580', bold: true), const SizedBox(height: 16), // Chart placeholder Container( @@ -141,14 +142,14 @@ class IssuerCouponDetailPage extends StatelessWidget { color: AppColors.gray50, borderRadius: BorderRadius.circular(8), ), - child: const Center(child: Text('日销量趋势', style: TextStyle(color: AppColors.textTertiary))), + child: Center(child: Text(context.t('coupon_detail_daily_trend'), style: const TextStyle(color: AppColors.textTertiary))), ), ], ), ); } - Widget _buildSecondaryMarketCard() { + Widget _buildSecondaryMarketCard(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -159,13 +160,13 @@ class IssuerCouponDetailPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('二级市场分析', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('coupon_detail_secondary_market'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 16), - _buildDataRow('挂单数', '128'), - _buildDataRow('平均转售价', '\$22.80'), - _buildDataRow('平均折扣率', '91.2%'), - _buildDataRow('转售成交量', '856'), - _buildDataRow('转售成交额', '\$19,517'), + _buildDataRow(context.t('coupon_detail_listing_count'), '128'), + _buildDataRow(context.t('coupon_detail_avg_resale_price'), '\$22.80'), + _buildDataRow(context.t('coupon_detail_avg_discount_rate'), '91.2%'), + _buildDataRow(context.t('coupon_detail_resale_volume'), '856'), + _buildDataRow(context.t('coupon_detail_resale_amount'), '\$19,517'), const SizedBox(height: 16), Container( height: 100, @@ -173,14 +174,14 @@ class IssuerCouponDetailPage extends StatelessWidget { color: AppColors.gray50, borderRadius: BorderRadius.circular(8), ), - child: const Center(child: Text('价格走势K线', style: TextStyle(color: AppColors.textTertiary))), + child: Center(child: Text(context.t('coupon_detail_price_chart'), style: const TextStyle(color: AppColors.textTertiary))), ), ], ), ); } - Widget _buildFinancingEffectCard() { + Widget _buildFinancingEffectCard(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -191,18 +192,18 @@ class IssuerCouponDetailPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('融资效果', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('coupon_detail_financing_effect'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 16), - _buildDataRow('现金提前回笼', '\$89,250'), - _buildDataRow('平均提前回笼天数', '45 天'), - _buildDataRow('融资成本', '\$4,463'), - _buildDataRow('等效年利率', '3.6%'), + _buildDataRow(context.t('coupon_detail_cash_advance'), '\$89,250'), + _buildDataRow(context.t('coupon_detail_avg_advance_days'), '45 天'), + _buildDataRow(context.t('coupon_detail_financing_cost'), '\$4,463'), + _buildDataRow(context.t('coupon_detail_equiv_annual_rate'), '3.6%'), ], ), ); } - Widget _buildRedemptionTimeline() { + Widget _buildRedemptionTimeline(BuildContext context) { final events = [ ('核销 5 张 · 门店A', '10分钟前', AppColors.success), ('核销 2 张 · 门店B', '25分钟前', AppColors.success), @@ -220,7 +221,7 @@ class IssuerCouponDetailPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('最近核销记录', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('coupon_detail_recent_redemptions'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 12), ...events.map((e) { final (desc, time, color) = e; @@ -258,11 +259,11 @@ class IssuerCouponDetailPage extends StatelessWidget { showDialog( context: context, builder: (ctx) => AlertDialog( - title: const Text('召回未售出券'), - content: const Text('确认召回所有未售出的券?此操作不可逆。'), + title: Text(context.t('coupon_detail_recall_title')), + content: Text(context.t('coupon_detail_recall_desc')), actions: [ - TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('取消')), - ElevatedButton(onPressed: () => Navigator.pop(ctx), child: const Text('确认召回')), + TextButton(onPressed: () => Navigator.pop(ctx), child: Text(context.t('cancel'))), + ElevatedButton(onPressed: () => Navigator.pop(ctx), child: Text(context.t('coupon_detail_confirm_recall'))), ], ), ); @@ -272,21 +273,21 @@ class IssuerCouponDetailPage extends StatelessWidget { showDialog( context: context, builder: (ctx) => AlertDialog( - title: const Text('紧急下架'), + title: Text(context.t('coupon_detail_delist_title')), content: Column( mainAxisSize: MainAxisSize.min, children: [ - const Text('确认下架此券?下架后消费者将无法购买。'), + Text(context.t('coupon_detail_delist_desc')), const SizedBox(height: 16), - TextField(decoration: const InputDecoration(labelText: '下架原因')), + TextField(decoration: InputDecoration(labelText: context.t('coupon_detail_delist_reason'))), ], ), actions: [ - TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('取消')), + TextButton(onPressed: () => Navigator.pop(ctx), child: Text(context.t('cancel'))), ElevatedButton( onPressed: () => Navigator.pop(ctx), style: ElevatedButton.styleFrom(backgroundColor: AppColors.error), - child: const Text('确认下架'), + child: Text(context.t('coupon_detail_confirm_delist')), ), ], ), diff --git a/frontend/admin-app/lib/features/coupon_management/presentation/pages/coupon_list_page.dart b/frontend/admin-app/lib/features/coupon_management/presentation/pages/coupon_list_page.dart index 161f3cd..629d2d5 100644 --- a/frontend/admin-app/lib/features/coupon_management/presentation/pages/coupon_list_page.dart +++ b/frontend/admin-app/lib/features/coupon_management/presentation/pages/coupon_list_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/router.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 券管理 - 列表页 /// @@ -13,7 +14,7 @@ class CouponListPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('券管理'), + title: Text(context.t('tab_coupons')), actions: [ IconButton( icon: const Icon(Icons.search_rounded), @@ -35,7 +36,7 @@ class CouponListPage extends StatelessWidget { _buildAiSuggestion(context), // Filter Chips - _buildFilterChips(), + _buildFilterChips(context), // Coupon List Expanded( @@ -55,7 +56,7 @@ class CouponListPage extends StatelessWidget { backgroundColor: AppColors.primary, foregroundColor: Colors.white, icon: const Icon(Icons.add_rounded), - label: const Text('发券'), + label: Text(context.t('coupon_list_fab')), ), ); } @@ -72,10 +73,10 @@ class CouponListPage extends StatelessWidget { children: [ const Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 18), const SizedBox(width: 8), - const Expanded( + Expanded( child: Text( - '建议:周末发行餐饮券销量通常提升30%', - style: TextStyle(fontSize: 12, color: AppColors.primary), + context.t('coupon_list_ai_suggestion'), + style: const TextStyle(fontSize: 12, color: AppColors.primary), ), ), GestureDetector( @@ -89,14 +90,20 @@ class CouponListPage extends StatelessWidget { ); } - Widget _buildFilterChips() { - final filters = ['全部', '在售中', '已售罄', '待审核', '已下架']; + Widget _buildFilterChips(BuildContext context) { + final filters = [ + context.t('all'), + context.t('coupon_filter_on_sale'), + context.t('coupon_filter_sold_out'), + context.t('coupon_filter_pending'), + context.t('coupon_filter_delisted'), + ]; return SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), child: Row( children: filters.map((f) { - final isSelected = f == '全部'; + final isSelected = f == context.t('all'); return Padding( padding: const EdgeInsets.only(right: 8), child: FilterChip( @@ -150,7 +157,7 @@ class CouponListPage extends StatelessWidget { ), const SizedBox(height: 2), Text( - '${coupon.template} · 面值 \$${coupon.faceValue}', + '${coupon.template} · ${context.t('coupon_face_value')} \$${coupon.faceValue}', style: const TextStyle(fontSize: 12, color: AppColors.textSecondary), ), ], @@ -163,10 +170,10 @@ class CouponListPage extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _buildMiniStat('发行量', '${coupon.issued}'), - _buildMiniStat('已售', '${coupon.sold}'), - _buildMiniStat('已核销', '${coupon.redeemed}'), - _buildMiniStat('核销率', '${coupon.redemptionRate}%'), + _buildMiniStat(context.t('coupon_stat_issued'), '${coupon.issued}'), + _buildMiniStat(context.t('coupon_stat_sold'), '${coupon.sold}'), + _buildMiniStat(context.t('coupon_stat_redeemed'), '${coupon.redeemed}'), + _buildMiniStat(context.t('coupon_stat_rate'), '${coupon.redemptionRate}%'), ], ), ], diff --git a/frontend/admin-app/lib/features/coupon_management/presentation/pages/create_coupon_page.dart b/frontend/admin-app/lib/features/coupon_management/presentation/pages/create_coupon_page.dart index efa6e17..c15d7e6 100644 --- a/frontend/admin-app/lib/features/coupon_management/presentation/pages/create_coupon_page.dart +++ b/frontend/admin-app/lib/features/coupon_management/presentation/pages/create_coupon_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 模板化发券页面 /// @@ -29,13 +30,13 @@ class _CreateCouponPageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('发行新券'), + title: Text(context.t('create_coupon_title')), actions: [ TextButton( onPressed: () { Navigator.pop(context); }, - child: const Text('存为草稿'), + child: Text(context.t('create_coupon_save_draft')), ), ], ), @@ -60,7 +61,12 @@ class _CreateCouponPageState extends State { } Widget _buildStepBar() { - final steps = ['选择模板', '基本信息', '规则设置', '预览确认']; + final steps = [ + context.t('create_coupon_step_template'), + context.t('create_coupon_step_info'), + context.t('create_coupon_step_rules'), + context.t('create_coupon_step_preview'), + ]; return Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), child: Row( @@ -107,18 +113,18 @@ class _CreateCouponPageState extends State { Widget _buildTemplateStep() { final templates = [ - ('折扣券', '按比例打折', Icons.percent_rounded, AppColors.error), - ('代金券', '抵扣固定金额', Icons.money_rounded, AppColors.primary), - ('礼品卡', '可充值消费', Icons.card_giftcard_rounded, AppColors.info), - ('储值券', '预存金额消费', Icons.account_balance_wallet_rounded, AppColors.success), + (context.t('create_coupon_tpl_discount'), context.t('create_coupon_tpl_discount_desc'), Icons.percent_rounded, AppColors.error), + (context.t('create_coupon_tpl_voucher'), context.t('create_coupon_tpl_voucher_desc'), Icons.money_rounded, AppColors.primary), + (context.t('create_coupon_tpl_gift'), context.t('create_coupon_tpl_gift_desc'), Icons.card_giftcard_rounded, AppColors.info), + (context.t('create_coupon_tpl_stored'), context.t('create_coupon_tpl_stored_desc'), Icons.account_balance_wallet_rounded, AppColors.success), ]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('选择券模板', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), + Text(context.t('create_coupon_select_template'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 8), - const Text('选择适合您业务场景的券类型', style: TextStyle(color: AppColors.textSecondary)), + Text(context.t('create_coupon_select_template_desc'), style: const TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 24), ...templates.map((t) { final (name, desc, icon, color) = t; @@ -172,23 +178,23 @@ class _CreateCouponPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('基本信息', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), + Text(context.t('create_coupon_step_info'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 24), TextField( controller: _nameController, - decoration: const InputDecoration(labelText: '券名称', hintText: '如:¥25 星巴克礼品卡'), + decoration: InputDecoration(labelText: context.t('create_coupon_name'), hintText: context.t('create_coupon_name_hint')), ), const SizedBox(height: 16), TextField( controller: _faceValueController, keyboardType: TextInputType.number, - decoration: const InputDecoration(labelText: '面值 (\$)', hintText: '输入面值金额'), + decoration: InputDecoration(labelText: context.t('create_coupon_face_value'), hintText: context.t('create_coupon_face_value_hint')), ), const SizedBox(height: 16), TextField( controller: _issuePriceController, keyboardType: TextInputType.number, - decoration: const InputDecoration(labelText: '发行价 (\$)', hintText: '通常低于面值'), + decoration: InputDecoration(labelText: context.t('create_coupon_issue_price'), hintText: context.t('create_coupon_issue_price_hint')), ), // AI Price Suggestion @@ -199,14 +205,14 @@ class _CreateCouponPageState extends State { color: AppColors.primarySurface, borderRadius: BorderRadius.circular(10), ), - child: const Row( + child: Row( children: [ - Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 16), - SizedBox(width: 8), + const Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 16), + const SizedBox(width: 8), Expanded( child: Text( - 'AI建议:面值¥25的礼品卡,最优发行价为¥21.25(8.5折),可最大化销量', - style: TextStyle(fontSize: 12, color: AppColors.primary), + context.t('create_coupon_ai_price_suggestion'), + style: const TextStyle(fontSize: 12, color: AppColors.primary), ), ), ], @@ -217,18 +223,18 @@ class _CreateCouponPageState extends State { TextField( controller: _quantityController, keyboardType: TextInputType.number, - decoration: const InputDecoration(labelText: '发行数量', hintText: '本次发行总量'), + decoration: InputDecoration(labelText: context.t('create_coupon_quantity'), hintText: context.t('create_coupon_quantity_hint')), ), const SizedBox(height: 16), InputDatePickerFormField( firstDate: DateTime.now(), lastDate: DateTime.now().add(const Duration(days: 365)), - fieldLabelText: '有效期截止日(最长12个月)', + fieldLabelText: context.t('create_coupon_expiry'), ), const SizedBox(height: 16), TextField( maxLines: 3, - decoration: const InputDecoration(labelText: '券描述(可选)', hintText: '详细描述使用规则'), + decoration: InputDecoration(labelText: context.t('create_coupon_description'), hintText: context.t('create_coupon_description_hint')), ), ], ); @@ -238,13 +244,13 @@ class _CreateCouponPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('规则设置', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), + Text(context.t('create_coupon_step_rules'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 24), // Transfer settings SwitchListTile( - title: const Text('允许转让'), - subtitle: const Text('消费者可在二级市场转售此券'), + title: Text(context.t('create_coupon_transferable')), + subtitle: Text(context.t('create_coupon_transferable_desc')), value: _transferable, onChanged: (v) => setState(() => _transferable = v), activeColor: AppColors.primary, @@ -254,7 +260,7 @@ class _CreateCouponPageState extends State { const SizedBox(height: 8), Row( children: [ - const Text('最大转售次数', style: TextStyle(fontSize: 14)), + Text(context.t('create_coupon_max_resale'), style: const TextStyle(fontSize: 14)), const Spacer(), IconButton( icon: const Icon(Icons.remove_circle_outline), @@ -271,11 +277,11 @@ class _CreateCouponPageState extends State { const Divider(height: 32), // Refund Policy - const Text('退款策略', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)), + Text(context.t('create_coupon_refund_policy'), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600)), const SizedBox(height: 12), Row( children: [ - const Text('退款窗口(天)', style: TextStyle(fontSize: 14)), + Text(context.t('create_coupon_refund_window'), style: const TextStyle(fontSize: 14)), const Spacer(), IconButton( icon: const Icon(Icons.remove_circle_outline), @@ -289,8 +295,8 @@ class _CreateCouponPageState extends State { ], ), SwitchListTile( - title: const Text('允许自动退款'), - subtitle: const Text('窗口期内用户可直接退款无需审核'), + title: Text(context.t('create_coupon_auto_refund')), + subtitle: Text(context.t('create_coupon_auto_refund_desc')), value: _autoRefund, onChanged: (v) => setState(() => _autoRefund = v), activeColor: AppColors.primary, @@ -300,8 +306,8 @@ class _CreateCouponPageState extends State { // Usage Rules SwitchListTile( - title: const Text('可叠加使用'), - subtitle: const Text('同一订单可使用多张此券'), + title: Text(context.t('create_coupon_stackable')), + subtitle: Text(context.t('create_coupon_stackable_desc')), value: false, onChanged: (_) { // TODO: Toggle stackable usage setting @@ -310,11 +316,11 @@ class _CreateCouponPageState extends State { ), TextField( keyboardType: TextInputType.number, - decoration: const InputDecoration(labelText: '最低消费金额 (\$,可选)'), + decoration: InputDecoration(labelText: context.t('create_coupon_min_purchase')), ), const SizedBox(height: 16), TextField( - decoration: const InputDecoration(labelText: '限定门店(可选)', hintText: '留空则全部门店可用'), + decoration: InputDecoration(labelText: context.t('create_coupon_store_limit'), hintText: context.t('create_coupon_store_limit_hint')), ), ], ); @@ -324,9 +330,9 @@ class _CreateCouponPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('预览确认', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), + Text(context.t('create_coupon_step_preview'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 8), - const Text('请确认以下信息,提交后将进入审核流程', style: TextStyle(color: AppColors.textSecondary)), + Text(context.t('create_coupon_preview_desc'), style: const TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 24), // Preview Card @@ -345,16 +351,16 @@ class _CreateCouponPageState extends State { ), const SizedBox(height: 8), Text( - '模板:${_selectedTemplate ?? '礼品卡'}', + '${context.t('create_coupon_template_label')}${_selectedTemplate ?? context.t('create_coupon_tpl_gift')}', style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: 0.8)), ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _buildPreviewStat('面值', '\$${_faceValueController.text.isNotEmpty ? _faceValueController.text : '25'}'), - _buildPreviewStat('发行价', '\$${_issuePriceController.text.isNotEmpty ? _issuePriceController.text : '21.25'}'), - _buildPreviewStat('数量', _quantityController.text.isNotEmpty ? _quantityController.text : '5000'), + _buildPreviewStat(context.t('create_coupon_face_value_short'), '\$${_faceValueController.text.isNotEmpty ? _faceValueController.text : '25'}'), + _buildPreviewStat(context.t('create_coupon_issue_price_short'), '\$${_issuePriceController.text.isNotEmpty ? _issuePriceController.text : '21.25'}'), + _buildPreviewStat(context.t('create_coupon_quantity_short'), _quantityController.text.isNotEmpty ? _quantityController.text : '5000'), ], ), ], @@ -363,9 +369,9 @@ class _CreateCouponPageState extends State { const SizedBox(height: 20), // Details List - _buildDetailRow('可转让', _transferable ? '是(最多${_maxResaleCount}次)' : '否'), - _buildDetailRow('退款窗口', '$_refundWindowDays 天'), - _buildDetailRow('自动退款', _autoRefund ? '是' : '否'), + _buildDetailRow(context.t('create_coupon_transferable'), _transferable ? '${context.t('yes')}(${context.t('create_coupon_max_times')}${_maxResaleCount}${context.t('create_coupon_times')})' : context.t('no')), + _buildDetailRow(context.t('create_coupon_refund_window'), '$_refundWindowDays ${context.t('create_coupon_day_unit')}'), + _buildDetailRow(context.t('create_coupon_auto_refund'), _autoRefund ? context.t('yes') : context.t('no')), const SizedBox(height: 20), Container( @@ -374,14 +380,14 @@ class _CreateCouponPageState extends State { color: AppColors.infoLight, borderRadius: BorderRadius.circular(10), ), - child: const Row( + child: Row( children: [ - Icon(Icons.info_outline_rounded, color: AppColors.info, size: 18), - SizedBox(width: 8), + const Icon(Icons.info_outline_rounded, color: AppColors.info, size: 18), + const SizedBox(width: 8), Expanded( child: Text( - '提交后将自动进入平台审核,审核通过后券将自动上架销售', - style: TextStyle(fontSize: 12, color: AppColors.info), + context.t('create_coupon_review_notice'), + style: const TextStyle(fontSize: 12, color: AppColors.info), ), ), ], @@ -427,7 +433,7 @@ class _CreateCouponPageState extends State { Expanded( child: OutlinedButton( onPressed: () => setState(() => _currentStep--), - child: const Text('上一步'), + child: Text(context.t('prev_step')), ), ), if (_currentStep > 0) const SizedBox(width: 12), @@ -440,7 +446,7 @@ class _CreateCouponPageState extends State { _submitForReview(); } }, - child: Text(_currentStep < 3 ? '下一步' : '提交审核'), + child: Text(_currentStep < 3 ? context.t('next') : context.t('onboarding_submit_review')), ), ), ], @@ -452,15 +458,15 @@ class _CreateCouponPageState extends State { showDialog( context: context, builder: (ctx) => AlertDialog( - title: const Text('提交成功'), - content: const Text('您的券已提交审核,预计1-2个工作日内完成。'), + title: Text(context.t('create_coupon_submit_success')), + content: Text(context.t('create_coupon_submit_desc')), actions: [ TextButton( onPressed: () { Navigator.of(ctx).pop(); Navigator.of(context).pop(); }, - child: const Text('确定'), + child: Text(context.t('confirm')), ), ], ), diff --git a/frontend/admin-app/lib/features/credit/presentation/pages/credit_page.dart b/frontend/admin-app/lib/features/credit/presentation/pages/credit_page.dart index 19c2dc0..d69f9ae 100644 --- a/frontend/admin-app/lib/features/credit/presentation/pages/credit_page.dart +++ b/frontend/admin-app/lib/features/credit/presentation/pages/credit_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 信用评级页面 /// @@ -11,36 +12,36 @@ class CreditPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('信用评级')), + appBar: AppBar(title: Text(context.t('credit_title'))), body: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( children: [ // Score Gauge - _buildScoreGauge(), + _buildScoreGauge(context), const SizedBox(height: 24), // Four Factors - _buildFactorsCard(), + _buildFactorsCard(context), const SizedBox(height: 20), // Tier Progress - _buildTierProgress(), + _buildTierProgress(context), const SizedBox(height: 20), // AI Suggestions - _buildAiSuggestions(), + _buildAiSuggestions(context), const SizedBox(height: 20), // Credit History - _buildCreditHistory(), + _buildCreditHistory(context), ], ), ), ); } - Widget _buildScoreGauge() { + Widget _buildScoreGauge(BuildContext context) { return Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( @@ -72,20 +73,20 @@ class CreditPage extends StatelessWidget { ), ), const SizedBox(height: 16), - const Text('信用等级 AA', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600)), + Text(context.t('credit_score_label'), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600)), const SizedBox(height: 4), - const Text('距离 AAA 等级还差 8 分', style: TextStyle(fontSize: 13, color: AppColors.textSecondary)), + Text(context.t('credit_gap_label'), style: const TextStyle(fontSize: 13, color: AppColors.textSecondary)), ], ), ); } - Widget _buildFactorsCard() { + Widget _buildFactorsCard(BuildContext context) { final factors = [ - ('核销率', 0.85, 0.35, AppColors.success), - ('沉淀控制', 0.72, 0.25, AppColors.info), - ('市场存续', 0.90, 0.20, AppColors.primary), - ('用户满意度', 0.78, 0.20, AppColors.warning), + (context.t('credit_factor_redemption'), 0.85, 0.35, AppColors.success), + (context.t('credit_factor_breakage'), 0.72, 0.25, AppColors.info), + (context.t('credit_factor_market'), 0.90, 0.20, AppColors.primary), + (context.t('credit_factor_satisfaction'), 0.78, 0.20, AppColors.warning), ]; return Container( @@ -98,7 +99,7 @@ class CreditPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('评分因子', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('credit_factors'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 16), ...factors.map((f) { final (label, score, weight, color) = f; @@ -135,12 +136,12 @@ class CreditPage extends StatelessWidget { ); } - Widget _buildTierProgress() { + Widget _buildTierProgress(BuildContext context) { final tiers = [ - ('白银', AppColors.tierSilver, true), - ('黄金', AppColors.tierGold, true), - ('铂金', AppColors.tierPlatinum, false), - ('钻石', AppColors.tierDiamond, false), + (context.t('credit_tier_silver'), AppColors.tierSilver, true), + (context.t('credit_tier_gold'), AppColors.tierGold, true), + (context.t('credit_tier_platinum'), AppColors.tierPlatinum, false), + (context.t('credit_tier_diamond'), AppColors.tierDiamond, false), ]; return Container( @@ -153,7 +154,7 @@ class CreditPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('发行方层级', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('credit_tier_title'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, @@ -189,16 +190,16 @@ class CreditPage extends StatelessWidget { }).toList(), ), const SizedBox(height: 12), - const Text( - '当前:黄金 → 铂金需月发行量达500万', - style: TextStyle(fontSize: 12, color: AppColors.textSecondary), + Text( + context.t('credit_tier_progress'), + style: const TextStyle(fontSize: 12, color: AppColors.textSecondary), ), ], ), ); } - Widget _buildAiSuggestions() { + Widget _buildAiSuggestions(BuildContext context) { final suggestions = [ ('提升核销率', '建议在周末推出限时核销活动,预计可提升核销率5%', Icons.trending_up_rounded), ('降低Breakage', '当前有12%的券过期未用,建议到期前7天推送提醒', Icons.notification_important_rounded), @@ -208,11 +209,11 @@ class CreditPage extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Row( + Row( children: [ - Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), - SizedBox(width: 8), - Text('AI 信用提升建议', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + const Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), + const SizedBox(width: 8), + Text(context.t('credit_ai_title'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), ], ), const SizedBox(height: 12), @@ -247,7 +248,7 @@ class CreditPage extends StatelessWidget { ); } - Widget _buildCreditHistory() { + Widget _buildCreditHistory(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -258,7 +259,7 @@ class CreditPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('信用变动记录', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('credit_history_title'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 12), _buildHistoryItem('信用分 +3', '核销率提升至85%', '2天前', AppColors.success), _buildHistoryItem('信用分 -1', 'Breakage率微升', '1周前', AppColors.error), diff --git a/frontend/admin-app/lib/features/credit/presentation/pages/quota_management_page.dart b/frontend/admin-app/lib/features/credit/presentation/pages/quota_management_page.dart index e5dd79a..4c9a26c 100644 --- a/frontend/admin-app/lib/features/credit/presentation/pages/quota_management_page.dart +++ b/frontend/admin-app/lib/features/credit/presentation/pages/quota_management_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 发行方配额管理页面 /// @@ -16,20 +17,20 @@ class QuotaManagementPage extends StatefulWidget { } class _QuotaManagementPageState extends State { - String _selectedPeriod = '本月'; + String _selectedPeriod = 'quota_period_month'; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('配额管理'), + title: Text(context.t('quota_title')), actions: [ TextButton.icon( onPressed: () { // TODO: Show quota increase application dialog }, icon: const Icon(Icons.add_circle_outline_rounded, size: 18), - label: const Text('申请提额'), + label: Text(context.t('quota_apply_increase')), ), ], ), @@ -78,9 +79,9 @@ class _QuotaManagementPageState extends State { children: [ const Icon(Icons.pie_chart_rounded, color: Colors.white, size: 22), const SizedBox(width: 10), - const Text( - '当前配额', - style: TextStyle(fontSize: 17, fontWeight: FontWeight.w700, color: Colors.white), + Text( + context.t('quota_current'), + style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w700, color: Colors.white), ), const Spacer(), Container( @@ -89,8 +90,8 @@ class _QuotaManagementPageState extends State { color: Colors.white.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(999), ), - child: const Text( - '黄金层级', + child: Text( + context.t('quota_gold_tier'), style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Colors.white), ), ), @@ -122,7 +123,7 @@ class _QuotaManagementPageState extends State { style: TextStyle(fontSize: 28, fontWeight: FontWeight.w700, color: Colors.white), ), Text( - '已使用', + context.t('quota_used'), style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: 0.7)), ), ], @@ -134,9 +135,9 @@ class _QuotaManagementPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - _buildQuotaStat('月发行限额', '\$5,000,000'), - _buildQuotaStat('已使用', '\$3,100,000'), - _buildQuotaStat('剩余', '\$1,900,000'), + _buildQuotaStat(context.t('quota_monthly_limit'), '\$5,000,000'), + _buildQuotaStat(context.t('quota_used'), '\$3,100,000'), + _buildQuotaStat(context.t('quota_remaining'), '\$1,900,000'), ], ), ], @@ -178,7 +179,7 @@ class _QuotaManagementPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('配额分配明细', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('quota_breakdown'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 16), ...quotaTypes.map((q) { final (name, used, total, color) = q; @@ -217,21 +218,21 @@ class _QuotaManagementPageState extends State { } Widget _buildPeriodSelector() { - final periods = ['本月', '本季', '本年']; + final periodKeys = ['quota_period_month', 'quota_period_quarter', 'quota_period_year']; return Row( children: [ - const Text('使用记录', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('quota_usage_records'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const Spacer(), - ...periods.map((p) => Padding( + ...periodKeys.map((key) => Padding( padding: const EdgeInsets.only(left: 6), child: ChoiceChip( - label: Text(p, style: const TextStyle(fontSize: 12)), - selected: _selectedPeriod == p, - onSelected: (_) => setState(() => _selectedPeriod = p), + label: Text(context.t(key), style: const TextStyle(fontSize: 12)), + selected: _selectedPeriod == key, + onSelected: (_) => setState(() => _selectedPeriod = key), selectedColor: AppColors.primaryContainer, labelStyle: TextStyle( - color: _selectedPeriod == p ? AppColors.primary : AppColors.textSecondary, - fontWeight: _selectedPeriod == p ? FontWeight.w600 : FontWeight.w400, + color: _selectedPeriod == key ? AppColors.primary : AppColors.textSecondary, + fontWeight: _selectedPeriod == key ? FontWeight.w600 : FontWeight.w400, ), ), )), @@ -303,7 +304,7 @@ class _QuotaManagementPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('层级与配额', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('quota_tier_and_quota'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 16), ...tiers.map((t) { final (nameEn, nameCn, quota, reached, color) = t; @@ -346,13 +347,13 @@ class _QuotaManagementPageState extends State { color: color, borderRadius: BorderRadius.circular(999), ), - child: const Text('当前', style: TextStyle(fontSize: 9, color: Colors.white, fontWeight: FontWeight.w700)), + child: Text(context.t('quota_current_badge'), style: const TextStyle(fontSize: 9, color: Colors.white, fontWeight: FontWeight.w700)), ), ], ], ), Text( - '月发行配额: $quota', + '${context.t('quota_monthly_quota')}: $quota', style: const TextStyle(fontSize: 11, color: AppColors.textSecondary), ), ], @@ -373,14 +374,14 @@ class _QuotaManagementPageState extends State { color: AppColors.primarySurface, borderRadius: BorderRadius.circular(8), ), - child: const Row( + child: Row( children: [ - Icon(Icons.trending_up_rounded, color: AppColors.primary, size: 18), - SizedBox(width: 8), + const Icon(Icons.trending_up_rounded, color: AppColors.primary, size: 18), + const SizedBox(width: 8), Expanded( child: Text( - '距铂金升级: 信用分达90+ 且 月发行量连续3月 ≥\$10M', - style: TextStyle(fontSize: 12, color: AppColors.primary), + context.t('quota_upgrade_hint'), + style: const TextStyle(fontSize: 12, color: AppColors.primary), ), ), ], @@ -402,11 +403,11 @@ class _QuotaManagementPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('提额申请记录', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('quota_request_title'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 12), - _buildRequestItem('REQ-001', '临时提额: +\$2M', '2026-02-05', '审核中', AppColors.warning), - _buildRequestItem('REQ-002', '长期提额: Gold→Platinum', '2026-01-20', '已驳回', AppColors.error), - _buildRequestItem('REQ-003', '临时提额: +\$500K (春节活动)', '2026-01-15', '已批准', AppColors.success), + _buildRequestItem('REQ-001', '临时提额: +\$2M', '2026-02-05', context.t('quota_request_reviewing'), AppColors.warning), + _buildRequestItem('REQ-002', '长期提额: Gold→Platinum', '2026-01-20', context.t('quota_request_rejected'), AppColors.error), + _buildRequestItem('REQ-003', '临时提额: +\$500K (春节活动)', '2026-01-15', context.t('quota_request_approved'), AppColors.success), const SizedBox(height: 12), SizedBox( width: double.infinity, @@ -415,7 +416,7 @@ class _QuotaManagementPageState extends State { // TODO: Show new quota increase application dialog }, icon: const Icon(Icons.add_rounded, size: 18), - label: const Text('提交新申请'), + label: Text(context.t('quota_submit_new')), ), ), ], diff --git a/frontend/admin-app/lib/features/dashboard/presentation/pages/issuer_dashboard_page.dart b/frontend/admin-app/lib/features/dashboard/presentation/pages/issuer_dashboard_page.dart index 933d981..a8247c1 100644 --- a/frontend/admin-app/lib/features/dashboard/presentation/pages/issuer_dashboard_page.dart +++ b/frontend/admin-app/lib/features/dashboard/presentation/pages/issuer_dashboard_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/router.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 发行方数据仪表盘 /// @@ -13,7 +14,7 @@ class IssuerDashboardPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('数据概览'), + title: Text(context.t('tab_dashboard')), actions: [ IconButton( icon: const Icon(Icons.notifications_outlined), @@ -29,11 +30,11 @@ class IssuerDashboardPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ // Issuer Info Card - _buildIssuerInfoCard(), + _buildIssuerInfoCard(context), const SizedBox(height: 20), // Stats Grid (2x2) - _buildStatsGrid(), + _buildStatsGrid(context), const SizedBox(height: 20), // AI Insight Card @@ -45,18 +46,18 @@ class IssuerDashboardPage extends StatelessWidget { const SizedBox(height: 20), // Sales Trend Chart Placeholder - _buildSalesTrendCard(), + _buildSalesTrendCard(context), const SizedBox(height: 20), // Recent Activity - _buildRecentActivity(), + _buildRecentActivity(context), ], ), ), ); } - Widget _buildIssuerInfoCard() { + Widget _buildIssuerInfoCard(BuildContext context) { return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( @@ -90,9 +91,9 @@ class IssuerDashboardPage extends StatelessWidget { color: AppColors.tierGold.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(999), ), - child: const Text( - '黄金发行方', - style: TextStyle(fontSize: 11, color: Colors.white, fontWeight: FontWeight.w600), + child: Text( + context.t('dashboard_gold_issuer'), + style: const TextStyle(fontSize: 11, color: Colors.white, fontWeight: FontWeight.w600), ), ), ], @@ -104,12 +105,12 @@ class IssuerDashboardPage extends StatelessWidget { ); } - Widget _buildStatsGrid() { + Widget _buildStatsGrid(BuildContext context) { final stats = [ - ('总发行量', '12,580', Icons.confirmation_number_rounded, AppColors.primary), - ('核销率', '78.5%', Icons.check_circle_rounded, AppColors.success), - ('销售收入', '\$125,800', Icons.attach_money_rounded, AppColors.info), - ('可提现', '\$42,300', Icons.account_balance_wallet_rounded, AppColors.warning), + (context.t('dashboard_total_issued'), '12,580', Icons.confirmation_number_rounded, AppColors.primary), + (context.t('dashboard_redemption_rate'), '78.5%', Icons.check_circle_rounded, AppColors.success), + (context.t('dashboard_sales_revenue'), '\$125,800', Icons.attach_money_rounded, AppColors.info), + (context.t('dashboard_withdrawable'), '\$42,300', Icons.account_balance_wallet_rounded, AppColors.warning), ]; return GridView.builder( @@ -164,17 +165,17 @@ class IssuerDashboardPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Row( + Row( children: [ - Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), - SizedBox(width: 8), - Text('AI 洞察', style: TextStyle(fontSize: 14, color: AppColors.primary, fontWeight: FontWeight.w600)), + const Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), + const SizedBox(width: 8), + Text(context.t('dashboard_ai_insight'), style: const TextStyle(fontSize: 14, color: AppColors.primary, fontWeight: FontWeight.w600)), ], ), const SizedBox(height: 10), - const Text( - '您的 ¥25 礼品卡核销率达到 92%,远高于同类平均。建议增发 500 张以满足市场需求。', - style: TextStyle(fontSize: 13, color: AppColors.textSecondary, height: 1.5), + Text( + context.t('dashboard_ai_insight_content'), + style: const TextStyle(fontSize: 13, color: AppColors.textSecondary, height: 1.5), ), const SizedBox(height: 12), Row( @@ -187,7 +188,7 @@ class IssuerDashboardPage extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), minimumSize: Size.zero, ), - child: const Text('忽略', style: TextStyle(fontSize: 13)), + child: Text(context.t('dashboard_dismiss'), style: const TextStyle(fontSize: 13)), ), const SizedBox(width: 8), ElevatedButton( @@ -198,7 +199,7 @@ class IssuerDashboardPage extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), minimumSize: Size.zero, ), - child: const Text('采纳建议', style: TextStyle(fontSize: 13)), + child: Text(context.t('dashboard_accept'), style: const TextStyle(fontSize: 13)), ), ], ), @@ -232,12 +233,12 @@ class IssuerDashboardPage extends StatelessWidget { ), ), const SizedBox(width: 12), - const Expanded( + Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('信用等级 AA', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), - Text('距离 AAA 还差 12 分', style: TextStyle(fontSize: 12, color: AppColors.textTertiary)), + Text(context.t('dashboard_credit_rating'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('dashboard_credit_gap'), style: const TextStyle(fontSize: 12, color: AppColors.textTertiary)), ], ), ), @@ -245,7 +246,7 @@ class IssuerDashboardPage extends StatelessWidget { onPressed: () { Navigator.pushNamed(context, AppRouter.credit); }, - child: const Text('提升建议'), + child: Text(context.t('dashboard_improve_suggestion')), ), ], ), @@ -254,11 +255,11 @@ class IssuerDashboardPage extends StatelessWidget { const SizedBox(height: 16), // Quota Progress - const Row( + Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('发行额度', style: TextStyle(fontSize: 13, color: AppColors.textSecondary)), - Text('\$380,000 / \$500,000', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600)), + Text(context.t('dashboard_issue_quota'), style: const TextStyle(fontSize: 13, color: AppColors.textSecondary)), + const Text('\$380,000 / \$500,000', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600)), ], ), const SizedBox(height: 8), @@ -272,16 +273,16 @@ class IssuerDashboardPage extends StatelessWidget { ), ), const SizedBox(height: 4), - const Align( + Align( alignment: Alignment.centerRight, - child: Text('已用 76%', style: TextStyle(fontSize: 11, color: AppColors.textTertiary)), + child: Text(context.t('dashboard_used_percent'), style: const TextStyle(fontSize: 11, color: AppColors.textTertiary)), ), ], ), ); } - Widget _buildSalesTrendCard() { + Widget _buildSalesTrendCard(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -292,11 +293,11 @@ class IssuerDashboardPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Row( + Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('销售趋势', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), - Text('近7天', style: TextStyle(fontSize: 12, color: AppColors.primary)), + Text(context.t('dashboard_sales_trend'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('dashboard_last_7_days'), style: const TextStyle(fontSize: 12, color: AppColors.primary)), ], ), const SizedBox(height: 16), @@ -307,8 +308,8 @@ class IssuerDashboardPage extends StatelessWidget { color: AppColors.gray50, borderRadius: BorderRadius.circular(8), ), - child: const Center( - child: Text('销售趋势图表', style: TextStyle(color: AppColors.textTertiary)), + child: Center( + child: Text(context.t('dashboard_sales_chart'), style: const TextStyle(color: AppColors.textTertiary)), ), ), ], @@ -316,7 +317,7 @@ class IssuerDashboardPage extends StatelessWidget { ); } - Widget _buildRecentActivity() { + Widget _buildRecentActivity(BuildContext context) { final activities = [ ('¥25 礼品卡', '售出 15 张', '2分钟前', AppColors.success), ('¥100 购物券', '核销 8 张', '15分钟前', AppColors.info), @@ -333,7 +334,7 @@ class IssuerDashboardPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('最近动态', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('dashboard_recent_activity'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 12), ...activities.map((a) { final (title, desc, time, color) = a; diff --git a/frontend/admin-app/lib/features/dashboard/presentation/pages/user_portrait_page.dart b/frontend/admin-app/lib/features/dashboard/presentation/pages/user_portrait_page.dart index 0d7181d..8157623 100644 --- a/frontend/admin-app/lib/features/dashboard/presentation/pages/user_portrait_page.dart +++ b/frontend/admin-app/lib/features/dashboard/presentation/pages/user_portrait_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 用户画像分析页面(发行方管理后台) /// @@ -17,14 +18,14 @@ class UserPortraitPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('用户画像'), + title: Text(context.t('user_portrait_title')), actions: [ TextButton.icon( onPressed: () { // TODO: Export user portrait data }, icon: const Icon(Icons.file_download_outlined, size: 18), - label: const Text('导出'), + label: Text(context.t('export')), ), ], ), @@ -34,39 +35,39 @@ class UserPortraitPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ // User Stats Summary - _buildUserStatsSummary(), + _buildUserStatsSummary(context), const SizedBox(height: 20), // Age Distribution - _buildAgeDistribution(), + _buildAgeDistribution(context), const SizedBox(height: 20), // Geographic Distribution - _buildGeoDistribution(), + _buildGeoDistribution(context), const SizedBox(height: 20), // Purchase Preference - _buildPurchasePreference(), + _buildPurchasePreference(context), const SizedBox(height: 20), // Repurchase Analysis - _buildRepurchaseAnalysis(), + _buildRepurchaseAnalysis(context), const SizedBox(height: 20), // AI Insight - _buildAiInsight(), + _buildAiInsight(context), ], ), ), ); } - Widget _buildUserStatsSummary() { + Widget _buildUserStatsSummary(BuildContext context) { final stats = [ - ('总购买用户', '12,456', Icons.people_alt_rounded, AppColors.primary), - ('月活用户', '3,281', Icons.trending_up_rounded, AppColors.success), - ('平均客单价', '\$23.5', Icons.attach_money_rounded, AppColors.info), - ('复购率', '34.2%', Icons.replay_rounded, AppColors.warning), + (context.t('user_portrait_total_buyers'), '12,456', Icons.people_alt_rounded, AppColors.primary), + (context.t('user_portrait_mau'), '3,281', Icons.trending_up_rounded, AppColors.success), + (context.t('user_portrait_avg_price'), '\$23.5', Icons.attach_money_rounded, AppColors.info), + (context.t('user_portrait_repurchase_rate'), '34.2%', Icons.replay_rounded, AppColors.warning), ]; return Row( @@ -107,7 +108,7 @@ class UserPortraitPage extends StatelessWidget { ); } - Widget _buildAgeDistribution() { + Widget _buildAgeDistribution(BuildContext context) { final ages = [ ('18-24', 0.15, '15%'), ('25-34', 0.38, '38%'), @@ -118,7 +119,7 @@ class UserPortraitPage extends StatelessWidget { return _card( icon: Icons.cake_rounded, - title: '年龄分布', + title: context.t('user_portrait_age_dist'), child: Column( children: ages.map((a) { final (range, pct, label) = a; @@ -164,7 +165,7 @@ class UserPortraitPage extends StatelessWidget { ); } - Widget _buildGeoDistribution() { + Widget _buildGeoDistribution(BuildContext context) { final regions = [ ('加利福尼亚', 2845, AppColors.primary), ('纽约', 2134, AppColors.info), @@ -177,7 +178,7 @@ class UserPortraitPage extends StatelessWidget { return _card( icon: Icons.location_on_rounded, - title: '地域分布 (Top 5)', + title: context.t('user_portrait_geo_dist'), child: Column( children: regions.map((r) { final (name, count, color) = r; @@ -229,18 +230,18 @@ class UserPortraitPage extends StatelessWidget { ); } - Widget _buildPurchasePreference() { + Widget _buildPurchasePreference(BuildContext context) { final categories = [ - ('餐饮', 42, AppColors.couponDining, Icons.restaurant_rounded), - ('购物', 28, AppColors.couponShopping, Icons.shopping_bag_rounded), - ('娱乐', 15, AppColors.couponEntertainment, Icons.movie_rounded), - ('旅行', 10, AppColors.couponTravel, Icons.flight_rounded), - ('其他', 5, AppColors.couponOther, Icons.more_horiz_rounded), + (context.t('user_portrait_dining'), 42, AppColors.couponDining, Icons.restaurant_rounded), + (context.t('user_portrait_shopping'), 28, AppColors.couponShopping, Icons.shopping_bag_rounded), + (context.t('user_portrait_entertainment'), 15, AppColors.couponEntertainment, Icons.movie_rounded), + (context.t('user_portrait_travel'), 10, AppColors.couponTravel, Icons.flight_rounded), + (context.t('user_portrait_other'), 5, AppColors.couponOther, Icons.more_horiz_rounded), ]; return _card( icon: Icons.favorite_rounded, - title: '消费偏好', + title: context.t('user_portrait_preference'), child: Wrap( spacing: 10, runSpacing: 10, @@ -291,18 +292,18 @@ class UserPortraitPage extends StatelessWidget { ); } - Widget _buildRepurchaseAnalysis() { + Widget _buildRepurchaseAnalysis(BuildContext context) { final cohorts = [ - ('首次购买', 12456, '100%', AppColors.gray400), - ('2次购买', 4260, '34.2%', AppColors.primaryLight), - ('3-5次', 2134, '17.1%', AppColors.primary), - ('6-10次', 856, '6.9%', AppColors.primaryDark), - ('10次以上', 312, '2.5%', AppColors.primaryDark), + (context.t('user_portrait_first_purchase'), 12456, '100%', AppColors.gray400), + (context.t('user_portrait_2nd_purchase'), 4260, '34.2%', AppColors.primaryLight), + (context.t('user_portrait_3_5_purchase'), 2134, '17.1%', AppColors.primary), + (context.t('user_portrait_6_10_purchase'), 856, '6.9%', AppColors.primaryDark), + (context.t('user_portrait_10_plus_purchase'), 312, '2.5%', AppColors.primaryDark), ]; return _card( icon: Icons.replay_circle_filled_rounded, - title: '复购漏斗', + title: context.t('user_portrait_repurchase_funnel'), child: Column( children: cohorts.asMap().entries.map((entry) { final i = entry.key; @@ -348,12 +349,12 @@ class UserPortraitPage extends StatelessWidget { ); } - Widget _buildAiInsight() { + Widget _buildAiInsight(BuildContext context) { final insights = [ - ('核心用户群体', '25-34岁加利福尼亚用户,偏好餐饮类券,客单价\$28.5,高于整体均值21%'), - ('复购提升建议', '针对首次购买用户,7天内推送同品牌关联券可将复购率提升至42%'), - ('地域扩展机会', '德州、佛州用户增长率最快(+35% MoM),建议增加当地品牌合作'), - ('流失预警', '30天未活跃用户占比18%,建议发放专属回归优惠券'), + (context.t('user_portrait_core_users'), context.t('user_portrait_core_users_desc')), + (context.t('user_portrait_repurchase_advice'), context.t('user_portrait_repurchase_advice_desc')), + (context.t('user_portrait_geo_opportunity'), context.t('user_portrait_geo_opportunity_desc')), + (context.t('user_portrait_churn_warning'), context.t('user_portrait_churn_warning_desc')), ]; return Container( @@ -379,8 +380,8 @@ class UserPortraitPage extends StatelessWidget { Text('✨', style: TextStyle(fontSize: 14))), ), const SizedBox(width: 10), - const Text('AI 用户洞察', - style: TextStyle( + Text(context.t('user_portrait_ai_insight'), + style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w600)), ], ), diff --git a/frontend/admin-app/lib/features/finance/presentation/pages/finance_page.dart b/frontend/admin-app/lib/features/finance/presentation/pages/finance_page.dart index 4a658a4..c0d91ef 100644 --- a/frontend/admin-app/lib/features/finance/presentation/pages/finance_page.dart +++ b/frontend/admin-app/lib/features/finance/presentation/pages/finance_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/router.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 财务管理页面 /// @@ -15,18 +16,18 @@ class FinancePage extends StatelessWidget { length: 3, child: Scaffold( appBar: AppBar( - title: const Text('财务管理'), + title: Text(context.t('finance_title')), actions: [ IconButton( icon: const Icon(Icons.download_rounded), onPressed: () => _showExportDialog(context), ), ], - bottom: const TabBar( + bottom: TabBar( tabs: [ - Tab(text: '概览'), - Tab(text: '交易明细'), - Tab(text: '对账报表'), + Tab(text: context.t('finance_tab_overview')), + Tab(text: context.t('finance_tab_transactions')), + Tab(text: context.t('finance_tab_reconciliation')), ], ), ), @@ -45,11 +46,11 @@ class FinancePage extends StatelessWidget { showDialog( context: context, builder: (ctx) => SimpleDialog( - title: const Text('导出数据'), + title: Text(context.t('finance_export_title')), children: [ - SimpleDialogOption(onPressed: () => Navigator.pop(ctx), child: const Text('导出 CSV')), - SimpleDialogOption(onPressed: () => Navigator.pop(ctx), child: const Text('导出 Excel')), - SimpleDialogOption(onPressed: () => Navigator.pop(ctx), child: const Text('导出 PDF')), + SimpleDialogOption(onPressed: () => Navigator.pop(ctx), child: Text(context.t('finance_export_csv'))), + SimpleDialogOption(onPressed: () => Navigator.pop(ctx), child: Text(context.t('finance_export_excel'))), + SimpleDialogOption(onPressed: () => Navigator.pop(ctx), child: Text(context.t('finance_export_pdf'))), ], ), ); @@ -75,7 +76,7 @@ class _OverviewTab extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('可提现余额', style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: 0.7))), + Text(context.t('finance_withdrawable'), style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: 0.7))), const SizedBox(height: 4), const Text('\$42,300.00', style: TextStyle(fontSize: 32, fontWeight: FontWeight.w700, color: Colors.white)), const SizedBox(height: 16), @@ -89,7 +90,7 @@ class _OverviewTab extends StatelessWidget { backgroundColor: Colors.white, foregroundColor: AppColors.primary, ), - child: const Text('提现'), + child: Text(context.t('finance_withdraw')), ), ), ], @@ -98,11 +99,11 @@ class _OverviewTab extends StatelessWidget { const SizedBox(height: 20), // Financial Stats - _buildFinanceStatsGrid(), + _buildFinanceStatsGrid(context), const SizedBox(height: 20), // Guarantee Fund - _buildGuaranteeFundCard(), + _buildGuaranteeFundCard(context), const SizedBox(height: 20), // Revenue Trend @@ -116,7 +117,7 @@ class _OverviewTab extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('收入趋势', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + Text(context.t('finance_revenue_trend'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 16), Container( height: 160, @@ -124,7 +125,7 @@ class _OverviewTab extends StatelessWidget { color: AppColors.gray50, borderRadius: BorderRadius.circular(8), ), - child: const Center(child: Text('月度收入趋势图', style: TextStyle(color: AppColors.textTertiary))), + child: Center(child: Text(context.t('finance_revenue_chart'), style: const TextStyle(color: AppColors.textTertiary))), ), ], ), @@ -134,14 +135,14 @@ class _OverviewTab extends StatelessWidget { ); } - Widget _buildFinanceStatsGrid() { + Widget _buildFinanceStatsGrid(BuildContext context) { final stats = [ - ('销售收入', '\$125,800', AppColors.success), - ('Breakage收入', '\$8,200', AppColors.info), - ('平台手续费', '-\$1,510', AppColors.error), - ('待结算', '\$15,400', AppColors.warning), - ('已提现', '\$66,790', AppColors.textSecondary), - ('总收入', '\$132,490', AppColors.primary), + (context.t('finance_sales_income'), '\$125,800', AppColors.success), + (context.t('finance_breakage_income'), '\$8,200', AppColors.info), + (context.t('finance_platform_fee'), '-\$1,510', AppColors.error), + (context.t('finance_pending_settlement'), '\$15,400', AppColors.warning), + (context.t('finance_withdrawn'), '\$66,790', AppColors.textSecondary), + (context.t('finance_total_income'), '\$132,490', AppColors.primary), ]; return GridView.builder( @@ -176,7 +177,7 @@ class _OverviewTab extends StatelessWidget { ); } - Widget _buildGuaranteeFundCard() { + Widget _buildGuaranteeFundCard(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -187,21 +188,21 @@ class _OverviewTab extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Row( + Row( children: [ - Icon(Icons.shield_rounded, color: AppColors.info, size: 20), - SizedBox(width: 8), - Text('保证金与冻结款', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + const Icon(Icons.shield_rounded, color: AppColors.info, size: 20), + const SizedBox(width: 8), + Text(context.t('finance_guarantee_title'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), ], ), const SizedBox(height: 16), - _buildRow('已缴纳保证金', '\$10,000'), - _buildRow('冻结销售款', '\$5,200'), - _buildRow('冻结比例', '20%'), + _buildRow(context.t('finance_guarantee_deposit'), '\$10,000'), + _buildRow(context.t('finance_frozen_sales'), '\$5,200'), + _buildRow(context.t('finance_frozen_ratio'), '20%'), const SizedBox(height: 12), SwitchListTile( - title: const Text('自动冻结销售款', style: TextStyle(fontSize: 14)), - subtitle: const Text('开启后自动冻结20%销售额以提升信用'), + title: Text(context.t('finance_auto_freeze'), style: const TextStyle(fontSize: 14)), + subtitle: Text(context.t('finance_auto_freeze_desc')), value: true, onChanged: (_) { // TODO: Toggle auto-freeze setting @@ -282,7 +283,7 @@ class _ReconciliationTab extends StatelessWidget { // TODO: Trigger reconciliation report generation }, icon: const Icon(Icons.add_rounded), - label: const Text('生成新对账单'), + label: Text(context.t('finance_generate_report')), style: OutlinedButton.styleFrom( minimumSize: const Size(double.infinity, 48), ), @@ -326,14 +327,14 @@ class _ReconciliationTab extends StatelessWidget { // TODO: Navigate to reconciliation detail view }, icon: const Icon(Icons.visibility_rounded, size: 16), - label: const Text('查看'), + label: Text(context.t('view')), ), TextButton.icon( onPressed: () { // TODO: Export reconciliation report }, icon: const Icon(Icons.download_rounded, size: 16), - label: const Text('导出'), + label: Text(context.t('export')), ), ], ), diff --git a/frontend/admin-app/lib/features/finance/presentation/pages/financing_analysis_page.dart b/frontend/admin-app/lib/features/finance/presentation/pages/financing_analysis_page.dart index 04b7d2a..5c775eb 100644 --- a/frontend/admin-app/lib/features/finance/presentation/pages/financing_analysis_page.dart +++ b/frontend/admin-app/lib/features/finance/presentation/pages/financing_analysis_page.dart @@ -3,6 +3,7 @@ import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; import '../../../../app/router.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 融资效果分析页面 /// @@ -15,21 +16,21 @@ class FinancingAnalysisPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('融资效果分析'), + title: Text(context.t('financing_title')), actions: [ IconButton( icon: const Icon(Icons.refresh_rounded), onPressed: () { // TODO: Refresh financing analysis data }, - tooltip: '刷新数据', + tooltip: context.t('financing_refresh_tooltip'), ), IconButton( icon: const Icon(Icons.download_rounded), onPressed: () { // TODO: Export financing analysis report }, - tooltip: '导出报告', + tooltip: context.t('financing_export_tooltip'), ), ], ), @@ -39,23 +40,23 @@ class FinancingAnalysisPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ // Stats Cards - _buildStatsCards(), + _buildStatsCards(context), const SizedBox(height: 24), // Financing Timeline - _buildFinancingTimeline(), + _buildFinancingTimeline(context), const SizedBox(height: 24), // Cost-Benefit Analysis - _buildCostBenefitCard(), + _buildCostBenefitCard(context), const SizedBox(height: 24), // Liquidity Metrics - _buildLiquidityMetrics(), + _buildLiquidityMetrics(context), const SizedBox(height: 24), // Risk Indicators - _buildRiskIndicators(), + _buildRiskIndicators(context), const SizedBox(height: 24), // AI Recommendation @@ -70,12 +71,12 @@ class FinancingAnalysisPage extends StatelessWidget { // Stats Cards // ============================================================ - Widget _buildStatsCards() { + Widget _buildStatsCards(BuildContext context) { final stats = [ - ('融资总额', '\$2,850,000', AppColors.primary, Icons.account_balance_rounded, '+12.5%'), - ('平均利率', '4.2%', AppColors.info, Icons.percent_rounded, '-0.3%'), - ('融资笔数', '18', AppColors.success, Icons.receipt_long_rounded, '+3'), - ('资金利用率', '87.6%', AppColors.warning, Icons.pie_chart_rounded, '+5.2%'), + (context.t('financing_total_amount'), '\$2,850,000', AppColors.primary, Icons.account_balance_rounded, '+12.5%'), + (context.t('financing_avg_rate'), '4.2%', AppColors.info, Icons.percent_rounded, '-0.3%'), + (context.t('financing_count'), '18', AppColors.success, Icons.receipt_long_rounded, '+3'), + (context.t('financing_utilization'), '87.6%', AppColors.warning, Icons.pie_chart_rounded, '+5.2%'), ]; return GridView.builder( @@ -149,14 +150,14 @@ class FinancingAnalysisPage extends StatelessWidget { // Financing Timeline // ============================================================ - Widget _buildFinancingTimeline() { + Widget _buildFinancingTimeline(BuildContext context) { final stages = [ - ('申请提交', '2026-01-15', true, AppColors.success), - ('审批通过', '2026-01-17', true, AppColors.success), - ('资金到账', '2026-01-18', true, AppColors.success), - ('使用中', '2026-01-18 ~', true, AppColors.primary), - ('还款期', '2026-07-18', false, AppColors.textTertiary), - ('结清', '待定', false, AppColors.textTertiary), + (context.t('financing_stage_submitted'), '2026-01-15', true, AppColors.success), + (context.t('financing_stage_approved'), '2026-01-17', true, AppColors.success), + (context.t('financing_stage_funded'), '2026-01-18', true, AppColors.success), + (context.t('financing_stage_in_use'), '2026-01-18 ~', true, AppColors.primary), + (context.t('financing_stage_repayment'), '2026-07-18', false, AppColors.textTertiary), + (context.t('financing_stage_settled'), context.t('financing_stage_tbd'), false, AppColors.textTertiary), ]; return Container( @@ -173,7 +174,7 @@ class FinancingAnalysisPage extends StatelessWidget { children: [ const Icon(Icons.timeline_rounded, color: AppColors.primary, size: 20), const SizedBox(width: 8), - Text('融资生命周期', style: AppTypography.h3), + Text(context.t('financing_lifecycle'), style: AppTypography.h3), ], ), const SizedBox(height: 20), @@ -243,7 +244,7 @@ class FinancingAnalysisPage extends StatelessWidget { // Cost-Benefit Analysis // ============================================================ - Widget _buildCostBenefitCard() { + Widget _buildCostBenefitCard(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -258,7 +259,7 @@ class FinancingAnalysisPage extends StatelessWidget { children: [ const Icon(Icons.analytics_rounded, color: AppColors.primary, size: 20), const SizedBox(width: 8), - Text('成本效益分析', style: AppTypography.h3), + Text(context.t('financing_cost_benefit'), style: AppTypography.h3), ], ), const SizedBox(height: 20), @@ -268,9 +269,9 @@ class FinancingAnalysisPage extends StatelessWidget { children: [ Expanded( child: _buildCostBenefitItem( - '利息成本', + context.t('financing_interest_cost'), '\$119,700', - '年化 4.2%', + '${context.t('financing_annual_rate')} 4.2%', AppColors.error, Icons.trending_down_rounded, ), @@ -278,9 +279,9 @@ class FinancingAnalysisPage extends StatelessWidget { const SizedBox(width: 12), Expanded( child: _buildCostBenefitItem( - '产生收入', + context.t('financing_generated_income'), '\$458,200', - '利用融资收入', + context.t('financing_income_from_financing'), AppColors.success, Icons.trending_up_rounded, ), @@ -300,7 +301,7 @@ class FinancingAnalysisPage extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '净收益', + context.t('financing_net_benefit'), style: AppTypography.labelMedium.copyWith(color: Colors.white), ), Text( @@ -316,7 +317,7 @@ class FinancingAnalysisPage extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('投资回报率 (ROI)', style: AppTypography.bodySmall), + Text(context.t('financing_roi'), style: AppTypography.bodySmall), Text( '282.7%', style: AppTypography.labelLarge.copyWith(color: AppColors.success), @@ -327,7 +328,7 @@ class FinancingAnalysisPage extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('收益/成本比', style: AppTypography.bodySmall), + Text(context.t('financing_cost_ratio'), style: AppTypography.bodySmall), Text( '3.83x', style: AppTypography.labelLarge.copyWith(color: AppColors.primary), @@ -376,7 +377,7 @@ class FinancingAnalysisPage extends StatelessWidget { // Liquidity Metrics // ============================================================ - Widget _buildLiquidityMetrics() { + Widget _buildLiquidityMetrics(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -391,16 +392,16 @@ class FinancingAnalysisPage extends StatelessWidget { children: [ const Icon(Icons.water_drop_rounded, color: AppColors.info, size: 20), const SizedBox(width: 8), - Text('流动性指标', style: AppTypography.h3), + Text(context.t('financing_liquidity'), style: AppTypography.h3), ], ), const SizedBox(height: 20), // Quick Ratio _buildMetricRow( - '速动比率 (Quick Ratio)', + context.t('financing_quick_ratio'), '1.85', - '健康', + context.t('financing_status_healthy'), AppColors.success, 0.85, ), @@ -408,16 +409,16 @@ class FinancingAnalysisPage extends StatelessWidget { // Current Ratio _buildMetricRow( - '流动比率 (Current Ratio)', + context.t('financing_current_ratio'), '2.34', - '良好', + context.t('financing_status_good'), AppColors.success, 0.78, ), const SizedBox(height: 16), // Cash Flow Forecast - _buildSectionTitle('现金流预测'), + _buildSectionTitle(context.t('financing_cashflow_forecast')), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(14), @@ -427,17 +428,17 @@ class FinancingAnalysisPage extends StatelessWidget { ), child: Column( children: [ - _buildForecastRow('本月预计流入', '+\$85,200', AppColors.success), + _buildForecastRow(context.t('financing_this_month_inflow'), '+\$85,200', AppColors.success), const SizedBox(height: 8), - _buildForecastRow('本月预计流出', '-\$52,800', AppColors.error), + _buildForecastRow(context.t('financing_this_month_outflow'), '-\$52,800', AppColors.error), const Divider(height: 16), - _buildForecastRow('净现金流', '+\$32,400', AppColors.primary), + _buildForecastRow(context.t('financing_net_cashflow'), '+\$32,400', AppColors.primary), const SizedBox(height: 12), - _buildForecastRow('下月预计流入', '+\$92,500', AppColors.success), + _buildForecastRow(context.t('financing_next_month_inflow'), '+\$92,500', AppColors.success), const SizedBox(height: 8), - _buildForecastRow('下月预计流出', '-\$68,300', AppColors.error), + _buildForecastRow(context.t('financing_next_month_outflow'), '-\$68,300', AppColors.error), const Divider(height: 16), - _buildForecastRow('下月净现金流', '+\$24,200', AppColors.primary), + _buildForecastRow(context.t('financing_next_month_net'), '+\$24,200', AppColors.primary), ], ), ), @@ -509,7 +510,7 @@ class FinancingAnalysisPage extends StatelessWidget { // Risk Indicators // ============================================================ - Widget _buildRiskIndicators() { + Widget _buildRiskIndicators(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -524,7 +525,7 @@ class FinancingAnalysisPage extends StatelessWidget { children: [ const Icon(Icons.shield_rounded, color: AppColors.warning, size: 20), const SizedBox(width: 8), - Text('风险指标', style: AppTypography.h3), + Text(context.t('financing_risk_title'), style: AppTypography.h3), ], ), const SizedBox(height: 20), @@ -532,36 +533,36 @@ class FinancingAnalysisPage extends StatelessWidget { // Risk gauge cards Row( children: [ - Expanded(child: _buildRiskGauge('违约率', '0.8%', AppColors.success, 0.08)), + Expanded(child: _buildRiskGauge(context.t('financing_default_rate'), '0.8%', AppColors.success, 0.08)), const SizedBox(width: 12), - Expanded(child: _buildRiskGauge('逾期率', '2.3%', AppColors.warning, 0.23)), + Expanded(child: _buildRiskGauge(context.t('financing_overdue_rate'), '2.3%', AppColors.warning, 0.23)), const SizedBox(width: 12), - Expanded(child: _buildRiskGauge('集中度', '35%', AppColors.info, 0.35)), + Expanded(child: _buildRiskGauge(context.t('financing_concentration'), '35%', AppColors.info, 0.35)), ], ), const SizedBox(height: 20), // Risk detail rows _buildRiskDetailRow( - '违约率 (Default Rate)', + context.t('financing_default_detail'), '0.8%', - '低于行业平均 1.5%', + context.t('financing_default_desc'), AppColors.success, Icons.check_circle_rounded, ), const SizedBox(height: 12), _buildRiskDetailRow( - '逾期率 (Overdue Rate)', + context.t('financing_overdue_detail'), '2.3%', - '接近预警线 3.0%,需关注', + context.t('financing_overdue_desc'), AppColors.warning, Icons.warning_rounded, ), const SizedBox(height: 12), _buildRiskDetailRow( - '集中度风险 (Concentration)', + context.t('financing_concentration_detail'), '35%', - '最大单笔占比 35%,建议分散', + context.t('financing_concentration_desc'), AppColors.info, Icons.info_rounded, ), @@ -713,8 +714,8 @@ class FinancingAnalysisPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('AI 融资策略建议', style: AppTypography.h3), - Text('基于您的经营数据智能分析', style: AppTypography.caption), + Text(context.t('financing_ai_title'), style: AppTypography.h3), + Text(context.t('financing_ai_subtitle'), style: AppTypography.caption), ], ), ), @@ -748,7 +749,7 @@ class FinancingAnalysisPage extends StatelessWidget { borderRadius: BorderRadius.circular(AppSpacing.radiusFull), ), child: Text( - '$priority优先', + priority == '高' ? context.t('financing_priority_high') : context.t('financing_priority_medium'), style: AppTypography.caption.copyWith( color: priorityColor, fontWeight: FontWeight.w600, @@ -772,7 +773,7 @@ class FinancingAnalysisPage extends StatelessWidget { Navigator.pushNamed(context, AppRouter.aiAgent); }, icon: const Icon(Icons.auto_awesome_rounded, size: 18), - label: const Text('获取详细融资方案'), + label: Text(context.t('financing_get_detail_plan')), ), ), ], diff --git a/frontend/admin-app/lib/features/finance/presentation/pages/reconciliation_page.dart b/frontend/admin-app/lib/features/finance/presentation/pages/reconciliation_page.dart index 9457dea..5c2be38 100644 --- a/frontend/admin-app/lib/features/finance/presentation/pages/reconciliation_page.dart +++ b/frontend/admin-app/lib/features/finance/presentation/pages/reconciliation_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 对账与结算报表页面 /// @@ -15,19 +16,19 @@ class ReconciliationPage extends StatefulWidget { } class _ReconciliationPageState extends State { - String _selectedPeriod = '月'; - final _periods = ['日', '周', '月', '季度']; + String _selectedPeriod = 'reconciliation_period_month'; + final _periodKeys = ['reconciliation_period_day', 'reconciliation_period_week', 'reconciliation_period_month', 'reconciliation_period_quarter']; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('对账与结算'), + title: Text(context.t('reconciliation_title')), actions: [ IconButton( icon: const Icon(Icons.download_rounded), onPressed: () => _showExportDialog(context), - tooltip: '导出报表', + tooltip: context.t('reconciliation_export_tooltip'), ), ], ), @@ -76,11 +77,11 @@ class _ReconciliationPageState extends State { borderRadius: BorderRadius.circular(AppSpacing.radiusSm), ), child: Row( - children: _periods.map((p) { - final isSelected = _selectedPeriod == p; + children: _periodKeys.map((key) { + final isSelected = _selectedPeriod == key; return Expanded( child: GestureDetector( - onTap: () => setState(() => _selectedPeriod = p), + onTap: () => setState(() => _selectedPeriod = key), child: Container( padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( @@ -90,7 +91,7 @@ class _ReconciliationPageState extends State { ), child: Center( child: Text( - p, + context.t(key), style: AppTypography.labelMedium.copyWith( color: isSelected ? AppColors.primary : AppColors.textSecondary, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, @@ -111,10 +112,10 @@ class _ReconciliationPageState extends State { Widget _buildSummaryCards() { final summaries = [ - ('应结金额', '\$132,490', AppColors.primary, Icons.account_balance_rounded), - ('已结金额', '\$118,200', AppColors.success, Icons.check_circle_rounded), - ('待结金额', '\$12,180', AppColors.warning, Icons.schedule_rounded), - ('差异金额', '\$2,110', AppColors.error, Icons.error_outline_rounded), + (context.t('reconciliation_expected'), '\$132,490', AppColors.primary, Icons.account_balance_rounded), + (context.t('reconciliation_settled'), '\$118,200', AppColors.success, Icons.check_circle_rounded), + (context.t('reconciliation_pending'), '\$12,180', AppColors.warning, Icons.schedule_rounded), + (context.t('reconciliation_discrepancy_amount'), '\$2,110', AppColors.error, Icons.error_outline_rounded), ]; return GridView.builder( @@ -190,8 +191,8 @@ class _ReconciliationPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('自动对账', style: AppTypography.labelMedium), - Text('上次运行: 今天 06:00', style: AppTypography.caption), + Text(context.t('reconciliation_auto_title'), style: AppTypography.labelMedium), + Text(context.t('reconciliation_auto_last_run'), style: AppTypography.caption), ], ), ), @@ -202,7 +203,7 @@ class _ReconciliationPageState extends State { borderRadius: BorderRadius.circular(AppSpacing.radiusFull), ), child: Text( - '运行中', + context.t('reconciliation_auto_running'), style: AppTypography.caption.copyWith( color: AppColors.success, fontWeight: FontWeight.w600, @@ -215,7 +216,7 @@ class _ReconciliationPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('匹配率', style: AppTypography.bodySmall), + Text(context.t('reconciliation_match_rate'), style: AppTypography.bodySmall), Text( '$matchRate%', style: AppTypography.labelMedium.copyWith(color: AppColors.success), @@ -236,9 +237,9 @@ class _ReconciliationPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _buildMiniStat('已匹配', '4,832', AppColors.success), - _buildMiniStat('待核查', '158', AppColors.warning), - _buildMiniStat('有差异', '12', AppColors.error), + _buildMiniStat(context.t('reconciliation_matched'), '4,832', AppColors.success), + _buildMiniStat(context.t('reconciliation_to_check'), '158', AppColors.warning), + _buildMiniStat(context.t('reconciliation_has_diff'), '12', AppColors.error), ], ), ], @@ -267,7 +268,7 @@ class _ReconciliationPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('对账明细', style: AppTypography.h3), + Text(context.t('reconciliation_detail_title'), style: AppTypography.h3), const SizedBox(height: 12), Container( decoration: BoxDecoration( @@ -289,11 +290,11 @@ class _ReconciliationPageState extends State { ), child: Row( children: [ - Expanded(flex: 2, child: Text('期间', style: AppTypography.labelSmall)), - Expanded(flex: 2, child: Text('应结', style: AppTypography.labelSmall)), - Expanded(flex: 2, child: Text('实结', style: AppTypography.labelSmall)), - Expanded(flex: 2, child: Text('差异', style: AppTypography.labelSmall)), - Expanded(flex: 2, child: Text('状态', style: AppTypography.labelSmall)), + Expanded(flex: 2, child: Text(context.t('reconciliation_col_period'), style: AppTypography.labelSmall)), + Expanded(flex: 2, child: Text(context.t('reconciliation_col_expected'), style: AppTypography.labelSmall)), + Expanded(flex: 2, child: Text(context.t('reconciliation_col_actual'), style: AppTypography.labelSmall)), + Expanded(flex: 2, child: Text(context.t('reconciliation_col_diff'), style: AppTypography.labelSmall)), + Expanded(flex: 2, child: Text(context.t('reconciliation_col_status'), style: AppTypography.labelSmall)), ], ), ), @@ -386,7 +387,7 @@ class _ReconciliationPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('差异调查', style: AppTypography.h3), + Text(context.t('reconciliation_discrepancy_title'), style: AppTypography.h3), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( @@ -394,7 +395,7 @@ class _ReconciliationPageState extends State { borderRadius: BorderRadius.circular(AppSpacing.radiusFull), ), child: Text( - '3 项待处理', + '3 ${context.t('reconciliation_pending_items')}', style: AppTypography.caption.copyWith( color: AppColors.error, fontWeight: FontWeight.w600, @@ -454,7 +455,7 @@ class _ReconciliationPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '差异金额: $amount', + '${context.t('reconciliation_discrepancy_amount_label')}: $amount', style: AppTypography.bodySmall.copyWith(color: AppColors.error), ), Text(date, style: AppTypography.caption), @@ -483,7 +484,7 @@ class _ReconciliationPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('导出报表', style: AppTypography.h3), + Text(context.t('reconciliation_export_title'), style: AppTypography.h3), const SizedBox(height: 14), Row( children: [ @@ -493,7 +494,7 @@ class _ReconciliationPageState extends State { // TODO: Export reconciliation report as PDF }, icon: const Icon(Icons.picture_as_pdf_rounded, size: 18), - label: const Text('导出 PDF'), + label: Text(context.t('finance_export_pdf')), style: OutlinedButton.styleFrom( minimumSize: const Size(0, 48), foregroundColor: AppColors.error, @@ -508,7 +509,7 @@ class _ReconciliationPageState extends State { // TODO: Export reconciliation report as Excel }, icon: const Icon(Icons.table_chart_rounded, size: 18), - label: const Text('导出 Excel'), + label: Text(context.t('finance_export_excel')), style: OutlinedButton.styleFrom( minimumSize: const Size(0, 48), foregroundColor: AppColors.success, @@ -531,35 +532,35 @@ class _ReconciliationPageState extends State { showDialog( context: context, builder: (ctx) => SimpleDialog( - title: const Text('导出对账报表'), + title: Text(context.t('reconciliation_export_dialog_title')), children: [ SimpleDialogOption( onPressed: () => Navigator.pop(ctx), - child: const Row( + child: Row( children: [ - Icon(Icons.picture_as_pdf_rounded, color: AppColors.error, size: 20), - SizedBox(width: 12), - Text('导出 PDF'), + const Icon(Icons.picture_as_pdf_rounded, color: AppColors.error, size: 20), + const SizedBox(width: 12), + Text(context.t('finance_export_pdf')), ], ), ), SimpleDialogOption( onPressed: () => Navigator.pop(ctx), - child: const Row( + child: Row( children: [ - Icon(Icons.table_chart_rounded, color: AppColors.success, size: 20), - SizedBox(width: 12), - Text('导出 Excel'), + const Icon(Icons.table_chart_rounded, color: AppColors.success, size: 20), + const SizedBox(width: 12), + Text(context.t('finance_export_excel')), ], ), ), SimpleDialogOption( onPressed: () => Navigator.pop(ctx), - child: const Row( + child: Row( children: [ - Icon(Icons.description_rounded, color: AppColors.info, size: 20), - SizedBox(width: 12), - Text('导出 CSV'), + const Icon(Icons.description_rounded, color: AppColors.info, size: 20), + const SizedBox(width: 12), + Text(context.t('finance_export_csv')), ], ), ), diff --git a/frontend/admin-app/lib/features/onboarding/presentation/pages/onboarding_page.dart b/frontend/admin-app/lib/features/onboarding/presentation/pages/onboarding_page.dart index e178ca9..3895e8f 100644 --- a/frontend/admin-app/lib/features/onboarding/presentation/pages/onboarding_page.dart +++ b/frontend/admin-app/lib/features/onboarding/presentation/pages/onboarding_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/router.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 发行方入驻审核流程 /// @@ -25,7 +26,7 @@ class _OnboardingPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('企业入驻')), + appBar: AppBar(title: Text(context.t('onboarding_title'))), body: Column( children: [ // Step Indicator @@ -49,14 +50,14 @@ class _OnboardingPageState extends State { Expanded( child: OutlinedButton( onPressed: _goBack, - child: const Text('上一步'), + child: Text(context.t('prev_step')), ), ), if (_currentStep.index > 0 && _currentStep.index < 3) const SizedBox(width: 12), Expanded( child: ElevatedButton( onPressed: _goNext, - child: Text(_currentStep.index < 2 ? '下一步' : '提交审核'), + child: Text(_currentStep.index < 2 ? context.t('next') : context.t('onboarding_submit_review')), ), ), ], @@ -68,7 +69,12 @@ class _OnboardingPageState extends State { } Widget _buildStepIndicator() { - final steps = ['企业信息', '资质上传', '联系人', '审核中']; + final steps = [ + context.t('onboarding_step_company'), + context.t('onboarding_step_documents'), + context.t('onboarding_step_contact'), + context.t('onboarding_step_review'), + ]; return Padding( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), child: Row( @@ -143,27 +149,27 @@ class _OnboardingPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('企业基本信息', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), + Text(context.t('onboarding_company_title'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 8), - const Text('请填写真实的企业信息,用于入驻审核', style: TextStyle(color: AppColors.textSecondary)), + Text(context.t('onboarding_company_subtitle'), style: const TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 24), TextField( controller: _companyNameController, - decoration: const InputDecoration(labelText: '企业名称', hintText: '请输入企业全称'), + decoration: InputDecoration(labelText: context.t('onboarding_company_name'), hintText: context.t('onboarding_company_name_hint')), ), const SizedBox(height: 16), TextField( controller: _licenseController, - decoration: const InputDecoration(labelText: '统一社会信用代码', hintText: '请输入18位信用代码'), + decoration: InputDecoration(labelText: context.t('onboarding_credit_code'), hintText: context.t('onboarding_credit_code_hint')), ), const SizedBox(height: 16), DropdownButtonFormField( - decoration: const InputDecoration(labelText: '企业类型'), - items: const [ - DropdownMenuItem(value: 'restaurant', child: Text('餐饮企业')), - DropdownMenuItem(value: 'retail', child: Text('零售企业')), - DropdownMenuItem(value: 'entertainment', child: Text('娱乐/文旅')), - DropdownMenuItem(value: 'other', child: Text('其他')), + decoration: InputDecoration(labelText: context.t('onboarding_company_type')), + items: [ + DropdownMenuItem(value: 'restaurant', child: Text(context.t('onboarding_type_restaurant'))), + DropdownMenuItem(value: 'retail', child: Text(context.t('onboarding_type_retail'))), + DropdownMenuItem(value: 'entertainment', child: Text(context.t('onboarding_type_entertainment'))), + DropdownMenuItem(value: 'other', child: Text(context.t('onboarding_type_other'))), ], onChanged: (_) { // TODO: Update selected company type @@ -171,7 +177,7 @@ class _OnboardingPageState extends State { ), const SizedBox(height: 16), TextField( - decoration: const InputDecoration(labelText: '企业地址', hintText: '请输入企业注册地址'), + decoration: InputDecoration(labelText: context.t('onboarding_company_address'), hintText: context.t('onboarding_company_address_hint')), ), // AI合规助手 @@ -183,17 +189,17 @@ class _OnboardingPageState extends State { borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColors.primary.withValues(alpha: 0.15)), ), - child: const Row( + child: Row( children: [ - Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), - SizedBox(width: 10), + const Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), + const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('AI 合规助手', style: TextStyle(fontSize: 13, color: AppColors.primary, fontWeight: FontWeight.w600)), - SizedBox(height: 2), - Text('填写信息后,AI将自动检查合规要求', style: TextStyle(fontSize: 12, color: AppColors.textSecondary)), + Text(context.t('onboarding_ai_compliance'), style: const TextStyle(fontSize: 13, color: AppColors.primary, fontWeight: FontWeight.w600)), + const SizedBox(height: 2), + Text(context.t('onboarding_ai_compliance_desc'), style: const TextStyle(fontSize: 12, color: AppColors.textSecondary)), ], ), ), @@ -208,15 +214,15 @@ class _OnboardingPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('资质文件上传', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), + Text(context.t('onboarding_doc_title'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 8), - const Text('请上传清晰的企业资质文件', style: TextStyle(color: AppColors.textSecondary)), + Text(context.t('onboarding_doc_subtitle'), style: const TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 24), - _buildUploadArea('营业执照', Icons.business_rounded, true), + _buildUploadArea(context.t('onboarding_doc_license'), Icons.business_rounded, true), const SizedBox(height: 16), - _buildUploadArea('法人身份证(正反面)', Icons.badge_rounded, true), + _buildUploadArea(context.t('onboarding_doc_id'), Icons.badge_rounded, true), const SizedBox(height: 16), - _buildUploadArea('行业资质证书(可选)', Icons.verified_rounded, false), + _buildUploadArea(context.t('onboarding_doc_cert'), Icons.verified_rounded, false), ], ); } @@ -237,14 +243,14 @@ class _OnboardingPageState extends State { style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), ), if (required) - const Text('*必填', style: TextStyle(fontSize: 11, color: AppColors.error)), + Text(context.t('onboarding_required'), style: const TextStyle(fontSize: 11, color: AppColors.error)), const SizedBox(height: 8), OutlinedButton.icon( onPressed: () { // TODO: Open file picker for document upload }, icon: const Icon(Icons.upload_rounded, size: 18), - label: const Text('点击上传'), + label: Text(context.t('onboarding_upload')), ), ], ), @@ -255,26 +261,26 @@ class _OnboardingPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('联系人信息', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), + Text(context.t('onboarding_contact_title'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 24), TextField( controller: _contactController, - decoration: const InputDecoration(labelText: '联系人姓名'), + decoration: InputDecoration(labelText: context.t('onboarding_contact_name')), ), const SizedBox(height: 16), TextField( controller: _contactPhoneController, keyboardType: TextInputType.phone, - decoration: const InputDecoration(labelText: '联系人手机号'), + decoration: InputDecoration(labelText: context.t('onboarding_contact_phone')), ), const SizedBox(height: 16), TextField( keyboardType: TextInputType.emailAddress, - decoration: const InputDecoration(labelText: '企业邮箱'), + decoration: InputDecoration(labelText: context.t('onboarding_contact_email')), ), const SizedBox(height: 16), TextField( - decoration: const InputDecoration(labelText: '职位/角色'), + decoration: InputDecoration(labelText: context.t('onboarding_contact_role')), ), ], ); @@ -296,13 +302,13 @@ class _OnboardingPageState extends State { child: const Icon(Icons.hourglass_bottom_rounded, color: AppColors.warning, size: 40), ), const SizedBox(height: 24), - const Text('审核中', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w700)), + Text(context.t('onboarding_review_title'), style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w700)), const SizedBox(height: 8), - const Text('您的入驻申请已提交,预计1-3个工作日内完成审核', style: TextStyle(color: AppColors.textSecondary)), + Text(context.t('onboarding_review_desc'), style: const TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 32), OutlinedButton( onPressed: () => Navigator.pop(context), - child: const Text('返回登录'), + child: Text(context.t('onboarding_back_login')), ), ], ), @@ -325,13 +331,13 @@ class _OnboardingPageState extends State { child: const Icon(Icons.check_circle_rounded, color: AppColors.success, size: 40), ), const SizedBox(height: 24), - const Text('审核通过', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w700)), + Text(context.t('onboarding_approved_title'), style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w700)), const SizedBox(height: 8), - const Text('恭喜!您已获得白银级初始额度', style: TextStyle(color: AppColors.textSecondary)), + Text(context.t('onboarding_approved_desc'), style: const TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 32), ElevatedButton( onPressed: () => Navigator.pushReplacementNamed(context, AppRouter.main), - child: const Text('进入控制台'), + child: Text(context.t('onboarding_enter_console')), ), ], ), @@ -354,13 +360,13 @@ class _OnboardingPageState extends State { child: const Icon(Icons.cancel_rounded, color: AppColors.error, size: 40), ), const SizedBox(height: 24), - const Text('审核未通过', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w700)), + Text(context.t('onboarding_rejected_title'), style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w700)), const SizedBox(height: 8), - const Text('原因:资质文件不清晰,请重新上传', style: TextStyle(color: AppColors.textSecondary)), + Text(context.t('onboarding_rejected_desc'), style: const TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 32), ElevatedButton( onPressed: () => setState(() => _currentStep = OnboardingStep.documents), - child: const Text('重新提交'), + child: Text(context.t('onboarding_resubmit')), ), ], ), diff --git a/frontend/admin-app/lib/features/redemption/presentation/pages/redemption_page.dart b/frontend/admin-app/lib/features/redemption/presentation/pages/redemption_page.dart index 569587b..7dd2647 100644 --- a/frontend/admin-app/lib/features/redemption/presentation/pages/redemption_page.dart +++ b/frontend/admin-app/lib/features/redemption/presentation/pages/redemption_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 核销管理页面 /// @@ -13,11 +14,11 @@ class RedemptionPage extends StatelessWidget { length: 2, child: Scaffold( appBar: AppBar( - title: const Text('核销管理'), - bottom: const TabBar( + title: Text(context.t('redemption_title')), + bottom: TabBar( tabs: [ - Tab(text: '扫码核销'), - Tab(text: '核销记录'), + Tab(text: context.t('redemption_tab_scan')), + Tab(text: context.t('redemption_tab_history')), ], ), ), @@ -62,7 +63,7 @@ class _ScanRedeemTab extends StatelessWidget { child: const Icon(Icons.qr_code_scanner_rounded, color: AppColors.primary, size: 64), ), const SizedBox(height: 16), - const Text('将券码对准扫描框', style: TextStyle(color: Colors.white70, fontSize: 14)), + Text(context.t('redemption_scan_hint'), style: const TextStyle(color: Colors.white70, fontSize: 14)), ], ), ), @@ -74,9 +75,9 @@ class _ScanRedeemTab extends StatelessWidget { children: [ Expanded( child: TextField( - decoration: const InputDecoration( - hintText: '手动输入券码', - prefixIcon: Icon(Icons.keyboard_rounded), + decoration: InputDecoration( + hintText: context.t('redemption_manual_hint'), + prefixIcon: const Icon(Icons.keyboard_rounded), ), ), ), @@ -85,7 +86,7 @@ class _ScanRedeemTab extends StatelessWidget { height: 52, child: ElevatedButton( onPressed: () => _showRedeemConfirm(context), - child: const Text('核销'), + child: Text(context.t('redemption_redeem')), ), ), ], @@ -96,7 +97,7 @@ class _ScanRedeemTab extends StatelessWidget { OutlinedButton.icon( onPressed: () => _showBatchRedeem(context), icon: const Icon(Icons.list_alt_rounded), - label: const Text('批量核销'), + label: Text(context.t('redemption_batch')), style: OutlinedButton.styleFrom( minimumSize: const Size(double.infinity, 48), ), @@ -114,14 +115,14 @@ class _ScanRedeemTab extends StatelessWidget { child: const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('今日核销', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), - SizedBox(height: 12), + Text(context.t('redemption_today_title'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), + const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - _StatItem(label: '核销次数', value: '45'), - _StatItem(label: '核销金额', value: '\$1,125'), - _StatItem(label: '门店数', value: '3'), + _StatItem(label: context.t('redemption_today_count'), value: '45'), + _StatItem(label: context.t('redemption_today_amount'), value: '\$1,125'), + _StatItem(label: context.t('redemption_today_stores'), value: '3'), ], ), ], @@ -142,7 +143,7 @@ class _ScanRedeemTab extends StatelessWidget { children: [ const Icon(Icons.check_circle_rounded, color: AppColors.success, size: 56), const SizedBox(height: 16), - const Text('核销确认', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), + Text(context.t('redemption_confirm_title'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 8), const Text('¥25 星巴克礼品卡', style: TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 24), @@ -150,7 +151,7 @@ class _ScanRedeemTab extends StatelessWidget { width: double.infinity, child: ElevatedButton( onPressed: () => Navigator.pop(ctx), - child: const Text('确认核销'), + child: Text(context.t('redemption_confirm_button')), ), ), const SizedBox(height: 12), @@ -172,17 +173,17 @@ class _ScanRedeemTab extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('批量核销', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), + Text(context.t('redemption_batch'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 8), - const Text('输入多个券码,每行一个', style: TextStyle(color: AppColors.textSecondary)), + Text(context.t('redemption_batch_desc'), style: const TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 16), Expanded( child: TextField( maxLines: null, expands: true, textAlignVertical: TextAlignVertical.top, - decoration: const InputDecoration( - hintText: '粘贴券码列表...', + decoration: InputDecoration( + hintText: context.t('redemption_batch_hint'), border: OutlineInputBorder(), ), ), @@ -192,7 +193,7 @@ class _ScanRedeemTab extends StatelessWidget { width: double.infinity, child: ElevatedButton( onPressed: () => Navigator.pop(ctx), - child: const Text('批量核销'), + child: Text(context.t('redemption_batch')), ), ), ], diff --git a/frontend/admin-app/lib/features/settings/presentation/pages/settings_page.dart b/frontend/admin-app/lib/features/settings/presentation/pages/settings_page.dart index d5047ed..3ae78d9 100644 --- a/frontend/admin-app/lib/features/settings/presentation/pages/settings_page.dart +++ b/frontend/admin-app/lib/features/settings/presentation/pages/settings_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/router.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 发行方设置页面(我的) /// @@ -11,7 +12,7 @@ class SettingsPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('我的')), + appBar: AppBar(title: Text(context.t('settings_title'))), body: SingleChildScrollView( child: Column( children: [ @@ -24,44 +25,44 @@ class SettingsPage extends StatelessWidget { const SizedBox(height: 8), // Menu Groups - _buildMenuGroup('企业管理', [ - _MenuItem('企业信息', Icons.business_rounded, () { + _buildMenuGroup(context.t('settings_group_company'), [ + _MenuItem(context.t('settings_company_info'), Icons.business_rounded, () { // TODO: Navigate to company info page when available }), - _MenuItem('门店管理', Icons.store_rounded, () { + _MenuItem(context.t('settings_store_mgmt'), Icons.store_rounded, () { Navigator.pushNamed(context, AppRouter.storeManagement); }), - _MenuItem('员工管理', Icons.people_rounded, () { + _MenuItem(context.t('settings_employee_mgmt'), Icons.people_rounded, () { Navigator.pushNamed(context, AppRouter.storeManagement); }), - _MenuItem('权限设置', Icons.admin_panel_settings_rounded, () { + _MenuItem(context.t('settings_permissions'), Icons.admin_panel_settings_rounded, () { // TODO: Navigate to permissions page when available }), ]), - _buildMenuGroup('服务支持', [ - _MenuItem('AI 助手', Icons.auto_awesome_rounded, () { + _buildMenuGroup(context.t('settings_group_support'), [ + _MenuItem(context.t('settings_ai_assistant'), Icons.auto_awesome_rounded, () { Navigator.pushNamed(context, AppRouter.aiAgent); }), - _MenuItem('专属客服', Icons.headset_mic_rounded, () { + _MenuItem(context.t('settings_customer_service'), Icons.headset_mic_rounded, () { // TODO: Navigate to customer service page when available }), - _MenuItem('帮助中心', Icons.help_outline_rounded, () { + _MenuItem(context.t('settings_help_center'), Icons.help_outline_rounded, () { // TODO: Navigate to help center page when available }), - _MenuItem('意见反馈', Icons.feedback_rounded, () { + _MenuItem(context.t('settings_feedback'), Icons.feedback_rounded, () { // TODO: Navigate to feedback page when available }), ]), - _buildMenuGroup('安全与账号', [ - _MenuItem('修改密码', Icons.lock_outline_rounded, () { + _buildMenuGroup(context.t('settings_group_security'), [ + _MenuItem(context.t('settings_change_password'), Icons.lock_outline_rounded, () { // TODO: Navigate to change password page when available }), - _MenuItem('操作日志', Icons.history_rounded, () { + _MenuItem(context.t('settings_operation_log'), Icons.history_rounded, () { // TODO: Navigate to operation log page when available }), - _MenuItem('关于 Genex', Icons.info_outline_rounded, () { + _MenuItem(context.t('settings_about'), Icons.info_outline_rounded, () { // TODO: Navigate to about page when available }), ]), @@ -79,7 +80,7 @@ class SettingsPage extends StatelessWidget { foregroundColor: AppColors.error, side: const BorderSide(color: AppColors.error), ), - child: const Text('退出登录'), + child: Text(context.t('settings_logout')), ), ), ), @@ -105,13 +106,13 @@ class SettingsPage extends StatelessWidget { child: const Icon(Icons.storefront_rounded, color: Colors.white, size: 28), ), const SizedBox(width: 14), - const Expanded( + Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Starbucks China', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w700)), - SizedBox(height: 4), - Text('管理员:张经理', style: TextStyle(fontSize: 13, color: AppColors.textSecondary)), + const Text('Starbucks China', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w700)), + const SizedBox(height: 4), + Text('${context.t('settings_admin')}:张经理', style: const TextStyle(fontSize: 13, color: AppColors.textSecondary)), ], ), ), @@ -135,12 +136,12 @@ class SettingsPage extends StatelessWidget { children: [ const Icon(Icons.star_rounded, color: AppColors.tierGold, size: 28), const SizedBox(width: 12), - const Expanded( + Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('黄金发行方', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w700, color: AppColors.tierGold)), - Text('手续费率 1.2% · 高级数据分析', style: TextStyle(fontSize: 12, color: AppColors.textSecondary)), + Text(context.t('settings_gold_issuer'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w700, color: AppColors.tierGold)), + const Text('手续费率 1.2% · 高级数据分析', style: TextStyle(fontSize: 12, color: AppColors.textSecondary)), ], ), ), @@ -148,7 +149,7 @@ class SettingsPage extends StatelessWidget { onPressed: () { Navigator.pushNamed(context, AppRouter.credit); }, - child: const Text('升级', style: TextStyle(color: AppColors.tierGold)), + child: Text(context.t('settings_upgrade'), style: const TextStyle(color: AppColors.tierGold)), ), ], ), diff --git a/frontend/admin-app/lib/features/store_management/presentation/pages/store_management_page.dart b/frontend/admin-app/lib/features/store_management/presentation/pages/store_management_page.dart index 25935bf..b014bcb 100644 --- a/frontend/admin-app/lib/features/store_management/presentation/pages/store_management_page.dart +++ b/frontend/admin-app/lib/features/store_management/presentation/pages/store_management_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; +import '../../../../app/i18n/app_localizations.dart'; /// 多门店管理页面 /// @@ -14,11 +15,11 @@ class StoreManagementPage extends StatelessWidget { length: 2, child: Scaffold( appBar: AppBar( - title: const Text('门店管理'), - bottom: const TabBar( + title: Text(context.t('store_title')), + bottom: TabBar( tabs: [ - Tab(text: '门店列表'), - Tab(text: '员工管理'), + Tab(text: context.t('store_tab_list')), + Tab(text: context.t('store_tab_employees')), ], ), ), @@ -96,7 +97,7 @@ class _StoreListTab extends StatelessWidget { borderRadius: BorderRadius.circular(999), ), child: Text( - store.isActive ? '营业中' : '休息中', + store.isActive ? context.t('store_status_open') : context.t('store_status_closed'), style: TextStyle(fontSize: 10, color: store.isActive ? AppColors.success : AppColors.textTertiary), ), ), @@ -107,7 +108,7 @@ class _StoreListTab extends StatelessWidget { ], ), ), - Text('${store.staffCount}人', style: const TextStyle(fontSize: 12, color: AppColors.textTertiary)), + Text('${store.staffCount}${context.t('store_people_unit')}', style: const TextStyle(fontSize: 12, color: AppColors.textTertiary)), const SizedBox(width: 4), const Icon(Icons.chevron_right_rounded, size: 18, color: AppColors.textTertiary), ], @@ -169,8 +170,8 @@ class _EmployeeListTab extends StatelessWidget { subtitle: Text('$role · $store', style: const TextStyle(fontSize: 12, color: AppColors.textSecondary)), trailing: PopupMenuButton( itemBuilder: (ctx) => [ - const PopupMenuItem(value: 'edit', child: Text('编辑')), - const PopupMenuItem(value: 'delete', child: Text('移除')), + PopupMenuItem(value: 'edit', child: Text(context.t('store_emp_edit'))), + PopupMenuItem(value: 'delete', child: Text(context.t('store_emp_remove'))), ], ), ); diff --git a/frontend/admin-app/lib/main.dart b/frontend/admin-app/lib/main.dart index 9d74853..41ae845 100644 --- a/frontend/admin-app/lib/main.dart +++ b/frontend/admin-app/lib/main.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import 'app/theme/app_theme.dart'; import 'app/router.dart'; +import 'app/i18n/app_localizations.dart'; void main() { runApp(const GenexIssuerApp()); @@ -19,6 +21,18 @@ class GenexIssuerApp extends StatelessWidget { title: 'Genex Issuer Console', theme: AppTheme.light, debugShowCheckedModeBanner: false, + locale: const Locale('zh', 'CN'), + supportedLocales: const [ + Locale('zh', 'CN'), + Locale('en', 'US'), + Locale('ja', 'JP'), + ], + localizationsDelegates: const [ + AppLocalizationsDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], initialRoute: AppRouter.splash, onGenerateRoute: AppRouter.generateRoute, ); diff --git a/frontend/admin-app/lib/shared/widgets/ai_suggestion_card.dart b/frontend/admin-app/lib/shared/widgets/ai_suggestion_card.dart index 69261fe..1e25a79 100644 --- a/frontend/admin-app/lib/shared/widgets/ai_suggestion_card.dart +++ b/frontend/admin-app/lib/shared/widgets/ai_suggestion_card.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../../app/theme/app_colors.dart'; +import '../../app/i18n/app_localizations.dart'; /// 通用AI建议卡片(发行方专用) /// @@ -42,7 +43,7 @@ class AiSuggestionCard extends StatelessWidget { child: const Icon(Icons.auto_awesome_rounded, color: Colors.white, size: 14), ), const SizedBox(width: 8), - const Text('AI 建议', style: TextStyle(fontSize: 13, color: AppColors.primary, fontWeight: FontWeight.w600)), + Text(context.t('ai_suggestion_label'), style: const TextStyle(fontSize: 13, color: AppColors.primary, fontWeight: FontWeight.w600)), ], ), const SizedBox(height: 10), @@ -56,7 +57,7 @@ class AiSuggestionCard extends StatelessWidget { children: [ TextButton( onPressed: onDismiss, - child: const Text('忽略', style: TextStyle(fontSize: 13)), + child: Text(context.t('ai_suggestion_dismiss'), style: const TextStyle(fontSize: 13)), ), const SizedBox(width: 8), ElevatedButton( @@ -65,7 +66,7 @@ class AiSuggestionCard extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), minimumSize: Size.zero, ), - child: const Text('采纳', style: TextStyle(fontSize: 13)), + child: Text(context.t('ai_suggestion_accept'), style: const TextStyle(fontSize: 13)), ), ], ), diff --git a/frontend/admin-app/pubspec.yaml b/frontend/admin-app/pubspec.yaml index c8d2631..2132781 100644 --- a/frontend/admin-app/pubspec.yaml +++ b/frontend/admin-app/pubspec.yaml @@ -9,6 +9,8 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter dev_dependencies: flutter_test: diff --git a/frontend/admin-web/src/i18n/locales.ts b/frontend/admin-web/src/i18n/locales.ts index 3775812..fdc6bca 100644 --- a/frontend/admin-web/src/i18n/locales.ts +++ b/frontend/admin-web/src/i18n/locales.ts @@ -48,27 +48,105 @@ const translations: Record> = { 'total': '合计', 'yes': '是', 'no': '否', + 'all': '全部', + 'view': '查看', + 'process': '处理', + 'download': '下载', + 'collapse': '收起', + 'time': '时间', + 'amount': '金额', + 'type': '类型', + 'mark': '标记', + 'review': '审核', + 'suspend': '暂停', + 'resume': '恢复', + 'warning_label': '警告', + 'investigate': '审查', + 'completed': '已完成', + 'in_progress': '进行中', + 'pending': '待开始', + 'blocked': '阻塞', + 'custom_export': '自定义导出', + 'export_report': '导出报告', + 'auto_generated': '自动生成', + 'as_of': '截至', + 'generating': '生成中', + 'accuracy': '准确率', + 'overall_progress': '总体进度', + 'renew_now': '立即续期', + 'not_applied': '未申请', + 'urgency_critical': '紧急', + 'urgency_high': '高', + 'urgency_medium': '中', + 'urgency_low': '低', + 'expiry_date': '到期日', + 'remaining_days': '剩余 {0} 天', + 'severity_high': '高', + 'severity_medium': '中', + 'severity_low': '低', // ── Sidebar / Navigation ── - 'nav_dashboard': '仪表盘', + 'nav_dashboard': '运营总览', 'nav_overview': '总览', 'nav_users': '用户管理', 'nav_coupons': '券审核', 'nav_issuers': '发行方管理', - 'nav_finance': '财务', - 'nav_chain': '链监控', - 'nav_reports': '报表', - 'nav_compliance': '合规', + 'nav_issuers_review': '入驻审核', + 'nav_issuers_list': '发行方列表', + 'nav_issuers_coupons': '券审核', + 'nav_users_list': '用户列表', + 'nav_users_kyc': 'KYC审核', + 'nav_trading': '交易监控', + 'nav_trading_realtime': '实时交易流', + 'nav_trading_stats': '交易统计', + 'nav_trading_orders': '订单管理', + 'nav_risk': '风控中心', + 'nav_risk_dashboard': '风险仪表盘', + 'nav_risk_suspicious': '可疑交易', + 'nav_risk_blacklist': '黑名单管理', + 'nav_risk_ofac': 'OFAC筛查日志', + 'nav_finance': '财务管理', + 'nav_chain': '链上监控', + 'nav_reports': '报表中心', + 'nav_compliance': '合规报表', + 'nav_compliance_sar': 'SAR管理', + 'nav_compliance_ctr': 'CTR管理', + 'nav_compliance_audit': '审计日志', + 'nav_compliance_reports': '监管报表', 'nav_analytics': '数据分析', + 'nav_analytics_users': '用户分析', + 'nav_analytics_coupons': '券分析', + 'nav_analytics_market_maker': '做市商分析', + 'nav_analytics_consumer_protection': '消费者保护', 'nav_ai_agent': 'AI 代理', - 'nav_system': '系统设置', + 'nav_system': '系统管理', + 'nav_system_admins': '管理员账号', + 'nav_system_config': '系统配置', + 'nav_system_contracts': '合约管理', + 'nav_system_monitor': '系统监控', + 'nav_disputes': '争议处理', + 'nav_coupons_mgmt': '券管理', + 'nav_merchant': '商户核销', + 'nav_agent': '代理面板', 'nav_market_maker': '做市商', - 'nav_insurance': '保险', + 'nav_insurance': '保险管理', + + // ── Header ── + 'header_search_placeholder': '搜索用户/订单/交易...', + 'header_ai_assistant': 'AI 助手', // ── Dashboard ── - 'dashboard_title': '仪表盘', - 'dashboard_total_users': '总用户数', + 'dashboard_title': '运营总览', + 'dashboard_total_volume': '总交易量', + 'dashboard_total_amount': '交易金额', 'dashboard_active_users': '活跃用户', + 'dashboard_issuer_count': '发行方数量', + 'dashboard_coupon_circulation': '券流通总量', + 'dashboard_system_health': '系统健康', + 'dashboard_volume_trend': '交易量趋势', + 'dashboard_type_distribution': '交易类型占比', + 'dashboard_realtime_feed': '实时交易流', + 'dashboard_total_users': '总用户数', 'dashboard_total_coupons': '券总量', 'dashboard_trading_volume': '交易量', 'dashboard_revenue': '平台收入', @@ -77,10 +155,26 @@ const translations: Record> = { 'dashboard_monthly': '本月', 'dashboard_yearly': '本年', 'dashboard_real_time': '实时数据', - 'dashboard_system_health': '系统健康', 'dashboard_alerts': '告警', + 'dashboard_th_time': '时间', + 'dashboard_th_type': '类型', + 'dashboard_th_order': '订单号', + 'dashboard_th_amount': '金额', + 'dashboard_th_status': '状态', + 'dashboard_status_completed': '完成', + 'dashboard_status_processing': '处理中', + 'dashboard_type_purchase': '购买', + 'dashboard_type_redeem': '核销', + 'dashboard_type_resell': '转售', + 'dashboard_type_transfer': '转赠', + 'dashboard_service_api': 'API服务', + 'dashboard_service_db': '数据库', + 'dashboard_service_cache': '缓存服务', + 'dashboard_service_mq': '消息队列', // ── User Management ── + 'user_management_title': '用户管理', + 'user_search_placeholder': '搜索手机号/邮箱/用户ID...', 'user_list': '用户列表', 'user_detail': '用户详情', 'user_id': '用户ID', @@ -98,12 +192,39 @@ const translations: Record> = { 'user_consumer': '消费者', 'user_issuer': '发行方', 'user_admin': '管理员', + 'user_coupon_count': '持券数', + 'user_total_traded': '交易额', + 'user_risk_tags': '风险标签', - // ── Coupon Review ── + // ── Issuer Management ── + 'issuer_management_title': '发行方管理', + 'issuer_ai_pre_review': 'AI 预审', + 'issuer_list': '发行方列表', + 'issuer_detail': '发行方详情', + 'issuer_name': '名称', + 'issuer_company_name': '企业名称', + 'issuer_credit_rating': '信用评级', + 'issuer_onboarding_status': '入驻状态', + 'issuer_onboarding_pending': '待审核', + 'issuer_onboarding_approved': '已通过', + 'issuer_onboarding_rejected': '已驳回', + 'issuer_total_issued': '已发行总量', + 'issuer_total_redeemed': '已核销总量', + 'issuer_collateral': '质押品', + 'issuer_deposit': '保证金', + 'issuer_submit_time': '提交时间', + 'issuer_coupon_count': '券数量', + 'issuer_total_volume': '总发行额', + + // ── Coupon Management ── + 'coupon_management_title': '券管理', 'coupon_review': '券审核', 'coupon_pending_review': '待审核', 'coupon_approved': '已通过', 'coupon_rejected': '已拒绝', + 'coupon_active': '在售中', + 'coupon_suspended': '已暂停', + 'coupon_expired': '已过期', 'coupon_issuer': '发行方', 'coupon_face_value': '面值', 'coupon_quantity': '发行量', @@ -111,55 +232,64 @@ const translations: Record> = { 'coupon_category': '类别', 'coupon_risk_score': '风险评分', 'coupon_chain_status': '上链状态', - 'coupon_approve': '通过审核', - 'coupon_reject': '拒绝审核', + 'coupon_approve': '通过', + 'coupon_reject': '拒绝', 'coupon_review_comment': '审核意见', + 'coupon_id': '券ID', + 'coupon_name': '券名称', + 'coupon_template': '模板', + 'coupon_sold': '已售', + 'coupon_redeemed': '已核销', - // ── Issuer Management ── - 'issuer_list': '发行方列表', - 'issuer_detail': '发行方详情', - 'issuer_name': '名称', - 'issuer_credit_rating': '信用评级', - 'issuer_onboarding_status': '入驻状态', - 'issuer_onboarding_pending': '待审核', - 'issuer_onboarding_approved': '已入驻', - 'issuer_onboarding_rejected': '已拒绝', - 'issuer_total_issued': '已发行总量', - 'issuer_total_redeemed': '已核销总量', - 'issuer_collateral': '质押品', - 'issuer_deposit': '保证金', + // ── Trading Monitor ── + 'trading_title': '交易监控', + 'trading_today_volume': '今日交易量', + 'trading_today_amount': '今日交易额', + 'trading_avg_discount': '平均折扣率', + 'trading_large_trades': '大额交易', + 'trading_volume_trend': '交易量/金额趋势', + 'trading_order_management': '订单管理', + 'trading_search_order': '搜索订单号...', + 'trading_th_order_id': '订单号', + 'trading_th_type': '类型', + 'trading_th_coupon_name': '券名称', + 'trading_th_buyer': '买方', + 'trading_th_seller': '卖方', + 'trading_th_amount': '金额', + 'trading_th_status': '状态', + 'trading_th_time': '时间', + 'trading_type_purchase': '购买', + 'trading_type_resell': '转售', + 'trading_type_redeem': '核销', + 'trading_type_transfer': '转赠', + 'trading_status_completed': '完成', + 'trading_status_dispute': '争议', - // ── Finance ── - 'finance_overview': '财务概览', - 'finance_settlement': '结算管理', - 'finance_fee': '手续费', - 'finance_revenue': '收入', - 'finance_payout': '支出', - 'finance_reconciliation': '对账', - 'finance_invoice': '发票', - 'finance_tax': '税务', - 'finance_report': '财务报表', + // ── Risk Center ── + 'risk_title': '风控中心', + 'risk_ai_warning': 'AI 风险预警', + 'risk_events': '风险事件', + 'risk_suspicious_trades': '可疑交易', + 'risk_frozen_accounts': '冻结账户', + 'risk_ofac_hits': 'OFAC命中', + 'risk_th_trade_id': '交易ID', + 'risk_th_user': '用户', + 'risk_th_anomaly_type': '异常类型', + 'risk_th_amount': '金额', + 'risk_th_time': '时间', + 'risk_th_risk_score': '风险评分', + 'risk_type_high_freq': '高频交易', + 'risk_type_large_single': '大额单笔', + 'risk_type_related_account': '关联账户', + 'risk_type_abnormal_ip': '异常IP', - // ── Chain Monitor ── - 'chain_monitor': '链监控', - 'chain_block_height': '区块高度', - 'chain_tps': 'TPS', - 'chain_node_status': '节点状态', - 'chain_contracts': '智能合约', - 'chain_transactions': '链上交易', - 'chain_gas_usage': 'Gas 消耗', - 'chain_explorer': '区块浏览器', - - // ── Reports ── - 'report_list': '报表列表', - 'report_generate': '生成报表', - 'report_daily': '日报', - 'report_weekly': '周报', - 'report_monthly': '月报', - 'report_custom': '自定义报表', - 'report_download': '下载报表', - - // ── Compliance / Regulatory ── + // ── Compliance ── + 'compliance_title': '合规报表', + 'compliance_ai_generate': 'AI 生成报表', + 'compliance_tab_sar': 'SAR管理', + 'compliance_tab_ctr': 'CTR管理', + 'compliance_tab_audit': '审计日志', + 'compliance_tab_reports': '监管报表', 'compliance_overview': '合规概览', 'compliance_sec_filing': 'SEC 申报', 'compliance_license': '牌照管理', @@ -171,43 +301,42 @@ const translations: Record> = { 'compliance_risk_assessment': '风险评估', 'compliance_audit_log': '审计日志', 'compliance_policy': '合规政策', + 'compliance_sar_id': 'SAR编号', + 'compliance_sar_related_txn': '相关交易', + 'compliance_sar_user': '涉及用户', + 'compliance_sar_amount': '金额', + 'compliance_sar_risk_type': '风险类型', + 'compliance_sar_status': '状态', + 'compliance_sar_created': '创建时间', + 'compliance_sar_pending': '待提交', + 'compliance_sar_submitted': '已提交', + 'compliance_ctr_title': '大额交易报告', + 'compliance_ctr_desc': '超过$10,000的交易自动生成CTR,当前无待处理项', + 'compliance_audit_search': '搜索操作日志...', + 'compliance_audit_action_login': '登录', + 'compliance_audit_action_review': '审核', + 'compliance_audit_action_config': '配置', + 'compliance_audit_action_freeze': '冻结', + 'compliance_audit_action_export': '导出', + 'compliance_audit_action_query': '查询', + 'compliance_report_daily': '日报', + 'compliance_report_monthly': '月报', + 'compliance_report_sar_quarterly': '季度SAR汇总', + 'compliance_report_annual': '年度合规报告', - // ── Analytics ── - 'analytics_overview': '分析概览', - 'analytics_user_growth': '用户增长', - 'analytics_trading_volume': '交易量分析', - 'analytics_coupon_lifecycle': '券生命周期', - 'analytics_conversion': '转化率', - 'analytics_retention': '留存率', - 'analytics_heatmap': '热力图', - 'analytics_funnel': '漏斗分析', - 'analytics_cohort': '群组分析', - - // ── Market Maker ── - 'market_maker_list': '做市商列表', - 'market_maker_config': '做市商配置', - 'market_maker_spread': '价差', - 'market_maker_liquidity': '流动性', - 'market_maker_algorithm': '算法策略', - 'market_maker_pnl': '盈亏', - - // ── Insurance ── - 'insurance_pool': '保险池', - 'insurance_premium': '保费', - 'insurance_claim': '理赔', - 'insurance_coverage': '覆盖范围', - 'insurance_policy': '保险策略', - - // ── AI Agent ── - 'ai_agent_list': 'AI 代理列表', - 'ai_agent_config': 'AI 代理配置', - 'ai_agent_logs': 'AI 运行日志', - 'ai_agent_pricing': 'AI 定价引擎', - 'ai_agent_recommendation': 'AI 推荐引擎', - 'ai_agent_risk': 'AI 风控', - 'ai_agent_status': '运行状态', - - // ── System Settings ── + // ── System Management ── + 'system_title': '系统管理', + 'system_tab_admins': '管理员账号', + 'system_tab_config': '系统配置', + 'system_tab_contracts': '合约管理', + 'system_tab_monitor': '系统监控', + 'system_admin_list': '管理员列表', + 'system_add_admin': '+ 添加管理员', + 'system_th_account': '账号', + 'system_th_name': '姓名', + 'system_th_role': '角色', + 'system_th_last_login': '最后登录', + 'system_th_status': '状态', 'system_general': '通用设置', 'system_roles': '角色权限', 'system_api_keys': 'API 密钥', @@ -218,6 +347,387 @@ const translations: Record> = { 'system_logs': '系统日志', 'system_feature_flags': '功能开关', 'system_rate_limit': '限流配置', + 'system_fee_config': '手续费率设置', + 'system_kyc_config': 'KYC阈值配置', + 'system_trade_limit_config': '交易限额配置', + 'system_params': '系统参数', + 'system_contract_status': '智能合约状态', + 'system_running': '运行中', + 'system_health_check': '服务健康检查', + 'system_api_response': 'API 响应时间', + + // ── Disputes ── + 'dispute_title': '争议处理', + 'dispute_pending': '待处理', + 'dispute_processing': '处理中', + 'dispute_resolved_today': '今日解决', + 'dispute_resolved': '已解决', + 'dispute_rejected': '已驳回', + 'dispute_type_buyer': '买方申诉', + 'dispute_type_seller': '卖方申诉', + 'dispute_type_refund': '退款申请', + 'dispute_th_ticket_id': '工单号', + 'dispute_th_type': '类型', + 'dispute_th_order': '关联订单', + 'dispute_th_plaintiff': '申诉方', + 'dispute_th_defendant': '被诉方', + 'dispute_th_amount': '金额', + 'dispute_th_status': '状态', + 'dispute_th_sla': '处理时效', + 'dispute_th_created': '创建时间', + + // ── Finance Management ── + 'finance_title': '财务管理', + 'finance_platform_fee': '平台手续费收入', + 'finance_pending_settlement': '待结算给发行方', + 'finance_consumer_refund': '消费者退款', + 'finance_pool_balance': '资金池余额', + 'finance_settlement_queue': '结算队列', + 'finance_revenue_trend': '收入趋势', + 'finance_th_issuer': '发行方', + 'finance_th_amount': '金额', + 'finance_th_status': '状态', + 'finance_th_time': '时间', + 'finance_status_settled': '已结算', + 'finance_status_processing': '处理中', + 'finance_status_pending': '待结算', + 'finance_overview': '财务概览', + 'finance_settlement': '结算管理', + 'finance_fee': '手续费', + 'finance_revenue': '收入', + 'finance_payout': '支出', + 'finance_reconciliation': '对账', + 'finance_invoice': '发票', + 'finance_tax': '税务', + 'finance_report': '财务报表', + 'finance_period_month': '本月', + 'finance_period_cumulative': '累计', + 'finance_period_realtime': '实时', + + // ── Chain Monitor ── + 'chain_title': '链上监控', + 'chain_recent_events': '最近链上事件', + 'chain_gas_monitor': 'Gas费监控', + 'chain_current_gas': '当前Gas', + 'chain_today_avg': '今日均值', + 'chain_today_gas_spend': '今日Gas支出', + 'chain_monitor': '链监控', + 'chain_block_height': '区块高度', + 'chain_tps': 'TPS', + 'chain_node_status': '节点状态', + 'chain_contracts': '智能合约', + 'chain_transactions': '链上交易', + 'chain_gas_usage': 'Gas 消耗', + 'chain_explorer': '区块浏览器', + + // ── Reports ── + 'reports_title': '报表中心', + 'reports_operations': '运营报表', + 'reports_compliance': '合规报表', + 'reports_financial': '财务报表', + 'reports_audit': '审计报表', + 'reports_status_generated': '已生成', + 'reports_status_submitted': '已提交', + 'reports_status_passed': '已通过', + 'reports_status_pending_review': '待审核', + 'reports_status_pending_generate': '待生成', + 'report_list': '报表列表', + 'report_generate': '生成报表', + 'report_daily': '日报', + 'report_weekly': '周报', + 'report_monthly': '月报', + 'report_custom': '自定义报表', + 'report_download': '下载报表', + + // ── Merchant Redemption ── + 'merchant_title': '商户核销管理', + 'merchant_today_redemption': '今日核销', + 'merchant_today_amount': '今日核销金额', + 'merchant_active_stores': '活跃门店', + 'merchant_abnormal_redemption': '异常核销', + 'merchant_store_ranking': '门店核销排行', + 'merchant_realtime_feed': '实时核销流', + 'merchant_need_review': '需审核', + 'merchant_unit_count': '笔', + + // ── Agent Panel ── + 'agent_title': 'AI Agent 管理', + 'agent_today_sessions': '今日会话数', + 'agent_avg_response': '平均响应时间', + 'agent_satisfaction': '用户满意度', + 'agent_human_takeover': '人工接管率', + 'agent_top_questions': '热门问题 Top 5', + 'agent_modules': 'Agent 模块', + 'agent_running': '运行中', + 'agent_unit_times': '次', + + // ── Insurance ── + 'insurance_title': '保险与消费者保护', + 'insurance_protection_fund': '消费者保护基金', + 'insurance_monthly_payout': '本月赔付', + 'insurance_payout_rate': '赔付率', + 'insurance_ipo_readiness': 'IPO准备度', + 'insurance_recent_claims': '最近赔付记录', + 'insurance_th_id': '编号', + 'insurance_th_user': '用户', + 'insurance_th_reason': '原因', + 'insurance_th_amount': '金额', + 'insurance_th_status': '状态', + 'insurance_status_paid': '已赔付', + 'insurance_status_processing': '处理中', + 'insurance_ipo_checklist': 'IPO准备度检查清单', + 'insurance_pool': '保险池', + 'insurance_premium': '保费', + 'insurance_claim': '理赔', + 'insurance_coverage': '覆盖范围', + 'insurance_policy': '保险策略', + + // ── SEC Filing ── + 'sec_title': 'SEC文件管理', + 'sec_new_filing': '+ 新建Filing', + 'sec_filed_count': '已提交文件数', + 'sec_pending_review': '待审核', + 'sec_passed': '已通过', + 'sec_next_deadline': '距下次截止', + 'sec_filing_list': 'SEC申报文件列表', + 'sec_th_id': '编号', + 'sec_th_form_type': '表格类型', + 'sec_th_title': '标题', + 'sec_th_filing_date': '提交日期', + 'sec_th_deadline': '截止日期', + 'sec_th_reviewer': '审核方', + 'sec_th_status': '状态', + 'sec_status_reviewing': '审核中', + 'sec_status_submitted': '已提交', + 'sec_status_passed': '已通过', + 'sec_status_needs_revision': '需修订', + 'sec_status_pending': '待提交', + 'sec_timeline': '申报日程', + 'sec_upcoming': '即将到期', + 'sec_disclosure_status': '披露文件自动生成状态', + 'sec_disclosure_progress': '披露文件完成度', + + // ── License Management ── + 'license_title': '牌照与监管许可管理', + 'license_new': '+ 新增牌照申请', + 'license_active_count': '活跃牌照数', + 'license_pending': '待申请', + 'license_expiring_soon': '即将到期', + 'license_revoked': '已吊销', + 'license_list': '牌照清单', + 'license_th_id': '编号', + 'license_th_name': '牌照名称', + 'license_th_jurisdiction': '司法管辖区', + 'license_th_reg_body': '监管机构', + 'license_th_issue_date': '签发日期', + 'license_th_expiry_date': '到期日期', + 'license_th_status': '状态', + 'license_status_active': '有效', + 'license_status_applying': '申请中', + 'license_status_renewal': '待续期', + 'license_status_expiring': '即将到期', + 'license_status_expired': '已过期', + 'license_reg_body_mapping': '监管机构映射', + 'license_renewal_alerts': '续期提醒', + 'license_unit': '牌照', + 'license_jurisdictions_covered': '个有效牌照覆盖 {0} 个司法管辖区', + + // ── SOX Compliance ── + 'sox_title': 'SOX合规管理', + 'sox_overall_score': '整体合规评分', + 'sox_full_score': '满分 100', + 'sox_total_controls': '总控制点', + 'sox_test_passed': '测试通过', + 'sox_defects_found': '发现缺陷', + 'sox_pending_test': '待测试', + 'sox_control_categories': '内部控制类别', + 'sox_th_control_point': '控制点', + 'sox_th_test_result': '测试结果', + 'sox_th_last_test': '上次测试', + 'sox_th_next_test': '下次测试', + 'sox_result_passed': '通过', + 'sox_result_defect': '发现缺陷', + 'sox_result_pending': '待测试', + 'sox_deficiency_tracking': '缺陷追踪', + 'sox_th_id': '编号', + 'sox_th_control': '控制点', + 'sox_th_severity': '严重程度', + 'sox_th_description': '描述', + 'sox_th_due_date': '整改期限', + 'sox_th_status': '状态', + 'sox_th_owner': '负责方', + 'sox_severity_major': '重大缺陷', + 'sox_severity_minor': '一般缺陷', + 'sox_severity_observation': '观察项', + 'sox_status_remediating': '整改中', + 'sox_status_pending': '待整改', + 'sox_auditor_progress': '审计师审核进度', + 'sox_audit_progress': '审计进度', + + // ── Tax Compliance ── + 'tax_title': '税务合规管理', + 'tax_export_report': '导出税务报告', + 'tax_payable': '应纳税额', + 'tax_paid': '已缴税额', + 'tax_compliance_rate': '税务合规率', + 'tax_pending_items': '待处理事项', + 'tax_obligations': '各司法管辖区税务义务', + 'tax_th_jurisdiction': '管辖区', + 'tax_th_type': '税种', + 'tax_th_period': '期间', + 'tax_th_payable': '应缴金额', + 'tax_th_paid': '已缴金额', + 'tax_th_deadline': '截止日期', + 'tax_th_status': '状态', + 'tax_status_paid': '已缴', + 'tax_status_partial': '部分缴纳', + 'tax_status_unpaid': '待缴', + 'tax_type_breakdown': '税种分类汇总', + 'tax_th_tax_type': '税种', + 'tax_th_federal': '联邦', + 'tax_th_state': '州级', + 'tax_th_total': '合计', + 'tax_th_percentage': '占比', + 'tax_calendar': '税务日历', + 'tax_status_done': '已完成', + 'tax_status_pending': '待处理', + 'tax_irs_tracker': 'IRS表格提交追踪', + 'tax_th_form': '表格', + 'tax_th_description': '说明', + 'tax_th_tax_year': '税务年度', + 'tax_th_filed_date': '提交日期', + 'tax_filing_submitted': '已提交', + 'tax_filing_preparing': '准备中', + 'tax_filing_on_demand': '按需提交', + 'tax_filing_overdue': '逾期', + + // ── IPO Readiness ── + 'ipo_title': 'IPO准备度检查清单', + 'ipo_subtitle': '跟踪所有IPO里程碑、合规项、依赖关系和阻塞项', + 'ipo_total_items': '总计检查项', + 'ipo_overall_progress': '总体IPO准备进度', + 'ipo_cat_legal': '法律合规', + 'ipo_cat_financial': '财务审计', + 'ipo_cat_sox': 'SOX合规', + 'ipo_cat_governance': '公司治理', + 'ipo_cat_insurance': '保险保障', + 'ipo_th_id': '编号', + 'ipo_th_item': '检查项', + 'ipo_th_owner': '负责方', + 'ipo_th_deadline': '截止日', + 'ipo_th_status': '状态', + 'ipo_unit_done': '完成', + 'ipo_dependency': '依赖', + 'ipo_timeline': 'IPO时间线', + 'ipo_blockers': '阻塞项', + 'ipo_category_progress': '分类进度', + 'ipo_key_contacts': '关键联系方', + 'ipo_owner': '负责', + 'ipo_deadline': '截止', + + // ── User Analytics ── + 'ua_title': '用户分析', + 'ua_total_users': '总用户数', + 'ua_new_users_week': '新增用户/周', + 'ua_growth_trend': '用户增长趋势', + 'ua_kyc_distribution': 'KYC等级分布', + 'ua_geo_distribution': '地理分布 (Top 10)', + 'ua_th_rank': '排名', + 'ua_th_region': '地区', + 'ua_th_users': '用户数', + 'ua_th_percent': '占比', + 'ua_retention_matrix': '用户留存矩阵', + 'ua_th_cohort': '注册周', + 'ua_user_segments': '活跃用户分群', + 'ua_segment_high_freq': '高频交易', + 'ua_segment_occasional': '偶尔购买', + 'ua_segment_browse': '仅浏览', + 'ua_segment_churned': '流失用户', + 'ua_unit_people': '人', + + // ── Coupon Analytics ── + 'ca_title': '券分析', + 'ca_total_coupons': '券总量', + 'ca_active_coupons': '活跃券', + 'ca_redeemed': '已核销', + 'ca_expiring_soon': '即将过期', + 'ca_category_distribution': '品类分布', + 'ca_face_value_distribution': '面值分布', + 'ca_top_selling': '热销券 Top 10', + 'ca_th_rank': '排名', + 'ca_th_brand': '品牌', + 'ca_th_coupon_name': '券名称', + 'ca_th_sales': '销量', + 'ca_th_revenue': '收入', + 'ca_th_rating': '评分', + 'ca_breakage_trend': 'Breakage趋势 (未核销率)', + 'ca_secondary_market': '二级市场分析', + + // ── Market Maker ── + 'mm_title': '做市商管理', + 'mm_add_new': '新增做市商', + 'mm_active_makers': '活跃做市商', + 'mm_total_liquidity': '总流动性', + 'mm_daily_volume': '日均交易量', + 'mm_avg_spread': '平均价差', + 'mm_th_name': '做市商', + 'mm_th_status': '状态', + 'mm_th_daily_volume': '日交易量', + 'mm_status_active': '活跃', + 'mm_status_paused': '暂停', + 'mm_status_suspended': '停用', + 'mm_liquidity_pools': '流动性池分布', + 'mm_order_book_depth': '订单簿深度', + 'mm_health_indicators': '市场健康指标', + 'mm_risk_alerts': '风险预警', + 'mm_high_risk': '高风险', + 'mm_unit_makers': '做市商', + 'market_maker_list': '做市商列表', + 'market_maker_config': '做市商配置', + 'market_maker_spread': '价差', + 'market_maker_liquidity': '流动性', + 'market_maker_algorithm': '算法策略', + 'market_maker_pnl': '盈亏', + + // ── Consumer Protection ── + 'cp_title': '消费者保护', + 'cp_total_complaints': '投诉总数', + 'cp_resolved': '已解决', + 'cp_processing': '处理中', + 'cp_avg_resolution_time': '平均解决时间', + 'cp_complaint_categories': '投诉分类', + 'cp_cat_redeem_fail': '核销失败', + 'cp_cat_refund_dispute': '退款纠纷', + 'cp_cat_fake_coupon': '虚假券', + 'cp_cat_other': '其他', + 'cp_csat': '消费者满意度 (CSAT)', + 'cp_protection_fund': '保障基金使用率', + 'cp_recent_complaints': '近期投诉', + 'cp_search_complaints': '搜索投诉...', + 'cp_th_id': '编号', + 'cp_th_severity': '严重度', + 'cp_th_category': '分类', + 'cp_th_description': '描述', + 'cp_th_status': '状态', + 'cp_th_assignee': '负责人', + 'cp_th_date': '日期', + 'cp_refund_compliance': '退款合规 - 不合规发行方 Top 5', + 'cp_th_rank': '排名', + 'cp_th_issuer': '发行方', + 'cp_th_violations': '违规次数', + 'cp_th_refund_rate': '退款通过率', + 'cp_th_avg_delay': '平均处理延迟', + 'cp_th_risk_level': '风险等级', + 'cp_unit_cases': '件', + + // ── AI Agent ── + 'ai_agent_list': 'AI 代理列表', + 'ai_agent_config': 'AI 代理配置', + 'ai_agent_logs': 'AI 运行日志', + 'ai_agent_pricing': 'AI 定价引擎', + 'ai_agent_recommendation': 'AI 推荐引擎', + 'ai_agent_risk': 'AI 风控', + 'ai_agent_status': '运行状态', }, 'en-US': { @@ -248,6 +758,42 @@ const translations: Record> = { 'total': 'Total', 'yes': 'Yes', 'no': 'No', + 'all': 'All', + 'view': 'View', + 'process': 'Process', + 'download': 'Download', + 'collapse': 'Collapse', + 'time': 'Time', + 'amount': 'Amount', + 'type': 'Type', + 'mark': 'Mark', + 'review': 'Review', + 'suspend': 'Suspend', + 'resume': 'Resume', + 'warning_label': 'Warn', + 'investigate': 'Investigate', + 'completed': 'Completed', + 'in_progress': 'In Progress', + 'pending': 'Pending', + 'blocked': 'Blocked', + 'custom_export': 'Custom Export', + 'export_report': 'Export Report', + 'auto_generated': 'Auto Generated', + 'as_of': 'As of', + 'generating': 'Generating', + 'accuracy': 'Accuracy', + 'overall_progress': 'Overall Progress', + 'renew_now': 'Renew Now', + 'not_applied': 'Not Applied', + 'urgency_critical': 'Critical', + 'urgency_high': 'High', + 'urgency_medium': 'Medium', + 'urgency_low': 'Low', + 'expiry_date': 'Expiry', + 'remaining_days': '{0} days left', + 'severity_high': 'High', + 'severity_medium': 'Medium', + 'severity_low': 'Low', // ── Sidebar / Navigation ── 'nav_dashboard': 'Dashboard', @@ -255,20 +801,62 @@ const translations: Record> = { 'nav_users': 'User Management', 'nav_coupons': 'Coupon Review', 'nav_issuers': 'Issuer Management', + 'nav_issuers_review': 'Onboarding Review', + 'nav_issuers_list': 'Issuer List', + 'nav_issuers_coupons': 'Coupon Review', + 'nav_users_list': 'User List', + 'nav_users_kyc': 'KYC Review', + 'nav_trading': 'Trading Monitor', + 'nav_trading_realtime': 'Real-time Feed', + 'nav_trading_stats': 'Trading Stats', + 'nav_trading_orders': 'Order Management', + 'nav_risk': 'Risk Center', + 'nav_risk_dashboard': 'Risk Dashboard', + 'nav_risk_suspicious': 'Suspicious Trades', + 'nav_risk_blacklist': 'Blacklist', + 'nav_risk_ofac': 'OFAC Screening Log', 'nav_finance': 'Finance', 'nav_chain': 'Chain Monitor', 'nav_reports': 'Reports', 'nav_compliance': 'Compliance', + 'nav_compliance_sar': 'SAR Management', + 'nav_compliance_ctr': 'CTR Management', + 'nav_compliance_audit': 'Audit Log', + 'nav_compliance_reports': 'Regulatory Reports', 'nav_analytics': 'Analytics', + 'nav_analytics_users': 'User Analytics', + 'nav_analytics_coupons': 'Coupon Analytics', + 'nav_analytics_market_maker': 'Market Maker Analytics', + 'nav_analytics_consumer_protection': 'Consumer Protection', 'nav_ai_agent': 'AI Agent', - 'nav_system': 'System Settings', + 'nav_system': 'System', + 'nav_system_admins': 'Admin Accounts', + 'nav_system_config': 'System Config', + 'nav_system_contracts': 'Contract Management', + 'nav_system_monitor': 'System Monitor', + 'nav_disputes': 'Disputes', + 'nav_coupons_mgmt': 'Coupon Management', + 'nav_merchant': 'Merchant Redemption', + 'nav_agent': 'Agent Panel', 'nav_market_maker': 'Market Maker', 'nav_insurance': 'Insurance', + // ── Header ── + 'header_search_placeholder': 'Search users/orders/trades...', + 'header_ai_assistant': 'AI Assistant', + // ── Dashboard ── 'dashboard_title': 'Dashboard', - 'dashboard_total_users': 'Total Users', + 'dashboard_total_volume': 'Total Volume', + 'dashboard_total_amount': 'Total Amount', 'dashboard_active_users': 'Active Users', + 'dashboard_issuer_count': 'Issuers', + 'dashboard_coupon_circulation': 'Coupons in Circulation', + 'dashboard_system_health': 'System Health', + 'dashboard_volume_trend': 'Volume Trend', + 'dashboard_type_distribution': 'Trade Type Distribution', + 'dashboard_realtime_feed': 'Real-time Feed', + 'dashboard_total_users': 'Total Users', 'dashboard_total_coupons': 'Total Coupons', 'dashboard_trading_volume': 'Trading Volume', 'dashboard_revenue': 'Platform Revenue', @@ -277,10 +865,26 @@ const translations: Record> = { 'dashboard_monthly': 'This Month', 'dashboard_yearly': 'This Year', 'dashboard_real_time': 'Real-time Data', - 'dashboard_system_health': 'System Health', 'dashboard_alerts': 'Alerts', + 'dashboard_th_time': 'Time', + 'dashboard_th_type': 'Type', + 'dashboard_th_order': 'Order', + 'dashboard_th_amount': 'Amount', + 'dashboard_th_status': 'Status', + 'dashboard_status_completed': 'Completed', + 'dashboard_status_processing': 'Processing', + 'dashboard_type_purchase': 'Purchase', + 'dashboard_type_redeem': 'Redeem', + 'dashboard_type_resell': 'Resell', + 'dashboard_type_transfer': 'Transfer', + 'dashboard_service_api': 'API Service', + 'dashboard_service_db': 'Database', + 'dashboard_service_cache': 'Cache Service', + 'dashboard_service_mq': 'Message Queue', // ── User Management ── + 'user_management_title': 'User Management', + 'user_search_placeholder': 'Search phone/email/user ID...', 'user_list': 'User List', 'user_detail': 'User Details', 'user_id': 'User ID', @@ -298,12 +902,39 @@ const translations: Record> = { 'user_consumer': 'Consumer', 'user_issuer': 'Issuer', 'user_admin': 'Admin', + 'user_coupon_count': 'Coupons', + 'user_total_traded': 'Traded', + 'user_risk_tags': 'Risk Tags', - // ── Coupon Review ── + // ── Issuer Management ── + 'issuer_management_title': 'Issuer Management', + 'issuer_ai_pre_review': 'AI Pre-review', + 'issuer_list': 'Issuer List', + 'issuer_detail': 'Issuer Details', + 'issuer_name': 'Name', + 'issuer_company_name': 'Company Name', + 'issuer_credit_rating': 'Credit Rating', + 'issuer_onboarding_status': 'Onboarding Status', + 'issuer_onboarding_pending': 'Pending', + 'issuer_onboarding_approved': 'Approved', + 'issuer_onboarding_rejected': 'Rejected', + 'issuer_total_issued': 'Total Issued', + 'issuer_total_redeemed': 'Total Redeemed', + 'issuer_collateral': 'Collateral', + 'issuer_deposit': 'Deposit', + 'issuer_submit_time': 'Submitted', + 'issuer_coupon_count': 'Coupons', + 'issuer_total_volume': 'Total Volume', + + // ── Coupon Management ── + 'coupon_management_title': 'Coupon Management', 'coupon_review': 'Coupon Review', 'coupon_pending_review': 'Pending Review', 'coupon_approved': 'Approved', 'coupon_rejected': 'Rejected', + 'coupon_active': 'Active', + 'coupon_suspended': 'Suspended', + 'coupon_expired': 'Expired', 'coupon_issuer': 'Issuer', 'coupon_face_value': 'Face Value', 'coupon_quantity': 'Quantity', @@ -314,52 +945,61 @@ const translations: Record> = { 'coupon_approve': 'Approve', 'coupon_reject': 'Reject', 'coupon_review_comment': 'Review Comment', + 'coupon_id': 'Coupon ID', + 'coupon_name': 'Coupon Name', + 'coupon_template': 'Template', + 'coupon_sold': 'Sold', + 'coupon_redeemed': 'Redeemed', - // ── Issuer Management ── - 'issuer_list': 'Issuer List', - 'issuer_detail': 'Issuer Details', - 'issuer_name': 'Name', - 'issuer_credit_rating': 'Credit Rating', - 'issuer_onboarding_status': 'Onboarding Status', - 'issuer_onboarding_pending': 'Pending', - 'issuer_onboarding_approved': 'Approved', - 'issuer_onboarding_rejected': 'Rejected', - 'issuer_total_issued': 'Total Issued', - 'issuer_total_redeemed': 'Total Redeemed', - 'issuer_collateral': 'Collateral', - 'issuer_deposit': 'Deposit', + // ── Trading Monitor ── + 'trading_title': 'Trading Monitor', + 'trading_today_volume': 'Today Volume', + 'trading_today_amount': 'Today Amount', + 'trading_avg_discount': 'Avg Discount', + 'trading_large_trades': 'Large Trades', + 'trading_volume_trend': 'Volume/Amount Trend', + 'trading_order_management': 'Order Management', + 'trading_search_order': 'Search order ID...', + 'trading_th_order_id': 'Order ID', + 'trading_th_type': 'Type', + 'trading_th_coupon_name': 'Coupon', + 'trading_th_buyer': 'Buyer', + 'trading_th_seller': 'Seller', + 'trading_th_amount': 'Amount', + 'trading_th_status': 'Status', + 'trading_th_time': 'Time', + 'trading_type_purchase': 'Purchase', + 'trading_type_resell': 'Resell', + 'trading_type_redeem': 'Redeem', + 'trading_type_transfer': 'Transfer', + 'trading_status_completed': 'Completed', + 'trading_status_dispute': 'Dispute', - // ── Finance ── - 'finance_overview': 'Finance Overview', - 'finance_settlement': 'Settlement', - 'finance_fee': 'Fees', - 'finance_revenue': 'Revenue', - 'finance_payout': 'Payouts', - 'finance_reconciliation': 'Reconciliation', - 'finance_invoice': 'Invoices', - 'finance_tax': 'Tax', - 'finance_report': 'Financial Report', + // ── Risk Center ── + 'risk_title': 'Risk Center', + 'risk_ai_warning': 'AI Risk Alert', + 'risk_events': 'Risk Events', + 'risk_suspicious_trades': 'Suspicious Trades', + 'risk_frozen_accounts': 'Frozen Accounts', + 'risk_ofac_hits': 'OFAC Hits', + 'risk_th_trade_id': 'Trade ID', + 'risk_th_user': 'User', + 'risk_th_anomaly_type': 'Anomaly Type', + 'risk_th_amount': 'Amount', + 'risk_th_time': 'Time', + 'risk_th_risk_score': 'Risk Score', + 'risk_type_high_freq': 'High Frequency', + 'risk_type_large_single': 'Large Single', + 'risk_type_related_account': 'Related Account', + 'risk_type_abnormal_ip': 'Abnormal IP', - // ── Chain Monitor ── - 'chain_monitor': 'Chain Monitor', - 'chain_block_height': 'Block Height', - 'chain_tps': 'TPS', - 'chain_node_status': 'Node Status', - 'chain_contracts': 'Smart Contracts', - 'chain_transactions': 'On-chain Transactions', - 'chain_gas_usage': 'Gas Usage', - 'chain_explorer': 'Block Explorer', - - // ── Reports ── - 'report_list': 'Report List', - 'report_generate': 'Generate Report', - 'report_daily': 'Daily Report', - 'report_weekly': 'Weekly Report', - 'report_monthly': 'Monthly Report', - 'report_custom': 'Custom Report', - 'report_download': 'Download Report', - - // ── Compliance / Regulatory ── + // ── Compliance ── + 'compliance_title': 'Compliance Reports', + 'compliance_ai_generate': 'AI Generate Report', + 'compliance_tab_sar': 'SAR Management', + 'compliance_tab_ctr': 'CTR Management', + 'compliance_tab_audit': 'Audit Log', + 'compliance_tab_reports': 'Regulatory Reports', 'compliance_overview': 'Compliance Overview', 'compliance_sec_filing': 'SEC Filing', 'compliance_license': 'License Management', @@ -371,43 +1011,42 @@ const translations: Record> = { 'compliance_risk_assessment': 'Risk Assessment', 'compliance_audit_log': 'Audit Log', 'compliance_policy': 'Compliance Policy', + 'compliance_sar_id': 'SAR ID', + 'compliance_sar_related_txn': 'Related Txn', + 'compliance_sar_user': 'User', + 'compliance_sar_amount': 'Amount', + 'compliance_sar_risk_type': 'Risk Type', + 'compliance_sar_status': 'Status', + 'compliance_sar_created': 'Created', + 'compliance_sar_pending': 'Pending', + 'compliance_sar_submitted': 'Submitted', + 'compliance_ctr_title': 'Large Transaction Report', + 'compliance_ctr_desc': 'Transactions over $10,000 auto-generate CTR. No pending items.', + 'compliance_audit_search': 'Search audit log...', + 'compliance_audit_action_login': 'Login', + 'compliance_audit_action_review': 'Review', + 'compliance_audit_action_config': 'Config', + 'compliance_audit_action_freeze': 'Freeze', + 'compliance_audit_action_export': 'Export', + 'compliance_audit_action_query': 'Query', + 'compliance_report_daily': 'Daily', + 'compliance_report_monthly': 'Monthly', + 'compliance_report_sar_quarterly': 'Quarterly SAR Summary', + 'compliance_report_annual': 'Annual Compliance Report', - // ── Analytics ── - 'analytics_overview': 'Analytics Overview', - 'analytics_user_growth': 'User Growth', - 'analytics_trading_volume': 'Trading Volume Analysis', - 'analytics_coupon_lifecycle': 'Coupon Lifecycle', - 'analytics_conversion': 'Conversion Rate', - 'analytics_retention': 'Retention Rate', - 'analytics_heatmap': 'Heatmap', - 'analytics_funnel': 'Funnel Analysis', - 'analytics_cohort': 'Cohort Analysis', - - // ── Market Maker ── - 'market_maker_list': 'Market Makers', - 'market_maker_config': 'Market Maker Config', - 'market_maker_spread': 'Spread', - 'market_maker_liquidity': 'Liquidity', - 'market_maker_algorithm': 'Algorithm Strategy', - 'market_maker_pnl': 'P&L', - - // ── Insurance ── - 'insurance_pool': 'Insurance Pool', - 'insurance_premium': 'Premium', - 'insurance_claim': 'Claims', - 'insurance_coverage': 'Coverage', - 'insurance_policy': 'Insurance Policy', - - // ── AI Agent ── - 'ai_agent_list': 'AI Agent List', - 'ai_agent_config': 'AI Agent Config', - 'ai_agent_logs': 'AI Execution Logs', - 'ai_agent_pricing': 'AI Pricing Engine', - 'ai_agent_recommendation': 'AI Recommendation Engine', - 'ai_agent_risk': 'AI Risk Control', - 'ai_agent_status': 'Running Status', - - // ── System Settings ── + // ── System Management ── + 'system_title': 'System Management', + 'system_tab_admins': 'Admin Accounts', + 'system_tab_config': 'System Config', + 'system_tab_contracts': 'Contract Management', + 'system_tab_monitor': 'System Monitor', + 'system_admin_list': 'Admin List', + 'system_add_admin': '+ Add Admin', + 'system_th_account': 'Account', + 'system_th_name': 'Name', + 'system_th_role': 'Role', + 'system_th_last_login': 'Last Login', + 'system_th_status': 'Status', 'system_general': 'General Settings', 'system_roles': 'Roles & Permissions', 'system_api_keys': 'API Keys', @@ -418,6 +1057,387 @@ const translations: Record> = { 'system_logs': 'System Logs', 'system_feature_flags': 'Feature Flags', 'system_rate_limit': 'Rate Limiting', + 'system_fee_config': 'Fee Rate Settings', + 'system_kyc_config': 'KYC Threshold Config', + 'system_trade_limit_config': 'Trade Limit Config', + 'system_params': 'System Parameters', + 'system_contract_status': 'Smart Contract Status', + 'system_running': 'Running', + 'system_health_check': 'Service Health Check', + 'system_api_response': 'API Response Time', + + // ── Disputes ── + 'dispute_title': 'Dispute Resolution', + 'dispute_pending': 'Pending', + 'dispute_processing': 'Processing', + 'dispute_resolved_today': 'Resolved Today', + 'dispute_resolved': 'Resolved', + 'dispute_rejected': 'Rejected', + 'dispute_type_buyer': 'Buyer Complaint', + 'dispute_type_seller': 'Seller Complaint', + 'dispute_type_refund': 'Refund Request', + 'dispute_th_ticket_id': 'Ticket ID', + 'dispute_th_type': 'Type', + 'dispute_th_order': 'Related Order', + 'dispute_th_plaintiff': 'Plaintiff', + 'dispute_th_defendant': 'Defendant', + 'dispute_th_amount': 'Amount', + 'dispute_th_status': 'Status', + 'dispute_th_sla': 'SLA', + 'dispute_th_created': 'Created', + + // ── Finance Management ── + 'finance_title': 'Finance Management', + 'finance_platform_fee': 'Platform Fee Revenue', + 'finance_pending_settlement': 'Pending Settlement', + 'finance_consumer_refund': 'Consumer Refunds', + 'finance_pool_balance': 'Fund Pool Balance', + 'finance_settlement_queue': 'Settlement Queue', + 'finance_revenue_trend': 'Revenue Trend', + 'finance_th_issuer': 'Issuer', + 'finance_th_amount': 'Amount', + 'finance_th_status': 'Status', + 'finance_th_time': 'Time', + 'finance_status_settled': 'Settled', + 'finance_status_processing': 'Processing', + 'finance_status_pending': 'Pending', + 'finance_overview': 'Finance Overview', + 'finance_settlement': 'Settlement', + 'finance_fee': 'Fees', + 'finance_revenue': 'Revenue', + 'finance_payout': 'Payouts', + 'finance_reconciliation': 'Reconciliation', + 'finance_invoice': 'Invoices', + 'finance_tax': 'Tax', + 'finance_report': 'Financial Report', + 'finance_period_month': 'This Month', + 'finance_period_cumulative': 'Cumulative', + 'finance_period_realtime': 'Real-time', + + // ── Chain Monitor ── + 'chain_title': 'Chain Monitor', + 'chain_recent_events': 'Recent On-chain Events', + 'chain_gas_monitor': 'Gas Fee Monitor', + 'chain_current_gas': 'Current Gas', + 'chain_today_avg': 'Today Avg', + 'chain_today_gas_spend': 'Today Gas Spend', + 'chain_monitor': 'Chain Monitor', + 'chain_block_height': 'Block Height', + 'chain_tps': 'TPS', + 'chain_node_status': 'Node Status', + 'chain_contracts': 'Smart Contracts', + 'chain_transactions': 'On-chain Transactions', + 'chain_gas_usage': 'Gas Usage', + 'chain_explorer': 'Block Explorer', + + // ── Reports ── + 'reports_title': 'Report Center', + 'reports_operations': 'Operations Reports', + 'reports_compliance': 'Compliance Reports', + 'reports_financial': 'Financial Reports', + 'reports_audit': 'Audit Reports', + 'reports_status_generated': 'Generated', + 'reports_status_submitted': 'Submitted', + 'reports_status_passed': 'Passed', + 'reports_status_pending_review': 'Pending Review', + 'reports_status_pending_generate': 'Pending', + 'report_list': 'Report List', + 'report_generate': 'Generate Report', + 'report_daily': 'Daily Report', + 'report_weekly': 'Weekly Report', + 'report_monthly': 'Monthly Report', + 'report_custom': 'Custom Report', + 'report_download': 'Download Report', + + // ── Merchant Redemption ── + 'merchant_title': 'Merchant Redemption', + 'merchant_today_redemption': 'Today Redemptions', + 'merchant_today_amount': 'Today Amount', + 'merchant_active_stores': 'Active Stores', + 'merchant_abnormal_redemption': 'Abnormal Redemptions', + 'merchant_store_ranking': 'Store Ranking', + 'merchant_realtime_feed': 'Real-time Feed', + 'merchant_need_review': 'Needs Review', + 'merchant_unit_count': 'txns', + + // ── Agent Panel ── + 'agent_title': 'AI Agent Management', + 'agent_today_sessions': 'Today Sessions', + 'agent_avg_response': 'Avg Response Time', + 'agent_satisfaction': 'User Satisfaction', + 'agent_human_takeover': 'Human Takeover Rate', + 'agent_top_questions': 'Top Questions', + 'agent_modules': 'Agent Modules', + 'agent_running': 'Running', + 'agent_unit_times': 'times', + + // ── Insurance ── + 'insurance_title': 'Insurance & Consumer Protection', + 'insurance_protection_fund': 'Consumer Protection Fund', + 'insurance_monthly_payout': 'Monthly Payouts', + 'insurance_payout_rate': 'Payout Rate', + 'insurance_ipo_readiness': 'IPO Readiness', + 'insurance_recent_claims': 'Recent Claims', + 'insurance_th_id': 'ID', + 'insurance_th_user': 'User', + 'insurance_th_reason': 'Reason', + 'insurance_th_amount': 'Amount', + 'insurance_th_status': 'Status', + 'insurance_status_paid': 'Paid', + 'insurance_status_processing': 'Processing', + 'insurance_ipo_checklist': 'IPO Readiness Checklist', + 'insurance_pool': 'Insurance Pool', + 'insurance_premium': 'Premium', + 'insurance_claim': 'Claims', + 'insurance_coverage': 'Coverage', + 'insurance_policy': 'Insurance Policy', + + // ── SEC Filing ── + 'sec_title': 'SEC Filing Management', + 'sec_new_filing': '+ New Filing', + 'sec_filed_count': 'Filed Documents', + 'sec_pending_review': 'Pending Review', + 'sec_passed': 'Approved', + 'sec_next_deadline': 'Next Deadline', + 'sec_filing_list': 'SEC Filing List', + 'sec_th_id': 'ID', + 'sec_th_form_type': 'Form Type', + 'sec_th_title': 'Title', + 'sec_th_filing_date': 'Filing Date', + 'sec_th_deadline': 'Deadline', + 'sec_th_reviewer': 'Reviewer', + 'sec_th_status': 'Status', + 'sec_status_reviewing': 'Under Review', + 'sec_status_submitted': 'Submitted', + 'sec_status_passed': 'Approved', + 'sec_status_needs_revision': 'Needs Revision', + 'sec_status_pending': 'Pending', + 'sec_timeline': 'Filing Timeline', + 'sec_upcoming': 'Upcoming', + 'sec_disclosure_status': 'Disclosure Auto-generation Status', + 'sec_disclosure_progress': 'Disclosure Completion', + + // ── License Management ── + 'license_title': 'License & Regulatory Permit Management', + 'license_new': '+ New License Application', + 'license_active_count': 'Active Licenses', + 'license_pending': 'Pending', + 'license_expiring_soon': 'Expiring Soon', + 'license_revoked': 'Revoked', + 'license_list': 'License List', + 'license_th_id': 'ID', + 'license_th_name': 'License Name', + 'license_th_jurisdiction': 'Jurisdiction', + 'license_th_reg_body': 'Regulator', + 'license_th_issue_date': 'Issue Date', + 'license_th_expiry_date': 'Expiry Date', + 'license_th_status': 'Status', + 'license_status_active': 'Active', + 'license_status_applying': 'Applying', + 'license_status_renewal': 'Pending Renewal', + 'license_status_expiring': 'Expiring Soon', + 'license_status_expired': 'Expired', + 'license_reg_body_mapping': 'Regulatory Body Mapping', + 'license_renewal_alerts': 'Renewal Alerts', + 'license_unit': 'license(s)', + 'license_jurisdictions_covered': 'active licenses covering {0} jurisdictions', + + // ── SOX Compliance ── + 'sox_title': 'SOX Compliance Management', + 'sox_overall_score': 'Overall Compliance Score', + 'sox_full_score': 'Out of 100', + 'sox_total_controls': 'Total Controls', + 'sox_test_passed': 'Passed', + 'sox_defects_found': 'Defects Found', + 'sox_pending_test': 'Pending Test', + 'sox_control_categories': 'Internal Control Categories', + 'sox_th_control_point': 'Control Point', + 'sox_th_test_result': 'Test Result', + 'sox_th_last_test': 'Last Test', + 'sox_th_next_test': 'Next Test', + 'sox_result_passed': 'Passed', + 'sox_result_defect': 'Defect Found', + 'sox_result_pending': 'Pending', + 'sox_deficiency_tracking': 'Deficiency Tracking', + 'sox_th_id': 'ID', + 'sox_th_control': 'Control', + 'sox_th_severity': 'Severity', + 'sox_th_description': 'Description', + 'sox_th_due_date': 'Due Date', + 'sox_th_status': 'Status', + 'sox_th_owner': 'Owner', + 'sox_severity_major': 'Material Weakness', + 'sox_severity_minor': 'Significant Deficiency', + 'sox_severity_observation': 'Observation', + 'sox_status_remediating': 'Remediating', + 'sox_status_pending': 'Pending', + 'sox_auditor_progress': 'Auditor Review Progress', + 'sox_audit_progress': 'Audit Progress', + + // ── Tax Compliance ── + 'tax_title': 'Tax Compliance Management', + 'tax_export_report': 'Export Tax Report', + 'tax_payable': 'Tax Payable', + 'tax_paid': 'Tax Paid', + 'tax_compliance_rate': 'Tax Compliance Rate', + 'tax_pending_items': 'Pending Items', + 'tax_obligations': 'Tax Obligations by Jurisdiction', + 'tax_th_jurisdiction': 'Jurisdiction', + 'tax_th_type': 'Tax Type', + 'tax_th_period': 'Period', + 'tax_th_payable': 'Payable', + 'tax_th_paid': 'Paid', + 'tax_th_deadline': 'Deadline', + 'tax_th_status': 'Status', + 'tax_status_paid': 'Paid', + 'tax_status_partial': 'Partial', + 'tax_status_unpaid': 'Unpaid', + 'tax_type_breakdown': 'Tax Type Breakdown', + 'tax_th_tax_type': 'Tax Type', + 'tax_th_federal': 'Federal', + 'tax_th_state': 'State', + 'tax_th_total': 'Total', + 'tax_th_percentage': 'Share', + 'tax_calendar': 'Tax Calendar', + 'tax_status_done': 'Completed', + 'tax_status_pending': 'Pending', + 'tax_irs_tracker': 'IRS Filing Tracker', + 'tax_th_form': 'Form', + 'tax_th_description': 'Description', + 'tax_th_tax_year': 'Tax Year', + 'tax_th_filed_date': 'Filed Date', + 'tax_filing_submitted': 'Submitted', + 'tax_filing_preparing': 'Preparing', + 'tax_filing_on_demand': 'On Demand', + 'tax_filing_overdue': 'Overdue', + + // ── IPO Readiness ── + 'ipo_title': 'IPO Readiness Checklist', + 'ipo_subtitle': 'Track all IPO milestones, compliance items, dependencies and blockers', + 'ipo_total_items': 'Total Items', + 'ipo_overall_progress': 'Overall IPO Readiness', + 'ipo_cat_legal': 'Legal Compliance', + 'ipo_cat_financial': 'Financial Audit', + 'ipo_cat_sox': 'SOX Compliance', + 'ipo_cat_governance': 'Corporate Governance', + 'ipo_cat_insurance': 'Insurance Coverage', + 'ipo_th_id': 'ID', + 'ipo_th_item': 'Item', + 'ipo_th_owner': 'Owner', + 'ipo_th_deadline': 'Deadline', + 'ipo_th_status': 'Status', + 'ipo_unit_done': 'done', + 'ipo_dependency': 'Depends on', + 'ipo_timeline': 'IPO Timeline', + 'ipo_blockers': 'Blockers', + 'ipo_category_progress': 'Category Progress', + 'ipo_key_contacts': 'Key Contacts', + 'ipo_owner': 'Owner', + 'ipo_deadline': 'Deadline', + + // ── User Analytics ── + 'ua_title': 'User Analytics', + 'ua_total_users': 'Total Users', + 'ua_new_users_week': 'New Users/Week', + 'ua_growth_trend': 'User Growth Trend', + 'ua_kyc_distribution': 'KYC Level Distribution', + 'ua_geo_distribution': 'Geographic Distribution (Top 10)', + 'ua_th_rank': 'Rank', + 'ua_th_region': 'Region', + 'ua_th_users': 'Users', + 'ua_th_percent': 'Share', + 'ua_retention_matrix': 'User Retention Matrix', + 'ua_th_cohort': 'Cohort', + 'ua_user_segments': 'User Segments', + 'ua_segment_high_freq': 'High Frequency', + 'ua_segment_occasional': 'Occasional', + 'ua_segment_browse': 'Browse Only', + 'ua_segment_churned': 'Churned', + 'ua_unit_people': 'users', + + // ── Coupon Analytics ── + 'ca_title': 'Coupon Analytics', + 'ca_total_coupons': 'Total Coupons', + 'ca_active_coupons': 'Active Coupons', + 'ca_redeemed': 'Redeemed', + 'ca_expiring_soon': 'Expiring Soon', + 'ca_category_distribution': 'Category Distribution', + 'ca_face_value_distribution': 'Face Value Distribution', + 'ca_top_selling': 'Top 10 Best Sellers', + 'ca_th_rank': 'Rank', + 'ca_th_brand': 'Brand', + 'ca_th_coupon_name': 'Coupon Name', + 'ca_th_sales': 'Sales', + 'ca_th_revenue': 'Revenue', + 'ca_th_rating': 'Rating', + 'ca_breakage_trend': 'Breakage Trend (Unredeemed Rate)', + 'ca_secondary_market': 'Secondary Market Analytics', + + // ── Market Maker ── + 'mm_title': 'Market Maker Management', + 'mm_add_new': 'Add Market Maker', + 'mm_active_makers': 'Active Makers', + 'mm_total_liquidity': 'Total Liquidity', + 'mm_daily_volume': 'Daily Volume', + 'mm_avg_spread': 'Avg Spread', + 'mm_th_name': 'Market Maker', + 'mm_th_status': 'Status', + 'mm_th_daily_volume': 'Daily Volume', + 'mm_status_active': 'Active', + 'mm_status_paused': 'Paused', + 'mm_status_suspended': 'Suspended', + 'mm_liquidity_pools': 'Liquidity Pool Distribution', + 'mm_order_book_depth': 'Order Book Depth', + 'mm_health_indicators': 'Market Health Indicators', + 'mm_risk_alerts': 'Risk Alerts', + 'mm_high_risk': 'High Risk', + 'mm_unit_makers': 'makers', + 'market_maker_list': 'Market Makers', + 'market_maker_config': 'Market Maker Config', + 'market_maker_spread': 'Spread', + 'market_maker_liquidity': 'Liquidity', + 'market_maker_algorithm': 'Algorithm Strategy', + 'market_maker_pnl': 'P&L', + + // ── Consumer Protection ── + 'cp_title': 'Consumer Protection', + 'cp_total_complaints': 'Total Complaints', + 'cp_resolved': 'Resolved', + 'cp_processing': 'Processing', + 'cp_avg_resolution_time': 'Avg Resolution Time', + 'cp_complaint_categories': 'Complaint Categories', + 'cp_cat_redeem_fail': 'Redemption Failure', + 'cp_cat_refund_dispute': 'Refund Dispute', + 'cp_cat_fake_coupon': 'Fake Coupon', + 'cp_cat_other': 'Other', + 'cp_csat': 'Consumer Satisfaction (CSAT)', + 'cp_protection_fund': 'Protection Fund Utilization', + 'cp_recent_complaints': 'Recent Complaints', + 'cp_search_complaints': 'Search complaints...', + 'cp_th_id': 'ID', + 'cp_th_severity': 'Severity', + 'cp_th_category': 'Category', + 'cp_th_description': 'Description', + 'cp_th_status': 'Status', + 'cp_th_assignee': 'Assignee', + 'cp_th_date': 'Date', + 'cp_refund_compliance': 'Refund Compliance - Non-compliant Issuers Top 5', + 'cp_th_rank': 'Rank', + 'cp_th_issuer': 'Issuer', + 'cp_th_violations': 'Violations', + 'cp_th_refund_rate': 'Refund Rate', + 'cp_th_avg_delay': 'Avg Delay', + 'cp_th_risk_level': 'Risk Level', + 'cp_unit_cases': 'cases', + + // ── AI Agent ── + 'ai_agent_list': 'AI Agent List', + 'ai_agent_config': 'AI Agent Config', + 'ai_agent_logs': 'AI Execution Logs', + 'ai_agent_pricing': 'AI Pricing Engine', + 'ai_agent_recommendation': 'AI Recommendation Engine', + 'ai_agent_risk': 'AI Risk Control', + 'ai_agent_status': 'Running Status', }, 'ja-JP': { @@ -448,27 +1468,105 @@ const translations: Record> = { 'total': '合計', 'yes': 'はい', 'no': 'いいえ', + 'all': 'すべて', + 'view': '表示', + 'process': '処理', + 'download': 'ダウンロード', + 'collapse': '折りたたむ', + 'time': '時間', + 'amount': '金額', + 'type': 'タイプ', + 'mark': 'マーク', + 'review': '審査', + 'suspend': '一時停止', + 'resume': '再開', + 'warning_label': '警告', + 'investigate': '調査', + 'completed': '完了', + 'in_progress': '進行中', + 'pending': '未着手', + 'blocked': 'ブロック', + 'custom_export': 'カスタムエクスポート', + 'export_report': 'レポートエクスポート', + 'auto_generated': '自動生成', + 'as_of': '時点', + 'generating': '生成中', + 'accuracy': '精度', + 'overall_progress': '全体進捗', + 'renew_now': '今すぐ更新', + 'not_applied': '未申請', + 'urgency_critical': '緊急', + 'urgency_high': '高', + 'urgency_medium': '中', + 'urgency_low': '低', + 'expiry_date': '有効期限', + 'remaining_days': '残り {0} 日', + 'severity_high': '高', + 'severity_medium': '中', + 'severity_low': '低', // ── Sidebar / Navigation ── - 'nav_dashboard': 'ダッシュボード', + 'nav_dashboard': '運営概要', 'nav_overview': '概要', 'nav_users': 'ユーザー管理', 'nav_coupons': 'クーポン審査', 'nav_issuers': '発行者管理', - 'nav_finance': '財務', + 'nav_issuers_review': '申請審査', + 'nav_issuers_list': '発行者一覧', + 'nav_issuers_coupons': 'クーポン審査', + 'nav_users_list': 'ユーザー一覧', + 'nav_users_kyc': 'KYC審査', + 'nav_trading': '取引監視', + 'nav_trading_realtime': 'リアルタイムフィード', + 'nav_trading_stats': '取引統計', + 'nav_trading_orders': '注文管理', + 'nav_risk': 'リスクセンター', + 'nav_risk_dashboard': 'リスクダッシュボード', + 'nav_risk_suspicious': '不審な取引', + 'nav_risk_blacklist': 'ブラックリスト管理', + 'nav_risk_ofac': 'OFACスクリーニングログ', + 'nav_finance': '財務管理', 'nav_chain': 'チェーン監視', - 'nav_reports': 'レポート', + 'nav_reports': 'レポートセンター', 'nav_compliance': 'コンプライアンス', + 'nav_compliance_sar': 'SAR管理', + 'nav_compliance_ctr': 'CTR管理', + 'nav_compliance_audit': '監査ログ', + 'nav_compliance_reports': '規制レポート', 'nav_analytics': 'データ分析', + 'nav_analytics_users': 'ユーザー分析', + 'nav_analytics_coupons': 'クーポン分析', + 'nav_analytics_market_maker': 'マーケットメーカー分析', + 'nav_analytics_consumer_protection': '消費者保護', 'nav_ai_agent': 'AIエージェント', - 'nav_system': 'システム設定', + 'nav_system': 'システム管理', + 'nav_system_admins': '管理者アカウント', + 'nav_system_config': 'システム設定', + 'nav_system_contracts': 'コントラクト管理', + 'nav_system_monitor': 'システム監視', + 'nav_disputes': '紛争処理', + 'nav_coupons_mgmt': 'クーポン管理', + 'nav_merchant': '加盟店精算', + 'nav_agent': 'エージェントパネル', 'nav_market_maker': 'マーケットメーカー', - 'nav_insurance': '保険', + 'nav_insurance': '保険管理', + + // ── Header ── + 'header_search_placeholder': 'ユーザー/注文/取引を検索...', + 'header_ai_assistant': 'AIアシスタント', // ── Dashboard ── - 'dashboard_title': 'ダッシュボード', - 'dashboard_total_users': '総ユーザー数', + 'dashboard_title': '運営概要', + 'dashboard_total_volume': '総取引量', + 'dashboard_total_amount': '取引金額', 'dashboard_active_users': 'アクティブユーザー', + 'dashboard_issuer_count': '発行者数', + 'dashboard_coupon_circulation': 'クーポン流通量', + 'dashboard_system_health': 'システムヘルス', + 'dashboard_volume_trend': '取引量トレンド', + 'dashboard_type_distribution': '取引タイプ分布', + 'dashboard_realtime_feed': 'リアルタイムフィード', + 'dashboard_total_users': '総ユーザー数', 'dashboard_total_coupons': 'クーポン総数', 'dashboard_trading_volume': '取引量', 'dashboard_revenue': 'プラットフォーム収益', @@ -477,10 +1575,26 @@ const translations: Record> = { 'dashboard_monthly': '今月', 'dashboard_yearly': '今年', 'dashboard_real_time': 'リアルタイムデータ', - 'dashboard_system_health': 'システムヘルス', 'dashboard_alerts': 'アラート', + 'dashboard_th_time': '時間', + 'dashboard_th_type': 'タイプ', + 'dashboard_th_order': '注文番号', + 'dashboard_th_amount': '金額', + 'dashboard_th_status': 'ステータス', + 'dashboard_status_completed': '完了', + 'dashboard_status_processing': '処理中', + 'dashboard_type_purchase': '購入', + 'dashboard_type_redeem': '利用', + 'dashboard_type_resell': '転売', + 'dashboard_type_transfer': '譲渡', + 'dashboard_service_api': 'APIサービス', + 'dashboard_service_db': 'データベース', + 'dashboard_service_cache': 'キャッシュサービス', + 'dashboard_service_mq': 'メッセージキュー', // ── User Management ── + 'user_management_title': 'ユーザー管理', + 'user_search_placeholder': '電話番号/メール/ユーザーIDで検索...', 'user_list': 'ユーザー一覧', 'user_detail': 'ユーザー詳細', 'user_id': 'ユーザーID', @@ -498,12 +1612,39 @@ const translations: Record> = { 'user_consumer': '消費者', 'user_issuer': '発行者', 'user_admin': '管理者', + 'user_coupon_count': 'クーポン数', + 'user_total_traded': '取引額', + 'user_risk_tags': 'リスクタグ', - // ── Coupon Review ── + // ── Issuer Management ── + 'issuer_management_title': '発行者管理', + 'issuer_ai_pre_review': 'AI事前審査', + 'issuer_list': '発行者一覧', + 'issuer_detail': '発行者詳細', + 'issuer_name': '名称', + 'issuer_company_name': '企業名', + 'issuer_credit_rating': '信用格付け', + 'issuer_onboarding_status': '申請状態', + 'issuer_onboarding_pending': '審査中', + 'issuer_onboarding_approved': '承認済み', + 'issuer_onboarding_rejected': '却下済み', + 'issuer_total_issued': '発行総数', + 'issuer_total_redeemed': '検証総数', + 'issuer_collateral': '担保', + 'issuer_deposit': '保証金', + 'issuer_submit_time': '申請日', + 'issuer_coupon_count': 'クーポン数', + 'issuer_total_volume': '総発行額', + + // ── Coupon Management ── + 'coupon_management_title': 'クーポン管理', 'coupon_review': 'クーポン審査', 'coupon_pending_review': '審査待ち', 'coupon_approved': '承認済み', 'coupon_rejected': '却下済み', + 'coupon_active': '販売中', + 'coupon_suspended': '一時停止', + 'coupon_expired': '期限切れ', 'coupon_issuer': '発行者', 'coupon_face_value': '額面', 'coupon_quantity': '発行数', @@ -514,52 +1655,61 @@ const translations: Record> = { 'coupon_approve': '承認', 'coupon_reject': '却下', 'coupon_review_comment': '審査コメント', + 'coupon_id': 'クーポンID', + 'coupon_name': 'クーポン名', + 'coupon_template': 'テンプレート', + 'coupon_sold': '販売済み', + 'coupon_redeemed': '利用済み', - // ── Issuer Management ── - 'issuer_list': '発行者一覧', - 'issuer_detail': '発行者詳細', - 'issuer_name': '名称', - 'issuer_credit_rating': '信用格付け', - 'issuer_onboarding_status': '申請状態', - 'issuer_onboarding_pending': '審査中', - 'issuer_onboarding_approved': '承認済み', - 'issuer_onboarding_rejected': '却下済み', - 'issuer_total_issued': '発行総数', - 'issuer_total_redeemed': '検証総数', - 'issuer_collateral': '担保', - 'issuer_deposit': '保証金', + // ── Trading Monitor ── + 'trading_title': '取引監視', + 'trading_today_volume': '本日取引量', + 'trading_today_amount': '本日取引額', + 'trading_avg_discount': '平均割引率', + 'trading_large_trades': '大口取引', + 'trading_volume_trend': '取引量/金額トレンド', + 'trading_order_management': '注文管理', + 'trading_search_order': '注文番号で検索...', + 'trading_th_order_id': '注文番号', + 'trading_th_type': 'タイプ', + 'trading_th_coupon_name': 'クーポン名', + 'trading_th_buyer': '買い手', + 'trading_th_seller': '売り手', + 'trading_th_amount': '金額', + 'trading_th_status': 'ステータス', + 'trading_th_time': '時間', + 'trading_type_purchase': '購入', + 'trading_type_resell': '転売', + 'trading_type_redeem': '利用', + 'trading_type_transfer': '譲渡', + 'trading_status_completed': '完了', + 'trading_status_dispute': '紛争', - // ── Finance ── - 'finance_overview': '財務概要', - 'finance_settlement': '決済管理', - 'finance_fee': '手数料', - 'finance_revenue': '収益', - 'finance_payout': '支払い', - 'finance_reconciliation': '照合', - 'finance_invoice': '請求書', - 'finance_tax': '税務', - 'finance_report': '財務レポート', + // ── Risk Center ── + 'risk_title': 'リスクセンター', + 'risk_ai_warning': 'AIリスク警告', + 'risk_events': 'リスクイベント', + 'risk_suspicious_trades': '不審な取引', + 'risk_frozen_accounts': '凍結アカウント', + 'risk_ofac_hits': 'OFACヒット', + 'risk_th_trade_id': '取引ID', + 'risk_th_user': 'ユーザー', + 'risk_th_anomaly_type': '異常タイプ', + 'risk_th_amount': '金額', + 'risk_th_time': '時間', + 'risk_th_risk_score': 'リスクスコア', + 'risk_type_high_freq': '高頻度取引', + 'risk_type_large_single': '大口単独', + 'risk_type_related_account': '関連アカウント', + 'risk_type_abnormal_ip': '異常IP', - // ── Chain Monitor ── - 'chain_monitor': 'チェーン監視', - 'chain_block_height': 'ブロック高さ', - 'chain_tps': 'TPS', - 'chain_node_status': 'ノードステータス', - 'chain_contracts': 'スマートコントラクト', - 'chain_transactions': 'オンチェーン取引', - 'chain_gas_usage': 'Gas消費', - 'chain_explorer': 'ブロックエクスプローラー', - - // ── Reports ── - 'report_list': 'レポート一覧', - 'report_generate': 'レポート生成', - 'report_daily': '日次レポート', - 'report_weekly': '週次レポート', - 'report_monthly': '月次レポート', - 'report_custom': 'カスタムレポート', - 'report_download': 'レポートダウンロード', - - // ── Compliance / Regulatory ── + // ── Compliance ── + 'compliance_title': 'コンプライアンスレポート', + 'compliance_ai_generate': 'AIレポート生成', + 'compliance_tab_sar': 'SAR管理', + 'compliance_tab_ctr': 'CTR管理', + 'compliance_tab_audit': '監査ログ', + 'compliance_tab_reports': '規制レポート', 'compliance_overview': 'コンプライアンス概要', 'compliance_sec_filing': 'SEC申告', 'compliance_license': 'ライセンス管理', @@ -571,43 +1721,42 @@ const translations: Record> = { 'compliance_risk_assessment': 'リスク評価', 'compliance_audit_log': '監査ログ', 'compliance_policy': 'コンプライアンスポリシー', + 'compliance_sar_id': 'SAR番号', + 'compliance_sar_related_txn': '関連取引', + 'compliance_sar_user': '対象ユーザー', + 'compliance_sar_amount': '金額', + 'compliance_sar_risk_type': 'リスクタイプ', + 'compliance_sar_status': 'ステータス', + 'compliance_sar_created': '作成日', + 'compliance_sar_pending': '未提出', + 'compliance_sar_submitted': '提出済み', + 'compliance_ctr_title': '大口取引報告', + 'compliance_ctr_desc': '$10,000超の取引はCTR自動生成。現在保留中の項目はありません', + 'compliance_audit_search': '監査ログを検索...', + 'compliance_audit_action_login': 'ログイン', + 'compliance_audit_action_review': '審査', + 'compliance_audit_action_config': '設定', + 'compliance_audit_action_freeze': '凍結', + 'compliance_audit_action_export': 'エクスポート', + 'compliance_audit_action_query': '照会', + 'compliance_report_daily': '日次', + 'compliance_report_monthly': '月次', + 'compliance_report_sar_quarterly': '四半期SAR概要', + 'compliance_report_annual': '年次コンプライアンスレポート', - // ── Analytics ── - 'analytics_overview': '分析概要', - 'analytics_user_growth': 'ユーザー成長', - 'analytics_trading_volume': '取引量分析', - 'analytics_coupon_lifecycle': 'クーポンライフサイクル', - 'analytics_conversion': 'コンバージョン率', - 'analytics_retention': 'リテンション率', - 'analytics_heatmap': 'ヒートマップ', - 'analytics_funnel': 'ファネル分析', - 'analytics_cohort': 'コホート分析', - - // ── Market Maker ── - 'market_maker_list': 'マーケットメーカー一覧', - 'market_maker_config': 'マーケットメーカー設定', - 'market_maker_spread': 'スプレッド', - 'market_maker_liquidity': '流動性', - 'market_maker_algorithm': 'アルゴリズム戦略', - 'market_maker_pnl': '損益', - - // ── Insurance ── - 'insurance_pool': '保険プール', - 'insurance_premium': '保険料', - 'insurance_claim': '保険請求', - 'insurance_coverage': '補償範囲', - 'insurance_policy': '保険ポリシー', - - // ── AI Agent ── - 'ai_agent_list': 'AIエージェント一覧', - 'ai_agent_config': 'AIエージェント設定', - 'ai_agent_logs': 'AI実行ログ', - 'ai_agent_pricing': 'AI価格エンジン', - 'ai_agent_recommendation': 'AIレコメンドエンジン', - 'ai_agent_risk': 'AIリスク管理', - 'ai_agent_status': '実行ステータス', - - // ── System Settings ── + // ── System Management ── + 'system_title': 'システム管理', + 'system_tab_admins': '管理者アカウント', + 'system_tab_config': 'システム設定', + 'system_tab_contracts': 'コントラクト管理', + 'system_tab_monitor': 'システム監視', + 'system_admin_list': '管理者一覧', + 'system_add_admin': '+ 管理者追加', + 'system_th_account': 'アカウント', + 'system_th_name': '名前', + 'system_th_role': '役割', + 'system_th_last_login': '最終ログイン', + 'system_th_status': 'ステータス', 'system_general': '一般設定', 'system_roles': '役割と権限', 'system_api_keys': 'APIキー', @@ -618,5 +1767,386 @@ const translations: Record> = { 'system_logs': 'システムログ', 'system_feature_flags': '機能フラグ', 'system_rate_limit': 'レート制限', + 'system_fee_config': '手数料率設定', + 'system_kyc_config': 'KYC閾値設定', + 'system_trade_limit_config': '取引限度額設定', + 'system_params': 'システムパラメータ', + 'system_contract_status': 'スマートコントラクト状態', + 'system_running': '稼働中', + 'system_health_check': 'サービスヘルスチェック', + 'system_api_response': 'APIレスポンスタイム', + + // ── Disputes ── + 'dispute_title': '紛争処理', + 'dispute_pending': '未処理', + 'dispute_processing': '処理中', + 'dispute_resolved_today': '本日解決', + 'dispute_resolved': '解決済み', + 'dispute_rejected': '却下済み', + 'dispute_type_buyer': '買い手申立', + 'dispute_type_seller': '売り手申立', + 'dispute_type_refund': '返金申請', + 'dispute_th_ticket_id': 'チケットID', + 'dispute_th_type': 'タイプ', + 'dispute_th_order': '関連注文', + 'dispute_th_plaintiff': '申立人', + 'dispute_th_defendant': '被申立人', + 'dispute_th_amount': '金額', + 'dispute_th_status': 'ステータス', + 'dispute_th_sla': 'SLA', + 'dispute_th_created': '作成日', + + // ── Finance Management ── + 'finance_title': '財務管理', + 'finance_platform_fee': 'プラットフォーム手数料収入', + 'finance_pending_settlement': '未精算(発行者向け)', + 'finance_consumer_refund': '消費者返金', + 'finance_pool_balance': '資金プール残高', + 'finance_settlement_queue': '精算キュー', + 'finance_revenue_trend': '収益トレンド', + 'finance_th_issuer': '発行者', + 'finance_th_amount': '金額', + 'finance_th_status': 'ステータス', + 'finance_th_time': '時間', + 'finance_status_settled': '精算済み', + 'finance_status_processing': '処理中', + 'finance_status_pending': '未精算', + 'finance_overview': '財務概要', + 'finance_settlement': '決済管理', + 'finance_fee': '手数料', + 'finance_revenue': '収益', + 'finance_payout': '支払い', + 'finance_reconciliation': '照合', + 'finance_invoice': '請求書', + 'finance_tax': '税務', + 'finance_report': '財務レポート', + 'finance_period_month': '今月', + 'finance_period_cumulative': '累計', + 'finance_period_realtime': 'リアルタイム', + + // ── Chain Monitor ── + 'chain_title': 'チェーン監視', + 'chain_recent_events': '最近のオンチェーンイベント', + 'chain_gas_monitor': 'Gas費モニター', + 'chain_current_gas': '現在のGas', + 'chain_today_avg': '本日平均', + 'chain_today_gas_spend': '本日Gas支出', + 'chain_monitor': 'チェーン監視', + 'chain_block_height': 'ブロック高さ', + 'chain_tps': 'TPS', + 'chain_node_status': 'ノードステータス', + 'chain_contracts': 'スマートコントラクト', + 'chain_transactions': 'オンチェーン取引', + 'chain_gas_usage': 'Gas消費', + 'chain_explorer': 'ブロックエクスプローラー', + + // ── Reports ── + 'reports_title': 'レポートセンター', + 'reports_operations': '運営レポート', + 'reports_compliance': 'コンプライアンスレポート', + 'reports_financial': '財務レポート', + 'reports_audit': '監査レポート', + 'reports_status_generated': '生成済み', + 'reports_status_submitted': '提出済み', + 'reports_status_passed': '合格', + 'reports_status_pending_review': '審査待ち', + 'reports_status_pending_generate': '未生成', + 'report_list': 'レポート一覧', + 'report_generate': 'レポート生成', + 'report_daily': '日次レポート', + 'report_weekly': '週次レポート', + 'report_monthly': '月次レポート', + 'report_custom': 'カスタムレポート', + 'report_download': 'レポートダウンロード', + + // ── Merchant Redemption ── + 'merchant_title': '加盟店精算管理', + 'merchant_today_redemption': '本日精算', + 'merchant_today_amount': '本日精算額', + 'merchant_active_stores': 'アクティブ店舗', + 'merchant_abnormal_redemption': '異常精算', + 'merchant_store_ranking': '店舗精算ランキング', + 'merchant_realtime_feed': 'リアルタイムフィード', + 'merchant_need_review': '要審査', + 'merchant_unit_count': '件', + + // ── Agent Panel ── + 'agent_title': 'AIエージェント管理', + 'agent_today_sessions': '本日セッション数', + 'agent_avg_response': '平均応答時間', + 'agent_satisfaction': 'ユーザー満足度', + 'agent_human_takeover': '有人対応率', + 'agent_top_questions': '人気質問 Top 5', + 'agent_modules': 'エージェントモジュール', + 'agent_running': '稼働中', + 'agent_unit_times': '回', + + // ── Insurance ── + 'insurance_title': '保険と消費者保護', + 'insurance_protection_fund': '消費者保護基金', + 'insurance_monthly_payout': '今月支払い', + 'insurance_payout_rate': '支払い率', + 'insurance_ipo_readiness': 'IPO準備度', + 'insurance_recent_claims': '最近の保険請求', + 'insurance_th_id': '番号', + 'insurance_th_user': 'ユーザー', + 'insurance_th_reason': '理由', + 'insurance_th_amount': '金額', + 'insurance_th_status': 'ステータス', + 'insurance_status_paid': '支払い済み', + 'insurance_status_processing': '処理中', + 'insurance_ipo_checklist': 'IPO準備チェックリスト', + 'insurance_pool': '保険プール', + 'insurance_premium': '保険料', + 'insurance_claim': '保険請求', + 'insurance_coverage': '補償範囲', + 'insurance_policy': '保険ポリシー', + + // ── SEC Filing ── + 'sec_title': 'SEC文書管理', + 'sec_new_filing': '+ 新規Filing', + 'sec_filed_count': '提出済み文書数', + 'sec_pending_review': '審査待ち', + 'sec_passed': '承認済み', + 'sec_next_deadline': '次の締切まで', + 'sec_filing_list': 'SEC申告文書一覧', + 'sec_th_id': '番号', + 'sec_th_form_type': 'フォームタイプ', + 'sec_th_title': 'タイトル', + 'sec_th_filing_date': '提出日', + 'sec_th_deadline': '締切日', + 'sec_th_reviewer': '審査者', + 'sec_th_status': 'ステータス', + 'sec_status_reviewing': '審査中', + 'sec_status_submitted': '提出済み', + 'sec_status_passed': '承認済み', + 'sec_status_needs_revision': '要修正', + 'sec_status_pending': '未提出', + 'sec_timeline': '申告スケジュール', + 'sec_upcoming': '期限間近', + 'sec_disclosure_status': '開示文書自動生成状況', + 'sec_disclosure_progress': '開示文書完成度', + + // ── License Management ── + 'license_title': 'ライセンス・規制許可管理', + 'license_new': '+ 新規ライセンス申請', + 'license_active_count': 'アクティブライセンス数', + 'license_pending': '申請待ち', + 'license_expiring_soon': '期限間近', + 'license_revoked': '取消済み', + 'license_list': 'ライセンス一覧', + 'license_th_id': '番号', + 'license_th_name': 'ライセンス名', + 'license_th_jurisdiction': '管轄', + 'license_th_reg_body': '規制機関', + 'license_th_issue_date': '発行日', + 'license_th_expiry_date': '有効期限', + 'license_th_status': 'ステータス', + 'license_status_active': '有効', + 'license_status_applying': '申請中', + 'license_status_renewal': '更新待ち', + 'license_status_expiring': '期限間近', + 'license_status_expired': '期限切れ', + 'license_reg_body_mapping': '規制機関マッピング', + 'license_renewal_alerts': '更新アラート', + 'license_unit': 'ライセンス', + 'license_jurisdictions_covered': '件のライセンスが {0} 管轄区域をカバー', + + // ── SOX Compliance ── + 'sox_title': 'SOXコンプライアンス管理', + 'sox_overall_score': '総合コンプライアンススコア', + 'sox_full_score': '満点 100', + 'sox_total_controls': '総管理項目', + 'sox_test_passed': 'テスト合格', + 'sox_defects_found': '欠陥発見', + 'sox_pending_test': 'テスト待ち', + 'sox_control_categories': '内部統制カテゴリ', + 'sox_th_control_point': '管理項目', + 'sox_th_test_result': 'テスト結果', + 'sox_th_last_test': '前回テスト', + 'sox_th_next_test': '次回テスト', + 'sox_result_passed': '合格', + 'sox_result_defect': '欠陥発見', + 'sox_result_pending': 'テスト待ち', + 'sox_deficiency_tracking': '欠陥追跡', + 'sox_th_id': '番号', + 'sox_th_control': '管理項目', + 'sox_th_severity': '重要度', + 'sox_th_description': '説明', + 'sox_th_due_date': '是正期限', + 'sox_th_status': 'ステータス', + 'sox_th_owner': '担当者', + 'sox_severity_major': '重大な欠陥', + 'sox_severity_minor': '一般的な欠陥', + 'sox_severity_observation': '観察事項', + 'sox_status_remediating': '是正中', + 'sox_status_pending': '是正待ち', + 'sox_auditor_progress': '監査人レビュー進捗', + 'sox_audit_progress': '監査進捗', + + // ── Tax Compliance ── + 'tax_title': '税務コンプライアンス管理', + 'tax_export_report': '税務レポートエクスポート', + 'tax_payable': '納税額', + 'tax_paid': '納付済み', + 'tax_compliance_rate': '税務コンプライアンス率', + 'tax_pending_items': '未処理事項', + 'tax_obligations': '管轄区域別税務義務', + 'tax_th_jurisdiction': '管轄区域', + 'tax_th_type': '税種', + 'tax_th_period': '期間', + 'tax_th_payable': '納付額', + 'tax_th_paid': '納付済み', + 'tax_th_deadline': '締切日', + 'tax_th_status': 'ステータス', + 'tax_status_paid': '納付済み', + 'tax_status_partial': '一部納付', + 'tax_status_unpaid': '未納', + 'tax_type_breakdown': '税種別集計', + 'tax_th_tax_type': '税種', + 'tax_th_federal': '連邦', + 'tax_th_state': '州', + 'tax_th_total': '合計', + 'tax_th_percentage': '割合', + 'tax_calendar': '税務カレンダー', + 'tax_status_done': '完了', + 'tax_status_pending': '未処理', + 'tax_irs_tracker': 'IRS書類提出追跡', + 'tax_th_form': 'フォーム', + 'tax_th_description': '説明', + 'tax_th_tax_year': '課税年度', + 'tax_th_filed_date': '提出日', + 'tax_filing_submitted': '提出済み', + 'tax_filing_preparing': '準備中', + 'tax_filing_on_demand': '随時提出', + 'tax_filing_overdue': '期限超過', + + // ── IPO Readiness ── + 'ipo_title': 'IPO準備チェックリスト', + 'ipo_subtitle': 'すべてのIPOマイルストーン、コンプライアンス項目、依存関係、ブロッカーを追跡', + 'ipo_total_items': '総チェック項目', + 'ipo_overall_progress': '全体IPO準備進捗', + 'ipo_cat_legal': '法的コンプライアンス', + 'ipo_cat_financial': '財務監査', + 'ipo_cat_sox': 'SOXコンプライアンス', + 'ipo_cat_governance': 'コーポレートガバナンス', + 'ipo_cat_insurance': '保険保障', + 'ipo_th_id': '番号', + 'ipo_th_item': 'チェック項目', + 'ipo_th_owner': '担当', + 'ipo_th_deadline': '締切', + 'ipo_th_status': 'ステータス', + 'ipo_unit_done': '完了', + 'ipo_dependency': '依存', + 'ipo_timeline': 'IPOタイムライン', + 'ipo_blockers': 'ブロッカー', + 'ipo_category_progress': 'カテゴリ別進捗', + 'ipo_key_contacts': '主要連絡先', + 'ipo_owner': '担当', + 'ipo_deadline': '締切', + + // ── User Analytics ── + 'ua_title': 'ユーザー分析', + 'ua_total_users': '総ユーザー数', + 'ua_new_users_week': '週間新規ユーザー', + 'ua_growth_trend': 'ユーザー成長トレンド', + 'ua_kyc_distribution': 'KYCレベル分布', + 'ua_geo_distribution': '地域分布 (Top 10)', + 'ua_th_rank': '順位', + 'ua_th_region': '地域', + 'ua_th_users': 'ユーザー数', + 'ua_th_percent': '割合', + 'ua_retention_matrix': 'ユーザーリテンションマトリックス', + 'ua_th_cohort': 'コホート', + 'ua_user_segments': 'ユーザーセグメント', + 'ua_segment_high_freq': '高頻度取引', + 'ua_segment_occasional': '時々購入', + 'ua_segment_browse': '閲覧のみ', + 'ua_segment_churned': '離脱ユーザー', + 'ua_unit_people': '人', + + // ── Coupon Analytics ── + 'ca_title': 'クーポン分析', + 'ca_total_coupons': 'クーポン総数', + 'ca_active_coupons': 'アクティブクーポン', + 'ca_redeemed': '利用済み', + 'ca_expiring_soon': '期限間近', + 'ca_category_distribution': 'カテゴリ分布', + 'ca_face_value_distribution': '額面分布', + 'ca_top_selling': '人気クーポン Top 10', + 'ca_th_rank': '順位', + 'ca_th_brand': 'ブランド', + 'ca_th_coupon_name': 'クーポン名', + 'ca_th_sales': '販売数', + 'ca_th_revenue': '収益', + 'ca_th_rating': '評価', + 'ca_breakage_trend': 'Breakageトレンド (未利用率)', + 'ca_secondary_market': 'セカンダリーマーケット分析', + + // ── Market Maker ── + 'mm_title': 'マーケットメーカー管理', + 'mm_add_new': 'マーケットメーカー追加', + 'mm_active_makers': 'アクティブメーカー', + 'mm_total_liquidity': '総流動性', + 'mm_daily_volume': '日次取引量', + 'mm_avg_spread': '平均スプレッド', + 'mm_th_name': 'マーケットメーカー', + 'mm_th_status': 'ステータス', + 'mm_th_daily_volume': '日次取引量', + 'mm_status_active': 'アクティブ', + 'mm_status_paused': '一時停止', + 'mm_status_suspended': '停止', + 'mm_liquidity_pools': '流動性プール分布', + 'mm_order_book_depth': 'オーダーブック深度', + 'mm_health_indicators': '市場ヘルス指標', + 'mm_risk_alerts': 'リスクアラート', + 'mm_high_risk': '高リスク', + 'mm_unit_makers': 'メーカー', + 'market_maker_list': 'マーケットメーカー一覧', + 'market_maker_config': 'マーケットメーカー設定', + 'market_maker_spread': 'スプレッド', + 'market_maker_liquidity': '流動性', + 'market_maker_algorithm': 'アルゴリズム戦略', + 'market_maker_pnl': '損益', + + // ── Consumer Protection ── + 'cp_title': '消費者保護', + 'cp_total_complaints': '苦情総数', + 'cp_resolved': '解決済み', + 'cp_processing': '処理中', + 'cp_avg_resolution_time': '平均解決時間', + 'cp_complaint_categories': '苦情分類', + 'cp_cat_redeem_fail': '利用失敗', + 'cp_cat_refund_dispute': '返金紛争', + 'cp_cat_fake_coupon': '偽クーポン', + 'cp_cat_other': 'その他', + 'cp_csat': '消費者満足度 (CSAT)', + 'cp_protection_fund': '保護基金使用率', + 'cp_recent_complaints': '最近の苦情', + 'cp_search_complaints': '苦情を検索...', + 'cp_th_id': '番号', + 'cp_th_severity': '重要度', + 'cp_th_category': '分類', + 'cp_th_description': '説明', + 'cp_th_status': 'ステータス', + 'cp_th_assignee': '担当者', + 'cp_th_date': '日付', + 'cp_refund_compliance': '返金コンプライアンス - 非準拠発行者 Top 5', + 'cp_th_rank': '順位', + 'cp_th_issuer': '発行者', + 'cp_th_violations': '違反回数', + 'cp_th_refund_rate': '返金承認率', + 'cp_th_avg_delay': '平均遅延', + 'cp_th_risk_level': 'リスクレベル', + 'cp_unit_cases': '件', + + // ── AI Agent ── + 'ai_agent_list': 'AIエージェント一覧', + 'ai_agent_config': 'AIエージェント設定', + 'ai_agent_logs': 'AI実行ログ', + 'ai_agent_pricing': 'AI価格エンジン', + 'ai_agent_recommendation': 'AIレコメンドエンジン', + 'ai_agent_risk': 'AIリスク管理', + 'ai_agent_status': '実行ステータス', }, }; diff --git a/frontend/admin-web/src/layouts/AdminLayout.tsx b/frontend/admin-web/src/layouts/AdminLayout.tsx index e45374c..2f9b9a0 100644 --- a/frontend/admin-web/src/layouts/AdminLayout.tsx +++ b/frontend/admin-web/src/layouts/AdminLayout.tsx @@ -3,6 +3,7 @@ import React, { useState } from 'react'; import { usePathname, useRouter } from 'next/navigation'; import Link from 'next/link'; +import { t } from '@/i18n/locales'; /** * D. Web管理前端 - 主布局 @@ -20,72 +21,72 @@ interface NavItem { } const navItems: NavItem[] = [ - { key: 'dashboard', icon: '📊', label: '运营总览' }, + { key: 'dashboard', icon: '📊', label: t('nav_dashboard') }, { - key: 'issuers', icon: '🏢', label: '发行方管理', + key: 'issuers', icon: '🏢', label: t('nav_issuers'), children: [ - { key: 'issuers/review', icon: '', label: '入驻审核' }, - { key: 'issuers/list', icon: '', label: '发行方列表' }, - { key: 'issuers/coupons', icon: '', label: '券审核' }, + { key: 'issuers/review', icon: '', label: t('nav_issuers_review') }, + { key: 'issuers/list', icon: '', label: t('nav_issuers_list') }, + { key: 'issuers/coupons', icon: '', label: t('nav_issuers_coupons') }, ], }, { - key: 'users', icon: '👤', label: '用户管理', + key: 'users', icon: '👤', label: t('nav_users'), children: [ - { key: 'users/list', icon: '', label: '用户列表' }, - { key: 'users/kyc', icon: '', label: 'KYC审核', badge: 5 }, + { key: 'users/list', icon: '', label: t('nav_users_list') }, + { key: 'users/kyc', icon: '', label: t('nav_users_kyc'), badge: 5 }, ], }, { - key: 'trading', icon: '💱', label: '交易监控', + key: 'trading', icon: '💱', label: t('nav_trading'), children: [ - { key: 'trading/realtime', icon: '', label: '实时交易流' }, - { key: 'trading/stats', icon: '', label: '交易统计' }, - { key: 'trading/orders', icon: '', label: '订单管理' }, + { key: 'trading/realtime', icon: '', label: t('nav_trading_realtime') }, + { key: 'trading/stats', icon: '', label: t('nav_trading_stats') }, + { key: 'trading/orders', icon: '', label: t('nav_trading_orders') }, ], }, { - key: 'risk', icon: '🛡️', label: '风控中心', + key: 'risk', icon: '🛡️', label: t('nav_risk'), children: [ - { key: 'risk/dashboard', icon: '', label: '风险仪表盘', badge: 3 }, - { key: 'risk/suspicious', icon: '', label: '可疑交易' }, - { key: 'risk/blacklist', icon: '', label: '黑名单管理' }, - { key: 'risk/ofac', icon: '', label: 'OFAC筛查日志' }, + { key: 'risk/dashboard', icon: '', label: t('nav_risk_dashboard'), badge: 3 }, + { key: 'risk/suspicious', icon: '', label: t('nav_risk_suspicious') }, + { key: 'risk/blacklist', icon: '', label: t('nav_risk_blacklist') }, + { key: 'risk/ofac', icon: '', label: t('nav_risk_ofac') }, ], }, { - key: 'compliance', icon: '📋', label: '合规报表', + key: 'compliance', icon: '📋', label: t('nav_compliance'), children: [ - { key: 'compliance/sar', icon: '', label: 'SAR管理' }, - { key: 'compliance/ctr', icon: '', label: 'CTR管理' }, - { key: 'compliance/audit', icon: '', label: '审计日志' }, - { key: 'compliance/reports', icon: '', label: '监管报表' }, + { key: 'compliance/sar', icon: '', label: t('nav_compliance_sar') }, + { key: 'compliance/ctr', icon: '', label: t('nav_compliance_ctr') }, + { key: 'compliance/audit', icon: '', label: t('nav_compliance_audit') }, + { key: 'compliance/reports', icon: '', label: t('nav_compliance_reports') }, ], }, { - key: 'system', icon: '⚙️', label: '系统管理', + key: 'system', icon: '⚙️', label: t('nav_system'), children: [ - { key: 'system/admins', icon: '', label: '管理员账号' }, - { key: 'system/config', icon: '', label: '系统配置' }, - { key: 'system/contracts', icon: '', label: '合约管理' }, - { key: 'system/monitor', icon: '', label: '系统监控' }, + { key: 'system/admins', icon: '', label: t('nav_system_admins') }, + { key: 'system/config', icon: '', label: t('nav_system_config') }, + { key: 'system/contracts', icon: '', label: t('nav_system_contracts') }, + { key: 'system/monitor', icon: '', label: t('nav_system_monitor') }, ], }, - { key: 'disputes', icon: '⚖️', label: '争议处理', badge: 8 }, - { key: 'coupons', icon: '🎫', label: '券管理' }, - { key: 'finance', icon: '💰', label: '财务管理' }, - { key: 'chain', icon: '⛓️', label: '链上监控' }, - { key: 'reports', icon: '📈', label: '报表中心' }, - { key: 'merchant', icon: '🏪', label: '商户核销' }, - { key: 'agent', icon: '🤖', label: '代理面板' }, - { key: 'insurance', icon: '🛡️', label: '保险管理' }, + { key: 'disputes', icon: '⚖️', label: t('nav_disputes'), badge: 8 }, + { key: 'coupons', icon: '🎫', label: t('nav_coupons_mgmt') }, + { key: 'finance', icon: '💰', label: t('nav_finance') }, + { key: 'chain', icon: '⛓️', label: t('nav_chain') }, + { key: 'reports', icon: '📈', label: t('nav_reports') }, + { key: 'merchant', icon: '🏪', label: t('nav_merchant') }, + { key: 'agent', icon: '🤖', label: t('nav_agent') }, + { key: 'insurance', icon: '🛡️', label: t('nav_insurance') }, { - key: 'analytics', icon: '📊', label: '数据分析', + key: 'analytics', icon: '📊', label: t('nav_analytics'), children: [ - { key: 'analytics/users', icon: '', label: '用户分析' }, - { key: 'analytics/coupons', icon: '', label: '券分析' }, - { key: 'analytics/market-maker', icon: '', label: '做市商分析' }, - { key: 'analytics/consumer-protection', icon: '', label: '消费者保护' }, + { key: 'analytics/users', icon: '', label: t('nav_analytics_users') }, + { key: 'analytics/coupons', icon: '', label: t('nav_analytics_coupons') }, + { key: 'analytics/market-maker', icon: '', label: t('nav_analytics_market_maker') }, + { key: 'analytics/consumer-protection', icon: '', label: t('nav_analytics_consumer_protection') }, ], }, ]; @@ -266,7 +267,7 @@ export const AdminLayout: React.FC<{ children: React.ReactNode }> = ({ children color: 'var(--color-text-tertiary)', }} > - {collapsed ? '→' : '← 收起'} + {collapsed ? '→' : `← ${t('collapse')}`} @@ -284,7 +285,7 @@ export const AdminLayout: React.FC<{ children: React.ReactNode }> = ({ children }}>
= ({ children cursor: 'pointer', font: 'var(--text-label-sm)', }}> - ✨ AI 助手 + ✨ {t('header_ai_assistant')} {/* Notifications */} + }}>{t('export_report')}
{/* Stats Grid */} @@ -88,7 +89,7 @@ export const ConsumerProtectionPage: React.FC = () => {
{ border: '1px solid var(--color-border-light)', padding: 20, }}> -
投诉分类
+
{t('cp_complaint_categories')}
{complaintCategories.map(cat => (
{cat.name} - {cat.count} 件 ({cat.percent}%) + {cat.count} {t('cp_unit_cases')} ({cat.percent}%)
{ padding: 20, flex: 1, }}> -
消费者满意度 (CSAT)
+
{t('cp_csat')}
4.5 /5.0 @@ -182,7 +183,7 @@ export const ConsumerProtectionPage: React.FC = () => { border: '1px solid var(--color-border-light)', padding: 20, }}> -
保障基金使用率
+
{t('cp_protection_fund')}
{ marginBottom: 24, }}>
- 近期投诉 + {t('cp_recent_complaints')} { - {['编号', '严重度', '分类', '描述', '状态', '负责人', '日期'].map(h => ( + {[t('cp_th_id'), t('cp_th_severity'), t('cp_th_category'), t('cp_th_description'), t('cp_th_status'), t('cp_th_assignee'), t('cp_th_date')].map(h => (
{ overflow: 'hidden', }}>
- 退款合规 - 不合规发行方 Top 5 + {t('cp_refund_compliance')}
- {['排名', '发行方', '违规次数', '退款通过率', '平均处理延迟', '风险等级', '操作'].map(h => ( + {[t('cp_th_rank'), t('cp_th_issuer'), t('cp_th_violations'), t('cp_th_refund_rate'), t('cp_th_avg_delay'), t('cp_th_risk_level'), t('actions')].map(h => ( ); diff --git a/frontend/admin-web/src/views/analytics/CouponAnalyticsPage.tsx b/frontend/admin-web/src/views/analytics/CouponAnalyticsPage.tsx index a45a016..172a23a 100644 --- a/frontend/admin-web/src/views/analytics/CouponAnalyticsPage.tsx +++ b/frontend/admin-web/src/views/analytics/CouponAnalyticsPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * 券分析仪表盘 @@ -7,10 +8,10 @@ import React from 'react'; */ const stats = [ - { label: '券总量', value: '45,230', change: '+6.5%', trend: 'up' as const, color: 'var(--color-primary)' }, - { label: '活跃券', value: '32,100', change: '+3.2%', trend: 'up' as const, color: 'var(--color-success)' }, - { label: '已核销', value: '8,450', change: '+12.1%', trend: 'up' as const, color: 'var(--color-info)' }, - { label: '即将过期', value: '2,340', change: '+8.7%', trend: 'up' as const, color: 'var(--color-warning)' }, + { label: t('ca_total_coupons'), value: '45,230', change: '+6.5%', trend: 'up' as const, color: 'var(--color-primary)' }, + { label: t('ca_active_coupons'), value: '32,100', change: '+3.2%', trend: 'up' as const, color: 'var(--color-success)' }, + { label: t('ca_redeemed'), value: '8,450', change: '+12.1%', trend: 'up' as const, color: 'var(--color-info)' }, + { label: t('ca_expiring_soon'), value: '2,340', change: '+8.7%', trend: 'up' as const, color: 'var(--color-warning)' }, ]; const categoryDistribution = [ @@ -44,19 +45,19 @@ const breakageTrend = [ ]; const secondaryMarket = [ - { metric: '挂牌率', value: '23.5%', change: '+1.2%', trend: 'up' as const }, - { metric: '平均加价率', value: '8.3%', change: '-0.5%', trend: 'down' as const }, - { metric: '日均交易量', value: '1,230', change: '+15.2%', trend: 'up' as const }, - { metric: '日均交易额', value: '$98,400', change: '+11.8%', trend: 'up' as const }, - { metric: '平均成交时间', value: '4.2h', change: '-8.3%', trend: 'down' as const }, - { metric: '撤单率', value: '12.1%', change: '+0.8%', trend: 'up' as const }, + { metric: 'Listing Rate', value: '23.5%', change: '+1.2%', trend: 'up' as const }, + { metric: 'Avg Markup', value: '8.3%', change: '-0.5%', trend: 'down' as const }, + { metric: 'Daily Volume', value: '1,230', change: '+15.2%', trend: 'up' as const }, + { metric: 'Daily Amount', value: '$98,400', change: '+11.8%', trend: 'up' as const }, + { metric: 'Avg Fill Time', value: '4.2h', change: '-8.3%', trend: 'down' as const }, + { metric: 'Cancel Rate', value: '12.1%', change: '+0.8%', trend: 'up' as const }, ]; export const CouponAnalyticsPage: React.FC = () => { return (

- 券分析 + {t('ca_title')}

{/* Stats Grid */} @@ -94,7 +95,7 @@ export const CouponAnalyticsPage: React.FC = () => { border: '1px solid var(--color-border-light)', padding: 20, }}> -
品类分布
+
{t('ca_category_distribution')}
{categoryDistribution.map(cat => (
@@ -127,7 +128,7 @@ export const CouponAnalyticsPage: React.FC = () => { border: '1px solid var(--color-border-light)', padding: 20, }}> -
面值分布
+
{t('ca_face_value_distribution')}
{ marginBottom: 24, }}>
- 热销券 Top 10 + {t('ca_top_selling')}
{ }}>{row.riskLevel} - - + +
- {['排名', '品牌', '券名称', '销量', '收入', '评分'].map(h => ( + {[t('ca_th_rank'), t('ca_th_brand'), t('ca_th_coupon_name'), t('ca_th_sales'), t('ca_th_revenue'), t('ca_th_rating')].map(h => (
{ border: '1px solid var(--color-border-light)', padding: 20, }}> -
Breakage趋势 (未核销率)
+
{t('ca_breakage_trend')}
{ border: '1px solid var(--color-border-light)', padding: 20, }}> -
二级市场分析
+
{t('ca_secondary_market')}
{secondaryMarket.map(item => (
= { - active: { bg: 'var(--color-success-light)', color: 'var(--color-success)', label: '活跃' }, - paused: { bg: 'var(--color-warning-light)', color: 'var(--color-warning)', label: '暂停' }, - suspended: { bg: 'var(--color-error-light)', color: 'var(--color-error)', label: '停用' }, + active: { bg: 'var(--color-success-light)', color: 'var(--color-success)', label: t('mm_status_active') }, + paused: { bg: 'var(--color-warning-light)', color: 'var(--color-warning)', label: t('mm_status_paused') }, + suspended: { bg: 'var(--color-error-light)', color: 'var(--color-error)', label: t('mm_status_suspended') }, }; const liquidityPools = [ @@ -55,20 +56,20 @@ const riskAlerts = [ ]; const severityConfig: Record = { - high: { bg: 'var(--color-error-light)', color: 'var(--color-error)', label: '高' }, - medium: { bg: 'var(--color-warning-light)', color: 'var(--color-warning)', label: '中' }, - low: { bg: 'var(--color-info-light)', color: 'var(--color-info)', label: '低' }, + high: { bg: 'var(--color-error-light)', color: 'var(--color-error)', label: t('severity_high') }, + medium: { bg: 'var(--color-warning-light)', color: 'var(--color-warning)', label: t('severity_medium') }, + low: { bg: 'var(--color-info-light)', color: 'var(--color-info)', label: t('severity_low') }, }; export const MarketMakerPage: React.FC = () => { return (
-

做市商管理

+

{t('mm_title')}

+ }}>{t('mm_add_new')}
{/* Stats Grid */} @@ -89,8 +90,8 @@ export const MarketMakerPage: React.FC = () => {
{stat.change} @@ -108,12 +109,12 @@ export const MarketMakerPage: React.FC = () => { marginBottom: 24, }}>
- 做市商列表 + {t('market_maker_list')}
- {['做市商', '状态', 'TVL', '价差', '日交易量', 'P&L', '操作'].map(h => ( + {[t('mm_th_name'), t('mm_th_status'), 'TVL', t('market_maker_spread'), t('mm_th_daily_volume'), t('market_maker_pnl'), t('actions')].map(h => ( @@ -171,14 +172,14 @@ export const MarketMakerPage: React.FC = () => { border: '1px solid var(--color-border-light)', padding: 20, }}> -
流动性池分布
+
{t('mm_liquidity_pools')}
{liquidityPools.map(pool => (
{pool.category} - {pool.makers} 做市商 + {pool.makers} {t('mm_unit_makers')} @@ -209,7 +210,7 @@ export const MarketMakerPage: React.FC = () => { border: '1px solid var(--color-border-light)', padding: 20, }}> -
订单簿深度
+
{t('mm_order_book_depth')}
{ border: '1px solid var(--color-border-light)', padding: 20, }}> -
市场健康指标
+
{t('mm_health_indicators')}
{healthIndicators.map(ind => (
{ padding: 20, }}>
-
风险预警
+
{t('mm_risk_alerts')}
{ color: 'var(--color-error)', font: 'var(--text-caption)', }}> - {riskAlerts.filter(a => a.severity === 'high').length} 高风险 + {riskAlerts.filter(a => a.severity === 'high').length} {t('mm_high_risk')}
{riskAlerts.map((alert, i) => { diff --git a/frontend/admin-web/src/views/analytics/UserAnalyticsPage.tsx b/frontend/admin-web/src/views/analytics/UserAnalyticsPage.tsx index c2badad..324c0d9 100644 --- a/frontend/admin-web/src/views/analytics/UserAnalyticsPage.tsx +++ b/frontend/admin-web/src/views/analytics/UserAnalyticsPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * 用户分析仪表盘 @@ -7,10 +8,10 @@ import React from 'react'; */ const stats = [ - { label: '总用户数', value: '128,456', change: '+3.2%', trend: 'up' as const, color: 'var(--color-primary)' }, + { label: t('ua_total_users'), value: '128,456', change: '+3.2%', trend: 'up' as const, color: 'var(--color-primary)' }, { label: 'DAU', value: '12,340', change: '+5.8%', trend: 'up' as const, color: 'var(--color-success)' }, { label: 'MAU', value: '45,678', change: '+2.1%', trend: 'up' as const, color: 'var(--color-info)' }, - { label: '新增用户/周', value: '1,234', change: '-1.4%', trend: 'down' as const, color: 'var(--color-warning)' }, + { label: t('ua_new_users_week'), value: '1,234', change: '-1.4%', trend: 'down' as const, color: 'var(--color-warning)' }, ]; const kycDistribution = [ @@ -42,17 +43,17 @@ const cohortRetention = [ ]; const userSegments = [ - { name: '高频交易', count: '8,456', percent: 6.6, color: 'var(--color-primary)' }, - { name: '偶尔购买', count: '34,230', percent: 26.6, color: 'var(--color-success)' }, - { name: '仅浏览', count: '52,890', percent: 41.2, color: 'var(--color-warning)' }, - { name: '流失用户', count: '32,880', percent: 25.6, color: 'var(--color-error)' }, + { name: t('ua_segment_high_freq'), count: '8,456', percent: 6.6, color: 'var(--color-primary)' }, + { name: t('ua_segment_occasional'), count: '34,230', percent: 26.6, color: 'var(--color-success)' }, + { name: t('ua_segment_browse'), count: '52,890', percent: 41.2, color: 'var(--color-warning)' }, + { name: t('ua_segment_churned'), count: '32,880', percent: 25.6, color: 'var(--color-error)' }, ]; export const UserAnalyticsPage: React.FC = () => { return (

- 用户分析 + {t('ua_title')}

{/* Stats Grid */} @@ -90,7 +91,7 @@ export const UserAnalyticsPage: React.FC = () => { marginBottom: 24, }}>
- 用户增长趋势 + {t('ua_growth_trend')}
{['7D', '30D', '90D', '1Y'].map(p => (
{ color: mm.pnl.startsWith('+') ? 'var(--color-success)' : 'var(--color-error)', }}>{mm.pnl} - + {mm.status === 'active' && ( - + )} {mm.status === 'paused' && ( - + )}
- {['排名', '地区', '用户数', '占比'].map(h => ( + {[t('ua_th_rank'), t('ua_th_region'), t('ua_th_users'), t('ua_th_percent')].map(h => (
{ overflow: 'hidden', }}>
- 用户留存矩阵 + {t('ua_retention_matrix')}
- {['注册周', 'Week 0', 'Week 1', 'Week 2', 'Week 3', 'Week 4'].map(h => ( + {[t('ua_th_cohort'), 'Week 0', 'Week 1', 'Week 2', 'Week 3', 'Week 4'].map(h => (
{ border: '1px solid var(--color-border-light)', padding: 20, }}> -
活跃用户分群
+
{t('ua_user_segments')}
{userSegments.map(seg => (
{ }} />
{seg.name}
-
{seg.count} 人
+
{seg.count} {t('ua_unit_people')}
{seg.percent}%
diff --git a/frontend/admin-web/src/views/chain/ChainMonitorPage.tsx b/frontend/admin-web/src/views/chain/ChainMonitorPage.tsx index 542b2e3..afe86b5 100644 --- a/frontend/admin-web/src/views/chain/ChainMonitorPage.tsx +++ b/frontend/admin-web/src/views/chain/ChainMonitorPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * D4. 链上监控 - 合约状态与链上数据 @@ -31,7 +32,7 @@ const eventColors: Record = { export const ChainMonitorPage: React.FC = () => { return (
-

链上监控

+

{t('chain_title')}

{/* Contract Status */}
@@ -55,7 +56,7 @@ export const ChainMonitorPage: React.FC = () => {
{/* Chain Events */}
-

最近链上事件

+

{t('chain_recent_events')}

{recentEvents.map((e, i) => (
{ {/* Gas Monitor */}
-

Gas费监控

+

{t('chain_gas_monitor')}

{[ - { label: '当前Gas', value: '12 gwei', color: 'var(--color-success)' }, - { label: '今日均值', value: '18 gwei', color: 'var(--color-info)' }, - { label: '今日Gas支出', value: '$1,234', color: 'var(--color-warning)' }, + { label: t('chain_current_gas'), value: '12 gwei', color: 'var(--color-success)' }, + { label: t('chain_today_avg'), value: '18 gwei', color: 'var(--color-info)' }, + { label: t('chain_today_gas_spend'), value: '$1,234', color: 'var(--color-warning)' }, ].map(g => (
{g.value}
diff --git a/frontend/admin-web/src/views/compliance/CompliancePage.tsx b/frontend/admin-web/src/views/compliance/CompliancePage.tsx index 83b07e6..d0506e2 100644 --- a/frontend/admin-web/src/views/compliance/CompliancePage.tsx +++ b/frontend/admin-web/src/views/compliance/CompliancePage.tsx @@ -1,6 +1,7 @@ 'use client'; import React, { useState } from 'react'; +import { t } from '@/i18n/locales'; /** * D6. 合规报表 @@ -14,7 +15,7 @@ export const CompliancePage: React.FC = () => { return (
-

合规报表

+

{t('compliance_title')}

{/* Tabs */}
{[ - { key: 'sar', label: 'SAR管理', badge: 3 }, - { key: 'ctr', label: 'CTR管理', badge: 0 }, - { key: 'audit', label: '审计日志', badge: 0 }, - { key: 'reports', label: '监管报表', badge: 0 }, - ].map(t => ( + { key: 'sar', label: t('compliance_tab_sar'), badge: 3 }, + { key: 'ctr', label: t('compliance_tab_ctr'), badge: 0 }, + { key: 'audit', label: t('compliance_tab_audit'), badge: 0 }, + { key: 'reports', label: t('compliance_tab_reports'), badge: 0 }, + ].map(tab => ( ))} @@ -77,16 +78,16 @@ export const CompliancePage: React.FC = () => { - {['SAR编号', '相关交易', '涉及用户', '金额', '风险类型', '状态', '创建时间', '操作'].map(h => ( + {[t('compliance_sar_id'), t('compliance_sar_related_txn'), t('compliance_sar_user'), t('compliance_sar_amount'), t('compliance_sar_risk_type'), t('compliance_sar_status'), t('compliance_sar_created'), t('actions')].map(h => ( ))} {[ - { id: 'SAR-2026-001', txn: 'TXN-8901', user: 'U-045', amount: '$4,560', type: '高频交易', status: '待提交' }, - { id: 'SAR-2026-002', txn: 'TXN-8900', user: 'U-078', amount: '$8,900', type: '大额异常', status: '已提交' }, - { id: 'SAR-2026-003', txn: 'TXN-8850', user: 'U-012', amount: '$12,000', type: '结构化交易', status: '已提交' }, + { id: 'SAR-2026-001', txn: 'TXN-8901', user: 'U-045', amount: '$4,560', type: t('risk_type_high_freq'), status: t('compliance_sar_pending') }, + { id: 'SAR-2026-002', txn: 'TXN-8900', user: 'U-078', amount: '$8,900', type: t('risk_type_large_single'), status: t('compliance_sar_submitted') }, + { id: 'SAR-2026-003', txn: 'TXN-8850', user: 'U-012', amount: '$12,000', type: t('risk_type_related_account'), status: t('compliance_sar_submitted') }, ].map(sar => ( @@ -103,14 +104,14 @@ export const CompliancePage: React.FC = () => { ))} @@ -130,8 +131,8 @@ export const CompliancePage: React.FC = () => { color: 'var(--color-text-tertiary)', }}>
📋
-
大额交易报告
-
超过$10,000的交易自动生成CTR,当前无待处理项
+
{t('compliance_ctr_title')}
+
{t('compliance_ctr_desc')}
)} @@ -145,11 +146,11 @@ export const CompliancePage: React.FC = () => { }}>
{Array.from({ length: 6 }, (_, i) => ( @@ -166,7 +167,7 @@ export const CompliancePage: React.FC = () => { background: 'var(--color-info-light)', color: 'var(--color-info)', font: 'var(--text-caption)', }}> - {['登录', '审核', '配置', '冻结', '导出', '查询'][i]} + {[t('compliance_audit_action_login'), t('compliance_audit_action_review'), t('compliance_audit_action_config'), t('compliance_audit_action_freeze'), t('compliance_audit_action_export'), t('compliance_audit_action_query')][i]} 管理员 admin{i + 1} {['登录系统', '审核发行方ISS-003通过', '修改手续费率为2.5%', '冻结用户U-045', '导出月度报表', '查询OFAC筛查记录'][i]} @@ -183,10 +184,10 @@ export const CompliancePage: React.FC = () => { {activeTab === 'reports' && (
{[ - { title: '日报', desc: '每日交易汇总、异常事件', date: '2026-02-10', auto: true }, - { title: '月报', desc: '月度运营指标、合规状态', date: '2026-01-31', auto: true }, - { title: '季度SAR汇总', desc: '季度可疑活动报告汇总', date: '2025-12-31', auto: false }, - { title: '年度合规报告', desc: '年度合规审计报告', date: '2025-12-31', auto: false }, + { title: t('compliance_report_daily'), desc: '每日交易汇总、异常事件', date: '2026-02-10', auto: true }, + { title: t('compliance_report_monthly'), desc: '月度运营指标、合规状态', date: '2026-01-31', auto: true }, + { title: t('compliance_report_sar_quarterly'), desc: '季度可疑活动报告汇总', date: '2025-12-31', auto: false }, + { title: t('compliance_report_annual'), desc: '年度合规审计报告', date: '2025-12-31', auto: false }, ].map(report => (
{ padding: '2px 8px', borderRadius: 'var(--radius-full)', background: 'var(--color-success-light)', color: 'var(--color-success)', font: 'var(--text-caption)', - }}>自动生成 + }}>{t('auto_generated')} )}
{report.desc}
- 截至 {report.date} + {t('as_of')} {report.date} + }}>{t('download')}
))} diff --git a/frontend/admin-web/src/views/compliance/IpoReadinessPage.tsx b/frontend/admin-web/src/views/compliance/IpoReadinessPage.tsx index cc7b158..6ebcf72 100644 --- a/frontend/admin-web/src/views/compliance/IpoReadinessPage.tsx +++ b/frontend/admin-web/src/views/compliance/IpoReadinessPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * D8.4 IPO准备度检查清单 - 独立页面 @@ -19,11 +20,11 @@ interface CheckItem { } const categories = [ - { key: 'legal', label: '法律合规', icon: '§', color: 'var(--color-primary)' }, - { key: 'financial', label: '财务审计', icon: '$', color: 'var(--color-success)' }, - { key: 'sox', label: 'SOX合规', icon: '✓', color: 'var(--color-info)' }, - { key: 'governance', label: '公司治理', icon: '◆', color: 'var(--color-warning)' }, - { key: 'insurance', label: '保险保障', icon: '☂', color: '#FF6B6B' }, + { key: 'legal', label: t('ipo_cat_legal'), icon: '§', color: 'var(--color-primary)' }, + { key: 'financial', label: t('ipo_cat_financial'), icon: '$', color: 'var(--color-success)' }, + { key: 'sox', label: t('ipo_cat_sox'), icon: '✓', color: 'var(--color-info)' }, + { key: 'governance', label: t('ipo_cat_governance'), icon: '◆', color: 'var(--color-warning)' }, + { key: 'insurance', label: t('ipo_cat_insurance'), icon: '☂', color: '#FF6B6B' }, ]; const overallProgress = { @@ -79,28 +80,28 @@ const checklistItems: CheckItem[] = [ ]; const statusConfig: Record = { - done: { label: '已完成', bg: 'var(--color-success-light)', fg: 'var(--color-success)' }, - progress: { label: '进行中', bg: 'var(--color-warning-light)', fg: 'var(--color-warning)' }, - blocked: { label: '阻塞', bg: 'var(--color-error-light)', fg: 'var(--color-error)' }, - pending: { label: '待开始', bg: 'var(--color-gray-100)', fg: 'var(--color-text-tertiary)' }, + done: { label: t('completed'), bg: 'var(--color-success-light)', fg: 'var(--color-success)' }, + progress: { label: t('in_progress'), bg: 'var(--color-warning-light)', fg: 'var(--color-warning)' }, + blocked: { label: t('blocked'), bg: 'var(--color-error-light)', fg: 'var(--color-error)' }, + pending: { label: t('pending'), bg: 'var(--color-gray-100)', fg: 'var(--color-text-tertiary)' }, }; export const IpoReadinessPage: React.FC = () => { return (
-

IPO准备度检查清单

+

{t('ipo_title')}

- 跟踪所有IPO里程碑、合规项、依赖关系和阻塞项 + {t('ipo_subtitle')}

{/* Summary Stats */}
{[ - { label: '总计检查项', value: overallProgress.total, color: 'var(--color-text-primary)' }, - { label: '已完成', value: overallProgress.done, color: 'var(--color-success)' }, - { label: '进行中', value: overallProgress.inProgress, color: 'var(--color-warning)' }, - { label: '阻塞项', value: overallProgress.blocked, color: 'var(--color-error)' }, - { label: '待开始', value: overallProgress.pending, color: 'var(--color-text-tertiary)' }, + { label: t('ipo_total_items'), value: overallProgress.total, color: 'var(--color-text-primary)' }, + { label: t('completed'), value: overallProgress.done, color: 'var(--color-success)' }, + { label: t('in_progress'), value: overallProgress.inProgress, color: 'var(--color-warning)' }, + { label: t('blocked'), value: overallProgress.blocked, color: 'var(--color-error)' }, + { label: t('pending'), value: overallProgress.pending, color: 'var(--color-text-tertiary)' }, ].map(s => (
{ border: '1px solid var(--color-border-light)', padding: 20, marginBottom: 24, }}>
- 总体IPO准备进度 + {t('ipo_overall_progress')} {overallProgress.percent}%
@@ -128,10 +129,10 @@ export const IpoReadinessPage: React.FC = () => {
{[ - { label: '已完成', color: 'var(--color-success)' }, - { label: '进行中', color: 'var(--color-warning)' }, - { label: '阻塞', color: 'var(--color-error)' }, - { label: '待开始', color: 'var(--color-gray-200)' }, + { label: t('completed'), color: 'var(--color-success)' }, + { label: t('in_progress'), color: 'var(--color-warning)' }, + { label: t('blocked'), color: 'var(--color-error)' }, + { label: t('pending'), color: 'var(--color-gray-200)' }, ].map(l => (
@@ -164,14 +165,14 @@ export const IpoReadinessPage: React.FC = () => { {cat.label}
- {catDone}/{items.length} 完成 + {catDone}/{items.length} {t('ipo_unit_done')}
{h}
{sar.id} {sar.status} 2026-02-{10 - parseInt(sar.id.slice(-1))} - +
- {['编号', '检查项', '负责方', '截止日', '状态'].map(h => ( + {[t('ipo_th_id'), t('ipo_th_item'), t('ipo_th_owner'), t('ipo_th_deadline'), t('ipo_th_status')].map(h => (
{ {item.note &&
{item.note}
} {item.dependency && (
- 依赖: {item.dependency} + {t('ipo_dependency')}: {item.dependency}
)} @@ -219,7 +220,7 @@ export const IpoReadinessPage: React.FC = () => { background: 'var(--color-surface)', borderRadius: 'var(--radius-md)', border: '1px solid var(--color-border-light)', padding: 20, marginBottom: 16, }}> -

IPO时间线

+

{t('ipo_timeline')}

{milestones.map((m, i) => (
@@ -245,14 +246,14 @@ export const IpoReadinessPage: React.FC = () => { background: 'var(--color-surface)', borderRadius: 'var(--radius-md)', border: '1px solid var(--color-error)', padding: 20, marginBottom: 16, }}> -

阻塞项

+

{t('ipo_blockers')}

{checklistItems.filter(i => i.status === 'blocked').map(item => (
{item.id}: {item.item}
- 负责: {item.owner} · 截止: {item.deadline} + {t('ipo_owner')}: {item.owner} · {t('ipo_deadline')}: {item.deadline}
{item.note && (
{item.note}
@@ -266,7 +267,7 @@ export const IpoReadinessPage: React.FC = () => { background: 'var(--color-surface)', borderRadius: 'var(--radius-md)', border: '1px solid var(--color-border-light)', padding: 20, marginBottom: 16, }}> -

分类进度

+

{t('ipo_category_progress')}

{categories.map(cat => { const items = checklistItems.filter(i => i.category === cat.key); const catDone = items.filter(i => i.status === 'done').length; @@ -290,7 +291,7 @@ export const IpoReadinessPage: React.FC = () => { background: 'var(--color-surface)', borderRadius: 'var(--radius-md)', border: '1px solid var(--color-border-light)', padding: 20, }}> -

关键联系方

+

{t('ipo_key_contacts')}

{[ { role: '承销商 (Lead)', name: 'Goldman Sachs', status: '已签约' }, { role: '审计师', name: 'Deloitte', status: '审计中' }, diff --git a/frontend/admin-web/src/views/compliance/LicenseManagementPage.tsx b/frontend/admin-web/src/views/compliance/LicenseManagementPage.tsx index 4d0b984..8c9c4d6 100644 --- a/frontend/admin-web/src/views/compliance/LicenseManagementPage.tsx +++ b/frontend/admin-web/src/views/compliance/LicenseManagementPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * License & Regulatory Permits Management - 牌照与监管许可管理 @@ -8,23 +9,23 @@ import React from 'react'; */ const licenseStats = [ - { label: '活跃牌照数', value: '12', color: 'var(--color-success)' }, - { label: '待申请', value: '4', color: 'var(--color-info)' }, - { label: '即将到期', value: '2', color: 'var(--color-warning)' }, - { label: '已吊销', value: '0', color: 'var(--color-error)' }, + { label: t('license_active_count'), value: '12', color: 'var(--color-success)' }, + { label: t('license_pending'), value: '4', color: 'var(--color-info)' }, + { label: t('license_expiring_soon'), value: '2', color: 'var(--color-warning)' }, + { label: t('license_revoked'), value: '0', color: 'var(--color-error)' }, ]; const licenses = [ - { id: 'LIC-001', name: 'FinCEN MSB Registration', jurisdiction: 'Federal (US)', regBody: 'FinCEN', status: '有效', issueDate: '2024-06-01', expiryDate: '2026-06-01' }, - { id: 'LIC-002', name: 'New York BitLicense', jurisdiction: 'New York', regBody: 'NYDFS', status: '有效', issueDate: '2024-09-15', expiryDate: '2026-09-15' }, - { id: 'LIC-003', name: 'California MTL', jurisdiction: 'California', regBody: 'DFPI', status: '有效', issueDate: '2025-01-10', expiryDate: '2027-01-10' }, - { id: 'LIC-004', name: 'Texas Money Transmitter', jurisdiction: 'Texas', regBody: 'TDSML', status: '即将到期', issueDate: '2024-03-20', expiryDate: '2026-03-20' }, - { id: 'LIC-005', name: 'Florida Money Transmitter', jurisdiction: 'Florida', regBody: 'OFR', status: '有效', issueDate: '2025-04-01', expiryDate: '2027-04-01' }, - { id: 'LIC-006', name: 'Illinois TOMA', jurisdiction: 'Illinois', regBody: 'IDFPR', status: '申请中', issueDate: '-', expiryDate: '-' }, - { id: 'LIC-007', name: 'Washington Money Transmitter', jurisdiction: 'Washington', regBody: 'DFI', status: '有效', issueDate: '2025-02-15', expiryDate: '2027-02-15' }, - { id: 'LIC-008', name: 'SEC Broker-Dealer Registration', jurisdiction: 'Federal (US)', regBody: 'SEC / FINRA', status: '申请中', issueDate: '-', expiryDate: '-' }, - { id: 'LIC-009', name: 'Georgia Money Transmitter', jurisdiction: 'Georgia', regBody: 'DBF', status: '待续期', issueDate: '2024-02-28', expiryDate: '2026-02-28' }, - { id: 'LIC-010', name: 'Nevada Money Transmitter', jurisdiction: 'Nevada', regBody: 'FID', status: '有效', issueDate: '2025-06-01', expiryDate: '2027-06-01' }, + { id: 'LIC-001', name: 'FinCEN MSB Registration', jurisdiction: 'Federal (US)', regBody: 'FinCEN', status: t('license_status_active'), issueDate: '2024-06-01', expiryDate: '2026-06-01' }, + { id: 'LIC-002', name: 'New York BitLicense', jurisdiction: 'New York', regBody: 'NYDFS', status: t('license_status_active'), issueDate: '2024-09-15', expiryDate: '2026-09-15' }, + { id: 'LIC-003', name: 'California MTL', jurisdiction: 'California', regBody: 'DFPI', status: t('license_status_active'), issueDate: '2025-01-10', expiryDate: '2027-01-10' }, + { id: 'LIC-004', name: 'Texas Money Transmitter', jurisdiction: 'Texas', regBody: 'TDSML', status: t('license_status_expiring'), issueDate: '2024-03-20', expiryDate: '2026-03-20' }, + { id: 'LIC-005', name: 'Florida Money Transmitter', jurisdiction: 'Florida', regBody: 'OFR', status: t('license_status_active'), issueDate: '2025-04-01', expiryDate: '2027-04-01' }, + { id: 'LIC-006', name: 'Illinois TOMA', jurisdiction: 'Illinois', regBody: 'IDFPR', status: t('license_status_applying'), issueDate: '-', expiryDate: '-' }, + { id: 'LIC-007', name: 'Washington Money Transmitter', jurisdiction: 'Washington', regBody: 'DFI', status: t('license_status_active'), issueDate: '2025-02-15', expiryDate: '2027-02-15' }, + { id: 'LIC-008', name: 'SEC Broker-Dealer Registration', jurisdiction: 'Federal (US)', regBody: 'SEC / FINRA', status: t('license_status_applying'), issueDate: '-', expiryDate: '-' }, + { id: 'LIC-009', name: 'Georgia Money Transmitter', jurisdiction: 'Georgia', regBody: 'DBF', status: t('license_status_renewal'), issueDate: '2024-02-28', expiryDate: '2026-02-28' }, + { id: 'LIC-010', name: 'Nevada Money Transmitter', jurisdiction: 'Nevada', regBody: 'FID', status: t('license_status_active'), issueDate: '2025-06-01', expiryDate: '2027-06-01' }, ]; const regulatoryBodies = [ @@ -45,15 +46,15 @@ const renewalAlerts = [ const getLicenseStatusStyle = (status: string) => { switch (status) { - case '有效': + case t('license_status_active'): return { background: 'var(--color-success-light)', color: 'var(--color-success)' }; - case '申请中': + case t('license_status_applying'): return { background: 'var(--color-info-light)', color: 'var(--color-info)' }; - case '待续期': + case t('license_status_renewal'): return { background: 'var(--color-warning-light)', color: 'var(--color-warning)' }; - case '即将到期': + case t('license_status_expiring'): return { background: 'var(--color-error-light)', color: 'var(--color-error)' }; - case '已过期': + case t('license_status_expired'): return { background: 'var(--color-gray-100)', color: 'var(--color-error)' }; default: return { background: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }; @@ -79,7 +80,7 @@ export const LicenseManagementPage: React.FC = () => { return (
-

牌照与监管许可管理

+

{t('license_title')}

@@ -112,12 +113,12 @@ export const LicenseManagementPage: React.FC = () => { border: '1px solid var(--color-border-light)', overflow: 'hidden', marginBottom: 24, }}>
-

牌照清单

+

{t('license_list')}

- {['编号', '牌照名称', '司法管辖区', '监管机构', '签发日期', '到期日期', '状态', '操作'].map(h => ( + {[t('license_th_id'), t('license_th_name'), t('license_th_jurisdiction'), t('license_th_reg_body'), t('license_th_issue_date'), t('license_th_expiry_date'), t('license_th_status'), t('actions')].map(h => ( ))} @@ -144,7 +145,7 @@ export const LicenseManagementPage: React.FC = () => { }}>{l.status} ))} @@ -155,7 +156,7 @@ export const LicenseManagementPage: React.FC = () => {
{/* Regulatory Body Mapping */}
-

监管机构映射

+

{t('license_reg_body_mapping')}

{regulatoryBodies.map((rb, i) => (
{ color: rb.licenses > 0 ? 'var(--color-success)' : 'var(--color-text-tertiary)', font: 'var(--text-caption)', }}> - {rb.licenses > 0 ? `${rb.licenses} 牌照` : '未申请'} + {rb.licenses > 0 ? `${rb.licenses} ${t('license_unit')}` : t('not_applied')}
))} @@ -185,7 +186,7 @@ export const LicenseManagementPage: React.FC = () => { {/* Renewal Alerts */}
-

续期提醒

+

{t('license_renewal_alerts')}

{renewalAlerts.map((alert, i) => (
{ padding: '2px 8px', borderRadius: 'var(--radius-full)', font: 'var(--text-caption)', fontWeight: 600, ...getUrgencyStyle(alert.urgency), }}> - {alert.urgency === 'critical' ? '紧急' : alert.urgency === 'high' ? '高' : alert.urgency === 'medium' ? '中' : '低'} + {alert.urgency === 'critical' ? t('urgency_critical') : alert.urgency === 'high' ? t('urgency_high') : alert.urgency === 'medium' ? t('urgency_medium') : t('urgency_low')}
- 到期日: {alert.expiryDate} + {t('expiry_date')}: {alert.expiryDate} - 剩余 {alert.daysRemaining} 天 + {t('remaining_days').replace('{0}', String(alert.daysRemaining))}
{alert.urgency === 'critical' && ( @@ -218,7 +219,7 @@ export const LicenseManagementPage: React.FC = () => { background: 'var(--color-error)', color: 'white', cursor: 'pointer', font: 'var(--text-label-sm)', }}> - 立即续期 + {t('renew_now')} )}
@@ -226,7 +227,7 @@ export const LicenseManagementPage: React.FC = () => { {/* Summary */}
- 共 {licenses.filter(l => l.status === '有效').length} 个有效牌照覆盖 {new Set(licenses.filter(l => l.status === '有效').map(l => l.jurisdiction)).size} 个司法管辖区 + {licenses.filter(l => l.status === t('license_status_active')).length} {t('license_jurisdictions_covered').replace('{0}', String(new Set(licenses.filter(l => l.status === t('license_status_active')).map(l => l.jurisdiction)).size))}
diff --git a/frontend/admin-web/src/views/compliance/SecFilingPage.tsx b/frontend/admin-web/src/views/compliance/SecFilingPage.tsx index 6609da0..7d1f186 100644 --- a/frontend/admin-web/src/views/compliance/SecFilingPage.tsx +++ b/frontend/admin-web/src/views/compliance/SecFilingPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * SEC Filing Management - SEC文件提交与管理 @@ -8,19 +9,19 @@ import React from 'react'; */ const filingStats = [ - { label: '已提交文件数', value: '24', color: 'var(--color-primary)' }, - { label: '待审核', value: '3', color: 'var(--color-warning)' }, - { label: '已通过', value: '19', color: 'var(--color-success)' }, - { label: '距下次截止', value: '18天', color: 'var(--color-error)' }, + { label: t('sec_filed_count'), value: '24', color: 'var(--color-primary)' }, + { label: t('sec_pending_review'), value: '3', color: 'var(--color-warning)' }, + { label: t('sec_passed'), value: '19', color: 'var(--color-success)' }, + { label: t('sec_next_deadline'), value: '18天', color: 'var(--color-error)' }, ]; const secFilings = [ - { id: 'SEC-001', formType: 'S-1', title: 'IPO注册声明书', filingDate: '2026-01-15', deadline: '2026-02-28', status: '审核中', reviewer: 'SEC Division of Corporation Finance' }, - { id: 'SEC-002', formType: '10-K', title: '2025年度报告', filingDate: '2026-01-30', deadline: '2026-03-31', status: '已提交', reviewer: 'Internal Audit' }, - { id: 'SEC-003', formType: '10-Q', title: '2025 Q4季度报告', filingDate: '2026-02-01', deadline: '2026-02-15', status: '已通过', reviewer: 'External Auditor' }, - { id: 'SEC-004', formType: '8-K', title: '重大事项披露-战略合作', filingDate: '2026-02-05', deadline: '2026-02-09', status: '已通过', reviewer: 'Legal Counsel' }, - { id: 'SEC-005', formType: 'S-1/A', title: 'S-1修订稿(第2版)', filingDate: '2026-02-08', deadline: '2026-02-28', status: '需修订', reviewer: 'SEC Division of Corporation Finance' }, - { id: 'SEC-006', formType: '10-Q', title: '2026 Q1季度报告', filingDate: '', deadline: '2026-05-15', status: '待提交', reviewer: '-' }, + { id: 'SEC-001', formType: 'S-1', title: 'IPO注册声明书', filingDate: '2026-01-15', deadline: '2026-02-28', status: t('sec_status_reviewing'), reviewer: 'SEC Division of Corporation Finance' }, + { id: 'SEC-002', formType: '10-K', title: '2025年度报告', filingDate: '2026-01-30', deadline: '2026-03-31', status: t('sec_status_submitted'), reviewer: 'Internal Audit' }, + { id: 'SEC-003', formType: '10-Q', title: '2025 Q4季度报告', filingDate: '2026-02-01', deadline: '2026-02-15', status: t('sec_status_passed'), reviewer: 'External Auditor' }, + { id: 'SEC-004', formType: '8-K', title: '重大事项披露-战略合作', filingDate: '2026-02-05', deadline: '2026-02-09', status: t('sec_status_passed'), reviewer: 'Legal Counsel' }, + { id: 'SEC-005', formType: 'S-1/A', title: 'S-1修订稿(第2版)', filingDate: '2026-02-08', deadline: '2026-02-28', status: t('sec_status_needs_revision'), reviewer: 'SEC Division of Corporation Finance' }, + { id: 'SEC-006', formType: '10-Q', title: '2026 Q1季度报告', filingDate: '', deadline: '2026-05-15', status: t('sec_status_pending'), reviewer: '-' }, ]; const timelineEvents = [ @@ -44,15 +45,15 @@ const disclosureItems = [ const getFilingStatusStyle = (status: string) => { switch (status) { - case '已通过': + case t('sec_status_passed'): return { background: 'var(--color-success-light)', color: 'var(--color-success)' }; - case '审核中': + case t('sec_status_reviewing'): return { background: 'var(--color-info-light)', color: 'var(--color-info)' }; - case '已提交': + case t('sec_status_submitted'): return { background: 'var(--color-primary-light)', color: 'var(--color-primary)' }; - case '需修订': + case t('sec_status_needs_revision'): return { background: 'var(--color-error-light)', color: 'var(--color-error)' }; - case '待提交': + case t('sec_status_pending'): return { background: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }; default: return { background: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }; @@ -63,7 +64,7 @@ export const SecFilingPage: React.FC = () => { return (
-

SEC文件管理

+

{t('sec_title')}

@@ -96,12 +97,12 @@ export const SecFilingPage: React.FC = () => { border: '1px solid var(--color-border-light)', overflow: 'hidden', marginBottom: 24, }}>
-

SEC申报文件列表

+

{t('sec_filing_list')}

{h}
- +
- {['编号', '表格类型', '标题', '提交日期', '截止日期', '审核方', '状态', '操作'].map(h => ( + {[t('sec_th_id'), t('sec_th_form_type'), t('sec_th_title'), t('sec_th_filing_date'), t('sec_th_deadline'), t('sec_th_reviewer'), t('sec_th_status'), t('actions')].map(h => ( ))} @@ -128,7 +129,7 @@ export const SecFilingPage: React.FC = () => { }}>{f.status} ))} @@ -139,7 +140,7 @@ export const SecFilingPage: React.FC = () => {
{/* Filing Timeline */}
-

申报日程

+

{t('sec_timeline')}

{timelineEvents.map((evt, i) => (
{ padding: '2px 8px', borderRadius: 'var(--radius-full)', background: 'var(--color-error-light)', color: 'var(--color-error)', font: 'var(--text-caption)', whiteSpace: 'nowrap', - }}>即将到期 + }}>{t('sec_upcoming')} )}
))} @@ -167,7 +168,7 @@ export const SecFilingPage: React.FC = () => { {/* Auto-generation Status */}
-

披露文件自动生成状态

+

{t('sec_disclosure_status')}

{disclosureItems.map((item, i) => (
{ font: 'var(--text-caption)', color: item.status === 'done' ? 'var(--color-success)' : item.status === 'progress' ? 'var(--color-warning)' : 'var(--color-text-tertiary)', }}> - {item.status === 'done' ? '已完成' : item.status === 'progress' ? '生成中' : '待开始'} + {item.status === 'done' ? t('completed') : item.status === 'progress' ? t('generating') : t('pending')}
))} {/* Overall Progress */}
- 披露文件完成度 + {t('sec_disclosure_progress')} 57%
diff --git a/frontend/admin-web/src/views/compliance/SoxCompliancePage.tsx b/frontend/admin-web/src/views/compliance/SoxCompliancePage.tsx index 77ae7fa..02638f7 100644 --- a/frontend/admin-web/src/views/compliance/SoxCompliancePage.tsx +++ b/frontend/admin-web/src/views/compliance/SoxCompliancePage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * SOX Compliance (Sarbanes-Oxley) - SOX合规管理 @@ -11,76 +12,76 @@ const overallScore = 78; const controlCategories = [ { - name: '财务报告内控 (ICFR)', - description: '确保财务报告的准确性和完整性,包括收入确认、费用分摊、资产估值等关键控制点', + name: 'ICFR', + description: 'Financial Reporting Internal Controls - Revenue recognition, expense allocation, asset valuation', controls: [ - { name: '收入确认控制', result: '通过', lastTest: '2026-01-15', nextTest: '2026-04-15' }, - { name: '费用审批流程', result: '通过', lastTest: '2026-01-20', nextTest: '2026-04-20' }, - { name: '期末关账控制', result: '发现缺陷', lastTest: '2026-02-01', nextTest: '2026-03-01' }, - { name: '合并报表控制', result: '通过', lastTest: '2026-01-25', nextTest: '2026-04-25' }, + { name: 'Revenue Recognition', result: t('sox_result_passed'), lastTest: '2026-01-15', nextTest: '2026-04-15' }, + { name: 'Expense Approval', result: t('sox_result_passed'), lastTest: '2026-01-20', nextTest: '2026-04-20' }, + { name: 'Period-end Close', result: t('sox_result_defect'), lastTest: '2026-02-01', nextTest: '2026-03-01' }, + { name: 'Consolidation', result: t('sox_result_passed'), lastTest: '2026-01-25', nextTest: '2026-04-25' }, ], }, { - name: 'IT通用控制 (ITGC)', - description: '信息系统通用控制,包括系统开发、程序变更、计算机操作和数据安全', + name: 'ITGC', + description: 'IT General Controls - System development, program change, computer operations, data security', controls: [ - { name: '系统开发生命周期', result: '通过', lastTest: '2026-01-10', nextTest: '2026-04-10' }, - { name: '程序变更管理', result: '通过', lastTest: '2026-01-18', nextTest: '2026-04-18' }, - { name: '数据备份与恢复', result: '发现缺陷', lastTest: '2026-02-03', nextTest: '2026-03-03' }, - { name: '逻辑安全控制', result: '待测试', lastTest: '-', nextTest: '2026-02-20' }, + { name: 'SDLC', result: t('sox_result_passed'), lastTest: '2026-01-10', nextTest: '2026-04-10' }, + { name: 'Change Management', result: t('sox_result_passed'), lastTest: '2026-01-18', nextTest: '2026-04-18' }, + { name: 'Backup & Recovery', result: t('sox_result_defect'), lastTest: '2026-02-03', nextTest: '2026-03-03' }, + { name: 'Logical Security', result: t('sox_result_pending'), lastTest: '-', nextTest: '2026-02-20' }, ], }, { - name: '访问控制', - description: '系统与数据访问权限管理,包括用户权限分配、特权账户管理、职责分离', + name: 'Access Control', + description: 'System & data access management - User permissions, privileged accounts, SoD', controls: [ - { name: '用户权限审查', result: '通过', lastTest: '2026-02-01', nextTest: '2026-05-01' }, - { name: '特权账户管理', result: '通过', lastTest: '2026-01-28', nextTest: '2026-04-28' }, - { name: '职责分离 (SoD)', result: '发现缺陷', lastTest: '2026-02-05', nextTest: '2026-03-05' }, + { name: 'User Access Review', result: t('sox_result_passed'), lastTest: '2026-02-01', nextTest: '2026-05-01' }, + { name: 'Privileged Access', result: t('sox_result_passed'), lastTest: '2026-01-28', nextTest: '2026-04-28' }, + { name: 'SoD', result: t('sox_result_defect'), lastTest: '2026-02-05', nextTest: '2026-03-05' }, ], }, { - name: '变更管理', - description: '对生产环境变更的审批、测试、部署流程控制', + name: 'Change Management', + description: 'Production change approval, testing, deployment process controls', controls: [ - { name: '变更审批流程', result: '通过', lastTest: '2026-01-22', nextTest: '2026-04-22' }, - { name: '部署前测试验证', result: '通过', lastTest: '2026-01-30', nextTest: '2026-04-30' }, - { name: '紧急变更管理', result: '待测试', lastTest: '-', nextTest: '2026-02-25' }, + { name: 'Change Approval', result: t('sox_result_passed'), lastTest: '2026-01-22', nextTest: '2026-04-22' }, + { name: 'Pre-deploy Testing', result: t('sox_result_passed'), lastTest: '2026-01-30', nextTest: '2026-04-30' }, + { name: 'Emergency Change', result: t('sox_result_pending'), lastTest: '-', nextTest: '2026-02-25' }, ], }, { - name: '运营控制', - description: '日常运营流程控制,包括交易监控、对账、异常处理', + name: 'Operational Controls', + description: 'Daily operations - Transaction monitoring, reconciliation, exception handling', controls: [ - { name: '日终对账', result: '通过', lastTest: '2026-02-08', nextTest: '2026-05-08' }, - { name: '异常交易监控', result: '通过', lastTest: '2026-02-06', nextTest: '2026-05-06' }, - { name: '客户资金隔离', result: '通过', lastTest: '2026-02-04', nextTest: '2026-05-04' }, + { name: 'EOD Reconciliation', result: t('sox_result_passed'), lastTest: '2026-02-08', nextTest: '2026-05-08' }, + { name: 'Anomaly Monitoring', result: t('sox_result_passed'), lastTest: '2026-02-06', nextTest: '2026-05-06' }, + { name: 'Client Fund Segregation', result: t('sox_result_passed'), lastTest: '2026-02-04', nextTest: '2026-05-04' }, ], }, ]; const deficiencies = [ - { id: 'DEF-001', control: '期末关账控制', category: 'ICFR', severity: '重大缺陷', description: '部分手工调整缺少二级审批', foundDate: '2026-02-01', dueDate: '2026-03-01', status: '整改中', owner: 'CFO办公室' }, - { id: 'DEF-002', control: '数据备份与恢复', category: 'ITGC', severity: '一般缺陷', description: 'DR演练未按季度执行', foundDate: '2026-02-03', dueDate: '2026-03-15', status: '整改中', owner: 'IT部门' }, - { id: 'DEF-003', control: '职责分离 (SoD)', category: '访问控制', severity: '重大缺陷', description: '3名用户同时拥有创建与审批权限', foundDate: '2026-02-05', dueDate: '2026-02-20', status: '待整改', owner: '合规部门' }, + { id: 'DEF-001', control: 'Period-end Close', category: 'ICFR', severity: t('sox_severity_major'), description: 'Manual adjustments missing secondary approval', foundDate: '2026-02-01', dueDate: '2026-03-01', status: t('sox_status_remediating'), owner: 'CFO Office' }, + { id: 'DEF-002', control: 'Backup & Recovery', category: 'ITGC', severity: t('sox_severity_minor'), description: 'DR drill not executed quarterly', foundDate: '2026-02-03', dueDate: '2026-03-15', status: t('sox_status_remediating'), owner: 'IT Dept' }, + { id: 'DEF-003', control: 'SoD', category: 'Access Control', severity: t('sox_severity_major'), description: '3 users with both create & approve access', foundDate: '2026-02-05', dueDate: '2026-02-20', status: t('sox_status_pending'), owner: 'Compliance' }, ]; const auditorReview = [ - { phase: '审计计划确认', status: 'done', date: '2026-01-05', auditor: 'Deloitte' }, - { phase: 'Walk-through 测试', status: 'done', date: '2026-01-20', auditor: 'Deloitte' }, - { phase: '控制有效性测试', status: 'progress', date: '2026-02-10', auditor: 'Deloitte' }, - { phase: '缺陷评估与分类', status: 'pending', date: '2026-03-01', auditor: 'Deloitte' }, - { phase: '管理层报告出具', status: 'pending', date: '2026-03-15', auditor: 'Deloitte' }, - { phase: '最终审计意见', status: 'pending', date: '2026-04-01', auditor: 'Deloitte' }, + { phase: 'Audit Plan Confirmation', status: 'done', date: '2026-01-05', auditor: 'Deloitte' }, + { phase: 'Walk-through Testing', status: 'done', date: '2026-01-20', auditor: 'Deloitte' }, + { phase: 'Controls Effectiveness Testing', status: 'progress', date: '2026-02-10', auditor: 'Deloitte' }, + { phase: 'Deficiency Assessment', status: 'pending', date: '2026-03-01', auditor: 'Deloitte' }, + { phase: 'Management Report', status: 'pending', date: '2026-03-15', auditor: 'Deloitte' }, + { phase: 'Final Audit Opinion', status: 'pending', date: '2026-04-01', auditor: 'Deloitte' }, ]; const getResultStyle = (result: string) => { switch (result) { - case '通过': + case t('sox_result_passed'): return { background: 'var(--color-success-light)', color: 'var(--color-success)' }; - case '发现缺陷': + case t('sox_result_defect'): return { background: 'var(--color-error-light)', color: 'var(--color-error)' }; - case '待测试': + case t('sox_result_pending'): return { background: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }; default: return { background: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }; @@ -89,11 +90,11 @@ const getResultStyle = (result: string) => { const getSeverityStyle = (severity: string) => { switch (severity) { - case '重大缺陷': + case t('sox_severity_major'): return { background: 'var(--color-error-light)', color: 'var(--color-error)' }; - case '一般缺陷': + case t('sox_severity_minor'): return { background: 'var(--color-warning-light)', color: 'var(--color-warning)' }; - case '观察项': + case t('sox_severity_observation'): return { background: 'var(--color-info-light)', color: 'var(--color-info)' }; default: return { background: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }; @@ -102,13 +103,13 @@ const getSeverityStyle = (severity: string) => { export const SoxCompliancePage: React.FC = () => { const totalControls = controlCategories.reduce((sum, cat) => sum + cat.controls.length, 0); - const passedControls = controlCategories.reduce((sum, cat) => sum + cat.controls.filter(c => c.result === '通过').length, 0); - const defectControls = controlCategories.reduce((sum, cat) => sum + cat.controls.filter(c => c.result === '发现缺陷').length, 0); - const pendingControls = controlCategories.reduce((sum, cat) => sum + cat.controls.filter(c => c.result === '待测试').length, 0); + const passedControls = controlCategories.reduce((sum, cat) => sum + cat.controls.filter(c => c.result === t('sox_result_passed')).length, 0); + const defectControls = controlCategories.reduce((sum, cat) => sum + cat.controls.filter(c => c.result === t('sox_result_defect')).length, 0); + const pendingControls = controlCategories.reduce((sum, cat) => sum + cat.controls.filter(c => c.result === t('sox_result_pending')).length, 0); return (
-

SOX合规管理

+

{t('sox_title')}

{/* Compliance Score Gauge + Summary Stats */}
@@ -118,7 +119,7 @@ export const SoxCompliancePage: React.FC = () => { border: '1px solid var(--color-border-light)', padding: 24, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', }}> -
整体合规评分
+
{t('sox_overall_score')}
= 80 ? 'var(--color-success)' : overallScore >= 60 ? 'var(--color-warning)' : 'var(--color-error)'} ${overallScore * 3.6}deg, var(--color-gray-100) 0deg)`, @@ -133,16 +134,16 @@ export const SoxCompliancePage: React.FC = () => {
-
满分 100
+
{t('sox_full_score')}
{/* Summary Stats */}
{[ - { label: '总控制点', value: String(totalControls), color: 'var(--color-primary)' }, - { label: '测试通过', value: String(passedControls), color: 'var(--color-success)' }, - { label: '发现缺陷', value: String(defectControls), color: 'var(--color-error)' }, - { label: '待测试', value: String(pendingControls), color: 'var(--color-warning)' }, + { label: t('sox_total_controls'), value: String(totalControls), color: 'var(--color-primary)' }, + { label: t('sox_test_passed'), value: String(passedControls), color: 'var(--color-success)' }, + { label: t('sox_defects_found'), value: String(defectControls), color: 'var(--color-error)' }, + { label: t('sox_pending_test'), value: String(pendingControls), color: 'var(--color-warning)' }, ].map(s => (
{ border: '1px solid var(--color-border-light)', marginBottom: 24, overflow: 'hidden', }}>
-

内部控制类别

+

{t('sox_control_categories')}

{controlCategories.map((cat, catIdx) => (
@@ -174,7 +175,7 @@ export const SoxCompliancePage: React.FC = () => {
{h}
- +
- {['控制点', '测试结果', '上次测试', '下次测试'].map(h => ( + {[t('sox_th_control_point'), t('sox_th_test_result'), t('sox_th_last_test'), t('sox_th_next_test')].map(h => ( ))} @@ -206,12 +207,12 @@ export const SoxCompliancePage: React.FC = () => { border: '1px solid var(--color-border-light)', overflow: 'hidden', }}>
-

缺陷追踪

+

{t('sox_deficiency_tracking')}

{h}
- {['编号', '控制点', '严重程度', '描述', '整改期限', '状态', '负责方'].map(h => ( + {[t('sox_th_id'), t('sox_th_control'), t('sox_th_severity'), t('sox_th_description'), t('sox_th_due_date'), t('sox_th_status'), t('sox_th_owner')].map(h => ( ))} @@ -232,8 +233,8 @@ export const SoxCompliancePage: React.FC = () => { @@ -245,7 +246,7 @@ export const SoxCompliancePage: React.FC = () => { {/* Auditor Review Status */}
-

审计师审核进度

+

{t('sox_auditor_progress')}

External Auditor: Deloitte
{auditorReview.map((phase, i) => (
@@ -265,14 +266,14 @@ export const SoxCompliancePage: React.FC = () => { font: 'var(--text-caption)', color: phase.status === 'done' ? 'var(--color-success)' : phase.status === 'progress' ? 'var(--color-warning)' : 'var(--color-text-tertiary)', }}> - {phase.status === 'done' ? '已完成' : phase.status === 'progress' ? '进行中' : '待开始'} + {phase.status === 'done' ? t('completed') : phase.status === 'progress' ? t('in_progress') : t('pending')}
))} {/* Progress Bar */}
- 审计进度 + {t('sox_audit_progress')} 33%
diff --git a/frontend/admin-web/src/views/compliance/TaxCompliancePage.tsx b/frontend/admin-web/src/views/compliance/TaxCompliancePage.tsx index 8a9e450..8c1ec1f 100644 --- a/frontend/admin-web/src/views/compliance/TaxCompliancePage.tsx +++ b/frontend/admin-web/src/views/compliance/TaxCompliancePage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * Tax Compliance Management - 税务合规管理 @@ -8,22 +9,22 @@ import React from 'react'; */ const taxStats = [ - { label: '应纳税额', value: '$1,245,890', color: 'var(--color-primary)' }, - { label: '已缴税额', value: '$982,450', color: 'var(--color-success)' }, - { label: '税务合规率', value: '96.8%', color: 'var(--color-info)' }, - { label: '待处理事项', value: '5', color: 'var(--color-warning)' }, + { label: t('tax_payable'), value: '$1,245,890', color: 'var(--color-primary)' }, + { label: t('tax_paid'), value: '$982,450', color: 'var(--color-success)' }, + { label: t('tax_compliance_rate'), value: '96.8%', color: 'var(--color-info)' }, + { label: t('tax_pending_items'), value: '5', color: 'var(--color-warning)' }, ]; const taxObligations = [ - { jurisdiction: 'Federal', taxType: 'Corporate Income Tax', period: 'FY 2025', amount: '$425,000', paid: '$425,000', status: '已缴', dueDate: '2026-04-15' }, - { jurisdiction: 'Federal', taxType: 'Employment Tax (FICA)', period: 'Q4 2025', amount: '$68,200', paid: '$68,200', status: '已缴', dueDate: '2026-01-31' }, - { jurisdiction: 'California', taxType: 'State Income Tax', amount: '$187,500', paid: '$187,500', period: 'FY 2025', status: '已缴', dueDate: '2026-04-15' }, - { jurisdiction: 'California', taxType: 'Sales & Use Tax', amount: '$42,300', paid: '$42,300', period: 'Q4 2025', status: '已缴', dueDate: '2026-01-31' }, - { jurisdiction: 'New York', taxType: 'State Income Tax', amount: '$156,800', paid: '$120,000', period: 'FY 2025', status: '部分缴纳', dueDate: '2026-04-15' }, - { jurisdiction: 'New York', taxType: 'Metropolitan Commuter Tax', amount: '$12,400', paid: '$0', period: 'FY 2025', status: '待缴', dueDate: '2026-04-15' }, - { jurisdiction: 'Texas', taxType: 'Franchise Tax', amount: '$34,600', paid: '$34,600', period: 'FY 2025', status: '已缴', dueDate: '2026-05-15' }, - { jurisdiction: 'Florida', taxType: 'Sales Tax', amount: '$28,900', paid: '$28,900', period: 'Q4 2025', status: '已缴', dueDate: '2026-01-31' }, - { jurisdiction: 'Federal', taxType: 'Estimated Tax (Q1 2026)', amount: '$263,190', paid: '$0', period: 'Q1 2026', status: '待缴', dueDate: '2026-04-15' }, + { jurisdiction: 'Federal', taxType: 'Corporate Income Tax', period: 'FY 2025', amount: '$425,000', paid: '$425,000', status: t('tax_status_paid'), dueDate: '2026-04-15' }, + { jurisdiction: 'Federal', taxType: 'Employment Tax (FICA)', period: 'Q4 2025', amount: '$68,200', paid: '$68,200', status: t('tax_status_paid'), dueDate: '2026-01-31' }, + { jurisdiction: 'California', taxType: 'State Income Tax', amount: '$187,500', paid: '$187,500', period: 'FY 2025', status: t('tax_status_paid'), dueDate: '2026-04-15' }, + { jurisdiction: 'California', taxType: 'Sales & Use Tax', amount: '$42,300', paid: '$42,300', period: 'Q4 2025', status: t('tax_status_paid'), dueDate: '2026-01-31' }, + { jurisdiction: 'New York', taxType: 'State Income Tax', amount: '$156,800', paid: '$120,000', period: 'FY 2025', status: t('tax_status_partial'), dueDate: '2026-04-15' }, + { jurisdiction: 'New York', taxType: 'Metropolitan Commuter Tax', amount: '$12,400', paid: '$0', period: 'FY 2025', status: t('tax_status_unpaid'), dueDate: '2026-04-15' }, + { jurisdiction: 'Texas', taxType: 'Franchise Tax', amount: '$34,600', paid: '$34,600', period: 'FY 2025', status: t('tax_status_paid'), dueDate: '2026-05-15' }, + { jurisdiction: 'Florida', taxType: 'Sales Tax', amount: '$28,900', paid: '$28,900', period: 'Q4 2025', status: t('tax_status_paid'), dueDate: '2026-01-31' }, + { jurisdiction: 'Federal', taxType: 'Estimated Tax (Q1 2026)', amount: '$263,190', paid: '$0', period: 'Q1 2026', status: t('tax_status_unpaid'), dueDate: '2026-04-15' }, ]; const taxTypeBreakdown = [ @@ -35,14 +36,14 @@ const taxTypeBreakdown = [ ]; const irsFilings = [ - { form: 'Form 1120', description: '公司所得税申报', taxYear: '2025', deadline: '2026-04-15', status: '准备中', filedDate: '-' }, - { form: 'Form 1099-K', description: '支付卡和第三方网络交易', taxYear: '2025', deadline: '2026-01-31', status: '已提交', filedDate: '2026-01-28' }, - { form: 'Form 1099-MISC', description: '杂项收入(承包商支付)', taxYear: '2025', deadline: '2026-01-31', status: '已提交', filedDate: '2026-01-29' }, - { form: 'Form 1099-NEC', description: '非雇员报酬', taxYear: '2025', deadline: '2026-01-31', status: '已提交', filedDate: '2026-01-30' }, - { form: 'Form 941', description: '雇主季度联邦税', taxYear: 'Q4 2025', deadline: '2026-01-31', status: '已提交', filedDate: '2026-01-25' }, - { form: 'Form W-2', description: '工资与税务声明', taxYear: '2025', deadline: '2026-01-31', status: '已提交', filedDate: '2026-01-27' }, - { form: 'Form 1042-S', description: '外国人预扣所得', taxYear: '2025', deadline: '2026-03-15', status: '准备中', filedDate: '-' }, - { form: 'Form 8300', description: '现金支付超$10,000报告', taxYear: '2025', deadline: '交易后15天', status: '按需提交', filedDate: '-' }, + { form: 'Form 1120', description: 'Corporate Income Tax', taxYear: '2025', deadline: '2026-04-15', status: t('tax_filing_preparing'), filedDate: '-' }, + { form: 'Form 1099-K', description: 'Payment Card & Third-party Network', taxYear: '2025', deadline: '2026-01-31', status: t('tax_filing_submitted'), filedDate: '2026-01-28' }, + { form: 'Form 1099-MISC', description: 'Miscellaneous Income (Contractors)', taxYear: '2025', deadline: '2026-01-31', status: t('tax_filing_submitted'), filedDate: '2026-01-29' }, + { form: 'Form 1099-NEC', description: 'Non-employee Compensation', taxYear: '2025', deadline: '2026-01-31', status: t('tax_filing_submitted'), filedDate: '2026-01-30' }, + { form: 'Form 941', description: 'Employer Quarterly Federal Tax', taxYear: 'Q4 2025', deadline: '2026-01-31', status: t('tax_filing_submitted'), filedDate: '2026-01-25' }, + { form: 'Form W-2', description: 'Wage & Tax Statement', taxYear: '2025', deadline: '2026-01-31', status: t('tax_filing_submitted'), filedDate: '2026-01-27' }, + { form: 'Form 1042-S', description: 'Foreign Person Withholding', taxYear: '2025', deadline: '2026-03-15', status: t('tax_filing_preparing'), filedDate: '-' }, + { form: 'Form 8300', description: 'Cash Payments Over $10,000', taxYear: '2025', deadline: '15 days after txn', status: t('tax_filing_on_demand'), filedDate: '-' }, ]; const taxDeadlines = [ @@ -58,11 +59,11 @@ const taxDeadlines = [ const getPaymentStatusStyle = (status: string) => { switch (status) { - case '已缴': + case t('tax_status_paid'): return { background: 'var(--color-success-light)', color: 'var(--color-success)' }; - case '部分缴纳': + case t('tax_status_partial'): return { background: 'var(--color-warning-light)', color: 'var(--color-warning)' }; - case '待缴': + case t('tax_status_unpaid'): return { background: 'var(--color-error-light)', color: 'var(--color-error)' }; default: return { background: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }; @@ -71,13 +72,13 @@ const getPaymentStatusStyle = (status: string) => { const getFilingStatusStyle = (status: string) => { switch (status) { - case '已提交': + case t('tax_filing_submitted'): return { background: 'var(--color-success-light)', color: 'var(--color-success)' }; - case '准备中': + case t('tax_filing_preparing'): return { background: 'var(--color-warning-light)', color: 'var(--color-warning)' }; - case '按需提交': + case t('tax_filing_on_demand'): return { background: 'var(--color-info-light)', color: 'var(--color-info)' }; - case '逾期': + case t('tax_filing_overdue'): return { background: 'var(--color-error-light)', color: 'var(--color-error)' }; default: return { background: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }; @@ -88,7 +89,7 @@ export const TaxCompliancePage: React.FC = () => { return (
-

税务合规管理

+

{t('tax_title')}

@@ -121,37 +122,37 @@ export const TaxCompliancePage: React.FC = () => { border: '1px solid var(--color-border-light)', overflow: 'hidden', marginBottom: 24, }}>
-

各司法管辖区税务义务

+

{t('tax_obligations')}

{h}
{d.status} {d.owner}
- {['管辖区', '税种', '期间', '应缴金额', '已缴金额', '截止日期', '状态'].map(h => ( + {[t('tax_th_jurisdiction'), t('tax_th_type'), t('tax_th_period'), t('tax_th_payable'), t('tax_th_paid'), t('tax_th_deadline'), t('tax_th_status')].map(h => ( ))} - {taxObligations.map((t, i) => ( + {taxObligations.map((tax, i) => ( - - - - - + + + + + ))} @@ -167,12 +168,12 @@ export const TaxCompliancePage: React.FC = () => { border: '1px solid var(--color-border-light)', overflow: 'hidden', }}>
-

税种分类汇总

+

{t('tax_type_breakdown')}

{h}
{t.jurisdiction} + }}>{tax.jurisdiction} {t.taxType}{t.period}{t.amount}{t.paid}{t.dueDate}{tax.taxType}{tax.period}{tax.amount}{tax.paid}{tax.dueDate} {t.status} + ...getPaymentStatusStyle(tax.status), + }}>{tax.status}
- {['税种', '联邦', '州级', '合计', '占比'].map(h => ( + {[t('tax_th_tax_type'), t('tax_th_federal'), t('tax_th_state'), t('tax_th_total'), t('tax_th_percentage')].map(h => ( ))} @@ -200,7 +201,7 @@ export const TaxCompliancePage: React.FC = () => { {/* Tax Calendar / Deadlines */}
-

税务日历

+

{t('tax_calendar')}

{taxDeadlines.map((evt, i) => (
{ font: 'var(--text-caption)', color: evt.done ? 'var(--color-success)' : 'var(--color-error)', }}> - {evt.done ? '已完成' : '待处理'} + {evt.done ? t('tax_status_done') : t('tax_status_pending')}
))} @@ -232,12 +233,12 @@ export const TaxCompliancePage: React.FC = () => { border: '1px solid var(--color-border-light)', overflow: 'hidden', }}>
-

IRS表格提交追踪

+

{t('tax_irs_tracker')}

{h}
- {['表格', '说明', '税务年度', '截止日期', '提交日期', '状态'].map(h => ( + {[t('tax_th_form'), t('tax_th_description'), t('tax_th_tax_year'), t('tax_th_deadline'), t('tax_th_filed_date'), t('tax_th_status')].map(h => ( ))} diff --git a/frontend/admin-web/src/views/coupons/CouponManagementPage.tsx b/frontend/admin-web/src/views/coupons/CouponManagementPage.tsx index 52860ba..6dbe486 100644 --- a/frontend/admin-web/src/views/coupons/CouponManagementPage.tsx +++ b/frontend/admin-web/src/views/coupons/CouponManagementPage.tsx @@ -1,6 +1,7 @@ 'use client'; import React, { useState } from 'react'; +import { t } from '@/i18n/locales'; /** * D2. 券管理 - 平台券审核与管理 @@ -35,10 +36,10 @@ const statusColors: Record = { expired: 'var(--color-text-tertiary)', }; const statusLabels: Record = { - pending: '待审核', - active: '在售中', - suspended: '已暂停', - expired: '已过期', + pending: t('coupon_pending_review'), + active: t('coupon_active'), + suspended: t('coupon_suspended'), + expired: t('coupon_expired'), }; export const CouponManagementPage: React.FC = () => { @@ -49,7 +50,7 @@ export const CouponManagementPage: React.FC = () => { return (
-

券管理

+

{t('coupon_management_title')}

{['all', 'pending', 'active', 'suspended', 'expired'].map(f => ( ))}
@@ -69,7 +70,7 @@ export const CouponManagementPage: React.FC = () => {
{h}
- {['券ID', '发行方', '券名称', '模板', '面值', '发行量', '已售', '已核销', '状态', '操作'].map(h => ( + {[t('coupon_id'), t('coupon_issuer'), t('coupon_name'), t('coupon_template'), t('coupon_face_value'), t('coupon_quantity'), t('coupon_sold'), t('coupon_redeemed'), t('status'), t('actions')].map(h => ( ))} @@ -95,12 +96,12 @@ export const CouponManagementPage: React.FC = () => { diff --git a/frontend/admin-web/src/views/dashboard/DashboardPage.tsx b/frontend/admin-web/src/views/dashboard/DashboardPage.tsx index 8ad65e7..48eb14c 100644 --- a/frontend/admin-web/src/views/dashboard/DashboardPage.tsx +++ b/frontend/admin-web/src/views/dashboard/DashboardPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * D1. 平台运营仪表盘 @@ -16,19 +17,19 @@ interface StatCard { } const stats: StatCard[] = [ - { label: '总交易量', value: '156,890', change: '+12.3%', trend: 'up', color: 'var(--color-primary)' }, - { label: '交易金额', value: '$4,523,456', change: '+8.7%', trend: 'up', color: 'var(--color-success)' }, - { label: '活跃用户', value: '28,456', change: '+5.2%', trend: 'up', color: 'var(--color-info)' }, - { label: '发行方数量', value: '342', change: '+15', trend: 'up', color: 'var(--color-warning)' }, - { label: '券流通总量', value: '1,234,567', change: '-2.1%', trend: 'down', color: 'var(--color-primary-dark)' }, - { label: '系统健康', value: '99.97%', change: 'Normal', trend: 'up', color: 'var(--color-success)' }, + { label: t('dashboard_total_volume'), value: '156,890', change: '+12.3%', trend: 'up', color: 'var(--color-primary)' }, + { label: t('dashboard_total_amount'), value: '$4,523,456', change: '+8.7%', trend: 'up', color: 'var(--color-success)' }, + { label: t('dashboard_active_users'), value: '28,456', change: '+5.2%', trend: 'up', color: 'var(--color-info)' }, + { label: t('dashboard_issuer_count'), value: '342', change: '+15', trend: 'up', color: 'var(--color-warning)' }, + { label: t('dashboard_coupon_circulation'), value: '1,234,567', change: '-2.1%', trend: 'down', color: 'var(--color-primary-dark)' }, + { label: t('dashboard_system_health'), value: '99.97%', change: 'Normal', trend: 'up', color: 'var(--color-success)' }, ]; export const DashboardPage: React.FC = () => { return (

- 运营总览 + {t('dashboard_title')}

{/* Stats Grid */} @@ -71,7 +72,7 @@ export const DashboardPage: React.FC = () => { border: '1px solid var(--color-border-light)', padding: 20, }}> -
交易量趋势
+
{t('dashboard_volume_trend')}
{ border: '1px solid var(--color-border-light)', padding: 20, }}> -
交易类型占比
+
{t('dashboard_type_distribution')}
{ padding: 20, }}>
-
实时交易流
+
{t('dashboard_realtime_feed')}
{
{h}
{coupon.status === 'pending' && (
- - + +
)} {coupon.status === 'active' && ( - + )}
- {['时间', '类型', '订单号', '金额', '状态'].map(h => ( + {[t('dashboard_th_time'), t('dashboard_th_type'), t('dashboard_th_order'), t('dashboard_th_amount'), t('dashboard_th_status')].map(h => ( {[ - { time: '14:32:15', type: '购买', order: 'GNX-20260210-001234', amount: '$21.25', status: '完成' }, - { time: '14:31:58', type: '核销', order: 'GNX-20260210-001233', amount: '$50.00', status: '完成' }, - { time: '14:31:42', type: '转售', order: 'GNX-20260210-001232', amount: '$85.00', status: '完成' }, - { time: '14:31:20', type: '购买', order: 'GNX-20260210-001231', amount: '$42.50', status: '处理中' }, - { time: '14:30:55', type: '转赠', order: 'GNX-20260210-001230', amount: '$30.00', status: '完成' }, + { time: '14:32:15', type: t('dashboard_type_purchase'), order: 'GNX-20260210-001234', amount: '$21.25', status: t('dashboard_status_completed') }, + { time: '14:31:58', type: t('dashboard_type_redeem'), order: 'GNX-20260210-001233', amount: '$50.00', status: t('dashboard_status_completed') }, + { time: '14:31:42', type: t('dashboard_type_resell'), order: 'GNX-20260210-001232', amount: '$85.00', status: t('dashboard_status_completed') }, + { time: '14:31:20', type: t('dashboard_type_purchase'), order: 'GNX-20260210-001231', amount: '$42.50', status: t('dashboard_status_processing') }, + { time: '14:30:55', type: t('dashboard_type_transfer'), order: 'GNX-20260210-001230', amount: '$30.00', status: t('dashboard_status_completed') }, ].map((row, i) => ( @@ -157,8 +158,8 @@ export const DashboardPage: React.FC = () => { padding: '2px 8px', borderRadius: 'var(--radius-full)', font: 'var(--text-caption)', - background: row.status === '完成' ? 'var(--color-success-light)' : 'var(--color-warning-light)', - color: row.status === '完成' ? 'var(--color-success)' : 'var(--color-warning)', + background: row.status === t('dashboard_status_completed') ? 'var(--color-success-light)' : 'var(--color-warning-light)', + color: row.status === t('dashboard_status_completed') ? 'var(--color-success)' : 'var(--color-warning)', }}> {row.status} @@ -176,13 +177,13 @@ export const DashboardPage: React.FC = () => { border: '1px solid var(--color-border-light)', padding: 20, }}> -
系统健康
+
{t('dashboard_system_health')}
{[ - { name: 'API服务', status: 'healthy', latency: '12ms' }, - { name: '数据库', status: 'healthy', latency: '3ms' }, + { name: t('dashboard_service_api'), status: 'healthy', latency: '12ms' }, + { name: t('dashboard_service_db'), status: 'healthy', latency: '3ms' }, { name: 'Genex Chain', status: 'healthy', latency: '156ms' }, - { name: '缓存服务', status: 'healthy', latency: '1ms' }, - { name: '消息队列', status: 'warning', latency: '45ms' }, + { name: t('dashboard_service_cache'), status: 'healthy', latency: '1ms' }, + { name: t('dashboard_service_mq'), status: 'warning', latency: '45ms' }, ].map(service => (
= { - pending: { label: '待处理', bg: 'var(--color-warning-light)', color: 'var(--color-warning)' }, - processing: { label: '处理中', bg: 'var(--color-info-light)', color: 'var(--color-info)' }, - resolved: { label: '已解决', bg: 'var(--color-success-light)', color: 'var(--color-success)' }, - rejected: { label: '已驳回', bg: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }, + pending: { label: t('dispute_pending'), bg: 'var(--color-warning-light)', color: 'var(--color-warning)' }, + processing: { label: t('dispute_processing'), bg: 'var(--color-info-light)', color: 'var(--color-info)' }, + resolved: { label: t('dispute_resolved'), bg: 'var(--color-success-light)', color: 'var(--color-success)' }, + rejected: { label: t('dispute_rejected'), bg: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }, }; const typeConfig: Record = { - '买方申诉': { bg: 'var(--color-error-light)', color: 'var(--color-error)' }, - '卖方申诉': { bg: 'var(--color-warning-light)', color: 'var(--color-warning)' }, - '退款申请': { bg: 'var(--color-info-light)', color: 'var(--color-info)' }, + [t('dispute_type_buyer')]: { bg: 'var(--color-error-light)', color: 'var(--color-error)' }, + [t('dispute_type_seller')]: { bg: 'var(--color-warning-light)', color: 'var(--color-warning)' }, + [t('dispute_type_refund')]: { bg: 'var(--color-info-light)', color: 'var(--color-info)' }, }; export const DisputePage: React.FC = () => { return (
-

争议处理

+

{t('dispute_title')}

{/* Stats */} {[ - { label: '待处理', value: '3', color: 'var(--color-warning)' }, - { label: '处理中', value: '1', color: 'var(--color-info)' }, - { label: '今日解决', value: '5', color: 'var(--color-success)' }, + { label: t('dispute_pending'), value: '3', color: 'var(--color-warning)' }, + { label: t('dispute_processing'), value: '1', color: 'var(--color-info)' }, + { label: t('dispute_resolved_today'), value: '5', color: 'var(--color-success)' }, ].map(s => (
{
{
{row.time}
- {['工单号', '类型', '关联订单', '申诉方', '被诉方', '金额', '状态', '处理时效', '创建时间', '操作'].map(h => ( + {[t('dispute_th_ticket_id'), t('dispute_th_type'), t('dispute_th_order'), t('dispute_th_plaintiff'), t('dispute_th_defendant'), t('dispute_th_amount'), t('dispute_th_status'), t('dispute_th_sla'), t('dispute_th_created'), t('actions')].map(h => ( diff --git a/frontend/admin-web/src/views/finance/FinanceManagementPage.tsx b/frontend/admin-web/src/views/finance/FinanceManagementPage.tsx index fcf2c56..c4db605 100644 --- a/frontend/admin-web/src/views/finance/FinanceManagementPage.tsx +++ b/frontend/admin-web/src/views/finance/FinanceManagementPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * D3. 财务管理 - 平台级财务总览 @@ -7,23 +8,23 @@ import React from 'react'; */ const financeStats = [ - { label: '平台手续费收入', value: '$234,567', period: '本月', color: 'var(--color-success)' }, - { label: '待结算给发行方', value: '$1,456,000', period: '累计', color: 'var(--color-warning)' }, - { label: '消费者退款', value: '$12,340', period: '本月', color: 'var(--color-error)' }, - { label: '资金池余额', value: '$8,234,567', period: '实时', color: 'var(--color-primary)' }, + { label: t('finance_platform_fee'), value: '$234,567', period: t('finance_period_month'), color: 'var(--color-success)' }, + { label: t('finance_pending_settlement'), value: '$1,456,000', period: t('finance_period_cumulative'), color: 'var(--color-warning)' }, + { label: t('finance_consumer_refund'), value: '$12,340', period: t('finance_period_month'), color: 'var(--color-error)' }, + { label: t('finance_pool_balance'), value: '$8,234,567', period: t('finance_period_realtime'), color: 'var(--color-primary)' }, ]; const recentSettlements = [ - { issuer: 'Starbucks', amount: '$45,200', status: '已结算', time: '2026-02-10 14:00' }, - { issuer: 'Amazon', amount: '$128,000', status: '处理中', time: '2026-02-10 12:00' }, - { issuer: 'Nike', amount: '$23,500', status: '待结算', time: '2026-02-09' }, - { issuer: 'Walmart', amount: '$67,800', status: '已结算', time: '2026-02-08' }, + { issuer: 'Starbucks', amount: '$45,200', status: t('finance_status_settled'), time: '2026-02-10 14:00' }, + { issuer: 'Amazon', amount: '$128,000', status: t('finance_status_processing'), time: '2026-02-10 12:00' }, + { issuer: 'Nike', amount: '$23,500', status: t('finance_status_pending'), time: '2026-02-09' }, + { issuer: 'Walmart', amount: '$67,800', status: t('finance_status_settled'), time: '2026-02-08' }, ]; export const FinanceManagementPage: React.FC = () => { return (
-

财务管理

+

{t('finance_title')}

{/* Stats */}
@@ -45,10 +46,10 @@ export const FinanceManagementPage: React.FC = () => { background: 'var(--color-surface)', borderRadius: 'var(--radius-md)', border: '1px solid var(--color-border-light)', padding: 20, }}> -

结算队列

+

{t('finance_settlement_queue')}

{ borderRadius: 'var(--radius-sm)', background: 'none', cursor: 'pointer', font: 'var(--text-caption)', color: 'var(--color-primary)', }}> - {d.status === 'pending' || d.status === 'processing' ? '处理' : '查看'} + {d.status === 'pending' || d.status === 'processing' ? t('process') : t('view')}
- {['发行方', '金额', '状态', '时间'].map(h => ( + {[t('finance_th_issuer'), t('finance_th_amount'), t('finance_th_status'), t('finance_th_time')].map(h => ( ))} @@ -60,8 +61,8 @@ export const FinanceManagementPage: React.FC = () => { @@ -76,7 +77,7 @@ export const FinanceManagementPage: React.FC = () => { background: 'var(--color-surface)', borderRadius: 'var(--radius-md)', border: '1px solid var(--color-border-light)', padding: 20, }}> -

收入趋势

+

{t('finance_revenue_trend')}

{ return (
-

保险与消费者保护

+

{t('insurance_title')}

{/* Stats */}
@@ -50,10 +51,10 @@ export const InsurancePage: React.FC = () => {
{/* Claims */}
-

最近赔付记录

+

{t('insurance_recent_claims')}

{h}
{s.status} {s.time}
- {['编号', '用户', '原因', '金额', '状态'].map(h => ( + {[t('insurance_th_id'), t('insurance_th_user'), t('insurance_th_reason'), t('insurance_th_amount'), t('insurance_th_status')].map(h => ( ))} @@ -67,8 +68,8 @@ export const InsurancePage: React.FC = () => { @@ -79,7 +80,7 @@ export const InsurancePage: React.FC = () => { {/* IPO Readiness */}
-

IPO准备度检查清单

+

{t('insurance_ipo_checklist')}

{ipoChecklist.map((item, i) => (
{ font: 'var(--text-caption)', color: item.status === 'done' ? 'var(--color-success)' : item.status === 'progress' ? 'var(--color-warning)' : 'var(--color-text-tertiary)', }}> - {item.status === 'done' ? '已完成' : item.status === 'progress' ? '进行中' : '待开始'} + {item.status === 'done' ? t('completed') : item.status === 'progress' ? t('in_progress') : t('pending')}
))} {/* Progress Bar */}
- 总体进度 + {t('overall_progress')} 72%
diff --git a/frontend/admin-web/src/views/issuers/IssuerManagementPage.tsx b/frontend/admin-web/src/views/issuers/IssuerManagementPage.tsx index 69edc62..69bc325 100644 --- a/frontend/admin-web/src/views/issuers/IssuerManagementPage.tsx +++ b/frontend/admin-web/src/views/issuers/IssuerManagementPage.tsx @@ -1,6 +1,7 @@ 'use client'; import React, { useState } from 'react'; +import { t } from '@/i18n/locales'; /** * D2. 发行方管理 @@ -51,14 +52,14 @@ export const IssuerManagementPage: React.FC = () => { }; const statusLabel = (status: string) => { - const map: Record = { pending: '待审核', approved: '已通过', rejected: '已驳回' }; + const map: Record = { pending: t('issuer_onboarding_pending'), approved: t('issuer_onboarding_approved'), rejected: t('issuer_onboarding_rejected') }; return map[status] || status; }; return (
-

发行方管理

+

{t('issuer_management_title')}

{/* Tabs */}
- {(['all', 'pending', 'approved', 'rejected'] as const).map(t => ( + {(['all', 'pending', 'approved', 'rejected'] as const).map(tabKey => (
{h}
{c.status}
- {['ID', '企业名称', '信用评级', '状态', '提交时间', '券数量', '总发行额', '操作'].map(h => ( + {['ID', t('issuer_company_name'), t('issuer_credit_rating'), t('status'), t('issuer_submit_time'), t('issuer_coupon_count'), t('issuer_total_volume'), t('actions')].map(h => (
{ font: 'var(--text-caption)', color: 'var(--color-primary)', }}> - 详情 + {t('details')} {issuer.status === 'pending' && ( )} diff --git a/frontend/admin-web/src/views/merchant/MerchantRedemptionPage.tsx b/frontend/admin-web/src/views/merchant/MerchantRedemptionPage.tsx index 61d2e86..b1f1c39 100644 --- a/frontend/admin-web/src/views/merchant/MerchantRedemptionPage.tsx +++ b/frontend/admin-web/src/views/merchant/MerchantRedemptionPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * D6. 商户核销管理 - 平台视角的核销数据 @@ -7,10 +8,10 @@ import React from 'react'; */ const redemptionStats = [ - { label: '今日核销', value: '1,234', change: '+15%', color: 'var(--color-success)' }, - { label: '今日核销金额', value: '$45,600', change: '+8%', color: 'var(--color-primary)' }, - { label: '活跃门店', value: '89', change: '+3', color: 'var(--color-info)' }, - { label: '异常核销', value: '2', change: '需审核', color: 'var(--color-error)' }, + { label: t('merchant_today_redemption'), value: '1,234', change: '+15%', color: 'var(--color-success)' }, + { label: t('merchant_today_amount'), value: '$45,600', change: '+8%', color: 'var(--color-primary)' }, + { label: t('merchant_active_stores'), value: '89', change: '+3', color: 'var(--color-info)' }, + { label: t('merchant_abnormal_redemption'), value: '2', change: t('merchant_need_review'), color: 'var(--color-error)' }, ]; const topStores = [ @@ -24,7 +25,7 @@ const topStores = [ export const MerchantRedemptionPage: React.FC = () => { return (
-

商户核销管理

+

{t('merchant_title')}

{/* Stats */}
@@ -43,7 +44,7 @@ export const MerchantRedemptionPage: React.FC = () => {
{/* Top Stores */}
-

门店核销排行

+

{t('merchant_store_ranking')}

{topStores.map(s => (
{ color: s.rank <= 3 ? 'white' : 'var(--color-text-tertiary)', font: 'var(--text-caption)', fontWeight: 700, }}>{s.rank} {s.store} - {s.count}笔 + {s.count}{t('merchant_unit_count')} {s.amount}
))} @@ -63,7 +64,7 @@ export const MerchantRedemptionPage: React.FC = () => { {/* Realtime Feed */}
-

实时核销流

+

{t('merchant_realtime_feed')}

{[ { store: 'Starbucks 徐汇店', coupon: '¥25 礼品卡', time: '刚刚' }, { store: 'Nike 南京西路店', coupon: '¥80 运动券', time: '1分钟前' }, diff --git a/frontend/admin-web/src/views/reports/ReportsPage.tsx b/frontend/admin-web/src/views/reports/ReportsPage.tsx index a58153b..1d9643e 100644 --- a/frontend/admin-web/src/views/reports/ReportsPage.tsx +++ b/frontend/admin-web/src/views/reports/ReportsPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * D5. 报表中心 - 运营报表、合规报表、数据导出 @@ -9,50 +10,50 @@ import React from 'react'; const reportCategories = [ { - title: '运营报表', + title: t('reports_operations'), icon: '📊', reports: [ - { name: '日度运营报表', desc: '交易量/金额/用户/核销率', status: '已生成', date: '2026-02-10' }, - { name: '周度运营报表', desc: '周趋势分析', status: '已生成', date: '2026-02-09' }, - { name: '月度运营报表', desc: '月度综合分析', status: '已生成', date: '2026-01-31' }, + { name: '日度运营报表', desc: '交易量/金额/用户/核销率', status: t('reports_status_generated'), date: '2026-02-10' }, + { name: '周度运营报表', desc: '周趋势分析', status: t('reports_status_generated'), date: '2026-02-09' }, + { name: '月度运营报表', desc: '月度综合分析', status: t('reports_status_generated'), date: '2026-01-31' }, ], }, { - title: '合规报表', + title: t('reports_compliance'), icon: '📋', reports: [ - { name: 'SAR可疑活动报告', desc: '本月可疑交易汇总', status: '待审核', date: '2026-02-10' }, - { name: 'CTR大额交易报告', desc: '>$10,000交易申报', status: '已提交', date: '2026-02-10' }, - { name: 'OFAC筛查报告', desc: '制裁名单筛查结果', status: '已生成', date: '2026-02-09' }, + { name: 'SAR可疑活动报告', desc: '本月可疑交易汇总', status: t('reports_status_pending_review'), date: '2026-02-10' }, + { name: 'CTR大额交易报告', desc: '>$10,000交易申报', status: t('reports_status_submitted'), date: '2026-02-10' }, + { name: 'OFAC筛查报告', desc: '制裁名单筛查结果', status: t('reports_status_generated'), date: '2026-02-09' }, ], }, { - title: '财务报表', + title: t('reports_financial'), icon: '💰', reports: [ - { name: '发行方结算报表', desc: '各发行方结算明细', status: '已生成', date: '2026-02-10' }, - { name: '平台收入报表', desc: '手续费/Breakage收入', status: '已生成', date: '2026-01-31' }, - { name: '税务合规报表', desc: '1099-K/消费税汇总', status: '待生成', date: '' }, + { name: '发行方结算报表', desc: '各发行方结算明细', status: t('reports_status_generated'), date: '2026-02-10' }, + { name: '平台收入报表', desc: '手续费/Breakage收入', status: t('reports_status_generated'), date: '2026-01-31' }, + { name: '税务合规报表', desc: '1099-K/消费税汇总', status: t('reports_status_pending_generate'), date: '' }, ], }, { - title: '审计报表', + title: t('reports_audit'), icon: '🔍', reports: [ - { name: 'SOX合规检查', desc: '内部控制审计', status: '已通过', date: '2026-01-15' }, + { name: 'SOX合规检查', desc: '内部控制审计', status: t('reports_status_passed'), date: '2026-01-15' }, { name: 'SEC Filing', desc: '证券类披露(预留)', status: 'N/A', date: '' }, - { name: '操作审计日志', desc: '管理员操作记录', status: '已生成', date: '2026-02-10' }, + { name: '操作审计日志', desc: '管理员操作记录', status: t('reports_status_generated'), date: '2026-02-10' }, ], }, ]; const statusStyle = (status: string): React.CSSProperties => { const map: Record = { - '已生成': { bg: 'var(--color-success-light)', color: 'var(--color-success)' }, - '已提交': { bg: 'var(--color-info-light)', color: 'var(--color-info)' }, - '已通过': { bg: 'var(--color-success-light)', color: 'var(--color-success)' }, - '待审核': { bg: 'var(--color-warning-light)', color: 'var(--color-warning)' }, - '待生成': { bg: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }, + [t('reports_status_generated')]: { bg: 'var(--color-success-light)', color: 'var(--color-success)' }, + [t('reports_status_submitted')]: { bg: 'var(--color-info-light)', color: 'var(--color-info)' }, + [t('reports_status_passed')]: { bg: 'var(--color-success-light)', color: 'var(--color-success)' }, + [t('reports_status_pending_review')]: { bg: 'var(--color-warning-light)', color: 'var(--color-warning)' }, + [t('reports_status_pending_generate')]: { bg: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }, 'N/A': { bg: 'var(--color-gray-100)', color: 'var(--color-text-tertiary)' }, }; const s = map[status] || map['N/A']; @@ -63,11 +64,11 @@ export const ReportsPage: React.FC = () => { return (
-

报表中心

+

{t('reports_title')}

+ }}>{t('custom_export')}
@@ -91,11 +92,11 @@ export const ReportsPage: React.FC = () => {
{r.status} {r.date && {r.date}} - {r.status !== 'N/A' && r.status !== '待生成' && ( + {r.status !== 'N/A' && r.status !== t('reports_status_pending_generate') && ( + }}>{t('download')} )}
diff --git a/frontend/admin-web/src/views/risk/RiskCenterPage.tsx b/frontend/admin-web/src/views/risk/RiskCenterPage.tsx index e217b02..760a9df 100644 --- a/frontend/admin-web/src/views/risk/RiskCenterPage.tsx +++ b/frontend/admin-web/src/views/risk/RiskCenterPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n/locales'; /** * D5. 风控中心 @@ -10,7 +11,7 @@ export const RiskCenterPage: React.FC = () => { return (
-

风控中心

+

{t('risk_title')}

{/* Risk Stats */}
{[ - { label: '风险事件', value: '23', color: 'var(--color-error)', bg: 'var(--color-error-light)' }, - { label: '可疑交易', value: '15', color: 'var(--color-warning)', bg: 'var(--color-warning-light)' }, - { label: '冻结账户', value: '3', color: 'var(--color-info)', bg: 'var(--color-info-light)' }, - { label: 'OFAC命中', value: '0', color: 'var(--color-success)', bg: 'var(--color-success-light)' }, + { label: t('risk_events'), value: '23', color: 'var(--color-error)', bg: 'var(--color-error-light)' }, + { label: t('risk_suspicious_trades'), value: '15', color: 'var(--color-warning)', bg: 'var(--color-warning-light)' }, + { label: t('risk_frozen_accounts'), value: '3', color: 'var(--color-info)', bg: 'var(--color-info-light)' }, + { label: t('risk_ofac_hits'), value: '0', color: 'var(--color-success)', bg: 'var(--color-success-light)' }, ].map(s => (
{ marginBottom: 24, }}>
- 🤖 AI 风险预警 + 🤖 {t('risk_ai_warning')}
{[ '检测到异常模式:用户U-045在30分钟内完成12笔交易,总金额$4,560,建议人工审核', @@ -79,7 +80,7 @@ export const RiskCenterPage: React.FC = () => { font: 'var(--text-caption)', whiteSpace: 'nowrap', marginLeft: 12, - }}>处理 + }}>{t('process')}
))}
@@ -92,12 +93,12 @@ export const RiskCenterPage: React.FC = () => { overflow: 'hidden', }}>
- 可疑交易 + {t('risk_suspicious_trades')}
- {['交易ID', '用户', '异常类型', '金额', '时间', '风险评分', '操作'].map(h => ( + {[t('risk_th_trade_id'), t('risk_th_user'), t('risk_th_anomaly_type'), t('risk_th_amount'), t('risk_th_time'), t('risk_th_risk_score'), t('actions')].map(h => ( {[ - { id: 'TXN-8901', user: 'U-045', type: '高频交易', amount: '$4,560', time: '14:15', score: 87 }, - { id: 'TXN-8900', user: 'U-078', type: '大额单笔', amount: '$8,900', time: '13:45', score: 72 }, - { id: 'TXN-8899', user: 'U-091', type: '关联账户', amount: '$3,200', time: '12:30', score: 65 }, - { id: 'TXN-8898', user: 'U-023', type: '异常IP', amount: '$1,500', time: '11:20', score: 58 }, + { id: 'TXN-8901', user: 'U-045', type: t('risk_type_high_freq'), amount: '$4,560', time: '14:15', score: 87 }, + { id: 'TXN-8900', user: 'U-078', type: t('risk_type_large_single'), amount: '$8,900', time: '13:45', score: 72 }, + { id: 'TXN-8899', user: 'U-091', type: t('risk_type_related_account'), amount: '$3,200', time: '12:30', score: 65 }, + { id: 'TXN-8898', user: 'U-023', type: t('risk_type_abnormal_ip'), amount: '$1,500', time: '11:20', score: 58 }, ].map(tx => ( @@ -149,8 +150,8 @@ export const RiskCenterPage: React.FC = () => { diff --git a/frontend/admin-web/src/views/system/SystemManagementPage.tsx b/frontend/admin-web/src/views/system/SystemManagementPage.tsx index d70e991..72bdf12 100644 --- a/frontend/admin-web/src/views/system/SystemManagementPage.tsx +++ b/frontend/admin-web/src/views/system/SystemManagementPage.tsx @@ -1,6 +1,7 @@ 'use client'; import React, { useState } from 'react'; +import { t } from '@/i18n/locales'; /** * D7. 系统管理 @@ -13,29 +14,29 @@ export const SystemManagementPage: React.FC = () => { return (
-

系统管理

+

{t('system_title')}

{/* Tabs */}
{[ - { key: 'admins', label: '管理员账号' }, - { key: 'config', label: '系统配置' }, - { key: 'contracts', label: '合约管理' }, - { key: 'monitor', label: '系统监控' }, - ].map(t => ( + { key: 'admins', label: t('system_tab_admins') }, + { key: 'config', label: t('system_tab_config') }, + { key: 'contracts', label: t('system_tab_contracts') }, + { key: 'monitor', label: t('system_tab_monitor') }, + ].map(tab => ( + >{tab.label} ))}
@@ -48,16 +49,16 @@ export const SystemManagementPage: React.FC = () => { overflow: 'hidden', }}>
- 管理员列表 + {t('system_admin_list')} + }}>{t('system_add_admin')}
{
{tx.id} - - + +
- {['账号', '姓名', '角色', '最后登录', '状态', '操作'].map(h => ( + {[t('system_th_account'), t('system_th_name'), t('system_th_role'), t('system_th_last_login'), t('system_th_status'), t('actions')].map(h => ( ))} @@ -87,7 +88,7 @@ export const SystemManagementPage: React.FC = () => { }} /> ))} @@ -100,10 +101,10 @@ export const SystemManagementPage: React.FC = () => { {activeTab === 'config' && (
{[ - { title: '手续费率设置', items: [{ label: '一级市场手续费', value: '2.5%' }, { label: '二级市场手续费', value: '3.0%' }, { label: '提现手续费', value: '1.0%' }] }, - { title: 'KYC阈值配置', items: [{ label: 'L0每日限额', value: '$100' }, { label: 'L1每日限额', value: '$1,000' }, { label: 'L2每日限额', value: '$10,000' }] }, - { title: '交易限额配置', items: [{ label: '单笔最大金额', value: '$50,000' }, { label: '每日最大金额', value: '$100,000' }, { label: '大额交易阈值', value: '$10,000' }] }, - { title: '系统参数', items: [{ label: 'Utility Track价格上限', value: '≤面值' }, { label: '最大转售次数', value: '5次' }, { label: 'Breakage阈值', value: '3年' }] }, + { title: t('system_fee_config'), items: [{ label: '一级市场手续费', value: '2.5%' }, { label: '二级市场手续费', value: '3.0%' }, { label: '提现手续费', value: '1.0%' }] }, + { title: t('system_kyc_config'), items: [{ label: 'L0每日限额', value: '$100' }, { label: 'L1每日限额', value: '$1,000' }, { label: 'L2每日限额', value: '$10,000' }] }, + { title: t('system_trade_limit_config'), items: [{ label: '单笔最大金额', value: '$50,000' }, { label: '每日最大金额', value: '$100,000' }, { label: '大额交易阈值', value: '$10,000' }] }, + { title: t('system_params'), items: [{ label: 'Utility Track价格上限', value: '≤面值' }, { label: '最大转售次数', value: '5次' }, { label: 'Breakage阈值', value: '3年' }] }, ].map(section => (
{ padding: '4px 10px', border: '1px solid var(--color-border)', borderRadius: 'var(--radius-sm)', background: 'none', cursor: 'pointer', font: 'var(--text-caption)', color: 'var(--color-primary)', - }}>编辑 + }}>{t('edit')}
{section.items.map((item, i) => (
{ border: '1px solid var(--color-border-light)', padding: 20, }}> -
智能合约状态
+
{t('system_contract_status')}
{[ - { name: 'CouponNFT', address: '0x1234...abcd', version: 'v1.2.0', status: '运行中' }, - { name: 'Settlement', address: '0x5678...efgh', version: 'v1.1.0', status: '运行中' }, - { name: 'Marketplace', address: '0x9abc...ijkl', version: 'v1.0.0', status: '运行中' }, - { name: 'Oracle', address: '0xdef0...mnop', version: 'v1.0.0', status: '运行中' }, + { name: 'CouponNFT', address: '0x1234...abcd', version: 'v1.2.0', status: t('system_running') }, + { name: 'Settlement', address: '0x5678...efgh', version: 'v1.1.0', status: t('system_running') }, + { name: 'Marketplace', address: '0x9abc...ijkl', version: 'v1.0.0', status: t('system_running') }, + { name: 'Oracle', address: '0xdef0...mnop', version: 'v1.0.0', status: t('system_running') }, ].map(c => (
{ border: '1px solid var(--color-border-light)', padding: 20, }}> -
服务健康检查
+
{t('system_health_check')}
{[ { name: 'API Gateway', status: 'healthy', cpu: '23%', mem: '45%' }, { name: 'Auth Service', status: 'healthy', cpu: '12%', mem: '34%' }, @@ -206,7 +207,7 @@ export const SystemManagementPage: React.FC = () => { border: '1px solid var(--color-border-light)', padding: 20, }}> -
API 响应时间
+
{t('system_api_response')}
{ return (
-

交易监控

+

{t('trading_title')}

{/* Stats Row */}
{[ - { label: '今日交易量', value: '2,456', color: 'var(--color-primary)' }, - { label: '今日交易额', value: '$156,789', color: 'var(--color-success)' }, - { label: '平均折扣率', value: '82.3%', color: 'var(--color-info)' }, - { label: '大额交易', value: '12', color: 'var(--color-warning)' }, + { label: t('trading_today_volume'), value: '2,456', color: 'var(--color-primary)' }, + { label: t('trading_today_amount'), value: '$156,789', color: 'var(--color-success)' }, + { label: t('trading_avg_discount'), value: '82.3%', color: 'var(--color-info)' }, + { label: t('trading_large_trades'), value: '12', color: 'var(--color-warning)' }, ].map(s => (
{ marginBottom: 24, }}>
- 交易量/金额趋势 + {t('trading_volume_trend')}
{['1H', '24H', '7D', '30D'].map(p => (
{h}
- +
- {['订单号', '类型', '券名称', '买方', '卖方', '金额', '状态', '时间'].map(h => ( + {[t('trading_th_order_id'), t('trading_th_type'), t('trading_th_coupon_name'), t('trading_th_buyer'), t('trading_th_seller'), t('trading_th_amount'), t('trading_th_status'), t('trading_th_time')].map(h => (
{ GNX-20260210-{String(1200 - i).padStart(6, '0')} - {['购买', '转售', '核销', '转赠'][i % 4]} + {[t('trading_type_purchase'), t('trading_type_resell'), t('trading_type_redeem'), t('trading_type_transfer')][i % 4]} {['星巴克 $25', 'Amazon $100', 'Nike $80', 'Target $30'][i % 4]} @@ -133,7 +134,7 @@ export const TradingMonitorPage: React.FC = () => { color: i < 6 ? 'var(--color-success)' : 'var(--color-warning)', font: 'var(--text-caption)', }}> - {i < 6 ? '完成' : '争议'} + {i < 6 ? t('trading_status_completed') : t('trading_status_dispute')} diff --git a/frontend/admin-web/src/views/users/UserManagementPage.tsx b/frontend/admin-web/src/views/users/UserManagementPage.tsx index bbefb66..ecd7f8b 100644 --- a/frontend/admin-web/src/views/users/UserManagementPage.tsx +++ b/frontend/admin-web/src/views/users/UserManagementPage.tsx @@ -1,6 +1,7 @@ 'use client'; import React, { useState } from 'react'; +import { t } from '@/i18n/locales'; /** * D3. 用户管理 @@ -21,7 +22,7 @@ interface User { const mockUsers: User[] = [ { id: 'U-001', phone: '138****1234', email: 'john@mail.com', kycLevel: 2, couponCount: 15, totalTraded: '$2,340', riskTags: [], createdAt: '2026-01-10' }, - { id: 'U-002', phone: '139****5678', email: 'jane@mail.com', kycLevel: 1, couponCount: 8, totalTraded: '$890', riskTags: ['高频交易'], createdAt: '2026-01-15' }, + { id: 'U-002', phone: '139****5678', email: 'jane@mail.com', kycLevel: 1, couponCount: 8, totalTraded: '$890', riskTags: [t('risk_type_high_freq')], createdAt: '2026-01-15' }, { id: 'U-003', phone: '137****9012', email: 'bob@mail.com', kycLevel: 3, couponCount: 42, totalTraded: '$12,450', riskTags: [], createdAt: '2025-12-01' }, { id: 'U-004', phone: '136****3456', email: 'alice@mail.com', kycLevel: 0, couponCount: 0, totalTraded: '-', riskTags: [], createdAt: '2026-02-09' }, ]; @@ -54,12 +55,12 @@ export const UserManagementPage: React.FC = () => { return (
-

用户管理

+

{t('user_management_title')}

{/* Search + Filters */}
setSearch(e.target.value)} style={{ @@ -86,7 +87,7 @@ export const UserManagementPage: React.FC = () => { font: 'var(--text-label-sm)', }} > - {level === null ? '全部' : `L${level}`} + {level === null ? t('all') : `L${level}`} ))}
@@ -101,7 +102,7 @@ export const UserManagementPage: React.FC = () => { - {['用户ID', '手机号', '邮箱', 'KYC等级', '持券数', '交易额', '风险标签', '注册时间', '操作'].map(h => ( + {[t('user_id'), t('user_phone'), t('user_email'), t('user_kyc_level'), t('user_coupon_count'), t('user_total_traded'), t('user_risk_tags'), t('user_created_at'), t('actions')].map(h => ( ))} diff --git a/frontend/miniapp/src/components/ai-guide/index.tsx b/frontend/miniapp/src/components/ai-guide/index.tsx index 6df3d87..9a6daae 100644 --- a/frontend/miniapp/src/components/ai-guide/index.tsx +++ b/frontend/miniapp/src/components/ai-guide/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; // Taro mini-program component /** @@ -39,7 +40,7 @@ const AiGuide: React.FC = ({ type }) => { - 你好!我是AI助手,可以帮你找到最适合的券。试试搜索"星巴克"? + {t('ai_guide_greeting')} diff --git a/frontend/miniapp/src/components/share-card/index.tsx b/frontend/miniapp/src/components/share-card/index.tsx index 1f99476..639ef1b 100644 --- a/frontend/miniapp/src/components/share-card/index.tsx +++ b/frontend/miniapp/src/components/share-card/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; // Taro mini-program component /** @@ -44,11 +45,11 @@ const ShareCard: React.FC = ({ {/* Footer with QR */} - 小程序码 + {t('share_miniapp_code')} - 长按识别小程序码 - 立即抢购优惠好券 + {t('share_scan_miniapp')} + {t('share_buy_coupons')} diff --git a/frontend/miniapp/src/i18n/index.ts b/frontend/miniapp/src/i18n/index.ts index 2b7f2b6..c26b3d0 100644 --- a/frontend/miniapp/src/i18n/index.ts +++ b/frontend/miniapp/src/i18n/index.ts @@ -188,6 +188,130 @@ const translations: Record> = { 'error_unknown': '未知错误', 'error_not_found': '页面不存在', 'error_unauthorized': '请先登录', + + // ── Home (additional) ── + 'home_ai_text': '根据你的偏好,发现了高性价比券', + 'home_banner_new_user': '新用户专享', + 'home_banner_new_user_desc': '首单立减¥10', + 'home_banner_flash': '限时折扣', + 'home_banner_flash_desc': '全场低至7折', + 'home_banner_hot': '热门推荐', + 'home_banner_hot_desc': '精选高折扣券', + 'home_category_food': '餐饮', + 'home_category_shopping': '购物', + 'home_category_entertainment': '娱乐', + 'home_category_travel': '出行', + + // ── Login (additional) ── + 'app_slogan': '发现优质好券', + 'login_wechat': '微信一键登录', + 'login_or': '或', + 'login_phone': '手机号', + 'login_code': '验证码', + 'login_btn': '登录', + 'login_agree': '登录即表示同意', + + // ── Detail (additional) ── + 'coupon_type_label': '类型', + 'coupon_store': '使用门店', + 'coupon_type_consumer': '消费券', + 'coupon_price_save': '比面值节省', + 'coupon_utility_notice': '您正在购买消费券用于消费', + 'coupon_rule_universal': '全国星巴克门店通用', + 'coupon_rule_giftable': '可转赠给好友', + 'coupon_rule_anytime': '有效期内随时使用', + 'coupon_rule_no_stack': '不可叠加使用', + 'order_total': '合计', + 'coupon_buy_now': '立即购买', + + // ── My Coupons (additional) ── + 'coupon_valid_until_prefix': '有效期至', + + // ── Redeem (additional) ── + 'redeem_qr_label': '二维码', + 'redeem_valid_time': '有效时间', + 'redeem_refresh': '刷新券码', + 'redeem_hint': '请将此码出示给商户扫描,屏幕已自动调至最高亮度', + + // ── Profile (additional) ── + 'profile_kyc_basic': '基础认证', + 'profile_owned': '持有券', + 'profile_payment': '支付管理', + 'profile_notifications': '消息通知', + 'profile_language': '语言 / Language', + 'profile_currency': '货币', + 'download_app_full_desc': '解锁二级市场交易、P2P转赠等完整功能', + 'download_btn': '下载', + + // ── H5 Share ── + 'share_from_genex': '来自 Genex 的分享', + 'share_open_app': '打开 App 购买', + 'share_miniapp_buy': '小程序购买', + 'share_to_friends': '分享给好友', + + // ── H5 Activity ── + 'activity_flash': '限时活动', + 'activity_title': '限时特惠 | 新用户专享', + 'activity_subtitle': '精选大牌优惠券,折扣低至7折起', + 'activity_countdown': '距活动结束', + 'activity_featured': '精选好券', + 'activity_limited': '限量抢购,先到先得', + 'activity_tag_hot': '爆款', + 'activity_tag_selling': '热卖', + 'activity_tag_new': '新品', + 'activity_buy_now': '立即抢购', + 'activity_rules': '活动规则', + 'activity_rule_1': '活动时间:2026年2月10日 - 2026年2月28日', + 'activity_rule_2': '每位用户限购每种券3张,活动优惠券不与其他优惠叠加使用', + 'activity_rule_3': '优惠券自购买之日起30天内有效,过期自动作废', + 'activity_rule_4': '活动券仅限新注册用户首次购买使用', + 'activity_rule_5': '如遇商品售罄,Genex保留调整活动内容的权利', + 'activity_rule_6': '退款将原路返回,处理时间为1-3个工作日', + 'activity_rule_7': '如有疑问请联系客服:support@genex.com', + 'activity_participants': '已有 {count} 人参与', + 'app_platform_slogan': '全球券资产交易平台', + + // ── H5 Register ── + 'activity_new_user': '新用户专享', + 'activity_first_order': '首单立减 $10,限时优惠', + 'activity_coupons': '活动好券', + 'activity_brand': '品牌', + 'activity_join_now': '立即参与', + 'register_join': '加入 Genex', + 'register_slogan': '让每一张券都有价值', + 'register_benefit': '注册即享首单立减优惠', + 'register_benefit_coupons': '海量优惠券', + 'register_benefit_coupons_desc': '餐饮、购物、娱乐全覆盖', + 'register_benefit_discount': '超值折扣', + 'register_benefit_discount_desc': '最低7折起,省钱又省心', + 'register_benefit_safe': '安全交易', + 'register_benefit_safe_desc': '平台担保,放心购买', + 'register_now': '立即注册', + 'register_login': '已有账号,登录', + 'register_why_genex': '为什么选择 Genex?', + 'register_benefit_coupons_full': '覆盖餐饮、购物、娱乐等20+品类,全球大牌低价好券', + 'register_benefit_safe_full': '平台担保交易,资金托管机制,保障每一笔交易安全可靠', + 'register_benefit_ai': 'AI智能推荐', + 'register_benefit_ai_desc': '基于您的偏好智能推荐高性价比好券,省时又省钱', + 'register_create_account': '创建您的账户', + 'register_other_methods': '其他登录方式', + 'register_has_account': '已有账号?', + 'register_login_now': '立即登录', + 'trust_secure': '安全认证', + 'trust_guarantee': '用户保障', + 'trust_privacy': '隐私保护', + 'trust_encryption': '您的信息受到银行级加密保护', + + // ── AI Guide ── + 'ai_guide_greeting': '你好!我是AI助手,可以帮你找到最适合的券。试试搜索"星巴克"?', + + // ── Share Card ── + 'share_miniapp_code': '小程序码', + 'share_scan_miniapp': '长按识别小程序码', + 'share_buy_coupons': '立即抢购优惠好券', + + // ── Coupon Detail (stores) ── + 'coupon_stores_count': '全国 12,800+ 门店', }, 'en-US': { @@ -358,6 +482,130 @@ const translations: Record> = { 'error_unknown': 'Unknown Error', 'error_not_found': 'Page Not Found', 'error_unauthorized': 'Please Log In', + + // ── Home (additional) ── + 'home_ai_text': 'We found great deals based on your preferences', + 'home_banner_new_user': 'New User Exclusive', + 'home_banner_new_user_desc': 'Save ¥10 on first order', + 'home_banner_flash': 'Flash Sale', + 'home_banner_flash_desc': 'Up to 30% off', + 'home_banner_hot': 'Hot Picks', + 'home_banner_hot_desc': 'Best discount coupons', + 'home_category_food': 'Food', + 'home_category_shopping': 'Shopping', + 'home_category_entertainment': 'Fun', + 'home_category_travel': 'Travel', + + // ── Login (additional) ── + 'app_slogan': 'Discover great coupons', + 'login_wechat': 'Login with WeChat', + 'login_or': 'or', + 'login_phone': 'Phone number', + 'login_code': 'Verification code', + 'login_btn': 'Log In', + 'login_agree': 'By logging in, you agree to the', + + // ── Detail (additional) ── + 'coupon_type_label': 'Type', + 'coupon_store': 'Stores', + 'coupon_type_consumer': 'Consumer Coupon', + 'coupon_price_save': 'Save vs. face value', + 'coupon_utility_notice': 'You are buying a consumer coupon for consumption', + 'coupon_rule_universal': 'Valid at all Starbucks stores nationwide', + 'coupon_rule_giftable': 'Can be gifted to friends', + 'coupon_rule_anytime': 'Use anytime before expiry', + 'coupon_rule_no_stack': 'Cannot be stacked with other offers', + 'order_total': 'Total', + 'coupon_buy_now': 'Buy Now', + + // ── My Coupons (additional) ── + 'coupon_valid_until_prefix': 'Valid until', + + // ── Redeem (additional) ── + 'redeem_qr_label': 'QR Code', + 'redeem_valid_time': 'Valid for', + 'redeem_refresh': 'Refresh Code', + 'redeem_hint': 'Show this code to the merchant for scanning. Screen brightness has been maximized.', + + // ── Profile (additional) ── + 'profile_kyc_basic': 'Basic Verified', + 'profile_owned': 'Owned', + 'profile_payment': 'Payment', + 'profile_notifications': 'Notifications', + 'profile_language': 'Language', + 'profile_currency': 'Currency', + 'download_app_full_desc': 'Unlock secondary market trading, P2P gifting & more', + 'download_btn': 'Download', + + // ── H5 Share ── + 'share_from_genex': 'Shared via Genex', + 'share_open_app': 'Open App to Buy', + 'share_miniapp_buy': 'Buy in Mini Program', + 'share_to_friends': 'Share with Friends', + + // ── H5 Activity ── + 'activity_flash': 'Flash Sale', + 'activity_title': 'Flash Deals | New User Exclusive', + 'activity_subtitle': 'Top brand coupons from 30% off', + 'activity_countdown': 'Ends in', + 'activity_featured': 'Featured Coupons', + 'activity_limited': 'Limited stock, first come first served', + 'activity_tag_hot': 'Hot', + 'activity_tag_selling': 'Best Seller', + 'activity_tag_new': 'New', + 'activity_buy_now': 'Buy Now', + 'activity_rules': 'Rules', + 'activity_rule_1': 'Event period: Feb 10, 2026 - Feb 28, 2026', + 'activity_rule_2': 'Each user can buy up to 3 of each coupon. Cannot be combined with other offers.', + 'activity_rule_3': 'Coupons are valid for 30 days from purchase date.', + 'activity_rule_4': 'Activity coupons are for new users\' first purchase only.', + 'activity_rule_5': 'Genex reserves the right to adjust activity contents if items are sold out.', + 'activity_rule_6': 'Refunds will be returned via original payment method within 1-3 business days.', + 'activity_rule_7': 'For questions, contact support: support@genex.com', + 'activity_participants': '{count} people joined', + 'app_platform_slogan': 'Global Coupon Asset Trading Platform', + + // ── H5 Register ── + 'activity_new_user': 'New User Exclusive', + 'activity_first_order': 'Save $10 on first order, limited time', + 'activity_coupons': 'Event Coupons', + 'activity_brand': 'Brand', + 'activity_join_now': 'Join Now', + 'register_join': 'Join Genex', + 'register_slogan': 'Make every coupon count', + 'register_benefit': 'Get first-order discount on signup', + 'register_benefit_coupons': 'Massive Coupons', + 'register_benefit_coupons_desc': 'Dining, shopping, entertainment & more', + 'register_benefit_discount': 'Great Discounts', + 'register_benefit_discount_desc': 'Up to 30% off, save smart', + 'register_benefit_safe': 'Secure Trading', + 'register_benefit_safe_desc': 'Platform guaranteed, buy with confidence', + 'register_now': 'Sign Up Now', + 'register_login': 'Already have an account? Log In', + 'register_why_genex': 'Why Genex?', + 'register_benefit_coupons_full': 'Covering 20+ categories including dining, shopping, entertainment. Top brand coupons at low prices.', + 'register_benefit_safe_full': 'Platform-guaranteed transactions with escrow mechanism for secure trading.', + 'register_benefit_ai': 'AI Recommendations', + 'register_benefit_ai_desc': 'Smart recommendations based on your preferences. Save time and money.', + 'register_create_account': 'Create Your Account', + 'register_other_methods': 'Other login methods', + 'register_has_account': 'Already have an account?', + 'register_login_now': 'Log In', + 'trust_secure': 'Security Certified', + 'trust_guarantee': 'User Protection', + 'trust_privacy': 'Privacy Protected', + 'trust_encryption': 'Your data is protected with bank-grade encryption', + + // ── AI Guide ── + 'ai_guide_greeting': 'Hi! I\'m the AI assistant. I can help you find the best coupons. Try searching "Starbucks"!', + + // ── Share Card ── + 'share_miniapp_code': 'Mini Program Code', + 'share_scan_miniapp': 'Long press to scan', + 'share_buy_coupons': 'Buy great coupons now', + + // ── Coupon Detail (stores) ── + 'coupon_stores_count': '12,800+ stores nationwide', }, 'ja-JP': { @@ -528,5 +776,129 @@ const translations: Record> = { 'error_unknown': '不明なエラー', 'error_not_found': 'ページが見つかりません', 'error_unauthorized': 'ログインしてください', + + // ── Home (additional) ── + 'home_ai_text': 'あなたの好みに合ったお得なクーポンを見つけました', + 'home_banner_new_user': '新規ユーザー限定', + 'home_banner_new_user_desc': '初回注文¥10引き', + 'home_banner_flash': 'タイムセール', + 'home_banner_flash_desc': '最大30%OFF', + 'home_banner_hot': '人気のおすすめ', + 'home_banner_hot_desc': '厳選高割引クーポン', + 'home_category_food': 'グルメ', + 'home_category_shopping': 'ショッピング', + 'home_category_entertainment': 'エンタメ', + 'home_category_travel': '旅行', + + // ── Login (additional) ── + 'app_slogan': 'お得なクーポンを発見', + 'login_wechat': 'WeChatでログイン', + 'login_or': 'または', + 'login_phone': '電話番号', + 'login_code': '認証コード', + 'login_btn': 'ログイン', + 'login_agree': 'ログインすると以下に同意したものとみなされます', + + // ── Detail (additional) ── + 'coupon_type_label': '種類', + 'coupon_store': '利用店舗', + 'coupon_type_consumer': '消費クーポン', + 'coupon_price_save': '額面よりお得', + 'coupon_utility_notice': '消費用のクーポンを購入します', + 'coupon_rule_universal': '全国のスターバックス店舗で利用可能', + 'coupon_rule_giftable': '友達にプレゼント可能', + 'coupon_rule_anytime': '有効期限内いつでも利用可能', + 'coupon_rule_no_stack': '他のクーポンとの併用不可', + 'order_total': '合計', + 'coupon_buy_now': '今すぐ購入', + + // ── My Coupons (additional) ── + 'coupon_valid_until_prefix': '有効期限', + + // ── Redeem (additional) ── + 'redeem_qr_label': 'QRコード', + 'redeem_valid_time': '有効時間', + 'redeem_refresh': 'コードを更新', + 'redeem_hint': 'このコードを店舗スタッフに提示してください。画面の明るさが最大に設定されました。', + + // ── Profile (additional) ── + 'profile_kyc_basic': '基本認証済み', + 'profile_owned': '保有中', + 'profile_payment': '決済管理', + 'profile_notifications': 'お知らせ', + 'profile_language': '言語', + 'profile_currency': '通貨', + 'download_app_full_desc': '二次市場取引、P2Pギフトなどの機能をアンロック', + 'download_btn': 'ダウンロード', + + // ── H5 Share ── + 'share_from_genex': 'Genex からのシェア', + 'share_open_app': 'アプリで購入', + 'share_miniapp_buy': 'ミニプログラムで購入', + 'share_to_friends': '友達にシェア', + + // ── H5 Activity ── + 'activity_flash': 'タイムセール', + 'activity_title': '期間限定 | 新規ユーザー限定', + 'activity_subtitle': '人気ブランドクーポンが最大30%OFF', + 'activity_countdown': '終了まで', + 'activity_featured': '厳選クーポン', + 'activity_limited': '数量限定、お早めに', + 'activity_tag_hot': '人気', + 'activity_tag_selling': '売れ筋', + 'activity_tag_new': '新着', + 'activity_buy_now': '今すぐ購入', + 'activity_rules': 'キャンペーンルール', + 'activity_rule_1': 'キャンペーン期間:2026年2月10日~2026年2月28日', + 'activity_rule_2': 'お一人様各クーポン3枚まで。他の割引との併用不可。', + 'activity_rule_3': 'クーポンは購入日から30日間有効です。', + 'activity_rule_4': 'キャンペーンクーポンは新規ユーザーの初回購入のみ利用可能です。', + 'activity_rule_5': '商品完売の場合、キャンペーン内容を変更する場合があります。', + 'activity_rule_6': '返金は元の決済方法に1-3営業日以内に返金されます。', + 'activity_rule_7': 'ご質問はサポートへ:support@genex.com', + 'activity_participants': '{count}人が参加', + 'app_platform_slogan': 'グローバルクーポン資産取引プラットフォーム', + + // ── H5 Register ── + 'activity_new_user': '新規ユーザー限定', + 'activity_first_order': '初回注文$10割引、期間限定', + 'activity_coupons': 'キャンペーンクーポン', + 'activity_brand': 'ブランド', + 'activity_join_now': '今すぐ参加', + 'register_join': 'Genex に参加', + 'register_slogan': 'すべてのクーポンに価値を', + 'register_benefit': '登録で初回割引をゲット', + 'register_benefit_coupons': '豊富なクーポン', + 'register_benefit_coupons_desc': 'グルメ、ショッピング、エンタメを網羅', + 'register_benefit_discount': 'お得な割引', + 'register_benefit_discount_desc': '最大30%OFF、賢く節約', + 'register_benefit_safe': '安全な取引', + 'register_benefit_safe_desc': 'プラットフォーム保証、安心して購入', + 'register_now': '今すぐ登録', + 'register_login': 'アカウントをお持ちの方はログイン', + 'register_why_genex': 'なぜGenex?', + 'register_benefit_coupons_full': 'グルメ、ショッピング、エンタメなど20+カテゴリーをカバー。人気ブランドのお得なクーポン。', + 'register_benefit_safe_full': 'プラットフォーム保証取引、エスクロー機構で安全な取引を保障。', + 'register_benefit_ai': 'AIスマートレコメンド', + 'register_benefit_ai_desc': 'お好みに合わせたスマートなクーポン提案。時間もお金も節約。', + 'register_create_account': 'アカウントを作成', + 'register_other_methods': 'その他のログイン方法', + 'register_has_account': 'アカウントをお持ちですか?', + 'register_login_now': 'ログイン', + 'trust_secure': 'セキュリティ認証', + 'trust_guarantee': 'ユーザー保護', + 'trust_privacy': 'プライバシー保護', + 'trust_encryption': 'お客様の情報は銀行レベルの暗号化で保護されています', + + // ── AI Guide ── + 'ai_guide_greeting': 'こんにちは!AIアシスタントです。最適なクーポンを見つけるお手伝いをします。「スターバックス」で検索してみてください!', + + // ── Share Card ── + 'share_miniapp_code': 'ミニプログラムコード', + 'share_scan_miniapp': '長押しして読み取る', + 'share_buy_coupons': 'お得なクーポンを今すぐ購入', + + // ── Coupon Detail (stores) ── + 'coupon_stores_count': '全国12,800+店舗', }, }; diff --git a/frontend/miniapp/src/pages/detail/index.tsx b/frontend/miniapp/src/pages/detail/index.tsx index 76490d4..c809550 100644 --- a/frontend/miniapp/src/pages/detail/index.tsx +++ b/frontend/miniapp/src/pages/detail/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; // Taro mini-program - Coupon Detail + Purchase /** @@ -38,16 +39,16 @@ const DetailPage: React.FC = () => { ¥25 8.5折 - 比面值节省 ¥3.75 + {t('coupon_price_save')} ¥3.75 {/* Info List */} {[ - { label: '面值', value: '¥25.00' }, - { label: '有效期', value: '2026/12/31' }, - { label: '类型', value: '消费券' }, - { label: '使用门店', value: '全国 12,800+ 门店' }, + { label: t('coupon_face_value'), value: '¥25.00' }, + { label: t('coupon_valid_until'), value: '2026/12/31' }, + { label: t('coupon_type_label'), value: t('coupon_type_consumer') }, + { label: t('coupon_store'), value: t('coupon_stores_count') }, ].map((item, i) => ( {item.label} @@ -58,12 +59,12 @@ const DetailPage: React.FC = () => { {/* Rules */} - 使用说明 + {t('coupon_description')} {[ - '全国星巴克门店通用', - '可转赠给好友', - '有效期内随时使用', - '不可叠加使用', + t('coupon_rule_universal'), + t('coupon_rule_giftable'), + t('coupon_rule_anytime'), + t('coupon_rule_no_stack'), ].map((rule, i) => ( @@ -75,18 +76,18 @@ const DetailPage: React.FC = () => { {/* Utility Track Notice */} - 您正在购买消费券用于消费 + {t('coupon_utility_notice')} {/* Bottom Buy Bar */} - 合计 + {t('order_total')} ¥21.25 - 立即购买 + {t('coupon_buy_now')} diff --git a/frontend/miniapp/src/pages/h5-activity/index.tsx b/frontend/miniapp/src/pages/h5-activity/index.tsx index e5ffa85..1e83b29 100644 --- a/frontend/miniapp/src/pages/h5-activity/index.tsx +++ b/frontend/miniapp/src/pages/h5-activity/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; // Taro mini-program component /** @@ -15,14 +16,14 @@ const H5ActivityPage: React.FC = () => { 🔥 - 限时活动 + {t('activity_flash')} - 限时特惠 | 新用户专享 - 精选大牌优惠券,折扣低至7折起 + {t('activity_title')} + {t('activity_subtitle')} {/* Countdown Timer */} - 距活动结束 + {t('activity_countdown')} 02 @@ -46,8 +47,8 @@ const H5ActivityPage: React.FC = () => { {/* Featured Coupon Cards */} - 精选好券 - 限量抢购,先到先得 + {t('activity_featured')} + {t('activity_limited')} {[ @@ -58,7 +59,7 @@ const H5ActivityPage: React.FC = () => { originalPrice: '¥50.00', discountPrice: '¥35.00', discount: '7折', - tag: '爆款', + tag: t('activity_tag_hot'), }, { brand: 'Amazon', @@ -67,7 +68,7 @@ const H5ActivityPage: React.FC = () => { originalPrice: '¥200.00', discountPrice: '¥156.00', discount: '7.8折', - tag: '热卖', + tag: t('activity_tag_selling'), }, { brand: 'Nike', @@ -76,7 +77,7 @@ const H5ActivityPage: React.FC = () => { originalPrice: '¥100.00', discountPrice: '¥72.00', discount: '7.2折', - tag: '新品', + tag: t('activity_tag_new'), }, ].map((coupon, i) => ( @@ -113,7 +114,7 @@ const H5ActivityPage: React.FC = () => { {/* Buy Button */} - 立即抢购 + {t('activity_buy_now')} ))} @@ -125,18 +126,18 @@ const H5ActivityPage: React.FC = () => { 📋 - 活动规则 + {t('activity_rules')} {[ - '活动时间:2026年2月10日 - 2026年2月28日', - '每位用户限购每种券3张,活动优惠券不与其他优惠叠加使用', - '优惠券自购买之日起30天内有效,过期自动作废', - '活动券仅限新注册用户首次购买使用', - '如遇商品售罄,Genex保留调整活动内容的权利', - '退款将原路返回,处理时间为1-3个工作日', - '如有疑问请联系客服:support@genex.com', + t('activity_rule_1'), + t('activity_rule_2'), + t('activity_rule_3'), + t('activity_rule_4'), + t('activity_rule_5'), + t('activity_rule_6'), + t('activity_rule_7'), ].map((rule, i) => ( @@ -154,7 +155,7 @@ const H5ActivityPage: React.FC = () => { 📤 - 分享给好友 + {t('share_to_friends')} @@ -166,7 +167,7 @@ const H5ActivityPage: React.FC = () => { Genex - 全球券资产交易平台 + {t('app_platform_slogan')} © 2026 Genex. All rights reserved. diff --git a/frontend/miniapp/src/pages/h5-register/index.tsx b/frontend/miniapp/src/pages/h5-register/index.tsx index 12a229d..7e3a567 100644 --- a/frontend/miniapp/src/pages/h5-register/index.tsx +++ b/frontend/miniapp/src/pages/h5-register/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; // Taro mini-program component /** @@ -19,28 +20,28 @@ const H5RegisterPage: React.FC = () => { G Genex - 全球券资产交易平台 + {t('app_platform_slogan')} {/* Benefits Section */} - 为什么选择 Genex? + {t('register_why_genex')} {[ { icon: '🎫', - title: '海量优惠券', - desc: '覆盖餐饮、购物、娱乐等20+品类,全球大牌低价好券', + title: t('register_benefit_coupons'), + desc: t('register_benefit_coupons_full'), }, { icon: '🔒', - title: '安全交易', - desc: '平台担保交易,资金托管机制,保障每一笔交易安全可靠', + title: t('register_benefit_safe'), + desc: t('register_benefit_safe_full'), }, { icon: '🤖', - title: 'AI智能推荐', - desc: '基于您的偏好智能推荐高性价比好券,省时又省钱', + title: t('register_benefit_ai'), + desc: t('register_benefit_ai_desc'), }, ].map((benefit, i) => ( @@ -56,7 +57,7 @@ const H5RegisterPage: React.FC = () => { {/* Registration Form */} - 创建您的账户 + {t('register_create_account')} {/* Phone Input */} @@ -68,7 +69,7 @@ const H5RegisterPage: React.FC = () => { @@ -82,13 +83,13 @@ const H5RegisterPage: React.FC = () => { 🔑 - 获取验证码 + {t('login_send_code')} @@ -99,35 +100,35 @@ const H5RegisterPage: React.FC = () => { - 我已阅读并同意 - 《用户协议》 - - 《隐私政策》 + {t('login_agree_prefix')} + {`《${t('login_user_agreement')}》`} + {t('login_and')} + {`《${t('login_privacy_policy')}》`} {/* Primary CTA Button */} - 立即注册 + {t('register_now')} {/* Social Login Divider */} - 其他登录方式 + {t('register_other_methods')} {/* WeChat Login */} 💬 - 微信一键登录 + {t('login_wechat')} {/* Already Have Account */} - 已有账号? - 立即登录 + {t('register_has_account')} + {t('register_login_now')} @@ -135,9 +136,9 @@ const H5RegisterPage: React.FC = () => { {[ - { icon: '🛡️', label: '安全认证' }, - { icon: '✅', label: '用户保障' }, - { icon: '🔐', label: '隐私保护' }, + { icon: '🛡️', label: t('trust_secure') }, + { icon: '✅', label: t('trust_guarantee') }, + { icon: '🔐', label: t('trust_privacy') }, ].map((badge, i) => ( {badge.icon} @@ -145,7 +146,7 @@ const H5RegisterPage: React.FC = () => { ))} - 您的信息受到银行级加密保护 + {t('trust_encryption')} ); diff --git a/frontend/miniapp/src/pages/h5-share/index.tsx b/frontend/miniapp/src/pages/h5-share/index.tsx index 94924fc..1c418f7 100644 --- a/frontend/miniapp/src/pages/h5-share/index.tsx +++ b/frontend/miniapp/src/pages/h5-share/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; /** * E2. H5页面 - 券分享页 + 活动落地页 + 注册引导页 @@ -27,7 +28,7 @@ export const SharePage: React.FC = () => { fontSize: 13, }}> 💎 - 来自 Genex 的分享 + {t('share_from_genex')} @@ -89,14 +90,14 @@ export const SharePage: React.FC = () => { }}>8.5折
- 比面值节省 $3.75 + {t('coupon_price_save')} $3.75
{/* Info rows */} {[ - { label: '有效期', value: '2026/12/31' }, - { label: '使用门店', value: '全国 12,800+ 门店' }, + { label: t('coupon_valid_until'), value: '2026/12/31' }, + { label: t('coupon_store'), value: t('coupon_stores_count') }, ].map((item, i) => (
{ cursor: 'pointer', marginBottom: 12, }}> - 打开 App 购买 + {t('share_open_app')}
@@ -164,13 +165,13 @@ export const ActivityPage: React.FC = () => { alignItems: 'center', color: 'white', }}> -

新用户专享

-

首单立减 $10,限时优惠

+

{t('activity_new_user')}

+

{t('activity_first_order')}

{/* Coupon Grid */}
-

活动好券

+

{t('activity_coupons')}

{Array.from({ length: 4 }, (_, i) => (
{ 🎫
-
品牌 {i + 1}
+
{t('activity_brand')} {i + 1}
${(i + 1) * 8.5}
@@ -214,7 +215,7 @@ export const ActivityPage: React.FC = () => { fontWeight: 600, cursor: 'pointer', }}> - 立即参与 + {t('activity_join_now')}
@@ -249,18 +250,18 @@ export const RegisterGuidePage: React.FC = () => {

- 加入 Genex + {t('register_join')}

- 让每一张券都有价值
- 注册即享首单立减优惠 + {t('register_slogan')}
+ {t('register_benefit')}

{/* Features */} {[ - { icon: '🎫', title: '海量优惠券', desc: '餐饮、购物、娱乐全覆盖' }, - { icon: '💰', title: '超值折扣', desc: '最低7折起,省钱又省心' }, - { icon: '🔒', title: '安全交易', desc: '平台担保,放心购买' }, + { icon: '🎫', title: t('register_benefit_coupons'), desc: t('register_benefit_coupons_desc') }, + { icon: '💰', title: t('register_benefit_discount'), desc: t('register_benefit_discount_desc') }, + { icon: '🔒', title: t('register_benefit_safe'), desc: t('register_benefit_safe_desc') }, ].map((f, i) => (
{ fontSize: 16, fontWeight: 600, cursor: 'pointer', marginBottom: 12, }}> - 立即注册 + {t('register_now')}
diff --git a/frontend/miniapp/src/pages/home/index.tsx b/frontend/miniapp/src/pages/home/index.tsx index 82b601c..378845f 100644 --- a/frontend/miniapp/src/pages/home/index.tsx +++ b/frontend/miniapp/src/pages/home/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; // Taro mini-program component (WeChat / Alipay) /** @@ -15,7 +16,7 @@ const HomePage: React.FC = () => { 🔍 - 搜索券、品牌... + {t('home_search_hint')} @@ -27,11 +28,15 @@ const HomePage: React.FC = () => { circular indicatorActiveColor="#6C5CE7" > - {['新用户专享 - 首单立减¥10', '限时折扣 - 全场低至7折', '热门推荐 - 精选高折扣券'].map((text, i) => ( + {[ + { title: t('home_banner_new_user'), subtitle: t('home_banner_new_user_desc') }, + { title: t('home_banner_flash'), subtitle: t('home_banner_flash_desc') }, + { title: t('home_banner_hot'), subtitle: t('home_banner_hot_desc') }, + ].map((banner, i) => ( - {text.split(' - ')[0]} - {text.split(' - ')[1]} + {banner.title} + {banner.subtitle} ))} @@ -40,13 +45,13 @@ const HomePage: React.FC = () => { {/* Category Grid */} {[ - { name: '餐饮', icon: '🍽️' }, - { name: '购物', icon: '🛍️' }, - { name: '娱乐', icon: '🎮' }, - { name: '出行', icon: '🚗' }, - { name: '全部', icon: '📋' }, - ].map(cat => ( - + { name: t('home_category_food'), icon: '🍽️' }, + { name: t('home_category_shopping'), icon: '🛍️' }, + { name: t('home_category_entertainment'), icon: '🎮' }, + { name: t('home_category_travel'), icon: '🚗' }, + { name: t('all'), icon: '📋' }, + ].map((cat, i) => ( + {cat.icon} {cat.name} @@ -57,16 +62,16 @@ const HomePage: React.FC = () => { - AI 推荐 - 根据你的偏好,发现了高性价比券 + {t('home_recommended')} + {t('home_ai_text')} {/* Hot Coupons */} - 热门好券 - 更多 › + {t('home_hot')} + {t('more')} › diff --git a/frontend/miniapp/src/pages/login/index.tsx b/frontend/miniapp/src/pages/login/index.tsx index 1398c8f..f9f3092 100644 --- a/frontend/miniapp/src/pages/login/index.tsx +++ b/frontend/miniapp/src/pages/login/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; // Taro mini-program component /** @@ -17,19 +18,19 @@ const LoginPage: React.FC = () => { G Genex - 发现优质好券 + {t('app_slogan')} {/* WeChat Login (小程序) */} 💬 - 微信一键登录 + {t('login_wechat')} - + {t('login_or')} @@ -37,28 +38,28 @@ const LoginPage: React.FC = () => { 📱 - + 🔒 - + - 获取验证码 + {t('login_send_code')} - 登录 + {t('login_btn')} {/* Terms */} - 登录即表示同意 - 《用户协议》 - - 《隐私政策》 + {t('login_agree')} + {`《${t('login_user_agreement')}》`} + {t('login_and')} + {`《${t('login_privacy_policy')}》`} diff --git a/frontend/miniapp/src/pages/my-coupons/index.tsx b/frontend/miniapp/src/pages/my-coupons/index.tsx index 13a9dbf..4bb7007 100644 --- a/frontend/miniapp/src/pages/my-coupons/index.tsx +++ b/frontend/miniapp/src/pages/my-coupons/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; // Taro mini-program component /** @@ -9,7 +10,7 @@ import React from 'react'; */ const MyCouponsPage: React.FC = () => { - const tabs = ['可使用', '已使用', '已过期']; + const tabs = [t('my_coupons_available'), t('my_coupons_used'), t('my_coupons_expired')]; const [activeTab] = React.useState(0); return ( @@ -40,11 +41,11 @@ const MyCouponsPage: React.FC = () => { {coupon.brand} {coupon.name} - 有效期至 {coupon.expiry} + {t('coupon_valid_until_prefix')} {coupon.expiry} - 使用 + {t('coupon_use')} {/* Ticket notch decoration */} @@ -58,7 +59,7 @@ const MyCouponsPage: React.FC = () => { {activeTab > 0 && ( 📭 - 暂无券 + {t('my_coupons_empty')} )} diff --git a/frontend/miniapp/src/pages/profile/index.tsx b/frontend/miniapp/src/pages/profile/index.tsx index e63a6e8..188e35b 100644 --- a/frontend/miniapp/src/pages/profile/index.tsx +++ b/frontend/miniapp/src/pages/profile/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; // Taro mini-program component /** @@ -18,7 +19,7 @@ const ProfilePage: React.FC = () => { User_138****88 - L1 基础认证 + {`L1 ${t('profile_kyc_basic')}`} @@ -26,11 +27,11 @@ const ProfilePage: React.FC = () => { {/* Stats */} {[ - { value: '5', label: '持有券' }, - { value: '12', label: '已使用' }, - { value: '3', label: '已过期' }, - ].map(s => ( - + { value: '5', label: t('profile_owned') }, + { value: '12', label: t('my_coupons_used') }, + { value: '3', label: t('my_coupons_expired') }, + ].map((s, i) => ( + {s.value} {s.label} @@ -40,12 +41,12 @@ const ProfilePage: React.FC = () => { {/* Menu */} {[ - { icon: '🎫', label: '我的券', path: '/pages/my-coupons/index' }, - { icon: '📋', label: '我的订单', path: '/pages/orders/index' }, - { icon: '💳', label: '支付管理', path: '' }, - { icon: '🔔', label: '消息通知', path: '' }, - ].map(item => ( - + { icon: '🎫', label: t('my_coupons'), path: '/pages/my-coupons/index' }, + { icon: '📋', label: t('profile_orders'), path: '/pages/orders/index' }, + { icon: '💳', label: t('profile_payment'), path: '' }, + { icon: '🔔', label: t('profile_notifications'), path: '' }, + ].map((item, i) => ( + {item.icon} {item.label} @@ -55,12 +56,12 @@ const ProfilePage: React.FC = () => { {[ - { icon: '🌐', label: '语言 / Language', value: '简体中文' }, - { icon: '💰', label: '货币', value: 'USD' }, - { icon: '❓', label: '帮助中心', value: '' }, - { icon: '⚙️', label: '设置', value: '' }, - ].map(item => ( - + { icon: '🌐', label: t('profile_language'), value: '简体中文' }, + { icon: '💰', label: t('profile_currency'), value: 'USD' }, + { icon: '❓', label: t('profile_help'), value: '' }, + { icon: '⚙️', label: t('profile_settings'), value: '' }, + ].map((item, i) => ( + {item.icon} {item.label} {item.value ? {item.value} : null} @@ -72,11 +73,11 @@ const ProfilePage: React.FC = () => { {/* Download App Banner */} - 下载 Genex App - 解锁二级市场交易、P2P转赠等完整功能 + {t('download_app_title')} + {t('download_app_full_desc')} - 下载 + {t('download_btn')} diff --git a/frontend/miniapp/src/pages/redeem/index.tsx b/frontend/miniapp/src/pages/redeem/index.tsx index 9ac2f1f..318e012 100644 --- a/frontend/miniapp/src/pages/redeem/index.tsx +++ b/frontend/miniapp/src/pages/redeem/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { t } from '@/i18n'; // Taro mini-program component /** @@ -13,7 +14,7 @@ const RedeemPage: React.FC = () => { {/* Coupon Info */} 星巴克 ¥25 礼品卡 - 面值 ¥25.00 + {t('coupon_face_value')} ¥25.00 {/* QR Code */} @@ -21,7 +22,7 @@ const RedeemPage: React.FC = () => { 📱 - 二维码 + {t('redeem_qr_label')} @@ -33,18 +34,18 @@ const RedeemPage: React.FC = () => { {/* Countdown */} - 有效时间 04:58 + {t('redeem_valid_time')} 04:58 - 刷新券码 + {t('redeem_refresh')} {/* Hint */} ℹ️ - 请将此码出示给商户扫描,屏幕已自动调至最高亮度 + {t('redeem_hint')} ); diff --git a/frontend/mobile/lib/app/i18n/app_localizations.dart b/frontend/mobile/lib/app/i18n/app_localizations.dart index 20f07c6..f1c8e7d 100644 --- a/frontend/mobile/lib/app/i18n/app_localizations.dart +++ b/frontend/mobile/lib/app/i18n/app_localizations.dart @@ -1,302 +1,62 @@ -/// Genex Mobile App - i18n 多语言支持 +import 'package:flutter/material.dart'; +import 'strings/zh_cn.dart'; +import 'strings/zh_tw.dart'; +import 'strings/en.dart'; +import 'strings/ja.dart'; + +/// Genex 多语言支持 /// -/// 支持语言: zh-CN (默认), en-US, ja-JP -/// 使用方式: AppLocalizations.of(context).translate('key') - +/// 使用方式: context.t('key') 或 AppLocalizations.of(context).get('key') +/// 支持语言: zh_CN(默认), zh_TW, en, ja class AppLocalizations { - final String locale; + final Locale locale; + late final Map _strings; - AppLocalizations(this.locale); + AppLocalizations(this.locale) { + final key = locale.countryCode != null && locale.countryCode!.isNotEmpty + ? '${locale.languageCode}_${locale.countryCode}' + : locale.languageCode; - static AppLocalizations of(dynamic context) { - // In production, obtain from InheritedWidget / Provider - return AppLocalizations('zh-CN'); + _strings = _allStrings[key] ?? _allStrings[locale.languageCode] ?? zhCN; } - String translate(String key) { - return _localizedValues[locale]?[key] ?? - _localizedValues['zh-CN']?[key] ?? - key; + static AppLocalizations of(BuildContext context) { + return Localizations.of(context, AppLocalizations)!; } - // Shorthand - String t(String key) => translate(key); + /// 获取翻译字符串,找不到时 fallback 到中文,再找不到返回 key + String get(String key) => _strings[key] ?? zhCN[key] ?? key; - static const supportedLocales = ['zh-CN', 'en-US', 'ja-JP']; - - static const Map> _localizedValues = { - 'zh-CN': _zhCN, - 'en-US': _enUS, - 'ja-JP': _jaJP, - }; - - static const Map _zhCN = { - // Common - 'app_name': 'Genex', - 'confirm': '确认', - 'cancel': '取消', - 'save': '保存', - 'delete': '删除', - 'edit': '编辑', - 'search': '搜索', - 'loading': '加载中...', - 'retry': '重试', - 'done': '完成', - 'next': '下一步', - 'back': '返回', - 'close': '关闭', - 'more': '更多', - 'all': '全部', - - // Tabs - 'tab_home': '首页', - 'tab_market': '市场', - 'tab_wallet': '钱包', - 'tab_profile': '我的', - - // Home - 'home_greeting': '你好', - 'home_search_hint': '搜索券、品牌...', - 'home_recommended': 'AI推荐', - 'home_hot': '热门券', - 'home_new': '新上架', - 'home_categories': '分类浏览', - - // Coupon - 'coupon_buy': '购买', - 'coupon_sell': '出售', - 'coupon_transfer': '转赠', - 'coupon_use': '使用', - 'coupon_detail': '券详情', - 'coupon_face_value': '面值', - 'coupon_price': '价格', - 'coupon_discount': '折扣', - 'coupon_valid_until': '有效期至', - 'coupon_brand': '品牌', - 'coupon_category': '类别', - 'coupon_my_coupons': '我的券', - 'coupon_available': '可用', - 'coupon_used': '已使用', - 'coupon_expired': '已过期', - - // Trading - 'trade_buy_order': '买单', - 'trade_sell_order': '卖单', - 'trade_price_input': '输入价格', - 'trade_quantity': '数量', - 'trade_total': '合计', - 'trade_history': '交易记录', - 'trade_pending': '待成交', - 'trade_completed': '已完成', - - // Wallet - 'wallet_balance': '余额', - 'wallet_deposit': '充值', - 'wallet_withdraw': '提现', - 'wallet_transactions': '交易记录', - - // Profile - 'profile_settings': '设置', - 'profile_kyc': '身份认证', - 'profile_kyc_l0': '未认证', - 'profile_kyc_l1': 'L1 基础认证', - 'profile_kyc_l2': 'L2 身份认证', - 'profile_kyc_l3': 'L3 高级认证', - 'profile_language': '语言', - 'profile_currency': '货币', - 'profile_help': '帮助中心', - 'profile_about': '关于', - 'profile_logout': '退出登录', - 'profile_pro_mode': '高级模式', - - // Payment - 'payment_method': '支付方式', - 'payment_confirm': '确认支付', - 'payment_success': '支付成功', - - // AI - 'ai_assistant': 'AI助手', - 'ai_ask': '问我任何问题...', - 'ai_suggestion': 'AI建议', - }; - - static const Map _enUS = { - // Common - 'app_name': 'Genex', - 'confirm': 'Confirm', - 'cancel': 'Cancel', - 'save': 'Save', - 'delete': 'Delete', - 'edit': 'Edit', - 'search': 'Search', - 'loading': 'Loading...', - 'retry': 'Retry', - 'done': 'Done', - 'next': 'Next', - 'back': 'Back', - 'close': 'Close', - 'more': 'More', - 'all': 'All', - - // Tabs - 'tab_home': 'Home', - 'tab_market': 'Market', - 'tab_wallet': 'Wallet', - 'tab_profile': 'Profile', - - // Home - 'home_greeting': 'Hello', - 'home_search_hint': 'Search coupons, brands...', - 'home_recommended': 'AI Picks', - 'home_hot': 'Trending', - 'home_new': 'New Arrivals', - 'home_categories': 'Categories', - - // Coupon - 'coupon_buy': 'Buy', - 'coupon_sell': 'Sell', - 'coupon_transfer': 'Gift', - 'coupon_use': 'Redeem', - 'coupon_detail': 'Coupon Details', - 'coupon_face_value': 'Face Value', - 'coupon_price': 'Price', - 'coupon_discount': 'Discount', - 'coupon_valid_until': 'Valid Until', - 'coupon_brand': 'Brand', - 'coupon_category': 'Category', - 'coupon_my_coupons': 'My Coupons', - 'coupon_available': 'Available', - 'coupon_used': 'Used', - 'coupon_expired': 'Expired', - - // Trading - 'trade_buy_order': 'Buy Order', - 'trade_sell_order': 'Sell Order', - 'trade_price_input': 'Enter Price', - 'trade_quantity': 'Quantity', - 'trade_total': 'Total', - 'trade_history': 'Trade History', - 'trade_pending': 'Pending', - 'trade_completed': 'Completed', - - // Wallet - 'wallet_balance': 'Balance', - 'wallet_deposit': 'Deposit', - 'wallet_withdraw': 'Withdraw', - 'wallet_transactions': 'Transactions', - - // Profile - 'profile_settings': 'Settings', - 'profile_kyc': 'Verification', - 'profile_kyc_l0': 'Unverified', - 'profile_kyc_l1': 'L1 Basic', - 'profile_kyc_l2': 'L2 Identity', - 'profile_kyc_l3': 'L3 Advanced', - 'profile_language': 'Language', - 'profile_currency': 'Currency', - 'profile_help': 'Help Center', - 'profile_about': 'About', - 'profile_logout': 'Log Out', - 'profile_pro_mode': 'Pro Mode', - - // Payment - 'payment_method': 'Payment Method', - 'payment_confirm': 'Confirm Payment', - 'payment_success': 'Payment Successful', - - // AI - 'ai_assistant': 'AI Assistant', - 'ai_ask': 'Ask me anything...', - 'ai_suggestion': 'AI Suggestion', - }; - - static const Map _jaJP = { - // Common - 'app_name': 'Genex', - 'confirm': '確認', - 'cancel': 'キャンセル', - 'save': '保存', - 'delete': '削除', - 'edit': '編集', - 'search': '検索', - 'loading': '読み込み中...', - 'retry': 'リトライ', - 'done': '完了', - 'next': '次へ', - 'back': '戻る', - 'close': '閉じる', - 'more': 'もっと見る', - 'all': 'すべて', - - // Tabs - 'tab_home': 'ホーム', - 'tab_market': 'マーケット', - 'tab_wallet': 'ウォレット', - 'tab_profile': 'マイページ', - - // Home - 'home_greeting': 'こんにちは', - 'home_search_hint': 'クーポン、ブランドを検索...', - 'home_recommended': 'AIおすすめ', - 'home_hot': '人気', - 'home_new': '新着', - 'home_categories': 'カテゴリー', - - // Coupon - 'coupon_buy': '購入', - 'coupon_sell': '売却', - 'coupon_transfer': '贈与', - 'coupon_use': '使用', - 'coupon_detail': 'クーポン詳細', - 'coupon_face_value': '額面', - 'coupon_price': '価格', - 'coupon_discount': '割引', - 'coupon_valid_until': '有効期限', - 'coupon_brand': 'ブランド', - 'coupon_category': 'カテゴリー', - 'coupon_my_coupons': 'マイクーポン', - 'coupon_available': '利用可能', - 'coupon_used': '使用済み', - 'coupon_expired': '期限切れ', - - // Trading - 'trade_buy_order': '買い注文', - 'trade_sell_order': '売り注文', - 'trade_price_input': '価格を入力', - 'trade_quantity': '数量', - 'trade_total': '合計', - 'trade_history': '取引履歴', - 'trade_pending': '未約定', - 'trade_completed': '約定済み', - - // Wallet - 'wallet_balance': '残高', - 'wallet_deposit': '入金', - 'wallet_withdraw': '出金', - 'wallet_transactions': '取引履歴', - - // Profile - 'profile_settings': '設定', - 'profile_kyc': '本人確認', - 'profile_kyc_l0': '未確認', - 'profile_kyc_l1': 'L1 基本認証', - 'profile_kyc_l2': 'L2 身分認証', - 'profile_kyc_l3': 'L3 高度認証', - 'profile_language': '言語', - 'profile_currency': '通貨', - 'profile_help': 'ヘルプ', - 'profile_about': 'アプリについて', - 'profile_logout': 'ログアウト', - 'profile_pro_mode': 'プロモード', - - // Payment - 'payment_method': '支払い方法', - 'payment_confirm': '支払いを確認', - 'payment_success': '支払い完了', - - // AI - 'ai_assistant': 'AIアシスタント', - 'ai_ask': '何でも聞いてください...', - 'ai_suggestion': 'AIの提案', + static const Map> _allStrings = { + 'zh': zhCN, + 'zh_CN': zhCN, + 'zh_TW': zhTW, + 'en': en, + 'ja': ja, }; } + +/// LocalizationsDelegate +class AppLocalizationsDelegate extends LocalizationsDelegate { + const AppLocalizationsDelegate(); + + @override + bool isSupported(Locale locale) { + return ['zh', 'en', 'ja'].contains(locale.languageCode); + } + + @override + Future load(Locale locale) async { + return AppLocalizations(locale); + } + + @override + bool shouldReload(covariant LocalizationsDelegate old) => + false; +} + +/// BuildContext 扩展,快捷访问翻译 +extension AppLocalizationsExtension on BuildContext { + /// 快捷翻译: context.t('key') + String t(String key) => AppLocalizations.of(this).get(key); +} diff --git a/frontend/mobile/lib/app/i18n/strings/en.dart b/frontend/mobile/lib/app/i18n/strings/en.dart new file mode 100644 index 0000000..d6a4a0a --- /dev/null +++ b/frontend/mobile/lib/app/i18n/strings/en.dart @@ -0,0 +1,686 @@ +const Map en = { + // ============ Common ============ + 'common.confirm': 'Confirm', + 'common.cancel': 'Cancel', + 'common.save': 'Save', + 'common.delete': 'Delete', + 'common.edit': 'Edit', + 'common.search': 'Search', + 'common.loading': 'Loading...', + 'common.retry': 'Retry', + 'common.done': 'Done', + 'common.next': 'Next', + 'common.back': 'Back', + 'common.close': 'Close', + 'common.more': 'More', + 'common.all': 'All', + 'common.filter': 'Filter', + 'common.sort': 'Sort', + 'common.copy': 'Copy', + 'common.copied': 'Copied to clipboard', + 'common.today': 'Today', + 'common.thisWeek': 'This Week', + 'common.thisMonth': 'This Month', + + // ============ Navigation ============ + 'nav.home': 'Home', + 'nav.market': 'Market', + 'nav.myCoupons': 'My Coupons', + 'nav.messages': 'Messages', + 'nav.profile': 'Profile', + + // ============ Welcome / Auth ============ + 'welcome.slogan': 'Make Every Coupon Count', + 'welcome.phoneRegister': 'Phone Sign Up', + 'welcome.emailRegister': 'Email Sign Up', + 'welcome.otherLogin': 'Other Login Methods', + 'welcome.hasAccount': 'Already have an account?', + 'welcome.login': 'Log In', + 'welcome.agreement': 'By signing up you agree to Terms of Service and Privacy Policy', + + 'login.title': 'Welcome Back', + 'login.subtitle': 'Log in to manage your coupon assets', + 'login.passwordTab': 'Password', + 'login.codeTab': 'Verification Code', + 'login.phoneOrEmail': 'Phone or Email', + 'login.password': 'Password', + 'login.forgotPassword': 'Forgot password?', + 'login.submit': 'Log In', + 'login.phone': 'Phone', + 'login.verifyCode': 'Code', + 'login.getCode': 'Get Code', + + 'register.title': 'Create Account', + 'register.emailSubtitle': 'Sign up with your email', + 'register.phoneSubtitle': 'Sign up with your phone number', + 'register.email': 'Email', + 'register.phone': 'Phone', + 'register.emailHint': 'Enter your email', + 'register.phoneHint': 'Enter your phone number', + 'register.code': 'Code', + 'register.codeHint': 'Enter 6-digit code', + 'register.getCode': 'Get Code', + 'register.setPassword': 'Set Password', + 'register.passwordHint': '8-20 chars, letters and numbers', + 'register.agreement': 'I have read and agree to', + 'register.userAgreement': 'Terms of Service', + 'register.privacyPolicy': 'Privacy Policy', + 'register.submit': 'Sign Up', + 'register.stepVerify': 'Verify', + 'register.stepPassword': 'Password', + 'register.stepDone': 'Done', + 'register.rule8chars': '8+ chars', + 'register.ruleLetter': 'Letters', + 'register.ruleNumber': 'Numbers', + + 'forgot.title': 'Reset Password', + 'forgot.inputAccount': 'Enter phone or email', + 'forgot.sendHint': 'We\'ll send you a verification code', + 'forgot.accountHint': 'Phone / Email', + 'forgot.getCode': 'Get Code', + 'forgot.inputCode': 'Enter Code', + 'forgot.codeSentTo': 'Code sent to', + 'forgot.codeHint': '6-digit code', + 'forgot.resend': 'Resend', + 'forgot.next': 'Next', + 'forgot.setNewPassword': 'Set New Password', + 'forgot.newPasswordHint': 'Enter new password (8+ chars)', + 'forgot.newPassword': 'New Password', + 'forgot.confirmPassword': 'Confirm Password', + 'forgot.confirmChange': 'Confirm', + 'forgot.success': 'Password Changed', + 'forgot.successHint': 'Please log in with your new password', + 'forgot.backToLogin': 'Back to Login', + + // ============ Home ============ + 'home.searchHint': 'Search coupons, brands, categories...', + 'home.dining': 'Dining', + 'home.shopping': 'Shopping', + 'home.entertainment': 'Entertainment', + 'home.travel': 'Travel', + 'home.lifestyle': 'Lifestyle', + 'home.brand': 'Brands', + 'home.discount': 'Deals', + 'home.allCategories': 'All', + 'home.featuredCoupons': 'Featured Coupons', + 'home.viewAllCoupons': 'View All', + 'home.aiRecommend': 'AI Picks', + 'home.aiRecommendDesc': 'Found 3 great deals based on your preferences', + 'home.bannerNewUser': 'New User Special', + 'home.bannerNewUserDesc': 'Save \$10 on first order', + 'home.bannerDiscount': 'Flash Sale', + 'home.bannerDiscountDesc': 'Up to 30% off everything', + 'home.bannerHot': 'Hot Picks', + 'home.bannerHotDesc': 'Top discount coupons', + + // ============ Market ============ + 'market.title': 'Marketplace', + 'market.primary': 'Primary Market (New)', + 'market.secondary': 'Secondary Market (Resale)', + 'market.dining': 'Dining', + 'market.shopping': 'Shopping', + 'market.entertainment': 'Entertainment', + 'market.travel': 'Travel', + 'market.lifestyle': 'Lifestyle', + 'market.sports': 'Sports', + 'market.discountRate': 'Discount', + 'market.priceUp': 'Price \u2191', + 'market.priceDown': 'Price \u2193', + 'market.expiryDate': 'Expiry', + 'market.issuePrice': 'Issue Price', + 'market.faceValue': 'Face Value', + 'market.discount': 'Discount', + 'market.totalSupply': 'Supply', + 'market.salesProgress': 'Sales Progress', + 'market.upcoming': 'Upcoming', + 'market.subscribing': 'Live', + 'market.ended': 'Ended', + 'market.timeToStart': 'Starts in', + 'market.couponBrand': 'Coupon / Brand', + 'market.latestPrice': 'Price', + 'market.change24h': '24h Change', + 'market.discountSuffix': ' off', + + // ============ My Coupons ============ + 'myCoupons.title': 'My Coupons', + 'myCoupons.usable': 'Active', + 'myCoupons.pendingRedeem': 'Pending', + 'myCoupons.expired': 'Expired', + 'myCoupons.faceValue': 'Value', + 'myCoupons.transfer': 'Gift', + 'myCoupons.sell': 'Sell', + 'myCoupons.expiredText': 'Expired', + 'myCoupons.expiringToday': 'Expires today', + 'myCoupons.daysToExpiry': 'd left', + + // ============ Coupon Detail ============ + 'couponDetail.title': 'Coupon Details', + 'couponDetail.favorite': 'Favorite', + 'couponDetail.buyNow': 'Buy Now', + 'couponDetail.saveBadge': 'Save', + 'couponDetail.faceValue': 'Face Value', + 'couponDetail.validUntil': 'Valid Until', + 'couponDetail.type': 'Type', + 'couponDetail.issuer': 'Issuer', + 'couponDetail.consumeCoupon': 'Voucher', + 'couponDetail.usageNote': 'Usage Notes', + 'couponDetail.allStores': 'Valid at all nationwide stores', + 'couponDetail.canTransfer': 'Can be gifted to others', + 'couponDetail.useAnytime': 'Use anytime before expiry', + 'couponDetail.noStack': 'Cannot be combined', + 'couponDetail.noCash': 'Not redeemable for cash', + 'couponDetail.stores': 'Stores', + 'couponDetail.storeCount': '12,800+ Stores Nationwide', + 'couponDetail.storeDesc': 'Valid at all official stores nationwide', + 'couponDetail.priceTrend': 'Price Trend', + 'couponDetail.last30Days': 'Last 30 Days', + 'couponDetail.highest': 'High', + 'couponDetail.lowest': 'Low', + 'couponDetail.average': 'Avg', + 'couponDetail.tradeHistory': 'Trade History', + 'couponDetail.nearbyStores': 'Nearby Stores', + 'couponDetail.distance': 'Distance', + 'couponDetail.open': 'Open', + 'couponDetail.similar': 'Similar Coupons', + + // ============ My Coupon Detail ============ + 'myCoupon.title': 'My Coupon', + 'myCoupon.active': 'Active', + 'myCoupon.showQrHint': 'Show this QR code to the merchant to redeem', + 'myCoupon.switchBarcode': 'Switch to Barcode', + 'myCoupon.faceValue': 'Face Value', + 'myCoupon.purchasePrice': 'Purchase Price', + 'myCoupon.validUntil': 'Valid Until', + 'myCoupon.orderNo': 'Order No.', + 'myCoupon.resellCount': 'Resale Remaining', + 'myCoupon.transfer': 'Gift', + 'myCoupon.sell': 'Sell', + 'myCoupon.usageNote': 'Usage Notes', + 'myCoupon.useInStore': 'Valid at all nationwide stores', + 'myCoupon.useInTime': 'Use before expiry date', + 'myCoupon.onePerVisit': 'One coupon per visit', + 'myCoupon.noCash': 'Not redeemable for cash', + 'myCoupon.extractToWallet': 'Withdraw to External Wallet', + 'myCoupon.requireKycL2': 'Requires KYC L2+', + 'myCoupon.viewTrades': 'View Trade Records', + 'myCoupon.help': 'Help', + + // ============ Order Confirm ============ + 'orderConfirm.title': 'Confirm Order', + 'orderConfirm.quantity': 'Quantity', + 'orderConfirm.paymentMethod': 'Payment Method', + 'orderConfirm.bankCard': 'Bank/Credit Card', + 'orderConfirm.priceDetail': 'Price Details', + 'orderConfirm.buyingNote': 'You are purchasing a voucher for consumption', + 'orderConfirm.total': 'Total', + 'orderConfirm.confirmPay': 'Confirm Payment', + 'orderConfirm.unitPrice': 'Unit Price', + 'orderConfirm.count': 'Qty', + 'orderConfirm.saveBadge': 'Savings vs Face Value', + 'orderConfirm.biometricHint': 'Verify with fingerprint or face to complete payment', + 'orderConfirm.usePasswordPay': 'Use Password Instead', + + // ============ Payment ============ + 'payment.title': 'Select Payment Method', + 'payment.addNew': 'Add New Payment Method', + 'payment.confirmPay': 'Confirm Payment', + 'payment.bankTransfer': 'Bank Transfer', + + 'paymentSuccess.title': 'Payment Successful', + 'paymentSuccess.hint': 'Coupon added to your holdings', + 'paymentSuccess.couponName': 'Coupon', + 'paymentSuccess.payAmount': 'Amount Paid', + 'paymentSuccess.orderNo': 'Order No.', + 'paymentSuccess.payTime': 'Payment Time', + 'paymentSuccess.viewMyCoupon': 'View My Coupons', + 'paymentSuccess.continueBrowse': 'Continue Browsing', + + // ============ Search ============ + 'search.hint': 'Search coupons, brands, categories...', + 'search.cancel': 'Cancel', + 'search.hotSearch': 'Trending Searches', + 'search.history': 'Search History', + 'search.clear': 'Clear', + 'search.diningCoupon': 'Dining', + 'search.discountCoupon': 'Discount', + 'search.travel': 'Travel', + + // ============ Redeem ============ + 'redeem.title': 'Show Code', + 'redeem.faceValue': 'Face Value', + 'redeem.validTime': 'Valid Time', + 'redeem.refresh': 'Refresh Code', + 'redeem.showHint': 'Show this code to merchant. Screen brightness auto-maximized.', + + // ============ Sell Order ============ + 'sellOrder.title': 'List for Sale', + 'sellOrder.faceValue': 'Face Value', + 'sellOrder.credit': 'Rating', + 'sellOrder.setPrice': 'Set Price', + 'sellOrder.price': 'Price', + 'sellOrder.aiSuggest': 'AI Suggested Price', + 'sellOrder.bestDealRate': 'Best chance of selling', + 'sellOrder.discountRate': 'Discount', + 'sellOrder.platformFee': 'Platform Fee (1.5%)', + 'sellOrder.estimatedReceive': 'Est. Receive', + 'sellOrder.marketAvg': 'Market Average', + 'sellOrder.recent24hTrades': '24h Trades', + 'sellOrder.tradesUnit': ' trades', + 'sellOrder.confirmList': 'Confirm Listing', + 'sellOrder.success': 'Listed Successfully', + 'sellOrder.successHint': 'Your coupon is now on the market. It will be auto-matched when a buyer places an order.', + 'sellOrder.ok': 'OK', + + // ============ Trading Page ============ + 'tradingPage.title': 'My Trades', + 'tradingPage.pendingOrders': 'Open Orders', + 'tradingPage.tradeRecords': 'Trade History', + 'tradingPage.listPrice': 'List Price', + 'tradingPage.listTime': 'Listed', + 'tradingPage.cancelOrder': 'Cancel', + 'tradingPage.buy': 'Buy', + 'tradingPage.sell': 'Sell', + + // ============ Transfer ============ + 'transfer.title': 'Gift to Friend', + 'transfer.searchFriend': 'Search friend (phone/username)', + 'transfer.confirmTransfer': 'Confirm Transfer', + 'transfer.success': 'Transfer Successful', + 'transfer.confirm': 'OK', + 'transfer.cancel': 'Cancel', + + // ============ Wallet ============ + 'wallet.myBalance': 'My Balance', + 'wallet.totalBalance': 'Total Balance', + 'wallet.withdrawable': 'Withdrawable', + 'wallet.frozen': 'Frozen', + 'wallet.deposit': 'Deposit', + 'wallet.withdraw': 'Withdraw', + 'wallet.records': 'Records', + 'wallet.filter': 'Filter', + 'wallet.buyIn': 'Buy', + 'wallet.sellOut': 'Sell', + 'wallet.giftTransfer': 'Gift', + 'wallet.redeemUse': 'Redeem', + + 'deposit.title': 'Deposit', + 'deposit.currentBalance': 'Current Balance', + 'deposit.amount': 'Amount', + 'deposit.custom': 'Custom Amount', + 'deposit.paymentMethod': 'Payment Method', + 'deposit.submit': 'Deposit', + + 'withdraw.title': 'Withdraw', + 'withdraw.availableBalance': 'Available Balance', + 'withdraw.amount': 'Amount', + 'withdraw.all': 'All', + 'withdraw.to': 'Withdraw to', + 'withdraw.savingsAccount': 'Savings Account', + 'withdraw.fee': 'Fee (0.5%)', + 'withdraw.actualReceive': 'You\'ll Receive', + 'withdraw.estimateTime': 'Estimated 1-2 business days', + 'withdraw.submit': 'Confirm Withdrawal', + + 'txRecords.title': 'Transaction Records', + 'txRecords.all': 'All', + 'txRecords.buy': 'Buy', + 'txRecords.sell': 'Sell', + 'txRecords.transfer': 'Gift', + 'txRecords.noRecords': 'No records', + 'txRecords.orderNo': 'Order No.', + 'txRecords.transferTo': 'Gifted to', + + // ============ Profile ============ + 'profile.favorites': 'Favorites', + 'profile.orders': 'Orders', + 'profile.coupons': 'Coupons', + 'profile.wallet': 'Wallet', + 'profile.account': 'Account', + 'profile.trade': 'Trades', + 'profile.settings': 'Settings', + 'profile.holdCoupons': 'Held', + 'profile.saved': 'Saved', + 'profile.credit': 'Credit', + 'profile.creditScore': 'Credit Score', + 'profile.myTrades': 'My Trades', + 'profile.walletBalance': 'Balance', + 'profile.paymentManage': 'Payment', + 'profile.kyc': 'Verification', + 'profile.proMode': 'Pro Mode', + 'profile.myFavorites': 'My Favorites', + 'profile.securitySettings': 'Security', + 'profile.advancedSettings': 'Advanced', + 'profile.aboutGenex': 'About Genex', + 'profile.helpCenter': 'Help', + 'profile.issuerPortal': 'Issuer Portal', + 'profile.merchantPortal': 'Merchant Portal', + 'profile.simplifiedChinese': 'Simplified Chinese', + 'profile.logout': 'Log Out', + + // ============ Settings ============ + 'settings.title': 'Settings', + 'settings.accountSecurity': 'Account & Security', + 'settings.phone': 'Phone', + 'settings.email': 'Email', + 'settings.changePassword': 'Change Password', + 'settings.identity': 'Verification', + 'settings.paymentManage': 'Payment Management', + 'settings.paymentMethod': 'Payment Methods', + 'settings.bankAccount': 'Bank Account', + 'settings.paymentPassword': 'Payment Password', + 'settings.notifications': 'Notifications', + 'settings.tradeNotify': 'Trade Alerts', + 'settings.expiryRemind': 'Expiry Reminders', + 'settings.marketChange': 'Market Updates', + 'settings.marketingPush': 'Promotions', + 'settings.general': 'General', + 'settings.language': 'Language', + 'settings.currency': 'Currency', + 'settings.clearCache': 'Clear Cache', + 'settings.about': 'About', + 'settings.version': 'Version', + 'settings.userAgreement': 'Terms of Service', + 'settings.privacyPolicy': 'Privacy Policy', + 'settings.helpCenter': 'Help Center', + 'settings.logout': 'Log Out', + 'settings.selectCurrency': 'Select Currency', + 'settings.currencyNote': 'This affects currency display in all trading pages', + 'settings.selectLanguage': 'Select Language', + 'settings.currencySymbol': 'Symbol', + + // ============ KYC ============ + 'kyc.title': 'Verification', + 'kyc.currentLevel': 'Current Level', + 'kyc.l1Title': 'L1 Basic', + 'kyc.l1Desc': 'Phone + Email verification', + 'kyc.l1Limit': 'Daily limit \$500', + 'kyc.l1Feature': 'Buy coupons, redeem at stores', + 'kyc.l2Title': 'L2 Identity', + 'kyc.l2Desc': 'ID / Passport verification', + 'kyc.l2Limit': 'Daily limit \$5,000', + 'kyc.l2Feature': 'Unlock trading & P2P transfers', + 'kyc.l3Title': 'L3 Advanced', + 'kyc.l3Desc': 'Video review + Proof of address', + 'kyc.l3Limit': 'No limit', + 'kyc.l3Feature': 'Unlimited trading & withdrawals', + 'kyc.completed': 'Completed', + 'kyc.goVerify': 'Verify', + 'kyc.badgeLabel': 'Verified', + + // ============ Payment Management ============ + 'payManage.title': 'Payment Management', + 'payManage.myCards': 'My Cards', + 'payManage.addCard': 'Add New Card', + 'payManage.bankAccount': 'Bank Account (for withdrawals)', + 'payManage.paymentSecurity': 'Payment Security', + 'payManage.paymentPassword': 'Payment Password', + 'payManage.passwordSet': 'Set', + 'payManage.biometricPay': 'Biometric Payment', + 'payManage.biometricEnabled': 'Enabled', + 'payManage.noPasswordPay': 'Quick Pay', + 'payManage.noPasswordLimit': 'Up to \$10/txn', + + // ============ AI Chat ============ + 'aiChat.title': 'AI Assistant', + 'aiChat.greeting': 'Hi! I\'m Genex AI Assistant. I can help you find great deals, compare prices, and recommend combos. Try asking:', + 'aiChat.suggest1': 'Recommend coupons for me', + 'aiChat.suggest2': 'Is Starbucks coupon worth buying?', + 'aiChat.suggest3': 'Help me compare prices', + 'aiChat.suggest4': 'My coupon is expiring soon', + 'aiChat.inputHint': 'Ask me anything about coupons...', + 'aiChat.confirmAction': 'Confirm', + 'aiChat.riskLow': 'Low Risk', + 'aiChat.riskNormal': 'Confirm', + 'aiChat.riskHigh': 'High Risk', + + // ============ AI Fab ============ + 'aiFab.title': 'AI Assistant', + 'aiFab.greeting': 'Hi! I\'m Genex AI Assistant. I can help you manage coupon assets, find deals, and analyze prices. How can I help?', + 'aiFab.inputHint': 'Type a message...', + 'aiFab.suggest1': 'Find high-discount coupons', + 'aiFab.suggest2': 'Are my coupons expiring soon?', + 'aiFab.suggest3': 'Recommend today\'s best deals', + 'aiFab.suggest4': 'Analyze my coupon portfolio', + + // ============ Messages ============ + 'message.title': 'Messages', + 'message.markAllRead': 'Mark All Read', + 'message.tabTrade': 'Trades', + 'message.tabExpiry': 'Expiry', + 'message.tabAnnouncement': 'Notices', + 'message.detailTitle': 'Message Details', + 'message.tradeNotify': 'Trade Alert', + 'message.expiryRemind': 'Expiry Reminder', + 'message.systemNotify': 'System Notice', + 'message.promoNotify': 'Promotion', + 'message.tradeSuccess': 'Trade Successful', + 'message.couponName': 'Coupon', + 'message.faceValue': 'Face Value', + 'message.payAmount': 'Amount Paid', + 'message.orderNo': 'Order No.', + 'message.payMethod': 'Payment Method', + 'message.viewCouponDetail': 'View Coupon Details', + + // ============ Status Tags ============ + 'status.active': 'Active', + 'status.pending': 'Pending', + 'status.expired': 'Expired', + 'status.used': 'Used', + 'status.processing': 'Processing', + 'status.completed': 'Completed', + 'status.cancelled': 'Cancelled', + 'status.refunding': 'Refunding', + 'status.onSale': 'On Sale', + + // ============ Empty States ============ + 'empty.noCoupons': 'No Coupons Yet', + 'empty.noCouponsHint': 'Browse the market for great deals', + 'empty.browse': 'Browse', + 'empty.noTrades': 'No Trades Yet', + 'empty.noTradesHint': 'Your trade records will appear here', + 'empty.noResults': 'No Results Found', + 'empty.noResultsHint': 'Try a different keyword', + 'empty.noMessages': 'No Messages', + 'empty.noMessagesHint': 'Trade alerts and notifications will appear here', + 'empty.networkError': 'Network Error', + 'empty.networkErrorHint': 'Please check your connection and try again', + + // ============ Coupon Card (shared widget) ============ + 'couponCard.expiredText': 'Expired', + 'couponCard.expiringToday': 'Expires today', + 'couponCard.daysToExpiry': 'd left', + 'couponCard.expiryFormat': 'Expires', + + // ============ Issuer ============ + 'issuer.title': 'Issuer Portal', + 'issuer.verified': 'Verified Issuer', + 'issuer.overview': 'Overview', + 'issuer.issue': 'Issue', + 'issuer.redeem': 'Redeem', + 'issuer.finance': 'Finance', + 'issuer.more': 'More', + 'issuer.totalIssued': 'Total Issued', + 'issuer.totalSold': 'Sold', + 'issuer.totalRedeemed': 'Redeemed', + 'issuer.redeemRate': 'Redeem Rate', + 'issuer.quickActions': 'Quick Actions', + 'issuer.createCoupon': 'Create Coupon', + 'issuer.storeManage': 'Stores', + 'issuer.salesAnalysis': 'Analytics', + 'issuer.statement': 'Statements', + 'issuer.myCoupons': 'My Coupons', + 'issuer.listed': 'Listed', + 'issuer.underReview': 'Under Review', + 'issuer.soldOut': 'Sold Out', + 'issuer.unlisted': 'Unlisted', + 'issuer.issuedSlash': 'Issued', + 'issuer.sold': 'Sold', + 'issuer.issueCenter': 'Issue Center', + 'issuer.selectTemplate': 'Select Template', + 'issuer.voucherType': 'Voucher', + 'issuer.discountType': 'Discount', + 'issuer.giftCardType': 'Gift Card', + 'issuer.storedValueType': 'Stored Value', + 'issuer.couponManage': 'Manage', + 'issuer.viewAll': 'View All', + 'issuer.couponEvents': 'Events', + 'issuer.createNew': 'Create New', + 'issuer.redeemManage': 'Redemption', + 'issuer.redeemTrend': 'Redemption Trends', + 'issuer.allStores': 'All Stores', + 'issuer.employees': ' staff', + 'issuer.financeManage': 'Finance', + 'issuer.totalSales': 'Total Sales', + 'issuer.settled': 'Settled', + 'issuer.pendingSettle': 'Pending', + 'issuer.breakage': 'Breakage', + 'issuer.withdrawBtn': 'Withdraw', + 'issuer.reportBtn': 'Reports', + 'issuer.settleDetail': 'Settlement Details', + 'issuer.creditLevel': 'Credit Rating', + 'issuer.issueQuota': 'Issue Quota', + 'issuer.usedQuota': 'Used Quota', + 'issuer.dataCenter': 'Data Center', + 'issuer.issueSalesRate': 'Issue/Sales/Redeem Rate', + 'issuer.userProfile': 'User Insights', + 'issuer.userProfileDesc': 'Buyer demographics', + 'issuer.creditDetail': 'Credit Details', + 'issuer.creditDetailDesc': 'Score and improvement tips', + 'issuer.quotaChange': 'Quota Changes', + 'issuer.quotaChangeDesc': 'Historical quota adjustments', + 'issuer.companyInfo': 'Company Info', + 'issuer.companyInfoDesc': 'License / Contacts', + 'issuer.settingsItem': 'Settings', + 'issuer.settingsItemDesc': 'Notifications / Security', + 'issuer.helpItem': 'Help Center', + 'issuer.helpItemDesc': 'FAQ & Support', + + // ============ Merchant ============ + 'merchant.today': 'Today', + 'merchant.onlineMode': 'Online Mode', + 'merchant.offlineMode': 'Offline Mode', + 'merchant.pendingSync': 'Pending Sync', + 'merchant.syncUnit': ' txns', + 'merchant.scanHint': 'Align coupon QR code in the frame', + 'merchant.flashlight': 'Flashlight', + 'merchant.manualInput': 'Manual Entry', + 'merchant.redeemRecords': 'Records', + 'merchant.storeData': 'Store Data', + 'merchant.inputCode': 'Enter Coupon Code', + 'merchant.inputCodeHint': 'Enter code', + 'merchant.query': 'Look Up', + 'merchant.userNickname': 'User', + 'merchant.consumer': 'Consumer', + 'merchant.couponName': 'Coupon', + 'merchant.faceValue': 'Value', + 'merchant.validUntil': 'Valid Until', + 'merchant.useCondition': 'Conditions', + 'merchant.noMinSpend': 'No minimum spend', + 'merchant.confirmRedeem': 'Confirm Redemption', + 'merchant.redeemSuccess': 'Redeemed', + 'merchant.continueRedeem': 'Continue', + 'merchant.synced': 'Synced', + 'merchant.pendingSyncLabel': 'Pending', + 'merchant.redeemOperator': 'Operator', + 'merchant.todayRedeem': 'Today', + 'merchant.redeemAmount': 'Amount', + 'merchant.weekTrend': 'Weekly Trend', + 'merchant.operatorRank': 'Operator Ranking', + + // ============ Merchant AI ============ + 'merchantAi.title': 'AI Smart Assistant', + 'merchantAi.redeemAssist': 'Redeem Assist', + 'merchantAi.trafficForecast': 'Traffic Forecast', + 'merchantAi.anomalyAlert': 'Anomaly Alerts', + 'merchantAi.verifyAuth': 'Verify Coupon', + 'merchantAi.checkStatus': 'Check Status', + 'merchantAi.batchRedeem': 'Batch Redeem', + 'merchantAi.feedback': 'Feedback', + 'merchantAi.quickActions': 'AI Quick Actions', + 'merchantAi.redeemTips': 'Redemption Tips', + 'merchantAi.todayHotRedeem': 'Today\'s Top Redemptions', + 'merchantAi.countUnit': ' txns', + 'merchantAi.aiMarketing': 'AI Marketing Suggestions', + 'merchantAi.crossSellTitle': 'Cross-sell Recommendation', + 'merchantAi.crossSellDesc': 'Customers buying coffee coupons also show interest in bakery coupons. Consider offering combos.', + 'merchantAi.weekendPromoTitle': 'Weekend Promo Suggestion', + 'merchantAi.weekendPromoDesc': 'Historical data shows +30% redemptions on Saturdays. Consider launching a weekend flash deal.', + 'merchantAi.todayForecast': 'Today\'s Traffic Forecast', + 'merchantAi.expectedRedeem': 'Expected Redemptions', + 'merchantAi.peakHours': 'Peak Hours', + 'merchantAi.expectedRevenue': 'Expected Revenue', + 'merchantAi.trafficInsight': '+12% vs. last week. Consider adding 1 more cashier during lunch.', + 'merchantAi.hourlyForecast': 'Hourly Forecast', + 'merchantAi.weeklyForecast': 'Weekly Forecast', + 'merchantAi.staffSuggestion': 'Staff Scheduling', + 'merchantAi.pendingCount': 'Pending', + 'merchantAi.resolvedToday': 'Resolved Today', + 'merchantAi.riskIndex': 'Risk Index', + 'merchantAi.riskLow': 'Low', + 'merchantAi.activeAlerts': 'Active Alerts', + 'merchantAi.highFreqRedeem': 'High-frequency Redemption', + 'merchantAi.suspectFakeCode': 'Suspected Fake Code', + 'merchantAi.suspiciousPatterns': 'Suspicious Patterns', + 'merchantAi.consecutiveRedeem': 'Consecutive Redemptions by Same User', + 'merchantAi.offHoursRedeem': 'Off-hours Redemption Attempts', + 'merchantAi.expiredRedeemAttempt': 'Expired Coupon Redemption Attempts', + 'merchantAi.statusAbnormal': 'Abnormal', + 'merchantAi.statusWarning': 'Warning', + 'merchantAi.statusNormal': 'Normal', + 'merchantAi.expiredBlock': 'Expired Coupon Blocked', + 'merchantAi.duplicateBlock': 'Duplicate Redemption Blocked', + 'merchantAi.wrongStoreAlert': 'Wrong Store Alert', + 'merchantAi.insufficientBalance': 'Insufficient Balance', + 'merchantAi.systemRetry': 'System Timeout Retry', + 'merchantAi.monday': 'Mon', + 'merchantAi.tuesday': 'Tue', + 'merchantAi.wednesday': 'Wed', + 'merchantAi.thursday': 'Thu', + 'merchantAi.friday': 'Fri', + 'merchantAi.saturday': 'Sat', + 'merchantAi.sunday': 'Sun', + + // ============ Pro Mode ============ + 'proMode.title': 'Pro Mode', + 'proMode.toggleDesc': 'View on-chain info and connect external wallets', + 'proMode.requireKycL2': 'Requires KYC L2 or above', + 'proMode.connected': 'Connected', + 'proMode.disconnect': 'Disconnect', + 'proMode.connectWallet': 'Connect External Wallet', + 'proMode.walletDesc': 'After connecting, you can withdraw platform assets to your own address', + 'proMode.showChainAddress': 'Show Chain Address', + 'proMode.showChainAddressDesc': 'Display contract address in coupon details', + 'proMode.showTxHash': 'Show Tx Hash', + 'proMode.showTxHashDesc': 'Display on-chain hash in transaction records', + 'proMode.txExplorer': 'Transaction Explorer', + 'proMode.txBuyExample': 'Buy Starbucks \$25 Gift Card', + 'proMode.txSellExample': 'Sell Amazon \$100 Coupon', + 'proMode.confirmed': 'Confirmed', + 'proMode.confirming': 'Confirming', + 'proMode.viewAllTx': 'View All On-Chain Transactions', + 'proMode.chainAssets': 'On-Chain Assets', + 'proMode.custodialWallet': 'Custodial Wallet', + 'proMode.externalWallet': 'External Wallet (MetaMask)', + 'proMode.couponCount5': '5 coupons', + 'proMode.couponCount0': '0 coupons', + 'proMode.extractToWallet': 'Extract to External Wallet', + 'proMode.tradeTrack': 'Trading Track', + 'proMode.utilityTrackDesc': 'Coupon validity \u226412 months, no securities license needed', + 'proMode.securitiesTrackDesc': 'Long-term investment coupons (coming soon)', + 'proMode.mvpNote': 'Current MVP only supports Utility Track', + 'proMode.comingSoon': 'Coming Soon', + 'proMode.whatIsTitle': 'What is Pro Mode?', + 'proMode.whatIsDesc': 'Pro Mode is for users with blockchain experience. After enabling, you can:\n' + '\u2022 Connect external wallets (MetaMask, etc.)\n' + '\u2022 View on-chain addresses and transaction hashes\n' + '\u2022 Extract assets to your own wallet\n' + '\u2022 View underlying on-chain data\n\n' + 'KYC L2 verification is required to enable.', + + // ============ Receive Coupon ============ + 'receiveCoupon.title': 'Receive Coupon', + 'receiveCoupon.hint': 'Show the QR code or ID below to the sender. They can scan or enter the ID to transfer a coupon to you.', + 'receiveCoupon.id': 'Receive ID', + 'receiveCoupon.idCopied': 'Receive ID copied to clipboard', + 'receiveCoupon.note': 'Received coupons will be automatically added to your holdings.', +}; diff --git a/frontend/mobile/lib/app/i18n/strings/ja.dart b/frontend/mobile/lib/app/i18n/strings/ja.dart new file mode 100644 index 0000000..5ac065e --- /dev/null +++ b/frontend/mobile/lib/app/i18n/strings/ja.dart @@ -0,0 +1,686 @@ +const Map ja = { + // ============ Common ============ + 'common.confirm': '確認', + 'common.cancel': 'キャンセル', + 'common.save': '保存', + 'common.delete': '削除', + 'common.edit': '編集', + 'common.search': '検索', + 'common.loading': '読み込み中...', + 'common.retry': '再試行', + 'common.done': '完了', + 'common.next': '次へ', + 'common.back': '戻る', + 'common.close': '閉じる', + 'common.more': 'もっと見る', + 'common.all': 'すべて', + 'common.filter': 'フィルター', + 'common.sort': '並び替え', + 'common.copy': 'コピー', + 'common.copied': 'クリップボードにコピーしました', + 'common.today': '今日', + 'common.thisWeek': '今週', + 'common.thisMonth': '今月', + + // ============ Navigation ============ + 'nav.home': 'ホーム', + 'nav.market': 'マーケット', + 'nav.myCoupons': 'マイクーポン', + 'nav.messages': 'メッセージ', + 'nav.profile': 'マイページ', + + // ============ Welcome / Auth ============ + 'welcome.slogan': 'すべてのクーポンに価値を', + 'welcome.phoneRegister': '電話番号で登録', + 'welcome.emailRegister': 'メールで登録', + 'welcome.otherLogin': '他の方法でログイン', + 'welcome.hasAccount': 'アカウントをお持ちですか?', + 'welcome.login': 'ログイン', + 'welcome.agreement': '登録することで「利用規約」と「プライバシーポリシー」に同意したものとみなされます', + + 'login.title': 'おかえりなさい', + 'login.subtitle': 'Genex にログインしてクーポン資産を管理', + 'login.passwordTab': 'パスワードでログイン', + 'login.codeTab': '認証コードでログイン', + 'login.phoneOrEmail': '電話番号またはメール', + 'login.password': 'パスワード', + 'login.forgotPassword': 'パスワードを忘れた場合', + 'login.submit': 'ログイン', + 'login.phone': '電話番号', + 'login.verifyCode': '認証コード', + 'login.getCode': '認証コードを取得', + + 'register.title': 'アカウント作成', + 'register.emailSubtitle': 'メールアドレスで Genex アカウントを登録', + 'register.phoneSubtitle': '電話番号で Genex アカウントを登録', + 'register.email': 'メールアドレス', + 'register.phone': '電話番号', + 'register.emailHint': 'メールアドレスを入力', + 'register.phoneHint': '電話番号を入力', + 'register.code': '認証コード', + 'register.codeHint': '6桁の認証コードを入力', + 'register.getCode': '認証コードを取得', + 'register.setPassword': 'パスワードを設定', + 'register.passwordHint': '8〜20文字、英字と数字を含む', + 'register.agreement': '以下に同意します', + 'register.userAgreement': '「利用規約」', + 'register.privacyPolicy': '「プライバシーポリシー」', + 'register.submit': '登録', + 'register.stepVerify': '認証', + 'register.stepPassword': 'パスワード設定', + 'register.stepDone': '完了', + 'register.rule8chars': '8文字以上', + 'register.ruleLetter': '英字を含む', + 'register.ruleNumber': '数字を含む', + + 'forgot.title': 'パスワード再設定', + 'forgot.inputAccount': '電話番号またはメールを入力', + 'forgot.sendHint': '認証コードをお送りします', + 'forgot.accountHint': '電話番号 / メールアドレス', + 'forgot.getCode': '認証コードを取得', + 'forgot.inputCode': '認証コードを入力', + 'forgot.codeSentTo': '認証コードの送信先', + 'forgot.codeHint': '6桁の認証コード', + 'forgot.resend': '再送信', + 'forgot.next': '次へ', + 'forgot.setNewPassword': '新しいパスワードを設定', + 'forgot.newPasswordHint': '新しいパスワードを入力(8文字以上)', + 'forgot.newPassword': '新しいパスワード', + 'forgot.confirmPassword': '新しいパスワードを確認', + 'forgot.confirmChange': '変更を確認', + 'forgot.success': 'パスワードの変更が完了しました', + 'forgot.successHint': '新しいパスワードでログインしてください', + 'forgot.backToLogin': 'ログインに戻る', + + // ============ Home ============ + 'home.searchHint': 'クーポン、ブランド、カテゴリを検索...', + 'home.dining': 'グルメ', + 'home.shopping': 'ショッピング', + 'home.entertainment': 'エンタメ', + 'home.travel': 'トラベル', + 'home.lifestyle': 'ライフスタイル', + 'home.brand': 'ブランド', + 'home.discount': 'セール', + 'home.allCategories': 'すべて', + 'home.featuredCoupons': '厳選クーポン', + 'home.viewAllCoupons': 'すべて見る', + 'home.aiRecommend': 'AI おすすめ', + 'home.aiRecommendDesc': 'あなたの好みに基づき、コスパの高いクーポンを3枚発見しました', + 'home.bannerNewUser': '新規ユーザー特典', + 'home.bannerNewUserDesc': '初回注文 \$10 割引', + 'home.bannerDiscount': 'タイムセール', + 'home.bannerDiscountDesc': '全品最大30%オフ', + 'home.bannerHot': '人気おすすめ', + 'home.bannerHotDesc': '厳選割引クーポン', + + // ============ Market ============ + 'market.title': 'マーケットプレイス', + 'market.primary': 'プライマリー市場(新品)', + 'market.secondary': 'セカンダリー市場(リセール)', + 'market.dining': 'グルメ', + 'market.shopping': 'ショッピング', + 'market.entertainment': 'エンタメ', + 'market.travel': 'トラベル', + 'market.lifestyle': 'ライフスタイル', + 'market.sports': 'スポーツ', + 'market.discountRate': '割引率', + 'market.priceUp': '価格↑', + 'market.priceDown': '価格↓', + 'market.expiryDate': '有効期限', + 'market.issuePrice': '発行価格', + 'market.faceValue': '額面', + 'market.discount': '割引', + 'market.totalSupply': '発行数量', + 'market.salesProgress': '販売進捗', + 'market.upcoming': '開始予定', + 'market.subscribing': '申込受付中', + 'market.ended': '終了', + 'market.timeToStart': '開始まで', + 'market.couponBrand': 'クーポン名/ブランド', + 'market.latestPrice': '最新価格', + 'market.change24h': '24h騰落', + 'market.discountSuffix': '引', + + // ============ My Coupons ============ + 'myCoupons.title': 'マイクーポン', + 'myCoupons.usable': '利用可能', + 'myCoupons.pendingRedeem': '利用待ち', + 'myCoupons.expired': '期限切れ', + 'myCoupons.faceValue': '額面', + 'myCoupons.transfer': '譲渡', + 'myCoupons.sell': '売却', + 'myCoupons.expiredText': '期限切れ', + 'myCoupons.expiringToday': '本日期限', + 'myCoupons.daysToExpiry': '日後に期限切れ', + + // ============ Coupon Detail ============ + 'couponDetail.title': 'クーポン詳細', + 'couponDetail.favorite': 'お気に入り', + 'couponDetail.buyNow': '今すぐ購入', + 'couponDetail.saveBadge': '額面よりお得', + 'couponDetail.faceValue': '額面', + 'couponDetail.validUntil': '有効期限', + 'couponDetail.type': 'タイプ', + 'couponDetail.issuer': '発行元', + 'couponDetail.consumeCoupon': '消費クーポン', + 'couponDetail.usageNote': '利用案内', + 'couponDetail.allStores': '全国の店舗で利用可能', + 'couponDetail.canTransfer': '友達に譲渡可能', + 'couponDetail.useAnytime': '有効期間内いつでも利用可能', + 'couponDetail.noStack': '併用不可', + 'couponDetail.noCash': '現金との交換不可', + 'couponDetail.stores': '利用可能店舗', + 'couponDetail.storeCount': '全国 12,800+ 店舗', + 'couponDetail.storeDesc': '全国のすべての直営店舗で利用可能', + 'couponDetail.priceTrend': '価格推移', + 'couponDetail.last30Days': '過去30日間', + 'couponDetail.highest': '最高値', + 'couponDetail.lowest': '最安値', + 'couponDetail.average': '平均価格', + 'couponDetail.tradeHistory': '取引履歴', + 'couponDetail.nearbyStores': '近くの利用可能店舗', + 'couponDetail.distance': '距離', + 'couponDetail.open': '営業中', + 'couponDetail.similar': '類似クーポン', + + // ============ My Coupon Detail ============ + 'myCoupon.title': 'クーポン詳細', + 'myCoupon.active': '利用可能', + 'myCoupon.showQrHint': 'このQRコードを店舗スタッフに提示してスキャンしてもらってください', + 'myCoupon.switchBarcode': 'バーコードに切替', + 'myCoupon.faceValue': '額面', + 'myCoupon.purchasePrice': '購入価格', + 'myCoupon.validUntil': '有効期限', + 'myCoupon.orderNo': '注文番号', + 'myCoupon.resellCount': '残り転売回数', + 'myCoupon.transfer': '譲渡', + 'myCoupon.sell': '売却', + 'myCoupon.usageNote': '利用案内', + 'myCoupon.useInStore': '全国の店舗で利用可能', + 'myCoupon.useInTime': '有効期限内にご利用ください', + 'myCoupon.onePerVisit': '1回のお会計につき1枚のみ利用可能', + 'myCoupon.noCash': '現金との交換不可', + 'myCoupon.extractToWallet': '外部ウォレットに引き出す', + 'myCoupon.requireKycL2': 'KYC L2以上の認証が必要', + 'myCoupon.viewTrades': '取引履歴を見る', + 'myCoupon.help': '利用ヘルプ', + + // ============ Order Confirm ============ + 'orderConfirm.title': '注文確認', + 'orderConfirm.quantity': '購入数量', + 'orderConfirm.paymentMethod': '支払い方法', + 'orderConfirm.bankCard': '銀行カード/クレジットカード', + 'orderConfirm.priceDetail': '価格明細', + 'orderConfirm.buyingNote': '消費用クーポンを購入します', + 'orderConfirm.total': '合計', + 'orderConfirm.confirmPay': '支払いを確認', + 'orderConfirm.unitPrice': '単価', + 'orderConfirm.count': '数量', + 'orderConfirm.saveBadge': '額面よりお得', + 'orderConfirm.biometricHint': '支払いを完了するには指紋または顔認証を行ってください', + 'orderConfirm.usePasswordPay': 'パスワードで支払う', + + // ============ Payment ============ + 'payment.title': '支払い方法を選択', + 'payment.addNew': '新しい支払い方法を追加', + 'payment.confirmPay': '支払いを確認', + 'payment.bankTransfer': '銀行振込', + + 'paymentSuccess.title': '支払い完了', + 'paymentSuccess.hint': 'クーポンが届きました。「マイクーポン」で確認できます', + 'paymentSuccess.couponName': 'クーポン名', + 'paymentSuccess.payAmount': '支払い金額', + 'paymentSuccess.orderNo': '注文番号', + 'paymentSuccess.payTime': '支払い日時', + 'paymentSuccess.viewMyCoupon': 'マイクーポンを見る', + 'paymentSuccess.continueBrowse': '買い物を続ける', + + // ============ Search ============ + 'search.hint': 'クーポン、ブランド、カテゴリを検索...', + 'search.cancel': 'キャンセル', + 'search.hotSearch': '人気の検索', + 'search.history': '検索履歴', + 'search.clear': 'クリア', + 'search.diningCoupon': 'グルメクーポン', + 'search.discountCoupon': '割引クーポン', + 'search.travel': '旅行', + + // ============ Redeem ============ + 'redeem.title': 'クーポンコードを提示', + 'redeem.faceValue': '額面', + 'redeem.validTime': '有効期間', + 'redeem.refresh': 'コードを更新', + 'redeem.showHint': 'このコードを店舗スタッフに提示してスキャンしてもらってください。画面の明るさは自動的に最大に調整されました', + + // ============ Sell Order ============ + 'sellOrder.title': '売り注文を出す', + 'sellOrder.faceValue': '額面', + 'sellOrder.credit': '信用', + 'sellOrder.setPrice': '販売価格を設定', + 'sellOrder.price': '販売価格', + 'sellOrder.aiSuggest': 'AI推奨価格', + 'sellOrder.bestDealRate': 'この価格が最も成約率が高いです', + 'sellOrder.discountRate': '割引率', + 'sellOrder.platformFee': 'プラットフォーム手数料 (1.5%)', + 'sellOrder.estimatedReceive': '受取見込額', + 'sellOrder.marketAvg': '現在の市場平均価格', + 'sellOrder.recent24hTrades': '直近24時間の取引', + 'sellOrder.tradesUnit': '件', + 'sellOrder.confirmList': '出品を確認', + 'sellOrder.success': '出品完了', + 'sellOrder.successHint': 'クーポンが市場に出品されました。買い手が注文すると自動的に成約します。', + 'sellOrder.ok': 'OK', + + // ============ Trading Page ============ + 'tradingPage.title': 'マイ取引', + 'tradingPage.pendingOrders': '出品中の注文', + 'tradingPage.tradeRecords': '取引履歴', + 'tradingPage.listPrice': '出品価格', + 'tradingPage.listTime': '出品日時', + 'tradingPage.cancelOrder': '注文取消', + 'tradingPage.buy': '購入', + 'tradingPage.sell': '売却', + + // ============ Transfer ============ + 'transfer.title': '友達に譲渡', + 'transfer.searchFriend': '友達を検索(電話番号/ユーザー名)', + 'transfer.confirmTransfer': '譲渡を確認', + 'transfer.success': '譲渡完了', + 'transfer.confirm': 'OK', + 'transfer.cancel': 'キャンセル', + + // ============ Wallet ============ + 'wallet.myBalance': '残高', + 'wallet.totalBalance': '合計残高', + 'wallet.withdrawable': '出金可能', + 'wallet.frozen': '凍結中', + 'wallet.deposit': '入金', + 'wallet.withdraw': '出金', + 'wallet.records': '取引履歴', + 'wallet.filter': 'フィルター', + 'wallet.buyIn': '購入', + 'wallet.sellOut': '売却', + 'wallet.giftTransfer': '譲渡', + 'wallet.redeemUse': '利用', + + 'deposit.title': '入金', + 'deposit.currentBalance': '現在の残高', + 'deposit.amount': '入金額', + 'deposit.custom': 'カスタム金額', + 'deposit.paymentMethod': '支払い方法', + 'deposit.submit': '入金', + + 'withdraw.title': '出金', + 'withdraw.availableBalance': '出金可能残高', + 'withdraw.amount': '出金額', + 'withdraw.all': '全額', + 'withdraw.to': '出金先', + 'withdraw.savingsAccount': '普通預金口座', + 'withdraw.fee': '手数料 (0.5%)', + 'withdraw.actualReceive': '実際の受取額', + 'withdraw.estimateTime': '1〜2営業日で入金予定', + 'withdraw.submit': '出金を確認', + + 'txRecords.title': '取引履歴', + 'txRecords.all': 'すべて', + 'txRecords.buy': '購入', + 'txRecords.sell': '売却', + 'txRecords.transfer': '譲渡', + 'txRecords.noRecords': '記録がありません', + 'txRecords.orderNo': '注文番号', + 'txRecords.transferTo': '譲渡先', + + // ============ Profile ============ + 'profile.favorites': 'お気に入り', + 'profile.orders': '注文', + 'profile.coupons': 'クーポン', + 'profile.wallet': 'ウォレット', + 'profile.account': 'アカウント', + 'profile.trade': '取引', + 'profile.settings': '設定', + 'profile.holdCoupons': '保有', + 'profile.saved': '節約', + 'profile.credit': '信用', + 'profile.creditScore': '信用スコア', + 'profile.myTrades': 'マイ取引', + 'profile.walletBalance': 'ウォレット残高', + 'profile.paymentManage': '支払い管理', + 'profile.kyc': '本人確認', + 'profile.proMode': 'プロモード', + 'profile.myFavorites': 'お気に入り', + 'profile.securitySettings': 'セキュリティ設定', + 'profile.advancedSettings': '詳細設定', + 'profile.aboutGenex': 'Genex について', + 'profile.helpCenter': 'ヘルプセンター', + 'profile.issuerPortal': '発行者ポータル', + 'profile.merchantPortal': '加盟店ポータル', + 'profile.simplifiedChinese': '簡体中国語', + 'profile.logout': 'ログアウト', + + // ============ Settings ============ + 'settings.title': '設定', + 'settings.accountSecurity': 'アカウントとセキュリティ', + 'settings.phone': '電話番号', + 'settings.email': 'メール', + 'settings.changePassword': 'パスワード変更', + 'settings.identity': '本人確認', + 'settings.paymentManage': '支払い管理', + 'settings.paymentMethod': '支払い方法', + 'settings.bankAccount': '銀行口座', + 'settings.paymentPassword': '支払いパスワード', + 'settings.notifications': '通知設定', + 'settings.tradeNotify': '取引通知', + 'settings.expiryRemind': '期限切れリマインダー', + 'settings.marketChange': '相場変動', + 'settings.marketingPush': 'プロモーション通知', + 'settings.general': '一般', + 'settings.language': '言語', + 'settings.currency': '通貨', + 'settings.clearCache': 'キャッシュをクリア', + 'settings.about': 'アプリについて', + 'settings.version': 'バージョン', + 'settings.userAgreement': '利用規約', + 'settings.privacyPolicy': 'プライバシーポリシー', + 'settings.helpCenter': 'ヘルプセンター', + 'settings.logout': 'ログアウト', + 'settings.selectCurrency': '表示通貨を選択', + 'settings.currencyNote': 'この設定は取引ページの価格表示通貨に影響します', + 'settings.selectLanguage': '言語を選択', + 'settings.currencySymbol': '記号', + + // ============ KYC ============ + 'kyc.title': '本人確認', + 'kyc.currentLevel': '現在の認証レベル', + 'kyc.l1Title': 'L1 基本認証', + 'kyc.l1Desc': '電話番号 + メール認証', + 'kyc.l1Limit': '1日の購入上限 \$500', + 'kyc.l1Feature': 'クーポンの購入・利用が可能', + 'kyc.l2Title': 'L2 本人認証', + 'kyc.l2Desc': '身分証/パスポート認証', + 'kyc.l2Limit': '1日の購入上限 \$5,000', + 'kyc.l2Feature': 'セカンダリー市場取引・P2P譲渡を解放', + 'kyc.l3Title': 'L3 上級認証', + 'kyc.l3Desc': 'ビデオ面談 + 住所証明', + 'kyc.l3Limit': '上限なし', + 'kyc.l3Feature': '大口取引・出金制限なし', + 'kyc.completed': '完了', + 'kyc.goVerify': '認証する', + 'kyc.badgeLabel': '認証済', + + // ============ Payment Management ============ + 'payManage.title': '支払い管理', + 'payManage.myCards': '登録カード', + 'payManage.addCard': '新しいカードを追加', + 'payManage.bankAccount': '銀行口座(出金用)', + 'payManage.paymentSecurity': '支払いセキュリティ', + 'payManage.paymentPassword': '支払いパスワード', + 'payManage.passwordSet': '設定済み', + 'payManage.biometricPay': '指紋/顔認証支払い', + 'payManage.biometricEnabled': '有効', + 'payManage.noPasswordPay': 'パスワード不要の支払い', + 'payManage.noPasswordLimit': '1回あたり\$10以下', + + // ============ AI Chat ============ + 'aiChat.title': 'AI アシスタント', + 'aiChat.greeting': 'こんにちは!Genex AI アシスタントです。お得なクーポンの発見、価格比較、おすすめの組み合わせをお手伝いします。こんな質問をどうぞ:', + 'aiChat.suggest1': 'おすすめのクーポンを教えて', + 'aiChat.suggest2': 'Starbucksのクーポンは買い得?', + 'aiChat.suggest3': '価格比較をして', + 'aiChat.suggest4': 'クーポンがもうすぐ期限切れ、どうすればいい?', + 'aiChat.inputHint': 'クーポンについて何でも聞いてください...', + 'aiChat.confirmAction': '実行を確認', + 'aiChat.riskLow': '低リスク', + 'aiChat.riskNormal': '要確認', + 'aiChat.riskHigh': '高リスク', + + // ============ AI Fab ============ + 'aiFab.title': 'AI アシスタント', + 'aiFab.greeting': 'こんにちは!Genex AI アシスタントです。クーポン資産の管理、お得情報の検索、価格分析をお手伝いします。何かお手伝いできることはありますか?', + 'aiFab.inputHint': 'メッセージを入力...', + 'aiFab.suggest1': '割引率の高いクーポンを探して', + 'aiFab.suggest2': '期限切れ間近のクーポンはある?', + 'aiFab.suggest3': '今日のおすすめクーポンは?', + 'aiFab.suggest4': 'クーポン資産を分析して', + + // ============ Messages ============ + 'message.title': 'メッセージ', + 'message.markAllRead': 'すべて既読', + 'message.tabTrade': '取引', + 'message.tabExpiry': '期限', + 'message.tabAnnouncement': 'お知らせ', + 'message.detailTitle': 'メッセージ詳細', + 'message.tradeNotify': '取引通知', + 'message.expiryRemind': '期限切れリマインダー', + 'message.systemNotify': 'システム通知', + 'message.promoNotify': 'キャンペーン情報', + 'message.tradeSuccess': '取引完了通知', + 'message.couponName': 'クーポン名', + 'message.faceValue': '額面', + 'message.payAmount': '支払い金額', + 'message.orderNo': '注文番号', + 'message.payMethod': '支払い方法', + 'message.viewCouponDetail': 'クーポン詳細を見る', + + // ============ Status Tags ============ + 'status.active': '利用可能', + 'status.pending': '利用待ち', + 'status.expired': '期限切れ', + 'status.used': '使用済み', + 'status.processing': '処理中', + 'status.completed': '完了', + 'status.cancelled': 'キャンセル済み', + 'status.refunding': '返金処理中', + 'status.onSale': '出品中', + + // ============ Empty States ============ + 'empty.noCoupons': 'クーポンがありません', + 'empty.noCouponsHint': 'マーケットでお得なクーポンを探してみましょう', + 'empty.browse': '見てみる', + 'empty.noTrades': '取引履歴がありません', + 'empty.noTradesHint': '最初の取引を完了するとここに表示されます', + 'empty.noResults': '結果が見つかりません', + 'empty.noResultsHint': '別のキーワードで試してみてください', + 'empty.noMessages': 'メッセージはありません', + 'empty.noMessagesHint': '取引通知やシステムのお知らせがここに表示されます', + 'empty.networkError': 'ネットワーク接続に失敗しました', + 'empty.networkErrorHint': 'ネットワーク設定を確認してから再試行してください', + + // ============ Coupon Card (shared widget) ============ + 'couponCard.expiredText': '期限切れ', + 'couponCard.expiringToday': '本日期限', + 'couponCard.daysToExpiry': '日後に期限切れ', + 'couponCard.expiryFormat': '期限', + + // ============ Issuer ============ + 'issuer.title': '発行者管理', + 'issuer.verified': '認証済み発行者', + 'issuer.overview': '概要', + 'issuer.issue': '発行', + 'issuer.redeem': '利用処理', + 'issuer.finance': '財務', + 'issuer.more': 'もっと見る', + 'issuer.totalIssued': '総発行数', + 'issuer.totalSold': '販売済み', + 'issuer.totalRedeemed': '利用処理済み', + 'issuer.redeemRate': '利用率', + 'issuer.quickActions': 'クイック操作', + 'issuer.createCoupon': 'クーポン作成', + 'issuer.storeManage': '店舗管理', + 'issuer.salesAnalysis': '売上分析', + 'issuer.statement': '精算書', + 'issuer.myCoupons': 'マイクーポン', + 'issuer.listed': '掲載中', + 'issuer.underReview': '審査中', + 'issuer.soldOut': '完売', + 'issuer.unlisted': '非掲載', + 'issuer.issuedSlash': '発行', + 'issuer.sold': '販売済み', + 'issuer.issueCenter': '発行センター', + 'issuer.selectTemplate': 'クーポンテンプレートを選択', + 'issuer.voucherType': '割引券', + 'issuer.discountType': '値引きクーポン', + 'issuer.giftCardType': 'ギフトカード', + 'issuer.storedValueType': 'プリペイドクーポン', + 'issuer.couponManage': 'クーポン管理', + 'issuer.viewAll': 'すべて見る', + 'issuer.couponEvents': 'クーポンイベント', + 'issuer.createNew': '新規クーポン作成', + 'issuer.redeemManage': '利用処理管理', + 'issuer.redeemTrend': '利用処理トレンド', + 'issuer.allStores': '全店舗', + 'issuer.employees': '名のスタッフ', + 'issuer.financeManage': '財務管理', + 'issuer.totalSales': '総売上額', + 'issuer.settled': '入金済み', + 'issuer.pendingSettle': '精算待ち', + 'issuer.breakage': 'Breakage', + 'issuer.withdrawBtn': '出金', + 'issuer.reportBtn': '精算レポート', + 'issuer.settleDetail': '精算明細', + 'issuer.creditLevel': '信用等級', + 'issuer.issueQuota': '発行枠', + 'issuer.usedQuota': '使用済み枠', + 'issuer.dataCenter': 'データセンター', + 'issuer.issueSalesRate': '発行数/販売数/利用率', + 'issuer.userProfile': 'ユーザープロフィール', + 'issuer.userProfileDesc': '購入ユーザーの分布分析', + 'issuer.creditDetail': '信用詳細', + 'issuer.creditDetailDesc': 'スコア詳細と改善提案', + 'issuer.quotaChange': '枠の変動', + 'issuer.quotaChangeDesc': '過去の枠調整履歴', + 'issuer.companyInfo': '企業情報', + 'issuer.companyInfoDesc': '営業許可証/担当者', + 'issuer.settingsItem': '設定', + 'issuer.settingsItemDesc': '通知/セキュリティ/言語', + 'issuer.helpItem': 'ヘルプセンター', + 'issuer.helpItemDesc': 'よくある質問とサポート', + + // ============ Merchant ============ + 'merchant.today': '今日', + 'merchant.onlineMode': 'オンラインモード', + 'merchant.offlineMode': 'オフラインモード', + 'merchant.pendingSync': '同期待ち', + 'merchant.syncUnit': '件', + 'merchant.scanHint': 'クーポンのQRコードをスキャン枠に合わせてください', + 'merchant.flashlight': 'ライト', + 'merchant.manualInput': '手動入力', + 'merchant.redeemRecords': '利用処理履歴', + 'merchant.storeData': '店舗データ', + 'merchant.inputCode': 'クーポンコードを手動入力', + 'merchant.inputCodeHint': 'クーポンコードを入力', + 'merchant.query': '照会', + 'merchant.userNickname': 'ユーザー名', + 'merchant.consumer': '消費者', + 'merchant.couponName': 'クーポン名', + 'merchant.faceValue': '額面', + 'merchant.validUntil': '有効期限', + 'merchant.useCondition': '利用条件', + 'merchant.noMinSpend': '最低利用金額なし', + 'merchant.confirmRedeem': '利用処理を確認', + 'merchant.redeemSuccess': '利用処理完了', + 'merchant.continueRedeem': '続けて処理', + 'merchant.synced': '同期済み', + 'merchant.pendingSyncLabel': '同期待ち', + 'merchant.redeemOperator': '処理担当者', + 'merchant.todayRedeem': '本日の利用処理', + 'merchant.redeemAmount': '利用処理金額', + 'merchant.weekTrend': '今週のトレンド', + 'merchant.operatorRank': '担当者ランキング', + + // ============ Merchant AI ============ + 'merchantAi.title': 'AI スマートアシスタント', + 'merchantAi.redeemAssist': '利用処理アシスト', + 'merchantAi.trafficForecast': '客数予測', + 'merchantAi.anomalyAlert': '異常アラート', + 'merchantAi.verifyAuth': 'クーポン検証', + 'merchantAi.checkStatus': 'ステータス確認', + 'merchantAi.batchRedeem': '一括処理', + 'merchantAi.feedback': 'フィードバック', + 'merchantAi.quickActions': 'AI クイック操作', + 'merchantAi.redeemTips': '利用処理のヒント', + 'merchantAi.todayHotRedeem': '本日の人気利用処理', + 'merchantAi.countUnit': '件', + 'merchantAi.aiMarketing': 'AI マーケティング提案', + 'merchantAi.crossSellTitle': 'クロスセル提案', + 'merchantAi.crossSellDesc': 'コーヒークーポン購入者はベーカリークーポンにも関心があります。セット販売をお勧めします', + 'merchantAi.weekendPromoTitle': '週末プロモーション提案', + 'merchantAi.weekendPromoDesc': '過去のデータでは土曜日の利用処理が+30%。週末限定セールの実施をお勧めします', + 'merchantAi.todayForecast': '本日の客数予測', + 'merchantAi.expectedRedeem': '予想利用処理数', + 'merchantAi.peakHours': 'ピーク時間帯', + 'merchantAi.expectedRevenue': '予想収益', + 'merchantAi.trafficInsight': '先週同期比+12%。昼のピーク時にレジ担当を1名追加することをお勧めします', + 'merchantAi.hourlyForecast': '時間帯別予測', + 'merchantAi.weeklyForecast': '今週の予測', + 'merchantAi.staffSuggestion': 'シフト提案', + 'merchantAi.pendingCount': '未処理', + 'merchantAi.resolvedToday': '本日処理済み', + 'merchantAi.riskIndex': 'リスク指数', + 'merchantAi.riskLow': '低', + 'merchantAi.activeAlerts': 'アクティブアラート', + 'merchantAi.highFreqRedeem': '高頻度利用処理検知', + 'merchantAi.suspectFakeCode': '偽造コード疑い', + 'merchantAi.suspiciousPatterns': '不審なパターン検知', + 'merchantAi.consecutiveRedeem': '同一ユーザーの連続利用処理', + 'merchantAi.offHoursRedeem': '営業時間外の利用処理試行', + 'merchantAi.expiredRedeemAttempt': '期限切れクーポンの利用処理試行', + 'merchantAi.statusAbnormal': '異常', + 'merchantAi.statusWarning': '注意', + 'merchantAi.statusNormal': '正常', + 'merchantAi.expiredBlock': '期限切れクーポンブロック', + 'merchantAi.duplicateBlock': '重複利用処理ブロック', + 'merchantAi.wrongStoreAlert': '対象外店舗アラート', + 'merchantAi.insufficientBalance': '残高不足', + 'merchantAi.systemRetry': 'システムタイムアウト再試行', + 'merchantAi.monday': '月', + 'merchantAi.tuesday': '火', + 'merchantAi.wednesday': '水', + 'merchantAi.thursday': '木', + 'merchantAi.friday': '金', + 'merchantAi.saturday': '土', + 'merchantAi.sunday': '日', + + // ============ Pro Mode ============ + 'proMode.title': 'プロモード', + 'proMode.toggleDesc': 'オンチェーン情報の閲覧と外部ウォレット接続が可能', + 'proMode.requireKycL2': 'KYC L2以上の認証が必要', + 'proMode.connected': '接続済み', + 'proMode.disconnect': '切断', + 'proMode.connectWallet': '外部ウォレットを接続', + 'proMode.walletDesc': '外部ウォレット接続後、プラットフォーム資産を自分のアドレスに引き出せます', + 'proMode.showChainAddress': 'チェーンアドレスを表示', + 'proMode.showChainAddressDesc': 'クーポン詳細にコントラクトアドレスを表示', + 'proMode.showTxHash': '取引ハッシュを表示', + 'proMode.showTxHashDesc': '取引記録にオンチェーンハッシュを表示', + 'proMode.txExplorer': 'トランザクションエクスプローラー', + 'proMode.txBuyExample': 'スターバックス \$25 ギフトカード購入', + 'proMode.txSellExample': 'Amazon \$100 クーポン売却', + 'proMode.confirmed': '確認済み', + 'proMode.confirming': '確認中', + 'proMode.viewAllTx': 'すべてのオンチェーン取引を表示', + 'proMode.chainAssets': 'オンチェーン資産', + 'proMode.custodialWallet': 'プラットフォーム管理ウォレット', + 'proMode.externalWallet': '外部ウォレット (MetaMask)', + 'proMode.couponCount5': '5 枚のクーポン', + 'proMode.couponCount0': '0 枚のクーポン', + 'proMode.extractToWallet': '外部ウォレットに引き出し', + 'proMode.tradeTrack': '取引トラック', + 'proMode.utilityTrackDesc': 'クーポン有効期限\u226412ヶ月、証券ライセンス不要', + 'proMode.securitiesTrackDesc': '長期投資型クーポン商品(近日公開)', + 'proMode.mvpNote': '現在のMVP版はUtility Trackのみ対応', + 'proMode.comingSoon': '近日公開', + 'proMode.whatIsTitle': 'プロモードとは?', + 'proMode.whatIsDesc': 'プロモードはブロックチェーン経験のあるユーザー向けです。有効化後:\n' + '\u2022 外部ウォレット接続(MetaMask等)\n' + '\u2022 オンチェーンアドレスと取引ハッシュの閲覧\n' + '\u2022 資産を自分のウォレットに引き出し\n' + '\u2022 基盤となるオンチェーンデータの閲覧\n\n' + 'KYC L2認証完了後に有効化できます。', + + // ============ Receive Coupon ============ + 'receiveCoupon.title': 'クーポンを受取', + 'receiveCoupon.hint': '下のQRコードまたは受取IDを相手に見せてください。相手がスキャンまたはIDを入力することで、クーポンがあなたのウォレットに届きます。', + 'receiveCoupon.id': '受取ID', + 'receiveCoupon.idCopied': '受取IDをクリップボードにコピーしました', + 'receiveCoupon.note': '受取ったクーポンは自動的にウォレットに保存されます。ホーム画面のウォレットから確認・管理できます。', +}; diff --git a/frontend/mobile/lib/app/i18n/strings/zh_cn.dart b/frontend/mobile/lib/app/i18n/strings/zh_cn.dart new file mode 100644 index 0000000..9485224 --- /dev/null +++ b/frontend/mobile/lib/app/i18n/strings/zh_cn.dart @@ -0,0 +1,686 @@ +const Map zhCN = { + // ============ Common ============ + 'common.confirm': '确认', + 'common.cancel': '取消', + 'common.save': '保存', + 'common.delete': '删除', + 'common.edit': '编辑', + 'common.search': '搜索', + 'common.loading': '加载中...', + 'common.retry': '重试', + 'common.done': '完成', + 'common.next': '下一步', + 'common.back': '返回', + 'common.close': '关闭', + 'common.more': '更多', + 'common.all': '全部', + 'common.filter': '筛选', + 'common.sort': '排序', + 'common.copy': '复制', + 'common.copied': '已复制到剪贴板', + 'common.today': '今日', + 'common.thisWeek': '本周', + 'common.thisMonth': '本月', + + // ============ Navigation ============ + 'nav.home': '首页', + 'nav.market': '市场', + 'nav.myCoupons': '我的券', + 'nav.messages': '消息', + 'nav.profile': '我的', + + // ============ Welcome / Auth ============ + 'welcome.slogan': '让每一张券都有价值', + 'welcome.phoneRegister': '手机号注册', + 'welcome.emailRegister': '邮箱注册', + 'welcome.otherLogin': '其他方式登录', + 'welcome.hasAccount': '已有账号?', + 'welcome.login': '登录', + 'welcome.agreement': '注册即表示同意《用户协议》和《隐私政策》', + + 'login.title': '欢迎回来', + 'login.subtitle': '登录 Genex 管理你的券资产', + 'login.passwordTab': '密码登录', + 'login.codeTab': '验证码登录', + 'login.phoneOrEmail': '手机号或邮箱', + 'login.password': '密码', + 'login.forgotPassword': '忘记密码?', + 'login.submit': '登录', + 'login.phone': '手机号', + 'login.verifyCode': '验证码', + 'login.getCode': '获取验证码', + + 'register.title': '创建账号', + 'register.emailSubtitle': '使用邮箱注册 Genex 账号', + 'register.phoneSubtitle': '使用手机号注册 Genex 账号', + 'register.email': '邮箱地址', + 'register.phone': '手机号', + 'register.emailHint': '请输入邮箱地址', + 'register.phoneHint': '请输入手机号', + 'register.code': '验证码', + 'register.codeHint': '请输入6位验证码', + 'register.getCode': '获取验证码', + 'register.setPassword': '设置密码', + 'register.passwordHint': '8-20位,含字母和数字', + 'register.agreement': '我已阅读并同意', + 'register.userAgreement': '《用户协议》', + 'register.privacyPolicy': '《隐私政策》', + 'register.submit': '注册', + 'register.stepVerify': '验证', + 'register.stepPassword': '设密码', + 'register.stepDone': '完成', + 'register.rule8chars': '8位以上', + 'register.ruleLetter': '含字母', + 'register.ruleNumber': '含数字', + + 'forgot.title': '找回密码', + 'forgot.inputAccount': '输入手机号或邮箱', + 'forgot.sendHint': '我们将向您发送验证码', + 'forgot.accountHint': '手机号 / 邮箱地址', + 'forgot.getCode': '获取验证码', + 'forgot.inputCode': '输入验证码', + 'forgot.codeSentTo': '验证码已发送至', + 'forgot.codeHint': '6位验证码', + 'forgot.resend': '重新发送', + 'forgot.next': '下一步', + 'forgot.setNewPassword': '设置新密码', + 'forgot.newPasswordHint': '请输入新密码(8位以上)', + 'forgot.newPassword': '新密码', + 'forgot.confirmPassword': '确认新密码', + 'forgot.confirmChange': '确认修改', + 'forgot.success': '密码修改成功', + 'forgot.successHint': '请使用新密码登录', + 'forgot.backToLogin': '返回登录', + + // ============ Home ============ + 'home.searchHint': '搜索券、品牌、分类...', + 'home.dining': '餐饮', + 'home.shopping': '购物', + 'home.entertainment': '娱乐', + 'home.travel': '出行', + 'home.lifestyle': '生活', + 'home.brand': '品牌', + 'home.discount': '折扣', + 'home.allCategories': '全部', + 'home.featuredCoupons': '精选好券', + 'home.viewAllCoupons': '查看全部', + 'home.aiRecommend': 'AI 推荐', + 'home.aiRecommendDesc': '根据你的偏好,发现了3张高性价比券', + 'home.bannerNewUser': '新用户专享', + 'home.bannerNewUserDesc': '首单立减 \$10', + 'home.bannerDiscount': '限时折扣', + 'home.bannerDiscountDesc': '全场低至7折', + 'home.bannerHot': '热门推荐', + 'home.bannerHotDesc': '精选高折扣券', + + // ============ Market ============ + 'market.title': '交易市场', + 'market.primary': '一级市场(全新)', + 'market.secondary': '二级市场(转售)', + 'market.dining': '餐饮', + 'market.shopping': '购物', + 'market.entertainment': '娱乐', + 'market.travel': '出行', + 'market.lifestyle': '生活', + 'market.sports': '运动', + 'market.discountRate': '折扣率', + 'market.priceUp': '价格↑', + 'market.priceDown': '价格↓', + 'market.expiryDate': '到期时间', + 'market.issuePrice': '发行价', + 'market.faceValue': '面值', + 'market.discount': '折扣', + 'market.totalSupply': '发行量', + 'market.salesProgress': '销售进度', + 'market.upcoming': '即将开始', + 'market.subscribing': '申购中', + 'market.ended': '已结束', + 'market.timeToStart': '距开始', + 'market.couponBrand': '券名/品牌', + 'market.latestPrice': '最新价', + 'market.change24h': '24h涨跌', + 'market.discountSuffix': '折', + + // ============ My Coupons ============ + 'myCoupons.title': '我的券', + 'myCoupons.usable': '可使用', + 'myCoupons.pendingRedeem': '待核销', + 'myCoupons.expired': '已过期', + 'myCoupons.faceValue': '面值', + 'myCoupons.transfer': '转赠', + 'myCoupons.sell': '出售', + 'myCoupons.expiredText': '已过期', + 'myCoupons.expiringToday': '今天到期', + 'myCoupons.daysToExpiry': '天后到期', + + // ============ Coupon Detail ============ + 'couponDetail.title': '券详情', + 'couponDetail.favorite': '收藏', + 'couponDetail.buyNow': '立即购买', + 'couponDetail.saveBadge': '比面值节省', + 'couponDetail.faceValue': '面值', + 'couponDetail.validUntil': '有效期', + 'couponDetail.type': '类型', + 'couponDetail.issuer': '发行方', + 'couponDetail.consumeCoupon': '消费券', + 'couponDetail.usageNote': '使用说明', + 'couponDetail.allStores': '全国门店通用', + 'couponDetail.canTransfer': '可转赠给好友', + 'couponDetail.useAnytime': '有效期内随时使用', + 'couponDetail.noStack': '不可叠加使用', + 'couponDetail.noCash': '不可兑换现金', + 'couponDetail.stores': '使用门店', + 'couponDetail.storeCount': '全国 12,800+ 门店', + 'couponDetail.storeDesc': '支持全国所有直营门店使用', + 'couponDetail.priceTrend': '价格走势', + 'couponDetail.last30Days': '近30天', + 'couponDetail.highest': '最高', + 'couponDetail.lowest': '最低', + 'couponDetail.average': '均价', + 'couponDetail.tradeHistory': '历史成交', + 'couponDetail.nearbyStores': '附近可用门店', + 'couponDetail.distance': '距离', + 'couponDetail.open': '营业中', + 'couponDetail.similar': '同类券推荐', + + // ============ My Coupon Detail ============ + 'myCoupon.title': '券详情', + 'myCoupon.active': '可使用', + 'myCoupon.showQrHint': '出示此二维码给商户扫描核销', + 'myCoupon.switchBarcode': '切换条形码', + 'myCoupon.faceValue': '面值', + 'myCoupon.purchasePrice': '购买价格', + 'myCoupon.validUntil': '有效期', + 'myCoupon.orderNo': '订单号', + 'myCoupon.resellCount': '剩余可转售次数', + 'myCoupon.transfer': '转赠', + 'myCoupon.sell': '出售', + 'myCoupon.usageNote': '使用说明', + 'myCoupon.useInStore': '全国门店通用', + 'myCoupon.useInTime': '请在有效期内使用', + 'myCoupon.onePerVisit': '每次消费仅可使用一张', + 'myCoupon.noCash': '不可兑换现金', + 'myCoupon.extractToWallet': '提取到外部钱包', + 'myCoupon.requireKycL2': '需KYC L2+认证', + 'myCoupon.viewTrades': '查看交易记录', + 'myCoupon.help': '使用帮助', + + // ============ Order Confirm ============ + 'orderConfirm.title': '确认订单', + 'orderConfirm.quantity': '购买数量', + 'orderConfirm.paymentMethod': '支付方式', + 'orderConfirm.bankCard': '银行卡/信用卡', + 'orderConfirm.priceDetail': '价格明细', + 'orderConfirm.buyingNote': '您正在购买消费券用于消费', + 'orderConfirm.total': '合计', + 'orderConfirm.confirmPay': '确认支付', + 'orderConfirm.unitPrice': '单价', + 'orderConfirm.count': '数量', + 'orderConfirm.saveBadge': '比面值节省', + 'orderConfirm.biometricHint': '请验证指纹或面容以完成支付', + 'orderConfirm.usePasswordPay': '使用密码支付', + + // ============ Payment ============ + 'payment.title': '选择支付方式', + 'payment.addNew': '添加新支付方式', + 'payment.confirmPay': '确认支付', + 'payment.bankTransfer': '银行转账', + + 'paymentSuccess.title': '支付成功', + 'paymentSuccess.hint': '券已到账,可在「我的券」中查看', + 'paymentSuccess.couponName': '券名称', + 'paymentSuccess.payAmount': '支付金额', + 'paymentSuccess.orderNo': '订单号', + 'paymentSuccess.payTime': '支付时间', + 'paymentSuccess.viewMyCoupon': '查看我的券', + 'paymentSuccess.continueBrowse': '继续逛', + + // ============ Search ============ + 'search.hint': '搜索券、品牌、分类...', + 'search.cancel': '取消', + 'search.hotSearch': '热门搜索', + 'search.history': '搜索历史', + 'search.clear': '清空', + 'search.diningCoupon': '餐饮券', + 'search.discountCoupon': '折扣券', + 'search.travel': '旅游', + + // ============ Redeem ============ + 'redeem.title': '出示券码', + 'redeem.faceValue': '面值', + 'redeem.validTime': '有效时间', + 'redeem.refresh': '刷新券码', + 'redeem.showHint': '请将此码出示给商户扫描,屏幕已自动调至最高亮度', + + // ============ Sell Order ============ + 'sellOrder.title': '挂单出售', + 'sellOrder.faceValue': '面值', + 'sellOrder.credit': '信用', + 'sellOrder.setPrice': '设定售价', + 'sellOrder.price': '售价', + 'sellOrder.aiSuggest': 'AI建议售价', + 'sellOrder.bestDealRate': '此价格成交概率最高', + 'sellOrder.discountRate': '折扣率', + 'sellOrder.platformFee': '平台手续费 (1.5%)', + 'sellOrder.estimatedReceive': '预计到账', + 'sellOrder.marketAvg': '当前市场均价', + 'sellOrder.recent24hTrades': '最近24小时成交', + 'sellOrder.tradesUnit': '笔', + 'sellOrder.confirmList': '确认挂单', + 'sellOrder.success': '挂单成功', + 'sellOrder.successHint': '您的券已挂到市场,当有买家下单时将自动成交。', + 'sellOrder.ok': '确定', + + // ============ Trading Page (My Trades) ============ + 'tradingPage.title': '我的交易', + 'tradingPage.pendingOrders': '我的挂单', + 'tradingPage.tradeRecords': '交易记录', + 'tradingPage.listPrice': '挂单价', + 'tradingPage.listTime': '挂单时间', + 'tradingPage.cancelOrder': '撤单', + 'tradingPage.buy': '买入', + 'tradingPage.sell': '卖出', + + // ============ Transfer ============ + 'transfer.title': '转赠给好友', + 'transfer.searchFriend': '搜索好友(手机号/用户名)', + 'transfer.confirmTransfer': '确认转赠', + 'transfer.success': '转赠成功', + 'transfer.confirm': '确定', + 'transfer.cancel': '取消', + + // ============ Wallet ============ + 'wallet.myBalance': '我的余额', + 'wallet.totalBalance': '总余额', + 'wallet.withdrawable': '可提现', + 'wallet.frozen': '冻结中', + 'wallet.deposit': '充值', + 'wallet.withdraw': '提现', + 'wallet.records': '交易记录', + 'wallet.filter': '筛选', + 'wallet.buyIn': '买入', + 'wallet.sellOut': '卖出', + 'wallet.giftTransfer': '转赠', + 'wallet.redeemUse': '核销', + + 'deposit.title': '充值', + 'deposit.currentBalance': '当前余额', + 'deposit.amount': '充值金额', + 'deposit.custom': '自定义金额', + 'deposit.paymentMethod': '支付方式', + 'deposit.submit': '充值', + + 'withdraw.title': '提现', + 'withdraw.availableBalance': '可提现余额', + 'withdraw.amount': '提现金额', + 'withdraw.all': '全部', + 'withdraw.to': '提现到', + 'withdraw.savingsAccount': '储蓄账户', + 'withdraw.fee': '手续费 (0.5%)', + 'withdraw.actualReceive': '实际到账', + 'withdraw.estimateTime': '预计 1-2 个工作日到账', + 'withdraw.submit': '确认提现', + + 'txRecords.title': '交易记录', + 'txRecords.all': '全部', + 'txRecords.buy': '购买', + 'txRecords.sell': '出售', + 'txRecords.transfer': '转赠', + 'txRecords.noRecords': '暂无记录', + 'txRecords.orderNo': '订单号', + 'txRecords.transferTo': '转赠给', + + // ============ Profile ============ + 'profile.favorites': '收藏', + 'profile.orders': '订单', + 'profile.coupons': '券', + 'profile.wallet': '钱包', + 'profile.account': '账户', + 'profile.trade': '交易', + 'profile.settings': '设置', + 'profile.holdCoupons': '持券', + 'profile.saved': '节省', + 'profile.credit': '信用', + 'profile.creditScore': '信用积分', + 'profile.myTrades': '我的交易', + 'profile.walletBalance': '钱包余额', + 'profile.paymentManage': '支付管理', + 'profile.kyc': '身份认证', + 'profile.proMode': '高级模式', + 'profile.myFavorites': '我的收藏', + 'profile.securitySettings': '安全设置', + 'profile.advancedSettings': '高级设置', + 'profile.aboutGenex': '关于 Genex', + 'profile.helpCenter': '帮助中心', + 'profile.issuerPortal': '发行方入口', + 'profile.merchantPortal': '商户入口', + 'profile.simplifiedChinese': '简体中文', + 'profile.logout': '退出登录', + + // ============ Settings ============ + 'settings.title': '设置', + 'settings.accountSecurity': '账号与安全', + 'settings.phone': '手机号', + 'settings.email': '邮箱', + 'settings.changePassword': '修改密码', + 'settings.identity': '身份认证', + 'settings.paymentManage': '支付管理', + 'settings.paymentMethod': '支付方式', + 'settings.bankAccount': '银行账户', + 'settings.paymentPassword': '支付密码', + 'settings.notifications': '通知设置', + 'settings.tradeNotify': '交易通知', + 'settings.expiryRemind': '到期提醒', + 'settings.marketChange': '行情变动', + 'settings.marketingPush': '营销推送', + 'settings.general': '通用', + 'settings.language': '语言', + 'settings.currency': '货币', + 'settings.clearCache': '清除缓存', + 'settings.about': '关于', + 'settings.version': '版本', + 'settings.userAgreement': '用户协议', + 'settings.privacyPolicy': '隐私政策', + 'settings.helpCenter': '帮助中心', + 'settings.logout': '退出登录', + 'settings.selectCurrency': '选择计价货币', + 'settings.currencyNote': '此设置影响交易页面中所有价格的计价货币显示', + 'settings.selectLanguage': '选择语言', + 'settings.currencySymbol': '符号', + + // ============ KYC ============ + 'kyc.title': '身份认证', + 'kyc.currentLevel': '当前认证等级', + 'kyc.l1Title': 'L1 基础认证', + 'kyc.l1Desc': '手机号 + 邮箱验证', + 'kyc.l1Limit': '每日购买限额 \$500', + 'kyc.l1Feature': '可购买券、出示核销', + 'kyc.l2Title': 'L2 身份认证', + 'kyc.l2Desc': '身份证/护照验证', + 'kyc.l2Limit': '每日购买限额 \$5,000', + 'kyc.l2Feature': '解锁二级市场交易、P2P转赠', + 'kyc.l3Title': 'L3 高级认证', + 'kyc.l3Desc': '视频面审 + 地址证明', + 'kyc.l3Limit': '无限额', + 'kyc.l3Feature': '解锁大额交易、提现无限制', + 'kyc.completed': '已完成', + 'kyc.goVerify': '去认证', + 'kyc.badgeLabel': '认证', + + // ============ Payment Management ============ + 'payManage.title': '支付管理', + 'payManage.myCards': '我的银行卡', + 'payManage.addCard': '添加新银行卡', + 'payManage.bankAccount': '银行账户(提现用)', + 'payManage.paymentSecurity': '支付安全', + 'payManage.paymentPassword': '支付密码', + 'payManage.passwordSet': '已设置', + 'payManage.biometricPay': '指纹/面容支付', + 'payManage.biometricEnabled': '已开启', + 'payManage.noPasswordPay': '免密支付', + 'payManage.noPasswordLimit': '单笔≤\$10', + + // ============ AI Chat ============ + 'aiChat.title': 'AI 助手', + 'aiChat.greeting': '你好!我是 Genex AI 助手,可以帮你发现高性价比好券、比价分析、组合推荐。试试问我:', + 'aiChat.suggest1': '推荐适合我的券', + 'aiChat.suggest2': '星巴克券值不值得买?', + 'aiChat.suggest3': '帮我做比价分析', + 'aiChat.suggest4': '我的券快到期了怎么办?', + 'aiChat.inputHint': '问我任何关于券的问题...', + 'aiChat.confirmAction': '确认执行', + 'aiChat.riskLow': '低风险', + 'aiChat.riskNormal': '需确认', + 'aiChat.riskHigh': '高风险', + + // ============ AI Fab ============ + 'aiFab.title': 'AI 助手', + 'aiFab.greeting': '你好!我是 Genex AI 助手,可以帮你管理券资产、查找优惠、分析价格。有什么需要帮助的吗?', + 'aiFab.inputHint': '输入消息...', + 'aiFab.suggest1': '帮我找高折扣券', + 'aiFab.suggest2': '我的券快到期了吗?', + 'aiFab.suggest3': '推荐今日好券', + 'aiFab.suggest4': '分析我的券资产', + + // ============ Messages ============ + 'message.title': '消息', + 'message.markAllRead': '全部已读', + 'message.tabTrade': '交易', + 'message.tabExpiry': '到期', + 'message.tabAnnouncement': '公告', + 'message.detailTitle': '消息详情', + 'message.tradeNotify': '交易通知', + 'message.expiryRemind': '到期提醒', + 'message.systemNotify': '系统通知', + 'message.promoNotify': '活动推送', + 'message.tradeSuccess': '交易成功通知', + 'message.couponName': '券名称', + 'message.faceValue': '面值', + 'message.payAmount': '支付金额', + 'message.orderNo': '订单号', + 'message.payMethod': '支付方式', + 'message.viewCouponDetail': '查看券详情', + + // ============ Status Tags ============ + 'status.active': '可使用', + 'status.pending': '待核销', + 'status.expired': '已过期', + 'status.used': '已使用', + 'status.processing': '处理中', + 'status.completed': '已完成', + 'status.cancelled': '已取消', + 'status.refunding': '退款中', + 'status.onSale': '出售中', + + // ============ Empty States ============ + 'empty.noCoupons': '还没有券', + 'empty.noCouponsHint': '去市场看看有什么好券吧', + 'empty.browse': '去逛逛', + 'empty.noTrades': '暂无交易记录', + 'empty.noTradesHint': '完成首笔交易后这里会显示记录', + 'empty.noResults': '没有找到结果', + 'empty.noResultsHint': '换个关键词试试', + 'empty.noMessages': '暂无消息', + 'empty.noMessagesHint': '交易通知和系统公告会显示在这里', + 'empty.networkError': '网络连接失败', + 'empty.networkErrorHint': '请检查网络设置后重试', + + // ============ Coupon Card (shared widget) ============ + 'couponCard.expiredText': '已过期', + 'couponCard.expiringToday': '今天到期', + 'couponCard.daysToExpiry': '天后到期', + 'couponCard.expiryFormat': '到期', + + // ============ Issuer ============ + 'issuer.title': '发行方管理', + 'issuer.verified': '已认证发行方', + 'issuer.overview': '总览', + 'issuer.issue': '发券', + 'issuer.redeem': '核销', + 'issuer.finance': '财务', + 'issuer.more': '更多', + 'issuer.totalIssued': '发行总量', + 'issuer.totalSold': '已售出', + 'issuer.totalRedeemed': '已核销', + 'issuer.redeemRate': '核销率', + 'issuer.quickActions': '快捷操作', + 'issuer.createCoupon': '创建券', + 'issuer.storeManage': '门店管理', + 'issuer.salesAnalysis': '销售分析', + 'issuer.statement': '对账单', + 'issuer.myCoupons': '我的券', + 'issuer.listed': '已上架', + 'issuer.underReview': '审核中', + 'issuer.soldOut': '已售罄', + 'issuer.unlisted': '已下架', + 'issuer.issuedSlash': '发行', + 'issuer.sold': '已售', + 'issuer.issueCenter': '发券中心', + 'issuer.selectTemplate': '选择券模板', + 'issuer.voucherType': '满减券', + 'issuer.discountType': '折扣券', + 'issuer.giftCardType': '礼品卡', + 'issuer.storedValueType': '储值券', + 'issuer.couponManage': '券管理', + 'issuer.viewAll': '查看全部', + 'issuer.couponEvents': '券活动', + 'issuer.createNew': '创建新券', + 'issuer.redeemManage': '核销管理', + 'issuer.redeemTrend': '核销趋势', + 'issuer.allStores': '全部门店', + 'issuer.employees': '名员工', + 'issuer.financeManage': '财务管理', + 'issuer.totalSales': '总销售额', + 'issuer.settled': '已到账', + 'issuer.pendingSettle': '待结算', + 'issuer.breakage': 'Breakage', + 'issuer.withdrawBtn': '提现', + 'issuer.reportBtn': '对账报表', + 'issuer.settleDetail': '结算明细', + 'issuer.creditLevel': '信用等级', + 'issuer.issueQuota': '发行额度', + 'issuer.usedQuota': '已用额度', + 'issuer.dataCenter': '数据中心', + 'issuer.issueSalesRate': '发行量/销量/兑付率', + 'issuer.userProfile': '用户画像', + 'issuer.userProfileDesc': '购买用户分布分析', + 'issuer.creditDetail': '信用详情', + 'issuer.creditDetailDesc': '评分详情与提升建议', + 'issuer.quotaChange': '额度变动', + 'issuer.quotaChangeDesc': '历史额度调整记录', + 'issuer.companyInfo': '企业信息', + 'issuer.companyInfoDesc': '营业执照/联系人', + 'issuer.settingsItem': '设置', + 'issuer.settingsItemDesc': '通知/安全/语言', + 'issuer.helpItem': '帮助中心', + 'issuer.helpItemDesc': '常见问题与客服', + + // ============ Merchant ============ + 'merchant.today': '今日', + 'merchant.onlineMode': '在线模式', + 'merchant.offlineMode': '离线模式', + 'merchant.pendingSync': '待同步', + 'merchant.syncUnit': '笔', + 'merchant.scanHint': '将券二维码对准扫描框', + 'merchant.flashlight': '手电筒', + 'merchant.manualInput': '手动输码', + 'merchant.redeemRecords': '核销记录', + 'merchant.storeData': '门店数据', + 'merchant.inputCode': '手动输入券码', + 'merchant.inputCodeHint': '请输入券码', + 'merchant.query': '查询', + 'merchant.userNickname': '用户昵称', + 'merchant.consumer': '消费者', + 'merchant.couponName': '券名称', + 'merchant.faceValue': '面值', + 'merchant.validUntil': '有效期', + 'merchant.useCondition': '使用条件', + 'merchant.noMinSpend': '无最低消费', + 'merchant.confirmRedeem': '确认核销', + 'merchant.redeemSuccess': '核销成功', + 'merchant.continueRedeem': '继续核销', + 'merchant.synced': '已同步', + 'merchant.pendingSyncLabel': '待同步', + 'merchant.redeemOperator': '核销员', + 'merchant.todayRedeem': '今日核销', + 'merchant.redeemAmount': '核销金额', + 'merchant.weekTrend': '本周趋势', + 'merchant.operatorRank': '核销员排行', + + // ============ Merchant AI ============ + 'merchantAi.title': 'AI 智能助手', + 'merchantAi.redeemAssist': '核销辅助', + 'merchantAi.trafficForecast': '客流预测', + 'merchantAi.anomalyAlert': '异常预警', + 'merchantAi.verifyAuth': '验券真伪', + 'merchantAi.checkStatus': '查券状态', + 'merchantAi.batchRedeem': '批量核销', + 'merchantAi.feedback': '问题反馈', + 'merchantAi.quickActions': 'AI 快捷操作', + 'merchantAi.redeemTips': '核销提示', + 'merchantAi.todayHotRedeem': '今日热门核销', + 'merchantAi.countUnit': '笔', + 'merchantAi.aiMarketing': 'AI 营销建议', + 'merchantAi.crossSellTitle': '推荐搭配销售', + 'merchantAi.crossSellDesc': '购买咖啡券的顾客同时对糕点券感兴趣,建议推荐组合', + 'merchantAi.weekendPromoTitle': '周末促销建议', + 'merchantAi.weekendPromoDesc': '历史数据显示周六核销量+30%,建议推出周末限时活动', + 'merchantAi.todayForecast': '今日客流预测', + 'merchantAi.expectedRedeem': '预计核销', + 'merchantAi.peakHours': '高峰时段', + 'merchantAi.expectedRevenue': '预计收入', + 'merchantAi.trafficInsight': '较上周同期增长12%,建议午间增加1名收银员', + 'merchantAi.hourlyForecast': '分时段预测', + 'merchantAi.weeklyForecast': '本周预测', + 'merchantAi.staffSuggestion': '排班建议', + 'merchantAi.pendingCount': '待处理', + 'merchantAi.resolvedToday': '今日已处理', + 'merchantAi.riskIndex': '风险指数', + 'merchantAi.riskLow': '低', + 'merchantAi.activeAlerts': '活跃预警', + 'merchantAi.highFreqRedeem': '高频核销检测', + 'merchantAi.suspectFakeCode': '疑似伪造券码', + 'merchantAi.suspiciousPatterns': '可疑模式检测', + 'merchantAi.consecutiveRedeem': '同一用户连续核销', + 'merchantAi.offHoursRedeem': '非营业时间核销尝试', + 'merchantAi.expiredRedeemAttempt': '过期券核销尝试', + 'merchantAi.statusAbnormal': '异常', + 'merchantAi.statusWarning': '注意', + 'merchantAi.statusNormal': '正常', + 'merchantAi.expiredBlock': '过期券核销拦截', + 'merchantAi.duplicateBlock': '重复核销拦截', + 'merchantAi.wrongStoreAlert': '非本店券提醒', + 'merchantAi.insufficientBalance': '余额不足核销', + 'merchantAi.systemRetry': '系统超时重试', + 'merchantAi.monday': '周一', + 'merchantAi.tuesday': '周二', + 'merchantAi.wednesday': '周三', + 'merchantAi.thursday': '周四', + 'merchantAi.friday': '周五', + 'merchantAi.saturday': '周六', + 'merchantAi.sunday': '周日', + + // ============ Pro Mode ============ + 'proMode.title': '高级模式', + 'proMode.toggleDesc': '开启后可查看链上信息和连接外部钱包', + 'proMode.requireKycL2': '需要 KYC L2 及以上认证', + 'proMode.connected': '已连接', + 'proMode.disconnect': '断开', + 'proMode.connectWallet': '连接外部钱包', + 'proMode.walletDesc': '连接外部钱包后可将平台资产提取至自有地址', + 'proMode.showChainAddress': '显示链上地址', + 'proMode.showChainAddressDesc': '在券详情中展示合约地址', + 'proMode.showTxHash': '显示交易Hash', + 'proMode.showTxHashDesc': '在交易记录中展示链上Hash', + 'proMode.txExplorer': '交易浏览器', + 'proMode.txBuyExample': '购买 星巴克 \$25 礼品卡', + 'proMode.txSellExample': '出售 Amazon \$100 券', + 'proMode.confirmed': '已确认', + 'proMode.confirming': '确认中', + 'proMode.viewAllTx': '查看全部链上交易', + 'proMode.chainAssets': '链上资产', + 'proMode.custodialWallet': '平台托管钱包', + 'proMode.externalWallet': '外部钱包 (MetaMask)', + 'proMode.couponCount5': '5 张券', + 'proMode.couponCount0': '0 张券', + 'proMode.extractToWallet': '提取至外部钱包', + 'proMode.tradeTrack': '交易轨道', + 'proMode.utilityTrackDesc': '券有效期≤12个月,无需证券牌照', + 'proMode.securitiesTrackDesc': '长期投资型券产品(即将推出)', + 'proMode.mvpNote': '当前MVP版本仅支持Utility Track', + 'proMode.comingSoon': '敬请期待', + 'proMode.whatIsTitle': '什么是高级模式?', + 'proMode.whatIsDesc': '高级模式面向有区块链经验的用户,开启后可以:\n' + '• 连接外部钱包(MetaMask等)\n' + '• 查看链上地址和交易Hash\n' + '• 将资产提取至自有钱包\n' + '• 查看底层链上数据\n\n' + '需要完成 KYC L2 认证后方可开启。', + + // ============ Receive Coupon ============ + 'receiveCoupon.title': '接收券', + 'receiveCoupon.hint': '向他人展示下方二维码或接收ID,对方可通过扫码或输入ID将券转赠到你的钱包。', + 'receiveCoupon.id': '接收ID', + 'receiveCoupon.idCopied': '接收ID已复制到剪贴板', + 'receiveCoupon.note': '接收的券将自动存入你的钱包,可在首页钱包中查看和管理。', +}; diff --git a/frontend/mobile/lib/app/i18n/strings/zh_tw.dart b/frontend/mobile/lib/app/i18n/strings/zh_tw.dart new file mode 100644 index 0000000..c947cb8 --- /dev/null +++ b/frontend/mobile/lib/app/i18n/strings/zh_tw.dart @@ -0,0 +1,686 @@ +const Map zhTW = { + // ============ Common ============ + 'common.confirm': '確認', + 'common.cancel': '取消', + 'common.save': '儲存', + 'common.delete': '刪除', + 'common.edit': '編輯', + 'common.search': '搜尋', + 'common.loading': '載入中...', + 'common.retry': '重試', + 'common.done': '完成', + 'common.next': '下一步', + 'common.back': '返回', + 'common.close': '關閉', + 'common.more': '更多', + 'common.all': '全部', + 'common.filter': '篩選', + 'common.sort': '排序', + 'common.copy': '複製', + 'common.copied': '已複製到剪貼簿', + 'common.today': '今日', + 'common.thisWeek': '本週', + 'common.thisMonth': '本月', + + // ============ Navigation ============ + 'nav.home': '首頁', + 'nav.market': '市場', + 'nav.myCoupons': '我的券', + 'nav.messages': '訊息', + 'nav.profile': '我的', + + // ============ Welcome / Auth ============ + 'welcome.slogan': '讓每一張券都有價值', + 'welcome.phoneRegister': '手機號註冊', + 'welcome.emailRegister': '信箱註冊', + 'welcome.otherLogin': '其他方式登入', + 'welcome.hasAccount': '已有帳號?', + 'welcome.login': '登入', + 'welcome.agreement': '註冊即表示同意《使用者協議》和《隱私權政策》', + + 'login.title': '歡迎回來', + 'login.subtitle': '登入 Genex 管理你的券資產', + 'login.passwordTab': '密碼登入', + 'login.codeTab': '驗證碼登入', + 'login.phoneOrEmail': '手機號或信箱', + 'login.password': '密碼', + 'login.forgotPassword': '忘記密碼?', + 'login.submit': '登入', + 'login.phone': '手機號', + 'login.verifyCode': '驗證碼', + 'login.getCode': '取得驗證碼', + + 'register.title': '建立帳號', + 'register.emailSubtitle': '使用信箱註冊 Genex 帳號', + 'register.phoneSubtitle': '使用手機號註冊 Genex 帳號', + 'register.email': '信箱地址', + 'register.phone': '手機號', + 'register.emailHint': '請輸入信箱地址', + 'register.phoneHint': '請輸入手機號', + 'register.code': '驗證碼', + 'register.codeHint': '請輸入6位驗證碼', + 'register.getCode': '取得驗證碼', + 'register.setPassword': '設定密碼', + 'register.passwordHint': '8-20位,含字母和數字', + 'register.agreement': '我已閱讀並同意', + 'register.userAgreement': '《使用者協議》', + 'register.privacyPolicy': '《隱私權政策》', + 'register.submit': '註冊', + 'register.stepVerify': '驗證', + 'register.stepPassword': '設密碼', + 'register.stepDone': '完成', + 'register.rule8chars': '8位以上', + 'register.ruleLetter': '含字母', + 'register.ruleNumber': '含數字', + + 'forgot.title': '找回密碼', + 'forgot.inputAccount': '輸入手機號或信箱', + 'forgot.sendHint': '我們將向您發送驗證碼', + 'forgot.accountHint': '手機號 / 信箱地址', + 'forgot.getCode': '取得驗證碼', + 'forgot.inputCode': '輸入驗證碼', + 'forgot.codeSentTo': '驗證碼已發送至', + 'forgot.codeHint': '6位驗證碼', + 'forgot.resend': '重新發送', + 'forgot.next': '下一步', + 'forgot.setNewPassword': '設定新密碼', + 'forgot.newPasswordHint': '請輸入新密碼(8位以上)', + 'forgot.newPassword': '新密碼', + 'forgot.confirmPassword': '確認新密碼', + 'forgot.confirmChange': '確認修改', + 'forgot.success': '密碼修改成功', + 'forgot.successHint': '請使用新密碼登入', + 'forgot.backToLogin': '返回登入', + + // ============ Home ============ + 'home.searchHint': '搜尋券、品牌、分類...', + 'home.dining': '餐飲', + 'home.shopping': '購物', + 'home.entertainment': '娛樂', + 'home.travel': '出行', + 'home.lifestyle': '生活', + 'home.brand': '品牌', + 'home.discount': '折扣', + 'home.allCategories': '全部', + 'home.featuredCoupons': '精選好券', + 'home.viewAllCoupons': '查看全部', + 'home.aiRecommend': 'AI 推薦', + 'home.aiRecommendDesc': '根據你的偏好,發現了3張高性價比券', + 'home.bannerNewUser': '新用戶專享', + 'home.bannerNewUserDesc': '首單立減 \$10', + 'home.bannerDiscount': '限時折扣', + 'home.bannerDiscountDesc': '全場低至7折', + 'home.bannerHot': '熱門推薦', + 'home.bannerHotDesc': '精選高折扣券', + + // ============ Market ============ + 'market.title': '交易市場', + 'market.primary': '一級市場(全新)', + 'market.secondary': '二級市場(轉售)', + 'market.dining': '餐飲', + 'market.shopping': '購物', + 'market.entertainment': '娛樂', + 'market.travel': '出行', + 'market.lifestyle': '生活', + 'market.sports': '運動', + 'market.discountRate': '折扣率', + 'market.priceUp': '價格↑', + 'market.priceDown': '價格↓', + 'market.expiryDate': '到期時間', + 'market.issuePrice': '發行價', + 'market.faceValue': '面值', + 'market.discount': '折扣', + 'market.totalSupply': '發行量', + 'market.salesProgress': '銷售進度', + 'market.upcoming': '即將開始', + 'market.subscribing': '申購中', + 'market.ended': '已結束', + 'market.timeToStart': '距開始', + 'market.couponBrand': '券名/品牌', + 'market.latestPrice': '最新價', + 'market.change24h': '24h漲跌', + 'market.discountSuffix': '折', + + // ============ My Coupons ============ + 'myCoupons.title': '我的券', + 'myCoupons.usable': '可使用', + 'myCoupons.pendingRedeem': '待核銷', + 'myCoupons.expired': '已過期', + 'myCoupons.faceValue': '面值', + 'myCoupons.transfer': '轉贈', + 'myCoupons.sell': '出售', + 'myCoupons.expiredText': '已過期', + 'myCoupons.expiringToday': '今天到期', + 'myCoupons.daysToExpiry': '天後到期', + + // ============ Coupon Detail ============ + 'couponDetail.title': '券詳情', + 'couponDetail.favorite': '收藏', + 'couponDetail.buyNow': '立即購買', + 'couponDetail.saveBadge': '比面值節省', + 'couponDetail.faceValue': '面值', + 'couponDetail.validUntil': '有效期', + 'couponDetail.type': '類型', + 'couponDetail.issuer': '發行方', + 'couponDetail.consumeCoupon': '消費券', + 'couponDetail.usageNote': '使用說明', + 'couponDetail.allStores': '全國門市通用', + 'couponDetail.canTransfer': '可轉贈給好友', + 'couponDetail.useAnytime': '有效期內隨時使用', + 'couponDetail.noStack': '不可疊加使用', + 'couponDetail.noCash': '不可兌換現金', + 'couponDetail.stores': '使用門市', + 'couponDetail.storeCount': '全國 12,800+ 門市', + 'couponDetail.storeDesc': '支援全國所有直營門市使用', + 'couponDetail.priceTrend': '價格走勢', + 'couponDetail.last30Days': '近30天', + 'couponDetail.highest': '最高', + 'couponDetail.lowest': '最低', + 'couponDetail.average': '均價', + 'couponDetail.tradeHistory': '歷史成交', + 'couponDetail.nearbyStores': '附近可用門市', + 'couponDetail.distance': '距離', + 'couponDetail.open': '營業中', + 'couponDetail.similar': '同類券推薦', + + // ============ My Coupon Detail ============ + 'myCoupon.title': '券詳情', + 'myCoupon.active': '可使用', + 'myCoupon.showQrHint': '出示此二維碼給商戶掃描核銷', + 'myCoupon.switchBarcode': '切換條碼', + 'myCoupon.faceValue': '面值', + 'myCoupon.purchasePrice': '購買價格', + 'myCoupon.validUntil': '有效期', + 'myCoupon.orderNo': '訂單號', + 'myCoupon.resellCount': '剩餘可轉售次數', + 'myCoupon.transfer': '轉贈', + 'myCoupon.sell': '出售', + 'myCoupon.usageNote': '使用說明', + 'myCoupon.useInStore': '全國門市通用', + 'myCoupon.useInTime': '請在有效期內使用', + 'myCoupon.onePerVisit': '每次消費僅可使用一張', + 'myCoupon.noCash': '不可兌換現金', + 'myCoupon.extractToWallet': '提取到外部錢包', + 'myCoupon.requireKycL2': '需KYC L2+認證', + 'myCoupon.viewTrades': '查看交易紀錄', + 'myCoupon.help': '使用幫助', + + // ============ Order Confirm ============ + 'orderConfirm.title': '確認訂單', + 'orderConfirm.quantity': '購買數量', + 'orderConfirm.paymentMethod': '支付方式', + 'orderConfirm.bankCard': '銀行卡/信用卡', + 'orderConfirm.priceDetail': '價格明細', + 'orderConfirm.buyingNote': '您正在購買消費券用於消費', + 'orderConfirm.total': '合計', + 'orderConfirm.confirmPay': '確認支付', + 'orderConfirm.unitPrice': '單價', + 'orderConfirm.count': '數量', + 'orderConfirm.saveBadge': '比面值節省', + 'orderConfirm.biometricHint': '請驗證指紋或臉部辨識以完成支付', + 'orderConfirm.usePasswordPay': '使用密碼支付', + + // ============ Payment ============ + 'payment.title': '選擇支付方式', + 'payment.addNew': '新增支付方式', + 'payment.confirmPay': '確認支付', + 'payment.bankTransfer': '銀行轉帳', + + 'paymentSuccess.title': '支付成功', + 'paymentSuccess.hint': '券已到帳,可在「我的券」中查看', + 'paymentSuccess.couponName': '券名稱', + 'paymentSuccess.payAmount': '支付金額', + 'paymentSuccess.orderNo': '訂單號', + 'paymentSuccess.payTime': '支付時間', + 'paymentSuccess.viewMyCoupon': '查看我的券', + 'paymentSuccess.continueBrowse': '繼續逛', + + // ============ Search ============ + 'search.hint': '搜尋券、品牌、分類...', + 'search.cancel': '取消', + 'search.hotSearch': '熱門搜尋', + 'search.history': '搜尋歷史', + 'search.clear': '清空', + 'search.diningCoupon': '餐飲券', + 'search.discountCoupon': '折扣券', + 'search.travel': '旅遊', + + // ============ Redeem ============ + 'redeem.title': '出示券碼', + 'redeem.faceValue': '面值', + 'redeem.validTime': '有效時間', + 'redeem.refresh': '重新整理券碼', + 'redeem.showHint': '請將此碼出示給商戶掃描,螢幕已自動調至最高亮度', + + // ============ Sell Order ============ + 'sellOrder.title': '掛單出售', + 'sellOrder.faceValue': '面值', + 'sellOrder.credit': '信用', + 'sellOrder.setPrice': '設定售價', + 'sellOrder.price': '售價', + 'sellOrder.aiSuggest': 'AI建議售價', + 'sellOrder.bestDealRate': '此價格成交機率最高', + 'sellOrder.discountRate': '折扣率', + 'sellOrder.platformFee': '平台手續費 (1.5%)', + 'sellOrder.estimatedReceive': '預計到帳', + 'sellOrder.marketAvg': '目前市場均價', + 'sellOrder.recent24hTrades': '最近24小時成交', + 'sellOrder.tradesUnit': '筆', + 'sellOrder.confirmList': '確認掛單', + 'sellOrder.success': '掛單成功', + 'sellOrder.successHint': '您的券已掛到市場,當有買家下單時將自動成交。', + 'sellOrder.ok': '確定', + + // ============ Trading Page ============ + 'tradingPage.title': '我的交易', + 'tradingPage.pendingOrders': '我的掛單', + 'tradingPage.tradeRecords': '交易紀錄', + 'tradingPage.listPrice': '掛單價', + 'tradingPage.listTime': '掛單時間', + 'tradingPage.cancelOrder': '撤單', + 'tradingPage.buy': '買入', + 'tradingPage.sell': '賣出', + + // ============ Transfer ============ + 'transfer.title': '轉贈給好友', + 'transfer.searchFriend': '搜尋好友(手機號/使用者名稱)', + 'transfer.confirmTransfer': '確認轉贈', + 'transfer.success': '轉贈成功', + 'transfer.confirm': '確定', + 'transfer.cancel': '取消', + + // ============ Wallet ============ + 'wallet.myBalance': '我的餘額', + 'wallet.totalBalance': '總餘額', + 'wallet.withdrawable': '可提現', + 'wallet.frozen': '凍結中', + 'wallet.deposit': '儲值', + 'wallet.withdraw': '提現', + 'wallet.records': '交易紀錄', + 'wallet.filter': '篩選', + 'wallet.buyIn': '買入', + 'wallet.sellOut': '賣出', + 'wallet.giftTransfer': '轉贈', + 'wallet.redeemUse': '核銷', + + 'deposit.title': '儲值', + 'deposit.currentBalance': '目前餘額', + 'deposit.amount': '儲值金額', + 'deposit.custom': '自訂金額', + 'deposit.paymentMethod': '支付方式', + 'deposit.submit': '儲值', + + 'withdraw.title': '提現', + 'withdraw.availableBalance': '可提現餘額', + 'withdraw.amount': '提現金額', + 'withdraw.all': '全部', + 'withdraw.to': '提現到', + 'withdraw.savingsAccount': '儲蓄帳戶', + 'withdraw.fee': '手續費 (0.5%)', + 'withdraw.actualReceive': '實際到帳', + 'withdraw.estimateTime': '預計 1-2 個工作日到帳', + 'withdraw.submit': '確認提現', + + 'txRecords.title': '交易紀錄', + 'txRecords.all': '全部', + 'txRecords.buy': '購買', + 'txRecords.sell': '出售', + 'txRecords.transfer': '轉贈', + 'txRecords.noRecords': '暫無紀錄', + 'txRecords.orderNo': '訂單號', + 'txRecords.transferTo': '轉贈給', + + // ============ Profile ============ + 'profile.favorites': '收藏', + 'profile.orders': '訂單', + 'profile.coupons': '券', + 'profile.wallet': '錢包', + 'profile.account': '帳戶', + 'profile.trade': '交易', + 'profile.settings': '設定', + 'profile.holdCoupons': '持券', + 'profile.saved': '節省', + 'profile.credit': '信用', + 'profile.creditScore': '信用積分', + 'profile.myTrades': '我的交易', + 'profile.walletBalance': '錢包餘額', + 'profile.paymentManage': '支付管理', + 'profile.kyc': '身分認證', + 'profile.proMode': '進階模式', + 'profile.myFavorites': '我的收藏', + 'profile.securitySettings': '安全設定', + 'profile.advancedSettings': '進階設定', + 'profile.aboutGenex': '關於 Genex', + 'profile.helpCenter': '幫助中心', + 'profile.issuerPortal': '發行方入口', + 'profile.merchantPortal': '商戶入口', + 'profile.simplifiedChinese': '簡體中文', + 'profile.logout': '登出', + + // ============ Settings ============ + 'settings.title': '設定', + 'settings.accountSecurity': '帳號與安全', + 'settings.phone': '手機號', + 'settings.email': '信箱', + 'settings.changePassword': '修改密碼', + 'settings.identity': '身分認證', + 'settings.paymentManage': '支付管理', + 'settings.paymentMethod': '支付方式', + 'settings.bankAccount': '銀行帳戶', + 'settings.paymentPassword': '支付密碼', + 'settings.notifications': '通知設定', + 'settings.tradeNotify': '交易通知', + 'settings.expiryRemind': '到期提醒', + 'settings.marketChange': '行情變動', + 'settings.marketingPush': '行銷推播', + 'settings.general': '一般', + 'settings.language': '語言', + 'settings.currency': '貨幣', + 'settings.clearCache': '清除快取', + 'settings.about': '關於', + 'settings.version': '版本', + 'settings.userAgreement': '使用者協議', + 'settings.privacyPolicy': '隱私權政策', + 'settings.helpCenter': '幫助中心', + 'settings.logout': '登出', + 'settings.selectCurrency': '選擇計價貨幣', + 'settings.currencyNote': '此設定影響交易頁面中所有價格的計價貨幣顯示', + 'settings.selectLanguage': '選擇語言', + 'settings.currencySymbol': '符號', + + // ============ KYC ============ + 'kyc.title': '身分認證', + 'kyc.currentLevel': '目前認證等級', + 'kyc.l1Title': 'L1 基礎認證', + 'kyc.l1Desc': '手機號 + 信箱驗證', + 'kyc.l1Limit': '每日購買限額 \$500', + 'kyc.l1Feature': '可購買券、出示核銷', + 'kyc.l2Title': 'L2 身分認證', + 'kyc.l2Desc': '身分證/護照驗證', + 'kyc.l2Limit': '每日購買限額 \$5,000', + 'kyc.l2Feature': '解鎖二級市場交易、P2P轉贈', + 'kyc.l3Title': 'L3 進階認證', + 'kyc.l3Desc': '視訊面審 + 地址證明', + 'kyc.l3Limit': '無限額', + 'kyc.l3Feature': '解鎖大額交易、提現無限制', + 'kyc.completed': '已完成', + 'kyc.goVerify': '去認證', + 'kyc.badgeLabel': '認證', + + // ============ Payment Management ============ + 'payManage.title': '支付管理', + 'payManage.myCards': '我的銀行卡', + 'payManage.addCard': '新增銀行卡', + 'payManage.bankAccount': '銀行帳戶(提現用)', + 'payManage.paymentSecurity': '支付安全', + 'payManage.paymentPassword': '支付密碼', + 'payManage.passwordSet': '已設定', + 'payManage.biometricPay': '指紋/臉部辨識支付', + 'payManage.biometricEnabled': '已開啟', + 'payManage.noPasswordPay': '免密支付', + 'payManage.noPasswordLimit': '單筆≤\$10', + + // ============ AI Chat ============ + 'aiChat.title': 'AI 助手', + 'aiChat.greeting': '你好!我是 Genex AI 助手,可以幫你發現高性價比好券、比價分析、組合推薦。試試問我:', + 'aiChat.suggest1': '推薦適合我的券', + 'aiChat.suggest2': 'Starbucks 券值不值得買?', + 'aiChat.suggest3': '幫我做比價分析', + 'aiChat.suggest4': '我的券快到期了怎麼辦?', + 'aiChat.inputHint': '問我任何關於券的問題...', + 'aiChat.confirmAction': '確認執行', + 'aiChat.riskLow': '低風險', + 'aiChat.riskNormal': '需確認', + 'aiChat.riskHigh': '高風險', + + // ============ AI Fab ============ + 'aiFab.title': 'AI 助手', + 'aiFab.greeting': '你好!我是 Genex AI 助手,可以幫你管理券資產、查找優惠、分析價格。有什麼需要幫助的嗎?', + 'aiFab.inputHint': '輸入訊息...', + 'aiFab.suggest1': '幫我找高折扣券', + 'aiFab.suggest2': '我的券快到期了嗎?', + 'aiFab.suggest3': '推薦今日好券', + 'aiFab.suggest4': '分析我的券資產', + + // ============ Messages ============ + 'message.title': '訊息', + 'message.markAllRead': '全部已讀', + 'message.tabTrade': '交易', + 'message.tabExpiry': '到期', + 'message.tabAnnouncement': '公告', + 'message.detailTitle': '訊息詳情', + 'message.tradeNotify': '交易通知', + 'message.expiryRemind': '到期提醒', + 'message.systemNotify': '系統通知', + 'message.promoNotify': '活動推播', + 'message.tradeSuccess': '交易成功通知', + 'message.couponName': '券名稱', + 'message.faceValue': '面值', + 'message.payAmount': '支付金額', + 'message.orderNo': '訂單號', + 'message.payMethod': '支付方式', + 'message.viewCouponDetail': '查看券詳情', + + // ============ Status Tags ============ + 'status.active': '可使用', + 'status.pending': '待核銷', + 'status.expired': '已過期', + 'status.used': '已使用', + 'status.processing': '處理中', + 'status.completed': '已完成', + 'status.cancelled': '已取消', + 'status.refunding': '退款中', + 'status.onSale': '出售中', + + // ============ Empty States ============ + 'empty.noCoupons': '還沒有券', + 'empty.noCouponsHint': '去市場看看有什麼好券吧', + 'empty.browse': '去逛逛', + 'empty.noTrades': '暫無交易紀錄', + 'empty.noTradesHint': '完成首筆交易後這裡會顯示紀錄', + 'empty.noResults': '沒有找到結果', + 'empty.noResultsHint': '換個關鍵字試試', + 'empty.noMessages': '暫無訊息', + 'empty.noMessagesHint': '交易通知和系統公告會顯示在這裡', + 'empty.networkError': '網路連線失敗', + 'empty.networkErrorHint': '請檢查網路設定後重試', + + // ============ Coupon Card (shared widget) ============ + 'couponCard.expiredText': '已過期', + 'couponCard.expiringToday': '今天到期', + 'couponCard.daysToExpiry': '天後到期', + 'couponCard.expiryFormat': '到期', + + // ============ Issuer ============ + 'issuer.title': '發行方管理', + 'issuer.verified': '已認證發行方', + 'issuer.overview': '總覽', + 'issuer.issue': '發券', + 'issuer.redeem': '核銷', + 'issuer.finance': '財務', + 'issuer.more': '更多', + 'issuer.totalIssued': '發行總量', + 'issuer.totalSold': '已售出', + 'issuer.totalRedeemed': '已核銷', + 'issuer.redeemRate': '核銷率', + 'issuer.quickActions': '快捷操作', + 'issuer.createCoupon': '建立券', + 'issuer.storeManage': '門市管理', + 'issuer.salesAnalysis': '銷售分析', + 'issuer.statement': '對帳單', + 'issuer.myCoupons': '我的券', + 'issuer.listed': '已上架', + 'issuer.underReview': '審核中', + 'issuer.soldOut': '已售罄', + 'issuer.unlisted': '已下架', + 'issuer.issuedSlash': '發行', + 'issuer.sold': '已售', + 'issuer.issueCenter': '發券中心', + 'issuer.selectTemplate': '選擇券範本', + 'issuer.voucherType': '滿減券', + 'issuer.discountType': '折扣券', + 'issuer.giftCardType': '禮品卡', + 'issuer.storedValueType': '儲值券', + 'issuer.couponManage': '券管理', + 'issuer.viewAll': '查看全部', + 'issuer.couponEvents': '券活動', + 'issuer.createNew': '建立新券', + 'issuer.redeemManage': '核銷管理', + 'issuer.redeemTrend': '核銷趨勢', + 'issuer.allStores': '全部門市', + 'issuer.employees': '名員工', + 'issuer.financeManage': '財務管理', + 'issuer.totalSales': '總銷售額', + 'issuer.settled': '已到帳', + 'issuer.pendingSettle': '待結算', + 'issuer.breakage': 'Breakage', + 'issuer.withdrawBtn': '提現', + 'issuer.reportBtn': '對帳報表', + 'issuer.settleDetail': '結算明細', + 'issuer.creditLevel': '信用等級', + 'issuer.issueQuota': '發行額度', + 'issuer.usedQuota': '已用額度', + 'issuer.dataCenter': '數據中心', + 'issuer.issueSalesRate': '發行量/銷量/兌付率', + 'issuer.userProfile': '使用者畫像', + 'issuer.userProfileDesc': '購買使用者分佈分析', + 'issuer.creditDetail': '信用詳情', + 'issuer.creditDetailDesc': '評分詳情與提升建議', + 'issuer.quotaChange': '額度變動', + 'issuer.quotaChangeDesc': '歷史額度調整紀錄', + 'issuer.companyInfo': '企業資訊', + 'issuer.companyInfoDesc': '營業執照/聯絡人', + 'issuer.settingsItem': '設定', + 'issuer.settingsItemDesc': '通知/安全/語言', + 'issuer.helpItem': '幫助中心', + 'issuer.helpItemDesc': '常見問題與客服', + + // ============ Merchant ============ + 'merchant.today': '今日', + 'merchant.onlineMode': '線上模式', + 'merchant.offlineMode': '離線模式', + 'merchant.pendingSync': '待同步', + 'merchant.syncUnit': '筆', + 'merchant.scanHint': '將券二維碼對準掃描框', + 'merchant.flashlight': '手電筒', + 'merchant.manualInput': '手動輸碼', + 'merchant.redeemRecords': '核銷紀錄', + 'merchant.storeData': '門市數據', + 'merchant.inputCode': '手動輸入券碼', + 'merchant.inputCodeHint': '請輸入券碼', + 'merchant.query': '查詢', + 'merchant.userNickname': '使用者暱稱', + 'merchant.consumer': '消費者', + 'merchant.couponName': '券名稱', + 'merchant.faceValue': '面值', + 'merchant.validUntil': '有效期', + 'merchant.useCondition': '使用條件', + 'merchant.noMinSpend': '無最低消費', + 'merchant.confirmRedeem': '確認核銷', + 'merchant.redeemSuccess': '核銷成功', + 'merchant.continueRedeem': '繼續核銷', + 'merchant.synced': '已同步', + 'merchant.pendingSyncLabel': '待同步', + 'merchant.redeemOperator': '核銷員', + 'merchant.todayRedeem': '今日核銷', + 'merchant.redeemAmount': '核銷金額', + 'merchant.weekTrend': '本週趨勢', + 'merchant.operatorRank': '核銷員排行', + + // ============ Merchant AI ============ + 'merchantAi.title': 'AI 智能助手', + 'merchantAi.redeemAssist': '核銷輔助', + 'merchantAi.trafficForecast': '客流預測', + 'merchantAi.anomalyAlert': '異常預警', + 'merchantAi.verifyAuth': '驗券真偽', + 'merchantAi.checkStatus': '查券狀態', + 'merchantAi.batchRedeem': '批量核銷', + 'merchantAi.feedback': '問題回報', + 'merchantAi.quickActions': 'AI 快捷操作', + 'merchantAi.redeemTips': '核銷提示', + 'merchantAi.todayHotRedeem': '今日熱門核銷', + 'merchantAi.countUnit': '筆', + 'merchantAi.aiMarketing': 'AI 行銷建議', + 'merchantAi.crossSellTitle': '推薦搭配銷售', + 'merchantAi.crossSellDesc': '購買咖啡券的顧客同時對糕點券感興趣,建議推薦組合', + 'merchantAi.weekendPromoTitle': '週末促銷建議', + 'merchantAi.weekendPromoDesc': '歷史數據顯示週六核銷量+30%,建議推出週末限時活動', + 'merchantAi.todayForecast': '今日客流預測', + 'merchantAi.expectedRedeem': '預計核銷', + 'merchantAi.peakHours': '高峰時段', + 'merchantAi.expectedRevenue': '預計收入', + 'merchantAi.trafficInsight': '較上週同期增長12%,建議午間增加1名收銀員', + 'merchantAi.hourlyForecast': '分時段預測', + 'merchantAi.weeklyForecast': '本週預測', + 'merchantAi.staffSuggestion': '排班建議', + 'merchantAi.pendingCount': '待處理', + 'merchantAi.resolvedToday': '今日已處理', + 'merchantAi.riskIndex': '風險指數', + 'merchantAi.riskLow': '低', + 'merchantAi.activeAlerts': '活躍預警', + 'merchantAi.highFreqRedeem': '高頻核銷檢測', + 'merchantAi.suspectFakeCode': '疑似偽造券碼', + 'merchantAi.suspiciousPatterns': '可疑模式檢測', + 'merchantAi.consecutiveRedeem': '同一使用者連續核銷', + 'merchantAi.offHoursRedeem': '非營業時間核銷嘗試', + 'merchantAi.expiredRedeemAttempt': '過期券核銷嘗試', + 'merchantAi.statusAbnormal': '異常', + 'merchantAi.statusWarning': '注意', + 'merchantAi.statusNormal': '正常', + 'merchantAi.expiredBlock': '過期券核銷攔截', + 'merchantAi.duplicateBlock': '重複核銷攔截', + 'merchantAi.wrongStoreAlert': '非本店券提醒', + 'merchantAi.insufficientBalance': '餘額不足核銷', + 'merchantAi.systemRetry': '系統逾時重試', + 'merchantAi.monday': '週一', + 'merchantAi.tuesday': '週二', + 'merchantAi.wednesday': '週三', + 'merchantAi.thursday': '週四', + 'merchantAi.friday': '週五', + 'merchantAi.saturday': '週六', + 'merchantAi.sunday': '週日', + + // ============ Pro Mode ============ + 'proMode.title': '高級模式', + 'proMode.toggleDesc': '開啟後可查看鏈上資訊和連接外部錢包', + 'proMode.requireKycL2': '需要 KYC L2 及以上認證', + 'proMode.connected': '已連接', + 'proMode.disconnect': '斷開', + 'proMode.connectWallet': '連接外部錢包', + 'proMode.walletDesc': '連接外部錢包後可將平台資產提取至自有地址', + 'proMode.showChainAddress': '顯示鏈上地址', + 'proMode.showChainAddressDesc': '在券詳情中展示合約地址', + 'proMode.showTxHash': '顯示交易Hash', + 'proMode.showTxHashDesc': '在交易記錄中展示鏈上Hash', + 'proMode.txExplorer': '交易瀏覽器', + 'proMode.txBuyExample': '購買 星巴克 \$25 禮品卡', + 'proMode.txSellExample': '出售 Amazon \$100 券', + 'proMode.confirmed': '已確認', + 'proMode.confirming': '確認中', + 'proMode.viewAllTx': '查看全部鏈上交易', + 'proMode.chainAssets': '鏈上資產', + 'proMode.custodialWallet': '平台託管錢包', + 'proMode.externalWallet': '外部錢包 (MetaMask)', + 'proMode.couponCount5': '5 張券', + 'proMode.couponCount0': '0 張券', + 'proMode.extractToWallet': '提取至外部錢包', + 'proMode.tradeTrack': '交易軌道', + 'proMode.utilityTrackDesc': '券有效期≤12個月,無需證券牌照', + 'proMode.securitiesTrackDesc': '長期投資型券產品(即將推出)', + 'proMode.mvpNote': '當前MVP版本僅支持Utility Track', + 'proMode.comingSoon': '敬請期待', + 'proMode.whatIsTitle': '什麼是高級模式?', + 'proMode.whatIsDesc': '高級模式面向有區塊鏈經驗的使用者,開啟後可以:\n' + '• 連接外部錢包(MetaMask等)\n' + '• 查看鏈上地址和交易Hash\n' + '• 將資產提取至自有錢包\n' + '• 查看底層鏈上數據\n\n' + '需要完成 KYC L2 認證後方可開啟。', + + // ============ Receive Coupon ============ + 'receiveCoupon.title': '接收券', + 'receiveCoupon.hint': '向他人展示下方二維碼或接收ID,對方可透過掃碼或輸入ID將券轉贈到你的錢包。', + 'receiveCoupon.id': '接收ID', + 'receiveCoupon.idCopied': '接收ID已複製到剪貼簿', + 'receiveCoupon.note': '接收的券將自動存入你的錢包,可在首頁錢包中查看和管理。', +}; diff --git a/frontend/mobile/lib/app/main_shell.dart b/frontend/mobile/lib/app/main_shell.dart index 0825b2c..a110c96 100644 --- a/frontend/mobile/lib/app/main_shell.dart +++ b/frontend/mobile/lib/app/main_shell.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../app/i18n/app_localizations.dart'; import '../app/theme/app_colors.dart'; import '../app/theme/app_typography.dart'; import '../features/coupons/presentation/pages/home_page.dart'; @@ -44,20 +45,20 @@ class _MainShellState extends State { selectedIndex: _currentIndex, onDestinationSelected: (index) => setState(() => _currentIndex = index), destinations: [ - _buildDestination(Icons.home_rounded, Icons.home_outlined, '首页'), - _buildDestination(Icons.storefront_rounded, Icons.storefront_outlined, '市场'), + _buildDestination(Icons.home_rounded, Icons.home_outlined, context.t('nav.home')), + _buildDestination(Icons.storefront_rounded, Icons.storefront_outlined, context.t('nav.market')), _buildDestination( Icons.confirmation_number_rounded, Icons.confirmation_number_outlined, - '我的券', + context.t('nav.myCoupons'), ), _buildBadgeDestination( Icons.notifications_rounded, Icons.notifications_outlined, - '消息', + context.t('nav.messages'), 2, ), - _buildDestination(Icons.person_rounded, Icons.person_outlined, '我的'), + _buildDestination(Icons.person_rounded, Icons.person_outlined, context.t('nav.profile')), ], ), ), diff --git a/frontend/mobile/lib/features/ai_agent/presentation/pages/agent_chat_page.dart b/frontend/mobile/lib/features/ai_agent/presentation/pages/agent_chat_page.dart index c179647..efdadba 100644 --- a/frontend/mobile/lib/features/ai_agent/presentation/pages/agent_chat_page.dart +++ b/frontend/mobile/lib/features/ai_agent/presentation/pages/agent_chat_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -16,21 +17,38 @@ class AgentChatPage extends StatefulWidget { class _AgentChatPageState extends State { final _controller = TextEditingController(); final _scrollController = ScrollController(); - final List<_Msg> _messages = [ - _Msg(true, '你好!我是 Genex AI 助手,可以帮你发现高性价比好券、比价分析、组合推荐。试试问我:'), - ]; - final _suggestions = ['推荐适合我的券', '星巴克券值不值得买?', '帮我做比价分析', '我的券快到期了怎么办?']; + late final List<_Msg> _messages; + late final List _suggestions; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + if (!_initialized) { + _messages = [ + _Msg(true, context.t('aiChat.greeting')), + ]; + _suggestions = [ + context.t('aiChat.suggest1'), + context.t('aiChat.suggest2'), + context.t('aiChat.suggest3'), + context.t('aiChat.suggest4'), + ]; + _initialized = true; + } + } + + bool _initialized = false; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Row( + title: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), - SizedBox(width: 8), - Text('AI 助手'), + const Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), + const SizedBox(width: 8), + Text(context.t('aiChat.title')), ], ), actions: [ @@ -79,7 +97,7 @@ class _AgentChatPageState extends State { child: TextField( controller: _controller, decoration: InputDecoration( - hintText: '问我任何关于券的问题...', + hintText: context.t('aiChat.inputHint'), border: OutlineInputBorder( borderRadius: AppSpacing.borderRadiusFull, borderSide: const BorderSide(color: AppColors.borderLight), @@ -157,7 +175,7 @@ class _AgentChatPageState extends State { Future.delayed(const Duration(milliseconds: 800), () { if (mounted) { setState(() { - _messages.add(_Msg(true, '根据您的偏好和消费习惯,推荐以下高性价比券:\n\n1. 星巴克 \$25 礼品卡 - 当前售价 \$21.25(8.5折),信用AAA\n2. Amazon \$100 购物券 - 当前售价 \$85(8.5折),信用AA\n\n这两张券的折扣率在同类中最优,且发行方信用等级高。')); + _messages.add(_Msg(true, 'Based on your preferences, here are some great coupon recommendations:\n\n1. Starbucks \$25 Gift Card - \$21.25 (85% off), Credit AAA\n2. Amazon \$100 Voucher - \$85 (85% off), Credit AA\n\nThese coupons offer the best discount rates in their category with high issuer credit ratings.')); }); } }); diff --git a/frontend/mobile/lib/features/ai_agent/presentation/widgets/ai_fab.dart b/frontend/mobile/lib/features/ai_agent/presentation/widgets/ai_fab.dart index 6119fb2..e81addc 100644 --- a/frontend/mobile/lib/features/ai_agent/presentation/widgets/ai_fab.dart +++ b/frontend/mobile/lib/features/ai_agent/presentation/widgets/ai_fab.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -120,7 +121,7 @@ class AiChatPanel extends StatelessWidget { ), ), const SizedBox(width: 10), - Text('AI 助手', style: AppTypography.h3), + Text(context.t('aiFab.title'), style: AppTypography.h3), const Spacer(), IconButton( icon: const Icon(Icons.close_rounded, size: 22), @@ -139,11 +140,9 @@ class AiChatPanel extends StatelessWidget { controller: scrollController, padding: const EdgeInsets.all(20), children: [ - _buildAiMessage( - '你好!我是 Genex AI 助手,可以帮你管理券资产、查找优惠、分析价格。有什么需要帮助的吗?', - ), + _buildAiMessage(context.t('aiFab.greeting')), const SizedBox(height: 12), - _buildSuggestionChips(), + _buildSuggestionChips(context), ], ), ), @@ -171,7 +170,7 @@ class AiChatPanel extends StatelessWidget { Expanded( child: TextField( decoration: InputDecoration( - hintText: '输入消息...', + hintText: context.t('aiFab.inputHint'), hintStyle: AppTypography.bodyMedium .copyWith(color: AppColors.textTertiary), border: InputBorder.none, @@ -251,12 +250,12 @@ class AiChatPanel extends StatelessWidget { ); } - Widget _buildSuggestionChips() { + Widget _buildSuggestionChips(BuildContext context) { final suggestions = [ - '帮我找高折扣券', - '我的券快到期了吗?', - '推荐今日好券', - '分析我的券资产', + context.t('aiFab.suggest1'), + context.t('aiFab.suggest2'), + context.t('aiFab.suggest3'), + context.t('aiFab.suggest4'), ]; return Wrap( diff --git a/frontend/mobile/lib/features/auth/presentation/pages/forgot_password_page.dart b/frontend/mobile/lib/features/auth/presentation/pages/forgot_password_page.dart index 8c9b32b..64e334b 100644 --- a/frontend/mobile/lib/features/auth/presentation/pages/forgot_password_page.dart +++ b/frontend/mobile/lib/features/auth/presentation/pages/forgot_password_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -36,7 +37,7 @@ class _ForgotPasswordPageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(_step == 3 ? '' : '找回密码'), + title: Text(_step == 3 ? '' : context.t('forgot.title')), leading: _step == 3 ? const SizedBox.shrink() : IconButton( @@ -79,21 +80,21 @@ class _ForgotPasswordPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 24), - Text('输入手机号或邮箱', style: AppTypography.h1), + Text(context.t('forgot.inputAccount'), style: AppTypography.h1), const SizedBox(height: 8), - Text('我们将向您发送验证码', style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)), + Text(context.t('forgot.sendHint'), style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)), const SizedBox(height: 32), TextField( controller: _phoneController, keyboardType: TextInputType.phone, - decoration: const InputDecoration( - hintText: '手机号 / 邮箱地址', + decoration: InputDecoration( + hintText: context.t('forgot.accountHint'), prefixIcon: Icon(Icons.person_outline_rounded), ), ), const SizedBox(height: 24), GenexButton( - label: '获取验证码', + label: context.t('forgot.getCode'), onPressed: () => setState(() => _step = 1), ), ], @@ -105,18 +106,18 @@ class _ForgotPasswordPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 24), - Text('输入验证码', style: AppTypography.h1), + Text(context.t('forgot.inputCode'), style: AppTypography.h1), const SizedBox(height: 8), Text( - '验证码已发送至 ${_phoneController.text.isNotEmpty ? _phoneController.text : '***'}', + '${context.t('forgot.codeSentTo')} ${_phoneController.text.isNotEmpty ? _phoneController.text : '***'}', style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary), ), const SizedBox(height: 32), TextField( controller: _codeController, keyboardType: TextInputType.number, - decoration: const InputDecoration( - hintText: '6位验证码', + decoration: InputDecoration( + hintText: context.t('forgot.codeHint'), prefixIcon: Icon(Icons.lock_outline_rounded), ), ), @@ -125,12 +126,12 @@ class _ForgotPasswordPageState extends State { alignment: Alignment.centerRight, child: TextButton( onPressed: () {}, - child: const Text('重新发送'), + child: Text(context.t('forgot.resend')), ), ), const SizedBox(height: 8), GenexButton( - label: '下一步', + label: context.t('forgot.next'), onPressed: () => setState(() => _step = 2), ), ], @@ -142,15 +143,15 @@ class _ForgotPasswordPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 24), - Text('设置新密码', style: AppTypography.h1), + Text(context.t('forgot.setNewPassword'), style: AppTypography.h1), const SizedBox(height: 8), - Text('请输入新密码(8位以上)', style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)), + Text(context.t('forgot.newPasswordHint'), style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)), const SizedBox(height: 32), TextField( controller: _passwordController, obscureText: _obscurePassword, decoration: InputDecoration( - hintText: '新密码', + hintText: context.t('forgot.newPassword'), prefixIcon: const Icon(Icons.lock_outline_rounded), suffixIcon: IconButton( icon: Icon(_obscurePassword ? Icons.visibility_off_outlined : Icons.visibility_outlined), @@ -163,7 +164,7 @@ class _ForgotPasswordPageState extends State { controller: _confirmController, obscureText: _obscureConfirm, decoration: InputDecoration( - hintText: '确认新密码', + hintText: context.t('forgot.confirmPassword'), prefixIcon: const Icon(Icons.lock_outline_rounded), suffixIcon: IconButton( icon: Icon(_obscureConfirm ? Icons.visibility_off_outlined : Icons.visibility_outlined), @@ -173,7 +174,7 @@ class _ForgotPasswordPageState extends State { ), const SizedBox(height: 24), GenexButton( - label: '确认修改', + label: context.t('forgot.confirmChange'), onPressed: () => setState(() => _step = 3), ), ], @@ -195,14 +196,14 @@ class _ForgotPasswordPageState extends State { child: const Icon(Icons.check_rounded, color: AppColors.success, size: 40), ), const SizedBox(height: 24), - Text('密码修改成功', style: AppTypography.h1), + Text(context.t('forgot.success'), style: AppTypography.h1), const SizedBox(height: 8), - Text('请使用新密码登录', style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)), + Text(context.t('forgot.successHint'), style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)), const SizedBox(height: 40), SizedBox( width: double.infinity, child: GenexButton( - label: '返回登录', + label: context.t('forgot.backToLogin'), onPressed: () => Navigator.of(context).pushNamedAndRemoveUntil('/login', (_) => false), ), ), diff --git a/frontend/mobile/lib/features/auth/presentation/pages/login_page.dart b/frontend/mobile/lib/features/auth/presentation/pages/login_page.dart index 90b0b41..d522365 100644 --- a/frontend/mobile/lib/features/auth/presentation/pages/login_page.dart +++ b/frontend/mobile/lib/features/auth/presentation/pages/login_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -50,10 +51,10 @@ class _LoginPageState extends State with SingleTickerProviderStateMix crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 16), - Text('欢迎回来', style: AppTypography.displayMedium), + Text(context.t('login.title'), style: AppTypography.displayMedium), const SizedBox(height: 8), Text( - '登录 Genex 管理你的券资产', + context.t('login.subtitle'), style: AppTypography.bodyLarge.copyWith(color: AppColors.textSecondary), ), const SizedBox(height: 32), @@ -76,9 +77,9 @@ class _LoginPageState extends State with SingleTickerProviderStateMix labelColor: AppColors.textPrimary, unselectedLabelColor: AppColors.textTertiary, labelStyle: AppTypography.labelMedium, - tabs: const [ - Tab(text: '密码登录'), - Tab(text: '验证码登录'), + tabs: [ + Tab(text: context.t('login.passwordTab')), + Tab(text: context.t('login.codeTab')), ], ), ), @@ -107,8 +108,8 @@ class _LoginPageState extends State with SingleTickerProviderStateMix TextField( controller: _phoneController, keyboardType: TextInputType.phone, - decoration: const InputDecoration( - hintText: '手机号或邮箱', + decoration: InputDecoration( + hintText: context.t('login.phoneOrEmail'), prefixIcon: Icon(Icons.person_outline_rounded, color: AppColors.textTertiary), ), ), @@ -119,7 +120,7 @@ class _LoginPageState extends State with SingleTickerProviderStateMix controller: _passwordController, obscureText: _obscurePassword, decoration: InputDecoration( - hintText: '密码', + hintText: context.t('login.password'), prefixIcon: const Icon(Icons.lock_outline_rounded, color: AppColors.textTertiary), suffixIcon: IconButton( icon: Icon( @@ -140,7 +141,7 @@ class _LoginPageState extends State with SingleTickerProviderStateMix onTap: () { Navigator.pushNamed(context, '/forgot-password'); }, - child: Text('忘记密码?', style: AppTypography.labelSmall.copyWith( + child: Text(context.t('login.forgotPassword'), style: AppTypography.labelSmall.copyWith( color: AppColors.primary, )), ), @@ -149,7 +150,7 @@ class _LoginPageState extends State with SingleTickerProviderStateMix // Login Button GenexButton( - label: '登录', + label: context.t('login.submit'), onPressed: () { Navigator.pushReplacementNamed(context, '/main'); }, @@ -164,8 +165,8 @@ class _LoginPageState extends State with SingleTickerProviderStateMix // Phone Input TextField( keyboardType: TextInputType.phone, - decoration: const InputDecoration( - hintText: '手机号', + decoration: InputDecoration( + hintText: context.t('login.phone'), prefixIcon: Icon(Icons.phone_android_rounded, color: AppColors.textTertiary), ), ), @@ -178,8 +179,8 @@ class _LoginPageState extends State with SingleTickerProviderStateMix child: TextField( controller: _codeController, keyboardType: TextInputType.number, - decoration: const InputDecoration( - hintText: '验证码', + decoration: InputDecoration( + hintText: context.t('login.verifyCode'), prefixIcon: Icon(Icons.shield_outlined, color: AppColors.textTertiary), ), ), @@ -188,7 +189,7 @@ class _LoginPageState extends State with SingleTickerProviderStateMix SizedBox( height: AppSpacing.inputHeight, child: GenexButton( - label: '获取验证码', + label: context.t('login.getCode'), variant: GenexButtonVariant.secondary, size: GenexButtonSize.medium, fullWidth: false, @@ -202,7 +203,7 @@ class _LoginPageState extends State with SingleTickerProviderStateMix const SizedBox(height: 24), GenexButton( - label: '登录', + label: context.t('login.submit'), onPressed: () { Navigator.pushReplacementNamed(context, '/main'); }, diff --git a/frontend/mobile/lib/features/auth/presentation/pages/register_page.dart b/frontend/mobile/lib/features/auth/presentation/pages/register_page.dart index 697fd2c..bd438b1 100644 --- a/frontend/mobile/lib/features/auth/presentation/pages/register_page.dart +++ b/frontend/mobile/lib/features/auth/presentation/pages/register_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -48,10 +49,10 @@ class _RegisterPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 16), - Text('创建账号', style: AppTypography.displayMedium), + Text(context.t('register.title'), style: AppTypography.displayMedium), const SizedBox(height: 8), Text( - widget.isEmail ? '使用邮箱注册 Genex 账号' : '使用手机号注册 Genex 账号', + widget.isEmail ? context.t('register.emailSubtitle') : context.t('register.phoneSubtitle'), style: AppTypography.bodyLarge.copyWith(color: AppColors.textSecondary), ), const SizedBox(height: 40), @@ -62,7 +63,7 @@ class _RegisterPageState extends State { // Account Input (Phone/Email) Text( - widget.isEmail ? '邮箱地址' : '手机号', + widget.isEmail ? context.t('register.email') : context.t('register.phone'), style: AppTypography.labelMedium, ), const SizedBox(height: 8), @@ -71,7 +72,7 @@ class _RegisterPageState extends State { keyboardType: widget.isEmail ? TextInputType.emailAddress : TextInputType.phone, decoration: InputDecoration( - hintText: widget.isEmail ? '请输入邮箱地址' : '请输入手机号', + hintText: widget.isEmail ? context.t('register.emailHint') : context.t('register.phoneHint'), prefixIcon: Icon( widget.isEmail ? Icons.email_outlined : Icons.phone_android_rounded, color: AppColors.textTertiary, @@ -81,7 +82,7 @@ class _RegisterPageState extends State { const SizedBox(height: 20), // Verification Code - Text('验证码', style: AppTypography.labelMedium), + Text(context.t('register.code'), style: AppTypography.labelMedium), const SizedBox(height: 8), Row( children: [ @@ -90,8 +91,8 @@ class _RegisterPageState extends State { controller: _codeController, keyboardType: TextInputType.number, maxLength: 6, - decoration: const InputDecoration( - hintText: '请输入6位验证码', + decoration: InputDecoration( + hintText: context.t('register.codeHint'), counterText: '', prefixIcon: Icon(Icons.shield_outlined, color: AppColors.textTertiary), ), @@ -101,7 +102,7 @@ class _RegisterPageState extends State { SizedBox( height: AppSpacing.inputHeight, child: GenexButton( - label: '获取验证码', + label: context.t('register.getCode'), variant: GenexButtonVariant.secondary, size: GenexButtonSize.medium, fullWidth: false, @@ -113,13 +114,13 @@ class _RegisterPageState extends State { const SizedBox(height: 20), // Password - Text('设置密码', style: AppTypography.labelMedium), + Text(context.t('register.setPassword'), style: AppTypography.labelMedium), const SizedBox(height: 8), TextField( controller: _passwordController, obscureText: _obscurePassword, decoration: InputDecoration( - hintText: '8-20位,含字母和数字', + hintText: context.t('register.passwordHint'), prefixIcon: const Icon(Icons.lock_outline_rounded, color: AppColors.textTertiary), suffixIcon: IconButton( icon: Icon( @@ -159,14 +160,14 @@ class _RegisterPageState extends State { text: TextSpan( style: AppTypography.bodySmall, children: [ - const TextSpan(text: '我已阅读并同意 '), + TextSpan(text: '${context.t('register.agreement')} '), TextSpan( - text: '《用户协议》', + text: context.t('register.userAgreement'), style: AppTypography.bodySmall.copyWith(color: AppColors.primary), ), - const TextSpan(text: ' 和 '), + const TextSpan(text: ' & '), TextSpan( - text: '《隐私政策》', + text: context.t('register.privacyPolicy'), style: AppTypography.bodySmall.copyWith(color: AppColors.primary), ), ], @@ -180,7 +181,7 @@ class _RegisterPageState extends State { // Register Button GenexButton( - label: '注册', + label: context.t('register.submit'), onPressed: _agreeTerms ? () { Navigator.pushReplacementNamed(context, '/main'); } : null, @@ -196,11 +197,11 @@ class _RegisterPageState extends State { Widget _buildStepIndicator() { return Row( children: [ - _buildStep(1, '验证', true), + _buildStep(1, context.t('register.stepVerify'), true), _buildStepLine(true), - _buildStep(2, '设密码', true), + _buildStep(2, context.t('register.stepPassword'), true), _buildStepLine(false), - _buildStep(3, '完成', false), + _buildStep(3, context.t('register.stepDone'), false), ], ); } @@ -255,11 +256,11 @@ class _RegisterPageState extends State { return Row( children: [ - _buildCheck('8位以上', hasLength), + _buildCheck(context.t('register.rule8chars'), hasLength), const SizedBox(width: 16), - _buildCheck('含字母', hasLetter), + _buildCheck(context.t('register.ruleLetter'), hasLetter), const SizedBox(width: 16), - _buildCheck('含数字', hasDigit), + _buildCheck(context.t('register.ruleNumber'), hasDigit), ], ); } diff --git a/frontend/mobile/lib/features/auth/presentation/pages/welcome_page.dart b/frontend/mobile/lib/features/auth/presentation/pages/welcome_page.dart index c0800c5..f9fb4d4 100644 --- a/frontend/mobile/lib/features/auth/presentation/pages/welcome_page.dart +++ b/frontend/mobile/lib/features/auth/presentation/pages/welcome_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -49,7 +50,7 @@ class WelcomePage extends StatelessWidget { // Slogan Text( - '让每一张券都有价值', + context.t('welcome.slogan'), style: AppTypography.bodyLarge.copyWith( color: AppColors.textSecondary, ), @@ -59,7 +60,7 @@ class WelcomePage extends StatelessWidget { // Phone Register GenexButton( - label: '手机号注册', + label: context.t('welcome.phoneRegister'), icon: Icons.phone_android_rounded, onPressed: () { Navigator.pushNamed(context, '/register'); @@ -69,7 +70,7 @@ class WelcomePage extends StatelessWidget { // Email Register GenexButton( - label: '邮箱注册', + label: context.t('welcome.emailRegister'), icon: Icons.email_outlined, variant: GenexButtonVariant.outline, onPressed: () { @@ -84,7 +85,7 @@ class WelcomePage extends StatelessWidget { const Expanded(child: Divider(color: AppColors.border)), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), - child: Text('其他方式登录', style: AppTypography.caption), + child: Text(context.t('welcome.otherLogin'), style: AppTypography.caption), ), const Expanded(child: Divider(color: AppColors.border)), ], @@ -118,14 +119,14 @@ class WelcomePage extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text('已有账号?', style: AppTypography.bodyMedium.copyWith( + Text(context.t('welcome.hasAccount'), style: AppTypography.bodyMedium.copyWith( color: AppColors.textSecondary, )), GestureDetector( onTap: () { Navigator.pushNamed(context, '/login'); }, - child: Text('登录', style: AppTypography.labelMedium.copyWith( + child: Text(context.t('welcome.login'), style: AppTypography.labelMedium.copyWith( color: AppColors.primary, )), ), @@ -135,7 +136,7 @@ class WelcomePage extends StatelessWidget { // Terms Text( - '注册即表示同意《用户协议》和《隐私政策》', + context.t('welcome.agreement'), style: AppTypography.caption.copyWith(fontSize: 10), textAlign: TextAlign.center, ), diff --git a/frontend/mobile/lib/features/coupons/presentation/pages/coupon_detail_page.dart b/frontend/mobile/lib/features/coupons/presentation/pages/coupon_detail_page.dart index 7484832..5c77bc4 100644 --- a/frontend/mobile/lib/features/coupons/presentation/pages/coupon_detail_page.dart +++ b/frontend/mobile/lib/features/coupons/presentation/pages/coupon_detail_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -108,7 +109,7 @@ class CouponDetailPage extends StatelessWidget { ), const SizedBox(height: 8), Text( - '比面值节省 \$3.75', + '${context.t('couponDetail.saveBadge')} \$3.75', style: AppTypography.bodySmall.copyWith(color: AppColors.success), ), ], @@ -119,31 +120,31 @@ class CouponDetailPage extends StatelessWidget { // Info Cards Padding( padding: const EdgeInsets.fromLTRB(20, 16, 20, 0), - child: _buildInfoSection(), + child: _buildInfoSection(context), ), // Usage Rules Padding( padding: const EdgeInsets.fromLTRB(20, 16, 20, 0), - child: _buildUsageRules(), + child: _buildUsageRules(context), ), // Available Stores Padding( padding: const EdgeInsets.fromLTRB(20, 16, 20, 0), - child: _buildStores(), + child: _buildStores(context), ), // Price Trend (Optional) Padding( padding: const EdgeInsets.fromLTRB(20, 16, 20, 0), - child: _buildPriceTrend(), + child: _buildPriceTrend(context), ), // Similar Coupons Padding( padding: const EdgeInsets.fromLTRB(20, 24, 20, 0), - child: Text('同类券推荐', style: AppTypography.h3), + child: Text(context.t('couponDetail.similar'), style: AppTypography.h3), ), SizedBox( height: 180, @@ -177,7 +178,7 @@ class CouponDetailPage extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.favorite_border_rounded, color: AppColors.textTertiary, size: 22), - Text('收藏', style: AppTypography.caption), + Text(context.t('couponDetail.favorite'), style: AppTypography.caption), ], ), const SizedBox(width: 24), @@ -185,7 +186,7 @@ class CouponDetailPage extends StatelessWidget { // Buy Button Expanded( child: GenexButton( - label: '立即购买 \$21.25', + label: '${context.t('couponDetail.buyNow')} \$21.25', onPressed: () { Navigator.pushNamed(context, '/order/confirm'); }, @@ -211,12 +212,12 @@ class CouponDetailPage extends StatelessWidget { ); } - Widget _buildInfoSection() { + Widget _buildInfoSection(BuildContext context) { final items = [ - ('面值', '\$25.00'), - ('有效期', '2026/12/31'), - ('类型', '消费券'), - ('发行方', 'Starbucks Inc.'), + (context.t('couponDetail.faceValue'), '\$25.00'), + (context.t('couponDetail.validUntil'), '2026/12/31'), + (context.t('couponDetail.type'), context.t('couponDetail.consumeCoupon')), + (context.t('couponDetail.issuer'), 'Starbucks Inc.'), ]; return Container( @@ -251,7 +252,7 @@ class CouponDetailPage extends StatelessWidget { ); } - Widget _buildUsageRules() { + Widget _buildUsageRules(BuildContext context) { return Container( padding: AppSpacing.cardPadding, decoration: BoxDecoration( @@ -262,13 +263,13 @@ class CouponDetailPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('使用说明', style: AppTypography.labelMedium), + Text(context.t('couponDetail.usageNote'), style: AppTypography.labelMedium), const SizedBox(height: 12), - _buildRuleItem(Icons.check_circle_outline, '全国星巴克门店通用'), - _buildRuleItem(Icons.check_circle_outline, '可转赠给好友'), - _buildRuleItem(Icons.check_circle_outline, '有效期内随时使用'), - _buildRuleItem(Icons.info_outline_rounded, '不可叠加使用'), - _buildRuleItem(Icons.info_outline_rounded, '不可兑换现金'), + _buildRuleItem(Icons.check_circle_outline, context.t('couponDetail.allStores')), + _buildRuleItem(Icons.check_circle_outline, context.t('couponDetail.canTransfer')), + _buildRuleItem(Icons.check_circle_outline, context.t('couponDetail.useAnytime')), + _buildRuleItem(Icons.info_outline_rounded, context.t('couponDetail.noStack')), + _buildRuleItem(Icons.info_outline_rounded, context.t('couponDetail.noCash')), ], ), ); @@ -288,7 +289,7 @@ class CouponDetailPage extends StatelessWidget { ); } - Widget _buildStores() { + Widget _buildStores(BuildContext context) { return Container( padding: AppSpacing.cardPadding, decoration: BoxDecoration( @@ -302,15 +303,15 @@ class CouponDetailPage extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('使用门店', style: AppTypography.labelMedium), - Text('全国 12,800+ 门店', style: AppTypography.caption.copyWith( + Text(context.t('couponDetail.stores'), style: AppTypography.labelMedium), + Text(context.t('couponDetail.storeCount'), style: AppTypography.caption.copyWith( color: AppColors.primary, )), ], ), const SizedBox(height: 12), Text( - '支持全国所有星巴克直营门店使用', + context.t('couponDetail.storeDesc'), style: AppTypography.bodySmall, ), ], @@ -318,7 +319,7 @@ class CouponDetailPage extends StatelessWidget { ); } - Widget _buildPriceTrend() { + Widget _buildPriceTrend(BuildContext context) { return Container( padding: AppSpacing.cardPadding, decoration: BoxDecoration( @@ -332,8 +333,8 @@ class CouponDetailPage extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('价格走势', style: AppTypography.labelMedium), - Text('近30天', style: AppTypography.caption), + Text(context.t('couponDetail.priceTrend'), style: AppTypography.labelMedium), + Text(context.t('couponDetail.last30Days'), style: AppTypography.caption), ], ), const SizedBox(height: 16), @@ -346,7 +347,7 @@ class CouponDetailPage extends StatelessWidget { ), child: Center( child: Text( - '价格走势图 (fl_chart)', + '${context.t('couponDetail.priceTrend')} (fl_chart)', style: AppTypography.bodySmall.copyWith(color: AppColors.textTertiary), ), ), @@ -355,10 +356,10 @@ class CouponDetailPage extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _buildTrendStat('最高', '\$22.50', AppColors.error), - _buildTrendStat('最低', '\$20.00', AppColors.success), - _buildTrendStat('均价', '\$21.10', AppColors.textSecondary), - _buildTrendStat('历史成交', '1,234笔', AppColors.primary), + _buildTrendStat(context.t('couponDetail.highest'), '\$22.50', AppColors.error), + _buildTrendStat(context.t('couponDetail.lowest'), '\$20.00', AppColors.success), + _buildTrendStat(context.t('couponDetail.average'), '\$21.10', AppColors.textSecondary), + _buildTrendStat(context.t('couponDetail.tradeHistory'), '1,234', AppColors.primary), ], ), ], @@ -403,7 +404,7 @@ class CouponDetailPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('品牌 ${index + 1}', style: AppTypography.caption), + Text('Brand ${index + 1}', style: AppTypography.caption), const SizedBox(height: 2), Text('\$${(index + 1) * 8}.50', style: AppTypography.priceSmall.copyWith(fontSize: 14)), diff --git a/frontend/mobile/lib/features/coupons/presentation/pages/home_page.dart b/frontend/mobile/lib/features/coupons/presentation/pages/home_page.dart index e551760..8514a76 100644 --- a/frontend/mobile/lib/features/coupons/presentation/pages/home_page.dart +++ b/frontend/mobile/lib/features/coupons/presentation/pages/home_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -36,13 +37,13 @@ class HomePage extends StatelessWidget { ), // Banner Carousel - SliverToBoxAdapter(child: _buildBanner()), + SliverToBoxAdapter(child: _buildBanner(context)), // Category Grid - SliverToBoxAdapter(child: _buildCategoryGrid()), + SliverToBoxAdapter(child: _buildCategoryGrid(context)), // AI Smart Suggestions - SliverToBoxAdapter(child: _buildAiSuggestions()), + SliverToBoxAdapter(child: _buildAiSuggestions(context)), // Section: Featured Coupons SliverToBoxAdapter( @@ -51,10 +52,10 @@ class HomePage extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('精选好券', style: AppTypography.h2), + Text(context.t('home.featuredCoupons'), style: AppTypography.h2), GestureDetector( onTap: () {}, - child: Text('查看全部', style: AppTypography.labelSmall.copyWith( + child: Text(context.t('home.viewAllCoupons'), style: AppTypography.labelSmall.copyWith( color: AppColors.primary, )), ), @@ -125,7 +126,7 @@ class HomePage extends StatelessWidget { const Icon(Icons.search_rounded, size: 20, color: AppColors.textTertiary), const SizedBox(width: 8), Text( - '搜索券、品牌、分类...', + context.t('home.searchHint'), style: AppTypography.bodyMedium.copyWith(color: AppColors.textTertiary), ), ], @@ -134,7 +135,7 @@ class HomePage extends StatelessWidget { ); } - Widget _buildBanner() { + Widget _buildBanner(BuildContext context) { return Container( height: 160, margin: const EdgeInsets.fromLTRB(20, 8, 20, 0), @@ -146,8 +147,8 @@ class HomePage extends StatelessWidget { AppColors.successGradient, AppColors.cardGradient, ]; - final titles = ['新用户专享', '限时折扣', '热门推荐']; - final subtitles = ['首单立减 \$10', '全场低至7折', '精选高折扣券']; + final titleKeys = ['home.bannerNewUser', 'home.bannerDiscount', 'home.bannerHot']; + final subtitleKeys = ['home.bannerNewUserDesc', 'home.bannerDiscountDesc', 'home.bannerHotDesc']; return Container( margin: const EdgeInsets.symmetric(horizontal: 4), @@ -161,12 +162,12 @@ class HomePage extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - titles[index], + context.t(titleKeys[index]), style: AppTypography.h1.copyWith(color: Colors.white), ), const SizedBox(height: 4), Text( - subtitles[index], + context.t(subtitleKeys[index]), style: AppTypography.bodyMedium.copyWith( color: Colors.white.withValues(alpha: 0.8), ), @@ -179,16 +180,16 @@ class HomePage extends StatelessWidget { ); } - Widget _buildCategoryGrid() { - final categories = [ - ('餐饮', Icons.restaurant_rounded, AppColors.couponDining), - ('购物', Icons.shopping_bag_rounded, AppColors.couponShopping), - ('娱乐', Icons.sports_esports_rounded, AppColors.couponEntertainment), - ('出行', Icons.directions_car_rounded, AppColors.couponTravel), - ('生活', Icons.home_rounded, AppColors.couponOther), - ('品牌', Icons.storefront_rounded, AppColors.primary), - ('折扣', Icons.local_offer_rounded, AppColors.error), - ('全部', Icons.grid_view_rounded, AppColors.textSecondary), + Widget _buildCategoryGrid(BuildContext context) { + final categoryKeys = [ + ('home.dining', Icons.restaurant_rounded, AppColors.couponDining), + ('home.shopping', Icons.shopping_bag_rounded, AppColors.couponShopping), + ('home.entertainment', Icons.sports_esports_rounded, AppColors.couponEntertainment), + ('home.travel', Icons.directions_car_rounded, AppColors.couponTravel), + ('home.lifestyle', Icons.home_rounded, AppColors.couponOther), + ('home.brand', Icons.storefront_rounded, AppColors.primary), + ('home.discount', Icons.local_offer_rounded, AppColors.error), + ('home.allCategories', Icons.grid_view_rounded, AppColors.textSecondary), ]; return Padding( @@ -202,9 +203,9 @@ class HomePage extends StatelessWidget { crossAxisSpacing: 8, childAspectRatio: 0.85, ), - itemCount: categories.length, + itemCount: categoryKeys.length, itemBuilder: (context, index) { - final (name, icon, color) = categories[index]; + final (key, icon, color) = categoryKeys[index]; return GestureDetector( onTap: () {}, child: Column( @@ -220,7 +221,7 @@ class HomePage extends StatelessWidget { child: Icon(icon, color: color, size: 24), ), const SizedBox(height: 6), - Text(name, style: AppTypography.caption.copyWith( + Text(context.t(key), style: AppTypography.caption.copyWith( color: AppColors.textPrimary, fontWeight: FontWeight.w500, )), @@ -232,7 +233,7 @@ class HomePage extends StatelessWidget { ); } - Widget _buildAiSuggestions() { + Widget _buildAiSuggestions(BuildContext context) { return Container( margin: const EdgeInsets.fromLTRB(20, 16, 20, 0), padding: const EdgeInsets.all(14), @@ -257,12 +258,12 @@ class HomePage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('AI 推荐', style: AppTypography.labelSmall.copyWith( + Text(context.t('home.aiRecommend'), style: AppTypography.labelSmall.copyWith( color: AppColors.primary, )), const SizedBox(height: 2), Text( - '根据你的偏好,发现了3张高性价比券', + context.t('home.aiRecommendDesc'), style: AppTypography.bodySmall, maxLines: 1, overflow: TextOverflow.ellipsis, diff --git a/frontend/mobile/lib/features/coupons/presentation/pages/market_page.dart b/frontend/mobile/lib/features/coupons/presentation/pages/market_page.dart index d6204dd..f3b497e 100644 --- a/frontend/mobile/lib/features/coupons/presentation/pages/market_page.dart +++ b/frontend/mobile/lib/features/coupons/presentation/pages/market_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -35,7 +36,7 @@ class _MarketPageState extends State with SingleTickerProviderStateM Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('交易市场'), + title: Text(context.t('market.title')), bottom: PreferredSize( preferredSize: const Size.fromHeight(AppSpacing.tabBarHeight), child: Container( @@ -55,9 +56,9 @@ class _MarketPageState extends State with SingleTickerProviderStateM dividerColor: Colors.transparent, labelColor: AppColors.textPrimary, unselectedLabelColor: AppColors.textTertiary, - tabs: const [ - Tab(text: '一级市场(全新)'), - Tab(text: '二级市场(转售)'), + tabs: [ + Tab(text: context.t('market.primary')), + Tab(text: context.t('market.secondary')), ], ), ), @@ -90,17 +91,24 @@ class _MarketPageState extends State with SingleTickerProviderStateM } Widget _buildFilters() { - final categories = ['全部', '餐饮', '购物', '娱乐', '出行', '生活']; + final categoryKeys = [ + 'common.all', + 'market.dining', + 'market.shopping', + 'market.entertainment', + 'market.travel', + 'market.lifestyle', + ]; return SizedBox( height: 36, child: ListView.separated( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 20), - itemCount: categories.length, + itemCount: categoryKeys.length, separatorBuilder: (_, __) => const SizedBox(width: 8), itemBuilder: (context, index) { - final cat = categories[index]; + final cat = context.t(categoryKeys[index]); final isSelected = _selectedCategory == cat || (index == 0 && _selectedCategory == null); return GestureDetector( onTap: () => setState(() => _selectedCategory = index == 0 ? null : cat), @@ -127,10 +135,10 @@ class _MarketPageState extends State with SingleTickerProviderStateM Widget _buildSortBar() { final sortOptions = [ - ('discount', '折扣率'), - ('price_asc', '价格↑'), - ('price_desc', '价格↓'), - ('expiry', '到期时间'), + ('discount', context.t('market.discountRate')), + ('price_asc', context.t('market.priceUp')), + ('price_desc', context.t('market.priceDown')), + ('expiry', context.t('market.expiryDate')), ]; return Padding( diff --git a/frontend/mobile/lib/features/coupons/presentation/pages/my_coupon_detail_page.dart b/frontend/mobile/lib/features/coupons/presentation/pages/my_coupon_detail_page.dart index 0fef4df..5344f75 100644 --- a/frontend/mobile/lib/features/coupons/presentation/pages/my_coupon_detail_page.dart +++ b/frontend/mobile/lib/features/coupons/presentation/pages/my_coupon_detail_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -20,7 +21,7 @@ class MyCouponDetailPage extends StatelessWidget { icon: const Icon(Icons.arrow_back_ios_new_rounded, size: 20), onPressed: () => Navigator.of(context).pop(), ), - title: const Text('券详情'), + title: Text(context.t('myCoupon.title')), actions: [ IconButton( icon: const Icon(Icons.more_horiz_rounded), @@ -66,7 +67,7 @@ class MyCouponDetailPage extends StatelessWidget { color: Colors.white24, borderRadius: AppSpacing.borderRadiusFull, ), - child: Text('可使用', style: AppTypography.caption.copyWith( + child: Text(context.t('myCoupon.active'), style: AppTypography.caption.copyWith( color: Colors.white, fontWeight: FontWeight.w600, )), @@ -101,7 +102,7 @@ class MyCouponDetailPage extends StatelessWidget { // Instructions Text( - '出示此二维码给商户扫描核销', + context.t('myCoupon.showQrHint'), style: AppTypography.bodySmall.copyWith(color: Colors.white70), ), @@ -112,7 +113,7 @@ class MyCouponDetailPage extends StatelessWidget { onPressed: () {}, icon: const Icon(Icons.view_headline_rounded, size: 18, color: Colors.white70), - label: Text('切换条形码', style: AppTypography.labelSmall.copyWith( + label: Text(context.t('myCoupon.switchBarcode'), style: AppTypography.labelSmall.copyWith( color: Colors.white70, )), ), @@ -131,15 +132,15 @@ class MyCouponDetailPage extends StatelessWidget { ), child: Column( children: [ - _infoRow('面值', '\$25.00'), + _infoRow(context.t('myCoupon.faceValue'), '\$25.00'), const Padding(padding: EdgeInsets.symmetric(vertical: 10), child: Divider()), - _infoRow('购买价格', '\$21.25'), + _infoRow(context.t('myCoupon.purchasePrice'), '\$21.25'), const Padding(padding: EdgeInsets.symmetric(vertical: 10), child: Divider()), - _infoRow('有效期', '2026/12/31'), + _infoRow(context.t('myCoupon.validUntil'), '2026/12/31'), const Padding(padding: EdgeInsets.symmetric(vertical: 10), child: Divider()), - _infoRow('订单号', 'GNX-20260209-001234'), + _infoRow(context.t('myCoupon.orderNo'), 'GNX-20260209-001234'), const Padding(padding: EdgeInsets.symmetric(vertical: 10), child: Divider()), - _infoRow('剩余可转售次数', '3次'), + _infoRow(context.t('myCoupon.resellCount'), '3'), ], ), ), @@ -150,7 +151,7 @@ class MyCouponDetailPage extends StatelessWidget { children: [ Expanded( child: GenexButton( - label: '转赠', + label: context.t('myCoupon.transfer'), icon: Icons.card_giftcard_rounded, variant: GenexButtonVariant.secondary, onPressed: () { @@ -161,7 +162,7 @@ class MyCouponDetailPage extends StatelessWidget { const SizedBox(width: 12), Expanded( child: GenexButton( - label: '出售', + label: context.t('myCoupon.sell'), icon: Icons.sell_rounded, variant: GenexButtonVariant.outline, onPressed: () { @@ -185,12 +186,12 @@ class MyCouponDetailPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('使用说明', style: AppTypography.labelMedium), + Text(context.t('myCoupon.usageNote'), style: AppTypography.labelMedium), const SizedBox(height: 12), - _ruleItem('全国星巴克门店通用'), - _ruleItem('请在有效期内使用'), - _ruleItem('每次消费仅可使用一张'), - _ruleItem('不可兑换现金'), + _ruleItem(context.t('myCoupon.useInStore')), + _ruleItem(context.t('myCoupon.useInTime')), + _ruleItem(context.t('myCoupon.onePerVisit')), + _ruleItem(context.t('myCoupon.noCash')), ], ), ), @@ -249,11 +250,11 @@ class MyCouponDetailPage extends StatelessWidget { ), ), const SizedBox(height: 16), - _optionTile(Icons.wallet_rounded, '提取到外部钱包', '需KYC L2+认证', () {}), + _optionTile(Icons.wallet_rounded, context.t('myCoupon.extractToWallet'), context.t('myCoupon.requireKycL2'), () {}), const Divider(), - _optionTile(Icons.receipt_long_rounded, '查看交易记录', '', () {}), + _optionTile(Icons.receipt_long_rounded, context.t('myCoupon.viewTrades'), '', () {}), const Divider(), - _optionTile(Icons.help_outline_rounded, '使用帮助', '', () {}), + _optionTile(Icons.help_outline_rounded, context.t('myCoupon.help'), '', () {}), ], ), ), diff --git a/frontend/mobile/lib/features/coupons/presentation/pages/my_coupons_page.dart b/frontend/mobile/lib/features/coupons/presentation/pages/my_coupons_page.dart index 139db64..c61b14a 100644 --- a/frontend/mobile/lib/features/coupons/presentation/pages/my_coupons_page.dart +++ b/frontend/mobile/lib/features/coupons/presentation/pages/my_coupons_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -37,7 +38,7 @@ class _MyCouponsPageState extends State Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('我的券'), + title: Text(context.t('myCoupons.title')), actions: [ IconButton( icon: const Icon(Icons.sort_rounded, size: 22), @@ -46,11 +47,11 @@ class _MyCouponsPageState extends State ], bottom: TabBar( controller: _tabController, - tabs: const [ - Tab(text: '全部'), - Tab(text: '可使用'), - Tab(text: '待核销'), - Tab(text: '已过期'), + tabs: [ + Tab(text: context.t('common.all')), + Tab(text: context.t('myCoupons.usable')), + Tab(text: context.t('myCoupons.pendingRedeem')), + Tab(text: context.t('myCoupons.expired')), ], ), ), @@ -70,6 +71,7 @@ class _MyCouponsPageState extends State // Example: show empty state for expired tab if (filter == CouponStatus.expired) { return EmptyState.noCoupons( + context: context, onBrowse: () { // noop - market tab accessible from bottom nav }, @@ -160,10 +162,10 @@ class _MyCouponCard extends StatelessWidget { const SizedBox(height: 4), Row( children: [ - Text('面值 \$${faceValue.toStringAsFixed(0)}', + Text('${context.t('myCoupons.faceValue')} \$${faceValue.toStringAsFixed(0)}', style: AppTypography.bodySmall), const SizedBox(width: 8), - _statusWidget, + _buildStatusWidget(context), ], ), ], @@ -187,14 +189,14 @@ class _MyCouponCard extends StatelessWidget { Icon(Icons.access_time_rounded, size: 14, color: _expiryColor), const SizedBox(width: 4), Text( - _expiryText, + _getExpiryText(context), style: AppTypography.caption.copyWith(color: _expiryColor), ), const Spacer(), if (status == CouponStatus.active) ...[ - _quickAction('转赠', Icons.card_giftcard_rounded), + _quickAction(context.t('myCoupons.transfer'), Icons.card_giftcard_rounded), const SizedBox(width: 12), - _quickAction('出售', Icons.sell_rounded), + _quickAction(context.t('myCoupons.sell'), Icons.sell_rounded), ], ], ), @@ -205,16 +207,16 @@ class _MyCouponCard extends StatelessWidget { ); } - Widget get _statusWidget { + Widget _buildStatusWidget(BuildContext context) { switch (status) { case CouponStatus.active: - return StatusTags.active(); + return StatusTags.active(context: context); case CouponStatus.pending: - return StatusTags.pending(); + return StatusTags.pending(context: context); case CouponStatus.expired: - return StatusTags.expired(); + return StatusTags.expired(context: context); case CouponStatus.used: - return StatusTags.used(); + return StatusTags.used(context: context); } } @@ -232,12 +234,12 @@ class _MyCouponCard extends StatelessWidget { ); } - String get _expiryText { + String _getExpiryText(BuildContext context) { final days = expiryDate.difference(DateTime.now()).inDays; - if (days < 0) return '已过期'; - if (days == 0) return '今天到期'; - if (days <= 7) return '$days天后到期'; - return '${expiryDate.year}/${expiryDate.month}/${expiryDate.day}到期'; + if (days < 0) return context.t('myCoupons.expiredText'); + if (days == 0) return context.t('myCoupons.expiringToday'); + if (days <= 7) return '$days${context.t('myCoupons.daysToExpiry')}'; + return '${expiryDate.year}/${expiryDate.month}/${expiryDate.day}${context.t('couponCard.expiryFormat')}'; } Color get _expiryColor { diff --git a/frontend/mobile/lib/features/coupons/presentation/pages/order_confirm_page.dart b/frontend/mobile/lib/features/coupons/presentation/pages/order_confirm_page.dart index 65ca215..69839dc 100644 --- a/frontend/mobile/lib/features/coupons/presentation/pages/order_confirm_page.dart +++ b/frontend/mobile/lib/features/coupons/presentation/pages/order_confirm_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -30,7 +31,7 @@ class _OrderConfirmPageState extends State { icon: const Icon(Icons.arrow_back_ios_new_rounded, size: 20), onPressed: () => Navigator.of(context).pop(), ), - title: const Text('确认订单'), + title: Text(context.t('orderConfirm.title')), ), body: SingleChildScrollView( padding: AppSpacing.pagePadding, @@ -69,7 +70,7 @@ class _OrderConfirmPageState extends State { const SizedBox(width: 8), Expanded( child: Text( - '您正在购买消费券用于消费', + context.t('orderConfirm.buyingNote'), style: AppTypography.bodySmall.copyWith( color: AppColors.gray700, ), @@ -97,7 +98,7 @@ class _OrderConfirmPageState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('合计', style: AppTypography.caption), + Text(context.t('orderConfirm.total'), style: AppTypography.caption), Text( '\$${_totalPrice.toStringAsFixed(2)}', style: AppTypography.priceMedium, @@ -107,7 +108,7 @@ class _OrderConfirmPageState extends State { const SizedBox(width: 20), Expanded( child: GenexButton( - label: '确认支付', + label: context.t('orderConfirm.confirmPay'), onPressed: () => _showPaymentAuth(context), ), ), @@ -183,7 +184,7 @@ class _OrderConfirmPageState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('购买数量', style: AppTypography.labelMedium), + Text(context.t('orderConfirm.quantity'), style: AppTypography.labelMedium), Row( children: [ _buildQtyButton(Icons.remove_rounded, () { @@ -221,7 +222,7 @@ class _OrderConfirmPageState extends State { Widget _buildPaymentMethods() { final methods = [ - ('银行卡/信用卡', Icons.credit_card_rounded), + (context.t('orderConfirm.bankCard'), Icons.credit_card_rounded), ('Apple Pay', Icons.apple_rounded), ]; @@ -235,7 +236,7 @@ class _OrderConfirmPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('支付方式', style: AppTypography.labelMedium), + Text(context.t('orderConfirm.paymentMethod'), style: AppTypography.labelMedium), const SizedBox(height: 12), ...methods.asMap().entries.map((entry) { final isSelected = _selectedPayment == entry.key; @@ -285,15 +286,15 @@ class _OrderConfirmPageState extends State { ), child: Column( children: [ - _priceRow('单价', '\$${_unitPrice.toStringAsFixed(2)}'), + _priceRow(context.t('orderConfirm.unitPrice'), '\$${_unitPrice.toStringAsFixed(2)}'), const SizedBox(height: 8), - _priceRow('数量', '×$_quantity'), + _priceRow(context.t('orderConfirm.count'), '$_quantity'), const Padding( padding: EdgeInsets.symmetric(vertical: 10), child: Divider(), ), _priceRow( - '合计', + context.t('orderConfirm.total'), '\$${_totalPrice.toStringAsFixed(2)}', valueStyle: AppTypography.priceMedium, ), @@ -301,7 +302,7 @@ class _OrderConfirmPageState extends State { Align( alignment: Alignment.centerRight, child: Text( - '比面值节省 \$${(25.0 * _quantity - _totalPrice).toStringAsFixed(2)}', + '${context.t('orderConfirm.saveBadge')} \$${(25.0 * _quantity - _totalPrice).toStringAsFixed(2)}', style: AppTypography.caption.copyWith(color: AppColors.success), ), ), @@ -337,14 +338,14 @@ class _OrderConfirmPageState extends State { ), ), const SizedBox(height: 20), - Text('确认支付', style: AppTypography.h2), + Text(context.t('orderConfirm.confirmPay'), style: AppTypography.h2), const SizedBox(height: 8), Text( '\$${_totalPrice.toStringAsFixed(2)}', style: AppTypography.priceLarge.copyWith(fontSize: 36), ), const SizedBox(height: 4), - Text('星巴克 \$25 礼品卡 × $_quantity', + Text('星巴克 \$25 礼品卡 x $_quantity', style: AppTypography.bodySmall), const SizedBox(height: 32), // Biometric / Password @@ -358,10 +359,10 @@ class _OrderConfirmPageState extends State { size: 36, color: AppColors.primary), ), const SizedBox(height: 12), - Text('请验证指纹或面容以完成支付', style: AppTypography.bodySmall), + Text(context.t('orderConfirm.biometricHint'), style: AppTypography.bodySmall), const SizedBox(height: 24), GenexButton( - label: '使用密码支付', + label: context.t('orderConfirm.usePasswordPay'), variant: GenexButtonVariant.text, onPressed: () { Navigator.pop(ctx); diff --git a/frontend/mobile/lib/features/coupons/presentation/pages/payment_page.dart b/frontend/mobile/lib/features/coupons/presentation/pages/payment_page.dart index a45e207..870a1db 100644 --- a/frontend/mobile/lib/features/coupons/presentation/pages/payment_page.dart +++ b/frontend/mobile/lib/features/coupons/presentation/pages/payment_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -17,17 +18,18 @@ class PaymentPage extends StatefulWidget { class _PaymentPageState extends State { int _selectedMethod = 0; - final _methods = const [ + List<_PaymentMethod> _getMethods(BuildContext context) => [ _PaymentMethod('Visa •••• 4242', Icons.credit_card_rounded, 'visa'), _PaymentMethod('Apple Pay', Icons.apple_rounded, 'apple_pay'), _PaymentMethod('Google Pay', Icons.account_balance_wallet_rounded, 'google_pay'), - _PaymentMethod('银行转账', Icons.account_balance_rounded, 'bank'), + _PaymentMethod(context.t('payment.bankTransfer'), Icons.account_balance_rounded, 'bank'), ]; @override Widget build(BuildContext context) { + final methods = _getMethods(context); return Scaffold( - appBar: AppBar(title: const Text('选择支付方式')), + appBar: AppBar(title: Text(context.t('payment.title'))), body: Column( children: [ // Order Summary @@ -57,7 +59,7 @@ class _PaymentPageState extends State { children: [ Text('星巴克 \$25 礼品卡', style: AppTypography.labelMedium), const SizedBox(height: 2), - Text('面值 \$25.00', style: AppTypography.bodySmall), + Text('${context.t('couponDetail.faceValue')} \$25.00', style: AppTypography.bodySmall), ], ), ), @@ -70,9 +72,9 @@ class _PaymentPageState extends State { Expanded( child: ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 20), - itemCount: _methods.length, + itemCount: methods.length, itemBuilder: (context, index) { - final method = _methods[index]; + final method = methods[index]; final isSelected = _selectedMethod == index; return GestureDetector( onTap: () => setState(() => _selectedMethod = index), @@ -110,7 +112,7 @@ class _PaymentPageState extends State { child: TextButton.icon( onPressed: () {}, icon: const Icon(Icons.add_rounded), - label: const Text('添加新支付方式'), + label: Text(context.t('payment.addNew')), ), ), @@ -122,10 +124,9 @@ class _PaymentPageState extends State { height: AppSpacing.buttonHeight, child: ElevatedButton( onPressed: () { - // 后端自动完成法币→稳定币→链上原子交换 Navigator.pushNamed(context, '/payment/success'); }, - child: const Text('确认支付 \$21.25'), + child: Text('${context.t('payment.confirmPay')} \$21.25'), ), ), ), diff --git a/frontend/mobile/lib/features/coupons/presentation/pages/payment_success_page.dart b/frontend/mobile/lib/features/coupons/presentation/pages/payment_success_page.dart index 27ae308..19e899c 100644 --- a/frontend/mobile/lib/features/coupons/presentation/pages/payment_success_page.dart +++ b/frontend/mobile/lib/features/coupons/presentation/pages/payment_success_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -45,10 +46,10 @@ class PaymentSuccessPage extends StatelessWidget { ), const SizedBox(height: 24), - Text('支付成功', style: AppTypography.h1), + Text(context.t('paymentSuccess.title'), style: AppTypography.h1), const SizedBox(height: 8), Text( - '券已到账,可在「我的券」中查看', + context.t('paymentSuccess.hint'), style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary), ), const SizedBox(height: 32), @@ -64,19 +65,19 @@ class PaymentSuccessPage extends StatelessWidget { ), child: Column( children: [ - _infoRow('券名称', couponName), + _infoRow(context.t('paymentSuccess.couponName'), couponName), const SizedBox(height: 10), const Divider(), const SizedBox(height: 10), - _infoRow('支付金额', '\$$amount'), + _infoRow(context.t('paymentSuccess.payAmount'), '\$$amount'), const SizedBox(height: 10), const Divider(), const SizedBox(height: 10), - _infoRow('订单号', orderNumber), + _infoRow(context.t('paymentSuccess.orderNo'), orderNumber), const SizedBox(height: 10), const Divider(), const SizedBox(height: 10), - _infoRow('支付时间', '2026-02-09 14:32:15'), + _infoRow(context.t('paymentSuccess.payTime'), '2026-02-09 14:32:15'), ], ), ), @@ -85,14 +86,14 @@ class PaymentSuccessPage extends StatelessWidget { // Actions GenexButton( - label: '查看我的券', + label: context.t('paymentSuccess.viewMyCoupon'), onPressed: () { Navigator.pushNamedAndRemoveUntil(context, '/main', (route) => false); }, ), const SizedBox(height: 12), GenexButton( - label: '继续逛', + label: context.t('paymentSuccess.continueBrowse'), variant: GenexButtonVariant.outline, onPressed: () { Navigator.pushNamedAndRemoveUntil(context, '/main', (route) => false); diff --git a/frontend/mobile/lib/features/coupons/presentation/pages/redeem_qr_page.dart b/frontend/mobile/lib/features/coupons/presentation/pages/redeem_qr_page.dart index 6ba8a49..9a924ad 100644 --- a/frontend/mobile/lib/features/coupons/presentation/pages/redeem_qr_page.dart +++ b/frontend/mobile/lib/features/coupons/presentation/pages/redeem_qr_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -45,7 +46,7 @@ class _RedeemQrPageState extends State { appBar: AppBar( backgroundColor: AppColors.gray900, foregroundColor: Colors.white, - title: const Text('出示券码'), + title: Text(context.t('redeem.title')), ), body: Center( child: Column( @@ -54,7 +55,7 @@ class _RedeemQrPageState extends State { // Coupon Info Text('星巴克 \$25 礼品卡', style: AppTypography.h2.copyWith(color: Colors.white)), const SizedBox(height: 4), - Text('面值 \$25.00', style: AppTypography.bodyMedium.copyWith(color: Colors.white60)), + Text('${context.t('redeem.faceValue')} \$25.00', style: AppTypography.bodyMedium.copyWith(color: Colors.white60)), const SizedBox(height: 32), // QR Code Area @@ -103,7 +104,7 @@ class _RedeemQrPageState extends State { const Icon(Icons.timer_outlined, color: Colors.white54, size: 18), const SizedBox(width: 6), Text( - '有效时间 $_formattedTime', + '${context.t('redeem.validTime')} $_formattedTime', style: AppTypography.bodyMedium.copyWith(color: Colors.white54), ), ], @@ -113,7 +114,7 @@ class _RedeemQrPageState extends State { onPressed: () { setState(() => _remainingSeconds = 300); }, - child: Text('刷新券码', style: AppTypography.labelMedium.copyWith(color: AppColors.primaryLight)), + child: Text(context.t('redeem.refresh'), style: AppTypography.labelMedium.copyWith(color: AppColors.primaryLight)), ), const SizedBox(height: 40), @@ -131,7 +132,7 @@ class _RedeemQrPageState extends State { const SizedBox(width: 10), Expanded( child: Text( - '请将此码出示给商户扫描,屏幕已自动调至最高亮度', + context.t('redeem.showHint'), style: AppTypography.caption.copyWith(color: Colors.white54), ), ), diff --git a/frontend/mobile/lib/features/coupons/presentation/pages/search_page.dart b/frontend/mobile/lib/features/coupons/presentation/pages/search_page.dart index 3938fc7..c0d7a96 100644 --- a/frontend/mobile/lib/features/coupons/presentation/pages/search_page.dart +++ b/frontend/mobile/lib/features/coupons/presentation/pages/search_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -27,7 +28,7 @@ class _SearchPageState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('取消'), + child: Text(context.t('search.cancel')), ), ], ), @@ -46,11 +47,11 @@ class _SearchPageState extends State { child: TextField( controller: _searchController, autofocus: true, - decoration: const InputDecoration( - hintText: '搜索券、品牌、分类...', - prefixIcon: Icon(Icons.search_rounded, size: 20), + decoration: InputDecoration( + hintText: context.t('search.hint'), + prefixIcon: const Icon(Icons.search_rounded, size: 20), border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 10), + contentPadding: const EdgeInsets.symmetric(vertical: 10), ), onChanged: (v) => setState(() => _hasInput = v.isNotEmpty), ), @@ -68,7 +69,7 @@ class _SearchPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('热门搜索', style: AppTypography.h3), + Text(context.t('search.hotSearch'), style: AppTypography.h3), GestureDetector(onTap: () {}, child: const Icon(Icons.refresh_rounded, size: 18, color: AppColors.textTertiary)), ], ), @@ -76,7 +77,7 @@ class _SearchPageState extends State { Wrap( spacing: 8, runSpacing: 8, - children: ['星巴克', 'Amazon', '餐饮券', '折扣券', '旅游', 'Nike'].map((tag) { + children: ['Starbucks', 'Amazon', context.t('search.diningCoupon'), context.t('search.discountCoupon'), context.t('search.travel'), 'Nike'].map((tag) { return GestureDetector( onTap: () { _searchController.text = tag; @@ -100,10 +101,10 @@ class _SearchPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('搜索历史', style: AppTypography.h3), + Text(context.t('search.history'), style: AppTypography.h3), GestureDetector( onTap: () {}, - child: Text('清空', style: AppTypography.labelSmall.copyWith(color: AppColors.textTertiary)), + child: Text(context.t('search.clear'), style: AppTypography.labelSmall.copyWith(color: AppColors.textTertiary)), ), ], ), diff --git a/frontend/mobile/lib/features/issuer/presentation/pages/issuer_main_page.dart b/frontend/mobile/lib/features/issuer/presentation/pages/issuer_main_page.dart index 24d784d..f444da3 100644 --- a/frontend/mobile/lib/features/issuer/presentation/pages/issuer_main_page.dart +++ b/frontend/mobile/lib/features/issuer/presentation/pages/issuer_main_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -35,17 +36,17 @@ class _IssuerMainPageState extends State { bottomNavigationBar: NavigationBar( selectedIndex: _currentIndex, onDestinationSelected: (i) => setState(() => _currentIndex = i), - destinations: const [ - NavigationDestination(icon: Icon(Icons.dashboard_outlined), - selectedIcon: Icon(Icons.dashboard_rounded), label: '总览'), - NavigationDestination(icon: Icon(Icons.add_card_outlined), - selectedIcon: Icon(Icons.add_card_rounded), label: '发券'), - NavigationDestination(icon: Icon(Icons.fact_check_outlined), - selectedIcon: Icon(Icons.fact_check_rounded), label: '核销'), - NavigationDestination(icon: Icon(Icons.account_balance_outlined), - selectedIcon: Icon(Icons.account_balance_rounded), label: '财务'), - NavigationDestination(icon: Icon(Icons.more_horiz_rounded), - selectedIcon: Icon(Icons.more_horiz_rounded), label: '更多'), + destinations: [ + NavigationDestination(icon: const Icon(Icons.dashboard_outlined), + selectedIcon: const Icon(Icons.dashboard_rounded), label: context.t('issuer.overview')), + NavigationDestination(icon: const Icon(Icons.add_card_outlined), + selectedIcon: const Icon(Icons.add_card_rounded), label: context.t('issuer.issue')), + NavigationDestination(icon: const Icon(Icons.fact_check_outlined), + selectedIcon: const Icon(Icons.fact_check_rounded), label: context.t('issuer.redeem')), + NavigationDestination(icon: const Icon(Icons.account_balance_outlined), + selectedIcon: const Icon(Icons.account_balance_rounded), label: context.t('issuer.finance')), + NavigationDestination(icon: const Icon(Icons.more_horiz_rounded), + selectedIcon: const Icon(Icons.more_horiz_rounded), label: context.t('issuer.more')), ], ), floatingActionButton: AiFab( @@ -64,7 +65,7 @@ class _IssuerDashboard extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('发行方管理'), + title: Text(context.t('issuer.title')), actions: [ IconButton(icon: const Icon(Icons.notifications_outlined), onPressed: () {}), ], @@ -113,7 +114,7 @@ class _IssuerDashboard extends StatelessWidget { )), ), const SizedBox(width: 8), - Text('已认证发行方', style: AppTypography.bodySmall.copyWith( + Text(context.t('issuer.verified'), style: AppTypography.bodySmall.copyWith( color: Colors.white70, )), ], @@ -147,7 +148,7 @@ class _IssuerDashboard extends StatelessWidget { const SizedBox(width: 10), Expanded( child: Text( - 'AI建议:当前市场需求旺盛,建议增发 \$50 面值礼品卡', + 'AI: Market demand is strong, recommend issuing \$50 gift cards', style: AppTypography.bodySmall, maxLines: 2, ), @@ -159,29 +160,29 @@ class _IssuerDashboard extends StatelessWidget { const SizedBox(height: 20), // Stats Grid - _buildStatsGrid(), + _buildStatsGrid(context), const SizedBox(height: 24), // Quick Actions - Text('快捷操作', style: AppTypography.h3), + Text(context.t('issuer.quickActions'), style: AppTypography.h3), const SizedBox(height: 12), Row( children: [ - _quickAction(Icons.add_card_rounded, '创建券', AppColors.primary), + _quickAction(Icons.add_card_rounded, context.t('issuer.createCoupon'), AppColors.primary), const SizedBox(width: 12), - _quickAction(Icons.people_outline_rounded, '门店管理', AppColors.info), + _quickAction(Icons.people_outline_rounded, context.t('issuer.storeManage'), AppColors.info), const SizedBox(width: 12), - _quickAction(Icons.analytics_outlined, '销售分析', AppColors.success), + _quickAction(Icons.analytics_outlined, context.t('issuer.salesAnalysis'), AppColors.success), const SizedBox(width: 12), - _quickAction(Icons.download_rounded, '对账单', AppColors.warning), + _quickAction(Icons.download_rounded, context.t('issuer.statement'), AppColors.warning), ], ), const SizedBox(height: 24), // Recent Coupons - Text('我的券', style: AppTypography.h3), + Text(context.t('issuer.myCoupons'), style: AppTypography.h3), const SizedBox(height: 12), - ...List.generate(3, (i) => _couponItem(i)), + ...List.generate(3, (i) => _couponItem(context, i)), const SizedBox(height: 80), ], @@ -190,12 +191,12 @@ class _IssuerDashboard extends StatelessWidget { ); } - Widget _buildStatsGrid() { + Widget _buildStatsGrid(BuildContext context) { final stats = [ - ('发行总量', '12,800', AppColors.primary), - ('已售出', '9,650', AppColors.success), - ('已核销', '6,240', AppColors.info), - ('核销率', '64.7%', AppColors.warning), + (context.t('issuer.totalIssued'), '12,800', AppColors.primary), + (context.t('issuer.totalSold'), '9,650', AppColors.success), + (context.t('issuer.totalRedeemed'), '6,240', AppColors.info), + (context.t('issuer.redeemRate'), '64.7%', AppColors.warning), ]; return GridView.count( @@ -245,9 +246,13 @@ class _IssuerDashboard extends StatelessWidget { ); } - Widget _couponItem(int index) { - final names = ['\$25 礼品卡', '\$50 满减券', '\$10 折扣券']; - final statuses = ['已上架', '审核中', '已售罄']; + Widget _couponItem(BuildContext context, int index) { + final names = ['\$25 Gift Card', '\$50 Voucher', '\$10 Discount']; + final statuses = [ + context.t('issuer.listed'), + context.t('issuer.underReview'), + context.t('issuer.soldOut'), + ]; final colors = [AppColors.success, AppColors.warning, AppColors.textTertiary]; return Container( @@ -275,7 +280,7 @@ class _IssuerDashboard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(names[index], style: AppTypography.labelMedium), - Text('发行 1,000 / 已售 ${[850, 0, 500][index]}', + Text('${context.t('issuer.issuedSlash')} 1,000 / ${context.t('issuer.sold')} ${[850, 0, 500][index]}', style: AppTypography.caption), ], ), @@ -303,7 +308,7 @@ class _CouponCenter extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('发券中心')), + appBar: AppBar(title: Text(context.t('issuer.issueCenter'))), body: SingleChildScrollView( padding: AppSpacing.pagePadding, child: Column( @@ -312,7 +317,7 @@ class _CouponCenter extends StatelessWidget { const SizedBox(height: 16), // Template Selection - Text('选择券模板', style: AppTypography.h3), + Text(context.t('issuer.selectTemplate'), style: AppTypography.h3), const SizedBox(height: 12), GridView.count( crossAxisCount: 2, @@ -322,10 +327,10 @@ class _CouponCenter extends StatelessWidget { crossAxisSpacing: 12, childAspectRatio: 1.2, children: [ - _templateCard('满减券', Icons.local_offer_rounded, AppColors.couponDining), - _templateCard('折扣券', Icons.percent_rounded, AppColors.couponShopping), - _templateCard('礼品卡', Icons.card_giftcard_rounded, AppColors.couponEntertainment), - _templateCard('储值券', Icons.account_balance_wallet_rounded, AppColors.couponTravel), + _templateCard(context.t('issuer.voucherType'), Icons.local_offer_rounded, AppColors.couponDining), + _templateCard(context.t('issuer.discountType'), Icons.percent_rounded, AppColors.couponShopping), + _templateCard(context.t('issuer.giftCardType'), Icons.card_giftcard_rounded, AppColors.couponEntertainment), + _templateCard(context.t('issuer.storedValueType'), Icons.account_balance_wallet_rounded, AppColors.couponTravel), ], ), const SizedBox(height: 24), @@ -334,13 +339,19 @@ class _CouponCenter extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('券管理', style: AppTypography.h3), - TextButton(onPressed: () {}, child: const Text('查看全部')), + Text(context.t('issuer.couponManage'), style: AppTypography.h3), + TextButton(onPressed: () {}, child: Text(context.t('issuer.viewAll'))), ], ), ...List.generate(5, (i) { final statusColors = [AppColors.success, AppColors.warning, AppColors.success, AppColors.textTertiary, AppColors.error]; - final statuses = ['已上架', '审核中', '已上架', '已下架', '已售罄']; + final statuses = [ + context.t('issuer.listed'), + context.t('issuer.underReview'), + context.t('issuer.listed'), + context.t('issuer.unlisted'), + context.t('issuer.soldOut'), + ]; return ListTile( contentPadding: EdgeInsets.zero, leading: Container( @@ -352,8 +363,8 @@ class _CouponCenter extends StatelessWidget { child: const Icon(Icons.confirmation_number_outlined, color: AppColors.primary, size: 20), ), - title: Text('券活动 ${i + 1}', style: AppTypography.labelMedium), - subtitle: Text('已售 ${(i + 1) * 120} / ${(i + 1) * 200}', + title: Text('${context.t('issuer.couponEvents')} ${i + 1}', style: AppTypography.labelMedium), + subtitle: Text('${context.t('issuer.sold')} ${(i + 1) * 120} / ${(i + 1) * 200}', style: AppTypography.caption), trailing: Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), @@ -374,12 +385,12 @@ class _CouponCenter extends StatelessWidget { ), floatingActionButton: FloatingActionButton.extended( onPressed: () { - // Navigator: → CreateCouponPage + // Navigator: -> CreateCouponPage }, backgroundColor: AppColors.primary, foregroundColor: Colors.white, icon: const Icon(Icons.add_rounded), - label: const Text('创建新券'), + label: Text(context.t('issuer.createNew')), ), ); } @@ -410,7 +421,7 @@ class _RedeemManagement extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('核销管理')), + appBar: AppBar(title: Text(context.t('issuer.redeemManage'))), body: SingleChildScrollView( padding: AppSpacing.pagePadding, child: Column( @@ -421,11 +432,11 @@ class _RedeemManagement extends StatelessWidget { // Stats Row( children: [ - _stat('今日', '156笔', AppColors.primary), + _stat(context.t('common.today'), '156', AppColors.primary), const SizedBox(width: 12), - _stat('本周', '892笔', AppColors.success), + _stat(context.t('common.thisWeek'), '892', AppColors.success), const SizedBox(width: 12), - _stat('本月', '3,450笔', AppColors.info), + _stat(context.t('common.thisMonth'), '3,450', AppColors.info), ], ), const SizedBox(height: 24), @@ -439,7 +450,7 @@ class _RedeemManagement extends StatelessWidget { border: Border.all(color: AppColors.borderLight), ), child: Center( - child: Text('核销趋势图 (fl_chart)', + child: Text('${context.t('issuer.redeemTrend')} (fl_chart)', style: AppTypography.bodySmall.copyWith(color: AppColors.textTertiary)), ), ), @@ -449,8 +460,8 @@ class _RedeemManagement extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('门店管理', style: AppTypography.h3), - TextButton(onPressed: () {}, child: const Text('全部门店')), + Text(context.t('issuer.storeManage'), style: AppTypography.h3), + TextButton(onPressed: () {}, child: Text(context.t('issuer.allStores'))), ], ), const SizedBox(height: 8), @@ -470,13 +481,13 @@ class _RedeemManagement extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(['总部', '朝阳门店', '国贸门店'][i], + Text(['HQ', 'Downtown Store', 'Mall Store'][i], style: AppTypography.labelMedium), - Text('今日 ${[56, 23, 18][i]} 笔', style: AppTypography.caption), + Text('${context.t('common.today')} ${[56, 23, 18][i]}', style: AppTypography.caption), ], ), ), - Text('${[3, 2, 1][i]} 名员工', style: AppTypography.caption), + Text('${[3, 2, 1][i]} ${context.t('issuer.employees')}', style: AppTypography.caption), ], ), )), @@ -514,7 +525,7 @@ class _FinancePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('财务管理')), + appBar: AppBar(title: Text(context.t('issuer.financeManage'))), body: SingleChildScrollView( padding: AppSpacing.pagePadding, child: Column( @@ -532,7 +543,7 @@ class _FinancePage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('总销售额', style: AppTypography.bodySmall.copyWith( + Text(context.t('issuer.totalSales'), style: AppTypography.bodySmall.copyWith( color: Colors.white70, )), const SizedBox(height: 4), @@ -542,11 +553,11 @@ class _FinancePage extends StatelessWidget { const SizedBox(height: 20), Row( children: [ - _revenueItem('已到账', '\$98,200'), + _revenueItem(context.t('issuer.settled'), '\$98,200'), const SizedBox(width: 24), - _revenueItem('待结算', '\$24,250'), + _revenueItem(context.t('issuer.pendingSettle'), '\$24,250'), const SizedBox(width: 24), - _revenueItem('Breakage', '\$6,000'), + _revenueItem(context.t('issuer.breakage'), '\$6,000'), ], ), ], @@ -559,7 +570,7 @@ class _FinancePage extends StatelessWidget { children: [ Expanded( child: GenexButton( - label: '提现', + label: context.t('issuer.withdrawBtn'), icon: Icons.account_balance_rounded, onPressed: () {}, ), @@ -567,7 +578,7 @@ class _FinancePage extends StatelessWidget { const SizedBox(width: 12), Expanded( child: GenexButton( - label: '对账报表', + label: context.t('issuer.reportBtn'), icon: Icons.receipt_long_rounded, variant: GenexButtonVariant.outline, onPressed: () {}, @@ -578,7 +589,7 @@ class _FinancePage extends StatelessWidget { const SizedBox(height: 24), // Settlement details - Text('结算明细', style: AppTypography.h3), + Text(context.t('issuer.settleDetail'), style: AppTypography.h3), const SizedBox(height: 12), ...List.generate(5, (i) => Container( margin: const EdgeInsets.only(bottom: 8), @@ -604,7 +615,7 @@ class _FinancePage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('核销结算 - \$25券 × ${(i + 1) * 5}笔', + Text('Redeem Settlement - \$25 x ${(i + 1) * 5}', style: AppTypography.labelSmall), Text('02/${10 - i}', style: AppTypography.caption), ], @@ -643,7 +654,7 @@ class _IssuerMore extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('更多')), + appBar: AppBar(title: Text(context.t('issuer.more'))), body: ListView( padding: AppSpacing.pagePadding, children: [ @@ -663,7 +674,7 @@ class _IssuerMore extends StatelessWidget { children: [ const Icon(Icons.verified_rounded, color: AppColors.creditAAA), const SizedBox(width: 8), - Text('信用等级', style: AppTypography.labelMedium), + Text(context.t('issuer.creditLevel'), style: AppTypography.labelMedium), const Spacer(), const CreditBadge(rating: 'AAA', size: CreditBadgeSize.large), ], @@ -675,14 +686,14 @@ class _IssuerMore extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('发行额度', style: AppTypography.caption), + Text(context.t('issuer.issueQuota'), style: AppTypography.caption), Text('\$500,000', style: AppTypography.h2.copyWith(color: AppColors.primary)), ], ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ - Text('已用额度', style: AppTypography.caption), + Text(context.t('issuer.usedQuota'), style: AppTypography.caption), Text('\$128,450', style: AppTypography.h3), ], ), @@ -704,13 +715,13 @@ class _IssuerMore extends StatelessWidget { const SizedBox(height: 16), // Menu items - _menuItem(Icons.bar_chart_rounded, '数据中心', '发行量/销量/兑付率'), - _menuItem(Icons.people_rounded, '用户画像', '购买用户分布分析'), - _menuItem(Icons.shield_outlined, '信用详情', '评分详情与提升建议'), - _menuItem(Icons.history_rounded, '额度变动', '历史额度调整记录'), - _menuItem(Icons.business_rounded, '企业信息', '营业执照/联系人'), - _menuItem(Icons.settings_outlined, '设置', '通知/安全/语言'), - _menuItem(Icons.help_outline_rounded, '帮助中心', '常见问题与客服'), + _menuItem(Icons.bar_chart_rounded, context.t('issuer.dataCenter'), context.t('issuer.issueSalesRate')), + _menuItem(Icons.people_rounded, context.t('issuer.userProfile'), context.t('issuer.userProfileDesc')), + _menuItem(Icons.shield_outlined, context.t('issuer.creditDetail'), context.t('issuer.creditDetailDesc')), + _menuItem(Icons.history_rounded, context.t('issuer.quotaChange'), context.t('issuer.quotaChangeDesc')), + _menuItem(Icons.business_rounded, context.t('issuer.companyInfo'), context.t('issuer.companyInfoDesc')), + _menuItem(Icons.settings_outlined, context.t('issuer.settingsItem'), context.t('issuer.settingsItemDesc')), + _menuItem(Icons.help_outline_rounded, context.t('issuer.helpItem'), context.t('issuer.helpItemDesc')), ], ), ); diff --git a/frontend/mobile/lib/features/merchant/presentation/pages/merchant_ai_assistant_page.dart b/frontend/mobile/lib/features/merchant/presentation/pages/merchant_ai_assistant_page.dart index 50fcaab..9484786 100644 --- a/frontend/mobile/lib/features/merchant/presentation/pages/merchant_ai_assistant_page.dart +++ b/frontend/mobile/lib/features/merchant/presentation/pages/merchant_ai_assistant_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -37,13 +38,13 @@ class _MerchantAiAssistantPageState extends State Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('AI 助手'), + title: Text(context.t('merchantAi.title')), bottom: TabBar( controller: _tabController, - tabs: const [ - Tab(text: '核销辅助'), - Tab(text: '客流预测'), - Tab(text: '异常预警'), + tabs: [ + Tab(text: context.t('merchantAi.redeemAssist')), + Tab(text: context.t('merchantAi.trafficForecast')), + Tab(text: context.t('merchantAi.anomalyAlert')), ], labelColor: AppColors.primary, unselectedLabelColor: AppColors.textTertiary, @@ -92,10 +93,10 @@ class _MerchantAiAssistantPageState extends State Widget _buildAiQuickActions() { final actions = [ - ('验券真伪', Icons.verified_user_rounded, AppColors.success), - ('查券状态', Icons.search_rounded, AppColors.info), - ('批量核销', Icons.playlist_add_check_rounded, AppColors.primary), - ('问题反馈', Icons.feedback_rounded, AppColors.warning), + (context.t('merchantAi.verifyAuth'), Icons.verified_user_rounded, AppColors.success), + (context.t('merchantAi.checkStatus'), Icons.search_rounded, AppColors.info), + (context.t('merchantAi.batchRedeem'), Icons.playlist_add_check_rounded, AppColors.primary), + (context.t('merchantAi.feedback'), Icons.feedback_rounded, AppColors.warning), ]; return Container( @@ -117,12 +118,12 @@ class _MerchantAiAssistantPageState extends State borderRadius: AppSpacing.borderRadiusSm, ), child: - const Center(child: Text('✨', style: TextStyle(fontSize: 16))), + const Center(child: Text('AI', style: TextStyle(fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold))), ), const SizedBox(width: 10), - const Text( - 'AI 快捷操作', - style: TextStyle( + Text( + context.t('merchantAi.quickActions'), + style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w600, color: Colors.white), @@ -183,23 +184,23 @@ class _MerchantAiAssistantPageState extends State const Icon(Icons.lightbulb_outline_rounded, color: AppColors.warning, size: 20), const SizedBox(width: 8), - Text('核销提示', style: AppTypography.labelLarge), + Text(context.t('merchantAi.redeemTips'), style: AppTypography.labelLarge), ], ), const SizedBox(height: 12), _buildTipItem( - '星巴克 \$25 礼品卡有批次更新', - '新批次(#B2026-03)已上线,请注意核验二维码格式', + 'Starbucks \$25 Gift Card batch update', + 'New batch (#B2026-03) is live, verify QR format', AppColors.info, ), _buildTipItem( - '午间高峰期即将到来', - '预计 11:30-13:00 核销量将达峰值 ~15笔/小时', + 'Lunch rush approaching', + 'Expected 11:30-13:00 peak ~15 redeems/hour', AppColors.warning, ), _buildTipItem( - '本店暂不支持 Nike 体验券', - '该券仅限旗舰店核销,请引导顾客至正确门店', + 'Nike Experience Voucher not supported', + 'Only redeemable at flagship stores', AppColors.error, ), ], @@ -241,9 +242,9 @@ class _MerchantAiAssistantPageState extends State Widget _buildHotCouponsToday() { final hotCoupons = [ - ('星巴克 \$25 礼品卡', 12, AppColors.couponDining), - ('Amazon \$50 购物券', 8, AppColors.couponShopping), - ('电影票 \$12', 5, AppColors.couponEntertainment), + ('Starbucks \$25 Gift Card', 12, AppColors.couponDining), + ('Amazon \$50 Voucher', 8, AppColors.couponShopping), + ('Movie Ticket \$12', 5, AppColors.couponEntertainment), ]; return Container( @@ -261,7 +262,7 @@ class _MerchantAiAssistantPageState extends State const Icon(Icons.local_fire_department_rounded, color: AppColors.error, size: 20), const SizedBox(width: 8), - Text('今日热门核销', style: AppTypography.labelLarge), + Text(context.t('merchantAi.todayHotRedeem'), style: AppTypography.labelLarge), ], ), const SizedBox(height: 12), @@ -292,7 +293,7 @@ class _MerchantAiAssistantPageState extends State borderRadius: AppSpacing.borderRadiusFull, ), child: Text( - '$count笔', + '$count${context.t('merchantAi.countUnit')}', style: AppTypography.labelSmall .copyWith(color: AppColors.primary), ), @@ -321,18 +322,18 @@ class _MerchantAiAssistantPageState extends State const Icon(Icons.auto_awesome_rounded, color: AppColors.primary, size: 20), const SizedBox(width: 8), - Text('AI 营销建议', style: AppTypography.labelLarge), + Text(context.t('merchantAi.aiMarketing'), style: AppTypography.labelLarge), ], ), const SizedBox(height: 12), _buildSuggestionItem( - '推荐搭配销售', - '购买咖啡券的顾客同时对糕点券感兴趣,建议推荐组合', + context.t('merchantAi.crossSellTitle'), + context.t('merchantAi.crossSellDesc'), Icons.restaurant_rounded, ), _buildSuggestionItem( - '周末促销建议', - '历史数据显示周六核销量+30%,建议推出周末限时活动', + context.t('merchantAi.weekendPromoTitle'), + context.t('merchantAi.weekendPromoDesc'), Icons.campaign_rounded, ), ], @@ -404,13 +405,13 @@ class _MerchantAiAssistantPageState extends State ), child: Column( children: [ - const Row( + Row( children: [ - Icon(Icons.insights_rounded, color: Colors.white, size: 22), - SizedBox(width: 10), + const Icon(Icons.insights_rounded, color: Colors.white, size: 22), + const SizedBox(width: 10), Text( - '今日客流预测', - style: TextStyle( + context.t('merchantAi.todayForecast'), + style: const TextStyle( fontSize: 17, fontWeight: FontWeight.w700, color: Colors.white), @@ -421,9 +422,9 @@ class _MerchantAiAssistantPageState extends State Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - _predictionStat('预计核销', '45笔'), - _predictionStat('高峰时段', '11:30-13:00'), - _predictionStat('预计收入', '\$892'), + _predictionStat(context.t('merchantAi.expectedRedeem'), '45${context.t('merchantAi.countUnit')}'), + _predictionStat(context.t('merchantAi.peakHours'), '11:30-13:00'), + _predictionStat(context.t('merchantAi.expectedRevenue'), '\$892'), ], ), const SizedBox(height: 16), @@ -435,12 +436,11 @@ class _MerchantAiAssistantPageState extends State ), child: Row( children: [ - const Text('✨', - style: TextStyle(fontSize: 14)), + const Icon(Icons.auto_awesome_rounded, color: Colors.white70, size: 14), const SizedBox(width: 8), Expanded( child: Text( - '较上周同期增长12%,建议午间增加1名收银员', + context.t('merchantAi.trafficInsight'), style: TextStyle( fontSize: 12, color: Colors.white.withValues(alpha: 0.9), @@ -475,16 +475,9 @@ class _MerchantAiAssistantPageState extends State Widget _buildHourlyBreakdown() { final hours = [ - ('9:00', 3), - ('10:00', 5), - ('11:00', 8), - ('12:00', 12), - ('13:00', 9), - ('14:00', 4), - ('15:00', 3), - ('16:00', 2), - ('17:00', 5), - ('18:00', 7), + ('9:00', 3), ('10:00', 5), ('11:00', 8), ('12:00', 12), + ('13:00', 9), ('14:00', 4), ('15:00', 3), ('16:00', 2), + ('17:00', 5), ('18:00', 7), ]; final maxCount = 12; @@ -498,7 +491,7 @@ class _MerchantAiAssistantPageState extends State child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('分时段预测', style: AppTypography.labelLarge), + Text(context.t('merchantAi.hourlyForecast'), style: AppTypography.labelLarge), const SizedBox(height: 16), ...hours.map((h) { final (time, count) = h; @@ -510,9 +503,7 @@ class _MerchantAiAssistantPageState extends State children: [ SizedBox( width: 44, - child: Text(time, - style: AppTypography.caption - .copyWith(fontFamily: 'monospace')), + child: Text(time, style: AppTypography.caption.copyWith(fontFamily: 'monospace')), ), Expanded( child: ClipRRect( @@ -520,9 +511,7 @@ class _MerchantAiAssistantPageState extends State child: LinearProgressIndicator( value: pct, backgroundColor: AppColors.gray100, - valueColor: AlwaysStoppedAnimation( - isPeak ? AppColors.primary : AppColors.primaryLight, - ), + valueColor: AlwaysStoppedAnimation(isPeak ? AppColors.primary : AppColors.primaryLight), minHeight: 16, ), ), @@ -531,7 +520,7 @@ class _MerchantAiAssistantPageState extends State SizedBox( width: 30, child: Text( - '$count笔', + '$count${context.t('merchantAi.countUnit')}', style: TextStyle( fontSize: 11, fontWeight: isPeak ? FontWeight.w600 : FontWeight.w400, @@ -550,13 +539,13 @@ class _MerchantAiAssistantPageState extends State Widget _buildWeeklyForecast() { final days = [ - ('周一', 38, false), - ('周二', 42, false), - ('周三', 45, true), - ('周四', 40, false), - ('周五', 52, false), - ('周六', 68, false), - ('周日', 55, false), + (context.t('merchantAi.monday'), 38, false), + (context.t('merchantAi.tuesday'), 42, false), + (context.t('merchantAi.wednesday'), 45, true), + (context.t('merchantAi.thursday'), 40, false), + (context.t('merchantAi.friday'), 52, false), + (context.t('merchantAi.saturday'), 68, false), + (context.t('merchantAi.sunday'), 55, false), ]; return Container( @@ -569,7 +558,7 @@ class _MerchantAiAssistantPageState extends State child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('本周预测', style: AppTypography.labelLarge), + Text(context.t('merchantAi.weeklyForecast'), style: AppTypography.labelLarge), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, @@ -593,8 +582,7 @@ class _MerchantAiAssistantPageState extends State height: 80 * heightPct, decoration: BoxDecoration( color: isToday ? AppColors.primary : AppColors.primarySurface, - borderRadius: - const BorderRadius.vertical(top: Radius.circular(4)), + borderRadius: const BorderRadius.vertical(top: Radius.circular(4)), ), ), const SizedBox(height: 4), @@ -627,16 +615,15 @@ class _MerchantAiAssistantPageState extends State children: [ Row( children: [ - const Icon(Icons.people_alt_rounded, - color: AppColors.primary, size: 20), + const Icon(Icons.people_alt_rounded, color: AppColors.primary, size: 20), const SizedBox(width: 8), - Text('排班建议', style: AppTypography.labelLarge), + Text(context.t('merchantAi.staffSuggestion'), style: AppTypography.labelLarge), ], ), const SizedBox(height: 12), - _staffRow('上午 (9:00-13:00)', '建议 2 人', '含午间高峰'), - _staffRow('下午 (13:00-17:00)', '建议 1 人', '客流较少'), - _staffRow('傍晚 (17:00-21:00)', '建议 2 人', '下班高峰'), + _staffRow('AM (9:00-13:00)', '2 staff', 'Lunch peak'), + _staffRow('PM (13:00-17:00)', '1 staff', 'Low traffic'), + _staffRow('EVE (17:00-21:00)', '2 staff', 'Evening peak'), ], ), ); @@ -647,20 +634,9 @@ class _MerchantAiAssistantPageState extends State padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ - Expanded( - flex: 3, - child: Text(period, style: AppTypography.bodySmall), - ), - Expanded( - flex: 2, - child: Text(suggestion, - style: AppTypography.labelSmall - .copyWith(color: AppColors.primary)), - ), - Expanded( - flex: 2, - child: Text(reason, style: AppTypography.caption), - ), + Expanded(flex: 3, child: Text(period, style: AppTypography.bodySmall)), + Expanded(flex: 2, child: Text(suggestion, style: AppTypography.labelSmall.copyWith(color: AppColors.primary))), + Expanded(flex: 2, child: Text(reason, style: AppTypography.caption)), ], ), ); @@ -675,19 +651,12 @@ class _MerchantAiAssistantPageState extends State child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Alert Summary _buildAlertSummary(), const SizedBox(height: 20), - - // Active Alerts _buildActiveAlerts(), const SizedBox(height: 20), - - // Suspicious Patterns _buildSuspiciousPatterns(), const SizedBox(height: 20), - - // Recent Resolved _buildResolvedAlerts(), ], ), @@ -697,11 +666,11 @@ class _MerchantAiAssistantPageState extends State Widget _buildAlertSummary() { return Row( children: [ - _alertStatCard('待处理', '2', AppColors.error), + _alertStatCard(context.t('merchantAi.pendingCount'), '2', AppColors.error), const SizedBox(width: 12), - _alertStatCard('今日已处理', '5', AppColors.success), + _alertStatCard(context.t('merchantAi.resolvedToday'), '5', AppColors.success), const SizedBox(width: 12), - _alertStatCard('风险指数', '低', AppColors.info), + _alertStatCard(context.t('merchantAi.riskIndex'), context.t('merchantAi.riskLow'), AppColors.info), ], ); } @@ -717,9 +686,7 @@ class _MerchantAiAssistantPageState extends State ), child: Column( children: [ - Text(value, - style: TextStyle( - fontSize: 22, fontWeight: FontWeight.w700, color: color)), + Text(value, style: TextStyle(fontSize: 22, fontWeight: FontWeight.w700, color: color)), const SizedBox(height: 2), Text(label, style: AppTypography.caption.copyWith(color: color)), ], @@ -741,27 +708,24 @@ class _MerchantAiAssistantPageState extends State children: [ Row( children: [ - const Icon(Icons.warning_amber_rounded, - color: AppColors.error, size: 20), + const Icon(Icons.warning_amber_rounded, color: AppColors.error, size: 20), const SizedBox(width: 8), - Text('活跃预警', - style: - AppTypography.labelLarge.copyWith(color: AppColors.error)), + Text(context.t('merchantAi.activeAlerts'), style: AppTypography.labelLarge.copyWith(color: AppColors.error)), ], ), const SizedBox(height: 12), _alertItem( - '高频核销检测', - '用户#78901 在 5 分钟内尝试核销 3 张同品牌券', - '2 分钟前', + context.t('merchantAi.highFreqRedeem'), + 'User #78901 attempted 3 redeems of same brand in 5 minutes', + '2 min ago', AppColors.error, Icons.speed_rounded, ), const Divider(height: 20), _alertItem( - '疑似伪造券码', - '券码 GNX-FAKE-001 格式异常,不在系统记录中', - '15 分钟前', + context.t('merchantAi.suspectFakeCode'), + 'Code GNX-FAKE-001 format abnormal, not in system', + '15 min ago', AppColors.warning, Icons.gpp_bad_rounded, ), @@ -770,16 +734,14 @@ class _MerchantAiAssistantPageState extends State ); } - Widget _alertItem( - String title, String desc, String time, Color color, IconData icon) { + Widget _alertItem(String title, String desc, String time, Color color, IconData icon) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - width: 36, - height: 36, + width: 36, height: 36, decoration: BoxDecoration( color: color.withValues(alpha: 0.1), borderRadius: AppSpacing.borderRadiusSm, @@ -817,28 +779,23 @@ class _MerchantAiAssistantPageState extends State children: [ Row( children: [ - const Icon(Icons.pattern_rounded, - color: AppColors.warning, size: 20), + const Icon(Icons.pattern_rounded, color: AppColors.warning, size: 20), const SizedBox(width: 8), - Text('可疑模式检测', style: AppTypography.labelLarge), + Text(context.t('merchantAi.suspiciousPatterns'), style: AppTypography.labelLarge), ], ), const SizedBox(height: 12), - _patternItem( - '同一用户连续核销', '3次/5分钟 (阈值: 2次/5分钟)', 0.8, AppColors.error), + _patternItem(context.t('merchantAi.consecutiveRedeem'), '3x/5min (threshold: 2x/5min)', 0.8, AppColors.error), const SizedBox(height: 10), - _patternItem( - '非营业时间核销尝试', '0次/本周', 0.0, AppColors.success), + _patternItem(context.t('merchantAi.offHoursRedeem'), '0x/week', 0.0, AppColors.success), const SizedBox(height: 10), - _patternItem( - '过期券核销尝试', '2次/今日', 0.4, AppColors.warning), + _patternItem(context.t('merchantAi.expiredRedeemAttempt'), '2x/today', 0.4, AppColors.warning), ], ), ); } - Widget _patternItem( - String label, String detail, double severity, Color color) { + Widget _patternItem(String label, String detail, double severity, Color color) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -854,12 +811,11 @@ class _MerchantAiAssistantPageState extends State ), child: Text( severity > 0.6 - ? '异常' + ? context.t('merchantAi.statusAbnormal') : severity > 0.2 - ? '注意' - : '正常', - style: TextStyle( - fontSize: 10, fontWeight: FontWeight.w600, color: color), + ? context.t('merchantAi.statusWarning') + : context.t('merchantAi.statusNormal'), + style: TextStyle(fontSize: 10, fontWeight: FontWeight.w600, color: color), ), ), ], @@ -891,13 +847,13 @@ class _MerchantAiAssistantPageState extends State child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('今日已处理', style: AppTypography.labelLarge), + Text(context.t('merchantAi.resolvedToday'), style: AppTypography.labelLarge), const SizedBox(height: 12), - _resolvedItem('过期券核销拦截', '系统自动拦截', '10:24'), - _resolvedItem('重复核销拦截', '同一券码二次扫描', '11:05'), - _resolvedItem('非本店券提醒', '引导至正确门店', '12:30'), - _resolvedItem('余额不足核销', '告知顾客充值', '13:15'), - _resolvedItem('系统超时重试', '网络恢复后自动完成', '14:02'), + _resolvedItem(context.t('merchantAi.expiredBlock'), 'Auto-blocked', '10:24'), + _resolvedItem(context.t('merchantAi.duplicateBlock'), 'Same code scanned twice', '11:05'), + _resolvedItem(context.t('merchantAi.wrongStoreAlert'), 'Directed to correct store', '12:30'), + _resolvedItem(context.t('merchantAi.insufficientBalance'), 'Customer notified', '13:15'), + _resolvedItem(context.t('merchantAi.systemRetry'), 'Auto-completed on reconnect', '14:02'), ], ), ); @@ -908,8 +864,7 @@ class _MerchantAiAssistantPageState extends State padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ - const Icon(Icons.check_circle_rounded, - color: AppColors.success, size: 16), + const Icon(Icons.check_circle_rounded, color: AppColors.success, size: 16), const SizedBox(width: 10), Expanded( child: Column( @@ -920,9 +875,7 @@ class _MerchantAiAssistantPageState extends State ], ), ), - Text(time, - style: AppTypography.caption - .copyWith(fontFamily: 'monospace')), + Text(time, style: AppTypography.caption.copyWith(fontFamily: 'monospace')), ], ), ); diff --git a/frontend/mobile/lib/features/merchant/presentation/pages/merchant_home_page.dart b/frontend/mobile/lib/features/merchant/presentation/pages/merchant_home_page.dart index 0f9b40b..2f43343 100644 --- a/frontend/mobile/lib/features/merchant/presentation/pages/merchant_home_page.dart +++ b/frontend/mobile/lib/features/merchant/presentation/pages/merchant_home_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -20,10 +21,10 @@ class MerchantHomePage extends StatelessWidget { child: Column( children: [ // Header - _buildHeader(), + _buildHeader(context), // Network Status - _buildNetworkStatus(isOnline: true), + _buildNetworkStatus(context, isOnline: true), // Main Scanner Area Expanded(child: _buildScannerArea(context)), @@ -36,7 +37,7 @@ class MerchantHomePage extends StatelessWidget { ); } - Widget _buildHeader() { + Widget _buildHeader(BuildContext context) { return Container( padding: const EdgeInsets.fromLTRB(20, 12, 20, 12), child: Row( @@ -55,8 +56,8 @@ class MerchantHomePage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('星巴克 朝阳门店', style: AppTypography.labelMedium), - Text('收银员 - 张三', style: AppTypography.caption), + Text('Starbucks Store', style: AppTypography.labelMedium), + Text('${context.t('merchant.redeemOperator')} - Staff', style: AppTypography.caption), ], ), ), @@ -72,7 +73,7 @@ class MerchantHomePage extends StatelessWidget { children: [ const Icon(Icons.check_circle_rounded, size: 14, color: AppColors.success), const SizedBox(width: 4), - Text('今日 23 笔', style: AppTypography.labelSmall.copyWith( + Text('${context.t('merchant.today')} 23 ${context.t('merchant.syncUnit')}', style: AppTypography.labelSmall.copyWith( color: AppColors.success, )), ], @@ -83,7 +84,7 @@ class MerchantHomePage extends StatelessWidget { ); } - Widget _buildNetworkStatus({required bool isOnline}) { + Widget _buildNetworkStatus(BuildContext context, {required bool isOnline}) { return Container( margin: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), @@ -103,7 +104,9 @@ class MerchantHomePage extends StatelessWidget { ), const SizedBox(width: 6), Text( - isOnline ? '在线模式' : '离线模式 - 待同步 3 笔', + isOnline + ? context.t('merchant.onlineMode') + : '${context.t('merchant.offlineMode')} - ${context.t('merchant.pendingSync')} 3 ${context.t('merchant.syncUnit')}', style: AppTypography.caption.copyWith( color: isOnline ? AppColors.success : AppColors.warning, fontWeight: FontWeight.w500, @@ -153,7 +156,7 @@ class MerchantHomePage extends StatelessWidget { ), const SizedBox(height: 20), Text( - '将券二维码对准扫描框', + context.t('merchant.scanHint'), style: AppTypography.bodyMedium.copyWith(color: Colors.white70), ), ], @@ -182,7 +185,7 @@ class MerchantHomePage extends StatelessWidget { color: Colors.white70, size: 22), ), const SizedBox(height: 4), - Text('手电筒', style: AppTypography.caption.copyWith(color: Colors.white54)), + Text(context.t('merchant.flashlight'), style: AppTypography.caption.copyWith(color: Colors.white54)), ], ), ), @@ -247,16 +250,16 @@ class MerchantHomePage extends StatelessWidget { padding: const EdgeInsets.fromLTRB(20, 12, 20, 16), child: Row( children: [ - _bottomAction(Icons.keyboard_rounded, '手动输码', () { + _bottomAction(Icons.keyboard_rounded, context.t('merchant.manualInput'), () { _showManualInput(context); }), const SizedBox(width: 16), - _bottomAction(Icons.history_rounded, '核销记录', () { - // Navigator: → RedeemHistoryPage + _bottomAction(Icons.history_rounded, context.t('merchant.redeemRecords'), () { + // Navigator: -> RedeemHistoryPage }), const SizedBox(width: 16), - _bottomAction(Icons.bar_chart_rounded, '门店数据', () { - // Navigator: → StoreDashboardPage + _bottomAction(Icons.bar_chart_rounded, context.t('merchant.storeData'), () { + // Navigator: -> StoreDashboardPage }), ], ), @@ -310,20 +313,20 @@ class MerchantHomePage extends StatelessWidget { ), ), const SizedBox(height: 20), - Text('手动输入券码', style: AppTypography.h2), + Text(context.t('merchant.inputCode'), style: AppTypography.h2), const SizedBox(height: 16), TextField( autofocus: true, - decoration: const InputDecoration( - hintText: '请输入券码', - prefixIcon: Icon(Icons.confirmation_number_outlined, + decoration: InputDecoration( + hintText: context.t('merchant.inputCodeHint'), + prefixIcon: const Icon(Icons.confirmation_number_outlined, color: AppColors.textTertiary), ), textCapitalization: TextCapitalization.characters, ), const SizedBox(height: 16), GenexButton( - label: '查询', + label: context.t('merchant.query'), onPressed: () {}, ), ], @@ -369,8 +372,8 @@ class RedeemConfirmSheet extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('用户昵称', style: AppTypography.labelMedium), - Text('消费者', style: AppTypography.caption), + Text(context.t('merchant.userNickname'), style: AppTypography.labelMedium), + Text(context.t('merchant.consumer'), style: AppTypography.caption), ], ), ], @@ -387,20 +390,20 @@ class RedeemConfirmSheet extends StatelessWidget { ), child: Column( children: [ - _row('券名称', '星巴克 \$25 礼品卡'), + _row(context, context.t('merchant.couponName'), 'Starbucks \$25 Gift Card'), const SizedBox(height: 8), - _row('面值', '\$25.00'), + _row(context, context.t('merchant.faceValue'), '\$25.00'), const SizedBox(height: 8), - _row('有效期', '2026/12/31'), + _row(context, context.t('merchant.validUntil'), '2026/12/31'), const SizedBox(height: 8), - _row('使用条件', '无最低消费'), + _row(context, context.t('merchant.useCondition'), context.t('merchant.noMinSpend')), ], ), ), const SizedBox(height: 24), GenexButton( - label: '确认核销', + label: context.t('merchant.confirmRedeem'), onPressed: () { Navigator.of(context).pop(); // Show success @@ -408,7 +411,7 @@ class RedeemConfirmSheet extends StatelessWidget { ), const SizedBox(height: 8), GenexButton( - label: '取消', + label: context.t('common.cancel'), variant: GenexButtonVariant.text, onPressed: () => Navigator.of(context).pop(), ), @@ -417,7 +420,7 @@ class RedeemConfirmSheet extends StatelessWidget { ); } - Widget _row(String label, String value) { + Widget _row(BuildContext context, String label, String value) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -456,14 +459,14 @@ class RedeemSuccessSheet extends StatelessWidget { child: const Icon(Icons.check_rounded, color: Colors.white, size: 36), ), const SizedBox(height: 16), - Text('核销成功', style: AppTypography.h1), + Text(context.t('merchant.redeemSuccess'), style: AppTypography.h1), const SizedBox(height: 8), - Text('星巴克 \$25 礼品卡', style: AppTypography.bodyMedium.copyWith( + Text('Starbucks \$25 Gift Card', style: AppTypography.bodyMedium.copyWith( color: AppColors.textSecondary, )), const SizedBox(height: 32), GenexButton( - label: '继续核销', + label: context.t('merchant.continueRedeem'), onPressed: () => Navigator.of(context).pop(), ), ], @@ -484,11 +487,11 @@ class RedeemHistoryPage extends StatelessWidget { icon: const Icon(Icons.arrow_back_ios_new_rounded, size: 20), onPressed: () => Navigator.of(context).pop(), ), - title: const Text('核销记录'), + title: Text(context.t('merchant.redeemRecords')), actions: [ TextButton( onPressed: () {}, - child: Text('今日', style: AppTypography.labelSmall.copyWith( + child: Text(context.t('common.today'), style: AppTypography.labelSmall.copyWith( color: AppColors.primary, )), ), @@ -526,15 +529,15 @@ class RedeemHistoryPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('品牌 ${index + 1} \$${(index + 1) * 10} 券', + Text('Brand ${index + 1} \$${(index + 1) * 10} Voucher', style: AppTypography.labelSmall), - Text('核销员: 张三 · 14:${30 + index}', + Text('${context.t('merchant.redeemOperator')}: Staff · 14:${30 + index}', style: AppTypography.caption), ], ), ), Text( - isSync ? '已同步' : '待同步', + isSync ? context.t('merchant.synced') : context.t('merchant.pendingSyncLabel'), style: AppTypography.caption.copyWith( color: isSync ? AppColors.success : AppColors.warning, ), @@ -560,7 +563,7 @@ class StoreDashboardPage extends StatelessWidget { icon: const Icon(Icons.arrow_back_ios_new_rounded, size: 20), onPressed: () => Navigator.of(context).pop(), ), - title: const Text('门店数据'), + title: Text(context.t('merchant.storeData')), ), body: SingleChildScrollView( padding: AppSpacing.pagePadding, @@ -572,15 +575,15 @@ class StoreDashboardPage extends StatelessWidget { // Today Stats Row( children: [ - _statCard('今日核销', '23笔', Icons.check_circle_rounded, AppColors.success), + _statCard(context.t('merchant.todayRedeem'), '23${context.t('merchant.syncUnit')}', Icons.check_circle_rounded, AppColors.success), const SizedBox(width: 12), - _statCard('核销金额', '\$1,456', Icons.attach_money_rounded, AppColors.primary), + _statCard(context.t('merchant.redeemAmount'), '\$1,456', Icons.attach_money_rounded, AppColors.primary), ], ), const SizedBox(height: 24), // Weekly Trend (placeholder) - Text('本周趋势', style: AppTypography.h3), + Text(context.t('merchant.weekTrend'), style: AppTypography.h3), const SizedBox(height: 12), Container( height: 200, @@ -590,17 +593,17 @@ class StoreDashboardPage extends StatelessWidget { border: Border.all(color: AppColors.borderLight), ), child: Center( - child: Text('周核销趋势图 (fl_chart)', + child: Text('Weekly Redeem Trend (fl_chart)', style: AppTypography.bodySmall.copyWith(color: AppColors.textTertiary)), ), ), const SizedBox(height: 24), // Staff Ranking - Text('核销员排行', style: AppTypography.h3), + Text(context.t('merchant.operatorRank'), style: AppTypography.h3), const SizedBox(height: 12), ...List.generate(3, (index) { - final names = ['张三', '李四', '王五']; + final names = ['Staff A', 'Staff B', 'Staff C']; final counts = [12, 8, 3]; return Container( margin: const EdgeInsets.only(bottom: 8), @@ -631,7 +634,7 @@ class StoreDashboardPage extends StatelessWidget { const SizedBox(width: 12), Text(names[index], style: AppTypography.labelMedium), const Spacer(), - Text('${counts[index]}笔', style: AppTypography.bodyMedium.copyWith( + Text('${counts[index]}${context.t('merchant.syncUnit')}', style: AppTypography.bodyMedium.copyWith( color: AppColors.primary, )), ], diff --git a/frontend/mobile/lib/features/message/presentation/pages/message_detail_page.dart b/frontend/mobile/lib/features/message/presentation/pages/message_detail_page.dart index 1815d49..88b0465 100644 --- a/frontend/mobile/lib/features/message/presentation/pages/message_detail_page.dart +++ b/frontend/mobile/lib/features/message/presentation/pages/message_detail_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -8,19 +9,20 @@ import '../../../../app/theme/app_spacing.dart'; /// 查看单条通知的详细内容 /// 类型:交易通知、到期提醒、系统通知、活动推送 class MessageDetailPage extends StatelessWidget { - final String title; + final String? title; final String type; const MessageDetailPage({ super.key, - this.title = '交易成功通知', + this.title, this.type = 'transaction', }); @override Widget build(BuildContext context) { + final displayTitle = title ?? context.t('message.tradeSuccess'); return Scaffold( - appBar: AppBar(title: const Text('消息详情')), + appBar: AppBar(title: Text(context.t('message.detailTitle'))), body: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( @@ -45,16 +47,16 @@ class MessageDetailPage extends StatelessWidget { color: _typeColor.withValues(alpha: 0.1), borderRadius: AppSpacing.borderRadiusFull, ), - child: Text(_typeLabel, style: TextStyle(fontSize: 11, color: _typeColor, fontWeight: FontWeight.w600)), + child: Text(_getTypeLabel(context), style: TextStyle(fontSize: 11, color: _typeColor, fontWeight: FontWeight.w600)), ), ], ), const SizedBox(height: 16), // Title - Text(title, style: AppTypography.h1), + Text(displayTitle, style: AppTypography.h1), const SizedBox(height: 8), - Text('2026年2月10日 14:32', style: AppTypography.bodySmall), + Text('2026-02-10 14:32', style: AppTypography.bodySmall), const SizedBox(height: 24), // Content @@ -65,19 +67,19 @@ class MessageDetailPage extends StatelessWidget { borderRadius: AppSpacing.borderRadiusMd, border: Border.all(color: AppColors.borderLight), ), - child: const Column( + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - '您成功购买了 星巴克 \$25 礼品卡,支付金额 \$21.25。', + const Text( + 'You purchased Starbucks \$25 Gift Card for \$21.25.', style: TextStyle(fontSize: 15, height: 1.6), ), - SizedBox(height: 16), - _DetailRow('券名称', '星巴克 \$25 礼品卡'), - _DetailRow('面值', '\$25.00'), - _DetailRow('支付金额', '\$21.25'), - _DetailRow('订单号', 'GNX20260210001'), - _DetailRow('支付方式', 'Visa •••• 4242'), + const SizedBox(height: 16), + _DetailRow(context.t('message.couponName'), 'Starbucks \$25 Gift Card'), + _DetailRow(context.t('message.faceValue'), '\$25.00'), + _DetailRow(context.t('message.payAmount'), '\$21.25'), + _DetailRow(context.t('message.orderNo'), 'GNX20260210001'), + _DetailRow(context.t('message.payMethod'), 'Visa •••• 4242'), ], ), ), @@ -88,7 +90,7 @@ class MessageDetailPage extends StatelessWidget { width: double.infinity, child: OutlinedButton( onPressed: () {}, - child: const Text('查看券详情'), + child: Text(context.t('message.viewCouponDetail')), ), ), ], @@ -115,12 +117,12 @@ class MessageDetailPage extends StatelessWidget { } } - String get _typeLabel { + String _getTypeLabel(BuildContext context) { switch (type) { - case 'transaction': return '交易通知'; - case 'expiry': return '到期提醒'; - case 'system': return '系统通知'; - default: return '活动推送'; + case 'transaction': return context.t('message.tradeNotify'); + case 'expiry': return context.t('message.expiryRemind'); + case 'system': return context.t('message.systemNotify'); + default: return context.t('message.promoNotify'); } } } diff --git a/frontend/mobile/lib/features/message/presentation/pages/message_page.dart b/frontend/mobile/lib/features/message/presentation/pages/message_page.dart index e01960f..902f919 100644 --- a/frontend/mobile/lib/features/message/presentation/pages/message_page.dart +++ b/frontend/mobile/lib/features/message/presentation/pages/message_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -35,22 +36,22 @@ class _MessagePageState extends State Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('消息'), + title: Text(context.t('message.title')), actions: [ TextButton( onPressed: () {}, - child: Text('全部已读', style: AppTypography.labelSmall.copyWith( + child: Text(context.t('message.markAllRead'), style: AppTypography.labelSmall.copyWith( color: AppColors.primary, )), ), ], bottom: TabBar( controller: _tabController, - tabs: const [ - Tab(text: '全部'), - Tab(text: '交易'), - Tab(text: '到期'), - Tab(text: '公告'), + tabs: [ + Tab(text: context.t('common.all')), + Tab(text: context.t('message.tabTrade')), + Tab(text: context.t('message.tabExpiry')), + Tab(text: context.t('message.tabAnnouncement')), ], ), ), @@ -68,7 +69,7 @@ class _MessagePageState extends State Widget _buildMessageList({bool all = false, MessageType? type}) { if (type == MessageType.announcement) { - return EmptyState.noMessages(); + return EmptyState.noMessages(context: context); } final messages = _mockMessages @@ -178,36 +179,36 @@ class _MockMessage { const _mockMessages = [ _MockMessage( - '购买成功', - '您已成功购买 星巴克 \$25 礼品卡,共花费 \$21.25', + 'Purchase Successful', + 'You have successfully purchased Starbucks \$25 Gift Card for \$21.25', '14:32', MessageType.transaction, false, ), _MockMessage( - '券即将到期', - '您持有的 Target \$30 折扣券 将于3天后到期,请及时使用', + 'Coupon Expiring Soon', + 'Your Target \$30 Voucher will expire in 3 days', '10:15', MessageType.expiry, false, ), _MockMessage( - '价格提醒', - '您关注的 Amazon \$100 购物券 当前价格已降至 \$82,低于您设定的提醒价格', - '昨天', + 'Price Alert', + 'Amazon \$100 Voucher price dropped to \$82, below your alert price', + 'Yesterday', MessageType.price, true, ), _MockMessage( - '出售成交', - '您挂单出售的 Nike \$80 运动券 已成功售出,收入 \$68.00', + 'Sale Completed', + 'Your listed Nike \$80 Voucher has been sold for \$68.00', '02/07', MessageType.transaction, true, ), _MockMessage( - '核销成功', - 'Walmart \$50 生活券 已在门店核销成功', + 'Redeem Successful', + 'Walmart \$50 Voucher redeemed at store', '02/06', MessageType.transaction, true, diff --git a/frontend/mobile/lib/features/profile/presentation/pages/kyc_page.dart b/frontend/mobile/lib/features/profile/presentation/pages/kyc_page.dart index 56236ba..66182ab 100644 --- a/frontend/mobile/lib/features/profile/presentation/pages/kyc_page.dart +++ b/frontend/mobile/lib/features/profile/presentation/pages/kyc_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -13,34 +14,37 @@ class KycPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('身份认证')), + appBar: AppBar(title: Text(context.t('kyc.title'))), body: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( children: [ // Current Level - _buildCurrentLevel(), + _buildCurrentLevel(context), const SizedBox(height: 24), // KYC Levels _buildLevel( - 'L1 基础认证', - '手机号 + 邮箱验证', - ['每日购买限额 \$500', '可购买券、出示核销'], + context, + context.t('kyc.l1Title'), + context.t('kyc.l1Desc'), + [context.t('kyc.l1Limit'), context.t('kyc.l1Feature')], true, AppColors.success, ), _buildLevel( - 'L2 身份认证', - '身份证/护照验证', - ['每日购买限额 \$5,000', '解锁二级市场交易、P2P转赠'], + context, + context.t('kyc.l2Title'), + context.t('kyc.l2Desc'), + [context.t('kyc.l2Limit'), context.t('kyc.l2Feature')], false, AppColors.info, ), _buildLevel( - 'L3 高级认证', - '视频面审 + 地址证明', - ['无限额', '解锁大额交易、提现无限制'], + context, + context.t('kyc.l3Title'), + context.t('kyc.l3Desc'), + [context.t('kyc.l3Limit'), context.t('kyc.l3Feature')], false, AppColors.primary, ), @@ -50,7 +54,7 @@ class KycPage extends StatelessWidget { ); } - Widget _buildCurrentLevel() { + Widget _buildCurrentLevel(BuildContext context) { return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( @@ -73,11 +77,11 @@ class KycPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('当前认证等级', style: AppTypography.bodySmall.copyWith(color: Colors.white70)), + Text(context.t('kyc.currentLevel'), style: AppTypography.bodySmall.copyWith(color: Colors.white70)), const SizedBox(height: 4), - Text('L1 基础认证', style: AppTypography.h1.copyWith(color: Colors.white)), + Text(context.t('kyc.l1Title'), style: AppTypography.h1.copyWith(color: Colors.white)), const SizedBox(height: 4), - Text('每日购买限额 \$500', style: AppTypography.bodySmall.copyWith(color: Colors.white60)), + Text(context.t('kyc.l1Limit'), style: AppTypography.bodySmall.copyWith(color: Colors.white60)), ], ), ), @@ -87,6 +91,7 @@ class KycPage extends StatelessWidget { } Widget _buildLevel( + BuildContext context, String title, String requirement, List benefits, @@ -136,7 +141,7 @@ class KycPage extends StatelessWidget { color: AppColors.successLight, borderRadius: AppSpacing.borderRadiusFull, ), - child: Text('已完成', style: AppTypography.caption.copyWith(color: AppColors.success)), + child: Text(context.t('kyc.completed'), style: AppTypography.caption.copyWith(color: AppColors.success)), ) else ElevatedButton( @@ -145,7 +150,7 @@ class KycPage extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), minimumSize: Size.zero, ), - child: const Text('去认证', style: TextStyle(fontSize: 13)), + child: Text(context.t('kyc.goVerify'), style: const TextStyle(fontSize: 13)), ), ], ), diff --git a/frontend/mobile/lib/features/profile/presentation/pages/payment_management_page.dart b/frontend/mobile/lib/features/profile/presentation/pages/payment_management_page.dart index 00e8daa..4f27841 100644 --- a/frontend/mobile/lib/features/profile/presentation/pages/payment_management_page.dart +++ b/frontend/mobile/lib/features/profile/presentation/pages/payment_management_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -12,11 +13,11 @@ class PaymentManagementPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('支付管理')), + appBar: AppBar(title: Text(context.t('payManage.title'))), body: ListView( padding: const EdgeInsets.all(20), children: [ - Text('我的银行卡', style: AppTypography.h3), + Text(context.t('payManage.myCards'), style: AppTypography.h3), const SizedBox(height: 12), // Card List @@ -32,19 +33,19 @@ class PaymentManagementPage extends StatelessWidget { border: Border.all(color: AppColors.border, style: BorderStyle.solid), borderRadius: AppSpacing.borderRadiusMd, ), - child: const Row( + child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.add_circle_outline_rounded, color: AppColors.primary), - SizedBox(width: 8), - Text('添加新银行卡', style: TextStyle(color: AppColors.primary, fontWeight: FontWeight.w600)), + const Icon(Icons.add_circle_outline_rounded, color: AppColors.primary), + const SizedBox(width: 8), + Text(context.t('payManage.addCard'), style: const TextStyle(color: AppColors.primary, fontWeight: FontWeight.w600)), ], ), ), const SizedBox(height: 32), // Bank Account - Text('银行账户(提现用)', style: AppTypography.h3), + Text(context.t('payManage.bankAccount'), style: AppTypography.h3), const SizedBox(height: 12), Container( padding: AppSpacing.cardPadding, @@ -62,7 +63,7 @@ class PaymentManagementPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Bank of America', style: AppTypography.labelMedium), - Text('•••• 6789 · 储蓄账户', style: AppTypography.caption), + Text('•••• 6789 · ${context.t('withdraw.savingsAccount')}', style: AppTypography.caption), ], ), ), @@ -73,11 +74,11 @@ class PaymentManagementPage extends StatelessWidget { const SizedBox(height: 32), // Payment Security - Text('支付安全', style: AppTypography.h3), + Text(context.t('payManage.paymentSecurity'), style: AppTypography.h3), const SizedBox(height: 12), - _buildSettingTile('支付密码', '已设置', Icons.password_rounded), - _buildSettingTile('指纹/面容支付', '已开启', Icons.fingerprint_rounded), - _buildSettingTile('免密支付', '单笔≤\$10', Icons.flash_on_rounded), + _buildSettingTile(context.t('payManage.paymentPassword'), context.t('payManage.passwordSet'), Icons.password_rounded), + _buildSettingTile(context.t('payManage.biometricPay'), context.t('payManage.biometricEnabled'), Icons.fingerprint_rounded), + _buildSettingTile(context.t('payManage.noPasswordPay'), context.t('payManage.noPasswordLimit'), Icons.flash_on_rounded), ], ), ); diff --git a/frontend/mobile/lib/features/profile/presentation/pages/pro_mode_page.dart b/frontend/mobile/lib/features/profile/presentation/pages/pro_mode_page.dart index b5b3971..0af30f3 100644 --- a/frontend/mobile/lib/features/profile/presentation/pages/pro_mode_page.dart +++ b/frontend/mobile/lib/features/profile/presentation/pages/pro_mode_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -27,7 +28,7 @@ class _ProModePageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('高级模式')), + appBar: AppBar(title: Text(context.t('proMode.title'))), body: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( @@ -90,7 +91,7 @@ class _ProModePageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '高级模式 (Pro)', + '${context.t('proMode.title')} (Pro)', style: TextStyle( fontSize: 17, fontWeight: FontWeight.w700, @@ -99,7 +100,7 @@ class _ProModePageState extends State { ), const SizedBox(height: 2), Text( - '开启后可查看链上信息和连接外部钱包', + context.t('proMode.toggleDesc'), style: TextStyle( fontSize: 12, color: _proModeEnabled ? Colors.white70 : AppColors.textSecondary, @@ -124,9 +125,9 @@ class _ProModePageState extends State { color: Colors.white.withValues(alpha: 0.15), borderRadius: AppSpacing.borderRadiusFull, ), - child: const Text( - '需要 KYC L2 及以上认证', - style: TextStyle(fontSize: 11, color: Colors.white70), + child: Text( + context.t('proMode.requireKycL2'), + style: const TextStyle(fontSize: 11, color: Colors.white70), ), ), ], @@ -159,7 +160,7 @@ class _ProModePageState extends State { color: AppColors.successLight, borderRadius: AppSpacing.borderRadiusFull, ), - child: const Text('已连接', style: TextStyle(fontSize: 11, color: AppColors.success, fontWeight: FontWeight.w600)), + child: Text(context.t('proMode.connected'), style: const TextStyle(fontSize: 11, color: AppColors.success, fontWeight: FontWeight.w600)), ), ], ), @@ -186,7 +187,7 @@ class _ProModePageState extends State { ), TextButton( onPressed: () => setState(() => _walletConnected = false), - child: const Text('断开', style: TextStyle(color: AppColors.error, fontSize: 13)), + child: Text(context.t('proMode.disconnect'), style: const TextStyle(color: AppColors.error, fontSize: 13)), ), ], ), @@ -197,12 +198,12 @@ class _ProModePageState extends State { child: OutlinedButton.icon( onPressed: () => setState(() => _walletConnected = true), icon: const Icon(Icons.link_rounded, size: 18), - label: const Text('连接外部钱包'), + label: Text(context.t('proMode.connectWallet')), ), ), const SizedBox(height: 8), Text( - '连接外部钱包后可将平台资产提取至自有地址', + context.t('proMode.walletDesc'), style: AppTypography.caption, ), ], @@ -221,8 +222,8 @@ class _ProModePageState extends State { child: Column( children: [ SwitchListTile( - title: Text('显示链上地址', style: AppTypography.labelMedium), - subtitle: Text('在券详情中展示合约地址', style: AppTypography.caption), + title: Text(context.t('proMode.showChainAddress'), style: AppTypography.labelMedium), + subtitle: Text(context.t('proMode.showChainAddressDesc'), style: AppTypography.caption), value: _showChainAddress, onChanged: (v) => setState(() => _showChainAddress = v), activeColor: AppColors.primary, @@ -230,8 +231,8 @@ class _ProModePageState extends State { ), const Divider(height: 1), SwitchListTile( - title: Text('显示交易Hash', style: AppTypography.labelMedium), - subtitle: Text('在交易记录中展示链上Hash', style: AppTypography.caption), + title: Text(context.t('proMode.showTxHash'), style: AppTypography.labelMedium), + subtitle: Text(context.t('proMode.showTxHashDesc'), style: AppTypography.caption), value: _showTxHash, onChanged: (v) => setState(() => _showTxHash = v), activeColor: AppColors.primary, @@ -257,18 +258,18 @@ class _ProModePageState extends State { children: [ const Icon(Icons.explore_rounded, color: AppColors.primary, size: 20), const SizedBox(width: 8), - Text('交易浏览器', style: AppTypography.labelLarge), + Text(context.t('proMode.txExplorer'), style: AppTypography.labelLarge), ], ), const SizedBox(height: 12), - _buildTxItem('购买 星巴克 \$25 礼品卡', '0xabc1...def3', '已确认', AppColors.success), - _buildTxItem('出售 Amazon \$100 券', '0x789a...bc12', '已确认', AppColors.success), - _buildTxItem('转赠给 Alice', '0xdef4...5678', '确认中', AppColors.warning), + _buildTxItem(context.t('proMode.txBuyExample'), '0xabc1...def3', context.t('proMode.confirmed'), AppColors.success), + _buildTxItem(context.t('proMode.txSellExample'), '0x789a...bc12', context.t('proMode.confirmed'), AppColors.success), + _buildTxItem('Transfer to Alice', '0xdef4...5678', context.t('proMode.confirming'), AppColors.warning), const SizedBox(height: 8), Center( child: TextButton( onPressed: () {}, - child: const Text('查看全部链上交易'), + child: Text(context.t('proMode.viewAllTx')), ), ), ], @@ -318,19 +319,19 @@ class _ProModePageState extends State { children: [ const Icon(Icons.token_rounded, color: AppColors.primary, size: 20), const SizedBox(width: 8), - Text('链上资产', style: AppTypography.labelLarge), + Text(context.t('proMode.chainAssets'), style: AppTypography.labelLarge), ], ), const SizedBox(height: 12), - _buildAssetRow('平台托管钱包', '0x1234...abcd', '5 张券'), - if (_walletConnected) _buildAssetRow('外部钱包 (MetaMask)', '0x7a3b...c4f2', '0 张券'), + _buildAssetRow(context.t('proMode.custodialWallet'), '0x1234...abcd', context.t('proMode.couponCount5')), + if (_walletConnected) _buildAssetRow(context.t('proMode.externalWallet'), '0x7a3b...c4f2', context.t('proMode.couponCount0')), const SizedBox(height: 12), if (_walletConnected) SizedBox( width: double.infinity, child: OutlinedButton( onPressed: () {}, - child: const Text('提取至外部钱包'), + child: Text(context.t('proMode.extractToWallet')), ), ), ], @@ -373,16 +374,16 @@ class _ProModePageState extends State { children: [ const Icon(Icons.swap_horiz_rounded, color: AppColors.primary, size: 20), const SizedBox(width: 8), - Text('交易轨道', style: AppTypography.labelLarge), + Text(context.t('proMode.tradeTrack'), style: AppTypography.labelLarge), ], ), const SizedBox(height: 12), - _buildTrackOption('Utility Track', '券有效期≤12个月,无需证券牌照', AppColors.success, true), + _buildTrackOption('Utility Track', context.t('proMode.utilityTrackDesc'), AppColors.success, true), const SizedBox(height: 8), - _buildTrackOption('Securities Track', '长期投资型券产品(即将推出)', AppColors.warning, false), + _buildTrackOption('Securities Track', context.t('proMode.securitiesTrackDesc'), AppColors.warning, false), const SizedBox(height: 8), Text( - '当前MVP版本仅支持Utility Track', + context.t('proMode.mvpNote'), style: AppTypography.caption.copyWith(color: AppColors.textTertiary), ), ], @@ -419,7 +420,7 @@ class _ProModePageState extends State { ), ), if (active) Icon(Icons.check_circle_rounded, color: color, size: 20), - if (!active) Text('敬请期待', style: AppTypography.caption.copyWith(color: AppColors.textTertiary)), + if (!active) Text(context.t('proMode.comingSoon'), style: AppTypography.caption.copyWith(color: AppColors.textTertiary)), ], ), ); @@ -438,15 +439,10 @@ class _ProModePageState extends State { children: [ const Icon(Icons.info_outline_rounded, color: AppColors.textTertiary, size: 40), const SizedBox(height: 12), - Text('什么是高级模式?', style: AppTypography.h3), + Text(context.t('proMode.whatIsTitle'), style: AppTypography.h3), const SizedBox(height: 8), Text( - '高级模式面向有区块链经验的用户,开启后可以:\n' - '• 连接外部钱包(MetaMask等)\n' - '• 查看链上地址和交易Hash\n' - '• 将资产提取至自有钱包\n' - '• 查看底层链上数据\n\n' - '需要完成 KYC L2 认证后方可开启。', + context.t('proMode.whatIsDesc'), style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary, height: 1.6), ), ], diff --git a/frontend/mobile/lib/features/profile/presentation/pages/profile_page.dart b/frontend/mobile/lib/features/profile/presentation/pages/profile_page.dart index aa90437..2fecf8e 100644 --- a/frontend/mobile/lib/features/profile/presentation/pages/profile_page.dart +++ b/frontend/mobile/lib/features/profile/presentation/pages/profile_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -20,33 +21,33 @@ class ProfilePage extends StatelessWidget { SliverToBoxAdapter(child: _buildProfileHeader(context)), // Quick Stats - SliverToBoxAdapter(child: _buildQuickStats()), + SliverToBoxAdapter(child: _buildQuickStats(context)), // Menu Sections - SliverToBoxAdapter(child: _buildMenuSection('账户', [ - _MenuItem(Icons.verified_user_outlined, 'KYC 认证', '已完成 L1 认证', true, + SliverToBoxAdapter(child: _buildMenuSection(context.t('profile.account'), [ + _MenuItem(Icons.verified_user_outlined, context.t('profile.kyc'), 'L1', true, onTap: () => Navigator.pushNamed(context, '/kyc')), - _MenuItem(Icons.credit_card_rounded, '支付管理', '已绑定 2 张卡', true, + _MenuItem(Icons.credit_card_rounded, context.t('profile.paymentManage'), 'Visa •••• 4242', true, onTap: () => Navigator.pushNamed(context, '/payment/manage')), - _MenuItem(Icons.account_balance_wallet_outlined, '我的余额', '\$1,234.56', true, + _MenuItem(Icons.account_balance_wallet_outlined, context.t('profile.walletBalance'), '\$1,234.56', true, onTap: () => Navigator.pushNamed(context, '/wallet')), ])), - SliverToBoxAdapter(child: _buildMenuSection('交易', [ - _MenuItem(Icons.receipt_long_rounded, '交易记录', '', true, + SliverToBoxAdapter(child: _buildMenuSection(context.t('profile.trade'), [ + _MenuItem(Icons.receipt_long_rounded, context.t('profile.myTrades'), '', true, onTap: () => Navigator.pushNamed(context, '/trading')), - _MenuItem(Icons.storefront_rounded, '我的挂单', '2笔出售中', true, + _MenuItem(Icons.storefront_rounded, context.t('tradingPage.pendingOrders'), '', true, onTap: () => Navigator.pushNamed(context, '/trading')), - _MenuItem(Icons.favorite_border_rounded, '我的收藏', '', true), + _MenuItem(Icons.favorite_border_rounded, context.t('profile.myFavorites'), '', true), ])), - SliverToBoxAdapter(child: _buildMenuSection('设置', [ - _MenuItem(Icons.notifications_outlined, '通知设置', '', true), - _MenuItem(Icons.language_rounded, '语言', '简体中文', true), - _MenuItem(Icons.shield_outlined, '安全设置', '', true), - _MenuItem(Icons.tune_rounded, '高级设置', 'Pro模式', true, + SliverToBoxAdapter(child: _buildMenuSection(context.t('profile.settings'), [ + _MenuItem(Icons.notifications_outlined, context.t('settings.notifications'), '', true), + _MenuItem(Icons.language_rounded, context.t('settings.language'), context.t('profile.simplifiedChinese'), true), + _MenuItem(Icons.shield_outlined, context.t('profile.securitySettings'), '', true), + _MenuItem(Icons.tune_rounded, context.t('profile.advancedSettings'), context.t('profile.proMode'), true, onTap: () => Navigator.pushNamed(context, '/pro-mode')), - _MenuItem(Icons.info_outline_rounded, '关于 Genex', 'v1.0.0', true), + _MenuItem(Icons.info_outline_rounded, context.t('profile.aboutGenex'), 'v1.0.0', true), ])), // Logout @@ -57,7 +58,7 @@ class ProfilePage extends StatelessWidget { onPressed: () { Navigator.of(context).pushNamedAndRemoveUntil('/', (_) => false); }, - child: Text('退出登录', style: AppTypography.labelMedium.copyWith( + child: Text(context.t('profile.logout'), style: AppTypography.labelMedium.copyWith( color: AppColors.error, )), ), @@ -97,7 +98,7 @@ class ProfilePage extends StatelessWidget { children: [ Row( children: [ - Text('用户昵称', style: AppTypography.h2.copyWith(color: Colors.white)), + Text('User', style: AppTypography.h2.copyWith(color: Colors.white)), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), @@ -120,7 +121,7 @@ class ProfilePage extends StatelessWidget { ], ), const SizedBox(height: 4), - Text('信用积分: 750', style: AppTypography.bodySmall.copyWith( + Text('${context.t('profile.creditScore')}: 750', style: AppTypography.bodySmall.copyWith( color: Colors.white70, )), ], @@ -139,12 +140,12 @@ class ProfilePage extends StatelessWidget { ); } - Widget _buildQuickStats() { + Widget _buildQuickStats(BuildContext context) { final stats = [ - ('持券', '12'), - ('交易', '28'), - ('节省', '\$156'), - ('信用', '750'), + (context.t('profile.holdCoupons'), '12'), + (context.t('profile.trade'), '28'), + (context.t('profile.saved'), '\$156'), + (context.t('profile.credit'), '750'), ]; return Container( diff --git a/frontend/mobile/lib/features/profile/presentation/pages/settings_page.dart b/frontend/mobile/lib/features/profile/presentation/pages/settings_page.dart index 7249d8a..fd70914 100644 --- a/frontend/mobile/lib/features/profile/presentation/pages/settings_page.dart +++ b/frontend/mobile/lib/features/profile/presentation/pages/settings_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; @@ -11,47 +12,47 @@ class SettingsPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('设置')), + appBar: AppBar(title: Text(context.t('settings.title'))), body: ListView( children: [ // Account & Security - _buildSection('账号与安全', [ - _buildTile('手机号', subtitle: '138****8888', icon: Icons.phone_rounded), - _buildTile('邮箱', subtitle: 'u***@email.com', icon: Icons.email_rounded), - _buildTile('修改密码', icon: Icons.lock_rounded), - _buildTile('身份认证', subtitle: 'L1 基础认证', icon: Icons.verified_user_rounded, onTap: () { + _buildSection(context.t('settings.accountSecurity'), [ + _buildTile(context.t('settings.phone'), subtitle: '138****8888', icon: Icons.phone_rounded), + _buildTile(context.t('settings.email'), subtitle: 'u***@email.com', icon: Icons.email_rounded), + _buildTile(context.t('settings.changePassword'), icon: Icons.lock_rounded), + _buildTile(context.t('settings.identity'), subtitle: 'L1', icon: Icons.verified_user_rounded, onTap: () { Navigator.pushNamed(context, '/kyc'); }), ]), // Payment - _buildSection('支付管理', [ - _buildTile('支付方式', subtitle: 'Visa •••• 4242', icon: Icons.credit_card_rounded), - _buildTile('银行账户', subtitle: 'BoA •••• 6789', icon: Icons.account_balance_rounded), - _buildTile('支付密码', icon: Icons.password_rounded), + _buildSection(context.t('settings.paymentManage'), [ + _buildTile(context.t('settings.paymentMethod'), subtitle: 'Visa •••• 4242', icon: Icons.credit_card_rounded), + _buildTile(context.t('settings.bankAccount'), subtitle: 'BoA •••• 6789', icon: Icons.account_balance_rounded), + _buildTile(context.t('settings.paymentPassword'), icon: Icons.password_rounded), ]), // Notifications - _buildSection('通知设置', [ - _buildSwitchTile('交易通知', true), - _buildSwitchTile('到期提醒', true), - _buildSwitchTile('行情变动', false), - _buildSwitchTile('营销推送', false), + _buildSection(context.t('settings.notifications'), [ + _buildSwitchTile(context.t('settings.tradeNotify'), true), + _buildSwitchTile(context.t('settings.expiryRemind'), true), + _buildSwitchTile(context.t('settings.marketChange'), false), + _buildSwitchTile(context.t('settings.marketingPush'), false), ]), // General - _buildSection('通用', [ - _buildTile('语言', subtitle: '简体中文', icon: Icons.language_rounded), - _buildTile('货币', subtitle: 'USD', icon: Icons.attach_money_rounded), - _buildTile('清除缓存', icon: Icons.cleaning_services_rounded), + _buildSection(context.t('settings.general'), [ + _buildTile(context.t('settings.language'), subtitle: context.t('profile.simplifiedChinese'), icon: Icons.language_rounded), + _buildTile(context.t('settings.currency'), subtitle: 'USD', icon: Icons.attach_money_rounded), + _buildTile(context.t('settings.clearCache'), icon: Icons.cleaning_services_rounded), ]), // About - _buildSection('关于', [ - _buildTile('版本', subtitle: 'v1.0.0', icon: Icons.info_outline_rounded), - _buildTile('用户协议', icon: Icons.description_rounded), - _buildTile('隐私政策', icon: Icons.privacy_tip_rounded), - _buildTile('帮助中心', icon: Icons.help_outline_rounded), + _buildSection(context.t('settings.about'), [ + _buildTile(context.t('settings.version'), subtitle: 'v1.0.0', icon: Icons.info_outline_rounded), + _buildTile(context.t('settings.userAgreement'), icon: Icons.description_rounded), + _buildTile(context.t('settings.privacyPolicy'), icon: Icons.privacy_tip_rounded), + _buildTile(context.t('settings.helpCenter'), icon: Icons.help_outline_rounded), ]), // Logout @@ -66,7 +67,7 @@ class SettingsPage extends StatelessWidget { side: const BorderSide(color: AppColors.error), minimumSize: const Size(double.infinity, 48), ), - child: const Text('退出登录'), + child: Text(context.t('settings.logout')), ), ), ], diff --git a/frontend/mobile/lib/features/trading/presentation/pages/sell_order_page.dart b/frontend/mobile/lib/features/trading/presentation/pages/sell_order_page.dart index e43f91c..bf6887e 100644 --- a/frontend/mobile/lib/features/trading/presentation/pages/sell_order_page.dart +++ b/frontend/mobile/lib/features/trading/presentation/pages/sell_order_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -20,13 +21,13 @@ class _SellOrderPageState extends State { double get _price => double.tryParse(_priceController.text) ?? 0; double get _discount => _faceValue > 0 ? _price / _faceValue * 100 : 0; - double get _fee => _price * 0.015; // 1.5% 手续费 + double get _fee => _price * 0.015; // 1.5% double get _receive => _price - _fee; @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('挂单出售')), + appBar: AppBar(title: Text(context.t('sellOrder.title'))), body: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( @@ -58,7 +59,7 @@ class _SellOrderPageState extends State { children: [ Text('星巴克 \$25 礼品卡', style: AppTypography.labelLarge), const SizedBox(height: 4), - Text('面值 \$$_faceValue · 信用 AAA', style: AppTypography.bodySmall), + Text('${context.t('sellOrder.faceValue')} \$$_faceValue · ${context.t('sellOrder.credit')} AAA', style: AppTypography.bodySmall), ], ), ), @@ -68,14 +69,14 @@ class _SellOrderPageState extends State { const SizedBox(height: 24), // Price Input - Text('设定售价', style: AppTypography.h3), + Text(context.t('sellOrder.setPrice'), style: AppTypography.h3), const SizedBox(height: 12), TextField( controller: _priceController, keyboardType: const TextInputType.numberWithOptions(decimal: true), - decoration: const InputDecoration( + decoration: InputDecoration( prefixText: '\$ ', - labelText: '售价', + labelText: context.t('sellOrder.price'), suffixText: 'USD', ), style: AppTypography.priceLarge, @@ -96,7 +97,7 @@ class _SellOrderPageState extends State { const SizedBox(width: 8), Expanded( child: Text( - 'AI建议售价:\$22.50(9折),此价格成交概率最高', + '${context.t('sellOrder.aiSuggest')}: \$22.50 (90%), ${context.t('sellOrder.bestDealRate')}', style: AppTypography.caption.copyWith(color: AppColors.primary), ), ), @@ -115,11 +116,11 @@ class _SellOrderPageState extends State { ), child: Column( children: [ - _buildRow('售价', '\$${_price.toStringAsFixed(2)}'), - _buildRow('折扣率', '${_discount.toStringAsFixed(1)}%'), - _buildRow('平台手续费 (1.5%)', '-\$${_fee.toStringAsFixed(2)}'), + _buildRow(context.t('sellOrder.price'), '\$${_price.toStringAsFixed(2)}'), + _buildRow(context.t('sellOrder.discountRate'), '${_discount.toStringAsFixed(1)}%'), + _buildRow(context.t('sellOrder.platformFee'), '-\$${_fee.toStringAsFixed(2)}'), const Divider(height: 24), - _buildRow('预计到账', '\$${_receive.toStringAsFixed(2)}', isBold: true), + _buildRow(context.t('sellOrder.estimatedReceive'), '\$${_receive.toStringAsFixed(2)}', isBold: true), ], ), ), @@ -138,7 +139,7 @@ class _SellOrderPageState extends State { const SizedBox(width: 8), Expanded( child: Text( - '当前市场均价 \$22.80 · 最近24小时成交 42 笔', + '${context.t('sellOrder.marketAvg')} \$22.80 · ${context.t('sellOrder.recent24hTrades')} 42 ${context.t('sellOrder.tradesUnit')}', style: AppTypography.caption.copyWith(color: AppColors.info), ), ), @@ -154,7 +155,7 @@ class _SellOrderPageState extends State { height: AppSpacing.buttonHeight, child: ElevatedButton( onPressed: () => _confirmSell(context), - child: const Text('确认挂单'), + child: Text(context.t('sellOrder.confirmList')), ), ), ), @@ -178,10 +179,10 @@ class _SellOrderPageState extends State { showDialog( context: context, builder: (ctx) => AlertDialog( - title: const Text('挂单成功'), - content: const Text('您的券已挂到市场,当有买家下单时将自动成交。'), + title: Text(context.t('sellOrder.success')), + content: Text(context.t('sellOrder.successHint')), actions: [ - TextButton(onPressed: () { Navigator.pop(ctx); Navigator.pop(context); }, child: const Text('确定')), + TextButton(onPressed: () { Navigator.pop(ctx); Navigator.pop(context); }, child: Text(context.t('sellOrder.ok'))), ], ), ); diff --git a/frontend/mobile/lib/features/trading/presentation/pages/trading_page.dart b/frontend/mobile/lib/features/trading/presentation/pages/trading_page.dart index 0d3605e..cfd9409 100644 --- a/frontend/mobile/lib/features/trading/presentation/pages/trading_page.dart +++ b/frontend/mobile/lib/features/trading/presentation/pages/trading_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -35,12 +36,12 @@ class _TradingPageState extends State Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('我的交易'), + title: Text(context.t('tradingPage.title')), bottom: TabBar( controller: _tabController, - tabs: const [ - Tab(text: '我的挂单'), - Tab(text: '交易记录'), + tabs: [ + Tab(text: context.t('tradingPage.pendingOrders')), + Tab(text: context.t('tradingPage.tradeRecords')), ], ), ), @@ -61,9 +62,9 @@ class _TradingPageState extends State separatorBuilder: (_, __) => const SizedBox(height: 12), itemBuilder: (context, index) { final statuses = [ - StatusTags.onSale(), - StatusTags.completed(), - StatusTags.cancelled(), + StatusTags.onSale(context: context), + StatusTags.completed(context: context), + StatusTags.cancelled(context: context), ]; return Container( padding: AppSpacing.cardPadding, @@ -96,7 +97,7 @@ class _TradingPageState extends State const SizedBox(height: 4), Row( children: [ - Text('挂单价 ', style: AppTypography.caption), + Text('${context.t('tradingPage.listPrice')} ', style: AppTypography.caption), Text('\$${[21.25, 42.50, 68.00][index]}', style: AppTypography.priceSmall.copyWith(fontSize: 14)), ], @@ -117,12 +118,12 @@ class _TradingPageState extends State child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('挂单时间: 2026/02/${9 - index}', + Text('${context.t('tradingPage.listTime')}: 2026/02/${9 - index}', style: AppTypography.caption), if (index == 0) GestureDetector( onTap: () {}, - child: Text('撤单', style: AppTypography.labelSmall.copyWith( + child: Text(context.t('tradingPage.cancelOrder'), style: AppTypography.labelSmall.copyWith( color: AppColors.error, )), ), @@ -171,11 +172,11 @@ class _TradingPageState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - isBuy ? '买入' : '卖出', + isBuy ? context.t('tradingPage.buy') : context.t('tradingPage.sell'), style: AppTypography.labelMedium, ), Text( - '品牌 ${index + 1} 礼品卡', + 'Brand ${index + 1} Gift Card', style: AppTypography.caption, ), ], diff --git a/frontend/mobile/lib/features/trading/presentation/pages/transfer_page.dart b/frontend/mobile/lib/features/trading/presentation/pages/transfer_page.dart index be60098..9e551ac 100644 --- a/frontend/mobile/lib/features/trading/presentation/pages/transfer_page.dart +++ b/frontend/mobile/lib/features/trading/presentation/pages/transfer_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -21,7 +22,7 @@ class _TransferPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('转赠给好友')), + appBar: AppBar(title: Text(context.t('transfer.title'))), body: Column( children: [ // Coupon Info @@ -50,7 +51,7 @@ class _TransferPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('星巴克 \$25 礼品卡', style: AppTypography.labelMedium), - Text('面值 \$25.00', style: AppTypography.bodySmall), + Text('${context.t('couponDetail.faceValue')} \$25.00', style: AppTypography.bodySmall), ], ), ), @@ -63,9 +64,9 @@ class _TransferPageState extends State { padding: const EdgeInsets.symmetric(horizontal: 20), child: TextField( controller: _searchController, - decoration: const InputDecoration( - hintText: '搜索好友(手机号/用户名)', - prefixIcon: Icon(Icons.search_rounded), + decoration: InputDecoration( + hintText: context.t('transfer.searchFriend'), + prefixIcon: const Icon(Icons.search_rounded), ), ), ), @@ -92,7 +93,7 @@ class _TransferPageState extends State { height: AppSpacing.buttonHeight, child: ElevatedButton( onPressed: _selectedFriend != null ? () => _showConfirm(context) : null, - child: Text(_selectedFriend != null ? '转赠给 $_selectedFriend' : '请选择好友'), + child: Text(_selectedFriend != null ? '${context.t('transfer.confirmTransfer')} $_selectedFriend' : context.t('transfer.searchFriend')), ), ), ), @@ -150,18 +151,16 @@ class _TransferPageState extends State { children: [ const Icon(Icons.card_giftcard_rounded, color: AppColors.primary, size: 48), const SizedBox(height: 16), - Text('确认转赠', style: AppTypography.h2), + Text(context.t('transfer.confirmTransfer'), style: AppTypography.h2), const SizedBox(height: 8), - Text('将 星巴克 \$25 礼品卡 转赠给 $_selectedFriend?', style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)), - const SizedBox(height: 8), - Text('转赠后您将不再持有此券', style: AppTypography.caption.copyWith(color: AppColors.warning)), + Text('星巴克 \$25 礼品卡 -> $_selectedFriend', style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)), const SizedBox(height: 24), Row( children: [ Expanded( child: OutlinedButton( onPressed: () => Navigator.pop(ctx), - child: const Text('取消'), + child: Text(context.t('transfer.cancel')), ), ), const SizedBox(width: 12), @@ -171,7 +170,7 @@ class _TransferPageState extends State { Navigator.pop(ctx); _showSuccess(context); }, - child: const Text('确认转赠'), + child: Text(context.t('transfer.confirmTransfer')), ), ), ], @@ -191,9 +190,9 @@ class _TransferPageState extends State { children: [ const Icon(Icons.check_circle_rounded, color: AppColors.success, size: 56), const SizedBox(height: 16), - Text('转赠成功', style: AppTypography.h2), + Text(context.t('transfer.success'), style: AppTypography.h2), const SizedBox(height: 8), - Text('$_selectedFriend 已收到您的券', style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)), + Text('$_selectedFriend', style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)), ], ), actions: [ @@ -202,7 +201,7 @@ class _TransferPageState extends State { Navigator.pop(ctx); Navigator.pop(context); }, - child: const Text('确定'), + child: Text(context.t('transfer.confirm')), ), ], ), diff --git a/frontend/mobile/lib/features/wallet/presentation/pages/deposit_page.dart b/frontend/mobile/lib/features/wallet/presentation/pages/deposit_page.dart index adc19ed..d5fffd2 100644 --- a/frontend/mobile/lib/features/wallet/presentation/pages/deposit_page.dart +++ b/frontend/mobile/lib/features/wallet/presentation/pages/deposit_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -22,7 +23,7 @@ class _DepositPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('充值')), + appBar: AppBar(title: Text(context.t('deposit.title'))), body: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( @@ -38,7 +39,7 @@ class _DepositPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('当前余额', style: AppTypography.bodySmall.copyWith(color: Colors.white70)), + Text(context.t('deposit.currentBalance'), style: AppTypography.bodySmall.copyWith(color: Colors.white70)), const SizedBox(height: 4), Text('\$128.50', style: AppTypography.displayLarge.copyWith(color: Colors.white)), ], @@ -46,7 +47,7 @@ class _DepositPageState extends State { ), const SizedBox(height: 24), - Text('充值金额', style: AppTypography.h3), + Text(context.t('deposit.amount'), style: AppTypography.h3), const SizedBox(height: 12), // Preset Amounts @@ -90,8 +91,8 @@ class _DepositPageState extends State { TextField( controller: _amountController, keyboardType: const TextInputType.numberWithOptions(decimal: true), - decoration: const InputDecoration( - labelText: '自定义金额', + decoration: InputDecoration( + labelText: context.t('deposit.custom'), prefixText: '\$ ', ), onChanged: (_) => setState(() => _selectedPreset = null), @@ -99,7 +100,7 @@ class _DepositPageState extends State { const SizedBox(height: 24), // Payment Method - Text('支付方式', style: AppTypography.h3), + Text(context.t('deposit.paymentMethod'), style: AppTypography.h3), const SizedBox(height: 12), _buildPaymentOption('Visa •••• 4242', Icons.credit_card_rounded, true), _buildPaymentOption('Apple Pay', Icons.apple_rounded, false), @@ -112,7 +113,7 @@ class _DepositPageState extends State { height: AppSpacing.buttonHeight, child: ElevatedButton( onPressed: _amountController.text.isNotEmpty ? () {} : null, - child: Text('充值 \$${_amountController.text.isNotEmpty ? _amountController.text : '0'}'), + child: Text('${context.t('deposit.submit')} \$${_amountController.text.isNotEmpty ? _amountController.text : '0'}'), ), ), ), diff --git a/frontend/mobile/lib/features/wallet/presentation/pages/transaction_records_page.dart b/frontend/mobile/lib/features/wallet/presentation/pages/transaction_records_page.dart index 6df4cfc..596f419 100644 --- a/frontend/mobile/lib/features/wallet/presentation/pages/transaction_records_page.dart +++ b/frontend/mobile/lib/features/wallet/presentation/pages/transaction_records_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -16,30 +17,30 @@ class TransactionRecordsPage extends StatelessWidget { length: 4, child: Scaffold( appBar: AppBar( - title: const Text('交易记录'), - bottom: const TabBar( + title: Text(context.t('txRecords.title')), + bottom: TabBar( isScrollable: true, tabs: [ - Tab(text: '全部'), - Tab(text: '购买'), - Tab(text: '出售'), - Tab(text: '转赠'), + Tab(text: context.t('txRecords.all')), + Tab(text: context.t('txRecords.buy')), + Tab(text: context.t('txRecords.sell')), + Tab(text: context.t('txRecords.transfer')), ], ), ), body: TabBarView( children: [ - _buildList(_allRecords), - _buildList(_allRecords.where((r) => r.type == '购买').toList()), - _buildList(_allRecords.where((r) => r.type == '出售').toList()), - _buildList(_allRecords.where((r) => r.type == '转赠').toList()), + _buildList(context, _allRecords), + _buildList(context, _allRecords.where((r) => r.type == 'buy').toList()), + _buildList(context, _allRecords.where((r) => r.type == 'sell').toList()), + _buildList(context, _allRecords.where((r) => r.type == 'transfer').toList()), ], ), ), ); } - Widget _buildList(List<_TxRecord> records) { + Widget _buildList(BuildContext context, List<_TxRecord> records) { if (records.isEmpty) { return Center( child: Column( @@ -47,7 +48,7 @@ class TransactionRecordsPage extends StatelessWidget { children: [ const Icon(Icons.receipt_long_rounded, size: 48, color: AppColors.textTertiary), const SizedBox(height: 12), - Text('暂无记录', style: AppTypography.bodyMedium.copyWith(color: AppColors.textTertiary)), + Text(context.t('txRecords.noRecords'), style: AppTypography.bodyMedium.copyWith(color: AppColors.textTertiary)), ], ), ); @@ -124,9 +125,9 @@ class _TxRecord { } const _allRecords = [ - _TxRecord(type: '购买', title: '购买 星巴克 \$25 礼品卡', subtitle: '订单号 GNX20260210001', amount: '-\$21.25', time: '今天 14:32', icon: Icons.shopping_cart_rounded, color: AppColors.primary), - _TxRecord(type: '出售', title: '出售 Amazon \$100 购物券', subtitle: '订单号 GNX20260210002', amount: '+\$92.00', time: '今天 12:15', icon: Icons.sell_rounded, color: AppColors.success), - _TxRecord(type: '转赠', title: '转赠给 Alice', subtitle: 'Nike \$80 运动券', amount: '\$0', time: '昨天 18:45', icon: Icons.card_giftcard_rounded, color: AppColors.info), - _TxRecord(type: '购买', title: '购买 Target \$30 折扣券', subtitle: '订单号 GNX20260209001', amount: '-\$24.00', time: '昨天 10:20', icon: Icons.shopping_cart_rounded, color: AppColors.primary), - _TxRecord(type: '出售', title: '出售 Walmart \$50 生活券', subtitle: '订单号 GNX20260208003', amount: '+\$46.50', time: '2天前', icon: Icons.sell_rounded, color: AppColors.success), + _TxRecord(type: 'buy', title: 'Starbucks \$25 Gift Card', subtitle: 'GNX20260210001', amount: '-\$21.25', time: '14:32', icon: Icons.shopping_cart_rounded, color: AppColors.primary), + _TxRecord(type: 'sell', title: 'Amazon \$100 Voucher', subtitle: 'GNX20260210002', amount: '+\$92.00', time: '12:15', icon: Icons.sell_rounded, color: AppColors.success), + _TxRecord(type: 'transfer', title: 'Nike \$80 Voucher -> Alice', subtitle: 'GNX20260209003', amount: '\$0', time: '18:45', icon: Icons.card_giftcard_rounded, color: AppColors.info), + _TxRecord(type: 'buy', title: 'Target \$30 Voucher', subtitle: 'GNX20260209001', amount: '-\$24.00', time: '10:20', icon: Icons.shopping_cart_rounded, color: AppColors.primary), + _TxRecord(type: 'sell', title: 'Walmart \$50 Voucher', subtitle: 'GNX20260208003', amount: '+\$46.50', time: '02/08', icon: Icons.sell_rounded, color: AppColors.success), ]; diff --git a/frontend/mobile/lib/features/wallet/presentation/pages/wallet_page.dart b/frontend/mobile/lib/features/wallet/presentation/pages/wallet_page.dart index 00559ef..8c3c73b 100644 --- a/frontend/mobile/lib/features/wallet/presentation/pages/wallet_page.dart +++ b/frontend/mobile/lib/features/wallet/presentation/pages/wallet_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -15,13 +16,13 @@ class WalletPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('我的余额'), + title: Text(context.t('wallet.myBalance')), ), body: SingleChildScrollView( child: Column( children: [ // Balance Card - _buildBalanceCard(), + _buildBalanceCard(context), // Quick Actions Padding( @@ -30,7 +31,7 @@ class WalletPage extends StatelessWidget { children: [ Expanded( child: GenexButton( - label: '充值', + label: context.t('wallet.deposit'), icon: Icons.add_rounded, variant: GenexButtonVariant.primary, onPressed: () { @@ -41,7 +42,7 @@ class WalletPage extends StatelessWidget { const SizedBox(width: 12), Expanded( child: GenexButton( - label: '提现', + label: context.t('wallet.withdraw'), icon: Icons.account_balance_rounded, variant: GenexButtonVariant.outline, onPressed: () { @@ -60,14 +61,14 @@ class WalletPage extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('交易记录', style: AppTypography.h3), + Text(context.t('wallet.records'), style: AppTypography.h3), GestureDetector( onTap: () { Navigator.pushNamed(context, '/wallet/records'); }, child: Row( children: [ - Text('筛选', style: AppTypography.labelSmall.copyWith( + Text(context.t('wallet.filter'), style: AppTypography.labelSmall.copyWith( color: AppColors.textTertiary, )), const Icon(Icons.filter_list_rounded, size: 16, @@ -81,7 +82,7 @@ class WalletPage extends StatelessWidget { const SizedBox(height: 12), // Transaction List - _buildTransactionList(), + _buildTransactionList(context), const SizedBox(height: 80), ], @@ -90,7 +91,7 @@ class WalletPage extends StatelessWidget { ); } - Widget _buildBalanceCard() { + Widget _buildBalanceCard(BuildContext context) { return Container( margin: const EdgeInsets.fromLTRB(20, 16, 20, 16), padding: const EdgeInsets.all(24), @@ -102,7 +103,7 @@ class WalletPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('总余额', style: AppTypography.bodySmall.copyWith( + Text(context.t('wallet.totalBalance'), style: AppTypography.bodySmall.copyWith( color: Colors.white70, )), const SizedBox(height: 8), @@ -116,9 +117,9 @@ class WalletPage extends StatelessWidget { const SizedBox(height: 20), Row( children: [ - _balanceItem('可提现', '\$1,034.56'), + _balanceItem(context.t('wallet.withdrawable'), '\$1,034.56'), const SizedBox(width: 32), - _balanceItem('冻结中', '\$200.00'), + _balanceItem(context.t('wallet.frozen'), '\$200.00'), ], ), ], @@ -137,14 +138,14 @@ class WalletPage extends StatelessWidget { ); } - Widget _buildTransactionList() { + Widget _buildTransactionList(BuildContext context) { final transactions = [ - ('买入 星巴克 \$25 礼品卡', '-\$21.25', Icons.shopping_cart_rounded, AppColors.textPrimary, '今天 14:32'), - ('卖出 Amazon \$50 购物券', '+\$42.50', Icons.sell_rounded, AppColors.success, '今天 10:15'), - ('充值', '+\$500.00', Icons.add_circle_outline_rounded, AppColors.info, '昨天 09:20'), - ('转赠 Target 券', '-\$30.00', Icons.card_giftcard_rounded, AppColors.textPrimary, '02/07 16:45'), - ('核销 Nike 运动券', '使用', Icons.check_circle_outline_rounded, AppColors.success, '02/06 12:00'), - ('提现', '-\$200.00', Icons.account_balance_rounded, AppColors.textPrimary, '02/05 08:30'), + ('${context.t('wallet.buyIn')} 星巴克 \$25 礼品卡', '-\$21.25', Icons.shopping_cart_rounded, AppColors.textPrimary, '14:32'), + ('${context.t('wallet.sellOut')} Amazon \$50 购物券', '+\$42.50', Icons.sell_rounded, AppColors.success, '10:15'), + (context.t('wallet.deposit'), '+\$500.00', Icons.add_circle_outline_rounded, AppColors.info, '09:20'), + ('${context.t('wallet.giftTransfer')} Target 券', '-\$30.00', Icons.card_giftcard_rounded, AppColors.textPrimary, '16:45'), + ('${context.t('wallet.redeemUse')} Nike 运动券', '-', Icons.check_circle_outline_rounded, AppColors.success, '12:00'), + (context.t('wallet.withdraw'), '-\$200.00', Icons.account_balance_rounded, AppColors.textPrimary, '08:30'), ]; return ListView.separated( diff --git a/frontend/mobile/lib/features/wallet/presentation/pages/withdraw_page.dart b/frontend/mobile/lib/features/wallet/presentation/pages/withdraw_page.dart index 37b9885..a9261b5 100644 --- a/frontend/mobile/lib/features/wallet/presentation/pages/withdraw_page.dart +++ b/frontend/mobile/lib/features/wallet/presentation/pages/withdraw_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; @@ -25,20 +26,20 @@ class _WithdrawPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('提现')), + appBar: AppBar(title: Text(context.t('withdraw.title'))), body: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Balance - Text('可提现余额', style: AppTypography.bodySmall), + Text(context.t('withdraw.availableBalance'), style: AppTypography.bodySmall), const SizedBox(height: 4), Text('\$${_balance.toStringAsFixed(2)}', style: AppTypography.displayMedium), const SizedBox(height: 24), // Amount Input - Text('提现金额', style: AppTypography.h3), + Text(context.t('withdraw.amount'), style: AppTypography.h3), const SizedBox(height: 12), TextField( controller: _amountController, @@ -50,7 +51,7 @@ class _WithdrawPageState extends State { _amountController.text = _balance.toStringAsFixed(2); setState(() {}); }, - child: const Text('全部'), + child: Text(context.t('withdraw.all')), ), ), style: AppTypography.priceLarge, @@ -59,7 +60,7 @@ class _WithdrawPageState extends State { const SizedBox(height: 24), // Withdraw To - Text('提现到', style: AppTypography.h3), + Text(context.t('withdraw.to'), style: AppTypography.h3), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(14), @@ -77,7 +78,7 @@ class _WithdrawPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Bank of America •••• 6789', style: AppTypography.labelMedium), - Text('储蓄账户', style: AppTypography.caption), + Text(context.t('withdraw.savingsAccount'), style: AppTypography.caption), ], ), ), @@ -97,16 +98,16 @@ class _WithdrawPageState extends State { ), child: Column( children: [ - _buildRow('提现金额', '\$${_amount.toStringAsFixed(2)}'), - _buildRow('手续费 (0.5%)', '-\$${_fee.toStringAsFixed(2)}'), + _buildRow(context.t('withdraw.amount'), '\$${_amount.toStringAsFixed(2)}'), + _buildRow(context.t('withdraw.fee'), '-\$${_fee.toStringAsFixed(2)}'), const Divider(height: 16), - _buildRow('实际到账', '\$${_receive.toStringAsFixed(2)}', bold: true), + _buildRow(context.t('withdraw.actualReceive'), '\$${_receive.toStringAsFixed(2)}', bold: true), const SizedBox(height: 8), Row( children: [ const Icon(Icons.schedule_rounded, size: 14, color: AppColors.textTertiary), const SizedBox(width: 4), - Text('预计 1-2 个工作日到账', style: AppTypography.caption), + Text(context.t('withdraw.estimateTime'), style: AppTypography.caption), ], ), ], @@ -122,7 +123,7 @@ class _WithdrawPageState extends State { height: AppSpacing.buttonHeight, child: ElevatedButton( onPressed: _amount > 0 && _amount <= _balance ? () {} : null, - child: Text('确认提现 \$${_amount.toStringAsFixed(2)}'), + child: Text('${context.t('withdraw.submit')} \$${_amount.toStringAsFixed(2)}'), ), ), ), diff --git a/frontend/mobile/lib/main.dart b/frontend/mobile/lib/main.dart index 4dd3481..e119ec2 100644 --- a/frontend/mobile/lib/main.dart +++ b/frontend/mobile/lib/main.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'app/i18n/app_localizations.dart'; import 'app/theme/app_theme.dart'; import 'app/main_shell.dart'; import 'features/auth/presentation/pages/login_page.dart'; @@ -45,6 +47,32 @@ class GenexConsumerApp extends StatelessWidget { title: 'Genex', theme: AppTheme.light, debugShowCheckedModeBanner: false, + supportedLocales: const [ + Locale('zh', 'CN'), + Locale('zh', 'TW'), + Locale('en'), + Locale('ja'), + ], + localizationsDelegates: const [ + AppLocalizationsDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + localeResolutionCallback: (locale, supportedLocales) { + for (final supported in supportedLocales) { + if (supported.languageCode == locale?.languageCode && + supported.countryCode == locale?.countryCode) { + return supported; + } + } + for (final supported in supportedLocales) { + if (supported.languageCode == locale?.languageCode) { + return supported; + } + } + return const Locale('zh', 'CN'); + }, initialRoute: '/', onGenerateRoute: _generateRoute, ); diff --git a/frontend/mobile/lib/shared/widgets/ai_confirm_dialog.dart b/frontend/mobile/lib/shared/widgets/ai_confirm_dialog.dart index 8a6eb06..2686bff 100644 --- a/frontend/mobile/lib/shared/widgets/ai_confirm_dialog.dart +++ b/frontend/mobile/lib/shared/widgets/ai_confirm_dialog.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../app/i18n/app_localizations.dart'; import '../../app/theme/app_colors.dart'; import '../../app/theme/app_typography.dart'; import '../../app/theme/app_spacing.dart'; @@ -19,7 +20,7 @@ class AiConfirmDialog extends StatelessWidget { final String actionDescription; final List details; final String? riskWarning; - final String confirmText; + final String? confirmText; final String? cancelText; final VoidCallback onConfirm; final VoidCallback? onCancel; @@ -31,8 +32,8 @@ class AiConfirmDialog extends StatelessWidget { required this.actionDescription, required this.details, this.riskWarning, - this.confirmText = '确认执行', - this.cancelText = '取消', + this.confirmText, + this.cancelText, required this.onConfirm, this.onCancel, this.level = AiConfirmLevel.normal, @@ -40,6 +41,9 @@ class AiConfirmDialog extends StatelessWidget { @override Widget build(BuildContext context) { + final resolvedConfirmText = confirmText ?? context.t('aiChat.confirmAction'); + final resolvedCancelText = cancelText ?? context.t('common.cancel'); + return Dialog( backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.symmetric(horizontal: 24), @@ -59,7 +63,7 @@ class AiConfirmDialog extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ // Header with AI icon - _buildHeader(), + _buildHeader(context), // Body Padding( @@ -162,7 +166,7 @@ class AiConfirmDialog extends StatelessWidget { // Buttons GenexButton( - label: confirmText, + label: resolvedConfirmText, onPressed: () { Navigator.of(context).pop(true); onConfirm(); @@ -170,7 +174,7 @@ class AiConfirmDialog extends StatelessWidget { ), const SizedBox(height: 8), GenexButton( - label: cancelText ?? '取消', + label: resolvedCancelText, variant: GenexButtonVariant.text, onPressed: () { Navigator.of(context).pop(false); @@ -186,7 +190,7 @@ class AiConfirmDialog extends StatelessWidget { ); } - Widget _buildHeader() { + Widget _buildHeader(BuildContext context) { return Container( padding: const EdgeInsets.fromLTRB(20, 20, 20, 16), child: Row( @@ -200,10 +204,7 @@ class AiConfirmDialog extends StatelessWidget { borderRadius: AppSpacing.borderRadiusSm, ), child: const Center( - child: Text( - '✨', - style: TextStyle(fontSize: 20), - ), + child: Icon(Icons.auto_awesome_rounded, color: Colors.white, size: 20), ), ), const SizedBox(width: 12), @@ -211,7 +212,7 @@ class AiConfirmDialog extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('AI助手请求确认', style: AppTypography.labelMedium), + Text(context.t('aiFab.title'), style: AppTypography.labelMedium), const SizedBox(height: 2), Text( actionTitle, @@ -228,7 +229,7 @@ class AiConfirmDialog extends StatelessWidget { borderRadius: AppSpacing.borderRadiusFull, ), child: Text( - _levelText, + _getLevelText(context), style: TextStyle( fontSize: 10, fontWeight: FontWeight.w600, @@ -252,14 +253,14 @@ class AiConfirmDialog extends StatelessWidget { } } - String get _levelText { + String _getLevelText(BuildContext context) { switch (level) { case AiConfirmLevel.low: - return '低风险'; + return context.t('aiChat.riskLow'); case AiConfirmLevel.normal: - return '需确认'; + return context.t('aiChat.riskNormal'); case AiConfirmLevel.high: - return '高风险'; + return context.t('aiChat.riskHigh'); } } @@ -270,7 +271,7 @@ class AiConfirmDialog extends StatelessWidget { required String actionDescription, required List details, String? riskWarning, - String confirmText = '确认执行', + String? confirmText, String? cancelText, AiConfirmLevel level = AiConfirmLevel.normal, }) { diff --git a/frontend/mobile/lib/shared/widgets/coupon_card.dart b/frontend/mobile/lib/shared/widgets/coupon_card.dart index ebe5447..9c20a1a 100644 --- a/frontend/mobile/lib/shared/widgets/coupon_card.dart +++ b/frontend/mobile/lib/shared/widgets/coupon_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../app/i18n/app_localizations.dart'; import '../../app/theme/app_colors.dart'; import '../../app/theme/app_typography.dart'; import '../../app/theme/app_spacing.dart'; @@ -36,14 +37,14 @@ class CouponCard extends StatelessWidget { }); double get discountRate => currentPrice / faceValue; - String get discountText => '${(discountRate * 10).toStringAsFixed(1)}折'; + String _getDiscountText(BuildContext context) => '${(discountRate * 10).toStringAsFixed(1)}${context.t('market.discountSuffix')}'; @override Widget build(BuildContext context) { - return style == CouponCardStyle.grid ? _buildGridCard() : _buildListCard(); + return style == CouponCardStyle.grid ? _buildGridCard(context) : _buildListCard(context); } - Widget _buildListCard() { + Widget _buildListCard(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( @@ -59,7 +60,7 @@ class CouponCard extends StatelessWidget { // Left: Coupon Image with Ticket Notch _buildCouponImage(width: 110, height: AppSpacing.couponCardHeight), - // Ticket Divider (锯齿分割线) + // Ticket Divider _buildTicketDivider(), // Right: Info @@ -106,7 +107,7 @@ class CouponCard extends StatelessWidget { style: AppTypography.priceOriginal, ), const Spacer(), - _buildDiscountBadge(), + _buildDiscountBadge(context), ], ), @@ -117,7 +118,7 @@ class CouponCard extends StatelessWidget { Icon(Icons.access_time_rounded, size: 12, color: _expiryColor), const SizedBox(width: 3), Text( - _expiryText, + _getExpiryText(context), style: AppTypography.caption.copyWith(color: _expiryColor), ), ], @@ -135,7 +136,7 @@ class CouponCard extends StatelessWidget { ); } - Widget _buildGridCard() { + Widget _buildGridCard(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( @@ -171,7 +172,7 @@ class CouponCard extends StatelessWidget { style: AppTypography.priceSmall.copyWith(fontSize: 15), ), const SizedBox(width: 4), - _buildDiscountBadge(), + _buildDiscountBadge(context), ], ), const SizedBox(height: 4), @@ -248,14 +249,14 @@ class CouponCard extends StatelessWidget { ); } - Widget _buildDiscountBadge() { + Widget _buildDiscountBadge(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( gradient: AppColors.primaryGradient, borderRadius: AppSpacing.borderRadiusFull, ), - child: Text(discountText, style: AppTypography.discountBadge), + child: Text(_getDiscountText(context), style: AppTypography.discountBadge), ); } @@ -294,14 +295,14 @@ class CouponCard extends StatelessWidget { } } - String get _expiryText { + String _getExpiryText(BuildContext context) { if (expiryDate == null) return ''; final days = expiryDate!.difference(DateTime.now()).inDays; - if (days < 0) return '已过期'; - if (days == 0) return '今天到期'; - if (days <= 3) return '$days天后到期'; - if (days <= 30) return '$days天'; - return '${expiryDate!.month}/${expiryDate!.day}到期'; + if (days < 0) return context.t('couponCard.expiredText'); + if (days == 0) return context.t('couponCard.expiringToday'); + if (days <= 3) return '$days${context.t('couponCard.daysToExpiry')}'; + if (days <= 30) return '$days${context.t('couponCard.daysToExpiry')}'; + return '${expiryDate!.month}/${expiryDate!.day}${context.t('couponCard.expiryFormat')}'; } Color get _expiryColor { diff --git a/frontend/mobile/lib/shared/widgets/empty_state.dart b/frontend/mobile/lib/shared/widgets/empty_state.dart index c4c4425..5d98cab 100644 --- a/frontend/mobile/lib/shared/widgets/empty_state.dart +++ b/frontend/mobile/lib/shared/widgets/empty_state.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../app/i18n/app_localizations.dart'; import '../../app/theme/app_colors.dart'; import '../../app/theme/app_typography.dart'; import '../../app/theme/app_spacing.dart'; @@ -68,37 +69,37 @@ class EmptyState extends StatelessWidget { } // 快捷工厂方法 - factory EmptyState.noCoupons({VoidCallback? onBrowse}) => EmptyState( + factory EmptyState.noCoupons({required BuildContext context, VoidCallback? onBrowse}) => EmptyState( icon: Icons.confirmation_number_outlined, - title: '还没有券', - subtitle: '去市场看看有什么好券吧', - actionText: '去逛逛', + title: context.t('empty.noCoupons'), + subtitle: context.t('empty.noCouponsHint'), + actionText: context.t('empty.browse'), onAction: onBrowse, ); - factory EmptyState.noOrders() => const EmptyState( + factory EmptyState.noOrders({required BuildContext context}) => EmptyState( icon: Icons.receipt_long_outlined, - title: '暂无交易记录', - subtitle: '完成首笔交易后这里会显示记录', + title: context.t('empty.noTrades'), + subtitle: context.t('empty.noTradesHint'), ); - factory EmptyState.noResults() => const EmptyState( + factory EmptyState.noResults({required BuildContext context}) => EmptyState( icon: Icons.search_off_rounded, - title: '没有找到结果', - subtitle: '换个关键词试试', + title: context.t('empty.noResults'), + subtitle: context.t('empty.noResultsHint'), ); - factory EmptyState.noMessages() => const EmptyState( + factory EmptyState.noMessages({required BuildContext context}) => EmptyState( icon: Icons.notifications_none_rounded, - title: '暂无消息', - subtitle: '交易通知和系统公告会显示在这里', + title: context.t('empty.noMessages'), + subtitle: context.t('empty.noMessagesHint'), ); - factory EmptyState.networkError({VoidCallback? onRetry}) => EmptyState( + factory EmptyState.networkError({required BuildContext context, VoidCallback? onRetry}) => EmptyState( icon: Icons.wifi_off_rounded, - title: '网络连接失败', - subtitle: '请检查网络设置后重试', - actionText: '重试', + title: context.t('empty.networkError'), + subtitle: context.t('empty.networkErrorHint'), + actionText: context.t('common.retry'), onAction: onRetry, ); } diff --git a/frontend/mobile/lib/shared/widgets/status_tag.dart b/frontend/mobile/lib/shared/widgets/status_tag.dart index e620e83..ab303a7 100644 --- a/frontend/mobile/lib/shared/widgets/status_tag.dart +++ b/frontend/mobile/lib/shared/widgets/status_tag.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../../app/i18n/app_localizations.dart'; import '../../app/theme/app_colors.dart'; import '../../app/theme/app_typography.dart'; import '../../app/theme/app_spacing.dart'; @@ -73,13 +74,13 @@ enum StatusType { success, pending, error, info, neutral } class StatusTags { StatusTags._(); - static StatusTag active() => const StatusTag(label: '可使用', type: StatusType.success); - static StatusTag pending() => const StatusTag(label: '待核销', type: StatusType.pending); - static StatusTag expired() => const StatusTag(label: '已过期', type: StatusType.neutral); - static StatusTag used() => const StatusTag(label: '已使用', type: StatusType.neutral); - static StatusTag processing() => const StatusTag(label: '处理中', type: StatusType.info); - static StatusTag completed() => const StatusTag(label: '已完成', type: StatusType.success); - static StatusTag cancelled() => const StatusTag(label: '已取消', type: StatusType.neutral); - static StatusTag refunding() => const StatusTag(label: '退款中', type: StatusType.pending); - static StatusTag onSale() => const StatusTag(label: '出售中', type: StatusType.info); + static StatusTag active({required BuildContext context}) => StatusTag(label: context.t('status.active'), type: StatusType.success); + static StatusTag pending({required BuildContext context}) => StatusTag(label: context.t('status.pending'), type: StatusType.pending); + static StatusTag expired({required BuildContext context}) => StatusTag(label: context.t('status.expired'), type: StatusType.neutral); + static StatusTag used({required BuildContext context}) => StatusTag(label: context.t('status.used'), type: StatusType.neutral); + static StatusTag processing({required BuildContext context}) => StatusTag(label: context.t('status.processing'), type: StatusType.info); + static StatusTag completed({required BuildContext context}) => StatusTag(label: context.t('status.completed'), type: StatusType.success); + static StatusTag cancelled({required BuildContext context}) => StatusTag(label: context.t('status.cancelled'), type: StatusType.neutral); + static StatusTag refunding({required BuildContext context}) => StatusTag(label: context.t('status.refunding'), type: StatusType.pending); + static StatusTag onSale({required BuildContext context}) => StatusTag(label: context.t('status.onSale'), type: StatusType.info); } diff --git a/frontend/mobile/pubspec.yaml b/frontend/mobile/pubspec.yaml index ea85c4b..a7c2dd7 100644 --- a/frontend/mobile/pubspec.yaml +++ b/frontend/mobile/pubspec.yaml @@ -9,6 +9,8 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter dev_dependencies: flutter_test:
{ cursor: 'pointer', font: 'var(--text-caption)', color: 'var(--color-primary)', - }}>详情 + }}>{t('details')}