Vite2+Vue3学习笔记(四):引入Vue-i18n并实现按钮切换页面语言

目录

参考链接

前言

项目码云Gitea地址

其他文章

四、引入Vue-i18n并实现按钮切换语言

1.安装vue-i18n

 package.json

2.准备语言文件

3.配置文件

4.全局配置

5.修改首页src/components/Main.vue

1)在Element Plus容器布局的例子基础上修改下拉菜单,增加单选按钮组和头像:

2)在setup()中使用vue-i18n:

3)修改单选按钮组和下拉菜单文本,渲染en_US.js中自定义的文本:

4)添加change事件监听单选按钮组,实现点击按钮切换自定义国际化文件的功能:

6. 配置Element Plus组件国际化

7.折腾系列之添加退出登录事件

8.折腾系列之替换首页el-main


参考链接

vue3.0配置vue-i18n - 易函123 - 博客园

vue3国际化如何使用vue-i18n以及解决切换语言不刷新的问题 - baifangzi - 博客园

前言

        本人职场小白,公司让学习Vite和Vue3并搭建项目Demo,借这个机会自己尝试写写博客,主要目的是搭项目,所以原理性的知识没有过多阐述,写博客时也根据步骤复现了,对于新手直接跟着操作就可以把项目搭起来,少走了很多弯路,希望对大家有帮助。

        文中参考链接都有附上,参考时可以看看,如果有任何错误或意见也欢迎大家指点。

项目码云Gitea地址

Vite-Demo: 使用vite2.0及vue3.0并集成Element Plus,开发后台管理系统demo。https://gitee.com/YG-CST/vite-demo

其他文章

Vite2+Vue3学习笔记(一):Vue3.0项目搭建及配置过程_YGいくこさん的博客-CSDN博客

Vite2+Vue3学习笔记(二):引入Vue-Router_YGいくこさん的博客-CSDN博客

Vite2+Vue3学习笔记(三):引入Axios并调用后端接口_YGいくこさん的博客-CSDN博客

四、引入Vue-i18n并实现按钮切换语言

官网:Installation | Vue I18n

1.安装vue-i18n

npm i vue-i18n@next --save

  •  package.json

{
  "name": "test-demo-1",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview"
  },
  "dependencies": {
    "axios": "^0.24.0",
    "element-plus": "^1.2.0-beta.3",
    "sass": "^1.43.5",
    "scss": "^0.2.4",
    "vue": "^3.2.16",
    "vue-i18n": "^9.2.0-beta.20",
    "vue-router": "^4.0.12"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^1.9.3",
    "vite": "^2.6.4"
  }
}

2.准备语言文件

  • src/lang/zh_CN.js

自定义中文文本。

const zh_CN = {
    nav: {
        chi: '简体中文',
        eng: '英语',
        personalCenter: '个人中心',
        logout: '退出登录',
    },
};
export default zh_CN;
  • src/lang/en_US.js

自定义英文文本。

const en_US = {
    nav: {
        chi: 'CN',
        eng: 'EN',
        personalCenter: 'Personal Center',
        logout: 'Sign Out',
    },
};
export default en_US;

3.配置文件

  • src/lang/index.js

import { createI18n } from 'vue-i18n';

// 自定义国际化文件
import zh_CN from './zh_CN';
import en_US from './en_US';

const i18n = createI18n({
    legacy: false, // Composition API 模式
    globalInjection: true, // 全局注册 $t方法
    // 默认语言
    locale: 'zh_CN',
    // 语言库
    messages: {
        zh_CN: zh_CN,
        en_US: en_US
    }
});

// 将i18n暴露出去,在main.js中引入挂载
export default i18n;

4.全局配置

  • src/main.js

// 引入Vue-i18n
import i18n from './lang'

app.use(i18n);

5.修改首页src/components/Main.vue

1)在Element Plus容器布局的例子基础上修改下拉菜单,增加单选按钮组和头像:

官网:Container 布局容器 | Element Plus

