blob: e1cc5c53c2494c8f3806487fdeec974ef625266b [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {loadTimeData} from '//resources/js/load_time_data.js';
import type {BrowserProxy} from './browser_proxy.js';
import type {Language} from './translate.mojom-webui.js';
/**
* @fileoverview A browser proxy for fetching language settings.
*/
let instance: LanguageBrowserProxy|null = null;
const LAST_FETCH_SUPPORTED_LANGUAGES_TIME_KEY =
'lastFetchSupportedLanguagesTime';
const LAST_USED_SOURCE_LANGUAGE_KEY = 'lastUsedSourceLanguage';
const LAST_USED_TARGET_LANGUAGE_KEY = 'lastUsedTargetLanguage';
const RECENT_SOURCE_LANGUAGES_KEY = 'recentSourceLangauges';
const RECENT_TARGET_LANGAUGES_KEY = 'recentTargetLanguages';
const SUPPORTED_LANGUAGES_LOCALE_KEY = 'supportedLanguagesLocale';
const SUPPORTED_SOURCE_LANGUAGES_KEY = 'supportedSourceLanguages';
const SUPPORTED_TARGET_LANGUAGES_KEY = 'supportedTargetLanguages';
export interface LanguageBrowserProxy {
getClientLanguageList(): Promise<Language[]>;
getLastUsedSourceLanguage(): string|null;
getLastUsedTargetLanguage(): string|null;
getTranslateTargetLanguage(): Promise<string>;
getRecentSourceLanguages(): string[];
getRecentTargetLanguages(): string[];
getStoredServerLanguages(browserProxy: BrowserProxy):
Promise<{sourceLanguages: Language[], targetLanguages: Language[]}>;
storeLanguages(
locale: string, sourceLanguages: Language[],
targetLanguages: Language[]): void;
storeLastUsedSourceLanguage(sourceLanguageCode: string|null): void;
storeLastUsedTargetLanguage(targetLanguageCode: string|null): void;
storeRecentSourceLanguages(languages: string[]): void;
storeRecentTargetLanguages(languages: string[]): void;
}
export class LanguageBrowserProxyImpl implements LanguageBrowserProxy {
static getInstance(): LanguageBrowserProxy {
return instance || (instance = new LanguageBrowserProxyImpl());
}
static setInstance(obj: LanguageBrowserProxy) {
instance = obj;
}
getClientLanguageList(): Promise<Language[]> {
return chrome.languageSettingsPrivate.getLanguageList().then(
(clientLanguageList: chrome.languageSettingsPrivate.Language[]) => {
return clientLanguageList.map(lang => ({
languageCode: lang.code,
name: lang.displayName,
}));
});
}
getLastUsedSourceLanguage(): string|null {
return window.localStorage.getItem(LAST_USED_SOURCE_LANGUAGE_KEY);
}
getLastUsedTargetLanguage(): string|null {
return window.localStorage.getItem(LAST_USED_TARGET_LANGUAGE_KEY);
}
getTranslateTargetLanguage(): Promise<string> {
return chrome.languageSettingsPrivate.getTranslateTargetLanguage();
}
getRecentSourceLanguages(): string[] {
const sourceLanguagesJSON =
window.localStorage.getItem(RECENT_SOURCE_LANGUAGES_KEY);
if (!sourceLanguagesJSON) {
return [];
}
return JSON.parse(sourceLanguagesJSON) as string[];
}
getRecentTargetLanguages(): string[] {
const targetLanguagesJSON =
window.localStorage.getItem(RECENT_TARGET_LANGAUGES_KEY);
if (!targetLanguagesJSON) {
return [];
}
return JSON.parse(targetLanguagesJSON) as string[];
}
getStoredServerLanguages(browserProxy: BrowserProxy):
Promise<{sourceLanguages: Language[], targetLanguages: Language[]}> {
if (this.shouldFetchSupportedLanguages()) {
return browserProxy.handler.fetchSupportedLanguages().then(
this.onServerLanguageListFetched.bind(this));
}
const sourceLangsJSON =
window.localStorage.getItem(SUPPORTED_SOURCE_LANGUAGES_KEY);
const targetLangsJSON =
window.localStorage.getItem(SUPPORTED_TARGET_LANGUAGES_KEY);
if (!sourceLangsJSON || !targetLangsJSON) {
return Promise.resolve({sourceLanguages: [], targetLanguages: []});
}
const sourceLanguages = JSON.parse(sourceLangsJSON) as Language[];
const targetLanguages = JSON.parse(targetLangsJSON) as Language[];
return Promise.resolve({sourceLanguages, targetLanguages});
}
storeLanguages(
locale: string, sourceLanguages: Language[],
targetLanguages: Language[]): void {
window.localStorage.setItem(SUPPORTED_LANGUAGES_LOCALE_KEY, locale);
window.localStorage.setItem(
SUPPORTED_SOURCE_LANGUAGES_KEY, JSON.stringify(sourceLanguages));
window.localStorage.setItem(
SUPPORTED_TARGET_LANGUAGES_KEY, JSON.stringify(targetLanguages));
window.localStorage.setItem(
LAST_FETCH_SUPPORTED_LANGUAGES_TIME_KEY, Date.now().toString());
}
storeLastUsedSourceLanguage(sourceLanguageCode: string|null) {
// If source language code is null, then it is likely set to 'auto'. We do
// not need to store this value since it is default already.
if (!sourceLanguageCode) {
window.localStorage.removeItem(LAST_USED_SOURCE_LANGUAGE_KEY);
return;
}
window.localStorage.setItem(
LAST_USED_SOURCE_LANGUAGE_KEY, sourceLanguageCode);
}
storeLastUsedTargetLanguage(targetLanguageCode: string|null) {
if (!targetLanguageCode) {
return;
}
window.localStorage.setItem(
LAST_USED_TARGET_LANGUAGE_KEY, targetLanguageCode);
}
storeRecentSourceLanguages(languages: string[]) {
window.localStorage.setItem(
RECENT_SOURCE_LANGUAGES_KEY, JSON.stringify(languages));
}
storeRecentTargetLanguages(languages: string[]) {
window.localStorage.setItem(
RECENT_TARGET_LANGAUGES_KEY, JSON.stringify(languages));
}
private onServerLanguageListFetched(response: {
browserLocale: string,
sourceLanguages: Language[],
targetLanguages: Language[],
}): Promise<{sourceLanguages: Language[], targetLanguages: Language[]}> {
if (response.sourceLanguages.length === 0 ||
response.targetLanguages.length === 0) {
return Promise.resolve({sourceLanguages: [], targetLanguages: []});
}
this.storeLanguages(
response.browserLocale, response.sourceLanguages,
response.targetLanguages);
const sourceLanguages = response.sourceLanguages;
const targetLanguages = response.targetLanguages;
return Promise.resolve({sourceLanguages, targetLanguages});
}
private shouldFetchSupportedLanguages(): boolean {
const languagesCacheTimeout =
loadTimeData.getInteger('languagesCacheTimeout');
const currentTimestamp = Date.now();
const locale = window.localStorage.getItem(SUPPORTED_LANGUAGES_LOCALE_KEY);
if (locale && !locale.startsWith(loadTimeData.getString('language'))) {
return true;
}
// If there is no stored timestamp, we should fetch supported languages.
const storedTimestampString =
window.localStorage.getItem(LAST_FETCH_SUPPORTED_LANGUAGES_TIME_KEY);
if (!storedTimestampString) {
return true;
}
// If the stored timestamp is stored incorrectly, we need to fetch supported
// languages.
const storedTimestamp = parseInt(storedTimestampString);
if (isNaN(storedTimestamp)) {
return true;
}
// If the languages are not stored at all, we should also fetch supported
// languages.
const sourceLanguages =
window.localStorage.getItem(SUPPORTED_SOURCE_LANGUAGES_KEY);
const targetLanguages =
window.localStorage.getItem(SUPPORTED_TARGET_LANGUAGES_KEY);
if (!sourceLanguages || !targetLanguages) {
return true;
}
// Finally, if the cache is to have expired, we should fetch supported
// languages.
const difference = currentTimestamp - storedTimestamp;
return (difference / languagesCacheTimeout) >= 1;
}
}