Reworked the trgen project structure and remove unneeded functionality
This commit is contained in:
parent
9d8c3600e1
commit
084dd4cb63
16 changed files with 65 additions and 424 deletions
|
@ -1,13 +1,8 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
BASEDIR=$(dirname "$0")
|
npm run compile-tr-gen
|
||||||
source "${BASEDIR}/../scripts/resolve_commands.sh"
|
|
||||||
cd "$BASEDIR/trgen"
|
|
||||||
|
|
||||||
execute_tsc -p tsconfig.json
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Failed to build typescript translation generator"
|
echo "Failed to build typescript translation generator"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit 0
|
exit 0
|
|
@ -1,52 +0,0 @@
|
||||||
import * as ts from "typescript";
|
|
||||||
import * as ts_generator from "./TsGenerator";
|
|
||||||
import {TranslationEntry} from "./generator";
|
|
||||||
|
|
||||||
export interface TransformerConfig {
|
|
||||||
verbose: boolean;
|
|
||||||
optimized: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output array for all gathered translations.
|
|
||||||
*/
|
|
||||||
translations?: TranslationEntry[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const deltaTranslations = (result: TranslationEntry[], fileName: string, processSpeed: number, newTranslations: TranslationEntry[]) => {
|
|
||||||
let deletedTranslations = 0;
|
|
||||||
for(let index = 0; index < result.length; index++) {
|
|
||||||
if(result[index].filename === fileName) {
|
|
||||||
result.splice(index, 1);
|
|
||||||
index--;
|
|
||||||
deletedTranslations++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.push(...newTranslations);
|
|
||||||
if(deletedTranslations === 0 && newTranslations.length === 0) {
|
|
||||||
console.log("Processed %s (%dms). No translations found.", fileName, processSpeed);
|
|
||||||
} else if(deletedTranslations === 0) {
|
|
||||||
console.log("Processed %s (%dms). Found %d translations", fileName, processSpeed, newTranslations.length);
|
|
||||||
} else if(newTranslations.length === 0) {
|
|
||||||
console.log("Processed %s (%dms). %d translations deleted.", fileName, processSpeed, deletedTranslations);
|
|
||||||
} else {
|
|
||||||
console.log("Processed %s (%dms). Old translation count: %d New translation count: %d", fileName, processSpeed, deletedTranslations, newTranslations.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createTransformer = (program: ts.Program, config: TransformerConfig) : ts.TransformerFactory<ts.SourceFile> => {
|
|
||||||
return ctx => sourceFile => {
|
|
||||||
const timestampBegin = Date.now();
|
|
||||||
const result = ts_generator.transform({
|
|
||||||
module: true,
|
|
||||||
useWindow: false,
|
|
||||||
/* Note: Even though caching might cause less method calls but if the tr method is performant developed it's faster than having the cache lookup */
|
|
||||||
cacheTranslations: false,
|
|
||||||
optimized: config.optimized,
|
|
||||||
}, ctx, sourceFile);
|
|
||||||
const timestampEnd = Date.now();
|
|
||||||
|
|
||||||
deltaTranslations(config.translations || [], sourceFile.fileName, timestampEnd - timestampBegin, result.translations);
|
|
||||||
return result.node;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
BASEDIR=$(dirname "$0")
|
|
||||||
FILE="${BASEDIR}/../compiler.ts"
|
|
||||||
|
|
||||||
npm run dtsgen -- $@
|
|
|
@ -1,82 +0,0 @@
|
||||||
import * as ts from "typescript";
|
|
||||||
import * as generator from "./TsGenerator";
|
|
||||||
|
|
||||||
import {readFileSync} from "fs";
|
|
||||||
import * as glob from "glob";
|
|
||||||
import * as path from "path";
|
|
||||||
|
|
||||||
const transformer = <T extends ts.Node>(context: ts.TransformationContext) => (rootNode: T) => {
|
|
||||||
return generator.transform({
|
|
||||||
useWindow: false,
|
|
||||||
cacheTranslations: true,
|
|
||||||
verbose: true
|
|
||||||
}, context, rootNode as any).node;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function compile(fileNames: string[], options: ts.CompilerOptions): void {
|
|
||||||
const program: ts.Program = ts.createProgram(fileNames, options);
|
|
||||||
|
|
||||||
let emitResult = program.emit(undefined, undefined, undefined, undefined, {
|
|
||||||
before: [ transformer ]
|
|
||||||
});
|
|
||||||
|
|
||||||
let allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
|
|
||||||
|
|
||||||
allDiagnostics.forEach(diagnostic => {
|
|
||||||
if (diagnostic.file) {
|
|
||||||
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(
|
|
||||||
diagnostic.start!
|
|
||||||
);
|
|
||||||
let message = ts.flattenDiagnosticMessageText(
|
|
||||||
diagnostic.messageText,
|
|
||||||
"\n"
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
`${ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let exitCode = emitResult.emitSkipped ? 1 : 0;
|
|
||||||
console.log(`Process exiting with code '${exitCode}'.`);
|
|
||||||
process.exit(exitCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = ts.parseCommandLine(process.argv.slice(2), file => readFileSync(file).toString());
|
|
||||||
if(config.errors && config.errors.length > 0) {
|
|
||||||
for(const error of config.errors)
|
|
||||||
console.log(error.messageText);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(config.options.project) {
|
|
||||||
const project = ts.readConfigFile(config.options.project, file => readFileSync(file).toString()).config;
|
|
||||||
const base_path = path.dirname(config.options.project) + "/";
|
|
||||||
console.dir(project);
|
|
||||||
|
|
||||||
|
|
||||||
const negate_files: string[] = [].concat.apply([], (project.exclude || []).map(file => glob.sync(base_path + file))).map(file => path.normalize(file));
|
|
||||||
project.include.forEach(file => {
|
|
||||||
glob.sync(base_path + file).forEach(_file => {
|
|
||||||
_file = path.normalize(_file);
|
|
||||||
for(const n_file of negate_files) {
|
|
||||||
if(n_file == _file) {
|
|
||||||
console.log("Skipping %s", _file);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config.fileNames.push(_file);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.assign(config.options, project.compilerOptions);
|
|
||||||
console.log(config.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
compile(config.fileNames, config.options);
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {TranslationEntry} from "./generator";
|
import {TranslationEntry} from "../Definitions";
|
||||||
|
|
||||||
export interface File {
|
export interface File {
|
||||||
content: string;
|
content: string;
|
||||||
|
@ -17,7 +17,6 @@ export function extractJsRendererTranslations(file: File) : TranslationEntry[] {
|
||||||
|
|
||||||
while(match = regex.exec(file.content.substr(baseIndex))) {
|
while(match = regex.exec(file.content.substr(baseIndex))) {
|
||||||
let expression = (match.groups || {})["message_expression"] || match[1];
|
let expression = (match.groups || {})["message_expression"] || match[1];
|
||||||
//expression = expression.replace(/\n/g, "\\n");
|
|
||||||
|
|
||||||
let message;
|
let message;
|
||||||
try {
|
try {
|
|
@ -1,7 +1,7 @@
|
||||||
import * as ts from "typescript";
|
import * as ts from "typescript";
|
||||||
import sha256 from "sha256";
|
import sha256 from "sha256";
|
||||||
import {SyntaxKind} from "typescript";
|
import {SyntaxKind} from "typescript";
|
||||||
import {TranslationEntry} from "./generator";
|
import {TranslationEntry} from "../Definitions";
|
||||||
|
|
||||||
const getSourceLocation = (node: ts.Node) => {
|
const getSourceLocation = (node: ts.Node) => {
|
||||||
const sf = node.getSourceFile();
|
const sf = node.getSourceFile();
|
||||||
|
@ -384,6 +384,7 @@ export function visitNode(config: Configuration, cache: VolatileTransformConfig,
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Configuration {
|
export interface Configuration {
|
||||||
useWindow?: boolean;
|
useWindow?: boolean;
|
||||||
cacheTranslations?: boolean;
|
cacheTranslations?: boolean;
|
|
@ -1,150 +0,0 @@
|
||||||
import * as ts from "typescript";
|
|
||||||
import * as ts_generator from "./TsGenerator";
|
|
||||||
import * as jsrender_generator from "./JsRendererGenerator";
|
|
||||||
import {readFileSync, writeFileSync} from "fs";
|
|
||||||
import * as path from "path";
|
|
||||||
import * as glob from "glob";
|
|
||||||
import {isArray} from "util";
|
|
||||||
import * as mkdirp from "mkdirp";
|
|
||||||
import {TranslationEntry} from "./generator";
|
|
||||||
|
|
||||||
/*
|
|
||||||
const files = ["/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/build/trgen/test/test_01.ts"];
|
|
||||||
files.forEach(file => {
|
|
||||||
let source = ts.createSourceFile(
|
|
||||||
file,
|
|
||||||
readFileSync(file).toString(),
|
|
||||||
ts.ScriptTarget.ES2016,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
generator.generate(source);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
interface Config {
|
|
||||||
source_files?: string[];
|
|
||||||
excluded_files?: string[];
|
|
||||||
target_file?: string;
|
|
||||||
verbose?: boolean;
|
|
||||||
|
|
||||||
base_bath?: string;
|
|
||||||
file_config?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
let config: Config = {};
|
|
||||||
|
|
||||||
let args = process.argv.slice(2);
|
|
||||||
while(args.length > 0) {
|
|
||||||
if(args[0] == "-f" || args[0] == "--file") {
|
|
||||||
(config.source_files || (config.source_files = [])).push(args[1]);
|
|
||||||
args = args.slice(2);
|
|
||||||
} else if(args[0] == "-e" || args[0] == "--exclude") {
|
|
||||||
(config.excluded_files || (config.excluded_files = [])).push(args[1]);
|
|
||||||
args = args.slice(2);
|
|
||||||
} else if(args[0] == "-d" || args[0] == "--destination") {
|
|
||||||
config.target_file = args[1];
|
|
||||||
args = args.slice(2);
|
|
||||||
} else if(args[0] == "-v" || args[0] == "--verbose") {
|
|
||||||
config.verbose = true;
|
|
||||||
args = args.slice(1);
|
|
||||||
} else if(args[0] == "-c" || args[0] == "--config") {
|
|
||||||
config.file_config = args[1];
|
|
||||||
config.base_bath = path.normalize(path.dirname(config.file_config)) + "/";
|
|
||||||
args = args.slice(2);
|
|
||||||
} else {
|
|
||||||
console.error("Invalid command line option \"%s\"", args[0]);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config.base_bath = config.base_bath || "";
|
|
||||||
|
|
||||||
|
|
||||||
if(config.verbose) {
|
|
||||||
console.log("Base path: " + config.base_bath);
|
|
||||||
console.log("Input files:");
|
|
||||||
for(const file of config.source_files)
|
|
||||||
console.log(" - " + file);
|
|
||||||
console.log("Target file: " + config.target_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
const negate_files: string[] = [].concat.apply([], (config.excluded_files || []).map(file => glob.sync(config.base_bath + file))).map(file => path.normalize(file));
|
|
||||||
|
|
||||||
let result = "";
|
|
||||||
|
|
||||||
function print(nodes: ts.Node[] | ts.SourceFile) : string {
|
|
||||||
if(!isArray(nodes) && nodes.kind == ts.SyntaxKind.SourceFile)
|
|
||||||
nodes = (<ts.SourceFile>nodes).getChildren();
|
|
||||||
const dummy_file = ts.createSourceFile(
|
|
||||||
"dummy_file",
|
|
||||||
"",
|
|
||||||
ts.ScriptTarget.ES2016,
|
|
||||||
false,
|
|
||||||
ts.ScriptKind.TS
|
|
||||||
);
|
|
||||||
|
|
||||||
const printer = ts.createPrinter({
|
|
||||||
newLine: ts.NewLineKind.LineFeed
|
|
||||||
});
|
|
||||||
|
|
||||||
return printer.printList(
|
|
||||||
ts.ListFormat.SpaceBetweenBraces | ts.ListFormat.MultiLine | ts.ListFormat.PreferNewLine,
|
|
||||||
nodes as any,
|
|
||||||
dummy_file
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const translations: TranslationEntry[] = [];
|
|
||||||
config.source_files.forEach(file => {
|
|
||||||
if(config.verbose)
|
|
||||||
console.log("iterating over %s (%s)", file, path.resolve(path.normalize(config.base_bath + file)));
|
|
||||||
|
|
||||||
glob.sync(config.base_bath + file).forEach(_file => {
|
|
||||||
_file = path.normalize(_file);
|
|
||||||
for(const n_file of negate_files) {
|
|
||||||
if(n_file == _file) {
|
|
||||||
console.log("Skipping %s", _file);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const file_type = path.extname(_file);
|
|
||||||
if(file_type == ".ts" || file_type == ".tsx") {
|
|
||||||
let source = ts.createSourceFile(
|
|
||||||
_file,
|
|
||||||
readFileSync(_file).toString(),
|
|
||||||
ts.ScriptTarget.ES2016,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
console.log("Compile " + _file);
|
|
||||||
|
|
||||||
throw "not supported";
|
|
||||||
//const messages = ts_generator.generate(source, {});
|
|
||||||
//translations.push(...messages);
|
|
||||||
} else if(file_type == ".html") {
|
|
||||||
const messages = jsrender_generator.extractJsRendererTranslations({
|
|
||||||
content: readFileSync(_file).toString(),
|
|
||||||
name: _file
|
|
||||||
});
|
|
||||||
translations.push(...messages);
|
|
||||||
/*
|
|
||||||
messages.forEach(message => {
|
|
||||||
console.log(message);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
} else {
|
|
||||||
console.log("Unknown file type \"%s\". Skipping file %s", file_type, _file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if(config.target_file) {
|
|
||||||
mkdirp(path.normalize(path.dirname(config.base_bath + config.target_file)), error => {
|
|
||||||
if(error)
|
|
||||||
throw error;
|
|
||||||
writeFileSync(config.base_bath + config.target_file, JSON.stringify(translations, null, 2));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.log(JSON.stringify(translations, null, 2));
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
function tr(message: string) : string {
|
|
||||||
console.log("Message: " + message);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
const x = tr("yyy");
|
|
||||||
function y() {
|
|
||||||
const y = tr(tr("yyy"));
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("XXX: " + tr("XXX"));
|
|
||||||
console.log("YYY: " + tr("YYY"));
|
|
||||||
|
|
||||||
var z = 1 + 2 + 3;
|
|
||||||
|
|
||||||
debugger;
|
|
||||||
debugger;
|
|
||||||
debugger;
|
|
||||||
debugger;
|
|
||||||
const zzz = true ? "yyy" : "bbb";
|
|
||||||
|
|
||||||
const zy = "";
|
|
||||||
debugger;
|
|
||||||
debugger;
|
|
||||||
debugger;
|
|
||||||
debugger;
|
|
||||||
const { a } = {a : ""};
|
|
|
@ -1,66 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Title</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script class="jsrender-template" id="tmpl_connect" type="text/html">
|
|
||||||
<div style="margin-top: 5px;">
|
|
||||||
<div style="display: flex; flex-direction: row; width: 100%; justify-content: space-between">
|
|
||||||
<div style="width: 68%; margin-bottom: 5px">
|
|
||||||
<div>{{tr "Remote address and port:" /}}</div>
|
|
||||||
<input type="text" style="width: 100%" class="connect_address" value="unknown">
|
|
||||||
</div>
|
|
||||||
<div style="width: 20%">
|
|
||||||
<div>{{tr "Server password:" /}}</div>
|
|
||||||
<form name="server_password_form" onsubmit="return false;">
|
|
||||||
<input type="password" id="connect_server_password_{{rnd '0~13377331'/}}" autocomplete="off" style="width: 100%" class="connect_password">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div>{{tr "Nickname:" /}}</div>
|
|
||||||
<input type="text" style="width: 100%" class="connect_nickname" value="">
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class="group_box">
|
|
||||||
<div style="display: flex; justify-content: space-between;">
|
|
||||||
<div style="text-align: right;">{{tr "Identity Settings" /}}</div>
|
|
||||||
<select class="identity_select">
|
|
||||||
<option name="identity_type" value="TEAFORO">{{tr "Forum Account" /}}</option>
|
|
||||||
<option name="identity_type" value="TEAMSPEAK">{{tr "TeamSpeak" /}}</option>
|
|
||||||
<option name="identity_type" value="NICKNAME">{{tr "Nickname (Debug purposes only!)" /}}</option> <!-- Only available on localhost for debug -->
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class="identity_config_TEAMSPEAK identity_config">
|
|
||||||
{{tr "Please enter your exported TS3 Identity string bellow or select your exported Identity"/}}<br>
|
|
||||||
<div style="width: 100%; display: flex; justify-content: stretch; flex-direction: row">
|
|
||||||
<input placeholder="Identity string" style="min-width: 60%; flex-shrink: 1; flex-grow: 2; margin: 5px;" class="identity_string">
|
|
||||||
<div style="max-width: 200px; flex-grow: 1; flex-shrink: 4; margin: 5px"><input style="display: flex; width: 100%;" class="identity_file" type="file"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="identity_config_TEAFORO identity_config">
|
|
||||||
<div class="connected">
|
|
||||||
{{tr "You're using your forum account as verification"/}}
|
|
||||||
</div>
|
|
||||||
<div class="disconnected">
|
|
||||||
<!-- TODO tr -->
|
|
||||||
You cant use your TeaSpeak forum account.<br>
|
|
||||||
You're not connected!<br>
|
|
||||||
Click {{if !client}}<a href="{{:forum_path}}login.php">here</a>{{else}}<a href="#" class="native-teaforo-login">here</a>{{/if}} to login via the TeaSpeak forum.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="identity_config_NICKNAME identity_config">
|
|
||||||
{{tr "This is just for debug and uses the name as unique identifier" /}}
|
|
||||||
{{tr "This is just for debug and uses the name as unique identifier" + "Hello World :D" /}}
|
|
||||||
{{tr "This is just for debug and uses the name as unique identifier" + `Hello World :D 2` /}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="background-color: red; border-radius: 1px; display: none" class="error_message"></div>
|
|
||||||
</div> <!-- <a href="<?php echo authPath() . "login.php"; ?>">Login</a> via the TeaSpeak forum. -->
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,8 +0,0 @@
|
||||||
import {Translatable, VariadicTranslatable} from "../../../shared/js/ui/react-elements/i18n";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
function test() {
|
|
||||||
const element_0 = <Translatable>Hello World</Translatable>;
|
|
||||||
const element_1 = <Translatable>{"Hello World"}</Translatable>;
|
|
||||||
const element_2 = <VariadicTranslatable text={"XXX"}><>XXX</></VariadicTranslatable>;
|
|
||||||
}
|
|
|
@ -11,11 +11,11 @@
|
||||||
"esModuleInterop": true
|
"esModuleInterop": true
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"generator.ts",
|
"./Definitions.ts",
|
||||||
"index.ts",
|
"./generator/JsRenderer.ts",
|
||||||
"compiler.ts",
|
"./generator/TypeScript.ts",
|
||||||
"JsRendererGenerator.ts",
|
"./webpack/Loader.ts",
|
||||||
"TsGenerator.ts",
|
"./webpack/Plugin.ts",
|
||||||
"JsRendererTranslationLoader.ts"
|
"./webpack/Utils.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import {extractJsRendererTranslations} from "./JsRendererGenerator";
|
import {extractJsRendererTranslations} from "../generator/JsRenderer";
|
||||||
import {deltaTranslations} from "./TsTransformer";
|
import {deltaTranslations} from "./Utils";
|
||||||
|
|
||||||
export default function (source) {
|
export default function (source) {
|
||||||
const options = this.getOptions({
|
const options = this.getOptions({
|
|
@ -1,7 +1,9 @@
|
||||||
import * as ts from "typescript";
|
import * as ts from "typescript";
|
||||||
import {createTransformer, TransformerConfig} from "./TsTransformer";
|
|
||||||
import * as webpack from "webpack";
|
import * as webpack from "webpack";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
import {transform} from "../generator/TypeScript";
|
||||||
|
import {deltaTranslations} from "./Utils";
|
||||||
|
import {TranslationEntry} from "../Definitions";
|
||||||
|
|
||||||
export interface TranslateableWebpackPluginConfig {
|
export interface TranslateableWebpackPluginConfig {
|
||||||
assetName: string,
|
assetName: string,
|
||||||
|
@ -9,33 +11,45 @@ export interface TranslateableWebpackPluginConfig {
|
||||||
|
|
||||||
export default class TranslateableWebpackPlugin {
|
export default class TranslateableWebpackPlugin {
|
||||||
private readonly config: TranslateableWebpackPluginConfig;
|
private readonly config: TranslateableWebpackPluginConfig;
|
||||||
private readonly transformerConfig: TransformerConfig;
|
private readonly translations: TranslationEntry[];
|
||||||
|
|
||||||
constructor(config: TranslateableWebpackPluginConfig) {
|
constructor(config: TranslateableWebpackPluginConfig) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.transformerConfig = {
|
this.translations = [];
|
||||||
optimized: true,
|
|
||||||
translations: [],
|
|
||||||
verbose: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createTypeScriptTransformer(program: ts.Program) : ts.TransformerFactory<ts.Node> {
|
createTypeScriptTransformer(program: ts.Program) : ts.TransformerFactory<ts.SourceFile> {
|
||||||
return createTransformer(program, this.transformerConfig);
|
return ctx => sourceFile => {
|
||||||
|
const timestampBegin = Date.now();
|
||||||
|
const result = transform({
|
||||||
|
module: true,
|
||||||
|
useWindow: false,
|
||||||
|
/*
|
||||||
|
* Note: Even though caching might cause less method calls but if the tr method is performant developed
|
||||||
|
* it's faster than having the cache lookup.
|
||||||
|
*/
|
||||||
|
cacheTranslations: false,
|
||||||
|
optimized: true,
|
||||||
|
}, ctx, sourceFile);
|
||||||
|
const timestampEnd = Date.now();
|
||||||
|
|
||||||
|
deltaTranslations(this.translations, sourceFile.fileName, timestampEnd - timestampBegin, result.translations);
|
||||||
|
return result.node;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
createTemplateLoader() {
|
createTemplateLoader() {
|
||||||
return {
|
return {
|
||||||
loader: path.join(__dirname, "JsRendererTranslationLoader.js"),
|
loader: path.join(__dirname, "Loader.js"),
|
||||||
options: {
|
options: {
|
||||||
translations: this.transformerConfig.translations
|
translations: this.translations
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(compiler: webpack.Compiler) {
|
apply(compiler: webpack.Compiler) {
|
||||||
compiler.hooks.emit.tap("TranslateableWebpackPlugin", compilation => {
|
compiler.hooks.emit.tap("TranslateableWebpackPlugin", compilation => {
|
||||||
const payload = JSON.stringify(this.transformerConfig.translations);
|
const payload = JSON.stringify(this.translations);
|
||||||
compilation.assets[this.config.assetName] = {
|
compilation.assets[this.config.assetName] = {
|
||||||
size() { return payload.length; },
|
size() { return payload.length; },
|
||||||
source() { return payload; }
|
source() { return payload; }
|
23
tools/trgen/webpack/Utils.ts
Normal file
23
tools/trgen/webpack/Utils.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import {TranslationEntry} from "./Definitions";
|
||||||
|
|
||||||
|
export const deltaTranslations = (result: TranslationEntry[], fileName: string, processSpeed: number, newTranslations: TranslationEntry[]) => {
|
||||||
|
let deletedTranslations = 0;
|
||||||
|
for(let index = 0; index < result.length; index++) {
|
||||||
|
if(result[index].filename === fileName) {
|
||||||
|
result.splice(index, 1);
|
||||||
|
index--;
|
||||||
|
deletedTranslations++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(...newTranslations);
|
||||||
|
if(deletedTranslations === 0 && newTranslations.length === 0) {
|
||||||
|
console.log("Processed %s (%dms). No translations found.", fileName, processSpeed);
|
||||||
|
} else if(deletedTranslations === 0) {
|
||||||
|
console.log("Processed %s (%dms). Found %d translations", fileName, processSpeed, newTranslations.length);
|
||||||
|
} else if(newTranslations.length === 0) {
|
||||||
|
console.log("Processed %s (%dms). %d translations deleted.", fileName, processSpeed, deletedTranslations);
|
||||||
|
} else {
|
||||||
|
console.log("Processed %s (%dms). Old translation count: %d New translation count: %d", fileName, processSpeed, deletedTranslations, newTranslations.length);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ import { DefinePlugin, Configuration, } from "webpack";
|
||||||
import { Plugin as SvgSpriteGenerator } from "webpack-svg-sprite-generator";
|
import { Plugin as SvgSpriteGenerator } from "webpack-svg-sprite-generator";
|
||||||
import ManifestGenerator from "./webpack/ManifestPlugin";
|
import ManifestGenerator from "./webpack/ManifestPlugin";
|
||||||
import HtmlWebpackInlineSourcePlugin from "./webpack/HtmlWebpackInlineSource";
|
import HtmlWebpackInlineSourcePlugin from "./webpack/HtmlWebpackInlineSource";
|
||||||
import TranslateableWebpackPlugin from "./tools/trgen/WebpackPlugin";
|
import TranslateableWebpackPlugin from "./tools/trgen/webpack/Plugin";
|
||||||
|
|
||||||
import ZipWebpackPlugin from "zip-webpack-plugin";
|
import ZipWebpackPlugin from "zip-webpack-plugin";
|
||||||
import HtmlWebpackPlugin from "html-webpack-plugin";
|
import HtmlWebpackPlugin from "html-webpack-plugin";
|
||||||
|
@ -209,7 +209,7 @@ export const config = async (env: any, target: "web" | "client"): Promise<Config
|
||||||
|
|
||||||
env.package ? new ZipWebpackPlugin({
|
env.package ? new ZipWebpackPlugin({
|
||||||
path: path.join(__dirname, "dist-package"),
|
path: path.join(__dirname, "dist-package"),
|
||||||
filename: `TeaWeb-${isDevelopment ? "development" : "release"}-${localBuildInfo.gitVersion}.zip`,
|
filename: `${target === "web" ? "TeaWeb" : "TeaClient"}-${isDevelopment ? "development" : "release"}-${localBuildInfo.gitVersion}.zip`,
|
||||||
}) : undefined
|
}) : undefined
|
||||||
].filter(e => !!e),
|
].filter(e => !!e),
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ export const config = async (env: any, target: "web" | "client"): Promise<Config
|
||||||
context: __dirname,
|
context: __dirname,
|
||||||
colors: true,
|
colors: true,
|
||||||
getCustomTransformers: program => ({
|
getCustomTransformers: program => ({
|
||||||
before: [translateablePlugin.createTypeScriptTransformer(program)]
|
before: [ translateablePlugin.createTypeScriptTransformer(program) ]
|
||||||
}),
|
}),
|
||||||
transpileOnly: isDevelopment
|
transpileOnly: isDevelopment
|
||||||
}
|
}
|
||||||
|
@ -278,7 +278,7 @@ export const config = async (env: any, target: "web" | "client"): Promise<Config
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.html$/i,
|
test: /\.html$/i,
|
||||||
use: [translateablePlugin.createTemplateLoader()],
|
use: [ translateablePlugin.createTemplateLoader() ],
|
||||||
type: "asset/source",
|
type: "asset/source",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue