diff --git a/.fatherrc.js b/.fatherrc.js index a191f716..d999990d 100644 --- a/.fatherrc.js +++ b/.fatherrc.js @@ -13,7 +13,8 @@ const headPkgs = [ "fes-plugin-access", "fes-plugin-model", "fes-plugin-layout", - "fes-plugin-icon" + "fes-plugin-icon", + "fes-plugin-locale" ]; const tailPkgs = []; // const otherPkgs = readdirSync(join(__dirname, 'packages')).filter( diff --git a/packages/fes-plugin-locale/.fatherrc.js b/packages/fes-plugin-locale/.fatherrc.js new file mode 100644 index 00000000..332f1bff --- /dev/null +++ b/packages/fes-plugin-locale/.fatherrc.js @@ -0,0 +1,3 @@ +export default { + disableTypeCheck: false, +}; diff --git a/packages/fes-plugin-locale/index.js b/packages/fes-plugin-locale/index.js deleted file mode 100644 index 29ec4699..00000000 --- a/packages/fes-plugin-locale/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import { createI18n, useI18n } from 'vue-i18n'; - -// 注入 i18n 上下文 -// 动态变更 local -// 其他组件能拿到 t 函数 -// local 变更后,能通知到其他函数 -// locales目录下以语言简称为子文件下存放配置信息 -// 其他插件可以运行时修改配置 -// 所有插件使用一个语言和配置 - -export default { - install(app, options, ctx) { - const i18n = createI18n(options); - ctx.useI18n = useI18n; - app.use(i18n); - } -}; diff --git a/packages/fes-plugin-locale/package.json b/packages/fes-plugin-locale/package.json index 85bb4410..e62d69b8 100644 --- a/packages/fes-plugin-locale/package.json +++ b/packages/fes-plugin-locale/package.json @@ -2,7 +2,11 @@ "name": "@webank/fes-plugin-locale", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "lib/index.js", + "files": [ + "lib" + ], + "module": "dist/index.esm.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, @@ -10,6 +14,10 @@ "author": "", "license": "MIT", "dependencies": { + "@umijs/utils": "3.3.3", "vue-i18n": "^9.0.0-beta.15" + }, + "peerDependencies": { + "@webank/fes": "^2.0.0" } } diff --git a/packages/fes-plugin-locale/src/index.js b/packages/fes-plugin-locale/src/index.js new file mode 100644 index 00000000..29d73eac --- /dev/null +++ b/packages/fes-plugin-locale/src/index.js @@ -0,0 +1,71 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; +import { getLocalesJSON } from './utils'; + +const namespace = 'plugin-locale'; + +export default (api) => { + const { + utils: { Mustache } + } = api; + + api.describe({ + config: { + schema(joi) { + return joi.object(); + }, + default: {} + } + }); + + const absoluteFilePath = join(namespace, 'core.js'); + + const absRuntimeFilePath = join(namespace, 'runtime.js'); + + function getLocaleFileBasePath() { + return join(api.paths.absSrcPath, api.config.singular ? 'locale' : 'locales'); + } + + // 监听 locale 文件改变,重新生成文件 + api.addTmpGenerateWatcherPaths(getLocaleFileBasePath); + + api.onGenerateFiles(() => { + const loacleConfigFileBasePath = getLocaleFileBasePath(); + + // 文件写出 + const defaultOptions = api.config.locale || {}; + + + const locales = getLocalesJSON(loacleConfigFileBasePath); + + api.writeTmpFile({ + path: absoluteFilePath, + content: Mustache.render( + readFileSync(join(__dirname, 'template/core.tpl'), 'utf-8'), + { + REPLACE_LOCALES: locales, + REPLACE_DEFAULT_OPTIONS: JSON.stringify(defaultOptions) + } + ) + }); + + api.writeTmpFile({ + path: absRuntimeFilePath, + content: readFileSync( + join(__dirname, 'template/runtime.tpl'), + 'utf-8' + ) + }); + }); + + api.addPluginExports(() => [ + { + specifiers: ['useI18n', 'setLocale'], + source: absoluteFilePath + } + ]); + + // api.addRuntimePluginKey(() => 'access'); + + api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`); +}; diff --git a/packages/fes-plugin-locale/src/template/core.tpl b/packages/fes-plugin-locale/src/template/core.tpl new file mode 100644 index 00000000..46031acf --- /dev/null +++ b/packages/fes-plugin-locale/src/template/core.tpl @@ -0,0 +1,351 @@ +// 注入 i18n 上下文 +// 动态变更 local +// 其他组件能拿到 t 函数 +// local 变更后,能通知到其他函数 +// locales目录下以语言简称为子文件下存放配置信息 +// 其他插件可以运行时修改配置 +// 所有插件使用一个语言和配置 + +import { createI18n, useI18n } from 'vue-i18n/dist/vue-i18n.esm-bundler.js'; + +const defaultLangUConfigMap = { + 'ar-EG': { + lang: 'ar-EG', + label: 'العربية', + icon: '🇪🇬', + title: 'لغة' + }, + 'az-AZ': { + lang: 'az-AZ', + label: 'Azərbaycan dili', + icon: '🇦🇿', + title: 'Dil' + }, + 'bg-BG': { + lang: 'bg-BG', + label: 'Български език', + icon: '🇧🇬', + title: 'език' + }, + 'ca-ES': { + lang: 'ca-ES', + label: 'Catalá', + icon: '🇨🇦', + title: 'llengua' + }, + 'cs-CZ': { + lang: 'cs-CZ', + label: 'Čeština', + icon: '🇨🇿', + title: 'Jazyk' + }, + 'da-DK': { + lang: 'da-DK', + label: 'Dansk', + icon: '🇩🇰', + title: 'Sprog' + }, + 'de-DE': { + lang: 'de-DE', + label: 'Deutsch', + icon: '🇩🇪', + title: 'Sprache' + }, + 'el-GR': { + lang: 'el-GR', + label: 'Ελληνικά', + icon: '🇬🇷', + title: 'Γλώσσα' + }, + 'en-GB': { + lang: 'en-GB', + label: 'English', + icon: '🇬🇧', + title: 'Language' + }, + 'en-US': { + lang: 'en-US', + label: 'English', + icon: '🇺🇸', + title: 'Language' + }, + 'es-ES': { + lang: 'es-ES', + label: 'Español', + icon: '🇪🇸', + title: 'Idioma' + }, + 'et-EE': { + lang: 'et-EE', + label: 'Eesti', + icon: '🇪🇪', + title: 'Keel' + }, + 'fa-IR': { + lang: 'fa-IR', + label: 'فارسی', + icon: '🇮🇷', + title: 'زبان' + }, + 'fi-FI': { + lang: 'fi-FI', + label: 'Suomi', + icon: '🇫🇮', + title: 'Kieli' + }, + 'fr-BE': { + lang: 'fr-BE', + label: 'Français', + icon: '🇧🇪', + title: 'Langue' + }, + 'fr-FR': { + lang: 'fr-FR', + label: 'Français', + icon: '🇫🇷', + title: 'Langue' + }, + 'ga-IE': { + lang: 'ga-IE', + label: 'Gaeilge', + icon: '🇮🇪', + title: 'Teanga' + }, + 'he-IL': { + lang: 'he-IL', + label: 'עברית', + icon: '🇮🇱', + title: 'שפה' + }, + 'hi-IN': { + lang: 'hi-IN', + label: 'हिन्दी, हिंदी', + icon: '🇮🇳', + title: 'भाषा: हिन्दी' + }, + 'hr-HR': { + lang: 'hr-HR', + label: 'Hrvatski jezik', + icon: '🇭🇷', + title: 'Jezik' + }, + 'hu-HU': { + lang: 'hu-HU', + label: 'Magyar', + icon: '🇭🇺', + title: 'Nyelv' + }, + 'hy-AM': { + lang: 'hu-HU', + label: 'Հայերեն', + icon: '🇦🇲', + title: 'Լեզու' + }, + 'id-ID': { + lang: 'id-ID', + label: 'Bahasa Indonesia', + icon: '🇮🇩', + title: 'Bahasa' + }, + 'it-IT': { + lang: 'it-IT', + label: 'Italiano', + icon: '🇮🇹', + title: 'Linguaggio' + }, + 'is-IS': { + lang: 'is-IS', + label: 'Íslenska', + icon: '🇮🇸', + title: 'Tungumál' + }, + 'ja-JP': { + lang: 'ja-JP', + label: '日本語', + icon: '🇯🇵', + title: '言語' + }, + 'ku-IQ': { + lang: 'ku-IQ', + label: 'کوردی', + icon: '🇮🇶', + title: 'Ziman' + }, + 'kn-IN': { + lang: 'zh-TW', + label: 'ಕನ್ನಡ', + icon: '🇮🇳', + title: 'ಭಾಷೆ' + }, + 'ko-KR': { + lang: 'ko-KR', + label: '한국어', + icon: '🇰🇷', + title: '언어' + }, + 'lv-LV': { + lang: 'lv-LV', + label: 'Latviešu valoda', + icon: '🇱🇮', + title: 'Kalba' + }, + 'mk-MK': { + lang: 'mk-MK', + label: 'македонски јазик', + icon: '🇲🇰', + title: 'Јазик' + }, + 'mn-MN': { + lang: 'mn-MN', + label: 'Монгол хэл', + icon: '🇲🇳', + title: 'Хэл' + }, + 'ms-MY': { + lang: 'ms-MY', + label: 'بهاس ملايو‎', + icon: '🇲🇾', + title: 'Bahasa' + }, + 'nb-NO': { + lang: 'nb-NO', + label: 'Norsk', + icon: '🇳🇴', + title: 'Språk' + }, + 'ne-NP': { + lang: 'ne-NP', + label: 'नेपाली', + icon: '🇳🇵', + title: 'भाषा' + }, + 'nl-BE': { + lang: 'nl-BE', + label: 'Vlaams', + icon: '🇧🇪', + title: 'Taal' + }, + 'nl-NL': { + lang: 'nl-NL', + label: 'Vlaams', + icon: '🇳🇱', + title: 'Taal' + }, + 'pt-BR': { + lang: 'pt-BR', + label: 'Português', + icon: '🇧🇷', + title: 'Idiomas' + }, + 'pt-PT': { + lang: 'pt-PT', + label: 'Português', + icon: '🇵🇹', + title: 'Idiomas' + }, + 'ro-RO': { + lang: 'ro-RO', + label: 'Română', + icon: '🇷🇴', + title: 'Limba' + }, + 'ru-RU': { + lang: 'ru-RU', + label: 'русский', + icon: '🇷🇺', + title: 'язык' + }, + 'sk-SK': { + lang: 'sk-SK', + label: 'Slovenčina', + icon: '🇸🇰', + title: 'Jazyk' + }, + 'sr-RS': { + lang: 'sr-RS', + label: 'српски језик', + icon: '🇸🇷', + title: 'Језик' + }, + 'sl-SI': { + lang: 'sl-SI', + label: 'Slovenščina', + icon: '🇸🇱', + title: 'Jezik' + }, + 'sv-SE': { + lang: 'sv-SE', + label: 'Svenska', + icon: '🇸🇪', + title: 'Språk' + }, + 'ta-IN': { + lang: 'ta-IN', + label: 'தமிழ்', + icon: '🇮🇳', + title: 'மொழி' + }, + 'th-TH': { + lang: 'th-TH', + label: 'ไทย', + icon: '🇹🇭', + title: 'ภาษา' + }, + 'tr-TR': { + lang: 'tr-TR', + label: 'Türkçe', + icon: '🇹🇷', + title: 'Dil' + }, + 'uk-UA': { + lang: 'uk-UA', + label: 'Українська', + icon: '🇺🇰', + title: 'Мова' + }, + 'vi-VN': { + lang: 'vi-VN', + label: 'Tiếng Việt', + icon: '🇻🇳', + title: 'Ngôn ngữ' + }, + 'zh-CN': { + lang: 'zh-CN', + label: '简体中文', + icon: '🇨🇳', + title: '语言' + }, + 'zh-TW': { + lang: 'zh-TW', + label: '繁体中文', + icon: '🇭🇰', + title: '語言' + } +}; + +const locales = {{{REPLACE_LOCALES}}}; + +const defaultOptions = {{{REPLACE_DEFAULT_OPTIONS}}} + +const messages = {}; +if (Array.isArray(locales)) { + locales.forEach((item) => { + messages[item.locale] = item.message; + }); +} + +const i18n = createI18n({ ...defaultOptions, messages }); + +const setLocale = (locale)=>{ + i18n.global.locale = locale +}; + +const addLocale = (locale, messages)=>{}; + +const getAllLocales = ()=>{}; + +const install = (app)=>{ + app.use(i18n); +} + +export { useI18n, setLocale, addLocale, getAllLocales, install } \ No newline at end of file diff --git a/packages/fes-plugin-locale/src/template/runtime.tpl b/packages/fes-plugin-locale/src/template/runtime.tpl new file mode 100644 index 00000000..41c090a7 --- /dev/null +++ b/packages/fes-plugin-locale/src/template/runtime.tpl @@ -0,0 +1,5 @@ +import { install } from "./core"; + +export function onAppCreated({ app }) { + install(app) +} diff --git a/packages/fes-plugin-locale/src/utils/index.js b/packages/fes-plugin-locale/src/utils/index.js new file mode 100644 index 00000000..1782598f --- /dev/null +++ b/packages/fes-plugin-locale/src/utils/index.js @@ -0,0 +1,33 @@ +import { glob } from '@umijs/utils'; +import { join, basename } from 'path'; + +export function getLocales(cwd) { + const files = glob + .sync('*.js', { + cwd + }) + .filter( + file => !file.endsWith('.d.ts') + && !file.endsWith('.test.js') + && !file.endsWith('.test.jsx') + ).map((fileName) => { + const locale = basename(fileName, '.js'); + return { + locale, + message: `require('${join(cwd, fileName)}').default` + }; + }); + + return files; +} + +export function getLocalesJSON(cwd) { + const locales = getLocales(cwd); + return JSON.stringify(locales) + .replace( + /"message":("(.+?)")/g, + (global, m1, m2) => `"message": ${m2.replace(/\^/g, '"')}` + ) + .replace(/\\r\\n/g, '\r\n') + .replace(/\\n/g, '\r\n'); +} diff --git a/packages/fes-plugin-model/src/index.js b/packages/fes-plugin-model/src/index.js index ca10132f..f4e245b8 100644 --- a/packages/fes-plugin-model/src/index.js +++ b/packages/fes-plugin-model/src/index.js @@ -27,7 +27,7 @@ export default (api) => { ...getModels(srcModelsPath), ...getModels( paths.absPagesPath, - `**/${getModelDir()}/**/*.{js,jsx}`, + `**/${getModelDir()}/**/*.{js,jsx}` ), ...getModels(paths.absPagesPath, '**/*.model.{js,jsx}') ]); diff --git a/packages/fes-preset-built-in/src/plugins/features/singular.js b/packages/fes-preset-built-in/src/plugins/features/singular.js index fd835dab..14cfc299 100644 --- a/packages/fes-preset-built-in/src/plugins/features/singular.js +++ b/packages/fes-preset-built-in/src/plugins/features/singular.js @@ -2,7 +2,7 @@ export default (api) => { api.describe({ key: 'singular', config: { - default: {}, + default: true, schema(joi) { return joi .boolean(); diff --git a/packages/fes-template/.fes.js b/packages/fes-template/.fes.js index 73b2812f..60638a5c 100644 --- a/packages/fes-template/.fes.js +++ b/packages/fes-template/.fes.js @@ -21,6 +21,10 @@ export default { name: 'onepiece' }] }, + locale: { + locale: 'zh-CN', + fallbackLocale: 'zh-CN' + }, devServer: { port: 8080 } diff --git a/packages/fes-template/package.json b/packages/fes-template/package.json index 090b1038..a203c27e 100644 --- a/packages/fes-template/package.json +++ b/packages/fes-template/package.json @@ -39,6 +39,7 @@ "@webank/fes-plugin-access": "^1.0.0", "@webank/fes-plugin-model": "^1.0.0", "@webank/fes-plugin-layout": "^1.0.0", + "@webank/fes-plugin-locale": "^1.0.0", "ant-design-vue": "2.0.0-rc.3" } } diff --git a/packages/fes-template/src/locale/en-US.js b/packages/fes-template/src/locale/en-US.js new file mode 100644 index 00000000..72836ca1 --- /dev/null +++ b/packages/fes-template/src/locale/en-US.js @@ -0,0 +1,11 @@ + +export default { + test: 'test', + 'navBar.lang': 'Languages', + 'layout.user.link.help': 'Help', + 'layout.user.link.privacy': 'Privacy', + 'layout.user.link.terms': 'Terms', + 'app.preview.down.block': 'Download this page to your local project', + 'app.welcome.link.fetch-blocks': 'Get all block', + 'app.welcome.link.block-list': 'Quickly build standard, pages based on `block` development' +}; diff --git a/packages/fes-template/src/locale/id-ID.js b/packages/fes-template/src/locale/id-ID.js new file mode 100644 index 00000000..3596ca12 --- /dev/null +++ b/packages/fes-template/src/locale/id-ID.js @@ -0,0 +1,11 @@ + +export default { + 'navbar.lang': 'Bahasa', + 'layout.user.link.help': 'Bantuan', + 'layout.user.link.privacy': 'Privasi', + 'layout.user.link.terms': 'Ketentuan', + 'app.preview.down.block': 'Unduh halaman ini dalam projek lokal anda', + 'app.welcome.link.fetch-blocks': 'Dapatkan semua blok', + 'app.welcome.link.block-list': + 'Buat standar dengan cepat, halaman-halaman berdasarkan pengembangan `block`' +}; diff --git a/packages/fes-template/src/locale/pt-BR.js b/packages/fes-template/src/locale/pt-BR.js new file mode 100644 index 00000000..7a7a80bd --- /dev/null +++ b/packages/fes-template/src/locale/pt-BR.js @@ -0,0 +1,8 @@ + +export default { + 'navBar.lang': 'Idiomas', + 'layout.user.link.help': 'ajuda', + 'layout.user.link.privacy': 'política de privacidade', + 'layout.user.link.terms': 'termos de serviços', + 'app.preview.down.block': 'Download this page to your local project' +}; diff --git a/packages/fes-template/src/locale/zh-CN.js b/packages/fes-template/src/locale/zh-CN.js new file mode 100644 index 00000000..a30cba5e --- /dev/null +++ b/packages/fes-template/src/locale/zh-CN.js @@ -0,0 +1,11 @@ + +export default { + test: '测试', + 'navBar.lang': '语言', + 'layout.user.link.help': '帮助', + 'layout.user.link.privacy': '隐私', + 'layout.user.link.terms': '条款', + 'app.preview.down.block': '下载此页面到本地项目', + 'app.welcome.link.fetch-blocks': '获取全部区块', + 'app.welcome.link.block-list': '基于 block 开发,快速构建标准页面' +}; diff --git a/packages/fes-template/src/locale/zh-TW.js b/packages/fes-template/src/locale/zh-TW.js new file mode 100644 index 00000000..6347aea9 --- /dev/null +++ b/packages/fes-template/src/locale/zh-TW.js @@ -0,0 +1,8 @@ + +export default { + 'navBar.lang': '語言', + 'layout.user.link.help': '幫助', + 'layout.user.link.privacy': '隱私', + 'layout.user.link.terms': '條款', + 'app.preview.down.block': '下載此頁面到本地項目' +}; diff --git a/packages/fes-template/src/models/user.js b/packages/fes-template/src/model/user.js similarity index 100% rename from packages/fes-template/src/models/user.js rename to packages/fes-template/src/model/user.js diff --git a/packages/fes-template/src/page/index.vue b/packages/fes-template/src/page/index.vue index 95a5438f..5dbe6cc8 100644 --- a/packages/fes-template/src/page/index.vue +++ b/packages/fes-template/src/page/index.vue @@ -1,5 +1,6 @@