59 changed files with 512 additions and 272 deletions
@ -0,0 +1,3 @@ |
|||
import AppLocalPicker from './src/AppLocalPicker.vue'; |
|||
|
|||
export { AppLocalPicker }; |
|||
@ -0,0 +1,53 @@ |
|||
<template> |
|||
<Dropdown |
|||
:trigger="['click']" |
|||
:dropMenuList="localeList" |
|||
:selectedKeys="selectedKeys" |
|||
@menuEvent="handleMenuEvent" |
|||
> |
|||
<GlobalOutlined class="app-locale" /> |
|||
</Dropdown> |
|||
</template> |
|||
<script lang="ts"> |
|||
import { defineComponent, ref, watchEffect, unref } from 'vue'; |
|||
|
|||
import { Dropdown, DropMenu } from '/@/components/Dropdown'; |
|||
import { GlobalOutlined } from '@ant-design/icons-vue'; |
|||
|
|||
import { useLocale } from '/@/hooks/web/useLocale'; |
|||
import { useLocaleSetting } from '/@/settings/use/useLocaleSetting'; |
|||
|
|||
import { LocaleType } from '/@/locales/types'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'AppLocalPicker', |
|||
components: { GlobalOutlined, Dropdown }, |
|||
setup() { |
|||
const { localeList } = useLocaleSetting(); |
|||
const selectedKeys = ref<string[]>([]); |
|||
|
|||
const { changeLocale, getLang } = useLocale(); |
|||
|
|||
watchEffect(() => { |
|||
selectedKeys.value = [unref(getLang)]; |
|||
}); |
|||
|
|||
function toggleLocale(lang: LocaleType | string) { |
|||
changeLocale(lang as LocaleType); |
|||
selectedKeys.value = [lang as string]; |
|||
} |
|||
|
|||
function handleMenuEvent(menu: DropMenu) { |
|||
toggleLocale(menu.event as string); |
|||
} |
|||
|
|||
return { localeList, handleMenuEvent, selectedKeys }; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.app-locale { |
|||
cursor: pointer; |
|||
} |
|||
</style> |
|||
@ -1,2 +1,2 @@ |
|||
export { default as Dropdown } from './Dropdown'; |
|||
export * from './types'; |
|||
export { default as Dropdown } from './src/Dropdown'; |
|||
export * from './src/types'; |
|||
|
|||
@ -1,16 +0,0 @@ |
|||
import { createI18n } from 'vue-i18n'; |
|||
import { ref, watch } from 'vue'; |
|||
import type { I18nOptions } from 'vue-i18n'; |
|||
export function useI18n(options?: I18nOptions) { |
|||
const i18n = createI18n(options); |
|||
|
|||
const localeRef = ref(i18n.global.locale); |
|||
|
|||
watch(localeRef, () => { |
|||
i18n.global.locale = localeRef.value as any; |
|||
}); |
|||
return { |
|||
t: i18n.global.t, |
|||
localeRef, |
|||
}; |
|||
} |
|||
@ -1,21 +1,74 @@ |
|||
/** |
|||
* Multi-language related operations |
|||
*/ |
|||
import type { LocaleType } from '/@/locales/types'; |
|||
import { appStore } from '/@/store/modules/app'; |
|||
|
|||
import { unref, ref } from 'vue'; |
|||
|
|||
import { getI18n } from '/@/setup/i18n'; |
|||
|
|||
import { useLocaleSetting } from '/@/settings/use/useLocaleSetting'; |
|||
|
|||
import moment from 'moment'; |
|||
|
|||
import 'moment/dist/locale/zh-cn'; |
|||
|
|||
moment.locale('zh-cn'); |
|||
|
|||
const antConfigLocaleRef = ref<any>(null); |
|||
|
|||
export function useLocale() { |
|||
/** |
|||
* |
|||
*/ |
|||
function getLocale(): string { |
|||
return appStore.getProjectConfig.locale; |
|||
const { getLang, getLocale, setLocale: setLocalSetting } = useLocaleSetting(); |
|||
|
|||
// Switching the language will change the locale of useI18n
|
|||
// And submit to configuration modification
|
|||
function changeLocale(lang: LocaleType): void { |
|||
(getI18n().global.locale as any).value = lang; |
|||
setLocalSetting({ lang }); |
|||
// i18n.global.setLocaleMessage(locale, messages);
|
|||
|
|||
antConfigLocaleRef.value = { a: 1 }; |
|||
switch (lang) { |
|||
// Simplified Chinese
|
|||
case 'zh_CN': |
|||
import('ant-design-vue/es/locale/zh_CN').then((locale) => { |
|||
antConfigLocaleRef.value = locale.default; |
|||
}); |
|||
|
|||
moment.locale('cn'); |
|||
break; |
|||
// English
|
|||
case 'en': |
|||
import('ant-design-vue/es/locale/en_US').then((locale) => { |
|||
antConfigLocaleRef.value = locale.default; |
|||
}); |
|||
moment.locale('en-us'); |
|||
break; |
|||
|
|||
// other
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param locale |
|||
*/ |
|||
async function changeLocale(locale: LocaleType): Promise<void> { |
|||
appStore.commitProjectConfigState({ locale: locale }); |
|||
// initialization
|
|||
function setupLocale() { |
|||
const lang = unref(getLang); |
|||
lang && changeLocale(lang); |
|||
} |
|||
|
|||
return { getLocale, changeLocale }; |
|||
return { |
|||
setupLocale, |
|||
getLocale, |
|||
getLang, |
|||
changeLocale, |
|||
antConfigLocale: antConfigLocaleRef, |
|||
}; |
|||
} |
|||
|
|||
/** |
|||
* For non-setup use |
|||
*/ |
|||
export function useExternalI18n() { |
|||
return getI18n().global; |
|||
} |
|||
|
|||
@ -1,3 +1,17 @@ |
|||
import messages from 'globby?locale!/@/locales/lang/**/*.@(ts)'; |
|||
|
|||
import type { DropMenu } from '/@/components/Dropdown'; |
|||
|
|||
// locale list
|
|||
export const localeList: DropMenu[] = [ |
|||
{ |
|||
text: '简体中文', |
|||
event: 'zh_CN', |
|||
}, |
|||
{ |
|||
text: 'English', |
|||
event: 'en', |
|||
}, |
|||
]; |
|||
|
|||
export default messages; |
|||
|
|||
@ -0,0 +1,18 @@ |
|||
export default { |
|||
tableTitle: 'Error log list', |
|||
tableColumnType: 'Type', |
|||
tableColumnDate: 'Time', |
|||
tableColumnFile: 'File', |
|||
tableColumnMsg: 'Error message', |
|||
tableColumnStackMsg: 'Stack info', |
|||
|
|||
tableActionDesc: 'Details', |
|||
|
|||
modalTitle: 'Error details', |
|||
|
|||
fireVueError: 'Fire vue error', |
|||
fireResourceError: 'Fire resource error', |
|||
fireAjaxError: 'Fire ajax error', |
|||
|
|||
enableMessage: 'Only effective when useErrorHandle=true in `/src/settings/projectSetting.ts`.', |
|||
}; |
|||
@ -0,0 +1,12 @@ |
|||
export default { |
|||
backLogin: 'Back Login', |
|||
backHome: 'Back Home', |
|||
redo: 'Refresh', |
|||
subTitle403: "Sorry, you don't have access to this page.", |
|||
subTitle404: 'Sorry, the page you visited does not exist.', |
|||
subTitle500: 'Sorry, the server is reporting an error.', |
|||
noDataTitle: 'No data on the current page.', |
|||
networkErrorTitle: 'Network Error', |
|||
networkErrorSubTitle: |
|||
'Sorry,Your network connection has been disconnected, please check your network!', |
|||
}; |
|||
@ -0,0 +1,6 @@ |
|||
export default { |
|||
alert: 'Lock screen password error', |
|||
backToLogin: 'Back to login', |
|||
entry: 'Enter the system', |
|||
placeholder: 'Please enter the lock screen password or user password', |
|||
}; |
|||
@ -0,0 +1,13 @@ |
|||
export default { |
|||
loginButton: 'Login', |
|||
autoLogin: 'AutoLogin', |
|||
forgetPassword: 'Forget Password', |
|||
|
|||
// notify
|
|||
loginSuccessTitle: 'Login successful', |
|||
loginSuccessDesc: 'Welcome back', |
|||
|
|||
// placeholder
|
|||
accountPlaceholder: 'Please input Username', |
|||
passwordPlaceholder: 'Please input Password', |
|||
}; |
|||
@ -1,3 +0,0 @@ |
|||
export default { |
|||
some: 'Get Out', |
|||
}; |
|||
@ -1,3 +0,0 @@ |
|||
export default { |
|||
button: 'Login', |
|||
}; |
|||
@ -1,3 +0,0 @@ |
|||
export default { |
|||
someentry: 'some text', |
|||
}; |
|||
@ -1,3 +0,0 @@ |
|||
export default { |
|||
some: 'Get Out', |
|||
}; |
|||
@ -1,7 +0,0 @@ |
|||
export default { |
|||
button: 'Login', |
|||
validation: { |
|||
account: 'Required Field account', |
|||
password: 'Required Field password', |
|||
}, |
|||
}; |
|||
@ -1,3 +0,0 @@ |
|||
export default { |
|||
some: '出去', |
|||
}; |
|||
@ -1,3 +0,0 @@ |
|||
export default { |
|||
button: '登录', |
|||
}; |
|||
@ -0,0 +1,18 @@ |
|||
export default { |
|||
tableTitle: '错误日志列表', |
|||
tableColumnType: '类型', |
|||
tableColumnDate: '时间', |
|||
tableColumnFile: '文件', |
|||
tableColumnMsg: '错误信息', |
|||
tableColumnStackMsg: 'stack信息', |
|||
|
|||
tableActionDesc: '详情', |
|||
|
|||
modalTitle: '错误详情', |
|||
|
|||
fireVueError: '点击触发vue错误', |
|||
fireResourceError: '点击触发资源加载错误', |
|||
fireAjaxError: '点击触发ajax错误', |
|||
|
|||
enableMessage: '只在`/src/settings/projectSetting.ts` 内的useErrorHandle=true时生效.', |
|||
}; |
|||
@ -0,0 +1,11 @@ |
|||
export default { |
|||
backLogin: '返回登录', |
|||
backHome: '返回首页', |
|||
redo: '刷新', |
|||
subTitle403: '抱歉,您无权访问此页面。', |
|||
subTitle404: '抱歉,您访问的页面不存在。', |
|||
subTitle500: '抱歉,服务器报告错误。', |
|||
noDataTitle: '当前页无数据', |
|||
networkErrorTitle: '网络错误', |
|||
networkErrorSubTitle: '抱歉,您的网络连接已断开,请检查您的网络!', |
|||
}; |
|||
@ -0,0 +1,6 @@ |
|||
export default { |
|||
alert: '锁屏密码错误', |
|||
backToLogin: '返回登录', |
|||
entry: '进入系统', |
|||
placeholder: '请输入锁屏密码或者用户密码', |
|||
}; |
|||
@ -0,0 +1,13 @@ |
|||
export default { |
|||
loginButton: '登录', |
|||
autoLogin: '自动登录', |
|||
forgetPassword: '忘记密码', |
|||
|
|||
// notify
|
|||
loginSuccessTitle: '登录成功', |
|||
loginSuccessDesc: '欢迎回来', |
|||
|
|||
// placeholder
|
|||
accountPlaceholder: '请输入账号', |
|||
passwordPlaceholder: '请输入密码', |
|||
}; |
|||
@ -1 +1 @@ |
|||
export type LocaleType = 'zhCN' | 'en' | 'ru' | 'ja'; |
|||
export type LocaleType = 'zh_CN' | 'en' | 'ru' | 'ja'; |
|||
|
|||
@ -0,0 +1,36 @@ |
|||
import type { LocaleSetting } from '/@/types/config'; |
|||
|
|||
import { computed } from 'vue'; |
|||
import { appStore } from '/@/store/modules/app'; |
|||
|
|||
import getProjectSetting from '/@/settings/projectSetting'; |
|||
import { localeList } from '/@/locales'; |
|||
|
|||
export function useLocaleSetting() { |
|||
// Get locale configuration
|
|||
const getLocale = computed(() => { |
|||
return appStore.getProjectConfig.locale || getProjectSetting.locale; |
|||
}); |
|||
|
|||
// get current language
|
|||
const getLang = computed(() => { |
|||
return getLocale.value.lang; |
|||
}); |
|||
|
|||
// get Available Locales
|
|||
const getAvailableLocales = computed((): string[] => { |
|||
return getLocale.value.availableLocales; |
|||
}); |
|||
|
|||
// get Fallback Locales
|
|||
const getFallbackLocale = computed((): string => { |
|||
return getLocale.value.fallback; |
|||
}); |
|||
|
|||
// Set locale configuration
|
|||
function setLocale(locale: Partial<LocaleSetting>): void { |
|||
appStore.commitProjectConfigState({ locale }); |
|||
} |
|||
|
|||
return { getLocale, getLang, localeList, setLocale, getAvailableLocales, getFallbackLocale }; |
|||
} |
|||
@ -1,38 +0,0 @@ |
|||
<template> |
|||
<div class="p-4"> |
|||
<Alert message="国际化方式,没有进行全局国际化,有需要可以自行处理。" type="info" /> |
|||
<Divider /> |
|||
国际化信息: {{ t('hello') }} |
|||
<Divider /> |
|||
<a-button :type="localeRef === 'zhCN' ? 'primary' : 'default'" @click="localeRef = 'zhCN'"> |
|||
中文 |
|||
</a-button> |
|||
<a-button :type="localeRef === 'en' ? 'primary' : 'default'" @click="localeRef = 'en'"> |
|||
英文 |
|||
</a-button> |
|||
<Divider /> |
|||
</div> |
|||
</template> |
|||
<script lang="ts"> |
|||
import { defineComponent } from 'vue'; |
|||
import { Alert, Divider } from 'ant-design-vue'; |
|||
|
|||
import { useI18n } from '/@/hooks/web/useI18n'; |
|||
export default defineComponent({ |
|||
components: { Alert, Divider }, |
|||
setup() { |
|||
const { t, localeRef } = useI18n({ |
|||
locale: 'zhCN', |
|||
messages: { |
|||
en: { |
|||
hello: 'hello', |
|||
}, |
|||
zhCN: { |
|||
hello: '你好', |
|||
}, |
|||
}, |
|||
}); |
|||
return { localeRef, t }; |
|||
}, |
|||
}); |
|||
</script> |
|||
Loading…
Reference in new issue