import assert from 'assert'; import parse from 'format-message-parse'; const flattenJson = (translations) => { let messages = Object.keys(translations).reduce((collection, id) => { collection[id] = translations[id].message; return collection; }, {}); return JSON.stringify(messages, null, 4); }; // filter placeholders out of a message // parse('a message with a {value} and {count, plural, one {one} other {more}}.') // returns an array: // [ 'a message with a ', // [ 'value' ], // ' and ', // [ 'count', 'plural', 0, { one: [Array], other: [Array] } ], // '.' // ] // placeholders are always an array, so filter for array elements to find the placeholders const placeholders = message => ( // this will throw an error if the message is not valid ICU parse(message).filter(item => Array.isArray(item)) ); const validMessage = (message, source) => { const transPlaceholders = placeholders(message); const srcPlaceholders = placeholders(source); // different number of placeholders if (transPlaceholders.length !== srcPlaceholders.length) { return false; } // TODO: Add checking to make sure placeholders in source have not been translated return true; }; const validateTranslations = (translation, source) => { const locale = translation.locale; const translations = translation.translations; const transKeys = Object.keys(translations); const sourceKeys = Object.keys(source); assert.strictEqual(transKeys.length, sourceKeys.length, `locale ${locale} has a different number of message keys`); transKeys.map(item => assert(sourceKeys.includes(item), `locale ${locale} has key ${item} not in the source`)); sourceKeys.map(item => assert(transKeys.includes(item), `locale ${locale} is missing key ${item}`)); sourceKeys.map(item => assert( validMessage(translations[item], source[item]), `locale ${locale}: "${translations[item]}" is not a valid translation for "${source[item]}"`) ); }; export {flattenJson, validateTranslations, validMessage};