<template>
  <el-container style="border: 1px solid #eee">
    <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
      <el-menu :default-openeds="['1', '3']" style="height: 100%">
        ......
      </el-menu>
    </el-aside>
    <el-container>
      <el-header class="flex-center-flex-end">
        <el-radio-group
          v-model="toggle_locale"
          size="mini"
          border
          style="margin-right: 20px"
        >
          <el-radio-button label="简体中文"></el-radio-button>
          <el-radio-button label="英语"></el-radio-button>
        </el-radio-group>
        <el-dropdown>
          <el-avatar
            src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
          ></el-avatar>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item>个人中心</el-dropdown-item>
              <el-dropdown-item>退出登录</el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
      </el-header>
      <el-main>
        ......
      </el-main>
    </el-container>
  </el-container>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import { Message, Menu, Setting } from "@element-plus/icons";
export default defineComponent({
  components: {
    Message,
    Setting,
    "icon-menu": Menu,
  },
  setup() {
    return {
      toggle_locale: ref("简体中文"), //和el-radio-button的label保持一致
    };
  },
});
</script>
<style>
.el-header {
  background-color: #b3c0d1;
  color: var(--el-text-color-primary);
  line-height: 60px;
}
.el-aside {
  color: var(--el-text-color-primary);
}
.flex-center-flex-end {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
</style>

2)在setup()中使用vue-i18n:

<script lang="ts">
import { defineComponent, ref } from "vue";
import { useI18n } from "vue-i18n";

export default defineComponent({
  setup() {  
    // i18n
    const { locale } = useI18n(); // vue-i18n提供了一个钩子函数 useI18n(),暴露出locale属性用于切换语言
    locale.value = "en_US"; // 要切换的语言
    const chi = useI18n().t("nav.chi");
    const eng = useI18n().t("nav.eng");
    let myLocale = useI18n().locale.value; // 记录自定义国际化文件的locale值,为【后续和Element Plus国际化文件的locale区分开】做准备
    
    // 切换按钮组选中值
    const toggle_locale = myLocale === "en_US" ? ref(chi) : ref(eng);
    
    return {
      // i18n
      chi,
      eng,
      toggle_locale,
    };
  },
});
</script>

3)修改单选按钮组和下拉菜单文本,渲染en_US.js中自定义的文本:

<el-header class="flex-center-flex-end">
    <el-radio-group
      v-model="toggle_locale"
      size="mini"
      border
      style="margin-right: 20px"
    >
      <el-radio-button :label="chi">{{ $t("nav.chi") }}</el-radio-button>
      <el-radio-button :label="eng">{{ $t("nav.eng") }}</el-radio-button>
    </el-radio-group>
    <el-dropdown>
      <el-avatar
        src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
      ></el-avatar>
      <template #dropdown>
        <el-dropdown-menu>
          <el-dropdown-item>{{ $t("nav.personalCenter") }}</el-dropdown-item>
          <el-dropdown-item>{{ $t("nav.logout") }}</el-dropdown-item>
        </el-dropdown-menu>
      </template>
    </el-dropdown>
</el-header>

4)添加change事件监听单选按钮组,实现点击按钮切换自定义国际化文件的功能:

  • <template>
<el-radio-group
    v-model="toggle_locale"
    size="mini"
    border
    style="margin-right: 20px"
    @change="changeLanguage"
  >
    <el-radio-button :label="chi">{{ $t("nav.chi") }}</el-radio-button>
    <el-radio-button :label="eng">{{ $t("nav.eng") }}</el-radio-button>
</el-radio-group>
  • <script> - setup()

按钮切换后把当前语言环境记录到localStorage中,用户刷新页面时根据localStorage的是否有值渲染当前页面的文本(※处)。

// i18n
const { locale } = useI18n(); // vue-i18n提供了一个钩子函数 useI18n(),暴露出locale属性用于切换语言
locale.value = localStorage.getItem("locale") || "zh_CN"; // 要切换的语言	——※
const chi = useI18n().t("nav.chi");
const eng = useI18n().t("nav.eng");
let myLocale = useI18n().locale.value;

