@crowdin/app-project-module 0.99.0 → 0.100.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/index.js +1 -0
- package/out/modules/file-processing/handlers/translations-alignment.d.ts +5 -0
- package/out/modules/file-processing/handlers/translations-alignment.js +72 -0
- package/out/modules/file-processing/index.d.ts +4 -0
- package/out/modules/file-processing/index.js +16 -1
- package/out/modules/file-processing/types.d.ts +36 -1
- package/out/modules/file-processing/types.js +1 -0
- package/out/modules/manifest.js +11 -0
- package/out/types.d.ts +2 -1
- package/package.json +5 -3
package/out/index.js
CHANGED
|
@@ -210,6 +210,7 @@ function addCrowdinEndpoints(app, clientConfig) {
|
|
|
210
210
|
fileProcessingApps.registerFilePostImport({ config, app });
|
|
211
211
|
fileProcessingApps.registerFilePreExport({ config, app });
|
|
212
212
|
fileProcessingApps.registerFilePostExport({ config, app });
|
|
213
|
+
fileProcessingApps.registerFileTranslationsAlignmentExport({ config, app });
|
|
213
214
|
apiApp.register({ config, app });
|
|
214
215
|
aiProvider.register({ config, app });
|
|
215
216
|
aiPromptProvider.register({ config, app });
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/// <reference types="qs" />
|
|
2
|
+
import { Response } from 'express';
|
|
3
|
+
import { Config, CrowdinClientRequest } from '../../../types';
|
|
4
|
+
import { TranslationsAlignmentLogic } from '../types';
|
|
5
|
+
export default function handle(baseConfig: Config, config: TranslationsAlignmentLogic, folderName: string): (req: CrowdinClientRequest | import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const fs_1 = __importDefault(require("fs"));
|
|
16
|
+
const path_1 = __importDefault(require("path"));
|
|
17
|
+
const util_1 = require("../../../util");
|
|
18
|
+
const files_1 = require("../util/files");
|
|
19
|
+
function handle(baseConfig, config, folderName) {
|
|
20
|
+
const folderPath = config.filesFolder || baseConfig.dbFolder;
|
|
21
|
+
if (!fs_1.default.existsSync(path_1.default.join(folderPath, folderName))) {
|
|
22
|
+
fs_1.default.mkdirSync(path_1.default.join(folderPath, folderName), { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
var _a;
|
|
26
|
+
const response = {};
|
|
27
|
+
const baseFilesUrl = `${baseConfig.baseUrl}/file/download/${folderName}`;
|
|
28
|
+
const body = req.body;
|
|
29
|
+
// Skip assets (e.g., images, videos, or other media files) as they typically don't need to be processed
|
|
30
|
+
if (((_a = body === null || body === void 0 ? void 0 : body.file) === null || _a === void 0 ? void 0 : _a.type) === 'assets' && !('processAssets' in config && config.processAssets)) {
|
|
31
|
+
res.sendStatus(415);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const fileSourceStringsContent = body.sourceStringsUrl
|
|
35
|
+
? (yield (0, files_1.getFileStrings)(body.sourceStringsUrl))
|
|
36
|
+
: body.sourceStrings;
|
|
37
|
+
const fileTranslationsContent = body.translationStringsUrl
|
|
38
|
+
? (yield (0, files_1.getFileStrings)(body.translationStringsUrl))
|
|
39
|
+
: body.translationStrings;
|
|
40
|
+
const fileProcessResult = yield config.fileProcess(body, {
|
|
41
|
+
sourceStrings: fileSourceStringsContent,
|
|
42
|
+
translations: fileTranslationsContent,
|
|
43
|
+
}, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id);
|
|
44
|
+
const { strings, error: processingErrorMessage } = fileProcessResult;
|
|
45
|
+
if (!strings) {
|
|
46
|
+
response.translations = [];
|
|
47
|
+
res.send({
|
|
48
|
+
data: response,
|
|
49
|
+
error: processingErrorMessage ? { message: processingErrorMessage } : undefined,
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const stringsNDJson = strings.map((s) => JSON.stringify(s)).join('\n\r');
|
|
54
|
+
const bufferData = Buffer.from(stringsNDJson, 'utf-8');
|
|
55
|
+
if (Buffer.byteLength(bufferData) < files_1.MAX_BODY_SIZE) {
|
|
56
|
+
response.translations = strings;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
let url;
|
|
60
|
+
if (config.storeFile) {
|
|
61
|
+
url = yield config.storeFile(bufferData);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const storedFile = yield (0, files_1.storeFile)(bufferData, path_1.default.join(folderPath, folderName));
|
|
65
|
+
url = `${baseFilesUrl}?file=${storedFile}`;
|
|
66
|
+
}
|
|
67
|
+
response.translationsUrl = url;
|
|
68
|
+
}
|
|
69
|
+
res.send({ data: response, error: processingErrorMessage ? { message: processingErrorMessage } : undefined });
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
exports.default = handle;
|
|
@@ -3,11 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.registerFilePostExport = exports.registerFilePreExport = exports.registerFilePostImport = exports.registerFilePreImport = exports.registerCustomFileFormat = void 0;
|
|
6
|
+
exports.registerFileTranslationsAlignmentExport = exports.registerFilePostExport = exports.registerFilePreExport = exports.registerFilePostImport = exports.registerFilePreImport = exports.registerCustomFileFormat = void 0;
|
|
7
7
|
const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client"));
|
|
8
8
|
const custom_file_format_1 = __importDefault(require("./handlers/custom-file-format"));
|
|
9
9
|
const file_download_1 = __importDefault(require("./handlers/file-download"));
|
|
10
10
|
const pre_post_process_1 = __importDefault(require("./handlers/pre-post-process"));
|
|
11
|
+
const translations_alignment_1 = __importDefault(require("./handlers/translations-alignment"));
|
|
11
12
|
const types_1 = require("./types");
|
|
12
13
|
const defaults_1 = require("./util/defaults");
|
|
13
14
|
function registerCustomFileFormat({ config, app }) {
|
|
@@ -87,3 +88,17 @@ function registerFilePostExport({ config, app }) {
|
|
|
87
88
|
app.get(`/file/download/${types_1.ProcessFileJobType.POST_EXPORT}`, (0, file_download_1.default)(config, config.filePostExport, types_1.ProcessFileJobType.POST_EXPORT));
|
|
88
89
|
}
|
|
89
90
|
exports.registerFilePostExport = registerFilePostExport;
|
|
91
|
+
function registerFileTranslationsAlignmentExport({ config, app }) {
|
|
92
|
+
if (!config.fileTranslationsAlignmentExport) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
(0, defaults_1.applyFileProcessorsModuleDefaults)(config, config.fileTranslationsAlignmentExport);
|
|
96
|
+
app.post('/translations-alignment', (0, crowdin_client_1.default)({
|
|
97
|
+
config,
|
|
98
|
+
optional: false,
|
|
99
|
+
checkSubscriptionExpiration: true,
|
|
100
|
+
moduleKey: config.fileTranslationsAlignmentExport.key,
|
|
101
|
+
}), (0, translations_alignment_1.default)(config, config.fileTranslationsAlignmentExport, types_1.ProcessFileJobType.TRANSLATIONS_ALIGNMENT));
|
|
102
|
+
app.get(`/file/download/${types_1.ProcessFileJobType.POST_EXPORT}`, (0, file_download_1.default)(config, config.fileTranslationsAlignmentExport, types_1.ProcessFileJobType.TRANSLATIONS_ALIGNMENT));
|
|
103
|
+
}
|
|
104
|
+
exports.registerFileTranslationsAlignmentExport = registerFileTranslationsAlignmentExport;
|
|
@@ -60,9 +60,17 @@ export interface CustomFileFormatLogic extends FileProcessLogic {
|
|
|
60
60
|
}
|
|
61
61
|
export type FileImportExportLogic = FilePreImportLogic | FilePostImportLogic | FilePreExportLogic | FilePostExportLogic;
|
|
62
62
|
export type FileImportExportContent = ProcessFileString[] | Buffer | undefined;
|
|
63
|
+
export type TranslationAlignmentContent = TranslationAlignmentString[] | Buffer | undefined;
|
|
64
|
+
export interface FileTranslationAlignmentContent {
|
|
65
|
+
sourceStrings: TranslationAlignmentContent;
|
|
66
|
+
translations: TranslationAlignmentContent;
|
|
67
|
+
}
|
|
63
68
|
export interface BaseFileProcessLogic<T> {
|
|
64
69
|
fileProcess: (req: ProcessFileRequest, content: FileImportExportContent, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<T>;
|
|
65
70
|
}
|
|
71
|
+
export interface TranslationAlignmentProcessLogin<T> {
|
|
72
|
+
fileProcess: (req: ProcessTranslationAlignmentRequest, content: FileTranslationAlignmentContent, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<T>;
|
|
73
|
+
}
|
|
66
74
|
export interface FilePreImportLogic extends FileProcessLogic, BaseFileProcessLogic<ContentFileResponse> {
|
|
67
75
|
/**
|
|
68
76
|
* Set to `true` to enable asset processing in the application.
|
|
@@ -79,6 +87,19 @@ export interface FilePostExportLogic extends FileProcessLogic, BaseFileProcessLo
|
|
|
79
87
|
*/
|
|
80
88
|
processAssets?: boolean;
|
|
81
89
|
}
|
|
90
|
+
export interface TranslationsAlignmentLogic extends FileProcessLogic, TranslationAlignmentProcessLogin<TranslationAlignmentResponse> {
|
|
91
|
+
}
|
|
92
|
+
export interface ProcessTranslationAlignmentRequest {
|
|
93
|
+
jobType: ProcessFileJobType;
|
|
94
|
+
file: ProcessFileRecord;
|
|
95
|
+
sourceLanguage: LanguagesModel.Language;
|
|
96
|
+
targetLanguages: LanguagesModel.Language[];
|
|
97
|
+
sourceStrings: TranslationAlignmentString[];
|
|
98
|
+
sourceStringsUrl: string;
|
|
99
|
+
translationStrings: TranslationAlignmentString[];
|
|
100
|
+
translationStringsUrl: string;
|
|
101
|
+
getRawContent?: (encoding: BufferEncoding) => Promise<string | Buffer>;
|
|
102
|
+
}
|
|
82
103
|
export interface ProcessFileRequest {
|
|
83
104
|
jobType: ProcessFileJobType;
|
|
84
105
|
file: ProcessFileRecord;
|
|
@@ -102,7 +123,8 @@ export declare enum ProcessFileJobType {
|
|
|
102
123
|
PRE_IMPORT = "pre-import-file",
|
|
103
124
|
POST_IMPORT = "post-import-file",
|
|
104
125
|
PRE_EXPORT = "pre-export-file",
|
|
105
|
-
POST_EXPORT = "post-export-file"
|
|
126
|
+
POST_EXPORT = "post-export-file",
|
|
127
|
+
TRANSLATIONS_ALIGNMENT = "translations-alignment-file"
|
|
106
128
|
}
|
|
107
129
|
export interface ParseFileResponse {
|
|
108
130
|
previewFile?: Buffer;
|
|
@@ -121,6 +143,14 @@ export interface StringsFileResponse extends ParseFileResponse {
|
|
|
121
143
|
export interface ContentFileResponse extends BuildFileResponse {
|
|
122
144
|
notModified?: boolean;
|
|
123
145
|
}
|
|
146
|
+
export interface TranslationAlignmentResponse {
|
|
147
|
+
strings?: TranslationAlignmentResult[];
|
|
148
|
+
error?: string;
|
|
149
|
+
}
|
|
150
|
+
export interface TranslationAlignmentResult {
|
|
151
|
+
sourceStringId: number;
|
|
152
|
+
text: string | SourceStringsModel.PluralText;
|
|
153
|
+
}
|
|
124
154
|
export interface ProcessFileString {
|
|
125
155
|
previewId?: number;
|
|
126
156
|
id: number;
|
|
@@ -135,6 +165,11 @@ export interface ProcessFileString {
|
|
|
135
165
|
translations?: StringTranslations;
|
|
136
166
|
uniqId?: string;
|
|
137
167
|
}
|
|
168
|
+
export interface TranslationAlignmentString {
|
|
169
|
+
id: number | null;
|
|
170
|
+
text: string | SourceStringsModel.PluralText;
|
|
171
|
+
context: string;
|
|
172
|
+
}
|
|
138
173
|
export interface StringTranslations {
|
|
139
174
|
[language: string]: {
|
|
140
175
|
text: string | SourceStringsModel.PluralText;
|
|
@@ -9,4 +9,5 @@ var ProcessFileJobType;
|
|
|
9
9
|
ProcessFileJobType["POST_IMPORT"] = "post-import-file";
|
|
10
10
|
ProcessFileJobType["PRE_EXPORT"] = "pre-export-file";
|
|
11
11
|
ProcessFileJobType["POST_EXPORT"] = "post-export-file";
|
|
12
|
+
ProcessFileJobType["TRANSLATIONS_ALIGNMENT"] = "translations-alignment-file";
|
|
12
13
|
})(ProcessFileJobType = exports.ProcessFileJobType || (exports.ProcessFileJobType = {}));
|
package/out/modules/manifest.js
CHANGED
|
@@ -86,6 +86,17 @@ function handle(config) {
|
|
|
86
86
|
},
|
|
87
87
|
];
|
|
88
88
|
}
|
|
89
|
+
if (config.fileTranslationsAlignmentExport) {
|
|
90
|
+
// prevent possible overrides of the other modules
|
|
91
|
+
config.fileTranslationsAlignmentExport = Object.assign(Object.assign({}, config.fileTranslationsAlignmentExport), { key: config.identifier + '-ftae' });
|
|
92
|
+
modules['file-translations-alignment'] = [
|
|
93
|
+
{
|
|
94
|
+
key: config.fileTranslationsAlignmentExport.key,
|
|
95
|
+
signaturePatterns: config.fileTranslationsAlignmentExport.signaturePatterns,
|
|
96
|
+
url: '/translations-alignment',
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
}
|
|
89
100
|
if (config.customMT) {
|
|
90
101
|
// prevent possible overrides of the other modules
|
|
91
102
|
config.customMT = Object.assign(Object.assign({}, config.customMT), { key: config.identifier + '-mt' });
|
package/out/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { ContextContent } from './modules/context-menu/types';
|
|
|
5
5
|
import { CustomMTLogic } from './modules/custom-mt/types';
|
|
6
6
|
import { CustomSpellcheckerModule } from './modules/custom-spell-check/types';
|
|
7
7
|
import { EditorPanels } from './modules/editor-right-panel/types';
|
|
8
|
-
import { CustomFileFormatLogic, FilePostExportLogic, FilePostImportLogic, FilePreExportLogic, FilePreImportLogic } from './modules/file-processing/types';
|
|
8
|
+
import { CustomFileFormatLogic, FilePostExportLogic, FilePostImportLogic, FilePreExportLogic, FilePreImportLogic, TranslationsAlignmentLogic } from './modules/file-processing/types';
|
|
9
9
|
import { IntegrationLogic } from './modules/integration/types';
|
|
10
10
|
import { Storage } from './storage';
|
|
11
11
|
import { MySQLStorageConfig } from './storage/mysql';
|
|
@@ -203,6 +203,7 @@ export interface ClientConfig extends ImagePath {
|
|
|
203
203
|
filePostImport?: FilePostImportLogic;
|
|
204
204
|
filePreExport?: FilePreExportLogic;
|
|
205
205
|
filePostExport?: FilePostExportLogic;
|
|
206
|
+
fileTranslationsAlignmentExport?: TranslationsAlignmentLogic;
|
|
206
207
|
/**
|
|
207
208
|
* Disable formatting logs
|
|
208
209
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crowdin/app-project-module",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.100.1",
|
|
4
4
|
"description": "Module that generates for you all common endpoints for serving standalone Crowdin App",
|
|
5
5
|
"main": "out/index.js",
|
|
6
6
|
"types": "out/index.d.ts",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"prettier": "prettier --config .prettierrc src/**/*.ts --write",
|
|
14
14
|
"lint-ci": "eslint \"{src,tests}/**/*.{js,ts}\"",
|
|
15
15
|
"test-coverage": "jest --ci --reporters=jest-junit --reporters=default --coverage --coverageReporters=cobertura --coverageReporters=html",
|
|
16
|
-
"test": "jest"
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"postinstall": "patch-package"
|
|
17
18
|
},
|
|
18
19
|
"files": [
|
|
19
20
|
"out/**/*"
|
|
@@ -89,7 +90,8 @@
|
|
|
89
90
|
"rollup": "^3.29.4",
|
|
90
91
|
"rollup-plugin-delete": "^2.1.0",
|
|
91
92
|
"ts-jest": "^29.2.5",
|
|
92
|
-
"typescript": "^4.9.5"
|
|
93
|
+
"typescript": "^4.9.5",
|
|
94
|
+
"patch-package": "^8.0.0"
|
|
93
95
|
},
|
|
94
96
|
"repository": {
|
|
95
97
|
"type": "git",
|