Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@doodle/i18n / dist / src / onesky / translations.js
Size: Mime:
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,
};