feat: plugin-locale 添加新功能

1. 支持 legacy 配置
2. 支持 share 配置
3. 支持 baseNavigator 配置
4. 添加setLocale方法
5. 添加addLocale方法
6. 添加getAllLocales方法
This commit is contained in:
万纯 2021-01-14 19:09:59 +08:00
parent b5e2a8426e
commit e43ea5e56c
9 changed files with 122 additions and 53 deletions

View File

@ -23,7 +23,6 @@ export default (api) => {
const absRuntimeFilePath = join(namespace, 'runtime.js'); const absRuntimeFilePath = join(namespace, 'runtime.js');
const generatedOnce = false;
api.onGenerateFiles(() => { api.onGenerateFiles(() => {
// 文件写出 // 文件写出
const { roles = {} } = api.config.access || {}; const { roles = {} } = api.config.access || {};

View File

@ -10,14 +10,18 @@ export default (api) => {
} = api; } = api;
api.describe({ api.describe({
key: 'locale',
config: { config: {
schema(joi) { schema(joi) {
return joi.object(); return joi.object();
}, },
default: {} default: {},
onChange: api.ConfigChangeType.regenerateTmpFiles
} }
}); });
api.addRuntimePluginKey(() => 'locale');
const absoluteFilePath = join(namespace, 'core.js'); const absoluteFilePath = join(namespace, 'core.js');
const absRuntimeFilePath = join(namespace, 'runtime.js'); const absRuntimeFilePath = join(namespace, 'runtime.js');
@ -30,12 +34,18 @@ export default (api) => {
api.addTmpGenerateWatcherPaths(getLocaleFileBasePath); api.addTmpGenerateWatcherPaths(getLocaleFileBasePath);
api.onGenerateFiles(() => { api.onGenerateFiles(() => {
// .fes配置
const userConfig = {
locale: 'zh-CN', // default locale
fallbackLocale: 'zh-CN', // set fallback locale
legacy: true,
baseNavigator: true, // 开启浏览器语言检测
share: true, // 用户是否需要手动改变语言
...api.config.locale
};
const loacleConfigFileBasePath = getLocaleFileBasePath(); const loacleConfigFileBasePath = getLocaleFileBasePath();
// 文件写出
const defaultOptions = api.config.locale || {};
const locales = getLocalesJSON(loacleConfigFileBasePath); const locales = getLocalesJSON(loacleConfigFileBasePath);
api.writeTmpFile({ api.writeTmpFile({
@ -44,19 +54,17 @@ export default (api) => {
readFileSync(join(__dirname, 'runtime/core.tpl'), 'utf-8'), readFileSync(join(__dirname, 'runtime/core.tpl'), 'utf-8'),
{ {
REPLACE_LOCALES: locales, REPLACE_LOCALES: locales,
REPLACE_DEFAULT_OPTIONS: JSON.stringify(defaultOptions) REPLACE_DEFAULT_OPTIONS: JSON.stringify({
locale: userConfig.locale,
fallbackLocale: userConfig.fallbackLocale,
legacy: userConfig.legacy
}, null, 2),
BASE_NAVIGATOR: userConfig.baseNavigator,
SHARE: userConfig.share
} }
) )
}); });
api.writeTmpFile({
path: absRuntimeFilePath,
content: readFileSync(
join(__dirname, 'runtime/runtime.tpl'),
'utf-8'
)
});
api.copyTmpFiles({ api.copyTmpFiles({
namespace, namespace,
path: join(__dirname, 'runtime'), path: join(__dirname, 'runtime'),
@ -66,12 +74,10 @@ export default (api) => {
api.addPluginExports(() => [ api.addPluginExports(() => [
{ {
specifiers: ['useI18n', 'setLocale'], specifiers: ['useI18n', 'locale'],
source: absoluteFilePath source: absoluteFilePath
} }
]); ]);
api.addRuntimePluginKey(() => 'onLocaleReady');
api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`); api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`);
}; };

View File

@ -5,13 +5,38 @@
// locales目录下以语言简称为子文件下存放配置信息 // locales目录下以语言简称为子文件下存放配置信息
// 其他插件可以运行时修改配置 // 其他插件可以运行时修改配置
// 所有插件使用一个语言和配置 // 所有插件使用一个语言和配置
import { createI18n, useI18n } from 'vue-i18n/dist/vue-i18n.esm-bundler.js'; import { isRef } from 'vue';
import { createI18n, useI18n } from 'vue-i18n/dist/vue-i18n.esm-bundler.js';
import { plugin, ApplyPluginsType } from "@@/core/coreExports"; import { plugin, ApplyPluginsType } from "@@/core/coreExports";
import SelectLang from "./views/SelectLang" import SelectLang from "./views/SelectLang";
{{ #SHARE }}
// 共享出去
plugin.share("locale", { SelectLang });
{{ /SHARE }}
const locales = {{{REPLACE_LOCALES}}}; const locales = {{{REPLACE_LOCALES}}};
const defaultOptions = {{{REPLACE_DEFAULT_OPTIONS}}} const defaultOptions = {{{REPLACE_DEFAULT_OPTIONS}}};
const BASE_NAVIGATOR = {{{BASE_NAVIGATOR}}};
const getDefaultLocale = () => {
const fes_locale = window.localStorage.getItem("fes_locale");
if (fes_locale) {
return {
locale: fes_locale,
fallbackLocale: fes_locale,
};
}
if (BASE_NAVIGATOR) {
return {
locale: window.navigator.language,
fallbackLocale: window.navigator.language,
};
}
return {};
};
const messages = {}; const messages = {};
if (Array.isArray(locales)) { if (Array.isArray(locales)) {
@ -20,21 +45,53 @@ if (Array.isArray(locales)) {
}); });
} }
const i18n = createI18n({ ...defaultOptions, messages }); const i18n = createI18n({
...defaultOptions,
...getDefaultLocale(),
messages,
});
// 共享出去 window.localStorage.setItem("fes_locale", i18n.global.locale);
plugin.share("locale", { i18n, SelectLang }); const setLocale = ({ lang }) => {
if (isRef(i18n.global.locale)) {
const setLocale = (locale)=>{ i18n.global.locale.value = lang;
i18n.global.locale = locale } else {
i18n.global.locale = lang;
}
window.localStorage.setItem("fes_locale", lang);
}; };
const addLocale = (locale, messages)=>{}; const addLocale = ({ lang, messages }) => {
messages[lang] = messages;
if (isRef(i18n.global.messages)) {
i18n.global.messages.value[lang] = messages;
} else {
i18n.global.messages[lang] = messages;
}
};
const getAllLocales = ()=>{}; const getAllLocales = () => {
return Object.keys(
isRef(i18n.global.messages)
? i18n.global.messages.value
: i18n.global.messages
).sort();
};
const install = (app)=>{ const install = (app) => {
const runtimeConfig = plugin.applyPlugins({
key: "locale",
type: ApplyPluginsType.modify,
initialValue: {},
});
app.use(i18n); app.use(i18n);
} };
export { useI18n, setLocale, install } const locale = {
setLocale,
addLocale,
getAllLocales,
messages,
};
export { useI18n, locale, install };

View File

@ -0,0 +1,5 @@
import { install } from './core';
export function onAppCreated({ app }) {
install(app);
}

View File

@ -1,5 +0,0 @@
import { install } from "./core";
export function onAppCreated({ app }) {
install(app)
}

View File

@ -4,7 +4,7 @@
<template #overlay> <template #overlay>
<a-menu :selectedKeys="selectedKeys" @click="handleClick"> <a-menu :selectedKeys="selectedKeys" @click="handleClick">
<a-menu-item <a-menu-item
v-for="(item) in configs" v-for="item in configs"
:key="item.lang" :key="item.lang"
class="lang-item" class="lang-item"
> >
@ -23,7 +23,7 @@ import 'ant-design-vue/lib/dropdown/style';
import 'ant-design-vue/lib/menu/style'; import 'ant-design-vue/lib/menu/style';
import { GlobalOutlined } from '@ant-design/icons-vue'; import { GlobalOutlined } from '@ant-design/icons-vue';
import { useI18n } from 'vue-i18n/dist/vue-i18n.esm-bundler'; import { useI18n } from 'vue-i18n/dist/vue-i18n.esm-bundler';
import { reactive, computed } from 'vue'; import { computed } from 'vue';
import langUConfigMap from '../langUConfigMap'; import langUConfigMap from '../langUConfigMap';
export default { export default {
@ -34,14 +34,20 @@ export default {
GlobalOutlined GlobalOutlined
}, },
setup() { setup() {
const { availableLocales, locale } = useI18n(); const { messages, locale } = useI18n();
const selectedKeys = computed(() => [locale.value]); const selectedKeys = computed(() => [locale.value]);
const configs = reactive([]); const configs = computed(() => {
availableLocales.forEach((item) => { const arr = [];
configs.push(langUConfigMap[item] || {}); Object.keys(messages.value)
.sort()
.forEach((item) => {
arr.push(langUConfigMap[item] || {});
});
return arr;
}); });
const handleClick = ({ key }) => { const handleClick = ({ key }) => {
locale.value = key; locale.value = key;
window.localStorage.setItem('fes_locale', key);
}; };
return { return {
handleClick, handleClick,

View File

@ -23,9 +23,9 @@ export function getLocales(cwd) {
export function getLocalesJSON(cwd) { export function getLocalesJSON(cwd) {
const locales = getLocales(cwd); const locales = getLocales(cwd);
return JSON.stringify(locales) return JSON.stringify(locales, null, 2)
.replace( .replace(
/"message":("(.+?)")/g, /"message": ("(.+?)")/g,
(global, m1, m2) => `"message": ${m2.replace(/\^/g, '"')}` (global, m1, m2) => `"message": ${m2.replace(/\^/g, '"')}`
) )
.replace(/\\r\\n/g, '\r\n') .replace(/\\r\\n/g, '\r\n')

View File

@ -22,6 +22,9 @@ export default {
name: 'onepiece' name: 'onepiece'
}] }]
}, },
locale: {
legacy: true
},
devServer: { devServer: {
port: 8080 port: 8080
} }

View File

@ -16,21 +16,22 @@
<script> <script>
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { import {
access, useAccess, useRouter, useI18n, setLocale access, useAccess, useRouter, useI18n, locale
} from '@webank/fes'; } from '@webank/fes';
export default { export default {
setup() { setup() {
const fes = ref('fes upgrade to vue3'); const fes = ref('fes upgrade to vue3');
const accessOnepicess = useAccess('/onepiece1'); const accessOnepicess = useAccess('/onepiece1');
const { t } = useI18n(); const localI18n = useI18n();
const router = useRouter(); const router = useRouter();
const accessId = ref('/onepiece1'); const accessId = ref('/onepiece1');
onMounted(() => { onMounted(() => {
console.log(router); console.log(router);
console.log('mounted1!!');
setTimeout(() => { setTimeout(() => {
setLocale('en-US'); locale.setLocale({ lang: 'en-US' });
locale.addLocale({ lang: 'ja-JP', messages: { test: 'テスト' } });
console.log(locale.getAllLocales());
access.addAccess('/onepiece1'); access.addAccess('/onepiece1');
}, 2000); }, 2000);
setTimeout(() => { setTimeout(() => {
@ -38,14 +39,11 @@ export default {
}, 4000); }, 4000);
// router.push('/onepiece'); // router.push('/onepiece');
}); });
onMounted(() => {
console.log('mounted2!!');
});
return { return {
accessId, accessId,
fes, fes,
accessOnepicess, accessOnepicess,
t t: localI18n.t
}; };
} }
}; };