wordpress本地網(wǎng)站搭建整套課程關(guān)鍵詞熱度查詢
痛點(diǎn)
在i18n多語(yǔ)言模塊使用過(guò)程中,發(fā)現(xiàn)下面幾個(gè)問(wèn)題,需要解決
1)uni-best框架下,$t功能函數(shù)無(wú)法實(shí)時(shí)的切換語(yǔ)言,可能跟使用有關(guān)
2)uni-best建議的translate方式在vue塊外使用太繁瑣,希望不用導(dǎo)入,直接書(shū)寫(xiě)$t使用。統(tǒng)一邏輯,減少?gòu)?fù)雜度
目標(biāo)
需要完成的目標(biāo)如下
1)將多語(yǔ)言模塊放到公共區(qū)域,可能會(huì)導(dǎo)致原生標(biāo)題無(wú)法正常切換語(yǔ)音。這個(gè)無(wú)所謂,因?yàn)闃?biāo)題欄已經(jīng)custom定制并組件化了
2)修復(fù)無(wú)法正常實(shí)時(shí)切換語(yǔ)言的$t,這個(gè)可能跟使用方式有關(guān),anyway,讓它能按原模式正常工作
3)在任何地方都可以使用$t功能,無(wú)論是template還是script部分
實(shí)現(xiàn)
uni-best的translate方法代碼實(shí)現(xiàn)了一個(gè)很好的思路,只是無(wú)法支持占位符的功能。讓我們改進(jìn)它
/*** 任意文件使用$t翻譯方法,需要在app里全局導(dǎo)入* @param { string } localeKey 多語(yǔ)言的key,eg: "app.name"*/
export const translate = (localeKey: string, opt: Record<string, any> = {}) => {if (!localeKey) {console.error(`[i18n] Function translate(), localeKey param is required`)return ''}const locale = uni.getLocale()const message = messages[locale]if (Object.keys(message).includes(localeKey)) {const template = message[localeKey]// 使用 Object.keys 遍歷 params 對(duì)象,替換模板中的大括號(hào)占位符return Object.keys(opt).reduce((acc, key) => acc.replace(new RegExp(`{${key}}`, 'g'), opt[key]),template)}return localeKey // 轉(zhuǎn)換不了則原樣輸出
}
然后在main.ts里把它掛載到全局
import { message, alert, confirm, translate } from '@/utils'...export function createApp() {const app = createSSRApp(App)...app.use(i18n)app.config.globalProperties.$t = translate // 覆蓋不能正常工作的$t函數(shù)// #ifdef MP-WEIXIN// 由于微信小程序的運(yùn)行機(jī)制問(wèn)題,需聲明如下一行,H5和APP非必填app.config.globalProperties._i18n = i18n// #endifreturn {app}
}
至于在任意位置使用,讓我們把translate掛載到代碼部分的全局
// 安裝到全局,覆蓋不能正常工作的$t
;(function (global) {console.log('install');(global as any).$t = translate
})(this || window || globalThis)
下面是最終完成的i18n.ts模塊,添加了語(yǔ)言切換功能的導(dǎo)出。
API.tools.locale.request是后端的語(yǔ)言切換代碼,實(shí)現(xiàn)前后端語(yǔ)言統(tǒng)一切換,目前只導(dǎo)入了3種語(yǔ)言,需要其它語(yǔ)言可以自行增加
/*** ccframe i18n模塊* 注意:由于某種未知的原因,uni-best的$t()翻譯方法有無(wú)法切換語(yǔ)音以及安卓出錯(cuò)的問(wèn)題,因此使用導(dǎo)出的translate方法進(jìn)行動(dòng)態(tài)翻譯* @Jim 24/09/20*/import { createI18n } from 'vue-i18n'import en from '@/datas/en.json'
import zhHans from '@/datas/zh-Hans.json'
import zhHant from '@/datas/zh-Hant.json'const messages = {en,'zh-Hant': zhHant,'zh-Hans': zhHans // key 不能亂寫(xiě),查看截圖 screenshots/i18n.png
}const i18n = createI18n({legacy: false, // 解決空白報(bào)錯(cuò)問(wèn)題locale: uni.getLocale(), // 獲取已設(shè)置的語(yǔ)言,fallback 語(yǔ)言需要再 manifest.config.ts 中設(shè)置messages
})type LocaleType = 'en' | 'zh-Hant' | 'zh-Hans'i18n.global.locale.value = import.meta.env.VITE_FALLBACK_LOCALE/*** 任意文件使用$t翻譯方法,需要在app里全局導(dǎo)入* @param { string } localeKey 多語(yǔ)言的key,eg: "app.name"*/
export const translate = (localeKey: string, opt: Record<string, any> = {}) => {if (!localeKey) {console.error(`[i18n] Function translate(), localeKey param is required`)return ''}const locale = uni.getLocale()const message = messages[locale]if (Object.keys(message).includes(localeKey)) {const template = message[localeKey]// 使用 Object.keys 遍歷 params 對(duì)象,替換模板中的大括號(hào)占位符return Object.keys(opt).reduce((acc, key) => acc.replace(new RegExp(`{${key}}`, 'g'), opt[key]),template)}return localeKey // 轉(zhuǎn)換不了則原樣輸出
}const langMapper: Record<string, string> = {'zh-Hans': 'zh-CN','zh-Hant': 'zh-TW',en: 'en-US'
}export const setLocale = async (locale: LocaleType) => {await API.tools.locale.request({ lang: langMapper[locale] })// #ifdef APP-PLUSsetTimeout(() => {// 如果是APP,需要等待重新啟動(dòng)頁(yè)面i18n.global.locale.value = localeuni.setLocale(locale)}, 300)// #endif// #ifndef APP-PLUSi18n.global.locale.value = localeuni.setLocale(locale)// #endif// currentLang.value = locale
}// 安裝到全局,覆蓋不能正常工作的$t
;(function (global) {console.log('install');(global as any).$t = translate
})(this || window || globalThis)export default i18n/** 非vue 文件使用 i18n
export const testI18n = () => {console.log(t('app.name'))// 下面同樣生效uni.showModal({title: 'i18n 測(cè)試',content: t('app.name')})
} */
然后就可以簡(jiǎn)單愉快的使用多語(yǔ)言功能了。
頁(yè)面上$t('login.enterPhone')根據(jù)語(yǔ)言顯示“輸入手機(jī)號(hào)碼”:
? ? ? ? ? <up-input
? ? ? ? ? ? fontSize="32rpx"
? ? ? ? ? ? :placeholder="$t('login.enterPhone')"
? ? ? ? ? ? border="surround"
? ? ? ? ? ? v-model="data.userMobile"
? ? ? ? ? ? style="letter-spacing: 2rpx"
? ? ? ? ? ? @change="data.mobileErr = ''"
? ? ? ? ? ? type="number"
? ? ? ? ? ? maxlength="11"
? ? ? ? ? />
代碼片段,這個(gè)是form表單驗(yàn)證公共庫(kù)里的使用:
?
? required(error?: string): Validator {
? ? this.push({
? ? ? required: true,
? ? ? validator: (rule: any, val: any, callback: (error?: Error) => void) => {
? ? ? ? // 補(bǔ)充驗(yàn)證模式
? ? ? ? return val !== undefined && val !== null && val !== ''
? ? ? },
? ? ? message:
? ? ? ? error ??
? ? ? ? (this.labelText
? ? ? ? ? ? $t('utils.validator.required') + this.labelText
? ? ? ? ? : $t('utils.validator.notEmpty')),
? ? ? trigger: ['change', 'blur']
? ? })
? ? return this
? }
$t('utils.validator.required')根據(jù)語(yǔ)言輸出:請(qǐng)輸入
$t('utils.validator.notEmpty')根據(jù)語(yǔ)言輸出:內(nèi)容不能為空
完善Typescript類型定義
這樣使用起來(lái),還有那么一點(diǎn)不舒服,就是在script中使用$t時(shí),會(huì)報(bào)錯(cuò)類型找不到紅紅的一片(實(shí)際編譯沒(méi)問(wèn)題)。對(duì)于代碼強(qiáng)迫癥人會(huì)有點(diǎn)一點(diǎn)受不了,那么讓這個(gè)錯(cuò)誤的爆紅消失掉:
unibest里原本帶了i18n.d.ts文件,把我們掛載到script全局的定義添加進(jìn)去:
?
/* eslint-disable no-unused-vars */
export {}declare module 'vue' {interface ComponentCustomProperties {$t: (key: string, opt?: Record<string, any>) => string// $tm: (key: string, opt?: Record<string, any>) => [] | { [p: string]: any }}
}declare global {function $t(localeKey: string, opt?: Record<string, any>): string
}
刷新一下vscode,不爆紅了,完美~