vue3玩转i18n

2 篇文章 0 订阅
1 篇文章 0 订阅

交流QQ群:555913397
有什么问题可以加群大家一起交流

1.安装i18n
yarn add vue-i18n
2.配置i18n
目录结构

image

index.ts i18n配置文件
import type { App } from 'vue'
import { createI18n, I18n } from 'vue-i18n'

import elementZhcnLocale from 'element-plus/lib/locale/lang/zh-cn'
import elementEnLocale from 'element-plus/lib/locale/lang/en'
import { useConfig } from '@/store/config'

export var i18n: I18n<IAnyObj, unknown, unknown, false>

//语言包
const assignLocale: IAnyObj = {
    'zh-cn': [elementZhcnLocale],
    en: [elementEnLocale]
}

export async function loadLang(app: App) {
    const config = useConfig()
    const locale = config.lang.defaultLang

    //加载框架语言包
    const lang = await import(`./globs-${locale}.ts`)
    const message = lang.default ?? {}

    /*
     * 0、加载页面语言包  import.meta.glob 的路径不能使用变量 
     * import.meta.glob 匹配到的文件默认是懒加载的,通过动态导入实现,并会在构建时分离为独立的 chunk。如果你倾向于直接引入所有的模块(例如依赖于这些模块中的副作用首先被应用),
     * 你可以传入 { eager: true } 作为第二个参数:
     * 1、vue3 setup 内只能使用 useI18n({messages:{}}) 来动态载入当前页面单独的语言包,不方便使用
     * 2、直接载入所有 /@/lang/pages/语言/*.ts 文件,若某页面有特别大量的语言配置,可在其他位置单独建立语言包文件,并在对应页面加载语言包
     */
    if (locale == 'zh-cn') {
        //
        let path1 = import.meta.glob('./pages/zh-cn/**/*.ts', { eager: true })
        let path = await getLangFileMessage(path1, locale)
        assignLocale[locale].push(path)
    } else if (locale == 'en') {
        assignLocale[locale].push(getLangFileMessage(import.meta.glob('./pages/en/**/*.ts'), locale))
    }

    const messages: IAnyObj = {
        [locale]: {
            ...message
        }
    }
    // 合并语言包(含element-puls、页面语言包)
    Object.assign(messages[locale], ...assignLocale[locale])

    i18n = createI18n({
        locale: locale,
        legacy: false,//组合式api
        globalInjection: true, //挂载$t,$d等到全局
        fallbackLocale: config.lang.fallbackLang,
        messages
    })

    app.use(i18n)
    return i18n

}

/**
 * 
 * @param mList 语言文件集合
 * @param locale 本地语言名称
 */
function getLangFileMessage(mList: any, locale: string) {
    interface IMsg {
        [key: string]: any
    }
    let msg: IMsg = {}
    locale = '/' + locale
    for (let path in mList) {
        if (mList[path].default) {
            //获取文件名 ps 从/zh-cn +1的位置开始截取到.ts前
            let fileName = path.slice(path.lastIndexOf(locale) + (locale.length + 1), path.lastIndexOf('.'))
            //如果还有子文件夹
            if (fileName.indexOf('/') > 0) {
                let fileNameTemp = fileName.split('/')
                //一级子目录
                if (fileNameTemp.length == 2) {
                    //如果msg对象内没有该key,便初始化,否则调用会报错
                    if (msg[fileNameTemp[0]] === undefined) msg[fileNameTemp[0]] = []
                    msg[fileNameTemp[0]][fileNameTemp[1]] = handleMsglist(mList[path].default)
                }
                //二级子目录
                else if (fileNameTemp.length == 3) {
                    if (msg[fileNameTemp[0]] === undefined) msg[fileNameTemp[0]] = []
                    if (msg[fileNameTemp[0]][fileNameTemp[1]] === undefined) msg[fileNameTemp[0]][fileNameTemp[1]] = []
                    msg[fileNameTemp[0]][fileNameTemp[1]][fileNameTemp[2]] = handleMsglist(mList[path].default)
                } else {
                    msg[fileName] = handleMsglist(mList[path].default)
                }
            } else {
                msg[fileName] = handleMsglist(mList[path].default)
            }
        }
    }
    return msg
}