const changeLanguage = (e) => {
  if (e == chi) {
    myLocale = "zh_CN";
    locale.value = "zh_CN";
  } else if (e == eng) {
    myLocale = "en_US";
    locale.value = "en_US";
  }
  localStorage.setItem("locale", myLocale); // ——※
};

// 定义方法集合,整体return出去
let methods = {
  // 切换语言
  changeLanguage,
};
return {
  // i18n
  chi,
  eng,
  toggle_locale,
  ...methods,
};

到这里就可以实现按钮切换页面语言了,但其实还没结束......

引入Element Plus的取色器组件(随便一个组件都可以),会发现切换按钮时,只有通过{{t("")}}或者userI18n().t()两种方式渲染的文本会变化,组件内部文本是不会切换语言的,所以需要配置Element Plus组件国际化。

6. 配置Element Plus组件国际化

参考官方文档:

国际化全局配置:国际化 | Element Plus

使用Config Provider全局配置:全局配置 | Element Plus

  • src/main.js

全局配置,判断当前localStorage的值并初始化:

// Element Plus全局配置国际化
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import en from "element-plus/lib/locale/lang/en";

// app.use(ElementPlus);
app.use(ElementPlus, {
    // locale: zhCn,
    locale: localStorage.getItem('locale') == 'zh_CN' ? zhCn : en,
});
app.mount('#app');
  • src/components/Main.vue

  • <template>

把el-container包裹在el-config-provider中:

<template>
  <el-config-provider :locale="elLocale">
    <el-container>
    ......
    </el-container>
  </el-config-provider>
</template>
  • <script>

修改※处。

注意:要删除<script>标签后面的【lang="ts"】,否则会报错。

<script>
// ElementPlus组件国际化
import { ElConfigProvider } from "element-plus";
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import en from "element-plus/lib/locale/lang/en";

export default defineComponent({
  components: {
    ElConfigProvider,
  },
  setup() {
    // i18n
    // 自定义国际化
    const { locale } = useI18n(); // vue-i18n提供了一个钩子函数 useI18n(),暴露出locale属性用于切换语言
    locale.value = localStorage.getItem("locale") || "zh_CN"; // 要切换的语言
    const chi = useI18n().t("nav.chi");
    const eng = useI18n().t("nav.eng");
    let myLocale = useI18n().locale.value;
    
    // Element Plus组件国际化
    const elLocale_zh = ref(zhCn);
    const elLocale_en = ref(en);
    let elLocale = localStorage.getItem("locale") == "zh_CN" ? elLocale_zh : elLocale_en;
    
    // 切换按钮组选中值
    const toggle_locale = myLocale === "zh_CN" ? ref(chi) : ref(eng);
    
    // 单选按钮组监听事件
    const changeLanguage = (e) => {
      if (e == chi) {
        myLocale = "zh_CN";
        locale.value = "zh_CN";
        // 组件国际化
        const temp = elLocale_zh.value;
        elLocale_zh.value = elLocale_en.value;
        elLocale_en.value = temp;
      } else if (e == eng) {
        myLocale = "en_US";
        locale.value = "en_US";
        // 组件国际化
        const temp = elLocale_en.value;
        elLocale_en.value = elLocale_zh.value;
        elLocale_zh.value = temp;
      }
      localStorage.setItem("locale", myLocale);
    };
    
    let methods = {
      // 切换语言
      changeLanguage,
    };
    
    return {
      // i18n
      chi,
      eng,
      toggle_locale,
      colorPicker: ref("#409EFF"),
      elLocale,
      ...methods,
    };
  },
});
</script>

7.折腾系列之添加退出登录事件

  • <template>

<el-dropdown-menu>
    <el-dropdown-item>{{ $t("nav.personalCenter") }}</el-dropdown-item>
    <el-dropdown-item @click="logout">{{ $t("nav.logout") }}</el-dropdown-item>
</el-dropdown-menu>
  • <script> - setup()

