Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core(i18n): export rendererFormattedStrings #5713

Merged
merged 3 commits into from
Jul 25, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion lighthouse-core/lib/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,22 @@ function getDefaultLocale() {
return 'en-US';
}

/**
* @param {LH.Locale} locale
* @return {LH.I18NRendererStrings}
*/
function getRendererFormattedStrings(locale) {
const icuMessageIds = Object.keys(LOCALES[locale]).filter(f => f.includes('core/report/html/'));
const strings = {};
for (const icuMessageId of icuMessageIds) {
const [filename, varName] = icuMessageId.split(' | ');
if (!filename.endsWith('util.js')) throw new Error(`Unexpected message: ${icuMessageId}`);
strings[varName] = LOCALES[locale][icuMessageId].message;
}

return strings;
}

/**
* @param {string} filename
* @param {Record<string, string>} fileStrings
Expand Down Expand Up @@ -208,13 +224,14 @@ function replaceIcuMessageInstanceIds(lhr, locale) {

const icuMessagePaths = {};
replaceInObject(lhr, icuMessagePaths);
lhr.i18n = {icuMessagePaths};
return icuMessagePaths;
}

module.exports = {
_formatPathAsString,
UIStrings,
getDefaultLocale,
getRendererFormattedStrings,
createMessageInstanceIdFn,
replaceIcuMessageInstanceIds,
};
36 changes: 36 additions & 0 deletions lighthouse-core/lib/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,41 @@
},
"lighthouse-core/lib/i18n.js | displayValueWastedMs": {
"message": "Potential savings of {wastedMs, number, milliseconds} ms"
},
"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer": {
"message": "Values are estimated and may vary."
},
"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel": {
"message": "Resource to optimize"
},
"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel": {
"message": "Estimated Savings"
},
"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo": {
"message": "Report error: no audit information"
},
"lighthouse-core/report/html/renderer/util.js | errorLabel": {
"message": "Error!"
},
"lighthouse-core/report/html/renderer/util.js | warningHeader": {
"message": "Warnings: "
},
"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip": {
"message": "Show audits"
},
"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle": {
"message": "Passed audits"
},
"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle": {
"message": "Not applicable"
},
"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle": {
"message": "Additional items to manually check"
},
"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage": {
"message": "There were issues affecting this run of Lighthouse:"
},
"lighthouse-core/report/html/renderer/util.js | scorescaleLabel": {
"message": "Score scale:"
}
}
36 changes: 36 additions & 0 deletions lighthouse-core/lib/locales/en-XA.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,41 @@
},
"lighthouse-core/lib/i18n.js | displayValueWastedMs": {
"message": "P̂ót̂én̂t́îál̂ śâv́îńĝś ôf́ {wastedMs, number, milliseconds} m̂ś"
},
"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer": {
"message": "V̂ál̂úêś âŕê éŝt́îḿât́êd́ âńd̂ ḿâý v̂ár̂ý."
},
"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel": {
"message": "R̂éŝóûŕĉé t̂ó ôṕt̂ím̂íẑé"
},
"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel": {
"message": "Êśt̂ím̂át̂éd̂ Śâv́îńĝś"
},
"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo": {
"message": "R̂ép̂ór̂t́ êŕr̂ór̂: ńô áûd́ît́ îńf̂ór̂ḿât́îón̂"
},
"lighthouse-core/report/html/renderer/util.js | errorLabel": {
"message": "Êŕr̂ór̂!"
},
"lighthouse-core/report/html/renderer/util.js | warningHeader": {
"message": "Ŵár̂ńîńĝś: "
},
"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip": {
"message": "Ŝh́ôẃ âúd̂ít̂ś"
},
"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle": {
"message": "P̂áŝśêd́ âúd̂ít̂ś"
},
"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle": {
"message": "N̂ót̂ áp̂ṕl̂íĉáb̂ĺê"
},
"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle": {
"message": "Âd́d̂ít̂íôńâĺ ît́êḿŝ t́ô ḿâńûál̂ĺŷ ćĥéĉḱ"
},
"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage": {
"message": "T̂h́êŕê ẃêŕê íŝśûéŝ áf̂f́êćt̂ín̂ǵ t̂h́îś r̂ún̂ óf̂ Ĺîǵĥt́ĥóûśê:"
},
"lighthouse-core/report/html/renderer/util.js | scorescaleLabel": {
"message": "Ŝćôŕê śĉál̂é:"
}
}
19 changes: 10 additions & 9 deletions lighthouse-core/report/html/renderer/category-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ class CategoryRenderer {
if (audit.result.scoreDisplayMode === 'error') {
auditEl.classList.add(`lh-audit--error`);
const textEl = this.dom.find('.lh-audit__display-text', auditEl);
textEl.textContent = 'Error!';
textEl.textContent = Util.UIStrings.errorLabel;
textEl.classList.add('tooltip-boundary');
const tooltip = this.dom.createChildOf(textEl, 'div', 'tooltip tooltip--error');
tooltip.textContent = audit.result.errorMessage || 'Report error: no audit information';
tooltip.textContent = audit.result.errorMessage || Util.UIStrings.errorMissingAuditInfo;
} else if (audit.result.explanation) {
const explEl = this.dom.createChildOf(titleEl, 'div', 'lh-audit-explanation');
explEl.textContent = audit.result.explanation;
Expand All @@ -89,9 +89,9 @@ class CategoryRenderer {
// Add list of warnings or singular warning
const warningsEl = this.dom.createChildOf(titleEl, 'div', 'lh-warnings');
if (warnings.length === 1) {
warningsEl.textContent = `Warning: ${warnings.join('')}`;
warningsEl.textContent = `${Util.UIStrings.warningHeader} ${warnings.join('')}`;
} else {
warningsEl.textContent = 'Warnings: ';
warningsEl.textContent = Util.UIStrings.warningHeader;
const warningsUl = this.dom.createChildOf(warningsEl, 'ul');
for (const warning of warnings) {
const item = this.dom.createChildOf(warningsUl, 'li');
Expand Down Expand Up @@ -158,7 +158,7 @@ class CategoryRenderer {
const itemCountEl = this.dom.createChildOf(summmaryEl, 'div', 'lh-audit-group__itemcount');
if (expandable) {
const chevronEl = summmaryEl.appendChild(this._createChevron());
chevronEl.title = 'Show audits';
chevronEl.title = Util.UIStrings.auditGroupExpandTooltip;
}

if (group.description) {
Expand All @@ -169,6 +169,7 @@ class CategoryRenderer {
headerEl.textContent = group.title;

if (opts.itemCount) {
// TODO(i18n): support multiple locales here
itemCountEl.textContent = `${opts.itemCount} audits`;
}
return groupEl;
Expand Down Expand Up @@ -211,7 +212,7 @@ class CategoryRenderer {
*/
renderPassedAuditsSection(elements) {
const passedElem = this.renderAuditGroup({
title: `Passed audits`,
title: Util.UIStrings.passedAuditsGroupTitle,
}, {expandable: true, itemCount: this._getTotalAuditsLength(elements)});
passedElem.classList.add('lh-passed-audits');
elements.forEach(elem => passedElem.appendChild(elem));
Expand All @@ -224,7 +225,7 @@ class CategoryRenderer {
*/
_renderNotApplicableAuditsSection(elements) {
const notApplicableElem = this.renderAuditGroup({
title: `Not applicable`,
title: Util.UIStrings.notApplicableAuditsGroupTitle,
}, {expandable: true, itemCount: this._getTotalAuditsLength(elements)});
notApplicableElem.classList.add('lh-audit-group--not-applicable');
elements.forEach(elem => notApplicableElem.appendChild(elem));
Expand All @@ -237,7 +238,7 @@ class CategoryRenderer {
* @return {Element}
*/
_renderManualAudits(manualAudits, manualDescription) {
const group = {title: 'Additional items to manually check', description: manualDescription};
const group = {title: Util.UIStrings.manualAuditsGroupTitle, description: manualDescription};
const auditGroupElem = this.renderAuditGroup(group,
{expandable: true, itemCount: manualAudits.length});
auditGroupElem.classList.add('lh-audit-group--manual');
Expand Down Expand Up @@ -282,7 +283,7 @@ class CategoryRenderer {
percentageEl.textContent = scoreOutOf100.toString();
if (category.score === null) {
percentageEl.textContent = '?';
percentageEl.title = 'Errors occurred while auditing';
percentageEl.title = Util.UIStrings.errorLabel;
}

this.dom.find('.lh-gauge__label', tmpl).textContent = category.title;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
});
const estValuesEl = this.dom.createChildOf(metricsColumn2El, 'div',
'lh-metrics__disclaimer lh-metrics__disclaimer');
estValuesEl.textContent = 'Values are estimated and may vary.';
estValuesEl.textContent = Util.UIStrings.varianceDisclaimer;

metricAuditsEl.classList.add('lh-audit-group--metrics');
element.appendChild(metricAuditsEl);
Expand Down Expand Up @@ -156,6 +156,12 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
const scale = Math.max(Math.ceil(maxWaste / 1000) * 1000, minimumScale);
const groupEl = this.renderAuditGroup(groups['load-opportunities'], {expandable: false});
const tmpl = this.dom.cloneTemplate('#tmpl-lh-opportunity-header', this.templateContext);

this.dom.find('.lh-load-opportunity__col--one', tmpl).textContent =
Util.UIStrings.opportunityResourceColumnLabel;
this.dom.find('.lh-load-opportunity__col--two', tmpl).textContent =
Util.UIStrings.opportunitySavingsColumnLabel;

const headerEl = this.dom.find('.lh-load-opportunity__header', tmpl);
groupEl.appendChild(headerEl);
opportunityAudits.forEach((item, i) =>
Expand Down
26 changes: 26 additions & 0 deletions lighthouse-core/report/html/renderer/report-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ class ReportRenderer {
renderReport(report, container) {
// If any mutations happen to the report within the renderers, we want the original object untouched
const clone = /** @type {LH.ReportResult} */ (JSON.parse(JSON.stringify(report)));
// Mutate the UIStrings if necessary (while saving originals)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the technical debt comment below be moved up here? :)

It does kind of suck to rely on utils as a mutable singleton. We pass at least a DOM into all of our report rendering classes. Should we pass in strings? Or pass the lhr to everything, use lhr.i18n.rendererFormattedStrings.string everywhere, and here (since we're mutating the lhr anyways) could set lhr.i18n.rendererFormattedStrings to the default strings if not set.

Fine to punt to a future PR, but it would be nice to have a plan before we get too deep.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or pass the lhr to everything, use lhr.i18n.rendererFormattedStrings.string everywhere, and here (since we're mutating the lhr anyways) could set lhr.i18n.rendererFormattedStrings to the default strings if not set.

This sounds good to me, we have other LHR reaching needs like locale in config settings and such that would be nice. I accept your offer for a followup :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a TODO?

const clonedStrings = JSON.parse(JSON.stringify(Util.UIStrings));
if (clone.i18n && clone.i18n.rendererFormattedStrings) {
ReportRenderer.updateAllUIStrings(clone.i18n.rendererFormattedStrings);
}

// TODO(phulce): we all agree this is technical debt we should fix
if (typeof clone.categories !== 'object') throw new Error('No categories provided.');
Expand All @@ -43,6 +48,10 @@ class ReportRenderer {

container.textContent = ''; // Remove previous report.
container.appendChild(this._renderReport(clone));

// put the UIStrings back into original state
ReportRenderer.updateAllUIStrings(clonedStrings);

return /** @type {Element} **/ (container);
}

Expand Down Expand Up @@ -126,6 +135,9 @@ class ReportRenderer {
}

const container = this._dom.cloneTemplate('#tmpl-lh-warnings--toplevel', this._templateContext);
const message = this._dom.find('.lh-warnings__msg', container);
message.textContent = Util.UIStrings.toplevelWarningsMessage;

const warnings = this._dom.find('ul', container);
for (const warningString of report.runWarnings) {
const warning = warnings.appendChild(this._dom.createElement('li'));
Expand Down Expand Up @@ -187,6 +199,8 @@ class ReportRenderer {

if (scoreHeader) {
const scoreScale = this._dom.cloneTemplate('#tmpl-lh-scorescale', this._templateContext);
this._dom.find('.lh-scorescale-label', scoreScale).textContent =
Util.UIStrings.scorescaleLabel;
scoresContainer.appendChild(scoreHeader);
scoresContainer.appendChild(scoreScale);
}
Expand All @@ -213,8 +227,20 @@ class ReportRenderer {
});
}
}

/**
* @param {LH.I18NRendererStrings} rendererFormattedStrings
*/
static updateAllUIStrings(rendererFormattedStrings) {
for (const [key, value] of Object.entries(rendererFormattedStrings)) {
Util.UIStrings[key] = value;
}
}
}

/** @type {LH.I18NRendererStrings} */
ReportRenderer._UIStringsStash = {};

if (typeof module !== 'undefined' && module.exports) {
module.exports = ReportRenderer;
} else {
Expand Down
17 changes: 17 additions & 0 deletions lighthouse-core/report/html/renderer/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,23 @@ class Util {
}
}

Util.UIStrings = {
varianceDisclaimer: 'Values are estimated and may vary.',
opportunityResourceColumnLabel: 'Resource to optimize',
opportunitySavingsColumnLabel: 'Estimated Savings',

errorMissingAuditInfo: 'Report error: no audit information',
errorLabel: 'Error!',
warningHeader: 'Warnings: ',
auditGroupExpandTooltip: 'Show audits',
passedAuditsGroupTitle: 'Passed audits',
notApplicableAuditsGroupTitle: 'Not applicable',
manualAuditsGroupTitle: 'Additional items to manually check',

toplevelWarningsMessage: 'There were issues affecting this run of Lighthouse:',
scorescaleLabel: 'Score scale:',
};

if (typeof module !== 'undefined' && module.exports) {
module.exports = Util;
} else {
Expand Down
15 changes: 7 additions & 8 deletions lighthouse-core/report/html/templates.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<!-- Lighthouse run warnings -->
<template id="tmpl-lh-warnings--toplevel">
<div class="lh-warnings lh-warnings--toplevel">
<strong>There were issues affecting this run of Lighthouse:</strong>
<strong class="lh-warnings__msg"></strong>
<ul></ul>
</div>
</template>

<!-- Lighthouse score scale -->
<template id="tmpl-lh-scorescale">
<div class="lh-scorescale">
<span class="lh-scorescale-label">Score scale:</span>
<span class="lh-scorescale-label"></span>
<span class="lh-scorescale-range lh-scorescale-range--fail">0-44</span>
<span class="lh-scorescale-range lh-scorescale-range--average">45-74</span>
<span class="lh-scorescale-range lh-scorescale-range--pass">75-100</span>
Expand Down Expand Up @@ -90,12 +90,8 @@
<!-- Lighthouse perf opportunity header -->
<template id="tmpl-lh-opportunity-header">
<div class="lh-load-opportunity__header lh-load-opportunity__cols">
<div class="lh-load-opportunity__col lh-load-opportunity__col--one">
Resource to optimize
</div>
<div class="lh-load-opportunity__col lh-load-opportunity__col--two">
Estimated Savings
</div>
<div class="lh-load-opportunity__col lh-load-opportunity__col--one"></div>
<div class="lh-load-opportunity__col lh-load-opportunity__col--two"></div>
</div>
</template>

Expand Down Expand Up @@ -394,6 +390,7 @@
<div class="lh-export">
<button class="report-icon report-icon--share lh-export__button" title="Export report"></button>
<div class="lh-export__dropdown">
<!-- TODO(i18n): localize export dropdown -->
<a href="#" class="report-icon report-icon--print" data-action="print-summary">Print Summary</a>
<a href="#" class="report-icon report-icon--print" data-action="print-expanded">Print Expanded</a>
<a href="#" class="report-icon report-icon--copy" data-action="copy">Copy JSON</a>
Expand Down Expand Up @@ -436,6 +433,7 @@
}
</style>
<footer class="lh-footer">
<!-- TODO(i18n): localize runtime settings -->
<div class="lh-env">
<div class="lh-env__title">Runtime settings</div>
<ul class="lh-env__items">
Expand Down Expand Up @@ -605,6 +603,7 @@
}
</style>
<div>
<!-- TODO(i18n): remove CRC sentences or localize -->
Longest chain: <b class="lh-crc__longest_duration"><!-- fill me: longestChain.duration --></b>
over <b class="lh-crc__longest_length"><!-- fill me: longestChain.length --></b> requests, totalling
<b class="lh-crc__longest_transfersize"><!-- fill me: longestChain.length --></b>
Expand Down
5 changes: 4 additions & 1 deletion lighthouse-core/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,10 @@ class Runner {
timing: {total: Date.now() - startTime},
};

i18n.replaceIcuMessageInstanceIds(lhr, settings.locale);
lhr.i18n = {
rendererFormattedStrings: i18n.getRendererFormattedStrings(settings.locale),
icuMessagePaths: i18n.replaceIcuMessageInstanceIds(lhr, settings.locale),
};

const report = generateReport(lhr, settings.output);
return {lhr, artifacts, report};
Expand Down
2 changes: 1 addition & 1 deletion lighthouse-core/scripts/i18n/collect-strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ const ignoredPathComponents = [
'/.git',
'/scripts',
'/node_modules',
'/renderer',
'/test/',
'-test.js',
'-renderer.js',
];

/**
Expand Down
Loading