From 7c83c80d5ddc7c831802b420d012c8ffa50bd05e Mon Sep 17 00:00:00 2001 From: zuiidea Date: Sat, 15 Sep 2018 12:26:22 +0800 Subject: [PATCH] Support for dynamically loading language packs. Load the `lodash` function as needed. Added i18n related configuration. --- .eslintignore | 2 ++ .gitignore | 3 ++- .umirc.js | 17 ++++++++++++- package.json | 5 ++-- src/layouts/index.js | 57 +++++++++++++++++++++++++++++++++++++++----- src/utils/config.js | 8 +++++++ src/utils/i18n.js | 42 -------------------------------- src/utils/index.js | 43 ++++++++++++++++++++++++++++++++- src/utils/request.js | 3 +-- yarn.lock | 17 ++++++++----- 10 files changed, 135 insertions(+), 62 deletions(-) delete mode 100644 src/utils/i18n.js diff --git a/.eslintignore b/.eslintignore index 49bcf6c..de014a1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,3 +2,5 @@ src/**/*-test.js src/public src/routes/chart/ECharts/theme src/routes/chart/highCharts/mapdata +src/locales/_build/ +src/locales/**/*.js \ No newline at end of file diff --git a/.gitignore b/.gitignore index e81b76e..1c930f5 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ yarn-error.log .umi-production # jslingui -src/locales/_build \ No newline at end of file +src/locales/_build +src/locales/**/*.js \ No newline at end of file diff --git a/.umirc.js b/.umirc.js index 75d30bb..6d1000a 100644 --- a/.umirc.js +++ b/.umirc.js @@ -1,5 +1,6 @@ // https://umijs.org/config/ import { resolve } from 'path' +import { i18n } from './src/utils/config' export default { plugins: [ @@ -27,16 +28,21 @@ export default { /chart\/Recharts\/Container\.js$/, ], update: routes => { + if (!i18n) return routes + const newRoutes = [] for (const item of routes[0].routes) { newRoutes.push(item) if (item.path) { newRoutes.push( - Object.assign({}, item, { path: '/:lang(en|zh)' + item.path }) + Object.assign({}, item, { + path: `/:lang(${i18n.languages.join('|')})` + item.path, + }) ) } } routes[0].routes = newRoutes + return routes }, }, @@ -91,5 +97,14 @@ export default { }, 'ant-design-pro', ], + [ + 'import', + { + libraryName: 'lodash', + libraryDirectory: '', + camel2DashComponentName: false, + }, + 'lodash', + ], ], } diff --git a/package.json b/package.json index 59d7760..f9a5254 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,7 @@ "eslint-plugin-flowtype": "^2.50.0", "highcharts-exporting": "^0.1.7", "highcharts-more": "^0.1.7", - "lodash.clonedeep": "^4.5.0", - "lodash.isempty": "^4.4.0", - "lodash.isequal": "^4.5.0", + "lodash": "^4.17.11", "nprogress": "^0.2.0", "path-to-regexp": "^2.4.0", "prop-types": "^15.6.2", @@ -39,6 +37,7 @@ "devDependencies": { "@lingui/babel-preset-react": "^2.7.0", "@lingui/cli": "^2.7.0", + "@lingui/loader": "^2.7.0", "babel-plugin-dev-expression": "^0.2.1", "babel-plugin-import": "^1.8.0", "babel-plugin-macros": "^2.4.0", diff --git a/src/layouts/index.js b/src/layouts/index.js index 3f28866..26ba8b1 100644 --- a/src/layouts/index.js +++ b/src/layouts/index.js @@ -1,25 +1,70 @@ -import React, { PureComponent } from 'react' +import React, { Component } from 'react' import withRouter from 'umi/withRouter' import { LocaleProvider } from 'antd' import { I18nProvider } from '@lingui/react' -import { catalogs, langFromPath } from 'utils/i18n' +import { langFromPath, defaultLanguage } from 'utils' import zh_CN from 'antd/lib/locale-provider/zh_CN' import en_US from 'antd/lib/locale-provider/en_US' + import BaseLayout from './BaseLayout' const languages = { zh: zh_CN, en: en_US, } + @withRouter -class Layout extends PureComponent { +class Layout extends Component { + state = { + catalogs: {}, + } + + language = defaultLanguage + + componentDidMount() { + const language = langFromPath(this.props.location.pathname) + this.language = language + this.loadCatalog(language) + } + + shouldComponentUpdate(nextProps, nextState) { + const language = langFromPath(nextProps.location.pathname) + const preLanguage = this.language + const { catalogs } = nextState + + if (preLanguage !== language && !catalogs[language]) { + this.loadCatalog(language) + this.language = language + return false + } + this.language = language + + return true + } + + loadCatalog = async language => { + const catalog = await import(/* webpackMode: "lazy", webpackChunkName: "i18n-[index]" */ + `@lingui/loader!../locales/${language}/messages.json`) + + this.setState(state => ({ + catalogs: { + ...state.catalogs, + [language]: catalog, + }, + })) + } + render() { const { location, children } = this.props - const lang = langFromPath(location.pathname) + const { catalogs } = this.state + + let language = langFromPath(location.pathname) + // If the language pack is not loaded or is loading, use the default language + if (!catalogs[language]) language = defaultLanguage return ( - - + + {children} diff --git a/src/utils/config.js b/src/utils/config.js index 927bad1..7fba313 100644 --- a/src/utils/config.js +++ b/src/utils/config.js @@ -6,6 +6,8 @@ module.exports = { logoPath: '/logo.svg', apiPrefix: '/api/v1', openPages: ['/login'], + + /* Layout configuration, specify which layout to use for route. */ layouts: [ { name: 'primary', @@ -13,4 +15,10 @@ module.exports = { exlude: [/(\/(en|zh))*\/login/], }, ], + + /* I18n configuration, `languages` and `defaultLanguage` are required currently. */ + i18n: { + languages: ['en', 'zh'], + defaultLanguage: 'en', + }, } diff --git a/src/utils/i18n.js b/src/utils/i18n.js deleted file mode 100644 index 11891ef..0000000 --- a/src/utils/i18n.js +++ /dev/null @@ -1,42 +0,0 @@ -const catalogs = { - en: { messages: require('../locales/en/messages.json') }, - zh: { messages: require('../locales/zh/messages.json') }, -} - -const defaultLanguage = 'en' - -const languages = [] -for (const key in catalogs) { - languages.push(key) -} - -/** - * Remove the language prefix in pathname. - * @param {string} pathname Remove the language prefix in pathname. - * @return {string} Return the pathname after removing the language prefix. - */ -const deLangPrefix = pathname => { - for (const item of languages) { - if (pathname.startsWith(`/${item}/`)) { - return pathname.replace(`/${item}/`, '/') - } - } - - return pathname -} - -/** - * Query language from pathname. - * @param {string} pathname Pathname to be queried. - * @return {string} Return the queryed language. - */ -const langFromPath = pathname => { - for (const item of languages) { - if (pathname.startsWith(`/${item}/`)) { - return item - } - } - return defaultLanguage -} - -export { languages, catalogs, langFromPath, deLangPrefix, defaultLanguage } diff --git a/src/utils/index.js b/src/utils/index.js index f4634d7..7cee279 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,10 +1,13 @@ -import cloneDeep from 'lodash.clonedeep' +import { cloneDeep, curry } from 'lodash' +import { i18n } from './config' export classnames from 'classnames' export config from './config' export request from './request' export { Color } from './theme' +const { languages, defaultLanguage } = i18n + /** * Query objects that specify keys and values in an array where all values are objects. * @param {array} array An array where all values are objects, like [{key:1},{key:2}]. @@ -56,3 +59,41 @@ export function arrayToTree( }) return result } + +const langFromPath = curry( + /** + * Query language from pathname. + * @param {string} languages Specify which languages are currently available. + * @param {string} defaultLanguage Specify the default language. + * @param {string} pathname Pathname to be queried. + * @return {string} Return the queryed language. + */ + (languages, defaultLanguage, pathname) => { + for (const item of languages) { + if (pathname.startsWith(`/${item}/`)) { + return item + } + } + return defaultLanguage + } +)(languages)(defaultLanguage) + +const deLangPrefix = curry( + /** + * Remove the language prefix in pathname. + * @param {array} languages Specify which languages are currently available. + * @param {string} pathname Remove the language prefix in pathname. + * @return {string} Return the pathname after removing the language prefix. + */ + (languages, pathname) => { + for (const item of languages) { + if (pathname.startsWith(`/${item}/`)) { + return pathname.replace(`/${item}/`, '/') + } + } + + return pathname + } +)(languages) + +export { langFromPath, deLangPrefix, defaultLanguage } diff --git a/src/utils/request.js b/src/utils/request.js index a8fdd2c..4a5eda3 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -1,6 +1,5 @@ import axios from 'axios' -import cloneDeep from 'lodash.clonedeep' -import isEmpty from 'lodash.isempty' +import { cloneDeep, isEmpty } from 'lodash' import pathToRegexp from 'path-to-regexp' import { message } from 'antd' import qs from 'qs' diff --git a/yarn.lock b/yarn.lock index 305c7fa..12fbb18 100644 --- a/yarn.lock +++ b/yarn.lock @@ -908,7 +908,7 @@ "@lingui/babel-plugin-transform-js" "2.7.0" "@lingui/babel-plugin-transform-react" "2.7.0" -"@lingui/cli@^2.7.0": +"@lingui/cli@2.7.0", "@lingui/cli@^2.7.0": version "2.7.0" resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-2.7.0.tgz#04137f770f148f17eb78bb6580e91eac7697b955" dependencies: @@ -957,6 +957,15 @@ make-plural "^4.1.1" messageformat-parser "^2.0.0" +"@lingui/loader@^2.7.0": + version "2.7.0" + resolved "https://registry.yarnpkg.com/@lingui/loader/-/loader-2.7.0.tgz#a9092f16f909ee94616f58f6d5e163e6305883f5" + dependencies: + "@lingui/cli" "2.7.0" + "@lingui/conf" "2.7.0" + babel-runtime "^6.26.0" + ramda "^0.25.0" + "@lingui/react@^2.7.0": version "2.7.0" resolved "https://registry.yarnpkg.com/@lingui/react/-/react-2.7.0.tgz#36a2e905ab6a7f39798dedee2bd4a2b8e98335a9" @@ -7306,10 +7315,6 @@ lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" -lodash.isempty@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" - lodash.isequal@^4.0.0, lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" @@ -7398,7 +7403,7 @@ lodash.uniq@^4.5.0: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" -lodash@^4.11.1: +lodash@^4.11.1, lodash@^4.17.11: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"