Add scripts to convert ftl to/from Transifex JSON (#3058)

This commit is contained in:
Tom Najdek 2023-04-03 13:04:32 +02:00 committed by Dan Stillman
parent d5a584c28b
commit afaf0b4968
6 changed files with 178 additions and 5 deletions

View file

@ -55,8 +55,7 @@ file-interface-items-were-relinked = { $numRelinked ->
*[other] { $numRelinked } items were relinked
}
import-mendeley-encrypted = The selected Mendeley database cannot be read, likely because it is encrypted.
See <a data-l10n-name="mendeley-import-kb">How do I import a Mendeley library into Zotero?</a> for more information.
import-mendeley-encrypted = The selected Mendeley database cannot be read, likely because it is encrypted. See <a data-l10n-name="mendeley-import-kb">How do I import a Mendeley library into Zotero?</a> for more information.
file-interface-import-error-translator = An error occurred importing the selected file with “{ $translator }”. Please ensure that the file is valid and try again.

38
js-build/ftl-to-json.mjs Normal file
View file

@ -0,0 +1,38 @@
import { ftlToJSON } from "ftl-tx";
import fs from 'fs-extra';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { onError, onSuccess } from './utils.js';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const JSONDir = join(ROOT, 'tmp', 'tx');
async function getJSON() {
const t1 = performance.now();
await fs.mkdirp(JSONDir);
const sourcefile = join(ROOT, 'chrome', 'locale', 'en-US', 'zotero', 'zotero.ftl');
const destFile = join(JSONDir, 'zotero_en_US.json');
const ftl = await fs.readFile(sourcefile, 'utf8');
const json = ftlToJSON(ftl, { transformTerms: false, storeTermsInJSON: false });
await fs.outputJSON(destFile, json);
const t2 = performance.now();
return ({
action: 'ftl->json',
count: 1,
totalCount: 1,
processingTime: t2 - t1
});
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
(async () => {
try {
onSuccess(await getJSON());
}
catch (err) {
process.exitCode = 1;
global.isError = true;
onError(err);
}
})();
}

98
js-build/localize-ftl.mjs Normal file
View file

@ -0,0 +1,98 @@
import { extractTerms, ftlToJSON, JSONToFtl } from 'ftl-tx';
import fs from 'fs-extra';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { onError, onProgress, onSuccess } from './utils.js';
import { exit } from 'process';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const JSONDir = join(ROOT, 'tmp', 'tx');
const localesDir = join(ROOT, 'chrome', 'locale');
const sourceDir = join(localesDir, 'en-US', 'zotero');
const termsSourceFTLPath = join(ROOT, 'app', 'assets', 'branding', 'locale', 'brand.ftl');
const fallbackJSONPath = join(sourceDir, 'zotero.json');
// don't override source zotero.ftl
const localeToSkip = ['en-US'];
async function getFTL() {
const t1 = performance.now();
if (!(await fs.pathExists(fallbackJSONPath))) {
console.error(`File ${fallbackJSONPath} does not exist, please run 'ftl-to-json' first`);
exit(1);
}
if (!(await fs.pathExists(termsSourceFTLPath))) {
console.error(`Required file ${termsSourceFTLPath} does not exist`);
exit(1);
}
const fallbackJSON = await fs.readJSON(fallbackJSONPath);
const terms = extractTerms(await fs.readFile(termsSourceFTLPath, 'utf-8'));
const expectedLocale = (await fs.readdir(localeDir, { withFileTypes: true }))
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);
const totalCount = expectedLocale.length;
let locale;
let count = 0;
while ((locale = expectedLocale.pop())) {
if (localeToSkip.includes(locale)) {
count++;
continue;
}
const ftlFilePath = join(ROOT, 'chrome', 'locale', locale, 'zotero', 'zotero.ftl');
let JSONFromLocalFTL = {};
try {
const ftl = await fs.readFile(ftlFilePath, 'utf8');
JSONFromLocalFTL = ftlToJSON(ftl, { transformTerms: false, storeTermsInJSON: false });
}
catch (e) {
// no local .ftl file
}
const JSONFilePath = join(JSONDir, `zotero_${locale.replace('-', '_')}.json`);
let JSONFromTransifex = {};
try {
const json = await fs.readJSON(JSONFilePath);
JSONFromTransifex = json;
}
catch (e) {
// no .json file from transifex
}
const mergedJSON = { ...fallbackJSON, ...JSONFromLocalFTL, ...JSONFromTransifex };
const ftl = JSONToFtl(mergedJSON, { addTermsToFTL: false, storeTermsInJSON: false, transformTerms: false, terms });
const outFtlPath = join(ROOT, 'chrome', 'locale', locale, 'zotero', 'zotero.ftl');
await fs.outputFile(outFtlPath, ftl);
onProgress(outFtlPath, outFtlPath, 'ftl');
count++;
}
const t2 = performance.now();
return ({
action: 'ftl',
count,
totalCount,
processingTime: t2 - t1
});
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
(async () => {
try {
onSuccess(await getFTL());
}
catch (err) {
process.exitCode = 1;
global.isError = true;
onError(err);
}
})();
}

