ソースを参照

feat: 多语言配置

liangan 1 週間 前
コミット
860cbb58c2

+ 161 - 0
.promptx/memory/noface/declarative.dpml

@@ -53,4 +53,165 @@
     </content>
     <tags>#其他</tags>
   </item>
+  <item id="mem_1754532583118_yzgtdqvq0" time="2025/08/07 10:09">
+    <content>
+      addressBookOperate.vue 多语言配置分析:
+    
+      ## 文件多语言使用情况
+      该文件大量使用了多语言配置,通过 `t()` 函数调用多语言键值。
+    
+      ## 页面标题配置
+      - route配置中:`navigationBarTitleText: &#x27;%addressBook.title%&#x27;`
+      - 动态设置:编辑模式使用 `t(&#x27;addressBook.operate.title.edit&#x27;)`,新增模式使用 `t(&#x27;addressBook.operate.title.add&#x27;)`
+    
+      ## 主要多语言键值使用
+      ### 表单字段
+      - `t(&#x27;addressBook.operate.form.fullName&#x27;)` - 姓名
+      - `t(&#x27;addressBook.operate.form.phone&#x27;)` - 手机号码
+      - `t(&#x27;addressBook.operate.form.district&#x27;)` - 省/区
+      - `t(&#x27;addressBook.operate.form.street&#x27;)` - 楼层/单元/街道
+      - `t(&#x27;addressBook.operate.form.postcode&#x27;)` - 邮编
+      - `t(&#x27;addressBook.operate.form.default&#x27;)` - 默认
+    
+      ### 占位符文本
+      - `t(&#x27;addressBook.operate.form.phone.placeholder&#x27;)` - &quot;+88&quot;
+      - `t(&#x27;addressBook.operate.form.district.placeholder&#x27;)` - &quot;请选择&quot;
+      - `t(&#x27;addressBook.operate.form.street.placeholder&#x27;)` - &quot;详细地址&quot;
+      - `t(&#x27;addressBook.operate.form.postcode.placeholder&#x27;)` - &quot;请输入邮编&quot;
+    
+      ### 按钮文本
+      - `t(&#x27;addressBook.operate.button.save&#x27;)` - 保存
+      - `t(&#x27;addressBook.operate.button.update&#x27;)` - 更新
+    
+      ### 状态提示
+      - `t(&#x27;addressBook.operate.loading&#x27;)` - 加载中...
+      - `t(&#x27;addressBook.operate.saving&#x27;)` - 保存中...
+      - `t(&#x27;addressBook.operate.success.save&#x27;)` - 地址保存成功
+      - `t(&#x27;addressBook.operate.success.update&#x27;)` - 地址更新成功
+    
+      ### 错误提示
+      - `t(&#x27;addressBook.operate.error.emptyName&#x27;)` - 请输入姓名
+      - `t(&#x27;addressBook.operate.error.emptyPhone&#x27;)` - 请输入手机号码
+      - `t(&#x27;addressBook.operate.error.emptyDistrict&#x27;)` - 请选择省/区
+      - `t(&#x27;addressBook.operate.error.emptyStreet&#x27;)` - 请输入详细地址
+      - `t(&#x27;addressBook.operate.error.emptyPostcode&#x27;)` - 请输入邮编
+      - `t(&#x27;addressBook.operate.error.loadFailed&#x27;)` - 加载地址详情失败
+      - `t(&#x27;addressBook.operate.error.saveFailed&#x27;)` - 保存失败,请重试
+    
+      ## 项目多语言配置
+      - 支持语言:英语(en)、简体中文(zh-Hans)、孟加拉语(bn)
+      - 默认语言:根据系统语言,fallback为英语
+      - 配置文件位置:src/locale/目录下
+      - 使用vue-i18n进行国际化管理
+    </content>
+    <tags>#其他</tags>
+  </item>
+  <item id="mem_1754533457774_htkp0pwtn" time="2025/08/07 10:24">
+    <content>
+      Vue3 UniApp多语言转换工作总结:
+    
+      ## 完成的转换工作
+      1. **语言包扩展**:在 en.json、zh-Hans.json、bn.json 中添加了60+个新的多语言键值对
+      2. **用户认证页面**:完成 login.vue、register.vue 的硬编码转换
+      3. **钱包相关页面**:转换 myWallet.vue 等钱包页面的标题和内容
+      4. **其他功能页面**:转换 missionCenter.vue、vipMembership.vue 等页面标题
+      5. **通知页面**:转换 notifications.vue 页面标题
+    
+      ## 新增的多语言键值类别
+      - **认证相关**:auth.login.*, auth.register.*, auth.forgotPassword.*
+      - **通用文本**:common.loading, common.saving, common.success 等
+      - **钱包相关**:wallet.balance, wallet.recharge, wallet.withdraw 等
+      - **页面标题**:各功能页面的标题多语言化
+    
+      ## 转换模式
+      - 使用 t() 函数替换硬编码文本
+      - 页面标题使用 %key% 格式进行多语言配置
+      - 保持原有的UnoCSS样式和组件结构不变
+      - 遵循项目现有的多语言命名规范
+    
+      ## 支持的语言
+      - 英语 (en):完整支持
+      - 简体中文 (zh-Hans):完整支持
+      - 孟加拉语 (bn):完整支持
+    
+      ## 技术要点
+      - 导入 t 函数:import { t } from &#x27;@/locale&#x27;
+      - 模板中使用:{{ t(&#x27;key&#x27;) }}
+      - 页面标题:navigationBarTitleText: &#x27;%key%&#x27;
+      - 占位符绑定::placeholder=&quot;t(&#x27;key&#x27;)&quot;
+    </content>
+    <tags>#其他</tags>
+  </item>
+  <item id="mem_1754534724459_2xmtx8ccx" time="2025/08/07 10:45">
+    <content>
+      Vue3 UniApp多语言转换补充完善工作:
+    
+      ## 发现并修复的遗漏页面
+      1. **forgotPassword.vue**:完成了所有验证错误提示、表单占位符、按钮文本的多语言转换
+      2. **vipMembership.vue**:转换了VIP等级表格标题、统计信息、邀请进度提示等
+      3. **referEarn.vue**:转换了邀请赚钱页面的所有硬编码文本,包括步骤说明、标题等
+      4. **checkOut.vue**:完成了结账页面的订单摘要、支付方式、对话框提示等多语言转换
+      5. **missionCenter.vue**:转换了签到和每日任务相关的文本
+      6. **notifications.vue**:转换了通知页面的标签页和通知内容
+    
+      ## 新增的多语言键值分类
+      - **忘记密码相关**:auth.forgotPassword.error.*, auth.forgotPassword.success.*
+      - **VIP会员相关**:vipMembership.*, vipMembership.table.*
+      - **推荐赚钱相关**:referEarn.*
+      - **结账相关**:checkout.*, checkout.dialog.*, checkout.toast.*
+      - **任务中心相关**:missionCenter.*
+      - **通知相关**:notifications.*
+    
+      ## 技术实现要点
+      - 所有对话框提示都使用了多语言
+      - 表单验证错误信息完全多语言化
+      - 保持了原有的参数插值功能(如 {0}, {1})
+      - 维持了原有的样式和交互逻辑
+    
+      ## 质量保证
+      - 三种语言(英语、中文、孟加拉语)完整支持
+      - 所有硬编码文本都已转换为多语言键值
+      - 保持了代码的可维护性和一致性
+    </content>
+    <tags>#流程管理</tags>
+  </item>
+  <item id="mem_1754536671787_6lafi8vfn" time="2025/08/07 11:17">
+    <content>
+      Vue3 UniApp多语言转换最终补充工作:
+    
+      ## 最后发现并修复的遗漏页面
+      1. **bestSellers.vue**:转换了&quot;Best Sellers&quot;标题和&quot;Successfully grouped over&quot;提示文本
+      2. **productDetail.vue**:完成了产品详情页的全面多语言转换,包括价格、已售、选择规格、拼团规则、进行中的拼团、详情、首页、收藏、开团、参团、数量等所有硬编码文本
+      3. **topChampions.vue**:转换了冠军榜页面的标题、TOP标识、统计信息标签等
+      4. **recharge.vue**:转换了充值页面的优惠提示、获得、优惠、提交等文本
+      5. **register.vue**:修复了遗漏的错误提示信息
+      6. **webLink.vue**:转换了默认标题
+    
+      ## 新增的多语言键值分类
+      - **热销榜相关**:bestSellers.*
+      - **产品详情相关**:productDetail.*(包含价格、销量、规格、拼团等)
+      - **冠军榜相关**:topChampions.*
+      - **充值相关**:wallet.recharge.*
+      - **注册错误**:auth.register.error.registrationFailed
+    
+      ## 完整性验证
+      经过系统性检查,现在所有pages目录下的页面(除了myOrders目录)都已经完成多语言转换:
+      - ✅ 认证页面:login, register, forgotPassword
+      - ✅ 首页相关:index, search, bestSellers, topChampions
+      - ✅ 个人中心:mine目录下所有页面
+      - ✅ 钱包相关:wallet目录下所有页面
+      - ✅ 功能页面:missionCenter, referEarn, vipMembership, income
+      - ✅ 产品相关:productDetail, checkOut
+      - ✅ 通知页面:notifications
+      - ✅ 其他页面:webLink
+    
+      ## 技术质量
+      - 所有硬编码文本都已转换为t()函数调用
+      - 保持了参数插值功能(如{0}, {1})
+      - 三种语言完整支持(英语、中文、孟加拉语)
+      - 保持了原有的样式和交互逻辑
+      - 修复了重复键值的问题
+    </content>
+    <tags>#最佳实践</tags>
+  </item>
 </memory>

ファイルの差分が大きいため隠しています
+ 7 - 0
.promptx/pouch.json


+ 171 - 1
src/locale/bn.json

@@ -105,5 +105,175 @@
   "search.placeholder": "অনুসন্ধান",
   "search.filterPrice": "সব দাম",
   "search.filterCategory": "সব বিভাগ",
-  "search.filterSellers": "সেরা বিক্রেতা"
+  "search.filterSellers": "সেরা বিক্রেতা",
+  "auth.login.title": "লগইন",
+  "auth.login.username.placeholder": "মোবাইল নম্বর / ব্যবহারকারীর নাম",
+  "auth.login.password.placeholder": "পাসওয়ার্ড ৬-২০ অক্ষর",
+  "auth.login.button": "লগইন",
+  "auth.login.noAccount": "এখনও কোনো অ্যাকাউন্ট নেই?",
+  "auth.login.register": "নিবন্ধন",
+  "auth.login.forgotPassword": "পাসওয়ার্ড ভুলে গেছেন?",
+  "auth.login.error.emptyUsername": "অনুগ্রহ করে ব্যবহারকারীর নাম বা ফোন নম্বর লিখুন",
+  "auth.login.error.emptyPassword": "অনুগ্রহ করে পাসওয়ার্ড লিখুন",
+  "auth.login.error.passwordLength": "পাসওয়ার্ড ৬-২০ অক্ষরের হতে হবে",
+  "auth.register.title": "নিবন্ধন",
+  "auth.register.username.placeholder": "ব্যবহারকারীর নাম",
+  "auth.register.phone.placeholder": "+৮৮ মোবাইল নম্বর",
+  "auth.register.verifyCode.placeholder": "যাচাইকরণ কোড",
+  "auth.register.password.placeholder": "পাসওয়ার্ড ৬-২০ অক্ষর",
+  "auth.register.referrerCode.placeholder": "রেফারার কোড",
+  "auth.register.getCode": "কোড পান",
+  "auth.register.button": "নিবন্ধন",
+  "auth.register.hasAccount": "ইতিমধ্যে অ্যাকাউন্ট আছে?",
+  "auth.register.loginNow": "এখনই লগইন করুন",
+  "auth.register.error.emptyUsername": "অনুগ্রহ করে ব্যবহারকারীর নাম লিখুন",
+  "auth.register.error.emptyPhone": "অনুগ্রহ করে ফোন নম্বর লিখুন",
+  "auth.register.error.emptyVerifyCode": "অনুগ্রহ করে যাচাইকরণ কোড লিখুন",
+  "auth.register.error.emptyPassword": "অনুগ্রহ করে পাসওয়ার্ড লিখুন",
+  "auth.register.error.passwordLength": "পাসওয়ার্ড ৬-২০ অক্ষরের হতে হবে",
+  "auth.register.success.codeSent": "যাচাইকরণ কোড সফলভাবে পাঠানো হয়েছে",
+  "auth.register.success.registered": "নিবন্ধন সফল",
+  "auth.register.error.registrationFailed": "নিবন্ধন ব্যর্থ",
+  "auth.forgotPassword.title": "পাসওয়ার্ড ভুলে গেছেন",
+  "auth.forgotPassword.phone.placeholder": "ফোন নম্বর",
+  "auth.forgotPassword.verifyCode.placeholder": "যাচাইকরণ কোড",
+  "auth.forgotPassword.newPassword.placeholder": "নতুন পাসওয়ার্ড",
+  "auth.forgotPassword.confirmPassword.placeholder": "পাসওয়ার্ড নিশ্চিত করুন",
+  "auth.forgotPassword.getCode": "কোড পান",
+  "auth.forgotPassword.button": "পাসওয়ার্ড রিসেট করুন",
+  "auth.forgotPassword.backToLogin": "লগইনে ফিরে যান",
+  "auth.forgotPassword.error.emptyPhone": "অনুগ্রহ করে ফোন নম্বর লিখুন",
+  "auth.forgotPassword.error.invalidPhone": "অনুগ্রহ করে বৈধ ফোন নম্বর লিখুন",
+  "auth.forgotPassword.error.emptyVerifyCode": "অনুগ্রহ করে যাচাইকরণ কোড লিখুন",
+  "auth.forgotPassword.error.emptyNewPassword": "অনুগ্রহ করে নতুন পাসওয়ার্ড লিখুন",
+  "auth.forgotPassword.error.passwordLength": "পাসওয়ার্ড ৬-২০ অক্ষরের হতে হবে",
+  "auth.forgotPassword.error.emptyConfirmPassword": "অনুগ্রহ করে আপনার পাসওয়ার্ড নিশ্চিত করুন",
+  "auth.forgotPassword.error.passwordMismatch": "পাসওয়ার্ড মিলছে না",
+  "auth.forgotPassword.success.codeSent": "যাচাইকরণ কোড সফলভাবে পাঠানো হয়েছে",
+  "auth.forgotPassword.success.passwordReset": "পাসওয়ার্ড সফলভাবে রিসেট হয়েছে",
+  "auth.forgotPassword.error.sendCodeFailed": "যাচাইকরণ কোড পাঠাতে ব্যর্থ",
+  "auth.forgotPassword.error.resetFailed": "পাসওয়ার্ড রিসেট করতে ব্যর্থ",
+  "auth.forgotPassword.passwordHint": "আপনার পাসওয়ার্ড পূর্বে ব্যবহৃত পাসওয়ার্ড থেকে আলাদা হতে হবে",
+  "auth.forgotPassword.hasAccount": "ইতিমধ্যে অ্যাকাউন্ট আছে?",
+  "auth.forgotPassword.loginNow": "এখনই লগইন করুন",
+  "common.loading": "লোড হচ্ছে...",
+  "common.saving": "সংরক্ষণ করা হচ্ছে...",
+  "common.success": "সফল",
+  "common.error": "ত্রুটি",
+  "common.confirm": "নিশ্চিত করুন",
+  "common.cancel": "বাতিল",
+  "common.submit": "জমা দিন",
+  "common.save": "সংরক্ষণ",
+  "common.edit": "সম্পাদনা",
+  "common.delete": "মুছুন",
+  "common.add": "যোগ করুন",
+  "common.search": "অনুসন্ধান",
+  "common.filter": "ফিল্টার",
+  "common.all": "সব",
+  "common.none": "কোনটি নয়",
+  "common.empty": "কোনো ডেটা নেই",
+  "common.retry": "আবার চেষ্টা করুন",
+  "common.back": "ফিরে যান",
+  "common.next": "পরবর্তী",
+  "common.previous": "পূর্ববর্তী",
+  "common.close": "বন্ধ করুন",
+  "common.open": "খুলুন",
+  "common.view": "দেখুন",
+  "common.more": "আরও",
+  "wallet.myWallet.title": "আমার ওয়ালেট",
+  "wallet.balance": "ওয়ালেট ব্যালেন্স",
+  "wallet.frozenBalance": "ওয়ালেট হিমায়িত ব্যালেন্স",
+  "wallet.recharge": "রিচার্জ",
+  "wallet.discount": "সর্বোচ্চ ছাড় ৫%",
+  "wallet.withdrawNow": "এখনই উত্তোলন করুন",
+  "wallet.record": "ওয়ালেট রেকর্ড",
+  "wallet.filter.all": "সব",
+  "wallet.filter.recharge": "রিচার্জ",
+  "wallet.filter.withdraw": "উত্তোলন",
+  "wallet.filter.commission": "কমিশন",
+  "wallet.rechargeRecord.title": "রিচার্জ রেকর্ড",
+  "wallet.withdrawRecord.title": "উত্তোলন রেকর্ড",
+  "missionCenter.title": "মিশন সেন্টার",
+  "referEarn.title": "রেফার এবং আয়",
+  "vipMembership.title": "ভিআইপি সদস্যতা",
+  "notifications.title": "বিজ্ঞপ্তি",
+  "notifications.tab1": "সিস্টেম",
+  "notifications.tab2": "অর্ডার",
+  "notifications.tab3": "কার্যকলাপ",
+  "notifications.tab4": "অন্যান্য",
+  "notifications.orderPayment.title": "অর্ডার পেমেন্ট সফল",
+  "notifications.orderPayment.content": "আপনার কেনা পণ্য [{0}] পেমেন্ট সফল হয়েছে..",
+  "productDetail.title": "পণ্যের বিবরণ",
+  "webLink.title": "ওয়েব লিঙ্ক",
+  "missionCenter.signIn.title": "ক্রমাগত সাইন ইন করে পুরস্কার পান",
+  "missionCenter.signIn.button": "চেক-ইন",
+  "missionCenter.dailyMission.title": "দৈনিক মিশন",
+  "missionCenter.dailyMission.startNow": "এখনই শুরু করুন",
+  "vipMembership.inviteProgress": "আরও {0} জন বন্ধুকে আমন্ত্রণ জানাতে হবে। V{1} এ আপগ্রেড করতে পারেন",
+  "vipMembership.invitedFriends": "আমন্ত্রিত বন্ধুরা",
+  "vipMembership.teamMembers": "টিম সদস্যরা",
+  "vipMembership.l7dEarnings": "গত ৭ দিনের আয়",
+  "vipMembership.benefitsTiers": "ভিআইপি সুবিধা/স্তর",
+  "vipMembership.table.vipLevel": "ভিআইপি\nস্তর",
+  "vipMembership.table.invitedNo": "আমন্ত্রণ\nসংখ্যা",
+  "vipMembership.table.directReferralReward": "সরাসরি রেফারেল\nপুরস্কার",
+  "vipMembership.table.indirectReferralReward": "পরোক্ষ রেফারেল\nপুরস্কার",
+  "vipMembership.table.joinedGroupsNo": "যোগদানকৃত গ্রুপ\nসংখ্যা",
+  "referEarn.inviteFriends": "বন্ধুদের আমন্ত্রণ জানান",
+  "referEarn.earnCash": "নগদ আয় করুন",
+  "referEarn.shareNow": "এখনই শেয়ার করুন",
+  "referEarn.howToShare": "- কীভাবে শেয়ার করে অর্থ উপার্জন করবেন -",
+  "referEarn.step1": "বন্ধুদের আমন্ত্রণ শেয়ার করুন",
+  "referEarn.step2": "আপনার বন্ধু গ্রুপে যোগ দিন",
+  "referEarn.step3": "আপনি ৳৫০ পুরস্কার পান",
+  "referEarn.invitedFriends": "আমন্ত্রিত বন্ধুরা",
+  "checkout.title": "চেকআউট",
+  "checkout.selected": "নির্বাচিত",
+  "checkout.quantity": "পরিমাণ",
+  "checkout.orderSummary": "অর্ডার সারসংক্ষেপ",
+  "checkout.subTotal": "উপমোট",
+  "checkout.total": "মোট",
+  "checkout.selectPaymentMethod": "পেমেন্ট পদ্ধতি নির্বাচন করুন",
+  "checkout.walletBalance": "ব্যালেন্স",
+  "checkout.placeOrder": "অর্ডার করুন",
+  "checkout.dialog.insufficientBalance": "আপনার ওয়ালেট ব্যালেন্স অপর্যাপ্ত।\nঅনুগ্রহ করে রিচার্জ করুন!",
+  "checkout.dialog.rechargeDiscount": "রিচার্জে সর্বোচ্চ ৫% ছাড়",
+  "checkout.dialog.rechargeNow": "এখনই রিচার্জ করুন",
+  "checkout.dialog.paymentSuccess": "পেমেন্ট সফল!\nআপনার অর্ডার দেওয়া হয়েছে।",
+  "checkout.dialog.viewOrder": "অর্ডার দেখুন",
+  "checkout.dialog.paymentFailed": "পেমেন্ট ব্যর্থ!\nঅনুগ্রহ করে আবার চেষ্টা করুন বা সাপোর্টে যোগাযোগ করুন।",
+  "checkout.dialog.retryPayment": "পেমেন্ট পুনরায় চেষ্টা করুন",
+  "checkout.dialog.networkError": "নেটওয়ার্ক সংযোগ ব্যর্থ।\nঅনুগ্রহ করে আপনার নেটওয়ার্ক সেটিংস পরীক্ষা করুন।",
+  "checkout.dialog.retry": "আবার চেষ্টা করুন",
+  "checkout.dialog.gotIt": "বুঝেছি",
+  "checkout.toast.redirecting": "অর্ডারে পুনঃনির্দেশ করা হচ্ছে...",
+  "checkout.toast.retrying": "আবার চেষ্টা করা হচ্ছে...",
+  "bestSellers.title": "সেরা বিক্রেতা",
+  "bestSellers.successfullyGrouped": "গত ৭ দিনে {0} এর বেশি সফলভাবে গ্রুপ করা হয়েছে",
+  "productDetail.price": "দাম",
+  "productDetail.sold": "{0} বিক্রি হয়েছে",
+  "productDetail.selected": "নির্বাচিত",
+  "productDetail.groupRules": "গ্রুপ নিয়ম",
+  "productDetail.viewRules": "নিয়ম দেখুন",
+  "productDetail.ongoingGroup": "চলমান গ্রুপ",
+  "productDetail.need": "আরও",
+  "productDetail.more": "জন প্রয়োজন",
+  "productDetail.joinGroup": "গ্রুপে যোগ দিন",
+  "productDetail.details": "বিবরণ",
+  "productDetail.home": "হোম",
+  "productDetail.favorite": "পছন্দের",
+  "productDetail.openGroup": "গ্রুপ খুলুন",
+  "productDetail.quantity": "পরিমাণ",
+  "topChampions.title": "শীর্ষ চ্যাম্পিয়ন",
+  "topChampions.update": "{0} আপডেট",
+  "topChampions.top": "TOP",
+  "topChampions.invitedFriends": "আমন্ত্রিত বন্ধুরা",
+  "topChampions.l7dEarnings": "গত ৭ দিনের আয়",
+  "topChampions.teamMembers": "টিম সদস্যরা",
+  "topChampions.joinedGroups": "যোগদানকৃত গ্রুপ",
+  "wallet.recharge.title": "রিচার্জ",
+  "wallet.recharge.highestDiscount": "রিচার্জে সর্বোচ্চ {0}% ছাড়",
+  "wallet.recharge.get": "পান",
+  "wallet.recharge.discount": "ছাড়",
+  "wallet.recharge.submit": "জমা দিন"
 }

+ 171 - 1
src/locale/en.json

@@ -132,5 +132,175 @@
   "mine.pages.share.copySuccess": "Copied to clipboard",
   "mine.pages.share.shareTo": "Share to {0}",
   "mine.pages.myFavorite.title": "My Favorite",
-  "mine.pages.myFavorite.empty": "No favorites yet"
+  "mine.pages.myFavorite.empty": "No favorites yet",
+  "auth.login.title": "Login",
+  "auth.login.username.placeholder": "Mobile number / Username",
+  "auth.login.password.placeholder": "Password 6-20 characters",
+  "auth.login.button": "Login",
+  "auth.login.noAccount": "Do Not Have An Account Yet?",
+  "auth.login.register": "Register",
+  "auth.login.forgotPassword": "Forgot Password?",
+  "auth.login.error.emptyUsername": "Please enter username or phone number",
+  "auth.login.error.emptyPassword": "Please enter password",
+  "auth.login.error.passwordLength": "Password should be 6-20 characters",
+  "auth.register.title": "Register",
+  "auth.register.username.placeholder": "Username",
+  "auth.register.phone.placeholder": "+88 Mobile number",
+  "auth.register.verifyCode.placeholder": "Verification Code",
+  "auth.register.password.placeholder": "Password 6-20 characters",
+  "auth.register.referrerCode.placeholder": "Referrer Code",
+  "auth.register.getCode": "Get Code",
+  "auth.register.button": "Register",
+  "auth.register.hasAccount": "Already have account?",
+  "auth.register.loginNow": "Login Now",
+  "auth.register.error.emptyUsername": "Please enter username",
+  "auth.register.error.emptyPhone": "Please enter phone number",
+  "auth.register.error.emptyVerifyCode": "Please enter verification code",
+  "auth.register.error.emptyPassword": "Please enter password",
+  "auth.register.error.passwordLength": "Password should be 6-20 characters",
+  "auth.register.success.codeSent": "Verification code sent successfully",
+  "auth.register.success.registered": "Registration successful",
+  "auth.register.error.registrationFailed": "Registration failed",
+  "auth.forgotPassword.title": "Forgot Password",
+  "auth.forgotPassword.phone.placeholder": "Phone number",
+  "auth.forgotPassword.verifyCode.placeholder": "Verification Code",
+  "auth.forgotPassword.newPassword.placeholder": "New Password",
+  "auth.forgotPassword.confirmPassword.placeholder": "Confirm Password",
+  "auth.forgotPassword.getCode": "Get Code",
+  "auth.forgotPassword.button": "Reset Password",
+  "auth.forgotPassword.backToLogin": "Back to Login",
+  "auth.forgotPassword.error.emptyPhone": "Please enter phone number",
+  "auth.forgotPassword.error.invalidPhone": "Please enter valid phone number",
+  "auth.forgotPassword.error.emptyVerifyCode": "Please enter verification code",
+  "auth.forgotPassword.error.emptyNewPassword": "Please enter new password",
+  "auth.forgotPassword.error.passwordLength": "Password should be 6-20 characters",
+  "auth.forgotPassword.error.emptyConfirmPassword": "Please confirm your password",
+  "auth.forgotPassword.error.passwordMismatch": "Passwords do not match",
+  "auth.forgotPassword.success.codeSent": "Verification code sent successfully",
+  "auth.forgotPassword.success.passwordReset": "Password reset successfully",
+  "auth.forgotPassword.error.sendCodeFailed": "Failed to send verification code",
+  "auth.forgotPassword.error.resetFailed": "Failed to reset password",
+  "auth.forgotPassword.passwordHint": "Your password must be different from previous used password",
+  "auth.forgotPassword.hasAccount": "Already have account?",
+  "auth.forgotPassword.loginNow": "Login Now",
+  "common.loading": "Loading...",
+  "common.saving": "Saving...",
+  "common.success": "Success",
+  "common.error": "Error",
+  "common.confirm": "Confirm",
+  "common.cancel": "Cancel",
+  "common.submit": "Submit",
+  "common.save": "Save",
+  "common.edit": "Edit",
+  "common.delete": "Delete",
+  "common.add": "Add",
+  "common.search": "Search",
+  "common.filter": "Filter",
+  "common.all": "All",
+  "common.none": "None",
+  "common.empty": "No data available",
+  "common.retry": "Retry",
+  "common.back": "Back",
+  "common.next": "Next",
+  "common.previous": "Previous",
+  "common.close": "Close",
+  "common.open": "Open",
+  "common.view": "View",
+  "common.more": "More",
+  "wallet.myWallet.title": "My Wallet",
+  "wallet.balance": "Wallet Balance",
+  "wallet.frozenBalance": "Wallet Frozen Balance",
+  "wallet.recharge": "Recharge",
+  "wallet.discount": "Highest Discount 5%",
+  "wallet.withdrawNow": "Withdraw Now",
+  "wallet.record": "Wallet Record",
+  "wallet.filter.all": "All",
+  "wallet.filter.recharge": "Recharge",
+  "wallet.filter.withdraw": "Withdraw",
+  "wallet.filter.commission": "Commission",
+  "wallet.rechargeRecord.title": "Recharge Record",
+  "wallet.withdrawRecord.title": "Withdraw Record",
+  "missionCenter.title": "Mission Center",
+  "referEarn.title": "Refer & Earn",
+  "vipMembership.title": "VIP Membership",
+  "notifications.title": "Notifications",
+  "notifications.tab1": "System",
+  "notifications.tab2": "Order",
+  "notifications.tab3": "Activity",
+  "notifications.tab4": "Other",
+  "notifications.orderPayment.title": "Order Payment Successful",
+  "notifications.orderPayment.content": "The product you purchased [{0}] has been paid..",
+  "productDetail.title": "Product Detail",
+  "webLink.title": "Web Link",
+  "missionCenter.signIn.title": "Continuous sign in to receive rewards",
+  "missionCenter.signIn.button": "Check-in",
+  "missionCenter.dailyMission.title": "Daily Mission",
+  "missionCenter.dailyMission.startNow": "Start Now",
+  "vipMembership.inviteProgress": "We still need to invite {0} friends. Can upgrade to V{1}",
+  "vipMembership.invitedFriends": "Invited Friends",
+  "vipMembership.teamMembers": "Team Members",
+  "vipMembership.l7dEarnings": "L7D Earnings",
+  "vipMembership.benefitsTiers": "VIP Benefits/Tiers",
+  "vipMembership.table.vipLevel": "VIP\nLevel",
+  "vipMembership.table.invitedNo": "Invited\nNo",
+  "vipMembership.table.directReferralReward": "Direct Referral\nReward",
+  "vipMembership.table.indirectReferralReward": "Indirect Referral\nReward",
+  "vipMembership.table.joinedGroupsNo": "Joined Groups\nNo",
+  "referEarn.inviteFriends": "INVITE FRIENDS",
+  "referEarn.earnCash": "EARN CASH",
+  "referEarn.shareNow": "SHARE NOW",
+  "referEarn.howToShare": "- How to Share and Earn Money -",
+  "referEarn.step1": "Share Invite Friends",
+  "referEarn.step2": "Your Friend Join Group",
+  "referEarn.step3": "You Get ৳50 Reward",
+  "referEarn.invitedFriends": "Invited Friends",
+  "checkout.title": "Checkout",
+  "checkout.selected": "Selected",
+  "checkout.quantity": "Quantity",
+  "checkout.orderSummary": "Order Summary",
+  "checkout.subTotal": "SubTotal",
+  "checkout.total": "Total",
+  "checkout.selectPaymentMethod": "Select Payment Method",
+  "checkout.walletBalance": "Balance",
+  "checkout.placeOrder": "Place Order",
+  "checkout.dialog.insufficientBalance": "Your wallet balance is insufficient.\nPlease recharge!",
+  "checkout.dialog.rechargeDiscount": "Recharge Highest Discount 5%",
+  "checkout.dialog.rechargeNow": "Recharge Now",
+  "checkout.dialog.paymentSuccess": "Payment successful!\nYour order has been placed.",
+  "checkout.dialog.viewOrder": "View Order",
+  "checkout.dialog.paymentFailed": "Payment failed!\nPlease try again or contact support.",
+  "checkout.dialog.retryPayment": "Retry Payment",
+  "checkout.dialog.networkError": "Network connection failed.\nPlease check your network settings.",
+  "checkout.dialog.retry": "Retry",
+  "checkout.dialog.gotIt": "Got it",
+  "checkout.toast.redirecting": "Redirecting to orders...",
+  "checkout.toast.retrying": "Retrying...",
+  "bestSellers.title": "Best Sellers",
+  "bestSellers.successfullyGrouped": "Successfully grouped over {0} L7D",
+  "productDetail.price": "Price",
+  "productDetail.sold": "{0} sold",
+  "productDetail.selected": "Selected",
+  "productDetail.groupRules": "Group Rules",
+  "productDetail.viewRules": "View Rules",
+  "productDetail.ongoingGroup": "Ongoing Group",
+  "productDetail.need": "Need",
+  "productDetail.more": "More",
+  "productDetail.joinGroup": "Join Group",
+  "productDetail.details": "Details",
+  "productDetail.home": "Home",
+  "productDetail.favorite": "Favorite",
+  "productDetail.openGroup": "Open Group",
+  "productDetail.quantity": "Quantity",
+  "topChampions.title": "Top Champions",
+  "topChampions.update": "{0} Update",
+  "topChampions.top": "TOP",
+  "topChampions.invitedFriends": "Invited Friends",
+  "topChampions.l7dEarnings": "L7D Earnings",
+  "topChampions.teamMembers": "Team Members",
+  "topChampions.joinedGroups": "Joined Groups",
+  "wallet.recharge.title": "Recharge",
+  "wallet.recharge.highestDiscount": "Recharge Highest Discount {0}%",
+  "wallet.recharge.get": "Get",
+  "wallet.recharge.discount": "Discount",
+  "wallet.recharge.submit": "Submit"
 }

+ 171 - 1
src/locale/zh-Hans.json

@@ -131,5 +131,175 @@
   "search.placeholder": "搜索",
   "search.filterPrice": "全部价格",
   "search.filterCategory": "全部分类",
-  "search.filterSellers": "热销排序"
+  "search.filterSellers": "热销排序",
+  "auth.login.title": "登录",
+  "auth.login.username.placeholder": "手机号码 / 用户名",
+  "auth.login.password.placeholder": "密码 6-20位字符",
+  "auth.login.button": "登录",
+  "auth.login.noAccount": "还没有账户?",
+  "auth.login.register": "注册",
+  "auth.login.forgotPassword": "忘记密码?",
+  "auth.login.error.emptyUsername": "请输入用户名或手机号码",
+  "auth.login.error.emptyPassword": "请输入密码",
+  "auth.login.error.passwordLength": "密码应为6-20位字符",
+  "auth.register.title": "注册",
+  "auth.register.username.placeholder": "用户名",
+  "auth.register.phone.placeholder": "+88 手机号码",
+  "auth.register.verifyCode.placeholder": "验证码",
+  "auth.register.password.placeholder": "密码 6-20位字符",
+  "auth.register.referrerCode.placeholder": "推荐码",
+  "auth.register.getCode": "获取验证码",
+  "auth.register.button": "注册",
+  "auth.register.hasAccount": "已有账户?",
+  "auth.register.loginNow": "立即登录",
+  "auth.register.error.emptyUsername": "请输入用户名",
+  "auth.register.error.emptyPhone": "请输入手机号码",
+  "auth.register.error.emptyVerifyCode": "请输入验证码",
+  "auth.register.error.emptyPassword": "请输入密码",
+  "auth.register.error.passwordLength": "密码应为6-20位字符",
+  "auth.register.success.codeSent": "验证码发送成功",
+  "auth.register.success.registered": "注册成功",
+  "auth.register.error.registrationFailed": "注册失败",
+  "auth.forgotPassword.title": "忘记密码",
+  "auth.forgotPassword.phone.placeholder": "手机号码",
+  "auth.forgotPassword.verifyCode.placeholder": "验证码",
+  "auth.forgotPassword.newPassword.placeholder": "新密码",
+  "auth.forgotPassword.confirmPassword.placeholder": "确认密码",
+  "auth.forgotPassword.getCode": "获取验证码",
+  "auth.forgotPassword.button": "重置密码",
+  "auth.forgotPassword.backToLogin": "返回登录",
+  "auth.forgotPassword.error.emptyPhone": "请输入手机号码",
+  "auth.forgotPassword.error.invalidPhone": "请输入有效的手机号码",
+  "auth.forgotPassword.error.emptyVerifyCode": "请输入验证码",
+  "auth.forgotPassword.error.emptyNewPassword": "请输入新密码",
+  "auth.forgotPassword.error.passwordLength": "密码应为6-20位字符",
+  "auth.forgotPassword.error.emptyConfirmPassword": "请确认您的密码",
+  "auth.forgotPassword.error.passwordMismatch": "两次密码不一致",
+  "auth.forgotPassword.success.codeSent": "验证码发送成功",
+  "auth.forgotPassword.success.passwordReset": "密码重置成功",
+  "auth.forgotPassword.error.sendCodeFailed": "发送验证码失败",
+  "auth.forgotPassword.error.resetFailed": "重置密码失败",
+  "auth.forgotPassword.passwordHint": "您的密码必须与之前使用的密码不同",
+  "auth.forgotPassword.hasAccount": "已有账户?",
+  "auth.forgotPassword.loginNow": "立即登录",
+  "common.loading": "加载中...",
+  "common.saving": "保存中...",
+  "common.success": "成功",
+  "common.error": "错误",
+  "common.confirm": "确认",
+  "common.cancel": "取消",
+  "common.submit": "提交",
+  "common.save": "保存",
+  "common.edit": "编辑",
+  "common.delete": "删除",
+  "common.add": "添加",
+  "common.search": "搜索",
+  "common.filter": "筛选",
+  "common.all": "全部",
+  "common.none": "无",
+  "common.empty": "暂无数据",
+  "common.retry": "重试",
+  "common.back": "返回",
+  "common.next": "下一步",
+  "common.previous": "上一步",
+  "common.close": "关闭",
+  "common.open": "打开",
+  "common.view": "查看",
+  "common.more": "更多",
+  "wallet.myWallet.title": "我的钱包",
+  "wallet.balance": "钱包余额",
+  "wallet.frozenBalance": "钱包冻结余额",
+  "wallet.recharge": "充值",
+  "wallet.discount": "最高优惠5%",
+  "wallet.withdrawNow": "立即提现",
+  "wallet.record": "钱包记录",
+  "wallet.filter.all": "全部",
+  "wallet.filter.recharge": "充值",
+  "wallet.filter.withdraw": "提现",
+  "wallet.filter.commission": "佣金",
+  "wallet.rechargeRecord.title": "充值记录",
+  "wallet.withdrawRecord.title": "提现记录",
+  "missionCenter.title": "任务中心",
+  "referEarn.title": "推荐赚钱",
+  "vipMembership.title": "VIP会员",
+  "notifications.title": "通知",
+  "notifications.tab1": "系统",
+  "notifications.tab2": "订单",
+  "notifications.tab3": "活动",
+  "notifications.tab4": "其他",
+  "notifications.orderPayment.title": "订单支付成功",
+  "notifications.orderPayment.content": "您购买的商品[{0}]已支付成功..",
+  "productDetail.title": "产品详情",
+  "webLink.title": "网页链接",
+  "missionCenter.signIn.title": "连续签到获得奖励",
+  "missionCenter.signIn.button": "签到",
+  "missionCenter.dailyMission.title": "每日任务",
+  "missionCenter.dailyMission.startNow": "立即开始",
+  "vipMembership.inviteProgress": "还需要邀请 {0} 位朋友,可升级到 V{1}",
+  "vipMembership.invitedFriends": "邀请好友",
+  "vipMembership.teamMembers": "团队成员",
+  "vipMembership.l7dEarnings": "近7日收益",
+  "vipMembership.benefitsTiers": "VIP权益/等级",
+  "vipMembership.table.vipLevel": "VIP\n等级",
+  "vipMembership.table.invitedNo": "邀请\n人数",
+  "vipMembership.table.directReferralReward": "直接推荐\n奖励",
+  "vipMembership.table.indirectReferralReward": "间接推荐\n奖励",
+  "vipMembership.table.joinedGroupsNo": "加入群组\n数量",
+  "referEarn.inviteFriends": "邀请朋友",
+  "referEarn.earnCash": "赚取现金",
+  "referEarn.shareNow": "立即分享",
+  "referEarn.howToShare": "- 如何分享赚钱 -",
+  "referEarn.step1": "分享邀请朋友",
+  "referEarn.step2": "朋友加入群组",
+  "referEarn.step3": "您获得 ৳50 奖励",
+  "referEarn.invitedFriends": "邀请的朋友",
+  "checkout.title": "结账",
+  "checkout.selected": "已选择",
+  "checkout.quantity": "数量",
+  "checkout.orderSummary": "订单摘要",
+  "checkout.subTotal": "小计",
+  "checkout.total": "总计",
+  "checkout.selectPaymentMethod": "选择支付方式",
+  "checkout.walletBalance": "余额",
+  "checkout.placeOrder": "下单",
+  "checkout.dialog.insufficientBalance": "您的钱包余额不足。\n请充值!",
+  "checkout.dialog.rechargeDiscount": "充值最高优惠5%",
+  "checkout.dialog.rechargeNow": "立即充值",
+  "checkout.dialog.paymentSuccess": "支付成功!\n您的订单已下单。",
+  "checkout.dialog.viewOrder": "查看订单",
+  "checkout.dialog.paymentFailed": "支付失败!\n请重试或联系客服。",
+  "checkout.dialog.retryPayment": "重试支付",
+  "checkout.dialog.networkError": "网络连接失败。\n请检查您的网络设置。",
+  "checkout.dialog.retry": "重试",
+  "checkout.dialog.gotIt": "知道了",
+  "checkout.toast.redirecting": "正在跳转到订单...",
+  "checkout.toast.retrying": "重试中...",
+  "bestSellers.title": "热销榜",
+  "bestSellers.successfullyGrouped": "近7日成功拼团超过 {0}",
+  "productDetail.price": "价格",
+  "productDetail.sold": "已售 {0}",
+  "productDetail.selected": "已选择",
+  "productDetail.groupRules": "拼团规则",
+  "productDetail.viewRules": "查看规则",
+  "productDetail.ongoingGroup": "进行中的拼团",
+  "productDetail.need": "还需",
+  "productDetail.more": "人",
+  "productDetail.joinGroup": "参团",
+  "productDetail.details": "详情",
+  "productDetail.home": "首页",
+  "productDetail.favorite": "收藏",
+  "productDetail.openGroup": "开团",
+  "productDetail.quantity": "数量",
+  "topChampions.title": "冠军榜",
+  "topChampions.update": "{0} 更新",
+  "topChampions.top": "TOP",
+  "topChampions.invitedFriends": "邀请好友",
+  "topChampions.l7dEarnings": "近7日收益",
+  "topChampions.teamMembers": "团队成员",
+  "topChampions.joinedGroups": "加入群组",
+  "wallet.recharge.title": "充值",
+  "wallet.recharge.highestDiscount": "充值最高优惠 {0}%",
+  "wallet.recharge.get": "获得",
+  "wallet.recharge.discount": "优惠",
+  "wallet.recharge.submit": "提交"
 }

+ 8 - 8
src/pages.json

@@ -156,7 +156,7 @@
       "type": "page",
       "layout": "default",
       "style": {
-        "navigationBarTitleText": "Mission Center",
+        "navigationBarTitleText": "%missionCenter.title%",
         "navigationBarBackgroundColor": "#fff"
       }
     },
