From 4cae64b537fe03666c3865f47b940fd72f8e0607 Mon Sep 17 00:00:00 2001 From: Dream Hunter Date: Thu, 7 Sep 2023 14:11:33 +0800 Subject: [PATCH] feat: add i18n (#14) * feat: add i18n * feat: update readme --- README.md | 1 + README_EN.md | 1 + frontend/package.json | 3 +- frontend/pnpm-lock.yaml | 58 ++++++++++++++++++++++++++++++++++++ frontend/src/App.vue | 53 +++++++++++++++++++++++++++------ frontend/src/Content.vue | 64 +++++++++++++++++++++++++++++++--------- frontend/src/main.js | 13 ++++++++ 7 files changed, 169 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 8c23a3e4..681ef956 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ - [x] email 转发使用 Cloudflare Email Routing - [x] 使用 password 重新登录之前的邮箱 - [x] 获取自定义名字的邮箱 +- [x] 支持多语言 - [ ] 免费版附件过大会造成 Exceeded CPU Limit 错误 --- diff --git a/README_EN.md b/README_EN.md index 9099293a..a05038c4 100644 --- a/README_EN.md +++ b/README_EN.md @@ -14,6 +14,7 @@ This is a temporary email service that uses Cloudflare Workers to create a tempo - [x] Email forwarding using Cloudflare Email Routing - [x] Use password to login to the previous mailbox again. - [x] Get Custom Name Email +- [x] Support multiple languages - [ ] Exceeded CPU Limit error caused by the free version of the attachment ![demo](readme_assets/demo.png) diff --git a/frontend/package.json b/frontend/package.json index 844135c3..33aa94f7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,7 +12,8 @@ "@vueuse/core": "^10.1.2", "naive-ui": "^2.34.3", "vue": "^3.3.4", - "vue-clipboard3": "^2.0.0" + "vue-clipboard3": "^2.0.0", + "vue-i18n": "9" }, "devDependencies": { "@vitejs/plugin-vue": "^4.2.3", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 6b624c0c..7be5be13 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -17,6 +17,9 @@ dependencies: vue-clipboard3: specifier: ^2.0.0 version: 2.0.0 + vue-i18n: + specifier: '9' + version: 9.3.0(vue@3.3.4) devDependencies: '@vitejs/plugin-vue': @@ -276,6 +279,44 @@ packages: dev: true optional: true + /@intlify/core-base@9.3.0: + resolution: {integrity: sha512-SRzn8TMnPZ6MY8OFrgouRq4DGaf01SHcJEF6FglYFYvRkgPzziEcQe+v2PD+O5lUp/rJafP4dabm1CmsVAA7rA==} + engines: {node: '>= 16'} + dependencies: + '@intlify/devtools-if': 9.3.0 + '@intlify/message-compiler': 9.3.0 + '@intlify/shared': 9.3.0 + '@intlify/vue-devtools': 9.3.0 + dev: false + + /@intlify/devtools-if@9.3.0: + resolution: {integrity: sha512-5aKZnqj0Ff4dfwBX2Oo+MheVs00CBnC0RzWK26aT2M4AF0cxdFLOJAs51/eHT01jmzrxSvfBMjdArUWHwgetfg==} + engines: {node: '>= 16'} + dependencies: + '@intlify/shared': 9.3.0 + dev: false + + /@intlify/message-compiler@9.3.0: + resolution: {integrity: sha512-D8tSJEhTCSFcCzkThjE4Sbk1tIdvzkYa1FaVIzUtZ8hKPATvokNrOiDw1i/h671m8A80l9Ywq594i/LPTB6EJA==} + engines: {node: '>= 16'} + dependencies: + '@intlify/shared': 9.3.0 + source-map-js: 1.0.2 + dev: false + + /@intlify/shared@9.3.0: + resolution: {integrity: sha512-MMGRz6zWxtz7rHtxIIdnyb8SYOIaaseN1IvUhAEs9tOW4u77RD4DFp4qgPXesp2Gxo/5QitH9kwSs0jnxGUNEw==} + engines: {node: '>= 16'} + dev: false + + /@intlify/vue-devtools@9.3.0: + resolution: {integrity: sha512-kEaxIz1VEgsz2q5RhoS+fBGTkXr/4+pxmK9mN14+speVGb82HPRntKBmz0GO18I1JisD4Z0vAva+KCTHGeAqbQ==} + engines: {node: '>= 16'} + dependencies: + '@intlify/core-base': 9.3.0 + '@intlify/shared': 9.3.0 + dev: false + /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} @@ -346,6 +387,10 @@ packages: '@vue/compiler-dom': 3.3.4 '@vue/shared': 3.3.4 + /@vue/devtools-api@6.5.0: + resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==} + dev: false + /@vue/reactivity-transform@3.3.4: resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==} dependencies: @@ -677,6 +722,19 @@ packages: vue: 3.3.4 dev: false + /vue-i18n@9.3.0(vue@3.3.4): + resolution: {integrity: sha512-+2L+ae/e4+fixhjym3lgzGCGQG8wVGlGrDHzjfdgUudheHvbVHu5i6tn6FF+buH75UFA7T5ZO2ZO7zrh6CzuaA==} + engines: {node: '>= 16'} + peerDependencies: + vue: ^3.0.0 + dependencies: + '@intlify/core-base': 9.3.0 + '@intlify/shared': 9.3.0 + '@intlify/vue-devtools': 9.3.0 + '@vue/devtools-api': 6.5.0 + vue: 3.3.4 + dev: false + /vue@3.3.4: resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} dependencies: diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 3bacbd11..53ac99ab 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -2,16 +2,20 @@ import { NMessageProvider, NGrid, NBackTop, NLayoutHeader, NInput } from 'naive-ui' import { NGi, NSpace, NButton, NConfigProvider, NSelect, NModal } from 'naive-ui' import { darkTheme, NSwitch, NGlobalStyle, NPopconfirm } from 'naive-ui' +import { zhCN } from 'naive-ui' import { computed, ref } from 'vue' import { useStorage } from '@vueuse/core' +import { useI18n } from 'vue-i18n' import Content from './Content.vue' const jwt = useStorage('jwt') +const localeCache = useStorage('locale', 'zhCN') const themeSwitch = useStorage('themeSwitch', false) const theme = computed(() => themeSwitch.value ? darkTheme : null) const showLogin = ref(false) const password = ref('') +const localeConfig = computed(() => localeCache.value == 'zh' ? zhCN : null) const login = () => { jwt.value = password.value; @@ -21,10 +25,37 @@ const logout = () => { jwt.value = ''; location.reload() } +const changeLocale = (locale) => { + localeCache.value = locale; + location.reload() +} +const { t, locale } = useI18n({ + useScope: 'global', + locale: localeCache.value || 'zh', + messages: { + en: { + title: 'Cloudflare Temp Email', + dark: 'Dark', + light: 'Light', + login: 'Login', + logout: 'Logout', + logoutConfirm: 'Are you sure to logout?', + }, + zh: { + title: 'Cloudflare 临时邮件', + dark: '暗色', + light: '亮色', + login: '登录', + logout: '登出', + logoutConfirm: '确定要登出吗?', + } + } +}); +locale.value = localeCache.value;