fix(i18n): 清除前端页面中残留的硬编码中文
问题: 在英文/日文语言环境下,部分页面仍显示中文字符
修复内容:
## genex-mobile
- register_page.dart: `const TextSpan(text: ' 和 ')` → `context.t('register.and')`
- 4 语言文件新增 `register.and` key (和/和/and/および)
## miniapp
- login + h5-register: 移除 Toast fallback 中文 (`|| '验证码已发送'` 等)
- login + h5-register: 移除 JSX 中硬编码的《》书名号,改为 i18n 值内包含
· zh-CN: `《用户协议》`、`《隐私政策》`
· en-US: `User Agreement`、`Privacy Policy` (无括号)
· ja-JP: `「利用規約」`、`「プライバシーポリシー」`
- ai-guide 组件: 4 个推荐标签从硬编码改为 `t('ai_recommend_N')`
· 新增 12 个 i18n key (3 语言 × 4 标签)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e59c0d0527
commit
7d00cade2f
|
|
@ -71,6 +71,7 @@ const Map<String, String> en = {
|
|||
'register.agreement': 'I have read and agree to',
|
||||
'register.userAgreement': 'Terms of Service',
|
||||
'register.privacyPolicy': 'Privacy Policy',
|
||||
'register.and': 'and',
|
||||
'register.submit': 'Sign Up',
|
||||
'register.stepVerify': 'Verify',
|
||||
'register.stepPassword': 'Password',
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ const Map<String, String> ja = {
|
|||
'register.agreement': '以下に同意します',
|
||||
'register.userAgreement': '「利用規約」',
|
||||
'register.privacyPolicy': '「プライバシーポリシー」',
|
||||
'register.and': 'および',
|
||||
'register.submit': '登録',
|
||||
'register.stepVerify': '認証',
|
||||
'register.stepPassword': 'パスワード設定',
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ const Map<String, String> zhCN = {
|
|||
'register.agreement': '我已阅读并同意',
|
||||
'register.userAgreement': '《用户协议》',
|
||||
'register.privacyPolicy': '《隐私政策》',
|
||||
'register.and': '和',
|
||||
'register.submit': '注册',
|
||||
'register.stepVerify': '验证',
|
||||
'register.stepPassword': '设密码',
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ const Map<String, String> zhTW = {
|
|||
'register.agreement': '我已閱讀並同意',
|
||||
'register.userAgreement': '《使用者協議》',
|
||||
'register.privacyPolicy': '《隱私權政策》',
|
||||
'register.and': '和',
|
||||
'register.submit': '註冊',
|
||||
'register.stepVerify': '驗證',
|
||||
'register.stepPassword': '設密碼',
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ class _RegisterPageState extends State<RegisterPage> {
|
|||
text: context.t('register.userAgreement'),
|
||||
style: AppTypography.bodySmall.copyWith(color: AppColors.primary),
|
||||
),
|
||||
const TextSpan(text: ' 和 '),
|
||||
TextSpan(text: ' ${context.t('register.and')} '),
|
||||
TextSpan(
|
||||
text: context.t('register.privacyPolicy'),
|
||||
style: AppTypography.bodySmall.copyWith(color: AppColors.primary),
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ const AiGuide: React.FC<AiGuideProps> = ({ type }) => {
|
|||
return (
|
||||
<scroll-view scrollX className="ai-suggest-bar">
|
||||
{[
|
||||
{ id: 1, text: '星巴克 8.5折' },
|
||||
{ id: 2, text: 'Nike 限时特价' },
|
||||
{ id: 3, text: '新品餐饮券' },
|
||||
{ id: 4, text: '高评级推荐' },
|
||||
{ id: 1, text: t('ai_recommend_1') },
|
||||
{ id: 2, text: t('ai_recommend_2') },
|
||||
{ id: 3, text: t('ai_recommend_3') },
|
||||
{ id: 4, text: t('ai_recommend_4') },
|
||||
].map(s => (
|
||||
<view key={s.id} className="ai-tag">
|
||||
<text className="ai-tag-icon">✨</text>
|
||||
|
|
|
|||
|
|
@ -151,8 +151,8 @@ const translations: Record<Locale, Record<string, string>> = {
|
|||
'login_send_code': '获取验证码',
|
||||
'login_resend': '{seconds}秒后重发',
|
||||
'login_agree_prefix': '我已阅读并同意',
|
||||
'login_user_agreement': '用户协议',
|
||||
'login_privacy_policy': '隐私政策',
|
||||
'login_user_agreement': '《用户协议》',
|
||||
'login_privacy_policy': '《隐私政策》',
|
||||
'login_and': '和',
|
||||
|
||||
// ── Redeem ──
|
||||
|
|
@ -310,6 +310,10 @@ const translations: Record<Locale, Record<string, string>> = {
|
|||
|
||||
// ── AI Guide ──
|
||||
'ai_guide_greeting': '你好!我是AI助手,可以帮你找到最适合的券。试试搜索"星巴克"?',
|
||||
'ai_recommend_1': '星巴克 8.5折',
|
||||
'ai_recommend_2': 'Nike 限时特价',
|
||||
'ai_recommend_3': '新品餐饮券',
|
||||
'ai_recommend_4': '高评级推荐',
|
||||
|
||||
// ── Share Card ──
|
||||
'share_miniapp_code': '小程序码',
|
||||
|
|
@ -766,6 +770,10 @@ const translations: Record<Locale, Record<string, string>> = {
|
|||
|
||||
// ── AI Guide ──
|
||||
'ai_guide_greeting': 'Hi! I\'m the AI assistant. I can help you find the best coupons. Try searching "Starbucks"!',
|
||||
'ai_recommend_1': 'Starbucks 15% off',
|
||||
'ai_recommend_2': 'Nike Flash Sale',
|
||||
'ai_recommend_3': 'New Dining Coupons',
|
||||
'ai_recommend_4': 'Top Rated Picks',
|
||||
|
||||
// ── Share Card ──
|
||||
'share_miniapp_code': 'Mini Program Code',
|
||||
|
|
@ -1063,8 +1071,8 @@ const translations: Record<Locale, Record<string, string>> = {
|
|||
'login_send_code': 'コードを送信',
|
||||
'login_resend': '{seconds}秒後に再送信',
|
||||
'login_agree_prefix': '以下に同意します:',
|
||||
'login_user_agreement': '利用規約',
|
||||
'login_privacy_policy': 'プライバシーポリシー',
|
||||
'login_user_agreement': '「利用規約」',
|
||||
'login_privacy_policy': '「プライバシーポリシー」',
|
||||
'login_and': 'および',
|
||||
|
||||
// ── Redeem ──
|
||||
|
|
@ -1222,6 +1230,10 @@ const translations: Record<Locale, Record<string, string>> = {
|
|||
|
||||
// ── AI Guide ──
|
||||
'ai_guide_greeting': 'こんにちは!AIアシスタントです。最適なクーポンを見つけるお手伝いをします。「スターバックス」で検索してみてください!',
|
||||
'ai_recommend_1': 'スタバ 15%オフ',
|
||||
'ai_recommend_2': 'Nike タイムセール',
|
||||
'ai_recommend_3': '新作グルメクーポン',
|
||||
'ai_recommend_4': '高評価おすすめ',
|
||||
|
||||
// ── Share Card ──
|
||||
'share_miniapp_code': 'ミニプログラムコード',
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const H5RegisterPage: React.FC = () => {
|
|||
setCodeSending(true);
|
||||
sendSmsCode(phone, 'REGISTER')
|
||||
.then(() => {
|
||||
Taro.showToast({ title: t('login_code_sent') || '验证码已发送', icon: 'success' });
|
||||
Taro.showToast({ title: t('login_code_sent'), icon: 'success' });
|
||||
setCodeCountdown(60);
|
||||
const timer = setInterval(() => {
|
||||
setCodeCountdown((prev) => {
|
||||
|
|
@ -51,7 +51,7 @@ const H5RegisterPage: React.FC = () => {
|
|||
const { config } = require('../../config');
|
||||
Taro.setStorageSync(config.TOKEN_KEY, result.accessToken);
|
||||
Taro.setStorageSync(config.USER_KEY, JSON.stringify(result.user));
|
||||
Taro.showToast({ title: t('register_success') || '注册成功', icon: 'success' });
|
||||
Taro.showToast({ title: t('register_success'), icon: 'success' });
|
||||
setTimeout(() => {
|
||||
Taro.reLaunch({ url: '/pages/home/index' });
|
||||
}, 1000);
|
||||
|
|
@ -163,15 +163,15 @@ const H5RegisterPage: React.FC = () => {
|
|||
</view>
|
||||
<view className="terms-text-wrap">
|
||||
<text className="terms-text-normal">{t('login_agree_prefix')}</text>
|
||||
<text className="terms-text-link">{`《${t('login_user_agreement')}》`}</text>
|
||||
<text className="terms-text-link">{t('login_user_agreement')}</text>
|
||||
<text className="terms-text-normal">{t('login_and')}</text>
|
||||
<text className="terms-text-link">{`《${t('login_privacy_policy')}》`}</text>
|
||||
<text className="terms-text-link">{t('login_privacy_policy')}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
{/* Primary CTA Button */}
|
||||
<view className="register-btn" onClick={handleRegister}>
|
||||
<text className="register-btn-text">{submitting ? (t('loading') || '注册中...') : t('register_now')}</text>
|
||||
<text className="register-btn-text">{submitting ? t('loading') : t('register_now')}</text>
|
||||
</view>
|
||||
|
||||
{/* Social Login Divider */}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const LoginPage: React.FC = () => {
|
|||
setCodeSending(true);
|
||||
sendSmsCode(phone, 'LOGIN')
|
||||
.then(() => {
|
||||
Taro.showToast({ title: t('login_code_sent') || '验证码已发送', icon: 'success' });
|
||||
Taro.showToast({ title: t('login_code_sent'), icon: 'success' });
|
||||
setCodeCountdown(60);
|
||||
const timer = setInterval(() => {
|
||||
setCodeCountdown((prev) => {
|
||||
|
|
@ -75,7 +75,7 @@ const LoginPage: React.FC = () => {
|
|||
<view className="login-actions">
|
||||
<view className="wechat-btn" onClick={handleWechatLogin}>
|
||||
<text className="wechat-icon">💬</text>
|
||||
<text className="wechat-text">{logging ? (t('loading') || '登录中...') : t('login_wechat')}</text>
|
||||
<text className="wechat-text">{logging ? t('loading') : t('login_wechat')}</text>
|
||||
</view>
|
||||
|
||||
<view className="divider">
|
||||
|
|
@ -116,16 +116,16 @@ const LoginPage: React.FC = () => {
|
|||
</view>
|
||||
</view>
|
||||
<view className="login-btn" onClick={handlePhoneLogin}>
|
||||
<text className="login-btn-text">{logging ? (t('loading') || '登录中...') : t('login_btn')}</text>
|
||||
<text className="login-btn-text">{logging ? t('loading') : t('login_btn')}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
{/* Terms */}
|
||||
<view className="terms">
|
||||
<text className="terms-text">{t('login_agree')}</text>
|
||||
<text className="terms-link">{`《${t('login_user_agreement')}》`}</text>
|
||||
<text className="terms-link">{t('login_user_agreement')}</text>
|
||||
<text className="terms-text">{t('login_and')}</text>
|
||||
<text className="terms-link">{`《${t('login_privacy_policy')}》`}</text>
|
||||
<text className="terms-link">{t('login_privacy_policy')}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
|
|||
Loading…
Reference in New Issue