function handleMsglist(mlist: IAnyObj) {
    let newMlist: any = []
    for (const key in mlist) {
        if (key.indexOf('.') > 0) {
            let keyTemp = key.split('.')
            if (typeof newMlist[keyTemp[0]] === 'undefined') {
                newMlist[keyTemp[0]] = []
            } else {
                newMlist[keyTemp[0]][keyTemp[1]] = mlist[key]
            }
        } else {
            newMlist[key] = mlist[key]
        }
    }
    return newMlist
}

export function editDefaultLang(lang: string): void {
    const config = useConfig()
    config.setLang(lang)

    /*
     * 语言包是按需加载的,比如默认语言为中文,则只在app实例内加载了中文语言包
     * 查阅文档无数遍,无耐接受当前的 i18n 版本并不支持动态添加语言包(或需要在 setup 内动态添加,无法满足全局替换的需求)
     * 故 reload;如果您有已经实现的无需一次性加载全部语言包且无需 reload 的方案,请一定@我
     */
    location.reload()
}
main.ts
import { createApp } from 'vue'
import '@/style.css'
import App from '@/App.vue'
import router from '@/router/index'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as Icons from '@element-plus/icons'
import { appendFile } from 'fs'
import pinia from './store'
import { loadLang } from './lang'

const app = createApp(App).use(router).use(pinia)

//注册语言包
const i18n = await loadLang(app)
//Todo 这里i18n.global.t 类型实例化过深,且可能无限。待解决
app.use(ElementPlus, { i18n: i18n.global.t })
// 循环注册所有图标
for (const name in Icons) {
    //name 为icon名称,也是组件名称。使用时:<Edit />,
    //也可以按需增加前缀或者后缀
    // eg: app.component(`eurake-name-${name}`,(Icons as any)[name])
    // 使用时:<eurake-name-Edit />
    // 当然你也可以写一个方法把首字母大写的图标名称改成小写等你想要的任意格式
    app.component(name, (Icons as any)[name])
}
app.mount('#app')

语言文件,其他需要自定义语言文件照着格式写就可以了

globs-en.ts
export default {
    id: 'ID',
    state: 'State',
    home: 'Home',
    'Return to home page': 'Return to home page',
    'Back to previous page': 'Back to previous page',
    complete: 'Complete',
    'switch language': 'Switch language',
    layout: {
        seting: 'seting',
        'Exit full screen': 'Exit full screen',
        'Full screen is not supported': 'Your browser does not support full screen. Please change your browser and try again~',
    },
    edit: 'Edit',
    add: 'Add',
    info: 'View details',
    'weigh-sort': 'Drag sorting',
    delete: 'Delete',
    refresh: 'Refresh',
    operate: 'Operate',
    Confirm: 'Confirm',
    Cancel: 'Cancel',
    Save: 'Save',
    Upload: 'Upload',
    Retry: 'Retry',
    Reminder: 'Warm Reminder',
    'Save and edit next item': 'Save and edit next item',
    'quick Search Placeholder': 'Fuzzy search by {fields}',
    'Please select field': 'Please select {field}',
    'Please input field': 'Please input {field}',
    'Please enter the correct field': 'Please enter the correct {field}',
    updatetime: 'Modify time',
    createtime: 'Creation time',
    'Fuzzy query': 'Fuzzy query',
    Disable: 'Disable',
    Enable: 'Enable',
    'Click Select': 'Click select',
    'Edit selected row': 'Edit selected row',
    'Delete selected row': 'Delete selected row',
    'Are you sure to delete the selected record?': 'Sure to delete the selected record?',
    shrink: 'Shrink',
    open: 'Open',
    'All submenus': 'All submenus',
    'Shrink all': 'Shrink all',
    'Expand all': 'Expand all',
    'Expand generic search': 'Expand Generic Search',
    search: 'Search',
    Reset: 'Reset',
    to: 'To',
    'Link address': 'Link address',
    none: 'None',
    unknown: 'Unknown',
    weigh: 'weigh',
    'No route found to jump~': 'No route found to jump~',
}