View file

@ -21,7 +21,7 @@ function onSuccess(result) {
msg += ` | ${result.totalCount} checked`;
}
msg += ` [${yellow(`${result.processingTime}ms`)}]`;
msg += ` [${yellow(`${result.processingTime.toFixed(2)}ms`)}]`;
console.log(msg);
}

39
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "zotero",
"version": "5.0.0",
"version": "7.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "zotero",
"version": "5.0.0",
"version": "7.0.0",
"dependencies": {
"@citeproc-rs/wasm": "^0.2.0",
"ace-builds": "^1.4.12",
@ -40,6 +40,7 @@
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.0.4",
"fs-extra": "^3.0.1",
"ftl-tx": "^0.6.0",
"globby": "^6.1.0",
"jspath": "^0.4.0",
"mocha": "^3.5.3",
@ -919,6 +920,16 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/@fluent/syntax": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/@fluent/syntax/-/syntax-0.19.0.tgz",
"integrity": "sha512-5D2qVpZrgpjtqU4eNOcWGp1gnUCgjfM+vKGE2y03kKN6z5EBhtx0qdRFbg8QuNNj8wXNoX93KJoYb+NqoxswmQ==",
"dev": true,
"engines": {
"node": ">=14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/@formatjs/intl-displaynames": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-1.2.10.tgz",
@ -3561,6 +3572,15 @@
"node": ">= 4.0"
}
},
"node_modules/ftl-tx": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/ftl-tx/-/ftl-tx-0.6.0.tgz",
"integrity": "sha512-w7s0p6RNsaUKpiuQZ5Q0KIyiX2JIDItqI4qRKt49u0aMqdGp0gDc5G5Qnubgu6l2ww5PDt4wsyL7A1iZo1VGMQ==",
"dev": true,
"dependencies": {
"@fluent/syntax": "^0.19.0"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@ -7533,6 +7553,12 @@
}
}
},
"@fluent/syntax": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/@fluent/syntax/-/syntax-0.19.0.tgz",
"integrity": "sha512-5D2qVpZrgpjtqU4eNOcWGp1gnUCgjfM+vKGE2y03kKN6z5EBhtx0qdRFbg8QuNNj8wXNoX93KJoYb+NqoxswmQ==",
"dev": true
},
"@formatjs/intl-displaynames": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-1.2.10.tgz",
@ -9769,6 +9795,15 @@
"nan": "^2.12.1"
}
},
"ftl-tx": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/ftl-tx/-/ftl-tx-0.6.0.tgz",
"integrity": "sha512-w7s0p6RNsaUKpiuQZ5Q0KIyiX2JIDItqI4qRKt49u0aMqdGp0gDc5G5Qnubgu6l2ww5PDt4wsyL7A1iZo1VGMQ==",
"dev": true,
"requires": {
"@fluent/syntax": "^0.19.0"
}
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",

View file

@ -10,6 +10,8 @@
"sass": "node ./js-build/sass.js",
"js": "node ./js-build/js.js",
"clean": "node ./js-build/clean.js",
"ftl-to-json": "node ./js-build/ftl-to-json.mjs",
"localize-ftl": "node ./js-build/localize-ftl.mjs",
"clean-build": "node ./js-build/clean.js && node ./js-build/build.js",
"clean-start": "node ./js-build/clean.js && node ./js-build/build.js && node ./js-build/watch.js"
},
@ -47,6 +49,7 @@
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.0.4",
"fs-extra": "^3.0.1",
"ftl-tx": "^0.6.0",
"globby": "^6.1.0",
"jspath": "^0.4.0",
"mocha": "^3.5.3",