feat: 自定义外部国际化文件

This commit is contained in:
fit2cloud-chenyw
2024-12-24 14:44:39 +08:00
committed by ulleo
parent 57853fd89c
commit 2fe2e67a80
11 changed files with 107 additions and 24 deletions

View File

@@ -37,6 +37,10 @@ public class DeMvcConfig implements WebMvcConfigurer {
String geoUrlPattern = ensureBoth(GEO_URL, AuthConstant.DE_API_PREFIX, URL_SEPARATOR) + "**";
registry.addResourceHandler(geoUrlPattern).addResourceLocations(geoDir);
String i18nDir = FILE_PROTOCOL + ensureSuffix(I18N_DIR, FILE_SEPARATOR);
String i18nUrlPattern = ensureBoth(I18N_URL, AuthConstant.DE_API_PREFIX, URL_SEPARATOR) + "**";
registry.addResourceHandler(i18nUrlPattern).addResourceLocations(i18nDir);
}
@Override

View File

@@ -4,14 +4,17 @@ import io.dataease.api.system.SysParameterApi;
import io.dataease.api.system.request.OnlineMapEditor;
import io.dataease.api.system.vo.SettingItemVO;
import io.dataease.api.system.vo.ShareBaseVO;
import io.dataease.constant.StaticResourceConstants;
import io.dataease.constant.XpackSettingConstants;
import io.dataease.system.dao.auto.entity.CoreSysSetting;
import io.dataease.system.manage.SysParameterManage;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -52,10 +55,9 @@ public class SysParameterServer implements SysParameterApi {
@Override
public Integer RequestTimeOut() {
Integer frontTimeOut = 60;
int frontTimeOut = 60;
List<SettingItemVO> settingItemVOS = queryBasicSetting();
for (int i = 0; i < settingItemVOS.size(); i++) {
SettingItemVO settingItemVO = settingItemVOS.get(i);
for (SettingItemVO settingItemVO : settingItemVOS) {
if (StringUtils.isNotBlank(settingItemVO.getPkey()) && settingItemVO.getPkey().equalsIgnoreCase(XpackSettingConstants.Front_Time_Out) && StringUtils.isNotBlank(settingItemVO.getPval())) {
frontTimeOut = Integer.parseInt(settingItemVO.getPval());
}
@@ -69,8 +71,7 @@ public class SysParameterServer implements SysParameterApi {
map.put(XpackSettingConstants.DEFAULT_SORT, "1");
List<SettingItemVO> settingItemVOS = queryBasicSetting();
for (int i = 0; i < settingItemVOS.size(); i++) {
SettingItemVO settingItemVO = settingItemVOS.get(i);
for (SettingItemVO settingItemVO : settingItemVOS) {
if (StringUtils.isNotBlank(settingItemVO.getPkey()) && settingItemVO.getPkey().equalsIgnoreCase(XpackSettingConstants.DEFAULT_SORT) && StringUtils.isNotBlank(settingItemVO.getPval())) {
map.put(XpackSettingConstants.DEFAULT_SORT, settingItemVO.getPval());
}
@@ -95,4 +96,24 @@ public class SysParameterServer implements SysParameterApi {
public ShareBaseVO shareBase() {
return sysParameterManage.shareBase();
}
@Override
public Map<String, String> i18nOptions() {
File dir = new File(StaticResourceConstants.I18N_DIR);
File[] files = null;
if (!dir.exists() || ObjectUtils.isEmpty(files = dir.listFiles())) {
return null;
}
Map<String, String> result = new HashMap<>();
for (File file : files) {
String name = file.getName();
int start = name.indexOf("custom_") + 7;
int end = name.indexOf("front");
String i18nName = name.substring(start, end - 1).replace("_", "-");
String languageName = name.substring(end + 6, name.lastIndexOf("."));
result.put(i18nName, languageName);
}
return result;
}
}

View File

@@ -171,7 +171,10 @@ service.interceptors.response.use(
} else if (response.config.url.match(/^\/map|geo\/\d{3}\/\d+\.json$/)) {
// TODO 处理静态文件
return response
} else if (response.config.url.includes('DEXPack.umd.js')) {
} else if (
response.config.url.includes('DEXPack.umd.js') ||
response.config.url.includes('/i18n/custom_')
) {
return response
} else if (response.config.url.startsWith('/xpackComponent/pluginStaticInfo/extensions-')) {
return response

View File

@@ -279,7 +279,7 @@ if (uid.value === '1') {
padding-bottom: 0 !important;
}
.language-popover {
max-height: 112px;
// max-height: 112px;
.ed-popper__arrow {
display: none;
}

View File

@@ -1,12 +1,15 @@
<script lang="ts" setup>
import icon_done_outlined from '@/assets/svg/icon_done_outlined.svg'
import { ref, onMounted } from 'vue'
import { ref, onMounted, reactive } from 'vue'
import { Icon } from '@/components/icon-custom'
import { useUserStoreWithOut } from '@/store/modules/user'
import { usePermissionStoreWithOut } from '@/store/modules/permission'
import { useLocaleStoreWithOut } from '@/store/modules/locale'
import { switchLangApi } from '@/api/user'
const permissionStore = usePermissionStoreWithOut()
const userStore = useUserStoreWithOut()
const localeStore = useLocaleStoreWithOut()
const language = ref(null)
const handleSetLanguage = lang => {
const param = { lang }
@@ -19,13 +22,16 @@ const handleSetLanguage = lang => {
}
})
}
const options = [
{ value: 'zh-CN', name: '简体中文' },
{ value: 'tw', name: '繁體中文' },
{ value: 'en', name: 'English' }
]
onMounted(() => {
const options = reactive([])
onMounted(async () => {
language.value = userStore.getLanguage
const localeMap = await localeStore.getLocaleMap
localeMap.forEach(item => {
const option = { value: item['lang'], name: item['name'] }
options.push(option)
})
})
</script>
<template>

View File

@@ -3,21 +3,34 @@ import { createI18n } from 'vue-i18n'
import { useLocaleStoreWithOut } from '@/store/modules/locale'
import type { I18n, I18nOptions } from 'vue-i18n'
import { setHtmlPageLang } from './helper'
export let i18n: ReturnType<typeof createI18n>
import { PATH_URL } from '@/config/axios/service'
const createI18nOptions = async (): Promise<I18nOptions> => {
const localeStore = useLocaleStoreWithOut()
const locale = localeStore.getCurrentLocale
const localeMap = localeStore.getLocaleMap
const defaultLocal = await import(`../../locales/${locale.lang}.ts`)
let locale = localeStore.getCurrentLocale
const localeMap = await localeStore.getLocaleMap
const cMap: any = localeMap.find(item => {
return item.lang === locale.lang
})
let defaultLocal = null
if (cMap) {
if (cMap['custom']) {
defaultLocal = await loadRemoteI18n(cMap)
} else {
defaultLocal = await import(`../../locales/${locale.lang}.ts`)
}
} else {
const item = localeMap[0]
localeStore.setLang(item.lang)
locale = localeStore.getCurrentLocale
defaultLocal = await import(`../../locales/${locale.lang}.ts`)
}
const message = defaultLocal.default ?? {}
setHtmlPageLang(locale.lang)
localeStore.setCurrentLocale({
lang: locale.lang
// elLocale: elLocal
})
return {
@@ -35,6 +48,13 @@ const createI18nOptions = async (): Promise<I18nOptions> => {
}
}
const loadRemoteI18n = async (option: any) => {
const name = option.lang.replace('-', '_')
// const basePath = import.meta.env.VITE_API_BASEPATH
const url = `${PATH_URL}/i18n/custom_${name}_front_${option.name}.js`
return await import(url)
}
export const setupI18n = async (app: App<Element>) => {
const options = await createI18nOptions()
i18n = createI18n(options) as I18n

View File

@@ -5,13 +5,14 @@ import zhCn from 'element-plus-secondary/es/locale/lang/zh-cn'
import en from 'element-plus-secondary/es/locale/lang/en'
import tw from 'element-plus-secondary/es/locale/lang/zh-tw'
import { getLocale } from '@/utils/utils'
import request from '@/config/axios'
const elLocaleMap = {
'zh-CN': zhCn,
en: en,
tw: tw
}
interface LocaleState {
customLoaded: boolean
currentLocale: LocaleDropdownType
localeMap: LocaleDropdownType[]
}
@@ -19,6 +20,7 @@ interface LocaleState {
export const useLocaleStore = defineStore('locales', {
state: (): LocaleState => {
return {
customLoaded: false,
currentLocale: {
lang: getLocale(),
elLocale: elLocaleMap[getLocale()]
@@ -44,8 +46,27 @@ export const useLocaleStore = defineStore('locales', {
getCurrentLocale(): LocaleDropdownType {
return this.currentLocale
},
getLocaleMap(): LocaleDropdownType[] {
return this.localeMap
async getLocaleMap(): Promise<LocaleDropdownType[]> {
if (this.customLoaded) {
return this.localeMap
}
try {
const res = await request.get({ url: '/sysParameter/i18nOptions' })
this.customLoaded = true
const customMap = res.data
for (const key in customMap) {
const item = {
lang: key,
name: customMap[key],
custom: true
}
this.localeMap.push(item)
}
return this.localeMap
} catch (error) {
this.customLoaded = true
return this.localeMap
}
}
},
actions: {

View File

@@ -3,7 +3,7 @@ import { store } from '../index'
import { useCache } from '@/hooks/web/useCache'
import { useLocaleStoreWithOut } from './locale'
const { wsCache } = useCache()
const locale = useLocaleStoreWithOut()
interface UserState {
token: string
uid: string
@@ -91,6 +91,7 @@ export const userStore = defineStore('user', {
this.oid = oid
},
setLanguage(language: string) {
const locale = useLocaleStoreWithOut()
if (!language || language === 'zh_CN') {
language = 'zh-CN'
}

View File

@@ -62,4 +62,7 @@ public interface SysParameterApi {
@Operation(summary = "查询分享设置")
ShareBaseVO shareBase();
@GetMapping("/i18nOptions")
@Operation(summary = "查询自定义国际化选项")
Map<String, String> i18nOptions();
}

View File

@@ -20,9 +20,11 @@ public class StaticResourceConstants {
public static String APPEARANCE_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "appearance";
public static String REPORT_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "report";
public static String PLUGIN_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "plugin";
public static String I18N_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "i18n/front";
public static String MAP_URL = "/map";
public static String GEO_URL = "/geo";
public static String I18N_URL = "/i18n";
/**
* Upload prefix.

View File

@@ -46,6 +46,7 @@ public class WhitelistUtils {
"/sysParameter/ui",
"/sysParameter/defaultLogin",
"/embedded/initIframe",
"/sysParameter/i18nOptions",
"/");
public static boolean match(String requestURI) {
@@ -84,6 +85,7 @@ public class WhitelistUtils {
|| StringUtils.startsWithAny(requestURI, "/typeface/defaultFont")
|| StringUtils.startsWithAny(requestURI, "/typeface/listFont")
|| StringUtils.startsWithAny(requestURI, "/exportCenter/download")
|| StringUtils.startsWithAny(requestURI, "/i18n/")
|| StringUtils.startsWithAny(requestURI, "/communicate/image/")
|| StringUtils.startsWithAny(requestURI, "/communicate/down/");
}