globs-zh-cn.ts
export default {
    id: 'ID',
    state: '状态',
    home: '首页',
    'Return to home page': '返回首页',
    'Back to previous page': '返回上一页',
    complete: '完成',
    'switch language': '切换语言',
    layout: {
        seting: '设置',
        'Exit full screen': '退出全屏',
        'Full screen is not supported': '您的浏览器不支持全屏,请更换浏览器再试~',
    },
    edit: '编辑',
    add: '添加',
    info: '查看详情',
    'weigh-sort': '拖动以排序',
    delete: '删除',
    refresh: '刷新',
    operate: '操作',
    Confirm: '确认',
    Cancel: '取消',
    Save: '保存',
    Upload: '上传',
    Retry: '重试',
    Reminder: '温馨提示',
    'Save and edit next item': '保存并编辑下一项',
    'quick Search Placeholder': '通过{fields}模糊搜索',
    'Please select field': '请选择{field}',
    'Please input field': '请输入{field}',
    'Please enter the correct field': '请输入正确的{field}',
    updatetime: '修改时间',
    createtime: '创建时间',
    'Fuzzy query': '模糊查询',
    Disable: '禁用',
    Enable: '启用',
    'Click Select': '点击选择',
    'Edit selected row': '编辑选中行',
    'Delete selected row': '删除选中行',
    'Are you sure to delete the selected record?': '确定删除选中记录?',
    shrink: '收缩',
    open: '展开',
    'All submenus': '所有子菜单',
    'Shrink all': '收缩所有',
    'Expand all': '展开所有',
    'Expand generic search': '展开通用搜索',
    search: '搜索',
    Reset: '重置',
    to: '至',
    'Link address': '链接地址',
    none: '无',
    unknown: '未知',
    weigh: '权重',
    'No route found to jump~': '没有找到可以跳转的路由~',
}

如何使用
#引用i18n
import { useI18n } from 'vue-i18n'
const { t } = useI18n()

#模板中
 <span>{{ t(`menu.${menu.title}`) }}</span>
 
 #代码中
 message: t('adminLogin.Please enter an account')
 
 #自定义语言文件 比如  /zh-cn/401.ts
 t('401.Please enter an account')
 
  #自定义语言文件 比如  /zh-cn/user/group.ts
 t('user.group.Please enter an account')
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue-i18n-next是Vue3版本的国际化插件,用于支持多语言的开发。你可以通过以下步骤来使用它: 第一步是下载Vue-i18n-next插件。你可以使用npm或yarn来进行下载。使用npm的命令是:npm install vue-i18n@next,而使用yarn的命令是:yarn add vue-i18n@next。 第二步是安装@intlify/vue-i18n-loader插件,这个插件用于自定义块的Vue-i18n加载程序,可以用于i18n资源的预编译。你可以使用npm或yarn来进行安装。使用npm的命令是:npm i --save-dev @intlify/vue-i18n-loader@next,而使用yarn的命令是:yarn add -D @intlify/vue-i18n-loader@next。 第三步是创建语言文件夹并在其中创建js或ts文件。在你的项目的src目录下创建一个名为language的文件夹,并在其中创建你的语言文件,可以使用js或ts格式。 通过以上步骤,你就可以开始在Vue3项目中使用Vue-i18n-next进行国际化开发了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [vue3多语言插件 vue-i18n使用](https://blog.csdn.net/qq_42859450/article/details/126103422)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [vue-i18n-loader:用于自定义块的vue-i18n-loader](https://download.csdn.net/download/weixin_42131628/15097221)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [vue3中多语言切换vue-i18n@next](https://blog.csdn.net/m0_59818968/article/details/119381340)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值