// 退出登录
const logout = () => {
  localStorage.removeItem("Token");
  window.location.href = "/login";
};

let methods = {
  // 退出登录
  logout,
  // 切换语言
  changeLanguage,
};

8.折腾系列之替换首页el-main

  • src/views/AppList.vue

<template>
  <el-table :data="tableData">
    <el-table-column prop="date" label="Date" width="140"> </el-table-column>
    <el-table-column prop="name" label="Name" width="120"> </el-table-column>
    <el-table-column prop="address" label="Address"> </el-table-column>
  </el-table>
</template>

<script>
import { defineComponent, ref } from "vue";
export default defineComponent({
  components: {},
  setup() {
    // 表格数据
    const item = {
      date: "2016-05-02",
      name: "Tom",
      address: "No. 189, Grove St, Los Angeles",
    };
    const tableData = ref(Array(20).fill(item));
    let methods = {};
    return {
      // 表格数据
      tableData,
      ...methods,
    };
  },
});
</script>

<style></style>
  • src/components/Main.vue

<el-main>
  <router-view></router-view>
</el-main>
  • src/router/index.js

import { createRouter, createWebHistory } from "vue-router";
const routerHistory = createWebHistory();
const router = createRouter({
    history: routerHistory,
    routes: [{
        path: "/login",
        name: "login",
        component: () =>
            import ("../components/Login.vue")
    }, {
        path: "/", // 父级路径
        name: "main",
        component: () =>
            import ("../components/Main.vue"),
        children: [{
                path: "/", // 空路径路由的路径与父级路径保持一致,否则会显示Main.vue,没有渲染router-view
                redirect: "/appList"
            }, // 定义空路径,用户访问localhost:5000时跳转至首页
            {
                path: "/appList",
                name: "appList",
                component: () =>
                    import ("../views/AppList.vue")
            }
        ]
    }, {
        path: "/:pathMatch(.*)*",
        name: "notFound",
        component: () =>
            import ("../components/NotFound.vue")
    }]
});

// 路由守卫
router.beforeEach((to) => {
    let token = localStorage.getItem('Token');
    if (token && to.path === '/login')
        return "/appList";
    else if (!token && to.path !== '/login')
        return "/login";
});

export default router;

2022年04月13日更新:

感谢评论区涩谷同学提出的问题,测试后发现了问题,代码更新记录请戳链接:

Gitee仓库代码更新记录

<!-- Main.vue -->
<el-dropdown>
    {{ $t("label.test") }}
    {{ testRefreshData1 }}
</el-dropdown>
// Main.vue
/**
 * 测试更新自定义data是否需要刷新
 * 解析:确实需要手动刷新页面才会更新,个人理解是国际化相关配置文件只在页面加载时重新引入,而setup中的响应式数据是热更新的,只要lang文件夹下的文件内容没有改变,就不会重新引入,所以需要手动刷新使页面重新import相关文件。
 * 测试:修改zh_CN中的label.test文本时页面是自动刷新的,所以按钮切换无效。
 * 结论:如果确实需要按钮切换更新页面文本,建议:
 *      1.要么自己在template中使用{{t()}},这个可以实现无刷新按钮切换;
 *      2.要么就在setup中监测自定义data的改变,一改变就强制刷新页面【不推荐,用户体验不好】。
*/
const testRefreshData1 = reactive(useI18n().t("label.test"));

return {
    testRefreshData1,
}
// 国际化配置文件
const zh_CN = {
  nav: {
    chi: '简体中文',
    eng: '英语',
    personalCenter: '个人中心',
    logout: '退出登录',
  },
  label: {
    test: '测试刷新更新文本'
  }
};

export default zh_CN;


const en_US = {
  nav: {
    chi: 'CN',
    eng: 'EN',
    personalCenter: 'Personal Center',
    logout: 'Sign Out',
  },
  label: {
    test: 'Test Refresh Update Text'
  }
};

export default en_US;

如果解释不对请大神们指出,谢谢~

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值