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,7 +1,7 @@
<template>
<view class="application-detail-page tn-safe-area-inset-bottom">
<tn-nav-bar :isBack="true" :bottomShadow="false" backgroundColor="transparent">
<view class="tn-text-bold tn-text-xl tn-color-black">{{ t('navTitle') }}</view>
<view class="tn-text-bold tn-text-xl tn-color-black">{{ $tr('申请详情') }}</view>
</tn-nav-bar>
<view class="page-main tn-padding" :style="{ paddingTop: vuex_custom_bar_height + 'px', paddingBottom: '48rpx' }">
@@ -35,54 +35,54 @@
<text :class="shouldPayDeposit(detail) ? 'tn-icon-warning-fill' : 'tn-icon-time-fill'"></text>
</view>
<view class="status-reminder-panel__content">
<view class="status-reminder-panel__title">{{ t('statusReminderTitle') }}</view>
<view class="status-reminder-panel__title">{{ $tr('当前进度提醒') }}</view>
<view class="status-reminder-panel__text">{{ statusReminderText }}</view>
</view>
</view>
<view class="content-panel tn-margin-bottom-lg">
<view class="panel-title">{{ t('basicInfoTitle') }}</view>
<view class="panel-title">{{ $tr('基础信息') }}</view>
<view class="meta-row tn-margin-top">
<text class="meta-label">{{ t('applicationCodeLabel') }}</text>
<text class="meta-label">{{ $tr('申请编号') }}</text>
<view class="meta-action-wrap">
<text class="meta-value">{{ detail.detailCode || '--' }}</text>
<view v-if="detail.detailCode" class="copy-btn" @click="copyCode">
<text class="tn-text-xs tn-text-bold">{{ t('copy') }}</text>
<text class="tn-text-xs tn-text-bold">{{ $tr('复制') }}</text>
</view>
</view>
</view>
<view class="meta-row">
<text class="meta-label">{{ t('applicationTypeLabel') }}</text>
<text class="meta-label">{{ $tr('申请类型') }}</text>
<text class="meta-value">{{ applicationTypeText }}</text>
</view>
<view class="meta-row">
<text class="meta-label">{{ t('statusLabel') }}</text>
<text class="meta-label">{{ $tr('当前状态') }}</text>
<text class="meta-value">{{ statusText }}</text>
</view>
<view class="meta-row">
<text class="meta-label">{{ t('applicantLabel') }}</text>
<text class="meta-label">{{ $tr('申请人') }}</text>
<text class="meta-value">{{ detail.userName || detail.phone || '--' }}</text>
</view>
<view class="meta-row">
<text class="meta-label">{{ t('apartmentLabel') }}</text>
<text class="meta-label">{{ $tr('所属公寓') }}</text>
<text class="meta-value">{{ detail.intendedAreaName || '--' }}</text>
</view>
<view class="meta-row" v-if="detail.intendedRoomTypeName">
<text class="meta-label">{{ isViewingApplication ? t('intendedRoomTypeLabel') : t('appliedRoomTypeLabel') }}</text>
<text class="meta-label">{{ isViewingApplication ? $tr('意向房型') : $tr('申请房型') }}</text>
<text class="meta-value">{{ detail.intendedRoomTypeName }}</text>
</view>
<view class="meta-row">
<text class="meta-label">{{ isViewingApplication ? t('viewingTimeLabel') : t('leaseTermLabel') }}</text>
<text class="meta-label">{{ isViewingApplication ? $tr('预约时间') : $tr('预计租期') }}</text>
<text class="meta-value">{{ displayDateRange }}</text>
</view>
<view class="meta-row">
<text class="meta-label">{{ t('submittedAtLabel') }}</text>
<text class="meta-label">{{ $tr('提交时间') }}</text>
<text class="meta-value">{{ formatDateTime(detail.createTime) }}</text>
</view>
</view>
<view class="content-panel tn-margin-bottom-lg" v-if="viewingMeta.length">
<view class="panel-title">{{ t('viewingInfoTitle') }}</view>
<view class="panel-title">{{ $tr('带看信息') }}</view>
<view
v-for="item in viewingMeta"
:key="item.label"
@@ -94,7 +94,7 @@
</view>
<view class="content-panel tn-margin-bottom-lg">
<view class="panel-title">{{ isViewingApplication ? t('applicationRemarkTitle') : t('remarkTitle') }}</view>
<view class="panel-title">{{ isViewingApplication ? $tr('申请说明') : $tr('补充说明') }}</view>
<view class="remark-panel tn-margin-top">
<view
v-for="(line, index) in remarkLines"
@@ -108,7 +108,7 @@
<view class="action-row">
<view class="ghost-btn" @click="goBackList">
<text class="tn-text-bold">{{ t('backList') }}</text>
<text class="tn-text-bold">{{ $tr('返回列表') }}</text>
</view>
<view
v-if="canCancelOrder"
@@ -116,7 +116,7 @@
:class="{ 'danger-btn--loading': canceling }"
@click.stop="handleCancelOrder"
>
<text class="tn-text-bold">{{ canceling ? t('cancelOrderLoading') : t('cancelOrder') }}</text>
<text class="tn-text-bold">{{ canceling ? $tr('取消中...') : $tr('取消订单') }}</text>
</view>
<view
v-if="currentStepActionText"
@@ -130,14 +130,14 @@
class="action-btn action-btn--ghost"
@click.stop="refreshCurrentPage"
>
<text class="tn-text-bold">{{ t('refreshAction') }}</text>
<text class="tn-text-bold">{{ $tr('刷新') }}</text>
</view>
<view
v-else-if="canViewBill"
class="action-btn"
@click.stop="goToBillPage"
>
<text class="tn-text-bold">{{ t('viewBill') }}</text>
<text class="tn-text-bold">{{ $tr('查看关联账单') }}</text>
</view>
</view>
</view>
@@ -221,112 +221,6 @@ function parseJsonStringMaybe(value) {
}
export default {
i18n: {
zh: {
navTitle: '申请详情',
basicInfoTitle: '基础信息',
applicationCodeLabel: '申请编号',
copy: '复制',
applicationTypeLabel: '申请类型',
statusLabel: '当前状态',
applicantLabel: '申请人',
apartmentLabel: '所属公寓',
intendedRoomTypeLabel: '意向房型',
appliedRoomTypeLabel: '申请房型',
viewingTimeLabel: '预约时间',
leaseTermLabel: '预计租期',
submittedAtLabel: '提交时间',
viewingInfoTitle: '带看信息',
applicationRemarkTitle: '申请说明',
remarkTitle: '补充说明',
backList: '返回列表',
viewBill: '查看关联账单',
viewingApplicationTitle: '预约看房申请',
stayApplicationTitle: '入住申请',
viewingApplicationType: '预约看房',
stayApplicationType: '入住申请',
statusPending: '待审核',
statusApproved: '已通过',
statusRejected: '已拒绝',
statusFinished: '已结束',
statusProcessing: '处理中',
statusPendingPayment: '请支付定金',
statusWaitingRoomAssign: '等待预订中心分配房间',
statusReminderTitle: '当前进度提醒',
emptyRemark: '暂无补充说明',
codeCopied: '申请编号已复制',
missingBillCode: '申请单编号缺失',
missingContractNo: '合同编号缺失',
checkinPendingHint: '宿管正在办理入住,请耐心等待',
refreshAction: '刷新',
cancelOrder: '取消订单',
cancelOrderLoading: '取消中...',
cancelOrderTitle: '取消订单',
cancelOrderContent: '取消后将关闭当前未支付的定金订单,是否继续?',
cancelOrderSuccess: '订单已取消',
cancelOrderFailed: '取消订单失败',
viewingTimeKey: '看房时间',
leaseDurationKey: '预计租住时长',
budgetKey: '租金预算',
commuteKey: '工作/通勤地点',
preferredAreaKey: '意向区域',
preferredRoomTypeKey: '意向房型',
paymentMethodKey: '支付方式',
dateRangeJoiner: ' 至 '
},
en: {
navTitle: 'Application Detail',
basicInfoTitle: 'Basic Information',
applicationCodeLabel: 'Application No.',
copy: 'Copy',
applicationTypeLabel: 'Application Type',
statusLabel: 'Status',
applicantLabel: 'Applicant',
apartmentLabel: 'Apartment',
intendedRoomTypeLabel: 'Preferred Room Type',
appliedRoomTypeLabel: 'Requested Room Type',
viewingTimeLabel: 'Viewing Time',
leaseTermLabel: 'Lease Term',
submittedAtLabel: 'Submitted At',
viewingInfoTitle: 'Viewing Details',
applicationRemarkTitle: 'Application Notes',
remarkTitle: 'Remarks',
backList: 'Back to List',
viewBill: 'View Related Bill',
viewingApplicationTitle: 'Viewing Request',
stayApplicationTitle: 'Stay Application',
viewingApplicationType: 'Viewing Request',
stayApplicationType: 'Stay Application',
statusPending: 'Pending',
statusApproved: 'Approved',
statusRejected: 'Rejected',
statusFinished: 'Closed',
statusProcessing: 'Processing',
statusPendingPayment: 'Please Pay Deposit',
statusWaitingRoomAssign: 'Waiting for Room Assignment',
statusReminderTitle: 'Current Progress',
emptyRemark: 'No additional remarks',
codeCopied: 'Application number copied',
missingBillCode: 'Missing application bill number',
missingContractNo: 'Missing contract number',
checkinPendingHint: 'Move-in is being processed, please wait',
refreshAction: 'Refresh',
cancelOrder: 'Cancel Order',
cancelOrderLoading: 'Canceling...',
cancelOrderTitle: 'Cancel Order',
cancelOrderContent: 'This will close the current unpaid deposit order. Continue?',
cancelOrderSuccess: 'Order canceled',
cancelOrderFailed: 'Failed to cancel order',
viewingTimeKey: 'Viewing Time',
leaseDurationKey: 'Expected Stay Duration',
budgetKey: 'Budget',
commuteKey: 'Work / Commute Location',
preferredAreaKey: 'Preferred Area',
preferredRoomTypeKey: 'Preferred Room Type',
paymentMethodKey: 'Payment Method',
dateRangeJoiner: ' to '
}
},
data() {
return {
detailCode: '',
@@ -347,24 +241,24 @@ export default {
},
displayTitle() {
if (this.isViewingApplication) {
return this.detail.intendedRoomTypeName || this.t('viewingApplicationTitle')
return this.detail.intendedRoomTypeName || this.$tr('预约看房申请')
}
return this.detail.intendedRoomTypeName || this.t('stayApplicationTitle')
return this.detail.intendedRoomTypeName || this.$tr('入住申请')
},
applicationTypeText() {
return this.isViewingApplication ? this.t('viewingApplicationType') : this.t('stayApplicationType')
return this.isViewingApplication ? this.$tr('预约看房') : this.$tr('入住申请')
},
statusText() {
if (this.language !== 'en' && this.detail && this.detail.statusDesc) {
return this.detail.statusDesc
}
const map = {
0: this.t('statusPending'),
10: this.t('statusApproved'),
20: this.t('statusRejected'),
99: this.t('statusFinished')
0: this.$tr('待审核'),
10: this.$tr('已通过'),
20: this.$tr('已拒绝'),
99: this.$tr('已结束')
}
return map[this.detail.status] || this.t('statusProcessing')
return map[this.detail.status] || this.$tr('处理中')
},
statusType() {
if (this.detail.status === 10) {
@@ -389,14 +283,14 @@ export default {
return '--'
}
if (this.isViewingApplication) {
return `${this.formatDateTime(this.detail.start)}${this.t('dateRangeJoiner')}${this.formatDateTime(this.detail.end)}`
return `${this.formatDateTime(this.detail.start)}${this.$tr(' 至 ')}${this.formatDateTime(this.detail.end)}`
}
return `${this.formatDate(this.detail.start)}${this.t('dateRangeJoiner')}${this.formatDate(this.detail.end)}`
return `${this.formatDate(this.detail.start)}${this.$tr(' 至 ')}${this.formatDate(this.detail.end)}`
},
remarkLines() {
const text = this.detail && this.detail.remark ? String(this.detail.remark).trim() : ''
if (!text) {
return [this.t('emptyRemark')]
return [this.$tr('暂无补充说明')]
}
return text.split(/\r?\n/).filter(Boolean)
},
@@ -429,17 +323,17 @@ export default {
return this.getReservationContractStatusText()
}
if (this.isReservationCheckinProcessing()) {
return this.t('checkinPendingHint')
return this.$tr('宿管正在办理入住,请耐心等待')
}
const reservationStepText = getReservationCurrentStepText(this.detail, this.language)
if (reservationStepText) {
return reservationStepText
}
if (this.shouldPayDeposit(this.detail)) {
return this.t('statusPendingPayment')
return this.$tr('请支付定金')
}
if (this.isWaitingRoomAssignment(this.detail)) {
return this.t('statusWaitingRoomAssign')
return this.$tr('等待预订中心分配房间')
}
return ''
},
@@ -466,9 +360,6 @@ export default {
this.loadReservationFlow()
},
methods: {
t(key, params) {
return this.$tm('pkgService.application_detail.application_detail', key, params)
},
isPaidApplication(item = {}) {
return !item.isViewingApplication && Number(item.payStatus) === 10
},
@@ -530,7 +421,7 @@ export default {
return Number(detail.status) === 2
},
getReservationInspectionStatusText() {
return this.t('inspectionPendingReviewHint')
return this.$tr('inspectionPendingReviewHint')
},
isReservationContractAwaitingReview() {
if (this.getReservationCurrentStepValue() !== RESERVATION_FLOW_STEP.CONTRACT) {
@@ -663,13 +554,13 @@ export default {
return null
}
const localizedLabelMap = {
'看房时间': this.t('viewingTimeKey'),
'预计租住时长': this.t('leaseDurationKey'),
'租金预算': this.t('budgetKey'),
'工作/通勤地点': this.t('commuteKey'),
'意向区域': this.t('preferredAreaKey'),
'意向房型': this.t('preferredRoomTypeKey'),
'支付方式': this.t('paymentMethodKey')
'看房时间': this.$tr('看房时间'),
'预计租住时长': this.$tr('预计租住时长'),
'租金预算': this.$tr('租金预算'),
'工作/通勤地点': this.$tr('工作/通勤地点'),
'意向区域': this.$tr('意向区域'),
'意向房型': this.$tr('意向房型'),
'支付方式': this.$tr('支付方式')
}
const rawValue = line
.replace(`${matched.zh}:`, '')
@@ -704,7 +595,7 @@ export default {
data: String(this.detail.detailCode),
success: () => {
uni.showToast({
title: this.t('codeCopied'),
title: this.$tr('申请编号已复制'),
icon: 'none'
})
}
@@ -713,8 +604,8 @@ export default {
confirmCancelOrder() {
return new Promise((resolve) => {
uni.showModal({
title: this.t('cancelOrderTitle'),
content: this.t('cancelOrderContent'),
title: this.$tr('取消订单'),
content: this.$tr('取消后将关闭当前未支付的定金订单,是否继续?'),
confirmColor: '#ef4444',
success: (res) => resolve(!!(res && res.confirm)),
fail: () => resolve(false)
@@ -733,7 +624,7 @@ export default {
return {
...item,
status: 99,
statusDesc: this.t('statusFinished')
statusDesc: this.$tr('已结束')
}
})
saveMyApplicationList(nextList)
@@ -757,18 +648,18 @@ export default {
this.detail = {
...this.detail,
status: 99,
statusDesc: this.t('statusFinished')
statusDesc: this.$tr('已结束')
}
this.syncCanceledDetailToCache()
uni.showToast({
title: this.t('cancelOrderSuccess'),
title: this.$tr('订单已取消'),
icon: 'success'
})
})
})
.catch((error) => {
uni.showToast({
title: (error && (error.message || error.msg)) || this.t('cancelOrderFailed'),
title: (error && (error.message || error.msg)) || this.$tr('取消订单失败'),
icon: 'none'
})
})
@@ -782,7 +673,7 @@ export default {
goToBillPage() {
if (!this.detail.detailCode) {
uni.showToast({
title: this.t('missingBillCode'),
title: this.$tr('申请单编号缺失'),
icon: 'none'
})
return
@@ -810,7 +701,7 @@ export default {
const contractNo = String(this.detail && this.detail.reservationCurrentNode && this.detail.reservationCurrentNode.refNo || '').trim()
if (!contractNo) {
uni.showToast({
title: this.t('missingContractNo'),
title: this.$tr('合同编号缺失'),
icon: 'none'
})
return