-
Notifications
You must be signed in to change notification settings - Fork 3
/
translate_indesign.ts
168 lines (148 loc) · 7.15 KB
/
translate_indesign.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import * as fs from "fs";
import * as path from "path";
import * as AdmZip from "adm-zip";
import * as rmfr from "rmfr";
import { removeForbiddenCharacters, extractStoryMap, getStoriesForSpread, getSpreadIdsInOrder, pageFileNameForSpreadId, TranslationEntry, getIDMLFilePathForName, htmlEntryToTextEntries } from "./shared_functions";
import * as ncp from "ncp";
let inputFolder = "./input";
let outputFolder = "./output";
let translateJSONPath = "./translate_json";
let tempFolder = "./temp";
async function ncpPromise(from: string, to: string): Promise<any> {
return new Promise((resolve, reject) => {
ncp(from, to, (err) => err ? reject(err) : resolve());
});
}
async function translateIDMLFiles() {
try {
await rmfr(tempFolder);
fs.mkdirSync(tempFolder);
console.log("Removed temp directory");
await rmfr(outputFolder);
fs.mkdirSync(outputFolder);
console.log("Removed output directory");
let fileNames = fs.readdirSync(inputFolder);
const idmlDirectoryNames = fileNames.filter((fileName) => fs.statSync(path.join(inputFolder, fileName)).isDirectory());
for (let idmlName of idmlDirectoryNames) {
await ncpPromise(path.join(inputFolder, idmlName), path.join(outputFolder, idmlName));
console.log("Copied input to output folder for ", path.join(inputFolder, idmlName));
translateIDML(idmlName);
}
} catch (ex) {
console.error("Error removing directory", ex);
}
}
translateIDMLFiles().then(() => {
console.log("Done");
})
function translateIDML(idmlName: string) {
// Create temp path for extracted contents of this IDML file
const tempPath = path.join(tempFolder, idmlName);
if (!fs.existsSync(tempPath)) {
fs.mkdirSync(tempPath);
}
// Create output folder for this IDML file
const outputSubPath = path.join(outputFolder, idmlName);
if (!fs.existsSync(outputSubPath)) {
fs.mkdirSync(outputSubPath);
}
let inputFilePath = getIDMLFilePathForName(inputFolder, idmlName);
if (inputFilePath === null) {
console.warn("Could not find IDML file for ", idmlName);
return;
}
let inputZip = new AdmZip(inputFilePath);
let translateJSONSubPath = path.join(translateJSONPath, idmlName);
let languageCodes = fs.readdirSync(translateJSONSubPath).filter((langCode) => langCode !== "en");
for (let langCode of languageCodes) {
const tempPathTranslated = path.join(tempPath, langCode);
if (!fs.existsSync(tempPathTranslated)) {
fs.mkdirSync(tempPathTranslated);
}
// Extract contents of input InDesign into temporary folder
console.log("Extracting English IDML into temp folder for ", langCode);
inputZip.extractAllTo(tempPathTranslated);
// Do actual translation
translateStoriesXML(tempPathTranslated, langCode, idmlName);
// Combine files back into ZIP file for output InDesign Markup file
const outputZip = new AdmZip();
fs.readdirSync(tempPathTranslated).forEach((file) => {
try {
var filePath = path.join(tempPathTranslated, file);
if (fs.statSync(filePath).isDirectory()) {
outputZip.addLocalFolder(filePath, file);
} else {
outputZip.addLocalFile(filePath);
}
} catch (ex) {
console.warn("Error adding file to IDML", ex);
}
});
const outputZipPath = path.join(outputSubPath, langCode + ".idml");
console.log("Writing InDesign Markup File for ", idmlName, "for language code ", langCode);
outputZip.writeZip(outputZipPath);
// rimraf(tempPath, (err) => {});
}
}
function translateStoriesXML(folder: string, langCode: string, idmlName: string) {
const storiesPath = path.join(folder, "Stories");
const spreadsPath = path.join(folder, "Spreads");
const spreadIdsInOrder = getSpreadIdsInOrder(folder);
fs.readdirSync(spreadsPath).forEach((spreadFile) => {
const spreadId = spreadFile.replace("Spread_", "").replace(".xml", "");
const spreadFilePath = path.join(spreadsPath, spreadFile);
const spreadFileContents = fs.readFileSync(spreadFilePath).toString();
const storyIds = getStoriesForSpread(spreadFileContents);
let perStoryTranslateMap: { [storyId: string]: { [en: string]: string } } = {};
let nonStoryTranslateMap: { [en: string]: string } = {};
storyIds.forEach((storyId) => perStoryTranslateMap[storyId] = {});
let pageFileName: string;
let spreadTranslateEntries: TranslationEntry[] = [];
try {
pageFileName = pageFileNameForSpreadId(spreadIdsInOrder, spreadId);
const pageFilePath = path.join(translateJSONPath, idmlName, langCode, pageFileName);
spreadTranslateEntries = JSON.parse(fs.readFileSync(pageFilePath).toString());
for (let entry of spreadTranslateEntries) {
if (entry.type === "html") {
let subEntries = htmlEntryToTextEntries(entry);
for (let subEntry of subEntries) {
if (subEntry.storyId) {
perStoryTranslateMap[subEntry.storyId][subEntry.sourceText] = subEntry.text;
}
nonStoryTranslateMap[subEntry.sourceText] = subEntry.text;
}
} else {
if (entry.storyId) {
perStoryTranslateMap[entry.storyId][entry.sourceText] = entry.text;
}
nonStoryTranslateMap[entry.sourceText] = entry.text;
}
}
} catch (ex) {
console.debug(ex);
if (pageFileName) {
console.log("In InDesign file ", idmlName, " Missing translation file for ", pageFileName, "for language ", langCode);
} else {
console.log("In InDesign file ", idmlName, " Missing translation file for spread id ", spreadId, "for language ", langCode);
}
return;
}
storyIds.forEach((storyId) => {
let storyFile = `Story_${storyId}.xml`;
const storyFileContents = fs.readFileSync(path.join(storiesPath, storyFile)).toString();
let modifiedXML = removeForbiddenCharacters(storyFileContents);
let storyTranslateMap = extractStoryMap(storyFileContents);
Object.keys(storyTranslateMap).forEach((key) => {
if (perStoryTranslateMap[storyId][key]) {
modifiedXML = modifiedXML.replace(key, perStoryTranslateMap[storyId][key]);
} else if (nonStoryTranslateMap[key]) {
console.warn("Translation used but no story id ", key, nonStoryTranslateMap[key])
modifiedXML.replace(key, nonStoryTranslateMap[key]);
} else {
console.warn("In InDesign file ", idmlName, "Missing translation for ", key);
}
})
fs.writeFileSync(path.join(storiesPath, storyFile), modifiedXML, { flag: "w+" });
});
});
}