Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
28 changes: 14 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 32 additions & 13 deletions src/background/LanguageDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import {
SUPPORTED_LANGUAGES,
SUPPORTED_LANGUAGES_SHORT_CODE,
resolveEnabledPredictionLanguages,
} from "../shared/lang";
import { SettingsManager } from "../shared/settingsManager";

Expand All @@ -11,41 +12,59 @@ export class LanguageDetector {
this.settings = settings;
}

async detectLanguage(text: string, tabId: number): Promise<string> {
const fallbackLanguage = (await this.settings.get(
async detectLanguage(
text: string,
tabId: number,
enabledLanguages?: string[],
): Promise<string> {
const fallbackLanguageRaw = (await this.settings.get(
"fallbackLanguage",
)) as string;
const allowedLanguages =
resolveEnabledPredictionLanguages(enabledLanguages);
const fallbackLanguage =
fallbackLanguageRaw && fallbackLanguageRaw !== "auto_detect"
? fallbackLanguageRaw
: allowedLanguages[0];
const allowedSet = new Set(allowedLanguages);
const globalAny = globalThis as { browser?: typeof chrome };
const api =
typeof globalAny.browser === "undefined" ? chrome : globalAny.browser;
const result = await api.i18n.detectLanguage(text);
let detectedLanguage: string | null = null;
let maxPercentage = -1;
for (const language of result.languages) {
let resolvedLanguage: string | null = null;
if (language.language in SUPPORTED_LANGUAGES) {
resolvedLanguage = language.language;
} else if (language.language in SUPPORTED_LANGUAGES_SHORT_CODE) {
resolvedLanguage = SUPPORTED_LANGUAGES_SHORT_CODE[language.language];
}
if (
language.language in SUPPORTED_LANGUAGES &&
resolvedLanguage &&
allowedSet.has(resolvedLanguage) &&
language.percentage > maxPercentage
) {
detectedLanguage = language.language;
maxPercentage = language.percentage;
} else if (
language.language in SUPPORTED_LANGUAGES_SHORT_CODE &&
language.percentage > maxPercentage
) {
detectedLanguage = SUPPORTED_LANGUAGES_SHORT_CODE[language.language];
detectedLanguage = resolvedLanguage;
maxPercentage = language.percentage;
}
}
if (detectedLanguage) {
return detectedLanguage;
}
const pageLang = await api.tabs.detectLanguage(tabId);
if (pageLang in SUPPORTED_LANGUAGES) {
if (pageLang in SUPPORTED_LANGUAGES && allowedSet.has(pageLang)) {
return pageLang;
}
if (pageLang in SUPPORTED_LANGUAGES_SHORT_CODE) {
if (
pageLang in SUPPORTED_LANGUAGES_SHORT_CODE &&
allowedSet.has(SUPPORTED_LANGUAGES_SHORT_CODE[pageLang])
) {
return SUPPORTED_LANGUAGES_SHORT_CODE[pageLang];
}
return fallbackLanguage;
if (allowedSet.has(fallbackLanguage)) {
return fallbackLanguage;
}
return allowedLanguages[0];
}
}
102 changes: 77 additions & 25 deletions src/background/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
KEY_AUTOCOMPLETE_ON_ENTER,
KEY_AUTOCOMPLETE,
KEY_LANGUAGE,
KEY_ENABLED_LANGUAGES,
KEY_ENABLED,
KEY_NUM_SUGGESTIONS,
KEY_INSERT_SPACE_AFTER_AUTOCOMPLETE,
Expand All @@ -30,7 +31,7 @@ import {
} from "../shared/constants";
import { getDomain, isEnabledForDomain, checkLastError } from "../shared/utils";
import { logError } from "../shared/error";
import { SUPPORTED_LANGUAGES } from "../shared/lang";
import { resolveEnabledLanguages } from "../shared/lang";
import { SettingsManager } from "../shared/settingsManager";
import { LanguageDetector } from "./LanguageDetector";
import { PresageConfig } from "./PresageHandler";
Expand Down Expand Up @@ -111,16 +112,24 @@ export class BackgroundServiceWorker {
});
}

async detectLanguage(text: string, tabId: number): Promise<string> {
return await this.languageDetector.detectLanguage(text, tabId);
async detectLanguage(
text: string,
tabId: number,
enabledLanguages?: string[],
): Promise<string> {
return await this.languageDetector.detectLanguage(
text,
tabId,
enabledLanguages,
);
}

sendCommandToActiveTabContentScript(message: Message) {
this.tabMessenger.sendToActiveTab(message);
}

async getBackgroundPageSetConfigMsg(): Promise<ConfigMessage> {
this.language = (await this.settingsManager.get(KEY_LANGUAGE)) as string;
this.language = await resolveActiveLanguage(this.settingsManager);
const [
enabled,
autocomplete,
Expand Down Expand Up @@ -206,7 +215,7 @@ export class BackgroundServiceWorker {

async updatePresageConfig() {
await this.predictionManager.initialize();
this.language = (await this.settingsManager.get(KEY_LANGUAGE)) as string;
this.language = await resolveActiveLanguage(this.settingsManager);
const [
numSuggestions,
minWordLengthToPredict,
Expand Down Expand Up @@ -250,6 +259,34 @@ export class BackgroundServiceWorker {
}
}

async function getEnabledLanguages(
settingsManager: SettingsManager,
): Promise<string[]> {
const enabledLanguages = await settingsManager.get(KEY_ENABLED_LANGUAGES);
return resolveEnabledLanguages(enabledLanguages);
}

async function resolveActiveLanguage(
settingsManager: SettingsManager,
): Promise<string> {
const [language, enabledLanguagesRaw] = await Promise.all([
settingsManager.get(KEY_LANGUAGE),
settingsManager.get(KEY_ENABLED_LANGUAGES),
]);
const enabledLanguages = resolveEnabledLanguages(enabledLanguagesRaw);
const currentLanguage = typeof language === "string" ? language : "";
const allowAutoDetect = enabledLanguages.length > 1;
if (currentLanguage === "auto_detect" && allowAutoDetect) {
return currentLanguage;
}
if (enabledLanguages.includes(currentLanguage)) {
return currentLanguage;
}
const fallbackLanguage = enabledLanguages[0];
await settingsManager.set(KEY_LANGUAGE, fallbackLanguage);
return fallbackLanguage;
}

function onInstalled(details: chrome.runtime.InstalledDetails) {
checkLastError();
if (details.reason === "install") {
Expand Down Expand Up @@ -286,23 +323,34 @@ function onCommand(command: string) {
break;
}
case CMD_TOGGLE_FT_ACTIVE_LANG: {
const availableLangs = [...Object.keys(SUPPORTED_LANGUAGES)];
const currentLangIndex = availableLangs.indexOf(
backgroundServiceWorker.language,
);
const nextLangIndex = (currentLangIndex + 1) % availableLangs.length;
const nextLang = availableLangs[nextLangIndex];
backgroundServiceWorker.settingsManager.set("language", nextLang);
backgroundServiceWorker.language = nextLang;
const updateLangConfigMessage: UpdateLangConfigMessage = {
command: CMD_BACKGROUND_PAGE_UPDATE_LANG_CONFIG,
context: {
lang: nextLang,
},
};
backgroundServiceWorker.sendCommandToActiveTabContentScript(
updateLangConfigMessage,
);
(async () => {
const availableLangs = await getEnabledLanguages(
backgroundServiceWorker.settingsManager,
);
const currentLanguage = await resolveActiveLanguage(
backgroundServiceWorker.settingsManager,
);
backgroundServiceWorker.language = currentLanguage;
const currentLangIndex = availableLangs.indexOf(currentLanguage);
const nextLangIndex =
(currentLangIndex >= 0 ? currentLangIndex + 1 : 0) %
availableLangs.length;
const nextLang = availableLangs[nextLangIndex];
await backgroundServiceWorker.settingsManager.set(
KEY_LANGUAGE,
nextLang,
);
backgroundServiceWorker.language = nextLang;
const updateLangConfigMessage: UpdateLangConfigMessage = {
command: CMD_BACKGROUND_PAGE_UPDATE_LANG_CONFIG,
context: {
lang: nextLang,
},
};
backgroundServiceWorker.sendCommandToActiveTabContentScript(
updateLangConfigMessage,
);
})().catch((error) => logError("onCommand", error));
break;
}
default:
Expand All @@ -318,14 +366,18 @@ async function handleContentScriptPredictReq(
backgroundServiceWorker: BackgroundServiceWorker,
) {
try {
let language = (await backgroundServiceWorker.settingsManager.get(
KEY_LANGUAGE,
)) as string;
let language = await resolveActiveLanguage(
backgroundServiceWorker.settingsManager,
);
backgroundServiceWorker.language = language;
if (language === "auto_detect") {
const enabledLanguages = await getEnabledLanguages(
backgroundServiceWorker.settingsManager,
);
language = await backgroundServiceWorker.detectLanguage(
request.context.text!,
sender.tab!.id!,
enabledLanguages,
);
}
if (request.context.lang !== language) {
Expand Down
42 changes: 36 additions & 6 deletions src/popup/popup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import {
blockUnBlockDomain,
} from "../shared/utils";
import { SettingsManager } from "../shared/settingsManager";
import { SUPPORTED_LANGUAGES } from "../shared/lang";
import { SUPPORTED_LANGUAGES, resolveEnabledLanguages } from "../shared/lang";
import {
CMD_POPUP_PAGE_ENABLE,
CMD_POPUP_PAGE_DISABLE,
CMD_OPTIONS_PAGE_CONFIG_CHANGE,
KEY_ENABLED_LANGUAGES,
KEY_LANGUAGE,
} from "../shared/constants";
import {
OptionsPageConfigChangeMessage,
Expand Down Expand Up @@ -49,17 +51,44 @@ function init() {
}
checkboxEnableNode.checked = Boolean(await settings.get("enable"));
}
const language = (await settings.get("language")) as string;
let language = (await settings.get(KEY_LANGUAGE)) as string;
const enabledLanguages = resolveEnabledLanguages(
await settings.get(KEY_ENABLED_LANGUAGES),
);
const select = window.document.getElementById(
"languageSelect",
) as HTMLSelectElement;
for (const [langCode, lang] of Object.entries(SUPPORTED_LANGUAGES)) {
const allowAutoDetect = enabledLanguages.length > 1;
const isAutoDetect = language === "auto_detect";
const isValidLanguage = enabledLanguages.includes(language);
const displayLanguage =
isAutoDetect && allowAutoDetect
? "auto_detect"
: isValidLanguage
? language
: enabledLanguages[0];

if (!isValidLanguage && !(isAutoDetect && allowAutoDetect)) {
language = displayLanguage;
await settings.set(KEY_LANGUAGE, language);
chrome.runtime.sendMessage({
command: CMD_OPTIONS_PAGE_CONFIG_CHANGE,
context: {},
});
}
if (allowAutoDetect) {
const opt = window.document.createElement("option");
opt.value = "auto_detect";
opt.innerHTML = SUPPORTED_LANGUAGES.auto_detect;
select.appendChild(opt);
}
for (const langCode of enabledLanguages) {
const opt = window.document.createElement("option");
opt.value = langCode;
opt.innerHTML = lang;
opt.innerHTML = SUPPORTED_LANGUAGES[langCode];
select.appendChild(opt);
}
select.value = language;
select.value = displayLanguage;
},
);
window.document
Expand Down Expand Up @@ -99,11 +128,12 @@ async function languageChangeEvent() {
const select = window.document.getElementById(
"languageSelect",
) as HTMLSelectElement;

const message: OptionsPageConfigChangeMessage = {
command: CMD_OPTIONS_PAGE_CONFIG_CHANGE,
context: {},
};
await settings.set("language", select.value);
await settings.set(KEY_LANGUAGE, select.value);
chrome.runtime.sendMessage(message);
}

Expand Down
1 change: 1 addition & 0 deletions src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const KEY_DATE_FORMAT = "dateFormat";
export const KEY_USER_DICTIONARY_LIST = "userDictionaryList";
export const KEY_LANGUAGE = "language";
export const KEY_FALLBACK_LANGUAGE = "fallbackLanguage";
export const KEY_ENABLED_LANGUAGES = "enabled_languages";
export const KEY_DOMAIN_LIST_MODE = "domainListMode";
export const KEY_DISPLAY_LANG_HEADER = "displayLangHeader";
export const KEY_ENABLED = "enabled";
Expand Down
Loading
Loading