Skip to content

Commit

Permalink
feat: language detect and save (#139)
Browse files Browse the repository at this point in the history
  • Loading branch information
object-kaz authored Jun 18, 2022
1 parent 68b5d0b commit 529fc3d
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 16 deletions.
11 changes: 9 additions & 2 deletions packages/web/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"files.associations": {
"*.css": "postcss"
},
"i18n-ally.sourceLanguage": "en",
"i18n-ally.sourceLanguage": "zh-CN",
"i18n-ally.keystyle": "nested",
"i18n-ally.localesPaths": "locales",
"i18n-ally.sortKeys": true,
Expand All @@ -16,5 +16,12 @@
"vue-sfc",
"i18next"
],
"i18n-ally.extract.autoDetect": true
"i18n-ally.extract.autoDetect": true,
"i18n-ally.refactor.templates": [{
"name": "i18n-ally-vue-sfc",
"extensions": [
"ts",
"i18n.global.t('${key}')"
]
}]
}
26 changes: 17 additions & 9 deletions packages/web/auto-imports.d.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
// Generated by 'unplugin-auto-import'
// We suggest you to commit this file into source control
export {}
declare global {
const $: typeof import('vue/macros')['$']
const $$: typeof import('vue/macros')['$$']
const $: typeof import('vue/macros')['$']
const $computed: typeof import('vue/macros')['$computed']
const $customRef: typeof import('vue/macros')['$customRef']
const $ref: typeof import('vue/macros')['$ref']
const $shallowRef: typeof import('vue/macros')['$shallowRef']
const $toRef: typeof import('vue/macros')['$toRef']
const EffectScope: typeof import('vue')['EffectScope']
const ElMessage: typeof import('element-plus/es')['ElMessage']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const computed: typeof import('vue')['computed']
const computedAsync: typeof import('@vueuse/core')['computedAsync']
const computedEager: typeof import('@vueuse/core')['computedEager']
const computedInject: typeof import('@vueuse/core')['computedInject']
const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
const confirmAsync: typeof import('~/utils/message')['confirmAsync']
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
const controlledRef: typeof import('@vueuse/core')['controlledRef']
const createApp: typeof import('vue')['createApp']
Expand All @@ -31,15 +34,16 @@ declare global {
const defineComponent: typeof import('vue')['defineComponent']
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
const effectScope: typeof import('vue')['effectScope']
const EffectScope: typeof import('vue')['EffectScope']
const ElMessage: typeof import('element-plus/es')['ElMessage']
const errorMsg: typeof import('~/utils/message')['errorMsg']
const extendRef: typeof import('@vueuse/core')['extendRef']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
const inject: typeof import('vue')['inject']
const isDefined: typeof import('@vueuse/core')['isDefined']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const logicAnd: typeof import('@vueuse/core')['logicAnd']
Expand Down Expand Up @@ -84,6 +88,7 @@ declare global {
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const successMsg: typeof import('~/utils/message')['successMsg']
const syncRef: typeof import('@vueuse/core')['syncRef']
const syncRefs: typeof import('@vueuse/core')['syncRefs']
const templateRef: typeof import('@vueuse/core')['templateRef']
Expand Down Expand Up @@ -125,8 +130,8 @@ declare global {
const useDark: typeof import('@vueuse/core')['useDark']
const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
const useDebounce: typeof import('@vueuse/core')['useDebounce']
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
Expand Down Expand Up @@ -208,8 +213,8 @@ declare global {
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
const useThrottle: typeof import('@vueuse/core')['useThrottle']
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
const useTimeout: typeof import('@vueuse/core')['useTimeout']
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
Expand All @@ -220,10 +225,10 @@ declare global {
const useTransition: typeof import('@vueuse/core')['useTransition']
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
const useVibrate: typeof import('@vueuse/core')['useVibrate']
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
const useVModel: typeof import('@vueuse/core')['useVModel']
const useVModels: typeof import('@vueuse/core')['useVModels']
const useVibrate: typeof import('@vueuse/core')['useVibrate']
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
const useWebNotification: typeof import('@vueuse/core')['useWebNotification']
const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
Expand All @@ -232,15 +237,18 @@ declare global {
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
const warnMsg: typeof import('~/utils/message')['warnMsg']
const watch: typeof import('vue')['watch']
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
const watchEffect: typeof import('vue')['watchEffect']
const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable']
const watchOnce: typeof import('@vueuse/core')['watchOnce']
const watchPausable: typeof import('@vueuse/core')['watchPausable']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
const whenever: typeof import('@vueuse/core')['whenever']
const withConfirm: typeof import('~/utils/message')['withConfirm']
}
export {}
7 changes: 5 additions & 2 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
"axios": "^0.27.2",
"dayjs": "^1.11.2",
"element-plus": "^2.2.0",
"get-user-locale": "^1.4.0",
"laf-client-sdk": "^0.8.0-alpha.9",
"lodash": "^4.17.21",
"nprogress": "^0.2.0",
"pinia": "^2.0.14",
"vite-plugin-vue-layouts": "^0.6.0",
"vue": "^3.2.33",
"vue-i18n": "^9.1.10",
"vue-request": "^1.2.4",
"vue-router": "^4.0.15"
},
"devDependencies": {
Expand All @@ -40,8 +43,8 @@
"postcss-nested": "^5.0.6",
"typescript": "^4.6.4",
"unocss": "^0.33.2",
"unplugin-auto-import": "^0.7.1",
"unplugin-vue-components": "^0.19.5",
"unplugin-auto-import": "^0.8.7",
"unplugin-vue-components": "^0.19.6",
"vite": "^2.9.8",
"vite-plugin-pages": "^0.23.0",
"vitest": "^0.12.4",
Expand Down
6 changes: 6 additions & 0 deletions packages/web/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
<script lang="ts" setup>
import { initLanguageModule } from './modules/locales'
initLanguageModule()
</script>

<template>
<main>
<router-view />
Expand Down
8 changes: 5 additions & 3 deletions packages/web/src/layout/components/LanguageMenu.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
<script lang="ts" setup>
import { LanguageOutlined } from '@vicons/material'
import { supportLanguages } from '~/modules/locales'
import { useConfigStore } from '~/store'
withDefaults(defineProps<{
showName?: boolean
}>(), {
showName: false,
})
const { locale } = useI18n()
const config = useConfigStore()
const langText = computed(() => {
return supportLanguages.find(item => item.name === locale.value)?.text || 'Language'
return supportLanguages.find(item => item.name === config.local.language)?.text || 'Language'
})
</script>

Expand All @@ -23,7 +25,7 @@ const langText = computed(() => {
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="lang in supportLanguages" :key="lang.name" :disabled="locale === lang.name" @click="locale = lang.name">
<el-dropdown-item v-for="lang in supportLanguages" :key="lang.name" :disabled="config.language === lang.name" @click="config.local.language = lang.name">
{{ lang.text }}
</el-dropdown-item>
</el-dropdown-menu>
Expand Down
23 changes: 23 additions & 0 deletions packages/web/src/modules/locales.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { createI18n } from 'vue-i18n'
import messages from '@intlify/vite-plugin-vue-i18n/messages'
import { getUserLocales } from 'get-user-locale'
import { intersection } from 'lodash'
import { useConfigStore } from '~/store'

export const i18n = createI18n({
locale: 'en',
Expand All @@ -18,4 +21,24 @@ export const supportLanguages = [
},
]

export const supportLanguageNames = supportLanguages.map(item => item.name)

export const t = i18n.global.t.bind(i18n.global)

// 检测浏览器中的默认语言
export const userLocales = getUserLocales()

// 共有的语言
const commonLanguages = intersection(userLocales, supportLanguageNames)

// 最佳的默认语言
export const bestDefaultLanguage = commonLanguages.length > 0 ? commonLanguages[0] : 'en'

export function initLanguageModule() {
// 同步语言设置
const { locale } = useI18n()
const config = useConfigStore()
watchEffect(() => {
locale.value = config.local.language
})
}
13 changes: 13 additions & 0 deletions packages/web/src/store/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { acceptHMRUpdate, defineStore } from 'pinia'
import { bestDefaultLanguage } from '~/modules/locales'

export const useConfigStore = defineStore('config', () => {
const local = useLocalStorage('laf-config-local', {
language: bestDefaultLanguage,
})

return { local }
})

if (import.meta.hot)
import.meta.hot.accept(acceptHMRUpdate(useConfigStore, import.meta.hot))
1 change: 1 addition & 0 deletions packages/web/src/store/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './user'
export * from './config'

0 comments on commit 529fc3d

Please sign in to comment.