Skip to content

Commit

Permalink
clients(extension): add locale selector (#15574)
Browse files Browse the repository at this point in the history
  • Loading branch information
connorjclark authored Oct 28, 2023
1 parent b07f647 commit 53746cc
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 6 deletions.
5 changes: 5 additions & 0 deletions build/build-extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ const packagePath = `${distDir}/../extension-${browserBrand}-package`;
const manifestVersion = readJson(`${sourceDir}/manifest.json`).version;

async function buildEntryPoint() {
const locales = fs.readdirSync(`${LH_ROOT}/shared/localization/locales`)
.filter(f => !f.includes('.ctc.json'))
.map(f => f.replace('.json', ''))
.filter(locale => !['en-XA', 'en-XL', 'ar-XB'].includes(locale));
await esbuild.build({
entryPoints: [`${sourceDir}/scripts/${sourceName}`],
outfile: `${distDir}/scripts/${distName}`,
Expand All @@ -38,6 +42,7 @@ async function buildEntryPoint() {
plugins.bulkLoader([
plugins.partialLoaders.replaceText({
'___BROWSER_BRAND___': browserBrand,
'__LOCALES__': JSON.stringify(locales),
}),
]),
],
Expand Down
7 changes: 7 additions & 0 deletions clients/extension/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ <h3 class="options__title">Categories</h3>
<!-- filled dynamically -->
</ul>
</div>

<div class="options__group options__group--locales">
<h3 class="options__title">Locale</h3>
<select class="options__select options__locales">
<!-- filled dynamically -->
</select>
</div>
</form>
</div>
</main>
Expand Down
75 changes: 75 additions & 0 deletions clients/extension/scripts/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import * as SettingsController from './settings-controller.js';
// Replaced with 'chrome' or 'firefox' in the build script.
/** @type {string} */
const BROWSER_BRAND = '___BROWSER_BRAND___';
/** @type {string[]} */
const LOCALES = JSON.parse('__LOCALES__');

const CHROME_STRINGS = {
localhostErrorMessage: 'Use DevTools to audit pages on localhost.',
Expand Down Expand Up @@ -100,13 +102,15 @@ function onGenerateReportButtonClick(backend, url, settings) {
for (const category of settings.selectedCategories) {
apiUrl.searchParams.append('category', category);
}
apiUrl.searchParams.append('hl', settings.locale);
} else {
apiUrl = new URL('https://googlechrome.github.io/lighthouse/viewer/');
apiUrl.searchParams.append('psiurl', url);
apiUrl.searchParams.append('strategy', settings.device);
for (const category of settings.selectedCategories) {
apiUrl.searchParams.append('category', category);
}
apiUrl.searchParams.append('locale', settings.locale);
}
apiUrl.searchParams.append('utm_source', 'lh-chrome-ext');
window.open(apiUrl.href);
Expand Down Expand Up @@ -146,6 +150,74 @@ function generateBackendOptionsList(settings) {
optionsCategoriesList.append(frag);
}

/**
* From third_party/devtools-frontend/src/front_end/core/i18n/i18nImpl.ts
*
* Returns a string of the form:
* "German (Austria) - Deutsch (Österreich)"
* where the former locale representation is written in the currently enabled DevTools
* locale and the latter locale representation is written in the locale of `localeString`.
*
* Should the two locales match (i.e. have the same language) then the latter locale
* representation is written in English.
*
* @param {string} localeString
* @param {string} currentLocale
* @return {string}
*/
function getLocalizedLanguageRegion(localeString, currentLocale) {
const locale = new Intl.Locale(localeString);
const localLanguage = locale.language || 'en';
const localBaseName = locale.baseName || 'en-US';
const devtoolsLoc = new Intl.Locale(currentLocale);
const targetLanguage = localLanguage === devtoolsLoc.language ? 'en' : localBaseName;
const languageInCurrentLocale =
new Intl.DisplayNames([currentLocale], {type: 'language'}).of(localLanguage);
const languageInTargetLocale =
new Intl.DisplayNames([targetLanguage], {type: 'language'}).of(localLanguage);

let wrappedRegionInCurrentLocale = '';
let wrappedRegionInTargetLocale = '';

if (locale.region) {
const regionInCurrentLocale =
new Intl.DisplayNames([currentLocale], {type: 'region', style: 'short'}).of(locale.region);
const regionInTargetLocale =
new Intl.DisplayNames([targetLanguage], {type: 'region', style: 'short'}).of(locale.region);
wrappedRegionInCurrentLocale = ` (${regionInCurrentLocale})`;
wrappedRegionInTargetLocale = ` (${regionInTargetLocale})`;
}

const lhs = languageInCurrentLocale + wrappedRegionInCurrentLocale;
const rhs = languageInTargetLocale + wrappedRegionInTargetLocale;
if (lhs === rhs) {
return lhs;
}

return `${lhs} - ${rhs}`;
}

/**
* Generates a document fragment containing a list of locale options.
* @param {SettingsController.Settings} settings
*/
function generateLocaleOptionsList(settings) {
const frag = document.createDocumentFragment();

LOCALES.forEach(locale => {
const optionEl = document.createElement('option');
optionEl.textContent = getLocalizedLanguageRegion(locale, navigator.language);
optionEl.value = locale;
if (settings.locale === locale) {
optionEl.selected = true;
}
frag.append(optionEl);
});

const optionsLocalesList = find('.options__locales');
optionsLocalesList.append(frag);
}

/**
* @param {SettingsController.Settings} settings
*/
Expand All @@ -168,12 +240,14 @@ function readSettingsFromDomAndPersist() {
const optionsEl = find('.section--options');
// Save settings when options page is closed.
const backend = find('.options__backend input:checked').value;
const locale = find('select.options__locales').value;
const checkboxes = optionsEl.querySelectorAll('.options__categories input:checked');
const selectedCategories = Array.from(checkboxes).map(input => input.value);
const device = find('input[name="device"]:checked').value;

const settings = {
backend,
locale,
selectedCategories,
device,
};
Expand Down Expand Up @@ -238,6 +312,7 @@ async function initPopup() {
// Generate checkboxes from saved settings.
generateBackendOptionsList(settings);
generateCategoryOptionsList(settings);
generateLocaleOptionsList(settings);
configureVisibleSettings(settings);
const selectedDeviceEl = find(`.options__device input[value="${settings.device}"]`);
selectedDeviceEl.checked = true;
Expand Down
5 changes: 4 additions & 1 deletion clients/extension/scripts/settings-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const DEFAULT_CATEGORIES = [{
title: 'PWA',
}];

/** @typedef {{backend: string, selectedCategories: string[], device: string}} Settings */
/** @typedef {{backend: string, selectedCategories: string[], device: string, locale: string}} Settings */

const STORAGE_KEYS = {
Categories: 'lighthouse_audits',
Expand Down Expand Up @@ -61,6 +61,8 @@ function saveSettings(settings) {
// Stash backend setting.
storage[STORAGE_KEYS.Settings].backend = settings.backend;

storage[STORAGE_KEYS.Settings].locale = settings.locale;

// Save object to chrome local storage.
chrome.storage.local.set(storage);
}
Expand Down Expand Up @@ -94,6 +96,7 @@ function loadSettings() {
resolve({
backend: savedSettings.backend ?? 'psi',
device: savedSettings.device,
locale: savedSettings.locale ?? navigator.language,
selectedCategories: Object.keys(savedCategories).filter(cat => savedCategories[cat]),
});
});
Expand Down
11 changes: 9 additions & 2 deletions clients/extension/styles/lighthouse.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
html, body {
padding: 0;
margin: 0;
width: 350px;
width: 450px;
background-color: var(--color-bg);
color: #212121;
font-family: var(--report-font-family);
Expand Down Expand Up @@ -105,6 +105,9 @@ main {
padding-bottom: 10px;
}

.options__group {
width: 50%;
}
.options__group:first-child {
width: 100%;
}
Expand Down Expand Up @@ -158,8 +161,12 @@ main {
margin-right: 8px;
}

.options__list {
.options__list, .options__select {
padding: 0;
margin: 0;
list-style-type: none;
}

.options__group--locales {
width: 100%;
}
5 changes: 2 additions & 3 deletions viewer/app/src/viewer-ui-features.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ export class ViewerUIFeatures extends ReportUIFeatures {
saveGistItem.setAttribute('disabled', 'true');
}

this._getI18nModule().then(async (i18nModule) => {
const locales = /** @type {LH.Locale[]} */ (
await i18nModule.format.getCanonicalLocales());
this._getI18nModule().then(i18nModule => {
const locales = /** @type {LH.Locale[]} */ (i18nModule.format.getCanonicalLocales());
this._swapLocales.enable(locales);
}).catch(err => console.error(err));
}
Expand Down

0 comments on commit 53746cc

Please sign in to comment.