parent
795969842c
commit
8e36765c2e
@ -1,28 +0,0 @@ |
||||
<?php |
||||
|
||||
/* This script is run on demand to generate JS version of tr() */ |
||||
|
||||
require_once __DIR__ . '/base.php'; |
||||
|
||||
$selected = [ |
||||
'wifi.connected_ip_is', |
||||
'wifi.not_conn', |
||||
'wifi.enter_passwd', |
||||
'term_nav.fullscreen', |
||||
'term_conn.connecting', |
||||
'term_conn.waiting_content', |
||||
'term_conn.disconnected', |
||||
'term_conn.waiting_server', |
||||
'term_conn.reconnecting' |
||||
]; |
||||
|
||||
$out = []; |
||||
foreach ($selected as $key) { |
||||
$out[$key] = tr($key); |
||||
} |
||||
|
||||
file_put_contents(__DIR__. '/js/lang.js', |
||||
"// Generated from PHP locale file\n" . |
||||
'let _tr = ' . json_encode($out, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) . ";\n\n" . |
||||
"module.exports = function tr (key) { return _tr[key] || '?' + key + '?' }\n" |
||||
); |
@ -0,0 +1,5 @@ |
||||
let data = require('locale-data') |
||||
|
||||
module.exports = function localize (key) { |
||||
return data[key] || `?${key}?` |
||||
} |
@ -0,0 +1,12 @@ |
||||
// define language keys used by JS here
|
||||
module.exports = [ |
||||
'wifi.connected_ip_is', |
||||
'wifi.not_conn', |
||||
'wifi.enter_passwd', |
||||
'term_nav.fullscreen', |
||||
'term_conn.connecting', |
||||
'term_conn.waiting_content', |
||||
'term_conn.disconnected', |
||||
'term_conn.waiting_server', |
||||
'term_conn.reconnecting' |
||||
] |
@ -0,0 +1,178 @@ |
||||
/* |
||||
* This is a Webpack loader. |
||||
* Loads language PHP files by parsing the PHP syntax and returning a Javascript |
||||
* Object. This is because using JSON instead of PHP would not allow multiline |
||||
* strings, and CSON is unsupported by PHP, and because splitting the language |
||||
* files into PHP and JSON seems unwieldy. |
||||
*/ |
||||
|
||||
const selectedKeys = require('./keys') |
||||
|
||||
const tokenizeRest = function (tokens, tokenize, ...args) { |
||||
let i = 0 |
||||
|
||||
while (i < tokens.length) { |
||||
if (typeof tokens[i] === 'string') { |
||||
tokens.splice(i, 1, ...tokenize(tokens[i], ...args)) |
||||
} |
||||
i++ |
||||
} |
||||
|
||||
return tokens |
||||
} |
||||
|
||||
const tokenizers = { |
||||
simpleType (code, regex, type, matchIndex = 1) { |
||||
let tokens = [] |
||||
let match |
||||
|
||||
while ((match = code.match(regex))) { |
||||
let before = code.substr(0, match.index) |
||||
code = code.substr(match.index + match[0].length) |
||||
|
||||
if (before) tokens.push(before) |
||||
tokens.push({ |
||||
type, |
||||
match, |
||||
content: match[matchIndex] |
||||
}) |
||||
} |
||||
|
||||
if (code) tokens.push(code) |
||||
|
||||
return tokens |
||||
} |
||||
} |
||||
|
||||
const unescapeString = function (token) { |
||||
if (token.match[1] === "'") { |
||||
// single-quoted string only has \\ and \'
|
||||
return token.content.replace(/\\[\\']/g, match => match[1]) |
||||
} else { |
||||
// double-quoted string
|
||||
// \n -> 0x0A
|
||||
// \r -> 0x0D
|
||||
// \t -> 0x09
|
||||
// \v -> 0x0B
|
||||
// \e -> 0x1B
|
||||
// \f -> 0x0C
|
||||
// \\ -> \
|
||||
// \$ -> $
|
||||
// \" -> "
|
||||
// \[0-7]{1,3} -> char
|
||||
// \x[\da-f]{1,2} -> char
|
||||
// \u{[\da-f]+} -> char
|
||||
let content = token.content |
||||
content = content.replace(/\\[nrtvef\\$"]/g, match => match[1]) |
||||
content = content.replace(/\\[0-7]{1,3}/g, match => { |
||||
return String.fromCodePoint(parseInt(match.substr(1), 8) % 0xFF) |
||||
}) |
||||
content = content.replace(/\\x[\da-f]{1,2}/ig, match => { |
||||
return String.fromCodePoint(parseInt(match.substr(1), 16) % 0xFF) |
||||
}) |
||||
content = content.replace(/\\u{[\da-f]+}/ig, match => { |
||||
return String.fromCodePoint(parseInt(match.substr(1), 16)) |
||||
}) |
||||
return content |
||||
} |
||||
} |
||||
|
||||
module.exports = function (source) { |
||||
let originalSource = source |
||||
|
||||
// remove PHP header
|
||||
source = source.replace(/^\s*<\?(?:php)?\s*/, '') |
||||
|
||||
// remove return statement
|
||||
source = source.replace(/^return\s*/, '') |
||||
|
||||
// remove trailing semicolon
|
||||
source = source.replace(/;\s*$/, '') |
||||
|
||||
// strings
|
||||
let tokens = tokenizeRest([source], tokenizers.simpleType, /(['"])((?:\\.|[^\\\1])*?)\1/, 'string', 2) |
||||
|
||||
// comments
|
||||
tokenizeRest(tokens, tokenizers.simpleType, /\/\/(.*)/, 'comment') |
||||
|
||||
// map delimiters
|
||||
tokenizeRest(tokens, tokenizers.simpleType, /([[\]])/, 'map') |
||||
|
||||
// arrows
|
||||
tokenizeRest(tokens, tokenizers.simpleType, /(=>)/, 'arrow') |
||||
|
||||
// commas
|
||||
tokenizeRest(tokens, tokenizers.simpleType, /(,)/, 'comma') |
||||
|
||||
// whitespace
|
||||
tokenizeRest(tokens, tokenizers.simpleType, /(\s+)/, 'whitespace') |
||||
|
||||
// remove whitespace tokens and comments
|
||||
tokens = tokens.filter(token => !(['whitespace', 'comment'].includes(token.type))) |
||||
|
||||
// split tokens into an array of items, separated by commas
|
||||
let currentItem = [] |
||||
let items = [currentItem] |
||||
|
||||
for (let token of tokens) { |
||||
let { type } = token |
||||
|
||||
if (type === 'map') continue |
||||
if (type === 'comma') items.push(currentItem = []) |
||||
else currentItem.push(token) |
||||
} |
||||
|
||||
// remove null items
|
||||
items = items.filter(item => item.length) |
||||
|
||||
// assume that every item will contain [string, arrow, string] and create
|
||||
// an object
|
||||
let data = {} |
||||
|
||||
for (let item of items) { |
||||
let key = item[0] |
||||
let value = item[2] |
||||
|
||||
if (!key || !value) { |
||||
console.error('Item has no key or value!', item) |
||||
continue |
||||
} |
||||
|
||||
data[unescapeString(key)] = unescapeString(value) |
||||
} |
||||
|
||||
let result = {} |
||||
|
||||
// put selected keys in result
|
||||
for (let key of selectedKeys) { |
||||
result[key] = data[key] |
||||
} |
||||
|
||||
// adapted from webpack/loader-utils
|
||||
let remainingRequest = this.remainingRequest |
||||
if (!remainingRequest) { |
||||
remainingRequest = this.loaders.slice(this.loaderIndex + 1) |
||||
.map(obj => obj.request) |
||||
.concat([this.resource]).join('!') |
||||
} |
||||
|
||||
let currentRequest = this.currentRequest |
||||
if (!currentRequest) { |
||||
remainingRequest = this.loaders.slice(this.loaderIndex) |
||||
.map(obj => obj.request) |
||||
.concat([this.resource]).join('!') |
||||
} |
||||
|
||||
let map = { |
||||
version: 3, |
||||
file: currentRequest, |
||||
sourceRoot: '', |
||||
sources: [remainingRequest], |
||||
sourcesContent: [originalSource], |
||||
names: [], |
||||
mappings: 'AAAA;AAAA' |
||||
} |
||||
|
||||
this.callback(null, `/* Generated language file */
|
||||
module.exports=${JSON.stringify(result)}`, map)
|
||||
} |
Loading…
Reference in new issue