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

@@ -16,17 +16,17 @@
<tn-popup v-model="showPopup" mode="bottom" length="72%" :borderRadius="32" :closeBtn="true">
<view class="popup-content">
<view class="popup-header">
<text class="popup-title">{{ t('popupTitle') }}</text>
<text class="popup-title">{{ $tr('选择意向楼栋') }}</text>
</view>
<scroll-view scroll-y class="building-list-scroll">
<view v-if="isLoading" class="loading-state tn-padding-xl tn-text-center">
<tn-loading mode="circle"></tn-loading>
<view class="tn-margin-top-sm tn-color-gray">{{ t('loadingText') }}</view>
<view class="tn-margin-top-sm tn-color-gray">{{ $tr('楼栋加载中...') }}</view>
</view>
<view v-else-if="!buildingList.length" class="empty-state tn-padding-xl tn-text-center">
<text class="tn-color-gray">{{ t('emptyText') }}</text>
<text class="tn-color-gray">{{ $tr('暂无可选楼栋') }}</text>
</view>
<view v-else class="building-list">
@@ -97,7 +97,7 @@ export default {
return this.$getLanguage ? this.$getLanguage() : 'zh'
},
placeholderText() {
return this.areaCode ? this.t('selectBuilding') : this.t('selectAreaFirst')
return this.areaCode ? this.$tr('请选择楼栋') : this.$tr('请先选择区域')
}
},
watch: {
@@ -120,13 +120,10 @@ export default {
this.loadData()
},
methods: {
t(key, params) {
return this.$tm('pkgService.submit_request.components.BuildingSelector', key, params)
},
handleOpen() {
if (!this.areaCode) {
uni.showToast({
title: this.t('selectAreaFirst'),
title: this.$tr('请先选择区域'),
icon: 'none'
})
return
@@ -189,7 +186,7 @@ export default {
this.buildingList = []
this.selectedBuilding = null
uni.showToast({
title: this.t('loadFailed'),
title: this.$tr('楼栋列表加载失败'),
icon: 'none'
})
})

View File

@@ -8,7 +8,7 @@
</view>
</picker>
</view>
<view class="date-divider">{{ t('dateDivider') }}</view>
<view class="date-divider">{{ $tr('至') }}</view>
<view class="date-item">
<view class="date-label">{{ resolvedEndLabel }}</view>
<picker mode="date" @change="onEndChange">
@@ -23,22 +23,6 @@
<script>
export default {
name: 'DateRangeSelector',
i18n: {
zh: {
startLabel: '预计入住',
endLabel: '预计离开',
startPlaceholder: '请选择入住日期',
endPlaceholder: '请选择离开日期',
dateDivider: '至'
},
en: {
startLabel: 'Expected Check-in',
endLabel: 'Expected Check-out',
startPlaceholder: 'Select check-in date',
endPlaceholder: 'Select check-out date',
dateDivider: 'to'
}
},
props: {
start: {
type: String,
@@ -67,22 +51,19 @@ export default {
},
computed: {
resolvedStartLabel() {
return this.startLabel || this.t('startLabel')
return this.startLabel || this.$tr('预计入住')
},
resolvedEndLabel() {
return this.endLabel || this.t('endLabel')
return this.endLabel || this.$tr('预计离开')
},
resolvedStartPlaceholder() {
return this.startPlaceholder || this.t('startPlaceholder')
return this.startPlaceholder || this.$tr('请选择入住日期')
},
resolvedEndPlaceholder() {
return this.endPlaceholder || this.t('endPlaceholder')
return this.endPlaceholder || this.$tr('请选择离开日期')
}
},
methods: {
t(key) {
return this.$tm('pkgService.submit_request.components.DateRangeSelector', key)
},
onStartChange(e) {
this.$emit('update:start', e.detail.value)
},
@@ -128,7 +109,7 @@ export default {
font-size: 28rpx;
color: #1A2B4C;
font-weight: 600;
&.is-empty {
color: #CBD5E1;
font-weight: normal;

View File

@@ -15,17 +15,17 @@
<tn-popup v-model="showPopup" mode="bottom" length="72%" :borderRadius="32" :closeBtn="true">
<view class="popup-content">
<view class="popup-header">
<text class="popup-title">{{ t('popupTitle') }}</text>
<text class="popup-title">{{ $tr('选择意向楼层') }}</text>
</view>
<scroll-view scroll-y class="floor-list-scroll">
<view v-if="isLoading" class="loading-state tn-padding-xl tn-text-center">
<tn-loading mode="circle"></tn-loading>
<view class="tn-margin-top-sm tn-color-gray">{{ t('loadingText') }}</view>
<view class="tn-margin-top-sm tn-color-gray">{{ $tr('楼层加载中...') }}</view>
</view>
<view v-else-if="!floorList.length" class="empty-state tn-padding-xl tn-text-center">
<text class="tn-color-gray">{{ t('emptyText') }}</text>
<text class="tn-color-gray">{{ $tr('暂无可选楼层') }}</text>
</view>
<view v-else class="floor-list">
@@ -34,7 +34,7 @@
:class="{ 'is-active': !selectedFloor }"
@click="handleClear"
>
<text class="floor-name">{{ t('clearSelection') }}</text>
<text class="floor-name">{{ $tr('不选择') }}</text>
<text v-if="!selectedFloor" class="tn-icon-success-circle-fill floor-check"></text>
</view>
<view
@@ -133,7 +133,7 @@ export default {
return this.$getLanguage ? this.$getLanguage() : 'zh'
},
placeholderText() {
return this.t('selectFloor')
return this.$tr('请选择楼层')
}
},
watch: {
@@ -148,9 +148,6 @@ export default {
this.loadData()
},
methods: {
t(key, params) {
return this.$tm('pkgService.submit_request.components.FloorSelector', key, params)
},
handleOpen() {
this.showPopup = true
this.loadData()
@@ -176,7 +173,7 @@ export default {
this.floorList = []
this.selectedFloor = null
uni.showToast({
title: this.t('loadFailed'),
title: this.$tr('楼层列表加载失败'),
icon: 'none'
})
})

View File

@@ -3,7 +3,7 @@
<view class="selector-header tn-flex tn-flex-row-between tn-flex-col-center" @click="openSelector">
<view class="selected-info">
<view class="selected-name tn-text-ellipsis" :class="{ 'is-empty': !selectedRoomType }">
{{ selectedRoomType ? getRoomTypeDisplayName(selectedRoomType) : t('selectRoomType') }}
{{ selectedRoomType ? getRoomTypeDisplayName(selectedRoomType) : $tr('请选择意向房型') }}
</view>
<view class="selected-area tn-text-ellipsis" v-if="selectedArea">
{{ getAreaDisplayName(selectedArea) }}
@@ -15,17 +15,17 @@
<tn-popup v-model="showPopup" mode="bottom" length="80%" :borderRadius="32" :closeBtn="true">
<view class="popup-content">
<view class="popup-header">
<text class="popup-title">{{ t('popupTitle') }}</text>
<text class="popup-title">{{ $tr('选择意向房型') }}</text>
</view>
<scroll-view scroll-y class="area-list-scroll">
<view v-if="isLoading" class="loading-state tn-padding-xl tn-text-center">
<tn-loading mode="circle"></tn-loading>
<view class="tn-margin-top-sm tn-color-gray">{{ t('loadingRoomTypes') }}</view>
<view class="tn-margin-top-sm tn-color-gray">{{ $tr('房型加载中...') }}</view>
</view>
<view v-else-if="!displayAreaList.length" class="empty-state tn-padding-xl tn-text-center">
<text class="tn-color-gray">{{ t('emptyRoomTypes') }}</text>
<text class="tn-color-gray">{{ $tr('暂无可选房型') }}</text>
</view>
<view v-else class="area-group" v-for="(area, index) in displayAreaList" :key="area.code">
@@ -45,7 +45,7 @@
@click="handleSelect(area, room)"
>
<view class="room-name tn-text-ellipsis">{{ getRoomTypeDisplayName(room) }}</view>
<view class="room-price" v-if="room.price">¥{{ getPriceValue(room.price) }}{{ t('priceUnit') }}</view>
<view class="room-price" v-if="room.price">¥{{ getPriceValue(room.price) }}{{ $tr('/月') }}</view>
</view>
</view>
</view>
@@ -118,9 +118,6 @@ export default {
this.loadData()
},
methods: {
t(key) {
return this.$translate(this.i18n, key)
},
openSelector() {
this.showPopup = true
this.loadData()
@@ -148,7 +145,7 @@ export default {
})
.catch((e) => {
console.error('load room types error', e)
uni.showToast({ title: this.t('loadFailed'), icon: 'none' })
uni.showToast({ title: this.$tr('房型列表加载失败'), icon: 'none' })
})
.finally(() => {
this.isLoading = false

View File

@@ -11,23 +11,13 @@
{{ item.value }}
</view>
</view>
<view v-else class="empty-tips">{{ loading ? t('loadingText') : resolvedEmptyText }}</view>
<view v-else class="empty-tips">{{ loading ? $tr('标签加载中...') : resolvedEmptyText }}</view>
</view>
</template>
<script>
export default {
name: 'TagSelector',
i18n: {
zh: {
loadingText: '标签加载中...',
emptyText: '暂无标签'
},
en: {
loadingText: 'Loading tags...',
emptyText: 'No tags available'
}
},
props: {
value: {
type: Array,
@@ -48,13 +38,10 @@ export default {
},
computed: {
resolvedEmptyText() {
return this.emptyText || this.t('emptyText')
return this.emptyText || this.$tr('暂无标签')
}
},
methods: {
t(key, params) {
return this.$tm('pkgService.submit_request.components.TagSelector', key, params)
},
toggleTag(key) {
const currentList = [...this.value]
const index = currentList.indexOf(key)