Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"dbaeumer.vscode-eslint",
"antfu.unocss",
"vitest.explorer",
"wiensss.region-highlighter"
"wiensss.region-highlighter",
"lokalise.i18n-ally"
]
}
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,10 @@
"scss",
"pcss",
"postcss"
]
],
"i18n-ally.localesPaths": [
"src/i18n/locale"
],
"i18n-ally.keystyle": "nested",
"i18n-ally.displayLanguage": "zh-cn"
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"pinia": "3.0.4",
"screenfull": "6.0.2",
"vue": "3.5.25",
"vue-i18n": "11.2.2",
"vue-router": "4.6.3",
"vxe-table": "4.6.25"
},
Expand Down
40 changes: 40 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<script lang="ts" setup>
import { useGreyAndColorWeakness } from "@@/composables/useGreyAndColorWeakness"
import { useLanguage } from "@@/composables/useLanguage"
import { usePany } from "@@/composables/usePany"
import { useTheme } from "@@/composables/useTheme"
import zhCn from "element-plus/es/locale/lang/zh-cn" // Element Plus 中文包

const { epLocale } = useLanguage()

const { initTheme } = useTheme()

Expand All @@ -26,7 +28,7 @@ initMobileNotification()
</script>

<template>
<el-config-provider :locale="zhCn">
<el-config-provider :locale="epLocale" :z-index="20000">
<router-view />
</el-config-provider>
</template>
1 change: 1 addition & 0 deletions src/common/assets/icons/language.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions src/common/components/LanguageSwitch/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
import { useLanguage } from "@/common/composables/useLanguage"

const { languageList, setLanguage, activeLanguageName } = useLanguage()
</script>

