mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-24 21:37:21 +00:00

* Version bump to 20180510.1 * Fix hass util * Fix translations * Bye paper-time-input * Add webpack config * Add webpack to package.json * Fix translation import * Disable web animations polyfill bad import * Disable importHref import * Update webpack config to build authorize.js * Build translations json * Build frontend correctly * Run eslint --fix * Load markdown JS on demand (#1155) * Add HTML imports (#1160) * Fix localize (#1161) * Fix Roboto in build (#1162) * Load web animations polyfill (#1163) * P3: Fix chart js (#1164) * P3: Fix Chart JS * Update timeline package * P3: panel resolver (#1165) * WIP * Initial importing of panels * Fix panel resolver * Fix automation and script editor (#1166) * Expose Polymer and Polymer.Element on window (#1167) * Remove unused import * eslint --fix * Es5 build (#1168) * Build for ES5 * Fix build_frontend * Remove stale comment * Migrate to use paper-material-styles (#1170) * Send parsed date to history/logbook (#1171) * Fork app storage behavior (#1172) * Add paper input with type time (#1173) * Fix authorize * Lint * Sort imports * Lint * Remove eslint-html * Do not lint authorize.html * Fix polymer lint * Try chrome 62 for wct * P3: Add patched iconset (#1175) * Add patched iconset * Lint * Test with latest Chrome again * Use less window.hassUtil * Teporarily use my fecha fork * Import correct intl.messageFormat * Update wct-browser-legacy to 1.0.0 * Include polyfill in right place * Fix IntlMessageFormat * Fix test not having a global scope * Rollup <_< * Fork app-localize-behavior * Disable wct tests * Lint
257 lines
8.0 KiB
JavaScript
Executable File
257 lines
8.0 KiB
JavaScript
Executable File
const path = require('path');
|
|
const gulp = require('gulp');
|
|
const foreach = require('gulp-foreach');
|
|
const hash = require('gulp-hash');
|
|
const insert = require('gulp-insert');
|
|
const merge = require('gulp-merge-json');
|
|
const minify = require('gulp-jsonminify');
|
|
const rename = require('gulp-rename');
|
|
const transform = require('gulp-json-transform');
|
|
|
|
const inDir = 'translations';
|
|
const workDir = 'build-translations';
|
|
const fullDir = workDir + '/full';
|
|
const coreDir = workDir + '/core';
|
|
const outDir = workDir + '/output';
|
|
|
|
// Panel translations which should be split from the core translations. These
|
|
// should mirror the fragment definitions in polymer.json, so that we load
|
|
// additional resources at equivalent points.
|
|
const TRANSLATION_FRAGMENTS = [
|
|
'config',
|
|
'history',
|
|
'logbook',
|
|
'mailbox',
|
|
'shopping-list',
|
|
];
|
|
|
|
const tasks = [];
|
|
|
|
function recursiveFlatten(prefix, data) {
|
|
let output = {};
|
|
Object.keys(data).forEach(function (key) {
|
|
if (typeof (data[key]) === 'object') {
|
|
output = Object.assign({}, output, recursiveFlatten(prefix + key + '.', data[key]));
|
|
} else {
|
|
output[prefix + key] = data[key];
|
|
}
|
|
});
|
|
return output;
|
|
}
|
|
|
|
function flatten(data) {
|
|
return recursiveFlatten('', data);
|
|
}
|
|
|
|
function emptyFilter(data) {
|
|
const newData = {};
|
|
Object.keys(data).forEach((key) => {
|
|
if (data[key]) {
|
|
if (typeof (data[key]) === 'object') {
|
|
newData[key] = emptyFilter(data[key]);
|
|
} else {
|
|
newData[key] = data[key];
|
|
}
|
|
}
|
|
});
|
|
return newData;
|
|
}
|
|
|
|
/**
|
|
* Replace Lokalise key placeholders with their actual values.
|
|
*
|
|
* We duplicate the behavior of Lokalise here so that placeholders can
|
|
* be included in src/translations/en.json, but still be usable while
|
|
* developing locally.
|
|
*
|
|
* @link https://docs.lokalise.co/article/KO5SZWLLsy-key-referencing
|
|
*/
|
|
const re_key_reference = /\[%key:([^%]+)%\]/;
|
|
function lokalise_transform (data, original) {
|
|
const output = {};
|
|
Object.entries(data).forEach(([key, value]) => {
|
|
if (value instanceof Object) {
|
|
output[key] = lokalise_transform(value, original);
|
|
} else {
|
|
output[key] = value.replace(re_key_reference, (match, key) => {
|
|
const replace = key.split('::').reduce((tr, k) => tr[k], original);
|
|
if (typeof replace !== 'string') {
|
|
throw Error(`Invalid key placeholder ${key} in src/translations/en.json`);
|
|
}
|
|
return replace;
|
|
});
|
|
}
|
|
});
|
|
return output;
|
|
}
|
|
|
|
/**
|
|
* This task will build a master translation file, to be used as the base for
|
|
* all languages. This starts with src/translations/en.json, and replaces all
|
|
* Lokalise key placeholders with their target values. Under normal circumstances,
|
|
* this will be the same as translations/en.json However, we build it here to
|
|
* facilitate both making changes in development mode, and to ensure that the
|
|
* project is buildable immediately after merging new translation keys, since
|
|
* the Lokalise update to translations/en.json will not happen immediately.
|
|
*/
|
|
let taskName = 'build-master-translation';
|
|
gulp.task(taskName, function () {
|
|
return gulp.src('src/translations/en.json')
|
|
.pipe(transform(function(data, file) {
|
|
return lokalise_transform(data, data);
|
|
}))
|
|
.pipe(rename('translationMaster.json'))
|
|
.pipe(gulp.dest(workDir));
|
|
});
|
|
tasks.push(taskName);
|
|
|
|
taskName = 'build-merged-translations';
|
|
gulp.task(taskName, ['build-master-translation'], function () {
|
|
return gulp.src(inDir + '/*.json')
|
|
.pipe(foreach(function(stream, file) {
|
|
// For each language generate a merged json file. It begins with the master
|
|
// translation as a failsafe for untranslated strings, and merges all parent
|
|
// tags into one file for each specific subtag
|
|
//
|
|
// TODO: This is a naive interpretation of BCP47 that should be improved.
|
|
// Will be OK for now as long as we don't have anything more complicated
|
|
// than a base translation + region.
|
|
const tr = path.basename(file.history[0], '.json');
|
|
const subtags = tr.split('-');
|
|
const src = [workDir + '/translationMaster.json'];
|
|
for (let i = 1; i <= subtags.length; i++) {
|
|
const lang = subtags.slice(0, i).join('-');
|
|
src.push(inDir + '/' + lang + '.json');
|
|
}
|
|
return gulp.src(src)
|
|
.pipe(transform(data => emptyFilter(data)))
|
|
.pipe(merge({
|
|
fileName: tr + '.json',
|
|
}))
|
|
.pipe(gulp.dest(fullDir));
|
|
}));
|
|
});
|
|
tasks.push(taskName);
|
|
|
|
const splitTasks = [];
|
|
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
|
taskName = 'build-translation-fragment-' + fragment;
|
|
gulp.task(taskName, ['build-merged-translations'], function () {
|
|
// Return only the translations for this fragment.
|
|
return gulp.src(fullDir + '/*.json')
|
|
.pipe(transform(data => ({
|
|
ui: {
|
|
panel: {
|
|
[fragment]: data.ui.panel[fragment],
|
|
},
|
|
},
|
|
})))
|
|
.pipe(gulp.dest(workDir + '/' + fragment));
|
|
});
|
|
tasks.push(taskName);
|
|
splitTasks.push(taskName);
|
|
});
|
|
|
|
taskName = 'build-translation-core';
|
|
gulp.task(taskName, ['build-merged-translations'], function () {
|
|
// Remove the fragment translations from the core translation.
|
|
return gulp.src(fullDir + '/*.json')
|
|
.pipe(transform((data) => {
|
|
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
|
delete data.ui.panel[fragment];
|
|
});
|
|
return data;
|
|
}))
|
|
.pipe(gulp.dest(coreDir));
|
|
});
|
|
tasks.push(taskName);
|
|
splitTasks.push(taskName);
|
|
|
|
taskName = 'build-flattened-translations';
|
|
gulp.task(taskName, splitTasks, function () {
|
|
// Flatten the split versions of our translations, and move them into outDir
|
|
return gulp.src(
|
|
TRANSLATION_FRAGMENTS.map(fragment => workDir + '/' + fragment + '/*.json')
|
|
.concat(coreDir + '/*.json'),
|
|
{ base: workDir },
|
|
)
|
|
.pipe(transform(function (data) {
|
|
// Polymer.AppLocalizeBehavior requires flattened json
|
|
return flatten(data);
|
|
}))
|
|
.pipe(minify())
|
|
.pipe(rename((filePath) => {
|
|
if (filePath.dirname === 'core') {
|
|
filePath.dirname = '';
|
|
}
|
|
}))
|
|
.pipe(gulp.dest(outDir));
|
|
});
|
|
tasks.push(taskName);
|
|
|
|
taskName = 'build-translation-fingerprints';
|
|
gulp.task(taskName, ['build-flattened-translations'], function () {
|
|
return gulp.src(outDir + '/**/*.json')
|
|
.pipe(rename({
|
|
extname: '',
|
|
}))
|
|
.pipe(hash({
|
|
algorithm: 'md5',
|
|
hashLength: 32,
|
|
template: '<%= name %>-<%= hash %>.json',
|
|
}))
|
|
.pipe(hash.manifest('translationFingerprints.json'))
|
|
.pipe(transform(function (data) {
|
|
// After generating fingerprints of our translation files, consolidate
|
|
// all translation fragment fingerprints under the translation name key
|
|
const newData = {};
|
|
Object.entries(data).forEach(([key, value]) => {
|
|
const parts = key.split('/');
|
|
let translation = key;
|
|
if (parts.length === 2) {
|
|
translation = parts[1];
|
|
}
|
|
if (!(translation in newData)) {
|
|
newData[translation] = {
|
|
fingerprints: {},
|
|
};
|
|
}
|
|
newData[translation].fingerprints[key] = value;
|
|
});
|
|
return newData;
|
|
}))
|
|
.pipe(gulp.dest(workDir));
|
|
});
|
|
tasks.push(taskName);
|
|
|
|
taskName = 'build-translations';
|
|
gulp.task(taskName, ['build-translation-fingerprints'], function () {
|
|
return gulp.src([
|
|
'src/translations/translationMetadata.json',
|
|
workDir + '/translationFingerprints.json',
|
|
])
|
|
.pipe(merge({}))
|
|
.pipe(transform(function (data) {
|
|
const newData = {};
|
|
Object.entries(data).forEach(([key, value]) => {
|
|
// Filter out translations without native name.
|
|
if (data[key].nativeName) {
|
|
newData[key] = data[key];
|
|
} else {
|
|
console.warn(`Skipping language ${key}. Native name was not translated.`);
|
|
}
|
|
if (data[key]) newData[key] = value;
|
|
});
|
|
return newData;
|
|
}))
|
|
.pipe(transform(data => ({
|
|
fragments: TRANSLATION_FRAGMENTS,
|
|
translations: data,
|
|
})))
|
|
.pipe(rename('translationMetadata.json'))
|
|
.pipe(gulp.dest(workDir));
|
|
});
|
|
tasks.push(taskName);
|
|
|
|
module.exports = tasks;
|