@crowdin/app-project-module 0.16.2 → 0.16.4

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/README.md CHANGED
@@ -173,9 +173,6 @@ const configuration = {
173
173
  crowdinModule.createApp(configuration);
174
174
  ```
175
175
 
176
-
177
-
178
-
179
176
  ## Payment
180
177
 
181
178
  By default App does not have any subscription and it's free to use. But you can override this.
@@ -519,6 +516,38 @@ const configuration = {
519
516
  crowdinModule.createApp(configuration);
520
517
  ```
521
518
 
519
+ Also custom file format module can support strings export.
520
+
521
+ ```javascript
522
+ const crowdinModule = require('@crowdin/app-project-module');
523
+ const convert = require('xml-js');
524
+
525
+ const configuration = {
526
+ baseUrl: 'https://123.ngrok.io',
527
+ clientId: 'clientId',
528
+ clientSecret: 'clientSecret',
529
+ name: 'Sample App',
530
+ identifier: 'sample-app',
531
+ description: 'Sample App description',
532
+ dbFolder: __dirname,
533
+ imagePath: __dirname + '/' + 'logo.png',
534
+ customFileFormat: {
535
+ type: 'type-xyz',
536
+ stringsExport: true,
537
+ extensions: [
538
+ '.resx'
539
+ ],
540
+ exportStrings: async (req, strings, client, context, projectId) => {
541
+ const file = req.file;
542
+ //export logic
543
+ return { contentFile: '' }
544
+ }
545
+ }
546
+ };
547
+
548
+ crowdinModule.createApp(configuration);
549
+ ```
550
+
522
551
  ### Custom MT
523
552
 
524
553
  Example of [custom mt module](https://support.crowdin.com/crowdin-apps-modules/#custom-mt-machine-translation-module).
@@ -29,7 +29,7 @@ function storeFile(fileContent, folder) {
29
29
  }
30
30
  }));
31
31
  }
32
- function handleBuildFile(baseUrl, dataFolder, config, file, req, client, context, projectId) {
32
+ function handleBuildFile(baseUrl, dataFolder, config, req, client, context, projectId, file) {
33
33
  return __awaiter(this, void 0, void 0, function* () {
34
34
  const response = {};
35
35
  if (!req.strings && !req.stringsUrl) {
@@ -42,7 +42,16 @@ function handleBuildFile(baseUrl, dataFolder, config, file, req, client, context
42
42
  else {
43
43
  strings = (yield axios_1.default.get(req.stringsUrl)).data;
44
44
  }
45
- const res = yield config.buildFile(file, req, strings, client, context, projectId);
45
+ let res;
46
+ if ((req.file.id || !file) && config.exportStrings) {
47
+ res = yield config.exportStrings(req, strings, client, context, projectId);
48
+ }
49
+ else if (file && config.buildFile) {
50
+ res = yield config.buildFile(file, req, strings, client, context, projectId);
51
+ }
52
+ else {
53
+ return response;
54
+ }
46
55
  const contentFileEncoded = Buffer.from(res.contentFile).toString('base64');
47
56
  if (Buffer.byteLength(contentFileEncoded, 'utf8') < MAX_BODY_SIZE) {
48
57
  response.content = contentFileEncoded;
@@ -54,9 +63,12 @@ function handleBuildFile(baseUrl, dataFolder, config, file, req, client, context
54
63
  return response;
55
64
  });
56
65
  }
57
- function handleParseFile(baseUrl, dataFolder, config, file, req, client, context, projectId) {
66
+ function handleParseFile(baseUrl, dataFolder, config, req, client, context, projectId, file) {
58
67
  return __awaiter(this, void 0, void 0, function* () {
59
68
  const response = {};
69
+ if (!config.parseFile || !file) {
70
+ return response;
71
+ }
60
72
  const res = yield config.parseFile(file, req, client, context, projectId);
61
73
  if (res.previewFile) {
62
74
  const previewFileEncoded = Buffer.from(res.previewFile).toString('base64');
@@ -103,16 +115,16 @@ function handle(baseConfig, baseUrl, folder, config) {
103
115
  if (body.file.content) {
104
116
  file = Buffer.from(body.file.content, 'base64').toString();
105
117
  }
106
- else {
107
- file = (yield axios_1.default.get(body.file.contentUrl || '')).data;
118
+ else if (body.file.contentUrl) {
119
+ file = (yield axios_1.default.get(body.file.contentUrl)).data;
108
120
  }
109
121
  let response = {};
110
122
  switch (body.jobType) {
111
123
  case models_1.ProcessFileJobType.BUILD_FILE:
112
- response = yield handleBuildFile(baseFilesUrl, folder, config, file, body, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id);
124
+ response = yield handleBuildFile(baseFilesUrl, folder, config, body, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id, file);
113
125
  break;
114
126
  case models_1.ProcessFileJobType.PARSE_FILE:
115
- response = yield handleParseFile(baseFilesUrl, folder, config, file, body, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id);
127
+ response = yield handleParseFile(baseFilesUrl, folder, config, body, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id, file);
116
128
  break;
117
129
  }
118
130
  (0, util_1.log)(`Returning response from process file action ${JSON.stringify(response, null, 2)}`, baseConfig.logger);
@@ -19,6 +19,9 @@ function handle(config) {
19
19
  {
20
20
  key: config.identifier + '-ff',
21
21
  type: config.customFileFormat.type,
22
+ stringsExport: !!config.customFileFormat.stringsExport,
23
+ multilingual: !!config.customFileFormat.multilingual,
24
+ extensions: config.customFileFormat.extensions,
22
25
  signaturePatterns: config.customFileFormat.signaturePatterns,
23
26
  url: '/process',
24
27
  },
@@ -390,14 +390,26 @@ export interface CustomFileFormatLogic {
390
390
  * Flag to automatically upload translations
391
391
  */
392
392
  autoUploadTranslations?: boolean;
393
+ /**
394
+ * Enable strings export
395
+ */
396
+ stringsExport?: boolean;
397
+ /**
398
+ * File extensions (used for strings export)
399
+ */
400
+ extensions?: string[];
393
401
  /**
394
402
  * Used for initial source file upload, source file update, and translation upload
395
403
  */
396
- parseFile: (fileContent: string | object, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<ParseFileResponse>;
404
+ parseFile?: (fileContent: string | object, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<ParseFileResponse>;
397
405
  /**
398
406
  * Used for translation download
399
407
  */
400
- buildFile: (fileContent: string | object, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, strings: ProcessFileString[], client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
408
+ buildFile?: (fileContent: string | object, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, strings: ProcessFileString[], client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
409
+ /**
410
+ * Used for strings export
411
+ */
412
+ exportStrings?: (req: Omit<ProcessFileRequest, 'jobType'>, strings: ProcessFileString[], client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
401
413
  }
402
414
  export interface SignaturePatterns {
403
415
  fileName?: string;
@@ -414,6 +426,9 @@ export interface ProcessFileRequest {
414
426
  export interface ProcessFileRecord {
415
427
  content?: string;
416
428
  contentUrl?: string;
429
+ path?: string;
430
+ id?: number;
431
+ name?: string;
417
432
  }
418
433
  export declare enum ProcessFileJobType {
419
434
  PARSE_FILE = "parse-file",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.16.2",
3
+ "version": "0.16.4",
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",