UNPKG

crowdfree

Version:

A crowdin compatible tool for translation and localisation of websites and applications

170 lines (153 loc) 5.72 kB
#!/usr/bin/env node /* Module for easily localising projects using a web interface and integrated webserver */ const express = require("express") const cors = require("cors") const fs = require("fs") const path = require("path") const { getTranslations } = require("./main") const { saveLocale, findLocaleFolder } = require("./localeTools") const findSuggestions = require("./findSuggestions") ; (async () => { // Parse CLI arguments const node_path = process.argv.shift() const index_location = process.argv.shift() const working_directory = process.argv.shift() || "." // Get locale from disk const localeFolder = await findLocaleFolder("./", working_directory) const { translations, locales } = await getTranslations(localeFolder, updatesCallback) let updatesToTransmit = [] function addToUpdatesToTransmit(transl) { // Remove old versions of the same updatesToTransmit = updatesToTransmit.filter(x => x.file !== transl.file && x.file !== transl.file) // Push new version updatesToTransmit.push(transl) } // Handle translations getting updated on disk during runtime async function updatesCallback(updates) { console.log("Updated translations: ", updates) // Repopulate suggestions await findSuggestions.translate(updates, locales) // Add to updates array with timestamp for clients to fetch updates.forEach(update => addToUpdatesToTransmit({ ...update, timestamp: Date.now(), }) ) } // Find suggested translations in the background findSuggestions.translate(translations, locales) // Start express API server const app = express() // Serve frontend app.use(express.static(path.join(__dirname, "../frontend/build"))) let port = process.argv.shift() || 3300 app.listen(port) console.log(`Listening to port ${port} (1st argument for project path, 2nd argument to specify a port)`) app.use(express.json()) app.use(cors()) // API endpoints // Get all translations app.get("/api/translations", (req, res) => { res.send({ ok: true, data: translations }) }) // Get translations that are missing strings only (to save on data for larger projects) app.get("/api/translations/todo", (req, res) => { res.send({ ok: true, data: translations.filter(x => x.value.length < locales.length) }) }) // Get translations that have been modified since [timestamp] app.get("/api/translations/since/:since", (req, res) => { // Remove old updates as clients should already have gotten them updatesToTransmit = updatesToTransmit.filter(x => x.timestamp > Date.now() - 5 * 60 * 1000) let time = Number(req.params.since) if (!time) { res.send({ ok: false, msg: "Invalid timestamp" }) } else { res.send({ ok: true, msg: `Sending translations that have been updated since ${time}`, data: updatesToTransmit.filter(x => x.timestamp > time) }) } }) app.get("/api/translation/:file/:key", (req, res) => { res.send({ ok: true, data: translations.find(x => x.file === req.params.file && x.key === req.params.key) }) }) app.post("/api/translations/update", async (req, res) => { // Update a record and send update to peers /* req.body { data: [{ file: "locale.json", key: "headertext", locale: "en", props: { value: "New english text" } }] } */ // TODO: Input validation // Update let data = [] let errors = [] req.body.data.forEach(update => { let oldRecord = translations.find(x => x.file === update.file && x.key === update.key) if (!oldRecord) { let error = new Error(`Could not find record ${update.file} ${update.key}`) console.log(error) return errors.push(error) } oldRecord.value[update.locale] = { ...oldRecord.value[update.locale], ...update.props, } oldRecord.timestamp = Date.now() // Return modified object to client data.push(oldRecord) // Prepare for return to all clients addToUpdatesToTransmit(oldRecord) }) // Clean up data with empty value fields // data.map(x => { // for (let loc in x.value) { // if (!x.value[loc].value) { // delete x.value[loc] // } // } // return x // }) // Write updated locale to file await saveLocale(translations, localeFolder) // Repopulate suggestions await findSuggestions.translate(data, locales) // Replace in-memory translations with updated ones res.send({ ok: true, msg: "Updated translation", data, error: errors, }) }) app.get("/api/locales", (req, res) => { res.send({ ok: true, data: locales }) }) })()