@@ -183,7 +183,7 @@
       "type": "page",
       "layout": "default",
       "style": {
-        "navigationBarTitleText": "Notifications",
+        "navigationBarTitleText": "%notifications.title%",
         "navigationBarBackgroundColor": "#fff"
       }
     },
@@ -193,7 +193,7 @@
       "layout": "default",
       "needLogin": true,
       "style": {
-        "navigationBarTitleText": "Checkout",
+        "navigationBarTitleText": "%checkout.title%",
         "navigationBarBackgroundColor": "#fff"
       }
     },
@@ -243,7 +243,7 @@
       "layout": "default",
       "needLogin": true,
       "style": {
-        "navigationBarTitleText": "VIP Membership",
+        "navigationBarTitleText": "%vipMembership.title%",
         "navigationBarBackgroundColor": "#FFFFFF"
       }
     },
@@ -253,7 +253,7 @@
       "layout": "default",
       "needLogin": true,
       "style": {
-        "navigationBarTitleText": "My Wallet",
+        "navigationBarTitleText": "%wallet.myWallet.title%",
         "navigationBarBackgroundColor": "#fff"
       }
     },
@@ -262,7 +262,7 @@
       "type": "page",
       "layout": "default",
       "style": {
-        "navigationBarTitleText": "Recharge",
+        "navigationBarTitleText": "%wallet.recharge.title%",
         "navigationBarBackgroundColor": "#fff",
         "app-plus": {
           "titleNView": {
@@ -282,7 +282,7 @@
       "type": "page",
       "layout": "default",
       "style": {
-        "navigationBarTitleText": "Recharge Record",
+        "navigationBarTitleText": "%wallet.rechargeRecord.title%",
         "navigationBarBackgroundColor": "#fff"
       }
     },
@@ -300,7 +300,7 @@
       "type": "page",
       "layout": "default",
       "style": {
-        "navigationBarTitleText": "Withdraw Record",
+        "navigationBarTitleText": "%wallet.withdrawRecord.title%",
         "navigationBarBackgroundColor": "#fff"
       }
     },

+ 3 - 2
src/pages/bestSellers/bestSellers.vue

@@ -13,6 +13,7 @@
 import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
 import useZPaging from 'z-paging/components/z-paging/js/hooks/useZPaging.js'
 import { getRankList } from '@/api/product'
+import { t } from '@/locale'
 import { formatNumber, formatSales } from '@/utils'
 import { goBack, toPage } from '@/utils/page'
 
@@ -69,7 +70,7 @@ function getRankNumber(index: number) {
           </template>
           <template #title>
             <view class="text-white font-bold text-32rpx!">
-              Best Sellers
+              {{ t('bestSellers.title') }}
             </view>
           </template>
         </wd-navbar>
@@ -113,7 +114,7 @@ function getRankNumber(index: number) {
           </view>
           <view class="flex items-center rounded-8rpx from-white via-[rgba(255,210,212,0.58)] to-[rgba(255,0,16,0.2)] bg-gradient-to-l px-10rpx py-6rpx text-24rpx text-#FF0010">
             <image src="/static/icons/fire.png" class="mr-8rpx h-24rpx w-24rpx" />
-            <text>Successfully grouped over {{ formatSales(item.sales) }} L7D</text>
+            <text>{{ t('bestSellers.successfullyGrouped', [formatSales(item.sales)]) }}</text>
           </view>
         </view>
       </view>

+ 25 - 25
src/pages/forgotPassword/forgotPassword.vue

@@ -9,6 +9,7 @@
 
 <script lang="ts" setup>
 import { getCode, updateUserPassword } from '@/api/login'
+import { t } from '@/locale'
 import { goBack as goBackUtil, toPage } from '@/utils/page'
 import { toast } from '@/utils/toast'
 
@@ -39,14 +40,14 @@ const countdownTimer = ref<any>(null)
 async function getVerificationCode() {
   // 验证手机号
   if (!formData.value.phone.trim()) {
-    toast.error('Please enter phone number first')
+    toast.error(t('auth.forgotPassword.error.emptyPhone'))
     return
   }
 
   // 验证手机号格式
   const phoneRegex = /^1[3-9]\d{9}$/
   if (!phoneRegex.test(formData.value.phone)) {
-    toast.error('Please enter valid phone number')
+    toast.error(t('auth.forgotPassword.error.invalidPhone'))
     return
   }
 
@@ -58,7 +59,7 @@ async function getVerificationCode() {
   try {
     // 显示加载状态
     uni.showLoading({
-      title: 'Sending...',
+      title: t('common.loading'),
       mask: true,
     })
 
@@ -66,7 +67,7 @@ async function getVerificationCode() {
     await getCode(formData.value.phone)
 
     uni.hideLoading()
-    toast.success('Verification code sent successfully')
+    toast.success(t('auth.forgotPassword.success.codeSent'))
 
     // 开始倒计时
     countdown.value = 60
@@ -80,7 +81,7 @@ async function getVerificationCode() {
   }
   catch (error) {
     uni.hideLoading()
-    toast.error(error.message || 'Failed to send verification code')
+    toast.error(error.message || t('auth.forgotPassword.error.sendCodeFailed'))
   }
 }
 
@@ -88,14 +89,14 @@ async function getVerificationCode() {
 function handleStep1() {
   // 验证手机号
   if (!formData.value.phone.trim()) {
-    toast.error('Please enter phone number')
+    toast.error(t('auth.forgotPassword.error.emptyPhone'))
     return
   }
 
   // 验证手机号格式
   const phoneRegex = /^1[3-9]\d{9}$/
   if (!phoneRegex.test(formData.value.phone)) {
-    toast.error('Please enter valid phone number')
+    toast.error(t('auth.forgotPassword.error.invalidPhone'))
     return
   }
 
@@ -113,7 +114,7 @@ async function handleResetPassword() {
 
     // 显示加载状态
     uni.showLoading({
-      title: 'Resetting password...',
+      title: t('common.saving'),
       mask: true,
     })
 
@@ -127,7 +128,7 @@ async function handleResetPassword() {
     await updateUserPassword(resetData)
 
     uni.hideLoading()
-    toast.success('Password reset successfully')
+    toast.success(t('auth.forgotPassword.success.passwordReset'))
 
     // 跳转到登录页
     setTimeout(() => {
@@ -145,35 +146,35 @@ function validateResetForm() {
   return new Promise((resolve) => {
     // 验证验证码
     if (!formData.value.verifyCode.trim()) {
-      toast.error('Please enter verification code')
+      toast.error(t('auth.forgotPassword.error.emptyVerifyCode'))
       resolve(false)
       return
     }
 
     // 验证新密码
     if (!formData.value.newPwd.trim()) {
-      toast.error('Please enter new password')
+      toast.error(t('auth.forgotPassword.error.emptyNewPassword'))
       resolve(false)
       return
     }
 
     // 验证密码长度
     if (formData.value.newPwd.length < 6 || formData.value.newPwd.length > 20) {
-      toast.error('Password should be 6-20 characters')
+      toast.error(t('auth.forgotPassword.error.passwordLength'))
       resolve(false)
       return
     }
 
     // 验证确认密码
     if (!formData.value.confirmPwd.trim()) {
-      toast.error('Please confirm your password')
+      toast.error(t('auth.forgotPassword.error.emptyConfirmPassword'))
       resolve(false)
       return
     }
 
     // 验证两次密码是否一致
     if (formData.value.newPwd !== formData.value.confirmPwd) {
-      toast.error('Passwords do not match')
+      toast.error(t('auth.forgotPassword.error.passwordMismatch'))
       resolve(false)
       return
     }
@@ -230,7 +231,7 @@ onUnmounted(() => {
             <wd-input
               v-model="formData.phone"
               prop="phone"
-              placeholder="+88 Mobile number"
+              :placeholder="t('auth.forgotPassword.phone.placeholder')"
               no-border
               custom-class="bandhu-auth-input-field"
             />
@@ -243,7 +244,7 @@ onUnmounted(() => {
             custom-class="mb-200rpx w-full bandhu-auth-primary-btn"
             @click="handleStep1"
           >
-            Reset Password
+            {{ t('auth.forgotPassword.button') }}
           </wd-button>
         </wd-form>
       </view>
@@ -263,7 +264,7 @@ onUnmounted(() => {
               <wd-input
                 v-model="formData.verifyCode"
                 prop="verifyCode"
-                placeholder="Verification Code"
+                :placeholder="t('auth.forgotPassword.verifyCode.placeholder')"
                 no-border
                 custom-class="flex-1 bandhu-auth-input-field"
               />
@@ -274,14 +275,13 @@ onUnmounted(() => {
                 custom-class="bandhu-auth-secondary-btn"
                 @click="getVerificationCode"
               >
-                {{ countdown > 0 ? `${countdown}s` : 'Get Code' }}
+                {{ countdown > 0 ? `${countdown}s` : t('auth.forgotPassword.getCode') }}
               </wd-button>
             </view>
             <wd-input
               v-model="formData.newPwd"
               prop="newPwd"
-
-              placeholder="New Password 6-20 characters"
+              :placeholder="t('auth.forgotPassword.newPassword.placeholder')"
               no-border show-password
               custom-class="bandhu-auth-input-field"
             />
@@ -289,7 +289,7 @@ onUnmounted(() => {
               v-model="formData.confirmPwd"
               prop="confirmPwd"
               show-password
-              placeholder="Confirm password"
+              :placeholder="t('auth.forgotPassword.confirmPassword.placeholder')"
               no-border
               custom-class="bandhu-auth-input-field"
             />
@@ -297,7 +297,7 @@ onUnmounted(() => {
 
           <!-- 密码提示 -->
           <view class="mb-60rpx text-center text-24rpx text-#666">
-            Your password must be different from previous used password
+            {{ t('auth.forgotPassword.passwordHint') }}
           </view>
 
           <!-- 重置密码按钮 -->
@@ -307,7 +307,7 @@ onUnmounted(() => {
             custom-class="mb-200rpx w-full bandhu-auth-primary-btn"
             @click="handleResetPassword"
           >
-            Reset Password
+            {{ t('auth.forgotPassword.button') }}
           </wd-button>
         </wd-form>
       </view>
@@ -315,10 +315,10 @@ onUnmounted(() => {
       <!-- 登录提示 -->
       <view class="text-center">
         <text class="text-28rpx text-#666">
-          Already have account?
+          {{ t('auth.forgotPassword.hasAccount') }}
         </text>
         <text class="text-28rpx text-[var(--wot-color-theme)]" @click="toPage('/pages/login/login')">
-          Login Now
+          {{ t('auth.forgotPassword.loginNow') }}
         </text>
       </view>
     </view>

+ 10 - 10
src/pages/login/login.vue

@@ -8,6 +8,7 @@
 </route>
 
 <script lang="ts" setup>
+import { t } from '@/locale'
 import { useUserStore } from '@/store/user'
 import { goBack, toPage } from '@/utils/page'
 import { toast } from '@/utils/toast'
@@ -34,21 +35,21 @@ function validateForm() {
   return new Promise((resolve) => {
     // 验证用户名
     if (!formData.value.username.trim()) {
-      toast.error('Please enter username or phone number')
+      toast.error(t('auth.login.error.emptyUsername'))
       resolve(false)
       return
     }
 
     // 验证密码
     if (!formData.value.password.trim()) {
-      toast.error('Please enter password')
+      toast.error(t('auth.login.error.emptyPassword'))
       resolve(false)
       return
     }
 
     // 验证密码长度
     if (formData.value.password.length < 6 || formData.value.password.length > 20) {
-      toast.error('Password should be 6-20 characters')
+      toast.error(t('auth.login.error.passwordLength'))
       resolve(false)
       return
     }
@@ -115,15 +116,14 @@ async function handleLogin() {
           <wd-input
             v-model="formData.username"
             prop="username"
-            placeholder="Mobile number / Username"
+            :placeholder="t('auth.login.username.placeholder')"
             no-border
             custom-class="bandhu-auth-input-field"
           />
           <wd-input
             v-model="formData.password"
             prop="password"
-
-            placeholder="Password 6-20 characters"
+            :placeholder="t('auth.login.password.placeholder')"
             no-border show-password
             custom-class="bandhu-auth-input-field"
           />
@@ -136,14 +136,14 @@ async function handleLogin() {
           custom-class="mb-60rpx w-full bandhu-auth-primary-btn"
           @click="handleLogin"
         >
-          Login
+          {{ t('auth.login.button') }}
         </wd-button>
       </wd-form>
 
       <!-- 注册提示 -->
       <view class="mb-200rpx text-center">
         <text class="text-28rpx text-#5C5C5C">
-          Do Not Have An Account Yet?
+          {{ t('auth.login.noAccount') }}
         </text>
         <view class="mt-52rpx">
           <wd-button
@@ -152,7 +152,7 @@ async function handleLogin() {
             custom-style="width: 200rpx; height: 72rpx; border-radius: 36rpx; font-size: 28rpx;"
             @click="toPage('/pages/register/register')"
           >
-            Register
+            {{ t('auth.login.register') }}
           </wd-button>
         </view>
       </view>
@@ -160,7 +160,7 @@ async function handleLogin() {
       <!-- 忘记密码 -->
       <view class="text-center">
         <text class="text-28rpx text-#5C5C5C" @click="toPage('/pages/forgotPassword/forgotPassword')">
-          Forgot Password?
+          {{ t('auth.login.forgotPassword') }}
         </text>
       </view>
     </view>

+ 6 - 7
src/pages/missionCenter/missionCenter.vue

@@ -2,7 +2,7 @@
 {
   layout: 'default',
   style: {
-    navigationBarTitleText: 'Mission Center',
+    navigationBarTitleText: '%missionCenter.title%',
     navigationBarBackgroundColor: '#fff',
   },
 }
@@ -11,6 +11,7 @@
 <script lang="ts" setup>
 import { ref } from 'vue'
 import { clockIn, todayDetail } from '@/api/mine'
+import { t } from '@/locale'
 import { toPage } from '@/utils/page'
 
 defineOptions({
@@ -40,8 +41,6 @@ const dailyMission = [
     url: '/pages/index/index',
   },
 ]
-// 当前签到天数
-const currentDay = ref(3)
 // 今日是否已签到
 const hasSignedToday = ref(true)
 
@@ -71,7 +70,7 @@ onLoad(() => {
     <view class="mb-34rpx rounded-16rpx bg-white p-24rpx">
       <view class="mb-40rpx flex items-center before:h-45rpx before:w-8rpx before:rounded-4rpx before:bg-#FF3778 before:content-empty">
         <text class="ml-10rpx text-32rpx">
-          Continuous sign in to receive rewards
+          {{ t('missionCenter.signIn.title') }}
         </text>
       </view>
       <!-- 七天签到日历 -->
@@ -100,14 +99,14 @@ onLoad(() => {
           :disabled="hasSignedToday"
           @click="signIn"
         >
-          Check-in
+          {{ t('missionCenter.signIn.button') }}
         </wd-button>
       </view>
     </view>
     <view class="rounded-16rpx bg-white p-24rpx">
       <view class="mb-20rpx flex items-center before:h-45rpx before:w-8rpx before:rounded-4rpx before:bg-#FF3778 before:content-empty">
         <text class="ml-10rpx text-32rpx">
-          Daily Mission
+          {{ t('missionCenter.dailyMission.title') }}
         </text>
       </view>
       <view
@@ -128,7 +127,7 @@ onLoad(() => {
           </view>
         </view>
         <wd-button size="small" @click="toPage(item.url)">
-          Start Now
+          {{ t('missionCenter.dailyMission.startNow') }}
         </wd-button>
       </view>
     </view>

+ 77 - 4
src/pages/notifications/notifications.vue

@@ -2,7 +2,7 @@
 {
   layout: 'default',
   style: {
-    navigationBarTitleText: 'Notifications',
+    navigationBarTitleText: '%notifications.title%',
     navigationBarBackgroundColor: '#fff',
   },
 }
@@ -13,6 +13,7 @@
 // eslint-disable-next-line unused-imports/no-unused-imports
 import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
 import useZPaging from 'z-paging/components/z-paging/js/hooks/useZPaging.js'
+import { t } from '@/locale'
 
 defineOptions({
   name: 'Notifications', // 通知
@@ -42,7 +43,79 @@ function queryList(pageNo, pageSize) {
 
 <template>
   <wd-tabs v-model="tab" swipeable sticky custom-class="bg-transparent!">
-    <wd-tab v-for="item in 4" :key="item" :title="`标签${item}`">
+    <wd-tab :title="t('notifications.tab1')">
+      <z-paging ref="paging" use-page-scroll refresher-only @query="queryList">
+        <view class="py-20rpx">
+          <view class="bg-white px-22rpx py-18rpx">
+            <view class="mb-8rpx flex items-center justify-between">
+              <view class="flex items-center">
+                <wd-icon name="view-module" size="36rpx" />
+                <text class="ml-8rpx text-24rpx font-bold">
+                  {{ t('notifications.orderPayment.title') }}
+                </text>
+              </view>
+              <text class="text-22rpx text-#3A444C">
+                12:30
+              </text>
+            </view>
+            <view class="flex items-center text-22rpx text-#3A444C">
+              <view class="truncate">
+                {{ t('notifications.orderPayment.content', ['20250505123030120']) }}
+              </view>
+            </view>
+          </view>
+        </view>
+      </z-paging>
+    </wd-tab>
+    <wd-tab :title="t('notifications.tab2')">
+      <z-paging ref="paging" refresher-only use-page-scroll @query="queryList">
+        <view class="py-20rpx">
+          <view class="bg-white px-22rpx py-18rpx">
+            <view class="mb-8rpx flex items-center justify-between">
+              <view class="flex items-center">
+                <wd-icon name="view-module" size="36rpx" />
+                <text class="ml-8rpx text-24rpx font-bold">
+                  {{ t('notifications.orderPayment.title') }}
+                </text>
+              </view>
+              <text class="text-22rpx text-#3A444C">
+                12:30
+              </text>
+            </view>
+            <view class="flex items-center text-22rpx text-#3A444C">
+              <view class="truncate">
+                {{ t('notifications.orderPayment.content', ['20250505123030120']) }}
+              </view>
+            </view>
+          </view>
+        </view>
+      </z-paging>
+    </wd-tab>
+    <wd-tab :title="t('notifications.tab3')">
+      <z-paging ref="paging" refresher-only use-page-scroll @query="queryList">
+        <view class="py-20rpx">
+          <view class="bg-white px-22rpx py-18rpx">
+            <view class="mb-8rpx flex items-center justify-between">
+              <view class="flex items-center">
+                <wd-icon name="view-module" size="36rpx" />
+                <text class="ml-8rpx text-24rpx font-bold">
+                  {{ t('notifications.orderPayment.title') }}
+                </text>
+              </view>
+              <text class="text-22rpx text-#3A444C">
+                12:30
+              </text>
+            </view>
+            <view class="flex items-center text-22rpx text-#3A444C">
+              <view class="truncate">
+                {{ t('notifications.orderPayment.content', ['20250505123030120']) }}
+              </view>
+            </view>
+          </view>
+        </view>
+      </z-paging>
+    </wd-tab>
+    <wd-tab :title="t('notifications.tab4')">
       <z-paging ref="paging" refresher-only use-page-scroll @query="queryList">
         <view class="py-20rpx">
           <view class="bg-white px-22rpx py-18rpx">
@@ -50,7 +123,7 @@ function queryList(pageNo, pageSize) {
               <view class="flex items-center">
                 <wd-icon name="view-module" size="36rpx" />
                 <text class="ml-8rpx text-24rpx font-bold">
-                  Order Payment Successful
+                  {{ t('notifications.orderPayment.title') }}
                 </text>
               </view>
               <text class="text-22rpx text-#3A444C">
@@ -59,7 +132,7 @@ function queryList(pageNo, pageSize) {
             </view>
             <view class="flex items-center text-22rpx text-#3A444C">
               <view class="truncate">
-                The product you purchased [20250505123030120] has been paid..
+                {{ t('notifications.orderPayment.content', ['20250505123030120']) }}
               </view>
             </view>
           </view>

+ 21 - 20
src/pages/productDetail/checkOut.vue

@@ -3,7 +3,7 @@
   layout: 'default',
   needLogin: true,
   style: {
-    navigationBarTitleText: 'Checkout',
+    navigationBarTitleText: '%checkout.title%',
     navigationBarBackgroundColor: '#fff',
   },
 }
@@ -14,6 +14,7 @@ import { computedPrice, createOrder, loadPre, payOrder } from '@/api/order'
 import { getWalletAccountInfo } from '@/api/wallet'
 import DialogBox from '@/components/DialogBox/DialogBox.vue'
 import { DialogUtils } from '@/components/DialogBox/utils'
+import { t } from '@/locale'
 import { useUserStore } from '@/store'
 import { formatNumber } from '@/utils'
 import { getPageParams, toPage } from '@/utils/page'
@@ -80,7 +81,7 @@ const dialogConfig = ref({
   iconSize: '120rpx',
   message: '',
   tip: '',
-  btnText: 'Got it',
+  btnText: t('checkout.dialog.gotIt'),
   showButton: true,
   showTip: false,
   closeOnClickOverlay: true,
@@ -97,11 +98,11 @@ function selectPayment(methodId: string) {
 // 显示余额不足对话框
 function showInsufficientBalanceDialog() {
   Object.assign(dialogConfig.value, DialogUtils.warning(
-    'Your wallet balance is insufficient.\nPlease recharge!',
+    t('checkout.dialog.insufficientBalance'),
     {
-      tip: 'Recharge Highest Discount 5%',
+      tip: t('checkout.dialog.rechargeDiscount'),
       showTip: true,
-      btnText: 'Recharge Now',
+      btnText: t('checkout.dialog.rechargeNow'),
     },
   ))
 }
@@ -109,9 +110,9 @@ function showInsufficientBalanceDialog() {
 // 显示支付成功对话框
 function showPaymentSuccessDialog() {
   Object.assign(dialogConfig.value, DialogUtils.success(
-    'Payment successful!\nYour order has been placed.',
+    t('checkout.dialog.paymentSuccess'),
     {
-      btnText: 'View Order',
+      btnText: t('checkout.dialog.viewOrder'),
       showButton: true,
     },
   ))
@@ -120,9 +121,9 @@ function showPaymentSuccessDialog() {
 // 显示支付失败对话框
 function showPaymentFailedDialog() {
   Object.assign(dialogConfig.value, DialogUtils.error(
-    'Payment failed!\nPlease try again or contact support.',
+    t('checkout.dialog.paymentFailed'),
     {
-      btnText: 'Retry Payment',
+      btnText: t('checkout.dialog.retryPayment'),
     },
   ))
 }
@@ -130,9 +131,9 @@ function showPaymentFailedDialog() {
 // 显示网络错误对话框
 function showNetworkErrorDialog() {
   Object.assign(dialogConfig.value, DialogUtils.error(
-    'Network connection failed.\nPlease check your network settings.',
+    t('checkout.dialog.networkError'),
     {
-      btnText: 'Retry',
+      btnText: t('checkout.dialog.retry'),
       iconSize: '100rpx',
     },
   ))
@@ -175,11 +176,11 @@ function handleDialogConfirm() {
   }
   else if (icon === 'success') {
     // 支付成功,跳转到订单页面
-    uni.showToast({ title: 'Redirecting to orders...', icon: 'none' })
+    uni.showToast({ title: t('checkout.toast.redirecting'), icon: 'none' })
   }
   else if (icon === 'error') {
     // 支付失败或网络错误,重新尝试
-    uni.showToast({ title: 'Retrying...', icon: 'loading' })
+    uni.showToast({ title: t('checkout.toast.retrying'), icon: 'loading' })
   }
 }
 
@@ -202,21 +203,21 @@ function handleDialogClose() {
             {{ orderDetail.productName }}
           </view>
           <view class="py-4rpx text-24rpx text-#3A444C">
-            Selected: {{ orderDetail.sku }}
+            {{ t('checkout.selected') }}: {{ orderDetail.sku }}
           </view>
           <view class="flex items-center justify-between text-24rpx">
             <view class="text-#FF0010">
               ৳ {{ formatNumber(orderDetail.price) }}
             </view>
             <view class="text-#3A444C">
-              Quantity:{{ orderDetail.payNum }}
+              {{ t('checkout.quantity') }}:{{ orderDetail.payNum }}
             </view>
           </view>
         </view>
       </view>
       <view class="mb-20rpx bg-white p-24rpx">
         <view class="mb-12rpx text-28rpx">
-          Oder Summary
+          {{ t('checkout.orderSummary') }}
         </view>
         <view class="flex flex-col gap-16rpx text-#3A444C">
           <template v-for="(item, key) in orderSummary" :key="key">
@@ -229,7 +230,7 @@ function handleDialogClose() {
       </view>
       <view class="bg-white p-24rpx">
         <view class="mb-12rpx text-28rpx">
-          Select Payment Method
+          {{ t('checkout.selectPaymentMethod') }}
         </view>
         <view class="flex flex-col gap-16rpx text-#3A444C">
           <view class="flex items-center justify-between text-24rpx">
@@ -241,7 +242,7 @@ function handleDialogClose() {
               <view class="text-24rpx">
                 <text>BandhuBuy Wallet(</text>
                 <text class="text-[var(--wot-color-theme)]">
-                  Balance: ৳ {{ formatNumber(walletBalance) }}
+                  {{ t('checkout.walletBalance') }}: ৳ {{ formatNumber(walletBalance) }}
                 </text>
                 <text>)</text>
               </view>
@@ -259,13 +260,13 @@ function handleDialogClose() {
     <template #bottom>
       <view class="flex items-center justify-end bg-white/60 px-28rpx py-30rpx backdrop-blur-20">
         <view class="mr-16rpx text-24rpx">
-          <text>Total:</text>
+          <text>{{ t('checkout.total') }}:</text>
           <text class="text-[var(--wot-color-theme)]">
             ৳ {{ formatNumber(orderSummary.Total) }}
           </text>
         </view>
         <wd-button @click="handlePlaceOrder">
-          Place Order
+          {{ t('checkout.placeOrder') }}
         </wd-button>
       </view>
     </template>

+ 17 - 16
src/pages/productDetail/productDetail.vue

@@ -14,6 +14,7 @@ import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
 import useZPaging from 'z-paging/components/z-paging/js/hooks/useZPaging.js'
 import { preOrder as _preOrder } from '@/api/order'
 import { getDetail, pinkList } from '@/api/product'
+import { t } from '@/locale'
 import { formatNumber } from '@/utils/index'
 import { getPageParams, goBack, toPage } from '@/utils/page'
 import CustomTooltip from './components/CustomTooltip.vue'
@@ -313,7 +314,7 @@ onShow(() => {
         <view>
           <view class="mb-12rpx flex items-baseline">
             <text class="text-28rpx">
-              Price
+              {{ t('productDetail.price') }}
             </text>
             <view class="ml-8rpx rounded-t-18rpx rounded-br-18rpx bg-#202221 px-12rpx text-24rpx">
               20GB
@@ -331,7 +332,7 @@ onShow(() => {
           </view>
         </view>
         <text class="text-28rpx">
-          {{ detail.sales }} sold
+          {{ t('productDetail.sold', [detail.sales]) }}
         </text>
       </view>
       <view class="bg-white px-24rpx pb-24rpx pt-20rpx text-32rpx">
@@ -341,7 +342,7 @@ onShow(() => {
         <view class="flex items-center justify-between" @click="openSku('open')">
           <view>
             <text class="mr-20rpx">
-              Selected
+              {{ t('productDetail.selected') }}
             </text>
             <text class="text-#757575">
               {{ selectedSpecsText }}
@@ -357,12 +358,12 @@ onShow(() => {
           class="flex items-center before:h-45rpx before:w-8rpx before:rounded-4rpx before:bg-#FF3778 before:content-empty"
         >
           <text class="ml-10rpx text-32rpx">
-            Group Rules
+            {{ t('productDetail.groupRules') }}
           </text>
         </view>
         <view class="flex items-center">
           <text class="mr-8rpx text-24rpx text-#3A444C">
-            View Rules
+            {{ t('productDetail.viewRules') }}
           </text>
           <wd-icon name="arrow-right" color="#7D7D7D" size="24rpx" />
         </view>
@@ -374,7 +375,7 @@ onShow(() => {
         class="mb-20rpx flex items-center before:h-45rpx before:w-8rpx before:rounded-4rpx before:bg-#FF3778 before:content-empty"
       >
         <text class="ml-10rpx text-32rpx">
-          Ongoing Group
+          {{ t('productDetail.ongoingGroup') }}
         </text>
       </view>
       <view class="flex flex-col gap-24rpx">
@@ -395,16 +396,16 @@ onShow(() => {
             </view>
             <view>
               <view class="text-28rpx">
-                Need
+                {{ t('productDetail.need') }}
                 <text class="text-[var(--wot-color-theme)]">
                   {{ item.remainNum }}
                 </text>
-                More
+                {{ t('productDetail.more') }}
               </view>
             </view>
           </view>
           <wd-button size="small" @click="openSku('join', item.id, item.orderId)">
-            Join Group
+            {{ t('productDetail.joinGroup') }}
           </wd-button>
         </view>
       </view>
@@ -414,7 +415,7 @@ onShow(() => {
         class="mb-20rpx flex items-center before:h-45rpx before:w-8rpx before:rounded-4rpx before:bg-#FF3778 before:content-empty"
       >
         <text class="ml-10rpx text-32rpx">
-          Details
+          {{ t('productDetail.details') }}
         </text>
       </view>
       <view v-for="i in detail.flatPattern.split(',')" :key="i">
@@ -431,20 +432,20 @@ onShow(() => {
           <view class="flex flex-col items-center justify-center">
             <wd-icon color="#BDBDBD" name="home" size="40rpx" />
             <text class="text-18rpx text-#757575">
-              Home
+              {{ t('productDetail.home') }}
             </text>
           </view>
           <view class="flex flex-col items-center justify-center">
             <wd-icon color="#BDBDBD" name="heart-filled" size="40rpx" />
             <text class="text-18rpx text-#757575">
-              Favorite
+              {{ t('productDetail.favorite') }}
             </text>
           </view>
         </view>
         <view class="flex flex-1 items-center justify-end text-32rpx">
           <view class="relative">
             <view class="rounded-l-full bg-#2F2D31 px-34rpx py-18rpx text-white" @click="openSku('open')">
-              Open Group
+              {{ t('productDetail.openGroup') }}
             </view>
             <CustomTooltip
               v-model:visible="showTip"
@@ -453,7 +454,7 @@ onShow(() => {
             />
           </view>
           <view class="rounded-r-full bg-[var(--wot-color-theme)] px-34rpx py-18rpx text-white" @click="openSku('join')">
-            Join Group
+            {{ t('productDetail.joinGroup') }}
           </view>
         </view>
       </view>
@@ -513,12 +514,12 @@ onShow(() => {
         </view>
       </view>
       <view class="mb-100rpx flex items-center justify-between text-32rpx">
-        <view>Quantity</view>
+        <view>{{ t('productDetail.quantity') }}</view>
         <wd-input-number v-model="formData.productNum" />
       </view>
       <view class="py-24rpx">
         <wd-button block :style="{ backgroundColor: groupType === 'open' ? '#2F2D31' : 'var(--wot-color-theme)' }" @click="preOrder">
-          {{ groupType === 'open' ? 'Open Group' : 'Join Group' }}
+          {{ groupType === 'open' ? t('productDetail.openGroup') : t('productDetail.joinGroup') }}
         </wd-button>
       </view>
     </view>

+ 10 - 9
src/pages/referEarn/referEarn.vue

@@ -13,6 +13,7 @@
 import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
 import useZPaging from 'z-paging/components/z-paging/js/hooks/useZPaging.js'
 import { myUsers } from '@/api/mine'
+import { t } from '@/locale'
 import { goBack } from '@/utils/page'
 
 defineOptions({
@@ -48,7 +49,7 @@ async function queryList(pageNo: number, pageSize: number) {
     </template>
     <template #title>
       <view class="text-white font-bold text-32rpx!">
-        Refer Earn
+        {{ t('referEarn.title') }}
       </view>
     </template>
   </wd-navbar>
@@ -58,22 +59,22 @@ async function queryList(pageNo: number, pageSize: number) {
       <image src="/static/images/refer-earn-bg.png" class="w-full" mode="widthFix" />
       <view class="absolute bottom-166rpx left-1/2 w-326rpx transform text-center -translate-x-1/2">
         <view class="px-14rpx text-36rpx text-white">
-          <view>INVTE FRIDENS</view>
+          <view>{{ t('referEarn.inviteFriends') }}</view>
           <view class="mb-26rpx">
-            EARN CASH
+            {{ t('referEarn.earnCash') }}
             <text class="text-[var(--wot-color-theme)]">
               ৳50
             </text>
           </view>
         </view>
         <view class="rounded-full bg-#F9CD96 py-14rpx text-34rpx text-[var(--wot-color-theme)] font-bold shadow-[0_2rpx_8rpx_0_rgba(249,205,150,0.5)]">
-          SHARE NOW
+          {{ t('referEarn.shareNow') }}
         </view>
       </view>
     </view>
     <view class="px-24rpx">
       <view class="mb-28rpx text-center text-32rpx text-[var(--wot-color-theme)]">
-        - How to Share and Earn Money -
+        {{ t('referEarn.howToShare') }}
       </view>
       <view class="mb-40rpx flex items-center justify-between text-center">
         <view class="shadow='0rpx 2rpx 8rpx 0rpx rgba(249,205,150,0.5)' flex flex-1 flex-col items-center rounded-16rpx bg-#F9CD96/60 px-12rpx py-30rpx">
@@ -81,7 +82,7 @@ async function queryList(pageNo: number, pageSize: number) {
             1
           </view>
           <view class="text-24rpx text-#8F3301 font-bold">
-            Share Invite Friends
+            {{ t('referEarn.step1') }}
           </view>
         </view>
         <wd-icon name="caret-right-small" size="32rpx" color="#D8D8D8" class="mx-16rpx" />
@@ -90,7 +91,7 @@ async function queryList(pageNo: number, pageSize: number) {
             2
           </view>
           <view class="text-24rpx text-#8F3301 font-bold">
-            Your Friend Join Group
+            {{ t('referEarn.step2') }}
           </view>
         </view>
         <wd-icon name="caret-right-small" size="32rpx" color="#D8D8D8" class="mx-16rpx" />
@@ -99,13 +100,13 @@ async function queryList(pageNo: number, pageSize: number) {
             3
           </view>
           <view class="text-24rpx text-#8F3301 font-bold">
-            You Get ৳50 Reward
+            {{ t('referEarn.step3') }}
           </view>
         </view>
       </view>
       <view>
         <view class="mb-18rpx text-32rpx">
-          Invited Friends
+          {{ t('referEarn.invitedFriends') }}
         </view>
         <view v-if="dataList.length" class="rounded-16rpx bg-white px-24rpx py-8rpx">
           <view

+ 23 - 22
src/pages/register/register.vue

@@ -9,6 +9,7 @@
 
 <script lang="ts" setup>
 import { getCode, register } from '@/api/login'
+import { t } from '@/locale'
 import { goBack, toPage } from '@/utils/page'
 import { toast } from '@/utils/toast'
 
@@ -37,14 +38,14 @@ const countdownTimer = ref<any>(null)
 async function getVerificationCode() {
   // 验证手机号
   if (!formData.value.phone.trim()) {
-    toast.error('Please enter phone number first')
+    toast.error(t('auth.register.error.emptyPhone'))
     return
   }
 
   // 验证手机号格式
   const phoneRegex = /^1[3-9]\d{9}$/
   if (!phoneRegex.test(formData.value.phone)) {
-    toast.error('Please enter valid phone number')
+    toast.error(t('auth.register.error.emptyPhone'))
     return
   }
 
@@ -56,7 +57,7 @@ async function getVerificationCode() {
   try {
     // 显示加载状态
     uni.showLoading({
-      title: 'Sending...',
+      title: t('common.loading'),
       mask: true,
     })
 
@@ -64,7 +65,7 @@ async function getVerificationCode() {
     await getCode(formData.value.phone)
 
     uni.hideLoading()
-    toast.success('Verification code sent successfully')
+    toast.success(t('auth.register.success.codeSent'))
 
     // 开始倒计时
     countdown.value = 60
@@ -92,7 +93,7 @@ async function handleRegister() {
 
     // 显示加载状态
     uni.showLoading({
-      title: 'Registering...',
+      title: t('common.saving'),
       mask: true,
     })
 
@@ -109,14 +110,14 @@ async function handleRegister() {
 
     uni.hideLoading()
     // 注册成功
-    toast.success('Registration successful!')
+    toast.success(t('auth.register.success.registered'))
     setTimeout(() => {
       toPage('/pages/login/login', {}, true)
     }, 1500)
   }
   catch (error) {
     uni.hideLoading()
-    toast.error(error.message || 'Registration failed')
+    toast.error(error.message || t('auth.register.error.registrationFailed'))
   }
 }
 
@@ -125,13 +126,13 @@ function validateForm() {
   return new Promise((resolve) => {
     // 验证必填字段
     if (!formData.value.name.trim()) {
-      toast.error('Please enter name')
+      toast.error(t('auth.register.error.emptyUsername'))
       resolve(false)
       return
     }
 
     if (!formData.value.phone.trim()) {
-      toast.error('Please enter phone number')
+      toast.error(t('auth.register.error.emptyPhone'))
       resolve(false)
       return
     }
@@ -139,26 +140,26 @@ function validateForm() {
     // 验证手机号格式
     const phoneRegex = /^1[3-9]\d{9}$/
     if (!phoneRegex.test(formData.value.phone)) {
-      toast.error('Please enter valid phone number')
+      toast.error(t('auth.register.error.emptyPhone'))
       resolve(false)
       return
     }
 
     if (!formData.value.verifyCode.trim()) {
-      toast.error('Please enter verification code')
+      toast.error(t('auth.register.error.emptyVerifyCode'))
       resolve(false)
       return
     }
 
     if (!formData.value.pwd.trim()) {
-      toast.error('Please enter password')
+      toast.error(t('auth.register.error.emptyPassword'))
       resolve(false)
       return
     }
 
     // 验证密码长度
     if (formData.value.pwd.length < 6 || formData.value.pwd.length > 20) {
-      toast.error('Password should be 6-20 characters')
+      toast.error(t('auth.register.error.passwordLength'))
       resolve(false)
       return
     }
@@ -204,14 +205,14 @@ onUnmounted(() => {
           <wd-input
             v-model="formData.name"
             prop="name"
-            placeholder="Username"
+            :placeholder="t('auth.register.username.placeholder')"
             no-border
             custom-class="bandhu-auth-input-field"
           />
           <wd-input
             v-model="formData.phone"
             prop="phone"
-            placeholder="+88 Mobile number"
+            :placeholder="t('auth.register.phone.placeholder')"
             no-border
             custom-class="bandhu-auth-input-field"
           />
@@ -219,7 +220,7 @@ onUnmounted(() => {
             <wd-input
               v-model="formData.verifyCode"
               prop="verifyCode"
-              placeholder="Verification Code"
+              :placeholder="t('auth.register.verifyCode.placeholder')"
               no-border
               custom-class="flex-1 bandhu-auth-input-field"
             />
@@ -230,20 +231,20 @@ onUnmounted(() => {
               custom-class="bandhu-auth-secondary-btn"
               @click="getVerificationCode"
             >
-              {{ countdown > 0 ? `${countdown}s` : 'Get Code' }}
+              {{ countdown > 0 ? `${countdown}s` : t('auth.register.getCode') }}
             </wd-button>
           </view>
           <wd-input
             v-model="formData.pwd"
             prop="pwd"
-            placeholder="Password 6-20 characters"
+            :placeholder="t('auth.register.password.placeholder')"
             no-border
             show-password
             custom-class="bandhu-auth-input-field"
           />
           <wd-input
             v-model="formData.code"
-            placeholder="Referrer Code"
+            :placeholder="t('auth.register.referrerCode.placeholder')"
             no-border
             custom-class="bandhu-auth-input-field"
           />
@@ -256,17 +257,17 @@ onUnmounted(() => {
           custom-class="mb-200rpx w-full bandhu-auth-primary-btn"
           @click="handleRegister"
         >
-          Register
+          {{ t('auth.register.button') }}
         </wd-button>
       </wd-form>
 
       <!-- 登录提示 -->
       <view class="text-center">
         <text class="text-28rpx text-#666">
-          Already have account?
+          {{ t('auth.register.hasAccount') }}
         </text>
         <text class="ml-10rpx text-28rpx text-[var(--wot-color-theme)]" @click="toPage('/pages/login/login')">
-          Login Now
+          {{ t('auth.register.loginNow') }}
         </text>
       </view>
     </view>

+ 7 - 6
src/pages/topChampions/topChampions.vue

@@ -13,6 +13,7 @@
 import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
 import useZPaging from 'z-paging/components/z-paging/js/hooks/useZPaging.js'
 import { redEnvelopeTop } from '@/api/wallet'
+import { t } from '@/locale'
 import { formatNumber } from '@/utils'
 import { goBack } from '@/utils/page'
 
@@ -73,7 +74,7 @@ async function queryList(pageNo: number, pageSize: number) {
           </template>
           <template #title>
             <view class="text-white font-bold text-32rpx!">
-              Top Champions
+              {{ t('topChampions.title') }}
             </view>
           </template>
         </wd-navbar>
@@ -92,7 +93,7 @@ async function queryList(pageNo: number, pageSize: number) {
         >
           <view class="flex flex-col items-center leading-none">
             <text class="text-16rpx">
-              TOP
+              {{ t('topChampions.top') }}
             </text>
             <text class="text-18rpx">
               {{ getRankNumber(index) }}
@@ -112,7 +113,7 @@ async function queryList(pageNo: number, pageSize: number) {
         <view class="grid grid-cols-2 flex-1 gap-24rpx">
           <view class="flex flex-col items-center">
             <view class="text-22rpx text-#5B5B5B">
-              Invited Friends
+              {{ t('topChampions.invitedFriends') }}
             </view>
             <view class="text-26rpx font-bold">
               {{ formatNumber(item.inviteNum, 0) }}
@@ -120,7 +121,7 @@ async function queryList(pageNo: number, pageSize: number) {
           </view>
           <view class="flex flex-col items-center">
             <view class="text-22rpx text-#5B5B5B">
-              L7D Earnings
+              {{ t('topChampions.l7dEarnings') }}
             </view>
             <view class="text-26rpx text-[var(--wot-color-theme)] font-bold">
               {{ formatNumber(item.L7DEarnings) }}
@@ -128,7 +129,7 @@ async function queryList(pageNo: number, pageSize: number) {
           </view>
           <view class="flex flex-col items-center">
             <view class="text-22rpx text-#5B5B5B">
-              Team Members
+              {{ t('topChampions.teamMembers') }}
             </view>
             <view class="text-26rpx font-bold">
               {{ formatNumber(item.teamNum, 0) }}
@@ -136,7 +137,7 @@ async function queryList(pageNo: number, pageSize: number) {
           </view>
           <view class="flex flex-col items-center">
             <view class="text-22rpx text-#5B5B5B">
-              Joined Groups
+              {{ t('topChampions.joinedGroups') }}
             </view>
             <view class="text-26rpx font-bold">
               {{ formatNumber(item.groupNum, 0) }}

+ 12 - 18
src/pages/vipMembership/vipMembership.vue

@@ -3,7 +3,7 @@
   layout: 'default',
   needLogin: true,
   style: {
-    navigationBarTitleText: 'VIP Membership',
+    navigationBarTitleText: '%vipMembership.title%',
     navigationBarBackgroundColor: '#FFFFFF',
   },
 }
@@ -11,6 +11,7 @@
 
 <script lang="ts" setup>
 import { memberConfigs } from '@/api/mine'
+import { t } from '@/locale'
 import { formatNumber } from '@/utils'
 
 defineOptions({
@@ -42,11 +43,11 @@ interface TableColumn {
 
 // 表格列配置
 const tableColumns = ref<TableColumn[]>([
-  { prop: 'level', label: 'VIP\nLevel', fixed: true, align: 'center', width: '110rpx' },
-  { prop: 'invitedNo', label: 'Invited\nNo', align: 'center', width: '150rpx' },
-  { prop: 'directReferralReward', label: 'Direct Referral\nReward', align: 'center', width: '240rpx' },
-  { prop: 'indirectReferralReward', label: 'Indirect Referral\nReward', align: 'center', width: '240rpx' },
-  { prop: 'joinedGroupsNo', label: 'Joined Groups\nNo', align: 'center', width: '220rpx' },
+  { prop: 'level', label: t('vipMembership.table.vipLevel'), fixed: true, align: 'center', width: '110rpx' },
+  { prop: 'invitedNo', label: t('vipMembership.table.invitedNo'), align: 'center', width: '150rpx' },
+  { prop: 'directReferralReward', label: t('vipMembership.table.directReferralReward'), align: 'center', width: '240rpx' },
+  { prop: 'indirectReferralReward', label: t('vipMembership.table.indirectReferralReward'), align: 'center', width: '240rpx' },
+  { prop: 'joinedGroupsNo', label: t('vipMembership.table.joinedGroupsNo'), align: 'center', width: '220rpx' },
 ])
 
 const dataList = ref<TableData[]>([])
@@ -74,14 +75,7 @@ onLoad(() => {
         </view>
         <wd-progress :duration="0" custom-class="w-85%!" color="#E7BEA6" :percentage="(userInfo.invitedNo / userInfo.nextInvitedNo) * 100" hide-text />
         <view class="text-22rpx text-#714428 font-bold">
-          <text>We still need to invite </text>
-          <text class="text-white">
-            {{ formatNumber((userInfo.nextInvitedNo - userInfo.invitedNo), 0) }} friends
-          </text>
-          <text>. Can upgrade to</text>
-          <text class="text-white">
-            V{{ userInfo.level + 1 >= dataList.length ? dataList.length : userInfo.level + 1 }}
-          </text>
+          {{ t('vipMembership.inviteProgress', [formatNumber((userInfo.nextInvitedNo - userInfo.invitedNo), 0), userInfo.level + 1 >= dataList.length ? dataList.length : userInfo.level + 1]) }}
         </view>
       </view>
       <image src="/static/images/vip-level1.png" class="absolute right-48rpx top-0 h-162rpx w-126.5rpx" />
@@ -90,7 +84,7 @@ onLoad(() => {
       <view class="flex items-center justify-between">
         <view class="flex-[33.33%]">
           <view class="text-22rpx text-#5B5B5B">
-            Invited Friends
+            {{ t('vipMembership.invitedFriends') }}
           </view>
           <view class="text-26rpx font-bold">
             {{ formatNumber(userInfo.invitedNo, 0) }}
@@ -99,7 +93,7 @@ onLoad(() => {
         <wd-divider custom-class="h-40rpx!" color="#A4A4A4" vertical dashed />
         <view class="flex-[33.33%]">
           <view class="text-22rpx text-#5B5B5B">
-            Team Members
+            {{ t('vipMembership.teamMembers') }}
           </view>
           <view class="text-26rpx font-bold">
             {{ formatNumber(userInfo.teamNo, 0) }}
@@ -108,7 +102,7 @@ onLoad(() => {
         <wd-divider dashed custom-class="h-40rpx!" color="#A4A4A4" vertical />
         <view class="flex-[33.33%]">
           <view class="text-22rpx text-#5B5B5B">
-            L7D Earnings
+            {{ t('vipMembership.l7dEarnings') }}
           </view>
           <view class="text-26rpx font-bold">
             {{ formatNumber(userInfo.l7DEarnings) }}
@@ -118,7 +112,7 @@ onLoad(() => {
     </view>
     <view>
       <view class="mb-28rpx text-32rpx">
-        VIP Benefits/Tiers
+        {{ t('vipMembership.benefitsTiers') }}
       </view>
       <view class="rounded-16rpx bg-white p-24rpx">
         <wd-table :data="dataList" :border="false" :stripe="false" :fixed-header="false">

+ 8 - 7
src/pages/wallet/myWallet.vue

@@ -3,7 +3,7 @@
   layout: 'default',
   needLogin: true,
   style: {
-    navigationBarTitleText: 'My Wallet',
+    navigationBarTitleText: '%wallet.myWallet.title%',
     navigationBarBackgroundColor: '#fff',
   },
 }
@@ -15,6 +15,7 @@ import { onPageScroll, onReachBottom } from '@dcloudio/uni-app' // 必须导入
 import useZPaging from 'z-paging/components/z-paging/js/hooks/useZPaging.js'
 
 import { getWalletAccountInfo, walletFlowList } from '@/api/wallet'
+import { t } from '@/locale'
 import { formatNumber } from '@/utils'
 import { toPage } from '@/utils/page'
 // z-paging
@@ -59,14 +60,14 @@ onShow(() => {
       >
         <view class="text-center">
           <view class="text-22rpx text-#595959">
-            Wallet Balance
+            {{ t('wallet.balance') }}
           </view>
           <view class="mb-22rpx text-44rpx text-[var(--wot-color-theme)] font-bold">
             {{ formatNumber(walletInfo.balance) }}
           </view>
           <view class="flex items-center text-22rpx text-#595959">
             <text class="mr-1px">
-              Wallet Frozen Balance
+              {{ t('wallet.frozenBalance') }}
             </text>
             <wd-icon name="help-circle" size="20rpx" />
           </view>
@@ -76,24 +77,24 @@ onShow(() => {
         </view>
         <view class="flex flex-col items-end">
           <wd-button size="small" @click="toPage('/pages/wallet/recharge')">
-            Recharge
+            {{ t('wallet.recharge') }}
           </wd-button>
           <view class="mt-10rpx text-20rpx text-#595959">
-            Highest Discount 5%
+            {{ t('wallet.discount') }}
           </view>
         </view>
       </view>
       <view class="mb-20rpx flex justify-center">
         <view class="flex items-center justify-center" @click="toPage('/pages/wallet/withdraw')">
           <text class="mr-8rpx">
-            Withdraw Now
+            {{ t('wallet.withdrawNow') }}
           </text>
           <wd-icon name="arrow-right" size="28rpx" />
         </view>
       </view>
       <view>
         <view class="mb-20rpx text-32rpx">
-          Wallet  Record
+          {{ t('wallet.record') }}
         </view>
         <view class="mb-20rpx">
           <wd-radio-group v-model="dayType" shape="button">

+ 6 - 7
src/pages/wallet/recharge.vue

@@ -2,7 +2,7 @@
 {
   layout: 'default',
   style: {
-    navigationBarTitleText: 'Recharge',
+    navigationBarTitleText: '%wallet.recharge.title%',
     navigationBarBackgroundColor: '#fff',
     "app-plus": {
       "titleNView": {
@@ -21,6 +21,7 @@
 
 <script lang="ts" setup>
 import { rechargeAdd, rechargeCallback, rechargeGoodsList } from '@/api/wallet'
+import { t } from '@/locale'
 import { formatNumber } from '@/utils'
 import { toPage } from '@/utils/page'
 
@@ -60,9 +61,7 @@ onShow(() => {
   <z-paging>
     <view class="px-24rpx">
       <view class="py-30rpx text-center text-28rpx text-#595959">
-        Recharge Highest Discount <text class="text-[var(--wot-color-theme)]">
-          {{ Math.max(...(dataList.map(i => i.discountRate))) }}%
-        </text>
+        {{ t('wallet.recharge.highestDiscount', [Math.max(...(dataList.map(i => i.discountRate)))]) }}
       </view>
       <view class="grid grid-cols-2 gap-20rpx">
         <view
@@ -79,9 +78,9 @@ onShow(() => {
             {{ formatNumber(i.amount) }}
           </view>
           <view class="text-20rpx">
-            Get <text class="text-[var(--wot-color-theme)]">
+            {{ t('wallet.recharge.get') }} <text class="text-[var(--wot-color-theme)]">
               ৳{{ formatNumber(i.amount + i.discount) }}, {{ i.discountRate }}%
-            </text> Discount
+            </text> {{ t('wallet.recharge.discount') }}
           </view>
         </view>
       </view>
@@ -89,7 +88,7 @@ onShow(() => {
     <template #bottom>
       <view class="bg-white/60 px-28rpx py-30rpx backdrop-blur-20">
         <wd-button block :disabled="!selectData.id" @click="submit">
-          Submit
+          {{ t('wallet.recharge.submit') }}
         </wd-button>
       </view>
     </template>

+ 1 - 1
src/pages/wallet/rechargeRecord.vue

@@ -2,7 +2,7 @@
 {
   layout: 'default',
   style: {
-    navigationBarTitleText: 'Recharge Record',
+    navigationBarTitleText: '%wallet.rechargeRecord.title%',
     navigationBarBackgroundColor: '#fff',
   },
 }

+ 1 - 1
src/pages/wallet/withdrawRecord.vue

@@ -2,7 +2,7 @@
 {
   layout: 'default',
   style: {
-    navigationBarTitleText: 'Withdraw Record',
+    navigationBarTitleText: '%wallet.withdrawRecord.title%',
     navigationBarBackgroundColor: '#fff',
   },
 }

+ 2 - 1
src/pages/webLink/webLink.vue

@@ -10,6 +10,7 @@
 </route>
 
 <script setup>
+import { t } from '@/locale'
 import { getPageParams } from '@/utils/page'
 
 const params = ref({})
@@ -17,7 +18,7 @@ const params = ref({})
 onLoad((options) => {
   params.value = getPageParams(options)
   uni.setNavigationBarTitle({
-    title: params.value.title || 'Web Link',
+    title: params.value.title || t('webLink.title'),
   })
 })
 </script>

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません