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="book-viewing-page tn-safe-area-inset-bottom">
<tn-nav-bar :isBack="true" :backTitle="t('backTitle')" backgroundColor="#F0F6FF" :bottomShadow="false" :fixed="true">
<view class="nav-title">{{ t('navTitle') }}</view>
<tn-nav-bar :isBack="true" :backTitle="$tr('返回')" backgroundColor="#F0F6FF" :bottomShadow="false" :fixed="true">
<view class="nav-title">{{ $tr('预约现场带看') }}</view>
</tn-nav-bar>
<view class="content-wrapper" :style="{ paddingTop: vuex_custom_bar_height + 'px' }">
@@ -21,8 +21,8 @@
<view class="form-card">
<view class="card-header tn-flex tn-flex-row-between tn-flex-col-bottom">
<view class="header-left tn-flex tn-flex-col-bottom">
<text class="card-title">{{ t('selectViewingTime') }}</text>
<text class="card-subtitle">{{ t('selectViewingTimeDesc') }}</text>
<text class="card-title">{{ $tr('选择看房时间') }}</text>
<text class="card-subtitle">{{ $tr('请选择您方便的时间段') }}</text>
</view>
</view>
@@ -60,13 +60,13 @@
<view class="form-card">
<view class="card-header">
<view class="header-left tn-flex tn-flex-col-bottom">
<text class="card-title">{{ t('rentalNeeds') }}</text>
<text class="card-subtitle">{{ t('rentalNeedsDesc') }}</text>
<text class="card-title">{{ $tr('您的租住需求') }}</text>
<text class="card-subtitle">{{ $tr('帮助管家更好地为您推荐房源') }}</text>
</view>
</view>
<view class="field-item">
<view class="field-label">{{ t('roomTypeLabel') }}</view>
<view class="field-label">{{ $tr('意向房型') }}</view>
<room-type-selector
v-model="formData.intendedRoomTypeCode"
:initial-area-code="formData.intendedAreaCode"
@@ -75,7 +75,7 @@
</view>
<view class="field-item">
<view class="field-label">{{ t('durationLabel') }}</view>
<view class="field-label">{{ $tr('预计租住时长') }}</view>
<view class="tag-grid">
<view
v-for="(item, index) in durationOptions"
@@ -90,28 +90,28 @@
</view>
<view class="field-item">
<view class="field-label">{{ t('budgetLabel') }}</view>
<view class="field-label">{{ $tr('租金预算 (元/月)') }}</view>
<view class="input-box tn-flex tn-flex-col-center">
<text class="tn-icon-money input-icon"></text>
<input
class="custom-input"
v-model="formData.budget"
type="digit"
:placeholder="t('budgetPlaceholder')"
:placeholder="$tr('请输入您的心理价位')"
placeholder-style="color: #A1B0C4;"
/>
</view>
</view>
<view class="field-item">
<view class="field-label">{{ t('workplaceLabel') }}</view>
<view class="field-label">{{ $tr('工作/通勤地点') }}</view>
<view class="input-box tn-flex tn-flex-col-center">
<text class="tn-icon-location input-icon"></text>
<input
class="custom-input"
v-model="formData.workplace"
type="text"
:placeholder="t('workplacePlaceholder')"
:placeholder="$tr('请输入主要通勤地点')"
placeholder-style="color: #A1B0C4;"
/>
</view>
@@ -123,7 +123,7 @@
<!-- 底部操作区 -->
<view class="footer-bar tn-safe-area-inset-bottom">
<view class="submit-btn" @click="handleSubmit">
<text>{{ t('submitBooking') }}</text>
<text>{{ $tr('提交预约') }}</text>
</view>
</view>
</view>
@@ -204,7 +204,7 @@ export default {
},
displayInfoDesc() {
if (!this.sourceData) {
return this.t('defaultInfoDesc')
return this.$tr('专属管家为您提供一对一带看服务')
}
const bannerCopy = this.language === 'en'
? compactEnglishText(this.sourceData.bannerSubtitleEn || this.sourceData.bannerDescEn || this.sourceData.bannerSubtitle || this.sourceData.bannerDesc || '', 48)
@@ -213,7 +213,7 @@ export default {
? (this.sourceData.areaLabelEnDisplay || this.sourceData.areaNameEnDisplay || compactEnglishText(this.sourceData.areaLabelEn || this.sourceData.areaLabel || this.sourceData.areaNameEn || this.sourceData.areaName || '', 26))
: (this.sourceData.areaLabel || this.sourceData.areaName || this.sourceData.areaLabelEn || this.sourceData.areaNameEn || '')
const meta = [bannerCopy, areaLabel, localizePayMethodText(this.sourceData.payMethod, this.language)].filter(Boolean).join(' · ')
return meta || this.t('defaultInfoDesc')
return meta || this.$tr('专属管家为您提供一对一带看服务')
}
},
data() {
@@ -236,101 +236,7 @@ export default {
workplace: ''
},
sourceData: null,
isSubmitting: false,
i18n: {
zh: {
backTitle: '返回',
navTitle: '预约现场带看',
selectViewingTime: '选择看房时间',
selectViewingTimeDesc: '请选择您方便的时间段',
rentalNeeds: '您的租住需求',
rentalNeedsDesc: '帮助管家更好地为您推荐房源',
roomTypeLabel: '意向房型',
durationLabel: '预计租住时长',
budgetLabel: '租金预算 (元/月)',
budgetPlaceholder: '请输入您的心理价位',
workplaceLabel: '工作/通勤地点',
workplacePlaceholder: '请输入主要通勤地点',
submitBooking: '提交预约',
defaultInfoDesc: '专属管家为您提供一对一带看服务',
duration1: '1-3个月',
duration2: '4-6个月',
duration3: '7-9个月',
duration4: '10-12个月',
duration5: '1年以上',
week0: '周日',
week1: '周一',
week2: '周二',
week3: '周三',
week4: '周四',
week5: '周五',
week6: '周六',
today: '今天',
tomorrow: '明天',
remarkTitle: '预约看房申请',
remarkTime: '看房时间:{date} {time}',
remarkDuration: '预计租住时长:{duration}',
remarkBudget: '租金预算:{budget} 元/月',
remarkWorkplace: '工作/通勤地点:{workplace}',
remarkArea: '意向区域:{area}',
remarkRoomType: '意向房型:{roomType}',
remarkSource: '当前来源:{room}',
remarkPayMethod: '支付方式:{payMethod}',
remarkTail: '备注:请宿管确认带看安排;若带看完成并锁定房号,可转为预定单通知租客支付。',
selectTimeRequired: '请选择看房时间段',
selectDurationRequired: '请选择预计租住时长',
submitting: '提交中...',
submitSuccessTitle: '预约成功',
submitSuccessContent: '您的预约看房申请已提交,请等待管家联系',
submitFailed: '预约提交失败'
},
en: {
backTitle: 'Back',
navTitle: 'On-site Viewing',
selectViewingTime: 'Select Viewing Time',
selectViewingTimeDesc: 'Choose a time slot that works for you',
rentalNeeds: 'Rental Needs',
rentalNeedsDesc: 'Help the manager recommend a suitable room',
roomTypeLabel: 'Preferred Room Type',
durationLabel: 'Expected Stay Duration',
budgetLabel: 'Budget (CNY/month)',
budgetPlaceholder: 'Enter your expected budget',
workplaceLabel: 'Work / Commute Location',
workplacePlaceholder: 'Enter your main commute location',
submitBooking: 'Submit Request',
defaultInfoDesc: 'A dedicated manager will arrange a one-on-one viewing for you',
duration1: '1-3 months',
duration2: '4-6 months',
duration3: '7-9 months',
duration4: '10-12 months',
duration5: 'Over 1 year',
week0: 'Sun',
week1: 'Mon',
week2: 'Tue',
week3: 'Wed',
week4: 'Thu',
week5: 'Fri',
week6: 'Sat',
today: 'Today',
tomorrow: 'Tomorrow',
remarkTitle: 'Viewing Request',
remarkTime: 'Viewing Time: {date} {time}',
remarkDuration: 'Expected Stay: {duration}',
remarkBudget: 'Budget: {budget} CNY/month',
remarkWorkplace: 'Work / Commute Location: {workplace}',
remarkArea: 'Preferred Area: {area}',
remarkRoomType: 'Preferred Room Type: {roomType}',
remarkSource: 'Current Source: {room}',
remarkPayMethod: 'Payment Method: {payMethod}',
remarkTail: 'Note: Please confirm the viewing schedule with the manager. After viewing and locking a room number, the order can be converted into a booking for payment.',
selectTimeRequired: 'Please select a viewing time slot',
selectDurationRequired: 'Please select the expected stay duration',
submitting: 'Submitting...',
submitSuccessTitle: 'Booking Submitted',
submitSuccessContent: 'Your viewing request has been submitted.\nThe system will forward it to the authorized manager of the selected area. After the manager confirms the viewing, the order can be completed directly or converted into a booking for payment once a room is selected.',
submitFailed: 'Failed to submit the booking'
}
}
isSubmitting: false
}
},
onLoad(options) {
@@ -348,9 +254,6 @@ export default {
this.redirectIfBookingUnavailable()
},
methods: {
t(key, params) {
return this.$tm('pkgBooking.book_viewing.book_viewing', key, params)
},
redirectIfBookingUnavailable() {
const session = getSessionSnapshot()
if (!session.isLogin) {
@@ -382,24 +285,24 @@ export default {
},
syncDurationOptions() {
this.durationOptions = [
this.t('duration1'),
this.t('duration2'),
this.t('duration3'),
this.t('duration4'),
this.t('duration5')
this.$tr('1-3个月'),
this.$tr('4-6个月'),
this.$tr('7-9个月'),
this.$tr('10-12个月'),
this.$tr('1年以上')
]
},
generateDates() {
const dates = []
const today = new Date()
const weeks = [
this.t('week0'),
this.t('week1'),
this.t('week2'),
this.t('week3'),
this.t('week4'),
this.t('week5'),
this.t('week6')
this.$tr('周日'),
this.$tr('周一'),
this.$tr('周二'),
this.$tr('周三'),
this.$tr('周四'),
this.$tr('周五'),
this.$tr('周六')
]
for (let i = 0; i < 7; i++) {
@@ -409,8 +312,8 @@ export default {
const day = String(d.getDate()).padStart(2, '0')
let weekStr = weeks[d.getDay()]
if (i === 0) weekStr = this.t('today');
else if (i === 1) weekStr = this.t('tomorrow');
if (i === 0) weekStr = this.$tr('今天');
else if (i === 1) weekStr = this.$tr('明天');
dates.push({
date: `${d.getFullYear()}-${month}-${day}`,
@@ -452,11 +355,11 @@ export default {
return
}
if (this.currentTimeIndex === -1) {
uni.showToast({ title: this.t('selectTimeRequired'), icon: 'none' })
uni.showToast({ title: this.$tr('请选择看房时间段'), icon: 'none' })
return
}
if (!this.formData.duration) {
uni.showToast({ title: this.t('selectDurationRequired'), icon: 'none' })
uni.showToast({ title: this.$tr('请选择预计租住时长'), icon: 'none' })
return
}
@@ -478,13 +381,13 @@ export default {
}
this.isSubmitting = true
uni.showLoading({ title: this.t('submitting'), mask: true })
uni.showLoading({ title: this.$tr('提交中...'), mask: true })
return submitViewingApplicationForm(payload)
.then(() => {
uni.hideLoading()
uni.showModal({
title: this.t('submitSuccessTitle'),
content: this.t('submitSuccessContent'),
title: this.$tr('预约成功'),
content: this.$tr('您的预约看房申请已提交,请等待管家联系'),
showCancel: false,
confirmColor: '#01BEFF',
success: () => {
@@ -498,7 +401,7 @@ export default {
console.error('submit viewing application failed', error)
uni.hideLoading()
uni.showToast({
title: (error && (error.message || error.msg)) || this.t('submitFailed'),
title: (error && (error.message || error.msg)) || this.$tr('预约提交失败'),
icon: 'none'
})
})