i18n 微信脚本wxs的支持

This commit is contained in:
Wang Kejun 2022-05-31 15:32:27 +08:00
parent 890fdbd2b2
commit 5ac542309a
7 changed files with 206 additions and 49 deletions

View File

@ -12,19 +12,19 @@ const parse = require('format-message-parse');
const { merge, set, get } = require('lodash');
const DEFAULT_WXS_FILENAME = 'locales.wxs';
const DEFAULT_JS_FILENAME = 'locales.js';
const DEFAULT_JS_FILENAME = 'locales.ts';
const READ_LOCALES_DIR = SOURCE + '/locales';
const WRITE_DIR = SOURCE + '/i18n';
const DEFAULT_LOCALE = 'zh-CN';
const DEFAULT_FALLBACK_LOCALE = 'zh-CN';
const CORE_PATH = path.dirname(
const BASE_PATH = path.dirname(
require.resolve(
'../../node_modules/oak-frontend-base/src/platforms/wechatMp/i18n/wxs/wxs.js'
`${process.cwd()}/node_modules/oak-frontend-base/src/platforms/wechatMp/i18n/wxs/wxs.js`
)
);
function getWxsCode() {
const code = fs.readFileSync(path.join(CORE_PATH, '/wxs.js'), 'utf-8');
const code = fs.readFileSync(path.join(BASE_PATH, '/wxs.js'), 'utf-8');
const runner = `module.exports = { \nt: Interpreter.getMessageInterpreter() \n}`;
return [code, runner].join('\n');
}
@ -32,17 +32,17 @@ function getWxsCode() {
function i18nLocalesLoader() {
const defaultLocale = DEFAULT_LOCALE;
const fallbackLocale = DEFAULT_FALLBACK_LOCALE;
const wxsContent = `${getWxsCode()}`;
// const wxsContent = `${getWxsCode()}`;
const translations = getTranslations(READ_LOCALES_DIR);
const translationsStr = JSON.stringify(translations, null, 2);
const jsContent = `module.exports = { \nfallbackLocale: '${fallbackLocale}', \ndefaultLocale:'${defaultLocale}', \ntranslations: ${translationsStr} \n};`;
const jsContent = `export default { \nfallbackLocale: '${fallbackLocale}', \ndefaultLocale:'${defaultLocale}', \ntranslations: ${translationsStr} \n};`;
if (!checkFileExists(WRITE_DIR)) {
fs.mkdirSync(WRITE_DIR);
}
// fs.writeFileSync(WRITE_DIR + '/' + DEFAULT_WXS_FILENAME, wxsContent);
fs.writeFileSync(WRITE_DIR + '/' + DEFAULT_JS_FILENAME, jsContent);
fs.writeFileSync(WRITE_DIR + '/' + DEFAULT_WXS_FILENAME, wxsContent);
}
@ -54,7 +54,7 @@ function getTranslations(source) {
if (paths && paths.length) {
for (const p of paths) {
// zh_CN/house.json
const d = path2Escape(p).replace(path2Escape(source), '');
const d = replaceDoubleSlash(p).replace(replaceDoubleSlash(source), '');
const arr = d.split('/');
const localeName = arr[1];
const fileName = arr[2];
@ -71,7 +71,7 @@ function getTranslations(source) {
return translations;
}
function path2Escape(str) {
function replaceDoubleSlash(str) {
return str.replace(/\\/g, '/');
}

View File

@ -75,11 +75,9 @@ function traverse(doc, callback) {
const isSrc = (name) => name === 'src';
const isDynamicSrc = (src) => /\{\{/.test(src);
const WeChatMpDir = 'wechatMp'; //规定文件夹名
const TranslationFunction = 't';
const I18nModuleName = 'i18n';
const CURRENT_LOCALE_KEY = '$_locale';
const LOCALE_CHANGE_HANDLER_NAME = '$_localeChange';
const COMMON_LOCALE_DATA = '$_common_translations';
@ -107,19 +105,45 @@ module.exports = async function (content) {
// this.cacheable && this.cacheable();
const options = this.getOptions() || {}; //获取配置参数
const { context: context2 } = options;
const { context: projectContext } = options; // context 本项目路径
const callback = this.async();
const { options: webpackLegacyOptions, _module = {}, _compilation = {}, resourcePath } = this;
const {
options: webpackLegacyOptions,
_module = {},
_compilation = {},
resourcePath,
} = this;
const { context, target } = webpackLegacyOptions || this;
// console.log(context, target);
const issuer = _compilation.moduleGraph.getIssuer(this._module);
const issuerContext = (issuer && issuer.context) || context;
const root = resolve(context, issuerContext);
let source = content;
let relativePath; // locales.wxs相对路径
//判断是否存在i18n的t函数
if (existsT(source)) {
const relativePath = relative(context, context2 + '/' + WXS_PATH);
source = `<wxs src='${relativePath}' module='${I18nModuleName}'></wxs>` + source;
//判断加载的xml是否为本项目自身的文件
const isSelf = context.indexOf(projectContext) !== -1;
if (isSelf) {
//本项目xml
relativePath = relative(context, projectContext + '/' + WXS_PATH);
} else {
//第三方项目的xml
const index = context.lastIndexOf(WeChatMpDir);
if (index !== -1) {
const p = context.substring(index + WeChatMpDir.length);
relativePath = relative(
projectContext + p,
projectContext + '/' + WXS_PATH
);
}
}
source =
`<wxs src='${relativePath}' module='${I18nModuleName}'></wxs>` +
source;
}
// 注入全局message组件
if (/pages/.test(context)) {
source =
source +
@ -127,9 +151,6 @@ module.exports = async function (content) {
}
// console.log(content, options);
/**
* domparser会自动给没有value的attribute赋上值目前改不动
*/
const doc = new DOMParser({
errorHandler: {
warning(x) {
@ -153,9 +174,15 @@ module.exports = async function (content) {
!isDynamicSrc(value) &&
isUrlRequest(value, root)
) {
const path = resolve(root, value)
// const request = urlToRequest(value, root);
requests.push(path);
if (relativePath === value) {
// 如果出现直接读取项目下i18n/locales.wxs
const path = projectContext + '/' + WXS_PATH;
requests.push(path);
} else {
const path = resolve(root, value);
// const request = urlToRequest(value, root);
requests.push(path);
}
}
}
// 处理oak:value声明的属性
@ -173,7 +200,6 @@ module.exports = async function (content) {
node.setAttribute('focus', `{{!!oakFocused.${oakValue}}}`);
}
}
}
if (node.nodeType === node.TEXT_NODE) {
// 处理i18n 把t()转成i18n.t()
@ -185,11 +211,15 @@ module.exports = async function (content) {
if (existsT(ele)) {
const head = ele.substring(0, ele.indexOf(')'));
const end = ele.substring(ele.indexOf(')'));
newVal += head + `,${CURRENT_LOCALE_KEY},${CURRENT_LOCALE_DATA} || ''` + end + '}}';
newVal +=
head +
`,${CURRENT_LOCALE_KEY},${CURRENT_LOCALE_DATA} || ''` +
end +
'}}';
} else if (ele) {
newVal += ele + '}}';
}
})
});
node.deleteData(0, node.nodeValue.length);
node.insertData(0, newVal);
}

View File

@ -19,14 +19,14 @@ const {
PLATFORM_CONFIG,
ENV_CONFIG,
} = require('./env');
// const localesLoader = require('../config/loaders/locales-loader');
const localesLoader = require('../config/loaders/locales-loader');
const isDev = NODE_ENV === 'development';
const pkg = require(`${process.cwd()}/package.json`)
// process.env.OAK_PLATFORM: wechatMp | wechatPublic | web | node
// localesLoader();
localesLoader();
const relativeFileLoader = (ext = '[ext]') => {
return {

View File

@ -45,7 +45,6 @@
"loader-utils": "^3.2.0",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "^2.5.3",
"oak-frontend-base": "file:../oak-frontend-base",
"postcss-less": "^6.0.0",
"progress-bar-webpack-plugin": "^2.1.0",
"required-path": "^1.0.1",

View File

@ -271,7 +271,7 @@ class OakWeChatMpPlugin {
}
if (getIsOak(c)) {
const oakComponent = OakPagePath + c.replace(new RegExp(OakPagePrefix), '');
const component2 = oakComponent.replace(/\\/g, '/');
const component2 = this.replaceDoubleSlash(oakComponent);
if (!this.oakComponents.has(component2)) {
this.oakComponents.add(component2);
components.add(component2);
@ -284,11 +284,11 @@ class OakWeChatMpPlugin {
continue;
}
if (mode === MODE.oak) {
const component = path
.resolve(instanceDir, c)
.replace(/\\/g, '/');
const component = this.replaceDoubleSlash(
path.resolve(instanceDir, c)
);
const component2 = component.replace(
process.cwd().replace(/\\/g, '/') + '/',
this.replaceDoubleSlash(process.cwd()) + '/',
''
);
if (!this.oakComponents.has(component2)) {
@ -301,11 +301,11 @@ class OakWeChatMpPlugin {
);
}
} else if (mode === MODE.external) {
const component = path
.resolve(instanceDir, c)
.replace(/\\/g, '/');
const component = this.replaceDoubleSlash(
path.resolve(instanceDir, c)
);
const component2 = component.replace(
process.cwd().replace(/\\/g, '/') + '/',
this.replaceDoubleSlash(process.cwd()) + '/',
''
);
if (!this.npmComponents.has(component2)) {
@ -318,15 +318,13 @@ class OakWeChatMpPlugin {
);
}
} else {
const component = path
.resolve(instanceDir, c)
.replace(/\\/g, '/');
const component = this.replaceDoubleSlash(path.resolve(instanceDir, c));
if (!components.has(component)) {
// components.add(path.relative(this.basePath, component));
// await this.getComponents(components, component);
const component2 = path
.relative(this.basePath, component)
.replace(/\\/g, '/');
const component2 = this.replaceDoubleSlash(
path.relative(this.basePath, component)
);
if (!components.has(component2)) {
components.add(component2);
await this.getComponents(components, component);
@ -452,7 +450,7 @@ class OakWeChatMpPlugin {
...npmAssetsEntry.map((resource) => {
return {
from: path.resolve(
process.cwd().replace(/\\/g, '/'),
this.replaceDoubleSlash(process.cwd()),
resource
),
to: resource.replace(
@ -539,7 +537,9 @@ class OakWeChatMpPlugin {
async emitAssetsFile(compilation) {
const emitAssets = [];
for (let entry of this.assetsEntry) {
const assets = path.resolve(this.basePath, entry).replace(/\\/g, '/');
const assets = this.replaceDoubleSlash(
path.resolve(this.basePath, entry)
);
if (/\.(sass|scss|css|less|styl|xml|wxml)$/.test(assets)) {
continue;
}
@ -595,10 +595,15 @@ class OakWeChatMpPlugin {
new RegExp(OakPagePrefix),
''
);
component = path.relative(
assets.substring(0, assets.lastIndexOf('/')),
path.resolve(this.basePath, component)
).replace(/\\/g, '/')
component = this.replaceDoubleSlash(
path.relative(
assets.substring(
0,
assets.lastIndexOf('/')
),
path.resolve(this.basePath, component)
)
);
}
usingComponents[ck] = component;
}
@ -655,6 +660,10 @@ class OakWeChatMpPlugin {
const { path } = compilation.options.output;
await fsExtra.remove(path);
}
replaceDoubleSlash(str) {
return str.replace(/\\/g, '/');
}
}
module.exports = OakWeChatMpPlugin;

View File

@ -0,0 +1,5 @@
export default {
fallbackLocale: 'zh-CN',
defaultLocale: 'zh-CN',
translations: {},
};

View File

@ -0,0 +1,114 @@
var Interpreter = (function (r) {
var o = '';
function i(r, n) {
return r
? 'string' == typeof r
? r
: r
.reduce(function (r, t) {
return r.concat([
(function (n, e) {
if (((e = e || {}), 'string' == typeof n))
return n;
{
var r, t, u;
if (n[2] && 'object' == typeof n[2])
return (
(r = Object.keys(n[2]).reduce(
function (r, t) {
return (
(r[t] = i(
n[2][t],
e
)),
r
);
},
{}
)),
(t = r[e[0]]),
void 0 !== (u = e[n[0]])
? r[u.toString()] ||
r.other ||
o
: t || r.other || o
);
}
if ('object' == typeof n && 0 < n.length)
return (function r(t, n, e) {
void 0 === e && (e = 0);
if (!n || !t || t.length <= 0)
return '';
n = n[t[e]];
if ('string' == typeof n) return n;
if ('number' == typeof n)
return n.toString();
if (!n)
return '{'.concat(
t.join('.'),
'}'
);
return r(t, n, ++e);
})(n[0].split('.'), e, 0);
return '';
})(t, n),
]);
}, [])
.join('')
: o;
}
function c(r, t, n) {
return (
('object' == typeof r &&
((t = t).constructor && 'Array' === t.constructor
? t
: t
.replace(getRegExp('\[', 'ig'), '.')
.replace(getRegExp('\]', 'ig'), '')
.split('.')
).reduce(function (r, t) {
return (r || {})[t];
}, r)) ||
n
);
}
function f(r) {
var t = r;
return (t =
r && -1 !== r.indexOf(':')
? r.replace(getRegExp(':', 'ig'), '.')
: t);
}
function g(r, t, n) {
var e = f(n),
r = r[t];
return (r && (r[e] || c(r, e))) || n;
}
return (
(r.getMessageInterpreter = function () {
function u(r, t, n, e) {
return i(
(function (r, t, n, e) {
var u = f(r);
if (!(n = t[n])) return g(t, e, r);
var o = n[u];
return (o = o || c(n, u)) ? o : g(t, e, r);
})(r, e, n, n),
t
);
}
return function (r, t, n, e) {
return 3 === arguments.length
? u(r, null, t, n)
: 4 === arguments.length
? u(r, t, n, e)
: '';
};
}),
r
);
})({});
module.exports = {
t: Interpreter.getMessageInterpreter()
}