<template>
<el-dropdown trigger="click">
<div>
<el-tooltip effect="dark" :content="$t('languageSwitch.tooltip')" placement="bottom">
<SvgIcon name="language" class="svg-icon" />
</el-tooltip>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
v-for="item in languageList"
:key="item.name"
:disabled="activeLanguageName === item.name"
@click="() => setLanguage(item.name)"
>
{{ item.title }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>

<style lang="scss" scoped>
.svg-icon {
font-size: 20px;
&:focus {
outline: none;
}
}
</style>
16 changes: 7 additions & 9 deletions src/common/components/Screenfull/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ import screenfull from "screenfull"
interface Props {
/** 全屏的元素,默认是 html */
element?: string
/** 打开全屏提示语 */
openTips?: string
/** 关闭全屏提示语 */
exitTips?: string
/** 是否只针对内容区 */
content?: boolean
}

const { element = "html", openTips = "全屏", exitTips = "退出全屏", content = false } = defineProps<Props>()
const { element = "html", content = false } = defineProps<Props>()

const { t } = useI18n()

const CONTENT_LARGE = "content-large"

Expand All @@ -25,13 +23,13 @@ const isEnabled = screenfull.isEnabled

const isFullscreen = ref<boolean>(false)

const fullscreenTips = computed(() => (isFullscreen.value ? exitTips : openTips))
const fullscreenTips = computed(() => (isFullscreen.value ? t("screenFull.exitTips") : t("screenFull.openTips")))

const fullscreenSvgName = computed(() => (isFullscreen.value ? "fullscreen-exit" : "fullscreen"))

function handleFullscreenClick() {
const dom = document.querySelector(element) || undefined
isEnabled ? screenfull.toggle(dom) : ElMessage.warning("您的浏览器无法工作")
isEnabled ? screenfull.toggle(dom) : ElMessage.warning(t("screenFull.browserNotSupport"))
}

function handleFullscreenChange() {
Expand All @@ -55,7 +53,7 @@ watchEffect(() => {
// #region 内容区
const isContentLarge = ref<boolean>(false)

const contentLargeTips = computed(() => (isContentLarge.value ? "内容区复原" : "内容区放大"))
const contentLargeTips = computed(() => (isContentLarge.value ? t("screenFull.contentRestore") : t("screenFull.contentLarge")))

const contentLargeSvgName = computed(() => (isContentLarge.value ? "fullscreen-exit" : "fullscreen"))

Expand Down Expand Up @@ -93,7 +91,7 @@ function handleContentFullClick() {
</el-dropdown-item>
<!-- 内容区全屏 -->
<el-dropdown-item @click="handleContentFullClick">
内容区全屏
{{ $t("screenFull.contentFull") }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
Expand Down
8 changes: 4 additions & 4 deletions src/common/components/SearchMenu/Footer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ const { isMobile } = useDevice()
<template v-if="!isMobile">
<span class="search-footer-item">
<SvgIcon name="keyboard-enter" class="svg-icon" />
<span>确认</span>
<span>{{ $t("searchMenu.confirm") }}</span>
</span>
<span class="search-footer-item">
<SvgIcon name="keyboard-up" class="svg-icon" />
<SvgIcon name="keyboard-down" class="svg-icon" />
<span>切换</span>
<span>{{ $t("searchMenu.switch") }}</span>
</span>
<span class="search-footer-item">
<SvgIcon name="keyboard-esc" class="svg-icon" />
<span>关闭</span>
<span>{{ $t("searchMenu.close") }}</span>
</span>
</template>
<span class="search-footer-total">{{ props.total }} 项</span>
<span class="search-footer-total">{{ $t("searchMenu.total", { total: props.total }) }}</span>
</div>
</template>

Expand Down
6 changes: 3 additions & 3 deletions src/common/components/SearchMenu/Modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,14 @@ function handleReleaseUpOrDown() {
@keydown.enter="handleEnter"
@keyup.up.down="handleReleaseUpOrDown"
>
<el-input ref="inputRef" v-model="keyword" placeholder="搜索菜单" size="large" clearable @input="handleSearch">
<el-input ref="inputRef" v-model="keyword" :placeholder="$t('searchMenu.placeholder')" size="large" clearable @input="handleSearch">
<template #prefix>
<SvgIcon name="search" class="svg-icon" />
</template>
</el-input>
<el-empty v-if="result.length === 0" description="暂无搜索结果" :image-size="100" />
<el-empty v-if="result.length === 0" :description="$t('searchMenu.noResult')" :image-size="100" />
<template v-else>
<p>搜索结果</p>
<p>{{ $t("searchMenu.result") }}</p>
<el-scrollbar ref="scrollbarRef" max-height="40vh" always>
<Result
ref="resultRef"
Expand Down
2 changes: 1 addition & 1 deletion src/common/components/SearchMenu/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function handleOpen() {

<template>
<div>
<el-tooltip effect="dark" content="搜索菜单" placement="bottom">
<el-tooltip effect="dark" :content="$t('searchMenu.tooltip')" placement="bottom">
<SvgIcon name="search" @click="handleOpen" class="svg-icon" />
</el-tooltip>
<Modal v-model="visible" />
Expand Down
4 changes: 2 additions & 2 deletions src/common/components/ThemeSwitch/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { themeList, activeThemeName, setTheme } = useTheme()
<template>
<el-dropdown trigger="click">
<div>
<el-tooltip effect="dark" content="主题模式" placement="bottom">
<el-tooltip effect="dark" :content="$t('themeSwitch.tooltip')" placement="bottom">
<el-icon :size="20">
<MagicStick />
</el-icon>
Expand All @@ -22,7 +22,7 @@ const { themeList, activeThemeName, setTheme } = useTheme()
:disabled="activeThemeName === theme.name"
@click="(e: MouseEvent) => setTheme(e, theme.name)"
>
<span>{{ theme.title }}</span>
<span>{{ $t(`themeSwitch.${theme.title}`) }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
Expand Down
43 changes: 43 additions & 0 deletions src/common/composables/useLanguage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import en from "element-plus/es/locale/lang/en" // Element Plus 英文包
import zhCn from "element-plus/es/locale/lang/zh-cn" // Element Plus 中文包
import { i18n } from "@/i18n"
import { getActiveLanguageName, setActiveLanguageName } from "../utils/cache/local-storage"

/** 注册的语言名称 */
export enum LanguageName {
ZH_CN = "zh-cn",
EN = "en"
}

const DEFAULT_LANGUAGE = LanguageName.ZH_CN

/** 语言列表 */
const languageList = [
{ title: "简体中文", name: LanguageName.ZH_CN },
{ title: "English", name: LanguageName.EN }
]

/** 正在应用的语言 */
const activeLanguageName = ref<LanguageName>(getActiveLanguageName() || DEFAULT_LANGUAGE)

/** 设置语言 */
function setLanguage(value: LanguageName) {
activeLanguageName.value = value
setActiveLanguageName(value)
i18n.global.locale.value = value
}

/** Element Plus 语言包 */
const epLocale = computed(() => {
switch (activeLanguageName.value) {
case LanguageName.EN:
return en
case LanguageName.ZH_CN:
default:
return zhCn
}
})

export function useLanguage() {
return { epLocale, languageList, activeLanguageName, setLanguage }
}
1 change: 1 addition & 0 deletions src/common/constants/cache-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export class CacheKey {
static readonly CONFIG_LAYOUT = `${SYSTEM_NAME}-config-layout-key`
static readonly SIDEBAR_STATUS = `${SYSTEM_NAME}-sidebar-status-key`
static readonly ACTIVE_THEME_NAME = `${SYSTEM_NAME}-active-theme-name-key`
static readonly ACTIVE_LANGUAGE_NAME = `${SYSTEM_NAME}-active-language-name-key`
static readonly VISITED_VIEWS = `${SYSTEM_NAME}-visited-views-key`
static readonly CACHED_VIEWS = `${SYSTEM_NAME}-cached-views-key`
}
11 changes: 11 additions & 0 deletions src/common/utils/cache/local-storage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// 统一处理 localStorage

import type { LanguageName } from "@@/composables/useLanguage"
import type { ThemeName } from "@@/composables/useTheme"
import type { SidebarClosed, SidebarOpened } from "@@/constants/app-key"
import type { LayoutsConfig } from "@/layouts/config"
Expand Down Expand Up @@ -41,6 +42,16 @@ export function setActiveThemeName(themeName: ThemeName) {
}
// #endregion

// #region 正在应用的语言名称
export function getActiveLanguageName() {
return localStorage.getItem(CacheKey.ACTIVE_LANGUAGE_NAME) as LanguageName | null
}

export function setActiveLanguageName(languageName: LanguageName) {
localStorage.setItem(CacheKey.ACTIVE_LANGUAGE_NAME, languageName)
}
// #endregion

// #region 标签栏
export function getVisitedViews() {
const json = localStorage.getItem(CacheKey.VISITED_VIEWS)
Expand Down
12 changes: 12 additions & 0 deletions src/common/utils/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Translate router.meta.title for use in breadcrumb, sidebar, and tagsview
import { i18n } from "@/i18n"

export function translateRouteTitle(title: string = "") {
// 判断是否存在国际化配置,如果没有原生返回
const hasKey = i18n.global.te(`route.${title}`)
if (hasKey) {
const translatedTitle = i18n.global.t(`route.${title}`)
return translatedTitle
}
return title
}
Loading