refactor: 国际化文本迁移至全局 locales/messages.js

将组件级 i18n 对象重构为统一由全局 locales/messages.js 管理,确保中英文语言切换时正确显示对应文本。

- 新增 utils/i18n.js 国际化工具函数
- 更新 store/$t.mixin.js 翻译混入逻辑
- 迁移 pkgService、pkgBooking、pkgAccount、pkgExplore、pages 等共 58 个组件的中英文文本至全局消息表
This commit is contained in:
liangjian
2026-07-24 13:43:41 +08:00
parent 445bd850f4
commit 6e721ccc7e
58 changed files with 1810 additions and 4065 deletions

View File

@@ -1,4 +1,4 @@
<template>
<template>
<view class="profile-page tn-safe-area-inset-bottom">
<!-- 头部背景与用户信息 (悬浮质感设计) -->
@@ -43,7 +43,7 @@
</view>
<view class="tn-margin-left-md">
<view class="user-name clamp-text-1">
{{ t('guest') }}
{{ $tr('游客') }}
</view>
<view class="tn-color-gray tn-text-sm tn-margin-top-xs">{{ guestHeaderDesc }}</view>
</view>
@@ -62,17 +62,17 @@
<view class="stats-row tn-flex tn-flex-row-between">
<view class="stat-item">
<view class="stat-value">{{ getStayDaysText() }}</view>
<view class="stat-label">{{ t('daysIn') }}</view>
<view class="stat-label">{{ $tr('入住天数') }}</view>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<view class="stat-value">{{ getActivityCountText() }}</view>
<view class="stat-label">{{ t('activities') }}</view>
<view class="stat-label">{{ $tr('参与活动') }}</view>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<view class="stat-value">{{ getPointsText() }}</view>
<view class="stat-label">{{ t('points') }}</view>
<view class="stat-label">{{ $tr('积分') }}</view>
</view>
</view>
</view>
@@ -84,40 +84,40 @@
<view class="guest-registration-card tn-padding-lg tn-margin-bottom-lg" v-if="!isLogin">
<view class="tn-flex tn-flex-row-between tn-flex-col-center">
<view>
<view class="tn-text-bold tn-text-lg tn-color-black">{{ t('registrationRecordTitle') }}</view>
<view class="tn-text-bold tn-text-lg tn-color-black">{{ $tr('注册记录') }}</view>
<view class="tn-margin-top-sm tn-text-sm tn-color-gray">
{{ registrationApplication ? t('registrationRecordSubmittedDesc') : t('registrationRecordGuestDesc') }}
{{ registrationApplication ? $tr('当前微信账号已提交注册申请,可查看历史记录与审批状态。') : $tr('未登录也可查看当前微信账号提交的注册申请记录。') }}
</view>
</view>
<view class="custom-btn btn-primary guest-registration-btn" @click="goToRegistrationRecords">
<text class="tn-text-sm tn-text-bold">{{ t('viewNow') }}</text>
<text class="tn-text-sm tn-text-bold">{{ $tr('立即查看') }}</text>
</view>
</view>
</view>
<view class="application-status-card tn-padding-lg tn-margin-bottom-lg" v-if="isLogin && pendingContractCount">
<view class="tn-flex tn-flex-row-between tn-flex-col-center">
<view class="tn-text-bold tn-text-lg tn-color-black">{{ t('contractStatusTitle') }}</view>
<view class="tn-text-bold tn-text-lg tn-color-black">{{ $tr('合同状态') }}</view>
<view class="status-tag status-pending">
{{ t('contractPendingTag') + ' ' + pendingContractCount }}
{{ $tr('待签约') + ' ' + pendingContractCount }}
</view>
</view>
<view class="tn-margin-top-sm tn-color-gray tn-text-sm">
{{ t('contractPendingDesc') }}
{{ $tr('您当前有待签署合同,请尽快查看并完成签约。') }}
</view>
<view class="tn-margin-top tn-flex tn-flex-row-between tn-flex-col-center">
<view class="tn-color-gray tn-text-xs">
{{ t('pendingCountText') + ':' + pendingContractCount }}
{{ $tr('待签合同') + ':' + pendingContractCount }}
</view>
<view class="custom-btn btn-primary" style="padding: 8rpx 28rpx;" @click="goToContractList">
<text class="tn-text-sm tn-text-bold">{{ t('viewDetail') }}</text>
<text class="tn-text-sm tn-text-bold">{{ $tr('查看详情') }}</text>
</view>
</view>
</view>
<!-- 核心服务 (宫格) -->
<view class="core-services-card tn-padding-lg tn-margin-bottom-lg" v-if="isLogin">
<view class="tn-text-bold tn-text-lg tn-color-black tn-margin-bottom">{{ t('coreServices') }}</view>
<view class="tn-text-bold tn-text-lg tn-color-black tn-margin-bottom">{{ $tr('我的服务') }}</view>
<view class="tn-flex tn-flex-row-between">
<view
class="core-service-item tn-flex tn-flex-direction-column tn-flex-col-center"
@@ -128,7 +128,7 @@
<view class="service-icon-box tn-flex tn-flex-col-center tn-flex-row-center">
<text :class="item.icon" class="service-icon-symbol"></text>
</view>
<text class="tn-margin-top-sm tn-text-sm tn-color-black">{{ t(item.i18nKey) }}</text>
<text class="tn-margin-top-sm tn-text-sm tn-color-black">{{ $tr(item.i18nKey) }}</text>
</view>
</view>
</view>
@@ -146,16 +146,16 @@
<text class="tn-margin-left-sm tn-text-md tn-color-black tn-text-bold">{{ getMenuLabel(item) }}</text>
</view>
<view class="tn-flex tn-flex-col-center">
<view v-if="item.available === false" class="menu-coming-soon">{{ t('comingSoon') }}</view>
<view v-if="item.available === false" class="menu-coming-soon">{{ $tr('建设中') }}</view>
<text class="tn-icon-right menu-arrow"></text>
</view>
</view>
<view class="menu-item tn-flex tn-flex-row-between tn-flex-col-center" @click="handleLanguageToggle">
<view class="tn-flex tn-flex-col-center">
<view class="menu-icon"><text class="tn-icon-set menu-icon-symbol"></text></view>
<text class="tn-margin-left-sm tn-text-md tn-color-black tn-text-bold">{{ t('languageSwitch') }}</text>
<text class="tn-margin-left-sm tn-text-md tn-color-black tn-text-bold">{{ $tr('语言切换') }}</text>
</view>
<text class="tn-text-sm tn-color-gray">{{ t('languageToggleLabel') }}</text>
<text class="tn-text-sm tn-color-gray">{{ $tr('EN') }}</text>
</view>
</view>
@@ -163,7 +163,7 @@
<!-- 退出登录 -->
<view class="tn-margin-top-xl tn-text-center" v-if="isLogin">
<view class="custom-btn btn-danger" style="width: 80%; height: 90rpx;" @click="handleLogout">
<text class="tn-text-bold">{{ t('logout') }}</text>
<text class="tn-text-bold">{{ $tr('退出登录') }}</text>
</view>
</view>
@@ -192,7 +192,7 @@ export default {
return typeof this.vuex_custom_bar_height === 'number' ? this.vuex_custom_bar_height : 0
},
displayUserName() {
return this.userInfo.name || this.userInfo.account || this.userInfo.username || this.userInfo.mobile || this.t('userFallback')
return this.userInfo.name || this.userInfo.account || this.userInfo.username || this.userInfo.mobile || this.$tr('用户')
},
displayUserInitial() {
const firstChar = this.userInfo.firstChar
@@ -217,21 +217,21 @@ export default {
},
guestHeaderDesc() {
return this.registrationApplication
? `${this.t('registrationStatusTitle')}:${this.getRegistrationStatusText(this.registrationStatus)}`
: this.t('clickToLogin')
? `${this.$tr('注册申请进度')}:${this.getRegistrationStatusText(this.registrationStatus)}`
: this.$tr('点击登录')
},
registrationStatusDesc() {
if (!this.registrationApplication) return this.t('clickToLogin')
if (!this.registrationApplication) return this.$tr('点击登录')
if (this.registrationStatus === 'pending') {
return this.t('registrationPendingDesc')
return this.$tr('注册申请审核中,审批通过后才可登录')
}
if (this.registrationStatus === 'approved') {
return this.t('registrationApprovedDesc')
return this.$tr('注册申请已通过,可前往登录')
}
if (this.registrationStatus === 'rejected') {
return this.registrationApplication.approveReason || this.t('registrationRejectedDesc')
return this.registrationApplication.approveReason || this.$tr('注册申请已驳回,请查看原因后重新提交')
}
return this.t('registrationEmptyDesc')
return this.$tr('暂未提交注册申请')
},
currentBookingCard() {
if (!this.isLogin) {
@@ -272,119 +272,11 @@ export default {
{ key: 'butler', label: '联系管家', labelEn: 'Contact Butler', icon: 'tn-icon-service-fill', title: '联系管家', titleEn: 'Contact Butler', desc: '联系专属管家,沟通入住和住中服务事项。', descEn: 'Contact your butler about move-in and in-stay services.', available: true }
],
coreServices: [
{ key: 'application', i18nKey: 'application', icon: 'tn-icon-edit-form' },
{ key: 'bookingList', i18nKey: 'bookingList', icon: 'tn-icon-order-fill' },
{ key: 'contract', i18nKey: 'contract', icon: 'tn-icon-copy' },
{ key: 'bill', i18nKey: 'bill', icon: 'tn-icon-money' }
{ key: 'application', i18nKey: '入住申请', icon: 'tn-icon-edit-form' },
{ key: 'bookingList', i18nKey: '预订记录', icon: 'tn-icon-order-fill' },
{ key: 'contract', i18nKey: '我的合同', icon: 'tn-icon-copy' },
{ key: 'bill', i18nKey: '账单', icon: 'tn-icon-money' }
],
i18n: {
zh: {
edit: '编辑资料',
guest: '游客',
clickToLogin: '点击登录',
daysIn: '入住天数',
activities: '参与活动',
points: '积分',
applicationStatus: '申请进度',
registrationStatusTitle: '注册申请进度',
notSubmittedYet: '暂未提交注册申请',
registrationPendingDesc: '注册申请审核中,审批通过后才可登录',
registrationApprovedDesc: '注册申请已通过,可前往登录',
registrationRejectedDesc: '注册申请已驳回,请查看原因后重新提交',
registrationEmptyDesc: '暂未提交注册申请',
registrationRecordTitle: '注册记录',
registrationRecordSubmittedDesc: '当前微信账号已提交注册申请,可查看历史记录与审批状态。',
registrationRecordGuestDesc: '未登录也可查看当前微信账号提交的注册申请记录。',
viewNow: '立即查看',
statusPending: '审核中',
statusApproved: '已通过',
statusRejected: '已拒绝',
remind: '催一下',
done: '已完成',
viewDetail: '查看详情',
exclusiveButler: '专属管家',
onlineService: '24小时在线服务',
contact: '联系',
application: '入住申请',
bookingList: '预订记录',
bookingStatusTitle: '预订审核进度',
contractStatusTitle: '合同状态',
bookingNo: '预定单号',
bookingPlaceholder: '支付后生成的预定单会显示在这里',
bookingProgressDesc: '支付完成后会进入审核,审核通过后分配管家并等待分房号。',
contractPendingTag: '待签约',
contractPendingDesc: '您当前有待签署合同,请尽快查看并完成签约。',
pendingCountText: '待签合同',
contract: '我的合同',
bill: '账单',
coreServices: '我的服务',
comingSoon: '建设中',
settings: '偏好设置',
languageSwitch: '语言切换',
languageToggleLabel: 'EN',
logout: '退出登录',
logoutConfirmTitle: '提示',
logoutConfirmContent: '确定要退出登录吗?',
logoutSuccess: '已退出',
userFallback: '用户',
submitRequest: '提交申请',
completeFormBeforeSubmit: '请完善表单信息后提交。',
comingSoonDesc: '{title} 功能正在建设中,后续开放后会在这里提供正式入口和数据。'
},
en: {
edit: 'Edit',
guest: 'Guest',
clickToLogin: 'Click to Sign In',
daysIn: 'Days Stayed',
activities: 'Activities',
points: 'Points',
applicationStatus: 'Application Status',
registrationStatusTitle: 'Registration Status',
notSubmittedYet: 'No registration submitted',
registrationPendingDesc: 'Registration is under review',
registrationApprovedDesc: 'Registration approved, ready to sign in',
registrationRejectedDesc: 'Registration rejected, please review the reason',
registrationEmptyDesc: 'No registration submitted',
registrationRecordTitle: 'Registration Records',
registrationRecordSubmittedDesc: 'A registration has been submitted with this Wechat account. You can review its history and approval status.',
registrationRecordGuestDesc: 'You can still review registration records submitted with this Wechat account before signing in.',
viewNow: 'View Now',
statusPending: 'Under Review',
statusApproved: 'Approved',
statusRejected: 'Rejected',
remind: 'Remind',
done: 'Done',
viewDetail: 'Details',
exclusiveButler: 'Exclusive Butler',
onlineService: '24/7 Online Service',
contact: 'Contact',
application: 'Applications',
bookingList: 'Bookings',
bookingStatusTitle: 'Booking Progress',
contractStatusTitle: 'Contract Status',
bookingNo: 'Booking No.',
bookingPlaceholder: 'Your booking will appear here after payment',
bookingProgressDesc: 'Booking will be reviewed after payment. Butler will be assigned upon approval.',
contractPendingTag: 'Pending',
contractPendingDesc: 'You have contracts waiting for signature. Please review them soon.',
pendingCountText: 'Pending Contracts',
contract: 'My Contract',
bill: 'Billing',
coreServices: 'My Services',
comingSoon: 'Soon',
settings: 'Preferences',
languageSwitch: 'Language',
languageToggleLabel: '中文',
logout: 'Log Out',
logoutConfirmTitle: 'Notice',
logoutConfirmContent: 'Are you sure to log out?',
logoutSuccess: 'Logged out',
userFallback: 'User',
submitRequest: 'Submit Request',
completeFormBeforeSubmit: 'Please complete the form before submitting.',
comingSoonDesc: '{title} is under development. The formal entry and data will be available here later.'
}
}
}
},
async mounted() {
@@ -398,9 +290,6 @@ export default {
else if (key === 'contract') this.goToContractList();
else if (key === 'bill') this.goToUtilityRecharge();
},
t(key, params) {
return this.$tm('pages.index.component.ProfileCenterTab', key, params)
},
getMenuLabel(item = {}) {
return this.language === 'en'
? (item.labelEnShort || item.labelEn || item.label || '')
@@ -511,14 +400,14 @@ export default {
},
handleLogout() {
uni.showModal({
title: this.t('logoutConfirmTitle'),
content: this.t('logoutConfirmContent'),
title: this.$tr('提示'),
content: this.$tr('确定要退出登录吗?'),
success: (res) => {
if (res.confirm) {
clearLoginSession()
this.checkLoginStatus();
this.$parent.changeTabbar && this.$parent.changeTabbar(0, 'select-room');
uni.showToast({ title: this.t('logoutSuccess'), icon: 'success' });
uni.showToast({ title: this.$tr('已退出'), icon: 'success' });
}
}
});
@@ -531,13 +420,13 @@ export default {
},
getRegistrationStatusText(status) {
if (this.registrationApplication && typeof this.registrationApplication.approvalStatus === 'number') {
return getApprovalStatusLabel(this.registrationApplication.approvalStatus, this.t('notSubmittedYet'))
return getApprovalStatusLabel(this.registrationApplication.approvalStatus, this.$tr('暂未提交注册申请'))
}
const map = {
unsubmitted: this.t('notSubmittedYet'),
pending: this.t('statusPending'),
approved: this.t('statusApproved'),
rejected: this.t('statusRejected')
unsubmitted: this.$tr('暂未提交注册申请'),
pending: this.$tr('审核中'),
approved: this.$tr('已通过'),
rejected: this.$tr('已拒绝')
}
return map[status] || map.unsubmitted
},
@@ -581,7 +470,7 @@ export default {
},
goToSubmitRequest(title, desc, payload = {}, titleZh = '', titleEn = '', descZh = '', descEn = '') {
uni.navigateTo({
url: `/pkgService/submit_request/submit_request?title=${encodeURIComponent(title || this.t('submitRequest'))}&titleZh=${encodeURIComponent(titleZh || title || this.t('submitRequest'))}&titleEn=${encodeURIComponent(titleEn || title || this.t('submitRequest'))}&desc=${encodeURIComponent(desc || this.t('completeFormBeforeSubmit'))}&descZh=${encodeURIComponent(descZh || desc || this.t('completeFormBeforeSubmit'))}&descEn=${encodeURIComponent(descEn || desc || this.t('completeFormBeforeSubmit'))}&payload=${encodeURIComponent(JSON.stringify(payload || {}))}`
url: `/pkgService/submit_request/submit_request?title=${encodeURIComponent(title || this.$tr('提交申请'))}&titleZh=${encodeURIComponent(titleZh || title || this.$tr('提交申请'))}&titleEn=${encodeURIComponent(titleEn || title || this.$tr('提交申请'))}&desc=${encodeURIComponent(desc || this.$tr('请完善表单信息后提交。'))}&descZh=${encodeURIComponent(descZh || desc || this.$tr('请完善表单信息后提交。'))}&descEn=${encodeURIComponent(descEn || desc || this.$tr('请完善表单信息后提交。'))}&payload=${encodeURIComponent(JSON.stringify(payload || {}))}`
})
},
handleApplicationEntry() {
@@ -627,9 +516,9 @@ export default {
}, itemTitleZh, itemTitleEn, itemDescZh, itemDescEn)
return
}
const comingSoonDesc = this.t('comingSoonDesc', { title: itemTitle })
const comingSoonDescZh = this.$tm('pages.index.component.ProfileCenterTab', 'comingSoonDesc', { title: itemTitleZh || itemTitle })
const comingSoonDescEn = this.$tm('pages.index.component.ProfileCenterTab', 'comingSoonDesc', { title: itemTitleEn || itemTitle })
const comingSoonDesc = this.$tr('{title} 功能正在建设中,后续开放后会在这里提供正式入口和数据。', { title: itemTitle })
const comingSoonDescZh = this.$tr('{title} 功能正在建设中,后续开放后会在这里提供正式入口和数据。', { title: itemTitleZh || itemTitle })
const comingSoonDescEn = this.$tr('{title} 功能正在建设中,后续开放后会在这里提供正式入口和数据。', { title: itemTitleEn || itemTitle })
uni.navigateTo({
url: `/pkgService/service_stub/service_stub?title=${encodeURIComponent(itemTitle)}&titleZh=${encodeURIComponent(itemTitleZh || itemTitle)}&titleEn=${encodeURIComponent(itemTitleEn || itemTitle)}&desc=${encodeURIComponent(comingSoonDesc)}&descZh=${encodeURIComponent(comingSoonDescZh)}&descEn=${encodeURIComponent(comingSoonDescEn)}&key=${item.key}`
});