wodax-umi-plugin-locale
Version:
A umi plugin for provide internationalization function.
145 lines (132 loc) • 4.48 kB
JavaScript
//
// TODOLIST:
// - 单元测试
// - example 里面的 antd 依赖改为 umi 插件
//
import { join, dirname, basename } from 'path';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import { winPath } from 'umi-utils';
import Mustache from 'mustache';
import globby from 'globby';
import groupBy from 'lodash.groupby';
const momentLocation = require.resolve('moment/locale/zh-cn').replace(/zh\-cn\.js$/, '');
function getMomentLocale(lang, country) {
if (existsSync(join(momentLocation, `${lang}-${country.toLocaleLowerCase()}.js`))) {
return `${lang}-${country.toLocaleLowerCase()}`;
}
if (existsSync(join(momentLocation, `${lang}.js`))) {
return lang;
}
return '';
}
// export for test
export function getLocaleFileList(absSrcPath, absPagesPath, singular) {
const localeFileMath = /^([a-z]{2})-([A-Z]{2})\.(js|ts)$/;
const localeFolder = singular ? 'locale' : 'locales';
const localeFiles = globby
.sync('*.{ts,js}', {
cwd: join(absSrcPath, localeFolder),
})
.map(name => join(absSrcPath, localeFolder, name))
.concat(
globby
.sync(`**/${localeFolder}/*.{ts,js}`, {
cwd: absPagesPath,
})
.map(name => join(absPagesPath, name)),
)
.filter(p => localeFileMath.test(basename(p)))
.map(fullname => {
const fileName = basename(fullname);
const fileInfo = localeFileMath.exec(fileName);
return {
name: `${fileInfo[1]}-${fileInfo[2]}`,
path: fullname,
};
});
const groups = groupBy(localeFiles, 'name');
return Object.keys(groups).map(name => {
const fileInfo = name.split('-');
return {
lang: fileInfo[0],
name,
country: fileInfo[1],
paths: groups[name].map(item => winPath(item.path)),
momentLocale: getMomentLocale(fileInfo[0], fileInfo[1]),
};
});
}
// data come from https://caniuse.com/#search=intl
// you can find all browsers in https://github.com/browserslist/browserslist#browsers
const polyfillTargets = {
ie: 10,
firefox: 28,
chrome: 23,
safari: 9.1,
opera: 12.1,
ios: 9.3,
ios_saf: 9.3,
operamini: Infinity,
op_mini: Infinity,
android: 4.3,
blackberry: Infinity,
operamobile: 12.1,
op_mob: 12.1,
explorermobil: 10,
ie_mob: 10,
ucandroid: Infinity,
};
export function isNeedPolyfill(targets = {}) {
return (
Object.keys(targets).find(key => {
const lowKey = key.toLocaleLowerCase();
return polyfillTargets[lowKey] && polyfillTargets[lowKey] >= targets[key];
}) !== undefined
);
}
export default function(api, options = {}) {
const { config, paths } = api;
const { targets } = config;
if (isNeedPolyfill(targets)) {
api.addEntryPolyfillImports({
source: 'intl',
});
}
api.addRuntimePluginKey('locale');
api.addPageWatcher(join(paths.absSrcPath, config.singular ? 'locale' : 'locales'));
api.onOptionChange(newOpts => {
options = newOpts;
api.rebuildTmpFiles();
});
api.addRendererWrapperWithComponent(() => {
const localeFileList = getLocaleFileList(paths.absSrcPath, paths.absPagesPath, config.singular);
const wrapperTpl = readFileSync(join(__dirname, '../template/wrapper.jsx.tpl'), 'utf-8');
const defaultLocale = options.default || 'zh-CN';
const [lang, country] = defaultLocale.split('-');
const wrapperContent = Mustache.render(wrapperTpl, {
localeList: localeFileList,
antd: options.antd === undefined ? true : options.antd,
baseNavigator: options.baseNavigator === undefined ? true : options.baseNavigator,
useLocalStorage: options.useLocalStorage || true,
defaultLocale,
defaultLang: lang,
defaultAntdLocale: `${lang}_${country}`,
defaultMomentLocale: getMomentLocale(lang, country),
});
const wrapperPath = join(paths.absTmpDirPath, './LocaleWrapper.jsx');
writeFileSync(wrapperPath, wrapperContent, 'utf-8');
return wrapperPath;
});
api.modifyAFWebpackOpts(memo => {
return {
...memo,
alias: {
...(memo.alias || {}),
// umi/locale is deprecated
// recommend use `import { getLocale } from 'umi-plugin-locale';` now.
'umi/locale': join(__dirname, './locale.js'),
'react-intl': dirname(require.resolve('react-intl/package.json')),
},
};
});
}