diff --git a/miniprogram/i18n/locales/autoScan.js b/miniprogram/i18n/locales/autoScan.js index 602777b..95c7609 100644 --- a/miniprogram/i18n/locales/autoScan.js +++ b/miniprogram/i18n/locales/autoScan.js @@ -1,5 +1,40 @@ -// Strings for the autoScan page. Fill zh/en with identical key structure. +// Strings for the auto-scan (smart scan) page. Keep zh/en with identical key structure. +// Pre/Post pairs are concatenated around a frame count in WXML (WXML cannot do {param}). module.exports = { - zh: {}, - en: {} + zh: { + title: '智能检测', + subReady: '准备就绪', + subWaiting: '等待佩戴贴合...', + subCollectingPre: '采集数据中 (', + subCollectingPost: '帧)...', + subDone: '检测完成,正在启动...', + readyHint: '设备已佩戴,点击下方按钮开始智能检测', + startBtn: '开始检测', + waitingStatus: '正在检测面膜贴合状态,请确保设备正确佩戴...', + collectingStatusPre: '已贴合,正在采集光谱数据... 已收到 ', + collectingStatusPost: ' 帧', + doneStatusPre: '检测完成(共 ', + doneStatusPost: ' 帧),正在启动治疗...', + notWorn: '面膜未佩戴好,请重新佩戴后再试', + timeout: '检测超时,未收到数据,请重试', + cmdFailed: '检测命令发送失败' + }, + en: { + title: 'Smart Scan', + subReady: 'Ready', + subWaiting: 'Waiting for fit...', + subCollectingPre: 'Collecting data (', + subCollectingPost: ' frames)...', + subDone: 'Scan complete, starting...', + readyHint: 'Device is on. Tap the button below to start the smart scan', + startBtn: 'Start Scan', + waitingStatus: 'Checking mask fit, please make sure the device is worn correctly...', + collectingStatusPre: 'Fitted. Collecting spectral data... received ', + collectingStatusPost: ' frames', + doneStatusPre: 'Scan complete (', + doneStatusPost: ' frames), starting treatment...', + notWorn: 'The mask is not worn properly. Please re-fit and try again', + timeout: 'Scan timed out with no data. Please try again', + cmdFailed: 'Failed to send scan command' + } } diff --git a/miniprogram/i18n/locales/bindSuccess.js b/miniprogram/i18n/locales/bindSuccess.js index 834031a..6186756 100644 --- a/miniprogram/i18n/locales/bindSuccess.js +++ b/miniprogram/i18n/locales/bindSuccess.js @@ -1,5 +1,23 @@ // Strings for the bindSuccess page. Fill zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '绑定成功', + subtitle: '设备已成功绑定', + successTitle: '绑定成功!', + freeModeOpen: '智能模式已开放', + trialGranted: '恭喜获得{days}天智能模式试用', + trialSub: '体验结束后可订阅继续使用', + startUsing: '开始使用', + goHome: '返回首页' + }, + en: { + title: 'Bound Successfully', + subtitle: 'Device bound successfully', + successTitle: 'Bound Successfully!', + freeModeOpen: 'Smart mode unlocked', + trialGranted: 'You got a {days}-day Smart mode trial', + trialSub: 'Subscribe to keep using it after the trial ends', + startUsing: 'Get Started', + goHome: 'Back to Home' + } } diff --git a/miniprogram/i18n/locales/bleConnect.js b/miniprogram/i18n/locales/bleConnect.js index 3fc321c..c9d6755 100644 --- a/miniprogram/i18n/locales/bleConnect.js +++ b/miniprogram/i18n/locales/bleConnect.js @@ -1,5 +1,33 @@ // Strings for the bleConnect page. Fill zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '蓝牙连接', + searchingSub: '正在搜索设备...', + connectingSub: '正在连接设备...', + bindingSub: '正在绑定...', + failedSub: '连接失败', + bluetoothTip: '请确保手机蓝牙已开启', + searching: '搜索中...', + pairing: '正在配对...', + failed: '连接失败', + scanTimeout: '搜索超时,请确认设备已开机并在附近', + confirmFailed: '后台确认绑定失败', + bindFailed: '设备绑定失败', + bindCmdFailed: '绑定命令失败' + }, + en: { + title: 'Bluetooth Connection', + searchingSub: 'Searching for device...', + connectingSub: 'Connecting to device...', + bindingSub: 'Binding...', + failedSub: 'Connection failed', + bluetoothTip: 'Please make sure Bluetooth is enabled on your phone', + searching: 'Searching...', + pairing: 'Pairing...', + failed: 'Connection failed', + scanTimeout: 'Search timed out. Please make sure the device is powered on and nearby', + confirmFailed: 'Failed to confirm binding on the server', + bindFailed: 'Device binding failed', + bindCmdFailed: 'Binding command failed' + } } diff --git a/miniprogram/i18n/locales/contact.js b/miniprogram/i18n/locales/contact.js index fa9d11e..ffcd7c6 100644 --- a/miniprogram/i18n/locales/contact.js +++ b/miniprogram/i18n/locales/contact.js @@ -1,5 +1,13 @@ // Strings for the contact page. Fill zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '联系我们', + placeholderText: '内容建设中', + placeholderSub: '联系方式正在整理,敬请期待' + }, + en: { + title: 'Contact Us', + placeholderText: 'Coming soon', + placeholderSub: 'Contact details are being prepared. Stay tuned.' + } } diff --git a/miniprogram/i18n/locales/help.js b/miniprogram/i18n/locales/help.js index f5ba7af..aed76a9 100644 --- a/miniprogram/i18n/locales/help.js +++ b/miniprogram/i18n/locales/help.js @@ -1,5 +1,13 @@ // Strings for the help page. Fill zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '使用帮助', + placeholderText: '内容建设中', + placeholderSub: '帮助文档正在编写,敬请期待' + }, + en: { + title: 'Help', + placeholderText: 'Coming soon', + placeholderSub: 'The help guide is being written. Stay tuned.' + } } diff --git a/miniprogram/i18n/locales/login.js b/miniprogram/i18n/locales/login.js index b09a6bc..391c25c 100644 --- a/miniprogram/i18n/locales/login.js +++ b/miniprogram/i18n/locales/login.js @@ -1,5 +1,21 @@ // Strings for the login page. Fill zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + wechatLogin: '微信登录', + welcome: '欢迎使用LumiFlow', + desc: '登录后即可使用全部功能', + agreement: '登录即表示同意《用户协议》和《隐私政策》', + loginFailed: '登录失败', + agreementTitle: '提示', + agreementContent: '用户协议和隐私政策内容建设中' + }, + en: { + wechatLogin: 'WeChat Login', + welcome: 'Welcome to LumiFlow', + desc: 'Log in to unlock all features', + agreement: 'By logging in, you agree to the Terms of Service and Privacy Policy', + loginFailed: 'Login failed', + agreementTitle: 'Notice', + agreementContent: 'Terms of Service and Privacy Policy are coming soon' + } } diff --git a/miniprogram/i18n/locales/register.js b/miniprogram/i18n/locales/register.js index 5ec9264..52cf28e 100644 --- a/miniprogram/i18n/locales/register.js +++ b/miniprogram/i18n/locales/register.js @@ -1,5 +1,45 @@ // Strings for the register page. Fill zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + subtitle: '完善个人资料', + avatarSection: '设置头像', + changeAvatar: '点击更换', + nicknameSection: '设置昵称', + nicknamePlaceholder: '请输入昵称', + authorizePhone: '授权手机号', + phoneHint: '手机号用于接收服务通知,必须授权', + submit: '完成注册', + agreement: '注册即表示同意《用户协议》和《隐私政策》', + nicknamePrefix: '用户', + phoneRequired: '需要授权手机号才能完成注册', + phoneAuthSuccess: '手机号授权成功', + phoneAuthFailed: '手机号授权失败', + authorized: '已授权', + uploadFailed: '上传失败', + phoneFirst: '请先授权手机号', + nicknameRequired: '请输入昵称', + agreementTitle: '提示', + agreementContent: '用户协议和隐私政策内容建设中' + }, + en: { + subtitle: 'Complete Your Profile', + avatarSection: 'Set Avatar', + changeAvatar: 'Tap to change', + nicknameSection: 'Set Nickname', + nicknamePlaceholder: 'Enter a nickname', + authorizePhone: 'Authorize Phone Number', + phoneHint: 'Your phone number is used to receive service notifications and is required', + submit: 'Complete Registration', + agreement: 'By registering, you agree to the Terms of Service and Privacy Policy', + nicknamePrefix: 'User', + phoneRequired: 'Phone number authorization is required to complete registration', + phoneAuthSuccess: 'Phone number authorized', + phoneAuthFailed: 'Phone authorization failed', + authorized: 'Authorized', + uploadFailed: 'Upload failed', + phoneFirst: 'Please authorize your phone number first', + nicknameRequired: 'Please enter a nickname', + agreementTitle: 'Notice', + agreementContent: 'Terms of Service and Privacy Policy are coming soon' + } } diff --git a/miniprogram/i18n/locales/scan.js b/miniprogram/i18n/locales/scan.js index aafd93f..94a7101 100644 --- a/miniprogram/i18n/locales/scan.js +++ b/miniprogram/i18n/locales/scan.js @@ -1,5 +1,29 @@ // Strings for the scan page. Fill zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '扫码绑定', + subtitle: '扫描设备底部二维码', + scanText: '扫描设备二维码', + scan: '扫码', + scanning: '扫描中...', + manualInput: '手动输入设备号', + manualPlaceholder: '请输入设备ID,如 672B6D5A 4DCD861', + invalidQr: '无效的设备二维码', + alreadyBound: '已绑定设备', + bindFailed: '绑定失败', + invalidFormat: '设备号格式不正确' + }, + en: { + title: 'Scan to Bind', + subtitle: 'Scan the QR code on the bottom of the device', + scanText: 'Scan device QR code', + scan: 'Scan', + scanning: 'Scanning...', + manualInput: 'Enter Device ID Manually', + manualPlaceholder: 'Enter device ID, e.g. 672B6D5A 4DCD861', + invalidQr: 'Invalid device QR code', + alreadyBound: 'Device already bound', + bindFailed: 'Binding failed', + invalidFormat: 'Invalid device ID format' + } } diff --git a/miniprogram/i18n/locales/setup.js b/miniprogram/i18n/locales/setup.js index 5acc645..ffd1e40 100644 --- a/miniprogram/i18n/locales/setup.js +++ b/miniprogram/i18n/locales/setup.js @@ -1,5 +1,33 @@ -// Strings for the setup page. Fill zh/en with identical key structure. +// Strings for the treatment-setup page. Keep zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '使用设置', + subtitle: '选择模式和区域', + selectMode: '选择模式', + normalMode: '普通模式', + normalModeSub: '6色循环', + smartMode: '智能模式', + remainDays: '剩余{days}天', + subscribeUnlock: '订阅解锁', + selectRegion: '选择区域', + normalTip: '普通模式固定 10 分钟,使用区域默认全区域,不可调整', + startBtn: '开始使用', + noRegion: '请至少选择一个区域', + startFailed: '启动失败' + }, + en: { + title: 'Session Setup', + subtitle: 'Choose mode and regions', + selectMode: 'Select Mode', + normalMode: 'Normal Mode', + normalModeSub: '6-color cycle', + smartMode: 'Smart Mode', + remainDays: '{days} days left', + subscribeUnlock: 'Subscribe to unlock', + selectRegion: 'Select Regions', + normalTip: 'Normal mode runs a fixed 10 minutes over all regions and cannot be adjusted', + startBtn: 'Start', + noRegion: 'Please select at least one region', + startFailed: 'Failed to start' + } } diff --git a/miniprogram/i18n/locales/subPlans.js b/miniprogram/i18n/locales/subPlans.js index 01f4b2d..7efabda 100644 --- a/miniprogram/i18n/locales/subPlans.js +++ b/miniprogram/i18n/locales/subPlans.js @@ -1,5 +1,87 @@ // Strings for the subPlans page. Fill zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '订阅服务', + subtitle: '解锁智能模式', + currentPlanLabel: '当前套餐', + remainDaysLabel: '剩余天数', + daysValue: '{days}天', + choosePlan: '选择订阅套餐', + loadingPlans: '加载套餐中...', + smartMode: '智能模式', + smartModeDesc: '智能自动调节', + renew: '续费', + confirmPay: '确认支付', + agreement: '支付即表示同意《订阅协议》', + // plan names (also used as fallback plan labels) + planTrial: '试用', + planMonthly: '月卡', + planYearly: '年卡', + // computed plan descriptions + free: '免费', + descTrial: '{days}天免费体验', + descSave: '省¥{amount}', + descDaily: '约{price}元/天', + tagRecommend: '推荐', + tagUsed: '已使用', + // modals / toasts + tipTitle: '提示', + agreementBuilding: '订阅协议内容建设中', + activateTrialTitle: '激活试用', + activateTrialConfirm: '免费试用 {desc}?', + confirmRenewTitle: '确认续费', + confirmPayTitle: '确认支付', + renewContent: '在现有订阅基础上延长{days}天,支付 ¥{price}', + payContent: '支付 ¥{price}', + trialActivated: '试用已激活', + activateFailed: '激活失败', + payUnavailable: '支付服务暂不可用', + payCancelled: '已取消支付', + payFailed: '支付失败', + createOrderFailed: '创建订单失败', + paySuccess: '支付成功', + payProcessing: '支付处理中,请稍后在订阅页查看' + }, + en: { + title: 'Subscription', + subtitle: 'Unlock Smart Mode', + currentPlanLabel: 'Current plan', + remainDaysLabel: 'Days remaining', + daysValue: '{days} days', + choosePlan: 'Choose a plan', + loadingPlans: 'Loading plans...', + smartMode: 'Smart Mode', + smartModeDesc: 'Automatic smart adjustment', + renew: 'Renew', + confirmPay: 'Pay Now', + agreement: 'By paying you agree to the Subscription Agreement', + // plan names (also used as fallback plan labels) + planTrial: 'Trial', + planMonthly: 'Monthly', + planYearly: 'Yearly', + // computed plan descriptions + free: 'Free', + descTrial: '{days}-day free trial', + descSave: 'Save ¥{amount}', + descDaily: 'About ¥{price}/day', + tagRecommend: 'Best value', + tagUsed: 'Used', + // modals / toasts + tipTitle: 'Notice', + agreementBuilding: 'The subscription agreement is being prepared', + activateTrialTitle: 'Activate trial', + activateTrialConfirm: 'Start free trial: {desc}?', + confirmRenewTitle: 'Confirm renewal', + confirmPayTitle: 'Confirm payment', + renewContent: 'Extend your current subscription by {days} days for ¥{price}', + payContent: 'Pay ¥{price}', + trialActivated: 'Trial activated', + activateFailed: 'Activation failed', + payUnavailable: 'Payment service is unavailable', + payCancelled: 'Payment cancelled', + payFailed: 'Payment failed', + createOrderFailed: 'Failed to create order', + paySuccess: 'Payment successful', + payProcessing: 'Payment is processing. Please check the subscription page later.' + } } diff --git a/miniprogram/i18n/locales/subPrompt.js b/miniprogram/i18n/locales/subPrompt.js index e7f2212..012e21f 100644 --- a/miniprogram/i18n/locales/subPrompt.js +++ b/miniprogram/i18n/locales/subPrompt.js @@ -1,5 +1,29 @@ // Strings for the subPrompt page. Fill zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '使用设置', + subtitle: '试用期已结束', + selectMode: '选择模式', + normalMode: '普通模式', + normalModeSub: '6色循环', + smartMode: '智能模式', + smartModeSub: '订阅解锁', + trialEndedTitle: '试用已结束', + trialEndedSub: '订阅后继续使用智能模式', + subscribeNow: '立即订阅', + useNormalFirst: '先使用普通模式' + }, + en: { + title: 'Settings', + subtitle: 'Your free trial has ended', + selectMode: 'Choose a mode', + normalMode: 'Standard Mode', + normalModeSub: '6-color cycle', + smartMode: 'Smart Mode', + smartModeSub: 'Unlock with subscription', + trialEndedTitle: 'Trial ended', + trialEndedSub: 'Subscribe to keep using Smart Mode', + subscribeNow: 'Subscribe Now', + useNormalFirst: 'Use Standard Mode for now' + } } diff --git a/miniprogram/i18n/locales/subSuccess.js b/miniprogram/i18n/locales/subSuccess.js index 5a936c6..2d097f5 100644 --- a/miniprogram/i18n/locales/subSuccess.js +++ b/miniprogram/i18n/locales/subSuccess.js @@ -1,5 +1,29 @@ // Strings for the subSuccess page. Fill zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '订阅成功', + subtitle: '欢迎使用智能模式', + successTitle: '订阅成功!', + subscribed: '已订阅', + validUntil: '有效期至:', + startSmart: '立即体验智能模式', + backHome: '返回首页', + planTrial: '试用会员', + planMonthly: '月卡会员', + planYearly: '年卡会员', + planDefault: '会员' + }, + en: { + title: 'Subscription Successful', + subtitle: 'Welcome to Smart Mode', + successTitle: 'Subscription successful!', + subscribed: 'Subscribed', + validUntil: 'Valid until: ', + startSmart: 'Try Smart Mode now', + backHome: 'Back to Home', + planTrial: 'Trial Member', + planMonthly: 'Monthly Member', + planYearly: 'Yearly Member', + planDefault: 'Member' + } } diff --git a/miniprogram/i18n/locales/treating.js b/miniprogram/i18n/locales/treating.js index 1e46344..4d7f233 100644 --- a/miniprogram/i18n/locales/treating.js +++ b/miniprogram/i18n/locales/treating.js @@ -1,5 +1,59 @@ -// Strings for the treating page. Fill zh/en with identical key structure. +// Strings for the treating (live treatment) page. Keep zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '使用中', + subtitle: '正在使用...', + remainingLabel: '剩余时间', + smartMode: '✨ 智能模式', + normalMode: '🔄 普通模式', + allRegions: '全区域', + regionTopLeft: '左上区', + regionTopRight: '右上区', + relax1: '请放松心情', + relax2: '享受美好时光', + stopBtn: '停止使用', + fittingLost: '检测到离肤,请重新佩戴设备', + fittingRestored: '已重新贴合,继续使用', + faultTitle: '设备故障', + faultContent: '设备上报故障,已自动停止。', + lowBatteryTitle: '电量过低', + lowBatteryContent: '设备电量不足5%,已自动停止。请及时充电。', + lowBatteryWarn: '电量低,请及时充电', + exceptionTitle: '设备异常', + exceptionContent: '使用过程中出现异常', + disconnected: '设备连接断开,正在重连...', + reconnected: '设备已重新连接', + reconnectFailedTitle: '连接丢失', + reconnectFailedContent: '设备蓝牙连接已断开,无法恢复。本次使用数据将保存。', + stopTitle: '结束使用', + stopContent: '确定要提前结束本次使用吗?' + }, + en: { + title: 'In Progress', + subtitle: 'Treatment in progress...', + remainingLabel: 'Time Left', + smartMode: '✨ Smart Mode', + normalMode: '🔄 Normal Mode', + allRegions: 'All regions', + regionTopLeft: 'Top-left', + regionTopRight: 'Top-right', + relax1: 'Relax and unwind', + relax2: 'Enjoy your moment', + stopBtn: 'Stop', + fittingLost: 'Device lifted off skin. Please put it back on', + fittingRestored: 'Re-fitted, continuing', + faultTitle: 'Device Fault', + faultContent: 'The device reported a fault and stopped automatically.', + lowBatteryTitle: 'Battery Too Low', + lowBatteryContent: 'Battery is below 5%. Stopped automatically. Please charge soon.', + lowBatteryWarn: 'Low battery, please charge soon', + exceptionTitle: 'Device Error', + exceptionContent: 'Something went wrong during the session', + disconnected: 'Device disconnected, reconnecting...', + reconnected: 'Device reconnected', + reconnectFailedTitle: 'Connection Lost', + reconnectFailedContent: 'The Bluetooth connection was lost and cannot be restored. This session will be saved.', + stopTitle: 'End Session', + stopContent: 'Are you sure you want to end this session early?' + } } diff --git a/miniprogram/i18n/locales/treatmentDone.js b/miniprogram/i18n/locales/treatmentDone.js index ba7cb31..5922c2d 100644 --- a/miniprogram/i18n/locales/treatmentDone.js +++ b/miniprogram/i18n/locales/treatmentDone.js @@ -1,5 +1,25 @@ -// Strings for the treatmentDone page. Fill zh/en with identical key structure. +// Strings for the treatment-done page. Keep zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '使用完成', + headerSub: '本次使用已结束', + resultTitle: '使用完成!', + durationLabel: '使用时长', + regionLabel: '使用区域', + recorded: '本次使用已记录', + backHome: '返回首页', + durationMin: '{min}分钟', + durationSec: '{sec}秒' + }, + en: { + title: 'Complete', + headerSub: 'This session has ended', + resultTitle: 'Session Complete!', + durationLabel: 'Duration', + regionLabel: 'Regions', + recorded: 'This session has been recorded', + backHome: 'Back to Home', + durationMin: '{min} min', + durationSec: '{sec} s' + } } diff --git a/miniprogram/i18n/locales/wearCheck.js b/miniprogram/i18n/locales/wearCheck.js index b40215a..f97c5af 100644 --- a/miniprogram/i18n/locales/wearCheck.js +++ b/miniprogram/i18n/locales/wearCheck.js @@ -1,5 +1,39 @@ -// Strings for the wearCheck page. Fill zh/en with identical key structure. +// Strings for the wear-check page. Keep zh/en with identical key structure. module.exports = { - zh: {}, - en: {} + zh: { + title: '确认佩戴', + subtitle: '请确保设备正确佩戴', + connected: '已连接', + disconnected: '未连接', + battery: '电量', + guideTitle: '佩戴指引', + guideImg: '设备佩戴示意图', + step1: '1. 取出设备,展开弹性绑带', + step2: '2. 将设备正确佩戴', + step3: '3. 调节绑带至舒适位置', + confirmBtn: '确认已佩戴,开始检测', + reconnect: '重新连接', + connecting: '正在连接...', + connectSuccess: '连接成功', + connectFailed: '连接失败', + searchTimeout: '搜索超时' + }, + en: { + title: 'Confirm Fit', + subtitle: 'Make sure the device is worn correctly', + connected: 'Connected', + disconnected: 'Not connected', + battery: 'Battery', + guideTitle: 'How to Wear', + guideImg: 'Wearing diagram', + step1: '1. Take out the device and unfold the strap', + step2: '2. Put the device on correctly', + step3: '3. Adjust the strap to a comfortable fit', + confirmBtn: 'Confirm Fit & Continue', + reconnect: 'Reconnect', + connecting: 'Connecting...', + connectSuccess: 'Connected', + connectFailed: 'Connection failed', + searchTimeout: 'Search timed out' + } } diff --git a/miniprogram/pages/auto-scan/auto-scan.js b/miniprogram/pages/auto-scan/auto-scan.js index 44221bf..cf17e52 100644 --- a/miniprogram/pages/auto-scan/auto-scan.js +++ b/miniprogram/pages/auto-scan/auto-scan.js @@ -1,6 +1,7 @@ var ble = require('../../services/ble') var api = require('../../utils/api') var diagnosis = require('../../services/diagnosis') +var i18n = require('../../i18n/index') var SCAN_TIMEOUT = 180000 Page({ @@ -31,6 +32,10 @@ Page({ }) }, + onShow: function () { + i18n.bind(this) + }, + _cleanup: function () { if (this._timeoutTimer) { clearTimeout(this._timeoutTimer); this._timeoutTimer = null } if (this._onAdc) { ble.off('adc', this._onAdc); this._onAdc = null } @@ -42,7 +47,7 @@ Page({ var self = this if (!ble.isConnected()) { - self.setData({ error: '设备未连接' }) + self.setData({ error: i18n.t('common.deviceNotConnected') }) return } @@ -90,7 +95,7 @@ Page({ console.log('[SCAN] 未贴合,检测失败') self._completed = true self._cleanup() - self.setData({ phase: 'ready', error: '面膜未佩戴好,请重新佩戴后再试' }) + self.setData({ phase: 'ready', error: i18n.t('autoScan.notWorn') }) return } @@ -129,7 +134,7 @@ Page({ }).catch(function (err) { console.error('[SCAN] 检测命令发送失败:', err) self._cleanup() - self.setData({ phase: 'ready', error: '检测命令发送失败' }) + self.setData({ phase: 'ready', error: i18n.t('autoScan.cmdFailed') }) }) self._timeoutTimer = setTimeout(function () { @@ -140,7 +145,7 @@ Page({ } else { self._completed = true self._cleanup() - self.setData({ phase: 'ready', error: '检测超时,未收到数据,请重试' }) + self.setData({ phase: 'ready', error: i18n.t('autoScan.timeout') }) } }, SCAN_TIMEOUT) }, diff --git a/miniprogram/pages/auto-scan/auto-scan.wxml b/miniprogram/pages/auto-scan/auto-scan.wxml index dc45217..9581d69 100644 --- a/miniprogram/pages/auto-scan/auto-scan.wxml +++ b/miniprogram/pages/auto-scan/auto-scan.wxml @@ -1,15 +1,15 @@ - ‹ 返回 - 智能检测 - {{phase === 'ready' ? '准备就绪' : phase === 'waiting_fit' ? '等待佩戴贴合...' : phase === 'collecting' ? '采集数据中 (' + frameCount + '帧)...' : '检测完成,正在启动...'}} + ‹ {{i18n.common.back}} + {{i18n.autoScan.title}} + {{phase === 'ready' ? i18n.autoScan.subReady : phase === 'waiting_fit' ? i18n.autoScan.subWaiting : phase === 'collecting' ? i18n.autoScan.subCollectingPre + frameCount + i18n.autoScan.subCollectingPost : i18n.autoScan.subDone}} - 设备已佩戴,点击下方按钮开始智能检测 - + {{i18n.autoScan.readyHint}} + @@ -19,7 +19,7 @@ - 正在检测面膜贴合状态,请确保设备正确佩戴... + {{i18n.autoScan.waitingStatus}} @@ -29,12 +29,12 @@ - 已贴合,正在采集光谱数据... 已收到 {{frameCount}} 帧 + {{i18n.autoScan.collectingStatusPre}}{{frameCount}}{{i18n.autoScan.collectingStatusPost}} - 检测完成(共 {{frameCount}} 帧),正在启动治疗... + {{i18n.autoScan.doneStatusPre}}{{frameCount}}{{i18n.autoScan.doneStatusPost}} {{error}} diff --git a/miniprogram/pages/bind-success/bind-success.js b/miniprogram/pages/bind-success/bind-success.js index 1f239f7..7c65e6d 100644 --- a/miniprogram/pages/bind-success/bind-success.js +++ b/miniprogram/pages/bind-success/bind-success.js @@ -1,9 +1,24 @@ +var i18n = require('../../i18n/index') + Page({ data: { statusBarHeight: 44, deviceId: '', trialDays: 7, - isFreeMode: false + isFreeMode: false, + tipTitle: '' + }, + + onShow: function () { + i18n.bind(this) + }, + + updateTip: function () { + this.setData({ + tipTitle: this.data.isFreeMode + ? i18n.t('bindSuccess.freeModeOpen') + : i18n.t('bindSuccess.trialGranted', { days: this.data.trialDays }) + }) }, onBack: function () { @@ -18,10 +33,14 @@ Page({ var app = getApp() this.setData({ statusBarHeight: app.globalData.statusBarHeight }) this.setData({ deviceId: options.device_id || '' }) + this.updateTip() var self = this var http = require('../../utils/request') http.get('/api/v1/subscription').then(function (sub) { - if (sub && sub.plan === 'free') self.setData({ isFreeMode: true }) + if (sub && sub.plan === 'free') { + self.setData({ isFreeMode: true }) + self.updateTip() + } }).catch(function () {}) }, diff --git a/miniprogram/pages/bind-success/bind-success.wxml b/miniprogram/pages/bind-success/bind-success.wxml index 694535d..0aa2286 100644 --- a/miniprogram/pages/bind-success/bind-success.wxml +++ b/miniprogram/pages/bind-success/bind-success.wxml @@ -1,25 +1,25 @@ - ‹ 返回 - 绑定成功 - 设备已成功绑定 + ‹ {{i18n.common.back}} + {{i18n.bindSuccess.title}} + {{i18n.bindSuccess.subtitle}} - 绑定成功! + {{i18n.bindSuccess.successTitle}} 🎁 - {{isFreeMode ? '智能模式已开放' : '恭喜获得7天智能模式试用'}} - 体验结束后可订阅继续使用 + {{tipTitle}} + {{i18n.bindSuccess.trialSub}} - - + + diff --git a/miniprogram/pages/ble-connect/ble-connect.js b/miniprogram/pages/ble-connect/ble-connect.js index ac9d337..a7d2fc1 100644 --- a/miniprogram/pages/ble-connect/ble-connect.js +++ b/miniprogram/pages/ble-connect/ble-connect.js @@ -1,5 +1,6 @@ var ble = require('../../services/ble') var http = require('../../utils/request') +var i18n = require('../../i18n/index') var app = getApp() var SCAN_TIMEOUT = 15000 @@ -12,6 +13,10 @@ Page({ error: '', }, + onShow: function () { + i18n.bind(this) + }, + onBack: function () { wx.navigateBack({ fail: function () { @@ -48,7 +53,7 @@ Page({ self._scanTimer = setTimeout(function () { ble.stopScan() - self.setData({ state: 'error', error: '搜索超时,请确认设备已开机并在附近' }) + self.setData({ state: 'error', error: i18n.t('bleConnect.scanTimeout') }) }, SCAN_TIMEOUT) ble.startScan({ @@ -64,7 +69,7 @@ Page({ }, onError: function (err) { clearTimeout(self._scanTimer) - self.setData({ state: 'error', error: err.msg || '连接失败' }) + self.setData({ state: 'error', error: err.msg || i18n.t('bleConnect.failed') }) } }) }, @@ -83,16 +88,16 @@ Page({ url: '/pages/bind-success/bind-success?device_id=' + self.data.deviceId }) }).catch(function (err) { - self.setData({ state: 'error', error: err.message || '后台确认绑定失败' }) + self.setData({ state: 'error', error: err.message || i18n.t('bleConnect.confirmFailed') }) }) } else { - self.setData({ state: 'error', error: '设备绑定失败' }) + self.setData({ state: 'error', error: i18n.t('bleConnect.bindFailed') }) } } ble.on('bind_result', this._onBindResult) ble.bindDevice(userId, self.data.bindToken).catch(function (err) { - self.setData({ state: 'error', error: err.error_msg || '绑定命令失败' }) + self.setData({ state: 'error', error: err.error_msg || i18n.t('bleConnect.bindCmdFailed') }) }) }, diff --git a/miniprogram/pages/ble-connect/ble-connect.wxml b/miniprogram/pages/ble-connect/ble-connect.wxml index 341d8d8..9c74685 100644 --- a/miniprogram/pages/ble-connect/ble-connect.wxml +++ b/miniprogram/pages/ble-connect/ble-connect.wxml @@ -1,31 +1,31 @@ - ‹ 返回 - 蓝牙连接 - {{state === 'scanning' ? '正在搜索设备...' : state === 'connecting' ? '正在连接设备...' : state === 'binding' ? '正在绑定...' : '连接失败'}} + ‹ {{i18n.common.back}} + {{i18n.bleConnect.title}} + {{state === 'scanning' ? i18n.bleConnect.searchingSub : state === 'connecting' ? i18n.bleConnect.connectingSub : state === 'binding' ? i18n.bleConnect.bindingSub : i18n.bleConnect.failedSub}} 📡 - 请确保手机蓝牙已开启 + {{i18n.bleConnect.bluetoothTip}} - 搜索中... + {{i18n.bleConnect.searching}} 💆 LumiFlow-{{deviceId}} - 正在配对... + {{i18n.bleConnect.pairing}} ⚠️ - {{error || '连接失败'}} - + {{error || i18n.bleConnect.failed}} + diff --git a/miniprogram/pages/contact/contact.js b/miniprogram/pages/contact/contact.js index 9353300..5bb0991 100644 --- a/miniprogram/pages/contact/contact.js +++ b/miniprogram/pages/contact/contact.js @@ -1,8 +1,14 @@ +var i18n = require('../../i18n/index') + Page({ data: { statusBarHeight: 44 }, + onShow: function () { + i18n.bind(this) + }, + onLoad: function () { var app = getApp() this.setData({ statusBarHeight: app.globalData.statusBarHeight }) diff --git a/miniprogram/pages/contact/contact.wxml b/miniprogram/pages/contact/contact.wxml index 46fea90..1dd307a 100644 --- a/miniprogram/pages/contact/contact.wxml +++ b/miniprogram/pages/contact/contact.wxml @@ -1,13 +1,13 @@ - ‹ 返回 - 联系我们 + ‹ {{i18n.common.back}} + {{i18n.contact.title}} 📬 - 内容建设中 - 联系方式正在整理,敬请期待 + {{i18n.contact.placeholderText}} + {{i18n.contact.placeholderSub}} diff --git a/miniprogram/pages/help/help.js b/miniprogram/pages/help/help.js index 9353300..5bb0991 100644 --- a/miniprogram/pages/help/help.js +++ b/miniprogram/pages/help/help.js @@ -1,8 +1,14 @@ +var i18n = require('../../i18n/index') + Page({ data: { statusBarHeight: 44 }, + onShow: function () { + i18n.bind(this) + }, + onLoad: function () { var app = getApp() this.setData({ statusBarHeight: app.globalData.statusBarHeight }) diff --git a/miniprogram/pages/help/help.wxml b/miniprogram/pages/help/help.wxml index 114bda9..be383a9 100644 --- a/miniprogram/pages/help/help.wxml +++ b/miniprogram/pages/help/help.wxml @@ -1,13 +1,13 @@ - ‹ 返回 - 使用帮助 + ‹ {{i18n.common.back}} + {{i18n.help.title}} 📖 - 内容建设中 - 帮助文档正在编写,敬请期待 + {{i18n.help.placeholderText}} + {{i18n.help.placeholderSub}} diff --git a/miniprogram/pages/login/login.js b/miniprogram/pages/login/login.js index 3f27340..4f959ca 100644 --- a/miniprogram/pages/login/login.js +++ b/miniprogram/pages/login/login.js @@ -1,4 +1,5 @@ var app = getApp() +var i18n = require('../../i18n/index') Page({ data: { @@ -6,6 +7,10 @@ Page({ loading: false }, + onShow: function () { + i18n.bind(this) + }, + onLoad: function () { this.setData({ statusBarHeight: app.globalData.statusBarHeight }) }, @@ -23,11 +28,11 @@ Page({ } }).catch(function (err) { self.setData({ loading: false }) - wx.showToast({ title: err.message || '登录失败', icon: 'none' }) + wx.showToast({ title: err.message || i18n.t('login.loginFailed'), icon: 'none' }) }) }, onAgreement: function () { - wx.showModal({ title: '提示', content: '用户协议和隐私政策内容建设中', showCancel: false }) + wx.showModal({ title: i18n.t('login.agreementTitle'), content: i18n.t('login.agreementContent'), showCancel: false }) } }) diff --git a/miniprogram/pages/login/login.wxml b/miniprogram/pages/login/login.wxml index 4d9851b..850ad48 100644 --- a/miniprogram/pages/login/login.wxml +++ b/miniprogram/pages/login/login.wxml @@ -1,21 +1,21 @@ LumiFlow - 微信登录 + {{i18n.login.wechatLogin}} - 欢迎使用LumiFlow + {{i18n.login.welcome}} 💎 - 登录后即可使用全部功能 + {{i18n.login.desc}} - 登录即表示同意《用户协议》和《隐私政策》 + {{i18n.login.agreement}} diff --git a/miniprogram/pages/register/register.js b/miniprogram/pages/register/register.js index 36fc27f..566e758 100644 --- a/miniprogram/pages/register/register.js +++ b/miniprogram/pages/register/register.js @@ -1,6 +1,7 @@ var app = getApp() var http = require('../../utils/request') var config = require('../../config/env') +var i18n = require('../../i18n/index') var DEFAULT_AVATAR = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI9t2NHfLvvMiaiaCJQn3KP2P0vAHp1QBP0piavhGfhKCARlGd6z1EbR58ibJXKCp5WVlNnojwA/640' @@ -9,7 +10,7 @@ function randomNickname() { for (var i = 0; i < 4; i++) { digits += Math.floor(Math.random() * 10) } - return '用户' + digits + return i18n.t('register.nicknamePrefix') + digits } Page({ @@ -21,6 +22,10 @@ Page({ phone: '' }, + onShow: function () { + i18n.bind(this) + }, + onLoad: function () { this.setData({ statusBarHeight: app.globalData.statusBarHeight, @@ -58,19 +63,19 @@ Page({ onGetPhoneNumber: function (e) { var self = this if (!e.detail || !e.detail.code) { - wx.showToast({ title: '需要授权手机号才能完成注册', icon: 'none' }) + wx.showToast({ title: i18n.t('register.phoneRequired'), icon: 'none' }) return } self.setData({ loading: true }) http.post('/api/v1/user/phone', { code: e.detail.code }).then(function (data) { self.setData({ loading: false, - phone: '已授权' + phone: i18n.t('register.authorized') }) - wx.showToast({ title: '手机号授权成功', icon: 'success' }) + wx.showToast({ title: i18n.t('register.phoneAuthSuccess'), icon: 'success' }) }).catch(function (err) { self.setData({ loading: false }) - wx.showToast({ title: err.message || '手机号授权失败', icon: 'none' }) + wx.showToast({ title: err.message || i18n.t('register.phoneAuthFailed'), icon: 'none' }) }) }, @@ -88,13 +93,13 @@ Page({ if (data.code === 0 && data.data && data.data.avatar) { resolve(data.data.avatar) } else { - reject(new Error(data.message || '上传失败')) + reject(new Error(data.message || i18n.t('register.uploadFailed'))) } } catch (e) { - reject(new Error('上传失败')) + reject(new Error(i18n.t('register.uploadFailed'))) } }, - fail: function () { reject(new Error('上传失败')) } + fail: function () { reject(new Error(i18n.t('register.uploadFailed'))) } }) }) }, @@ -105,12 +110,12 @@ Page({ var avatarUrl = self.data.avatarUrl if (!self.data.phone) { - wx.showToast({ title: '请先授权手机号', icon: 'none' }) + wx.showToast({ title: i18n.t('register.phoneFirst'), icon: 'none' }) return } if (!nickname) { - wx.showToast({ title: '请输入昵称', icon: 'none' }) + wx.showToast({ title: i18n.t('register.nicknameRequired'), icon: 'none' }) return } @@ -132,11 +137,11 @@ Page({ wx.switchTab({ url: '/pages/index/index' }) }).catch(function (err) { self.setData({ loading: false }) - wx.showToast({ title: err.message || '保存失败', icon: 'none' }) + wx.showToast({ title: err.message || i18n.t('common.saveFailed'), icon: 'none' }) }) }, onAgreement: function () { - wx.showModal({ title: '提示', content: '用户协议和隐私政策内容建设中', showCancel: false }) + wx.showModal({ title: i18n.t('register.agreementTitle'), content: i18n.t('register.agreementContent'), showCancel: false }) } }) diff --git a/miniprogram/pages/register/register.wxml b/miniprogram/pages/register/register.wxml index 791a833..012113f 100644 --- a/miniprogram/pages/register/register.wxml +++ b/miniprogram/pages/register/register.wxml @@ -1,24 +1,24 @@ LumiFlow - 完善个人资料 + {{i18n.register.subtitle}} - 设置头像 + {{i18n.register.avatarSection}} - 点击更换 + {{i18n.register.changeAvatar}} - 设置昵称 + {{i18n.register.nicknameSection}} - + - 授权手机号 + {{i18n.register.authorizePhone}} @@ -28,16 +28,16 @@ - 手机号用于接收服务通知,必须授权 + {{i18n.register.phoneHint}} - 注册即表示同意《用户协议》和《隐私政策》 + {{i18n.register.agreement}} diff --git a/miniprogram/pages/scan/scan.js b/miniprogram/pages/scan/scan.js index 0b2133a..ae98541 100644 --- a/miniprogram/pages/scan/scan.js +++ b/miniprogram/pages/scan/scan.js @@ -1,4 +1,5 @@ var http = require('../../utils/request') +var i18n = require('../../i18n/index') Page({ data: { @@ -8,6 +9,10 @@ Page({ error: '' }, + onShow: function () { + i18n.bind(this) + }, + onBack: function () { wx.navigateBack({ fail: function () { @@ -31,7 +36,7 @@ Page({ success: function (res) { var deviceId = self.parseDeviceId(res.result) if (!deviceId) { - self.setData({ scanning: false, error: '无效的设备二维码' }) + self.setData({ scanning: false, error: i18n.t('scan.invalidQr') }) return } self.bindDevice(deviceId) @@ -66,12 +71,12 @@ Page({ }).catch(function (err) { self.setData({ scanning: false }) if (err && err.code === 2001) { - wx.showToast({ title: '已绑定设备', icon: 'none' }) + wx.showToast({ title: i18n.t('scan.alreadyBound'), icon: 'none' }) setTimeout(function () { wx.navigateBack() }, 1500) } else { - self.setData({ error: err.message || '绑定失败' }) + self.setData({ error: err.message || i18n.t('scan.bindFailed') }) } }) }, @@ -79,16 +84,16 @@ Page({ onManualInput: function () { var self = this wx.showModal({ - title: '手动输入设备号', + title: i18n.t('scan.manualInput'), editable: true, - placeholderText: '请输入设备ID,如 672B6D5A 4DCD861', + placeholderText: i18n.t('scan.manualPlaceholder'), success: function (res) { if (res.confirm && res.content) { var deviceId = self.parseDeviceId(res.content) if (deviceId) { self.bindDevice(deviceId) } else { - wx.showToast({ title: '设备号格式不正确', icon: 'none' }) + wx.showToast({ title: i18n.t('scan.invalidFormat'), icon: 'none' }) } } } diff --git a/miniprogram/pages/scan/scan.wxml b/miniprogram/pages/scan/scan.wxml index d77efd0..12bd6b1 100644 --- a/miniprogram/pages/scan/scan.wxml +++ b/miniprogram/pages/scan/scan.wxml @@ -1,20 +1,20 @@ - ‹ 返回 - 扫码绑定 - 扫描设备底部二维码 + ‹ {{i18n.common.back}} + {{i18n.scan.title}} + {{i18n.scan.subtitle}} 📷 - 扫描设备二维码 + {{i18n.scan.scanText}} - + {{error}} diff --git a/miniprogram/pages/subscribe-plans/subscribe-plans.js b/miniprogram/pages/subscribe-plans/subscribe-plans.js index bee9f51..e6860a7 100644 --- a/miniprogram/pages/subscribe-plans/subscribe-plans.js +++ b/miniprogram/pages/subscribe-plans/subscribe-plans.js @@ -1,4 +1,5 @@ var api = require('../../utils/api') +var i18n = require('../../i18n/index') Page({ data: { @@ -8,6 +9,7 @@ Page({ purchasing: false, subscription: null, subRemaining: 0, + subRemainingText: '', loadingPlans: true }, @@ -25,10 +27,18 @@ Page({ }, onShow: function () { + i18n.bind(this) this.loadPlans() this.loadSubscription() }, + planName: function (key) { + if (key === 'trial') return i18n.t('subPlans.planTrial') + if (key === 'monthly') return i18n.t('subPlans.planMonthly') + if (key === 'yearly') return i18n.t('subPlans.planYearly') + return key + }, + loadPlans: function () { var self = this self.setData({ loadingPlans: true }) @@ -41,16 +51,16 @@ Page({ var plans = serverPlans.map(function (p) { var daily = p.days > 0 ? (p.price / p.days).toFixed(1) : 0 var desc = '' - if (p.key === 'trial') desc = p.days + '天免费体验' - else if (p.key === 'yearly') desc = '省¥' + Math.round(monthlyPrice * 12 - p.price) - else desc = '约' + daily + '元/天' + if (p.key === 'trial') desc = i18n.t('subPlans.descTrial', { days: p.days }) + else if (p.key === 'yearly') desc = i18n.t('subPlans.descSave', { amount: Math.round(monthlyPrice * 12 - p.price) }) + else desc = i18n.t('subPlans.descDaily', { price: daily }) return { key: p.key, - name: p.name, + name: self.planName(p.key), price: p.price, - priceLabel: p.key === 'trial' ? '免费' : '¥' + p.price, + priceLabel: p.key === 'trial' ? i18n.t('subPlans.free') : '¥' + p.price, desc: desc, - tag: p.key === 'yearly' ? '推荐' : '', + tag: p.key === 'yearly' ? i18n.t('subPlans.tagRecommend') : '', disabled: false } }) @@ -61,9 +71,9 @@ Page({ self.setData({ loadingPlans: false, plans: [ - { key: 'trial', name: '试用', price: 0, priceLabel: '免费', desc: '7天免费体验', disabled: false }, - { key: 'monthly', name: '月卡', price: 99, priceLabel: '¥99', desc: '约3.3元/天' }, - { key: 'yearly', name: '年卡', price: 899, priceLabel: '¥899', desc: '省¥289', tag: '推荐' } + { key: 'trial', name: self.planName('trial'), price: 0, priceLabel: i18n.t('subPlans.free'), desc: i18n.t('subPlans.descTrial', { days: 7 }), disabled: false }, + { key: 'monthly', name: self.planName('monthly'), price: 99, priceLabel: '¥99', desc: i18n.t('subPlans.descDaily', { price: '3.3' }) }, + { key: 'yearly', name: self.planName('yearly'), price: 899, priceLabel: '¥899', desc: i18n.t('subPlans.descSave', { amount: 289 }), tag: i18n.t('subPlans.tagRecommend') } ] }) self.checkTrialUsed() @@ -75,7 +85,7 @@ Page({ var sub = self.data.subscription if (sub && sub.trial_used) { var plans = self.data.plans.map(function (p) { - if (p.key === 'trial') return Object.assign({}, p, { disabled: true, tag: '已使用' }) + if (p.key === 'trial') return Object.assign({}, p, { disabled: true, tag: i18n.t('subPlans.tagUsed') }) return p }) self.setData({ plans: plans }) @@ -86,16 +96,18 @@ Page({ loadSubscription: function () { var self = this api.getSubscription().then(function (sub) { + var remaining = sub.remaining_days || 0 self.setData({ subscription: sub, - subRemaining: sub.remaining_days || 0 + subRemaining: remaining, + subRemainingText: i18n.t('subPlans.daysValue', { days: remaining }) }) self.checkTrialUsed() }).catch(function () {}) }, onAgreement: function () { - wx.showModal({ title: '提示', content: '订阅协议内容建设中', showCancel: false }) + wx.showModal({ title: i18n.t('subPlans.tipTitle'), content: i18n.t('subPlans.agreementBuilding'), showCancel: false }) }, onSelect: function (e) { @@ -116,8 +128,8 @@ Page({ if (plan.key === 'trial') { wx.showModal({ - title: '激活试用', - content: '免费试用 ' + plan.desc + '?', + title: i18n.t('subPlans.activateTrialTitle'), + content: i18n.t('subPlans.activateTrialConfirm', { desc: plan.desc }), success: function (res) { if (res.confirm) self.doActivateTrial() } @@ -127,10 +139,10 @@ Page({ var isRenew = self.data.subscription && self.data.subscription.status === 'active' && self.data.subRemaining > 0 var planDays = plan.key === 'yearly' ? 365 : 30 - var title = isRenew ? '确认续费' : '确认支付' + var title = isRenew ? i18n.t('subPlans.confirmRenewTitle') : i18n.t('subPlans.confirmPayTitle') var content = isRenew - ? '在现有订阅基础上延长' + planDays + '天,支付 ¥' + plan.price - : '支付 ¥' + plan.price + ? i18n.t('subPlans.renewContent', { days: planDays, price: plan.price }) + : i18n.t('subPlans.payContent', { price: plan.price }) wx.showModal({ title: title, @@ -148,13 +160,13 @@ Page({ self.setData({ purchasing: true }) api.activateTrial().then(function () { self.setData({ purchasing: false }) - wx.showToast({ title: '试用已激活', icon: 'success' }) + wx.showToast({ title: i18n.t('subPlans.trialActivated'), icon: 'success' }) setTimeout(function () { wx.redirectTo({ url: '/pages/subscribe-success/subscribe-success?plan=trial' }) }, 1000) }).catch(function (err) { self.setData({ purchasing: false }) - wx.showToast({ title: err.message || '激活失败', icon: 'none' }) + wx.showToast({ title: err.message || i18n.t('subPlans.activateFailed'), icon: 'none' }) }) }, @@ -164,7 +176,7 @@ Page({ api.purchase(plan.key).then(function (data) { if (!data.payment_params) { self.setData({ purchasing: false }) - wx.showToast({ title: '支付服务暂不可用', icon: 'none' }) + wx.showToast({ title: i18n.t('subPlans.payUnavailable'), icon: 'none' }) return } @@ -182,13 +194,13 @@ Page({ }, fail: function (err) { self.setData({ purchasing: false }) - var msg = (err.errMsg || '').indexOf('cancel') > -1 ? '已取消支付' : '支付失败' + var msg = (err.errMsg || '').indexOf('cancel') > -1 ? i18n.t('subPlans.payCancelled') : i18n.t('subPlans.payFailed') wx.showToast({ title: msg, icon: 'none' }) } }) }).catch(function (err) { self.setData({ purchasing: false }) - wx.showToast({ title: err.message || '创建订单失败', icon: 'none' }) + wx.showToast({ title: err.message || i18n.t('subPlans.createOrderFailed'), icon: 'none' }) }) }, @@ -201,7 +213,7 @@ Page({ api.syncPaymentOrder(orderId).then(function (result) { if (result.status === 'paid') { self.setData({ purchasing: false }) - wx.showToast({ title: '支付成功', icon: 'success' }) + wx.showToast({ title: i18n.t('subPlans.paySuccess'), icon: 'success' }) setTimeout(function () { wx.redirectTo({ url: '/pages/subscribe-success/subscribe-success?plan=' + planKey }) }, 1000) @@ -210,7 +222,7 @@ Page({ setTimeout(pollSync, 2000) } else { self.setData({ purchasing: false }) - wx.showToast({ title: '支付处理中,请稍后在订阅页查看', icon: 'none' }) + wx.showToast({ title: i18n.t('subPlans.payProcessing'), icon: 'none' }) } }).catch(function () { if (retryCount < maxRetries) { @@ -218,7 +230,7 @@ Page({ setTimeout(pollSync, 2000) } else { self.setData({ purchasing: false }) - wx.showToast({ title: '支付处理中,请稍后在订阅页查看', icon: 'none' }) + wx.showToast({ title: i18n.t('subPlans.payProcessing'), icon: 'none' }) } }) } diff --git a/miniprogram/pages/subscribe-plans/subscribe-plans.wxml b/miniprogram/pages/subscribe-plans/subscribe-plans.wxml index 0ad9110..8d02d37 100644 --- a/miniprogram/pages/subscribe-plans/subscribe-plans.wxml +++ b/miniprogram/pages/subscribe-plans/subscribe-plans.wxml @@ -1,35 +1,35 @@ - ‹ 返回 - 订阅服务 - 解锁智能模式 + ‹ {{i18n.common.back}} + {{i18n.subPlans.title}} + {{i18n.subPlans.subtitle}} - 当前套餐 - {{subscription.plan === 'trial' ? '试用' : subscription.plan === 'monthly' ? '月卡' : subscription.plan === 'yearly' ? '年卡' : subscription.plan}} + {{i18n.subPlans.currentPlanLabel}} + {{subscription.plan === 'trial' ? i18n.subPlans.planTrial : subscription.plan === 'monthly' ? i18n.subPlans.planMonthly : subscription.plan === 'yearly' ? i18n.subPlans.planYearly : subscription.plan}} - 剩余天数 - {{subRemaining}}天 + {{i18n.subPlans.remainDaysLabel}} + {{subRemainingText}} - 选择订阅套餐 + {{i18n.subPlans.choosePlan}} - 加载套餐中... + {{i18n.subPlans.loadingPlans}} - 智能模式 - 智能自动调节 + {{i18n.subPlans.smartMode}} + {{i18n.subPlans.smartModeDesc}} @@ -44,9 +44,9 @@ - 支付即表示同意《订阅协议》 + {{i18n.subPlans.agreement}} diff --git a/miniprogram/pages/subscribe-prompt/subscribe-prompt.js b/miniprogram/pages/subscribe-prompt/subscribe-prompt.js index 98c8872..180878e 100644 --- a/miniprogram/pages/subscribe-prompt/subscribe-prompt.js +++ b/miniprogram/pages/subscribe-prompt/subscribe-prompt.js @@ -1,8 +1,14 @@ +var i18n = require('../../i18n/index') + Page({ data: { statusBarHeight: 44 }, + onShow: function () { + i18n.bind(this) + }, + onLoad: function () { var app = getApp() this.setData({ statusBarHeight: app.globalData.statusBarHeight }) diff --git a/miniprogram/pages/subscribe-prompt/subscribe-prompt.wxml b/miniprogram/pages/subscribe-prompt/subscribe-prompt.wxml index d60ad27..f342939 100644 --- a/miniprogram/pages/subscribe-prompt/subscribe-prompt.wxml +++ b/miniprogram/pages/subscribe-prompt/subscribe-prompt.wxml @@ -1,35 +1,35 @@ - ‹ 返回 - 使用设置 - 试用期已结束 + ‹ {{i18n.common.back}} + {{i18n.subPrompt.title}} + {{i18n.subPrompt.subtitle}} - 选择模式 + {{i18n.subPrompt.selectMode}} 🔄 - 普通模式 - 6色循环 + {{i18n.subPrompt.normalMode}} + {{i18n.subPrompt.normalModeSub}} 🔒 - 智能模式 - 订阅解锁 + {{i18n.subPrompt.smartMode}} + {{i18n.subPrompt.smartModeSub}} - 试用已结束 - 订阅后继续使用智能模式 + {{i18n.subPrompt.trialEndedTitle}} + {{i18n.subPrompt.trialEndedSub}} - - + + diff --git a/miniprogram/pages/subscribe-success/subscribe-success.js b/miniprogram/pages/subscribe-success/subscribe-success.js index d713def..c17e82a 100644 --- a/miniprogram/pages/subscribe-success/subscribe-success.js +++ b/miniprogram/pages/subscribe-success/subscribe-success.js @@ -1,9 +1,10 @@ var api = require('../../utils/api') +var i18n = require('../../i18n/index') Page({ data: { statusBarHeight: 44, - planName: '年卡会员', + planName: '', expiryDate: '' }, @@ -15,33 +16,56 @@ Page({ }) }, + onShow: function () { + i18n.bind(this) + this.render() + }, + + // Recompute locale-dependent display strings from stored raw values. + render: function () { + this.setData({ + planName: this.planNameFor(this._plan), + expiryDate: this._expireTime ? this.formatDate(this._expireTime) : '' + }) + }, + + planNameFor: function (plan) { + if (plan === 'trial') return i18n.t('subSuccess.planTrial') + if (plan === 'monthly') return i18n.t('subSuccess.planMonthly') + if (plan === 'yearly') return i18n.t('subSuccess.planYearly') + return i18n.t('subSuccess.planDefault') + }, + + formatDate: function (raw) { + var date = new Date(raw) + var y = date.getFullYear() + var m = ('0' + (date.getMonth() + 1)).slice(-2) + var d = ('0' + date.getDate()).slice(-2) + if (i18n.getLocale() === 'en') return y + '-' + m + '-' + d + return y + '年' + m + '月' + d + '日' + }, + onLoad: function (options) { var self = this var app = getApp() self.setData({ statusBarHeight: app.globalData.statusBarHeight }) - var planMap = { yearly: '年卡会员', monthly: '月卡会员', trial: '试用会员' } var plan = options.plan || 'yearly' - self.setData({ planName: planMap[plan] || '会员' }) + self._plan = plan // Fetch actual subscription expiry from server instead of computing client-side api.getSubscription().then(function (res) { if (res && res.expire_time) { - var date = new Date(res.expire_time) - var y = date.getFullYear() - var m = ('0' + (date.getMonth() + 1)).slice(-2) - var d = ('0' + date.getDate()).slice(-2) - self.setData({ expiryDate: y + '年' + m + '月' + d + '日' }) + self._expireTime = res.expire_time } + self.render() }).catch(function () { // Fallback: compute from current date if server call fails var durationMap = { yearly: 365, monthly: 30, trial: 7 } var now = new Date() now.setDate(now.getDate() + (durationMap[plan] || 365)) - var y = now.getFullYear() - var m = ('0' + (now.getMonth() + 1)).slice(-2) - var d = ('0' + now.getDate()).slice(-2) - self.setData({ expiryDate: y + '年' + m + '月' + d + '日' }) + self._expireTime = now.getTime() + self.render() }) }, diff --git a/miniprogram/pages/subscribe-success/subscribe-success.wxml b/miniprogram/pages/subscribe-success/subscribe-success.wxml index 5456556..fda0152 100644 --- a/miniprogram/pages/subscribe-success/subscribe-success.wxml +++ b/miniprogram/pages/subscribe-success/subscribe-success.wxml @@ -1,25 +1,25 @@ - ‹ 返回 - 订阅成功 - 欢迎使用智能模式 + ‹ {{i18n.common.back}} + {{i18n.subSuccess.title}} + {{i18n.subSuccess.subtitle}} - 订阅成功! + {{i18n.subSuccess.successTitle}} ✨ {{planName}} - 已订阅 + {{i18n.subSuccess.subscribed}} - 有效期至:{{expiryDate}} + {{i18n.subSuccess.validUntil}}{{expiryDate}} - - + + diff --git a/miniprogram/pages/treating/treating.js b/miniprogram/pages/treating/treating.js index 82d3607..85e811a 100644 --- a/miniprogram/pages/treating/treating.js +++ b/miniprogram/pages/treating/treating.js @@ -1,6 +1,7 @@ var ble = require('../../services/ble') var api = require('../../utils/api') var commandSync = require('../../services/command-sync') +var i18n = require('../../i18n/index') Page({ data: { statusBarHeight: 44, @@ -16,19 +17,31 @@ Page({ paused: false, completed: false, startedAt: 0, - regionText: '全区域', + regionText: '', fittingLost: false, deviceFault: false }, _getRegionText: function (regionMask) { - var REGION_MAP = {1:'右区', 2:'左区', 4:'上区', 8:'中区', 16:'下区', 32:'左上区', 64:'右上区'} - if (regionMask === 0x7F) return '全区域' + var REGION_MAP = { + 1: 'common.regions.right', + 2: 'common.regions.left', + 4: 'common.regions.top', + 8: 'common.regions.middle', + 16: 'common.regions.bottom', + 32: 'treating.regionTopLeft', + 64: 'treating.regionTopRight' + } + if (regionMask === 0x7F) return i18n.t('treating.allRegions') var names = [] for (var bit in REGION_MAP) { - if (regionMask & parseInt(bit)) names.push(REGION_MAP[bit]) + if (regionMask & parseInt(bit)) names.push(i18n.t(REGION_MAP[bit])) } - return names.length > 0 ? names.join('+') : '全区域' + return names.length > 0 ? names.join('+') : i18n.t('treating.allRegions') + }, + + onShow: function () { + i18n.bind(this) }, onLoad: function (options) { @@ -91,10 +104,10 @@ Page({ if (this.data.completed) return if (data.fitting === 0 && !this.data.fittingLost) { this.setData({ fittingLost: true, paused: true }) - wx.showToast({ title: '检测到离肤,请重新佩戴设备', icon: 'none', duration: 3000 }) + wx.showToast({ title: i18n.t('treating.fittingLost'), icon: 'none', duration: 3000 }) } else if (data.fitting === 1 && this.data.fittingLost) { this.setData({ fittingLost: false, paused: false }) - wx.showToast({ title: '已重新贴合,继续使用', icon: 'success', duration: 2000 }) + wx.showToast({ title: i18n.t('treating.fittingRestored'), icon: 'success', duration: 2000 }) } }, @@ -112,8 +125,8 @@ Page({ this.setData({ deviceFault: true }) var self = this wx.showModal({ - title: '设备故障', - content: '设备上报故障,已自动停止。', + title: i18n.t('treating.faultTitle'), + content: i18n.t('treating.faultContent'), showCancel: false, complete: function () { self.finishAsComplete() } }) @@ -136,8 +149,8 @@ Page({ if (self.data.battery > 0 && self.data.battery <= 5) { clearInterval(timer) wx.showModal({ - title: '电量过低', - content: '设备电量不足5%,已自动停止。请及时充电。', + title: i18n.t('treating.lowBatteryTitle'), + content: i18n.t('treating.lowBatteryContent'), showCancel: false, complete: function () { self.finishAsComplete() } }) @@ -146,7 +159,7 @@ Page({ if (self.data.battery > 0 && self.data.battery <= 10 && !self._lowBatteryWarned) { self._lowBatteryWarned = true - wx.showToast({ title: '电量低,请及时充电', icon: 'none', duration: 3000 }) + wx.showToast({ title: i18n.t('treating.lowBatteryWarn'), icon: 'none', duration: 3000 }) } if (remaining <= 0) { @@ -262,8 +275,8 @@ Page({ onException: function (err) { wx.showModal({ - title: '设备异常', - content: err.error_msg || '使用过程中出现异常', + title: i18n.t('treating.exceptionTitle'), + content: err.error_msg || i18n.t('treating.exceptionContent'), showCancel: false, complete: function () { wx.navigateBack() @@ -274,7 +287,7 @@ Page({ onDisconnect: function () { this.setData({ paused: true }) wx.showToast({ - title: '设备连接断开,正在重连...', + title: i18n.t('treating.disconnected'), icon: 'none', duration: 3000 }) @@ -283,7 +296,7 @@ Page({ onReconnect: function () { this.setData({ paused: false }) wx.showToast({ - title: '设备已重新连接', + title: i18n.t('treating.reconnected'), icon: 'success', duration: 2000 }) @@ -296,8 +309,8 @@ Page({ this._localTimer = null } wx.showModal({ - title: '连接丢失', - content: '设备蓝牙连接已断开,无法恢复。本次使用数据将保存。', + title: i18n.t('treating.reconnectFailedTitle'), + content: i18n.t('treating.reconnectFailedContent'), showCancel: false, complete: function () { self.finishAsComplete() @@ -312,8 +325,8 @@ Page({ onStop: function () { var self = this wx.showModal({ - title: '结束使用', - content: '确定要提前结束本次使用吗?', + title: i18n.t('treating.stopTitle'), + content: i18n.t('treating.stopContent'), success: function (res) { if (res.confirm) { ble.stopTreatment().then(function (res) { diff --git a/miniprogram/pages/treating/treating.wxml b/miniprogram/pages/treating/treating.wxml index 0c58602..554b027 100644 --- a/miniprogram/pages/treating/treating.wxml +++ b/miniprogram/pages/treating/treating.wxml @@ -1,14 +1,14 @@ - ‹ 返回 - 使用中 - 正在使用... + ‹ {{i18n.common.back}} + {{i18n.treating.title}} + {{i18n.treating.subtitle}} {{remainingText}} - 剩余时间 + {{i18n.treating.remainingLabel}} @@ -16,17 +16,17 @@ - {{mode === 1 ? '✨ 智能模式' : '🔄 普通模式'}} · {{regionText}} + {{mode === 1 ? i18n.treating.smartMode : i18n.treating.normalMode}} · {{regionText}} 💆 - 请放松心情 - 享受美好时光 + {{i18n.treating.relax1}} + {{i18n.treating.relax2}} - + diff --git a/miniprogram/pages/treatment-done/treatment-done.js b/miniprogram/pages/treatment-done/treatment-done.js index d9405fd..3172acf 100644 --- a/miniprogram/pages/treatment-done/treatment-done.js +++ b/miniprogram/pages/treatment-done/treatment-done.js @@ -1,5 +1,6 @@ var api = require('../../utils/api') var ble = require('../../services/ble') +var i18n = require('../../i18n/index') Page({ data: { @@ -15,6 +16,10 @@ Page({ synced: false }, + onShow: function () { + i18n.bind(this) + }, + onBack: function () { wx.reLaunch({ url: '/pages/index/index' }) }, @@ -33,7 +38,7 @@ Page({ regions: parseInt(options.regions) || 0, duration: durationMs, avgPd: options.avg_pd || 0, - durationText: mins > 0 ? mins + '分钟' : secs + '秒', + durationText: mins > 0 ? i18n.t('treatmentDone.durationMin', { min: mins }) : i18n.t('treatmentDone.durationSec', { sec: secs }), mode: parseInt(options.mode) || 0, regionNames: ble.getRegionName(parseInt(options.regions) || 0) }) diff --git a/miniprogram/pages/treatment-done/treatment-done.wxml b/miniprogram/pages/treatment-done/treatment-done.wxml index b026f28..81ec128 100644 --- a/miniprogram/pages/treatment-done/treatment-done.wxml +++ b/miniprogram/pages/treatment-done/treatment-done.wxml @@ -1,30 +1,30 @@ - ‹ 返回 - 使用完成 - 本次使用已结束 + ‹ {{i18n.common.back}} + {{i18n.treatmentDone.title}} + {{i18n.treatmentDone.headerSub}} - 使用完成! + {{i18n.treatmentDone.resultTitle}} {{durationText}} - 使用时长 + {{i18n.treatmentDone.durationLabel}} {{regionNames.length}} - 使用区域 + {{i18n.treatmentDone.regionLabel}} - 本次使用已记录 + {{i18n.treatmentDone.recorded}} - + diff --git a/miniprogram/pages/treatment-setup/treatment-setup.js b/miniprogram/pages/treatment-setup/treatment-setup.js index d821690..5716c0e 100644 --- a/miniprogram/pages/treatment-setup/treatment-setup.js +++ b/miniprogram/pages/treatment-setup/treatment-setup.js @@ -4,11 +4,11 @@ Page({ data: { statusBarHeight: 44, regions: [ - { name: '右区', mask: 0x01, checked: true }, - { name: '左区', mask: 0x02, checked: true }, - { name: '上区', mask: 0x04, checked: true }, - { name: '中区', mask: 0x08, checked: true }, - { name: '下区', mask: 0x10, checked: true } + { name: '', mask: 0x01, checked: true }, + { name: '', mask: 0x02, checked: true }, + { name: '', mask: 0x04, checked: true }, + { name: '', mask: 0x08, checked: true }, + { name: '', mask: 0x10, checked: true } ], selectedMode: 0, subExpired: false, @@ -34,6 +34,15 @@ Page({ var app = getApp() this.setData({ statusBarHeight: app.globalData.statusBarHeight }) i18n.bind(this) + var regionKeys = ['right', 'left', 'top', 'middle', 'bottom'] + var regions = this.data.regions + regions.forEach(function (r, i) { + r.name = i18n.t('common.regions.' + regionKeys[i]) + }) + this.setData({ + regions: regions, + subDaysText: i18n.t('setup.remainDays', { days: this.data.subDays }) + }) this.checkSubscription() }, @@ -43,7 +52,8 @@ Page({ http.get('/api/v1/subscription').then(function (sub) { self.setData({ subExpired: sub.status !== 'active', - subDays: sub.remaining_days || 0 + subDays: sub.remaining_days || 0, + subDaysText: i18n.t('setup.remainDays', { days: sub.remaining_days || 0 }) }) }).catch(function () {}) }, @@ -79,7 +89,7 @@ Page({ }) if (mask === 0) { - wx.showToast({ title: '请至少选择一个区域', icon: 'none' }) + wx.showToast({ title: i18n.t('setup.noRegion'), icon: 'none' }) return } @@ -109,7 +119,7 @@ Page({ '&mode=' + self.data.selectedMode }) }).catch(function (err) { - self.setData({ submitting: false, error: err.error_msg || '启动失败' }) + self.setData({ submitting: false, error: err.error_msg || i18n.t('setup.startFailed') }) }) }, diff --git a/miniprogram/pages/treatment-setup/treatment-setup.wxml b/miniprogram/pages/treatment-setup/treatment-setup.wxml index 0c9082e..c9ad2c5 100644 --- a/miniprogram/pages/treatment-setup/treatment-setup.wxml +++ b/miniprogram/pages/treatment-setup/treatment-setup.wxml @@ -1,40 +1,40 @@ - ‹ 返回 - 使用设置 - 选择模式和区域 + ‹ {{i18n.common.back}} + {{i18n.setup.title}} + {{i18n.setup.subtitle}} - 选择模式 + {{i18n.setup.selectMode}} 🔄 - 普通模式 - 6色循环 + {{i18n.setup.normalMode}} + {{i18n.setup.normalModeSub}} - 智能模式 - 剩余{{subDays}}天 - 订阅解锁 + {{i18n.setup.smartMode}} + {{subDaysText}} + {{i18n.setup.subscribeUnlock}} - 选择区域 - 普通模式固定 10 分钟,使用区域默认全区域,不可调整 + {{i18n.setup.selectRegion}} + {{i18n.setup.normalTip}} - 上区 - 左区 - 右区 - 中区 - 下区 + {{i18n.common.regions.top}} + {{i18n.common.regions.left}} + {{i18n.common.regions.right}} + {{i18n.common.regions.middle}} + {{i18n.common.regions.bottom}} {{i18n.manual.entryLink}} diff --git a/miniprogram/pages/wear-check/wear-check.js b/miniprogram/pages/wear-check/wear-check.js index 8d9eac2..68beb83 100644 --- a/miniprogram/pages/wear-check/wear-check.js +++ b/miniprogram/pages/wear-check/wear-check.js @@ -1,4 +1,5 @@ var ble = require('../../services/ble') +var i18n = require('../../i18n/index') Page({ data: { @@ -8,6 +9,10 @@ Page({ reconnecting: false }, + onShow: function () { + i18n.bind(this) + }, + onBack: function () { wx.navigateBack({ fail: function () { @@ -28,7 +33,7 @@ Page({ onNext: function () { if (!ble.isConnected()) { - wx.showToast({ title: '设备未连接', icon: 'none' }) + wx.showToast({ title: i18n.t('common.deviceNotConnected'), icon: 'none' }) return } wx.redirectTo({ @@ -51,18 +56,18 @@ Page({ onConnected: function () { clearTimeout(self._reconnectTimer) self.setData({ connected: true, reconnecting: false }) - wx.showToast({ title: '连接成功', icon: 'success' }) + wx.showToast({ title: i18n.t('wearCheck.connectSuccess'), icon: 'success' }) }, onError: function (err) { clearTimeout(self._reconnectTimer) self.setData({ reconnecting: false }) - wx.showToast({ title: err.msg || '连接失败', icon: 'none' }) + wx.showToast({ title: err.msg || i18n.t('wearCheck.connectFailed'), icon: 'none' }) } }) self._reconnectTimer = setTimeout(function () { ble.stopScan() self.setData({ reconnecting: false }) - wx.showToast({ title: '搜索超时', icon: 'none' }) + wx.showToast({ title: i18n.t('wearCheck.searchTimeout'), icon: 'none' }) }, 5000) }, 500) }, diff --git a/miniprogram/pages/wear-check/wear-check.wxml b/miniprogram/pages/wear-check/wear-check.wxml index c61b7ca..4684796 100644 --- a/miniprogram/pages/wear-check/wear-check.wxml +++ b/miniprogram/pages/wear-check/wear-check.wxml @@ -1,8 +1,8 @@ - ‹ 返回 - 确认佩戴 - 请确保设备正确佩戴 + ‹ {{i18n.common.back}} + {{i18n.wearCheck.title}} + {{i18n.wearCheck.subtitle}} @@ -11,24 +11,24 @@ LumiFlow - 已连接 - 未连接 + {{i18n.wearCheck.connected}} + {{i18n.wearCheck.disconnected}} - 电量 {{battery}}% + {{i18n.wearCheck.battery}} {{battery}}% - 佩戴指引 - 设备佩戴示意图 + {{i18n.wearCheck.guideTitle}} + {{i18n.wearCheck.guideImg}} - 1. 取出设备,展开弹性绑带 - 2. 将设备正确佩戴 - 3. 调节绑带至舒适位置 + {{i18n.wearCheck.step1}} + {{i18n.wearCheck.step2}} + {{i18n.wearCheck.step3}} - - + +