Repository URL to install this package:
|
Version:
4.2.0 ▾
|
const deepmerge = require('deepmerge');
const { extractDefaultMessages } = require('./extract');
const { getProjectMessagesByLanguage, getProjectLanguages, uploadProjectTranslation } = require('./api');
const { flatten, unflatten } = require('./transform');
const { readJsonFile, writeJsonFile } = require('./utils');
const { getAddedKeys, getChangedKeys, getRenamedKeys, getDeletedKeys, updateMessages } = require('./diff');
/**
* Manage translations for OneSky
*
* @module @doodle/i18n/disty/onesky/translations
*/
/**
* Download translations from a OneSky project for all defined languages in the project
*
* @param {string} projectId
* @param {OneSkyCredentials} credentials
* @returns {Promise<object>}
* @async
*/
const getProjectTranslations = async (projectId, credentials) => {
const projectLanguages = await getProjectLanguages(projectId, credentials);
const languageCodes = projectLanguages.map(({ code }) => code);
const projectMessages = await Promise.all(
languageCodes.map(language => getProjectMessagesByLanguage({ projectId, language }, credentials))
);
return projectMessages.reduce((result, messages, index) => {
result[languageCodes[index]] = unflatten(messages);
return result;
}, {});
};
/**
* Download translations from multiple OneSky projects for all defined languages
* in the respective projects and combine the message translations
*
* @param {string[]} projectIds
* @param {OneSkyCredentials} credentials
* @returns {Promise<object>}
* @async
*/
const getMergedProjectTranslations = async (projectIds, credentials) => {
const errors = {};
const projectsTranslations = await Promise.all(
projectIds.map(projectId =>
getProjectTranslations(projectId, credentials).catch(error => {
errors[projectId] = error;
})
)
);
if (Object.keys(errors).length) {
throw new Error(JSON.stringify(errors));
}
return deepmerge.all(projectsTranslations);
};
/**
* Download all translations from multiple OneSky projects and write them to JSON files by language
*
* @param {string[]} projectIds
* @param {string} targetPath
* @param {OneSkyCredentials} credentials
* @returns {Promise<object>}
* @async
*/
const downloadMergedTranslationFiles = async (projectIds, targetPath, credentials) => {
const combinedTranslations = await getMergedProjectTranslations(projectIds, credentials);
await Promise.all(
Object.keys(combinedTranslations).map(language =>
writeJsonFile(`${targetPath}/${language}.json`, combinedTranslations[language])
)
);
return combinedTranslations;
};
/**
* Update a translation file containing hierarchical messages with changes from source messages
*
* @param {string} file
* @param {object} sourceMessages
* @param {bool} includeValues
* @returns {Promise}
* @async
*/
const updateTranslationFile = async (file, sourceMessages, includeValues = false) => {
const translation = await readJsonFile(file);
const messages = flatten(translation);
const addedKeys = includeValues ? getAddedKeys(sourceMessages, messages) : [];
const changedKeys = includeValues ? getChangedKeys(sourceMessages, messages) : [];
const renamed = getRenamedKeys(sourceMessages, messages);
const deleted = getDeletedKeys(sourceMessages, messages);
const sourceMessageEntries = Object.entries(sourceMessages);
const updatedMessages = updateMessages(messages, {
added: sourceMessageEntries.filter(([k]) => addedKeys.indexOf(k) >= 0),
changed: sourceMessageEntries.filter(([k]) => changedKeys.indexOf(k) >= 0),
renamed,
deleted,
});
await writeJsonFile(file, unflatten(updatedMessages));
};
/**
* Update local translation files with changes from the source for all languages defined by the OneSky project
*
* @param {string} projectId
* @param {OneSkyCredentials} credentials
* @param {string} sourcePattern
* @param {string} targetPath
* @param {string} includeValues
* @returns {Promise}
* @async
*/
const updateTranslationFiles = async (projectId, credentials, sourcePattern, targetPath, includeValues = false) => {
const projectLanguages = await getProjectLanguages(projectId, credentials);
const languageCodes = projectLanguages.map(({ code }) => code);
const baseLanguage = projectLanguages.filter(({ is_base_language: isBaseLanguage }) => isBaseLanguage)[0].code;
const sourceMessages = await extractDefaultMessages(`${sourcePattern}`);
const errors = {};
await Promise.all(
languageCodes.map(language =>
updateTranslationFile(
`${targetPath}/${language}.json`,
sourceMessages,
includeValues ? true : language === baseLanguage
).catch(error => {
errors[language] = error;
})
)
);
if (Object.keys(errors).length) {
console.error(errors);
}
};
/**
* Upload translation files for all languages of the project, not only the base language!
*
* @param {string} path path to folder containing the hierarchical `${language}.json` translation files
* @param {OneSkyTranslationOptions} translationOptions
* @param {OneSkyCredentials} credentials
* @param {OneSkySyncOptions} syncOptions
* @returns {Promise}
* @async
*/
const uploadTranslationFiles = async (path, { projectId, fileName }, credentials, { keepStrings, format } = {}) => {
const projectLanguages = await getProjectLanguages(projectId, credentials);
const languageCodes = projectLanguages.map(({ code }) => code);
const doUpload = async language => {
const translations = await readJsonFile(`${path}/${language}.json`);
await uploadProjectTranslation({ language, projectId, fileName }, flatten(translations), credentials, {
keepStrings,
format,
});
};
await Promise.all(languageCodes.map(doUpload));
};
module.exports = {
getProjectTranslations,
getMergedProjectTranslations,
updateTranslationFile,
updateTranslationFiles,
downloadMergedTranslationFiles,
uploadTranslationFiles,
};