Add coexistence checks to all enqueue methods to prevent loading both React and Grid.js assets simultaneously. Changes: - ReactAdmin.php: Only enqueue React assets when ?react=1 - Init.php: Skip Grid.js when React active on admin pages - Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0 - Customer.php, Product.php, License.php: Add coexistence checks Now the toggle between Classic and React versions works correctly. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
240 lines
6.2 KiB
JavaScript
240 lines
6.2 KiB
JavaScript
'use strict';
|
|
|
|
var Buffer = require('safe-buffer').Buffer;
|
|
var encoding = require('encoding');
|
|
var sharedFuncs = require('./shared');
|
|
|
|
/**
|
|
* Exposes general compiler function. Takes a translation
|
|
* object as a parameter and returns binary MO object
|
|
*
|
|
* @param {Object} table Translation object
|
|
* @return {Buffer} Compiled binary MO object
|
|
*/
|
|
module.exports = function (table) {
|
|
var compiler = new Compiler(table);
|
|
return compiler.compile();
|
|
};
|
|
|
|
/**
|
|
* Creates a MO compiler object.
|
|
*
|
|
* @constructor
|
|
* @param {Object} table Translation table as defined in the README
|
|
*/
|
|
function Compiler (table) {
|
|
this._table = table || {};
|
|
this._table.headers = this._table.headers || {};
|
|
this._table.translations = this._table.translations || {};
|
|
|
|
this._translations = [];
|
|
|
|
this._writeFunc = 'writeUInt32LE';
|
|
|
|
this._handleCharset();
|
|
}
|
|
|
|
/**
|
|
* Magic bytes for the generated binary data
|
|
*/
|
|
Compiler.prototype.MAGIC = 0x950412de;
|
|
|
|
/**
|
|
* Handles header values, replaces or adds (if needed) a charset property
|
|
*/
|
|
Compiler.prototype._handleCharset = function () {
|
|
var parts = (this._table.headers['content-type'] || 'text/plain').split(';');
|
|
var contentType = parts.shift();
|
|
var charset = sharedFuncs.formatCharset(this._table.charset);
|
|
var params = [];
|
|
|
|
params = parts.map(function (part) {
|
|
var parts = part.split('=');
|
|
var key = parts.shift().trim();
|
|
var value = parts.join('=');
|
|
|
|
if (key.toLowerCase() === 'charset') {
|
|
if (!charset) {
|
|
charset = sharedFuncs.formatCharset(value.trim() || 'utf-8');
|
|
}
|
|
return 'charset=' + charset;
|
|
}
|
|
|
|
return part;
|
|
});
|
|
|
|
if (!charset) {
|
|
charset = this._table.charset || 'utf-8';
|
|
params.push('charset=' + charset);
|
|
}
|
|
|
|
this._table.charset = charset;
|
|
this._table.headers['content-type'] = contentType + '; ' + params.join('; ');
|
|
|
|
this._charset = charset;
|
|
};
|
|
|
|
/**
|
|
* Generates an array of translation strings
|
|
* in the form of [{msgid:... , msgstr:...}]
|
|
*
|
|
* @return {Array} Translation strings array
|
|
*/
|
|
Compiler.prototype._generateList = function () {
|
|
var list = [];
|
|
|
|
list.push({
|
|
msgid: Buffer.alloc(0),
|
|
msgstr: encoding.convert(sharedFuncs.generateHeader(this._table.headers), this._charset)
|
|
});
|
|
|
|
Object.keys(this._table.translations).forEach(function (msgctxt) {
|
|
if (typeof this._table.translations[msgctxt] !== 'object') {
|
|
return;
|
|
}
|
|
Object.keys(this._table.translations[msgctxt]).forEach(function (msgid) {
|
|
if (typeof this._table.translations[msgctxt][msgid] !== 'object') {
|
|
return;
|
|
}
|
|
if (msgctxt === '' && msgid === '') {
|
|
return;
|
|
}
|
|
|
|
var msgidPlural = this._table.translations[msgctxt][msgid].msgid_plural;
|
|
var key = msgid;
|
|
var value;
|
|
|
|
if (msgctxt) {
|
|
key = msgctxt + '\u0004' + key;
|
|
}
|
|
|
|
if (msgidPlural) {
|
|
key += '\u0000' + msgidPlural;
|
|
}
|
|
|
|
value = [].concat(this._table.translations[msgctxt][msgid].msgstr || []).join('\u0000');
|
|
|
|
list.push({
|
|
msgid: encoding.convert(key, this._charset),
|
|
msgstr: encoding.convert(value, this._charset)
|
|
});
|
|
}.bind(this));
|
|
}.bind(this));
|
|
|
|
return list;
|
|
};
|
|
|
|
/**
|
|
* Calculate buffer size for the final binary object
|
|
*
|
|
* @param {Array} list An array of translation strings from _generateList
|
|
* @return {Object} Size data of {msgid, msgstr, total}
|
|
*/
|
|
Compiler.prototype._calculateSize = function (list) {
|
|
var msgidLength = 0;
|
|
var msgstrLength = 0;
|
|
var totalLength = 0;
|
|
|
|
list.forEach(function (translation) {
|
|
msgidLength += translation.msgid.length + 1; // + extra 0x00
|
|
msgstrLength += translation.msgstr.length + 1; // + extra 0x00
|
|
});
|
|
|
|
totalLength = 4 + // magic number
|
|
4 + // revision
|
|
4 + // string count
|
|
4 + // original string table offset
|
|
4 + // translation string table offset
|
|
4 + // hash table size
|
|
4 + // hash table offset
|
|
(4 + 4) * list.length + // original string table
|
|
(4 + 4) * list.length + // translations string table
|
|
msgidLength + // originals
|
|
msgstrLength; // translations
|
|
|
|
return {
|
|
msgid: msgidLength,
|
|
msgstr: msgstrLength,
|
|
total: totalLength
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Generates the binary MO object from the translation list
|
|
*
|
|
* @param {Array} list translation list
|
|
* @param {Object} size Byte size information
|
|
* @return {Buffer} Compiled MO object
|
|
*/
|
|
Compiler.prototype._build = function (list, size) {
|
|
var returnBuffer = Buffer.alloc(size.total);
|
|
var curPosition = 0;
|
|
var i;
|
|
var len;
|
|
|
|
// magic
|
|
returnBuffer[this._writeFunc](this.MAGIC, 0);
|
|
|
|
// revision
|
|
returnBuffer[this._writeFunc](0, 4);
|
|
|
|
// string count
|
|
returnBuffer[this._writeFunc](list.length, 8);
|
|
|
|
// original string table offset
|
|
returnBuffer[this._writeFunc](28, 12);
|
|
|
|
// translation string table offset
|
|
returnBuffer[this._writeFunc](28 + (4 + 4) * list.length, 16);
|
|
|
|
// hash table size
|
|
returnBuffer[this._writeFunc](0, 20);
|
|
|
|
// hash table offset
|
|
returnBuffer[this._writeFunc](28 + (4 + 4) * list.length * 2, 24);
|
|
|
|
// build originals table
|
|
curPosition = 28 + 2 * (4 + 4) * list.length;
|
|
for (i = 0, len = list.length; i < len; i++) {
|
|
list[i].msgid.copy(returnBuffer, curPosition);
|
|
returnBuffer[this._writeFunc](list[i].msgid.length, 28 + i * 8);
|
|
returnBuffer[this._writeFunc](curPosition, 28 + i * 8 + 4);
|
|
returnBuffer[curPosition + list[i].msgid.length] = 0x00;
|
|
curPosition += list[i].msgid.length + 1;
|
|
}
|
|
|
|
// build translations table
|
|
for (i = 0, len = list.length; i < len; i++) {
|
|
list[i].msgstr.copy(returnBuffer, curPosition);
|
|
returnBuffer[this._writeFunc](list[i].msgstr.length, 28 + (4 + 4) * list.length + i * 8);
|
|
returnBuffer[this._writeFunc](curPosition, 28 + (4 + 4) * list.length + i * 8 + 4);
|
|
returnBuffer[curPosition + list[i].msgstr.length] = 0x00;
|
|
curPosition += list[i].msgstr.length + 1;
|
|
}
|
|
|
|
return returnBuffer;
|
|
};
|
|
|
|
/**
|
|
* Compiles translation object into a binary MO object
|
|
*
|
|
* @return {Buffer} Compiled MO object
|
|
*/
|
|
Compiler.prototype.compile = function () {
|
|
var list = this._generateList();
|
|
var size = this._calculateSize(list);
|
|
|
|
// sort by msgid
|
|
list.sort(function (a, b) {
|
|
if (a.msgid > b.msgid) {
|
|
return 1;
|
|
}
|
|
if (a.msgid < b.msgid) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
});
|
|
|
|
return this._build(list, size);
|
|
};
|