UNPKG

crowdfree

Version:

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

154 lines (142 loc) 6.57 kB
/* Locales look like this: { locale: "en", files: [{ name: "locale.json", content: { name: "Crowdfree", description: "Simple localisations without all the fuss" } }] } A translation should look like this: { file: "locale.json", key: "headertext", value: { en: { value: "English header text", }, no: { value: "Norwegian header text", }, es: { value: false, // This one isn't translated yet, but is expected due to finding the locale folder suggestions: [{ type: "google_translate", value: "Habla es espanol?" },{ type: "similar_source_translation", value: "'en' value is similar to the 'en' value for another string in the project" }] } } } */ // const fs = require("fs-extra") const fs = require("fs").promises const path = require("path") const { saveLocale, findLocaleFolder } = require("./localeTools") const sortTranslations = require("./../frontend/src/util/sortTranslations") async function getTranslations(localeFolder, updatesCallback) { // Load locale from files const locales = await Promise.all((await fs.readdir(localeFolder)) .map(async folderName => { let localePath = path.join(localeFolder, folderName) let files = (await fs.readdir(localePath)) .map(async file => { // Handle changes in files after first start (after function exit) if (updatesCallback) { let watcher = fs.watch(path.join(localePath, file)); (async () => { let waitingForRead = false try { for await (const event of watcher) { if (!waitingForRead) { // console.log(event) waitingForRead = true; setTimeout(async () => { let newFile = { name: file, content: JSON.parse(await fs.readFile(path.join(localePath, file))) } waitingForRead = false // Update locale with file locales.find(x => x.locale === folderName) .files.find(x => x.name === file) .content = newFile.content let oldTranslations = JSON.parse(JSON.stringify(translations)) // Update translaitons populateTranslations(translations, locales) sortTranslations(translations) // Inform callee about updated translations let updated = translations.filter(translation => oldTranslations .find(x => x.file === translation.file && x.key === translation.key && Object.keys(x.value).find(y => // Value changed x.value[y].value != translation.value[y]?.value // Either new or old value has to be a string for there to be a change && (typeof x.value[y].value === "string" || typeof translation.value[y]?.value === "string") ) ) ) updatesCallback?.(updated) }, 1000) } } } catch (e) { console.error(e) } })() } // Return file contents (at function call) return { name: file, content: JSON.parse(await fs.readFile(path.join(localePath, file))) } }) return { locale: folderName, files: await Promise.all(files), } })); // console.log(JSON.stringify(locales, null, 2)) const translations = [] populateTranslations(translations, locales) translations.forEach(x => x.timestamp = Date.now()) sortTranslations(translations) return { translations, locales } } function populateTranslations(translations, locales) { while (translations.length) translations.shift() locales.forEach(locale => { locale.files.forEach(file => { for (let key in file.content) { let find = translations.find(translation => translation.key === key) if (find) { // Extend existing translation find.value[locale.locale] = { value: file.content[key] } } else { // Add new translation translations.push({ file: file.name, key, value: { [locale.locale]: { value: file.content[key] } } }) } } }) }) } module.exports = { getTranslations, }