angular-t9n
Version:
A translation tool for Angular i18n
210 lines (197 loc) • 9.25 kB
JavaScript
;
var common = require('@nestjs/common');
var core = require('@nestjs/core');
var platformWs = require('@nestjs/platform-ws');
var fs = require('fs');
var path = require('path');
var server = require('../server');
class AsyncWorkspaceHost {
readFile(path) {
return fs.promises.readFile(path, 'utf8');
}
writeFile(path, data) {
return fs.promises.writeFile(path, data, 'utf8');
}
isDirectory(path) {
return fs.promises
.stat(path)
.then((p) => p.isDirectory())
.catch(() => false);
}
isFile(path) {
return fs.promises
.stat(path)
.then((p) => p.isFile())
.catch(() => false);
}
}
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
function __decorate(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
}
function __metadata(metadataKey, metadataValue) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
let PatternPersistenceStrategy = class PatternPersistenceStrategy extends server.PersistenceStrategy {
constructor(_targetPathBuilder, _serializationStrategy) {
super();
this._targetPathBuilder = _targetPathBuilder;
this._serializationStrategy = _serializationStrategy;
}
async create(target) {
await this._write(target);
console.log(`${server.timestamp()}: Created translation file for ${target.language} at ${this._targetPathBuilder.createPath(target)}`);
}
async update(target) {
await this._write(target);
console.log(`${server.timestamp()}: Updated translation file for ${target.language} at ${this._targetPathBuilder.createPath(target)}`);
}
async _write(target) {
const filePath = this._targetPathBuilder.createPath(target);
await this._serializationStrategy.serializeTarget(target, filePath);
}
};
PatternPersistenceStrategy = __decorate([
common.Injectable(),
__metadata("design:paramtypes", [server.TargetPathBuilder,
server.SerializationStrategy])
], PatternPersistenceStrategy);
function init(name = 't9n.conf.json') {
name = name.endsWith('.json') ? name : `${name}.json`;
const options = {
$schema: 'https://raw.githubusercontent.com/kyubisation/angular-t9n/master/t9n.schema.json',
translationFile: 'messages.xlf',
targetTranslationPath: '',
includeContextInTarget: false,
port: 4300,
};
fs.writeFileSync(path.join(process.cwd(), name), JSON.stringify(options, null, 2), 'utf8');
}
async function runT9nStandalone(configFile) {
const configFilePath = path.resolve(configFile);
let config;
try {
const content = fs.readFileSync(configFilePath, 'utf8');
config = JSON.parse(content);
}
catch (e) {
throw new Error(`Unable to parse file ${configFilePath}`);
}
await t9nStandalone(config);
}
async function t9nStandalone(options, currentWorkingDirectory) {
var _a;
const host = new AsyncWorkspaceHost();
const workspaceRoot = path.resolve(currentWorkingDirectory || process.cwd());
const sourceFile = path.join(workspaceRoot, options.translationFile);
const targetTranslationPath = options.targetTranslationPath || path.dirname(options.translationFile);
const targetDirectory = path.join(workspaceRoot, targetTranslationPath);
if (!(await host.isFile(sourceFile))) {
throw new Error(`${options.translationFile} does not exist or is not a file!`);
}
else if (!(await host.isDirectory(targetDirectory))) {
throw new Error(`targetTranslationPath ${targetTranslationPath} is not a valid directory!`);
}
const xliffVersion = await detectXliffVersion();
console.log(`Detected version ${xliffVersion} of XLIFF`);
const targetPathBuilder = new server.TargetPathBuilder(targetDirectory, sourceFile);
console.log(`Loading translations. Depending on the amount, this might take a moment.`);
const app = await core.NestFactory.create(server.AppModule.forRoot([
{ provide: server.TargetPathBuilder, useValue: targetPathBuilder },
{ provide: server.WorkspaceHost, useValue: host },
{
provide: server.TargetInfo,
useFactory: (source) => new server.TargetInfo('-', options.translationFile, source.language),
inject: [server.TranslationSource],
},
{ provide: server.SerializationOptions, useValue: options },
{
provide: server.TranslationDeserializer,
useExisting: xliffVersion === '1.2' ? server.XlfDeserializer : server.Xlf2Deserializer,
},
{
provide: server.TranslationSerializer,
useExisting: xliffVersion === '1.2' ? server.XlfSerializer : server.Xlf2Serializer,
},
{
provide: server.TranslationSource,
useFactory: TRANSLATION_SOURCE_FACTORY,
inject: [server.SerializationStrategy],
},
{
provide: server.TranslationTargetRegistry,
useFactory: TRANSLATION_TARGET_REGISTRY_FACTORY,
inject: [server.TranslationSource, server.SerializationStrategy, server.PersistenceStrategy],
},
{ provide: server.PersistenceStrategy, useClass: PatternPersistenceStrategy },
]), {
cors: true,
logger: ['error', 'warn'],
});
app.setGlobalPrefix('api');
app.useWebSocketAdapter(new platformWs.WsAdapter(app));
app.useGlobalPipes(new common.ValidationPipe({ skipMissingProperties: true, whitelist: true }));
await app.listen((_a = options.port) !== null && _a !== void 0 ? _a : 4300, () => console.log(`Translation server started: http://localhost:${options.port}\n`));
return new Promise(() => { });
async function detectXliffVersion() {
const content = await host.readFile(sourceFile);
const doc = new server.XmlParser().parse(content);
const version = doc.documentElement.getAttribute('version');
if (doc.documentElement.tagName !== 'xliff') {
throw new Error('Only xliff is supported!');
}
else if (version !== '2.0' && version !== '1.2') {
throw new Error('Unsupported xliff version!');
}
else {
return version;
}
}
async function TRANSLATION_SOURCE_FACTORY(serializationStrategy) {
const result = await serializationStrategy.deserializeSource(sourceFile);
return new server.TranslationSource(result.language, result.unitMap);
}
async function TRANSLATION_TARGET_REGISTRY_FACTORY(source, serializationStrategy, persistenceStrategy) {
const targetRegistry = new server.TranslationTargetRegistry(source, persistenceStrategy);
await Promise.all(fs.readdirSync(targetDirectory, { withFileTypes: true })
.filter((d) => d.isFile())
.map(async (d) => {
const targetPath = path.join(targetDirectory, d.name);
if (sourceFile === targetPath) {
return;
}
try {
const result = await serializationStrategy.deserializeTarget(targetPath);
if (targetPath !== targetPathBuilder.createPath(result.language)) {
return;
}
console.log(`Detected ${path.relative(workspaceRoot, targetPath)}`);
targetRegistry.register(result.language, result.unitMap);
}
catch (_a) { }
}));
return targetRegistry;
}
}
exports.init = init;
exports.runT9nStandalone = runT9nStandalone;
exports.t9nStandalone = t9nStandalone;