import { svgIcons } from "./modal/svgIcons";
class Translator {
private translator: any;
private sourceLang: string;
private targetLang: string;
private targetLangLabel: string;
private sourceLangLabel: string;
constructor(sourceLang: string, targetLang: string, targetLangLabel: string, sourceLangLabel: string) {
this.sourceLang = sourceLang;
this.targetLang = targetLang;
this.targetLangLabel = targetLangLabel;
this.sourceLangLabel = sourceLangLabel;
}
public async LanguagePairStatus() {
// @ts-ignore
if (!window?.self?.translation && !window?.self?.ai?.translator && !window?.self?.Translator) {
return { error: 'The Translator AI modal is currently not supported or disabled in your browser. Please enable it. For detailed instructions on how to enable the Translator AI modal in your Chrome browser, click here.' };
}
const status = await this.languagePairAvality(this.sourceLang, this.targetLang);
// Handle case for language pack after download
if (status === "after-download" || status === "downloadable" || status === "unavailable") {
return { error: `
Installation Instructions for Language Packs:
To proceed, please install the language pack for ${this.targetLangLabel} (${this.targetLang}) or ${this.sourceLangLabel} (${this.sourceLang}).
After installing the language pack, add this language to your browser's system languages in Chrome settings.
Go to Settings > Languages > Add languages and add ${this.targetLangLabel} or ${this.sourceLangLabel} to your preferred languages list & reload the page.
You can install it by visiting the following link:
chrome://on-device-translation-internals ${svgIcons({iconName: 'copy'})}
. Click on the URL to copy it, then open a new window and paste this URL to access the settings.
Please check if both your source (${this.sourceLang}) and target (${this.targetLang}) languages are available in the language packs list.
You need to install both language packs for translation to work. You can search for each language by its language code: ${this.sourceLang} and ${this.targetLang}.
`};
}
// Handle case for language pack downloading
if (status === "downloading") {
const message = `
Language Pack Download In Progress:
The language pack for ${this.targetLangLabel} (${this.targetLang}) or ${this.sourceLangLabel} (${this.sourceLang}) is already being downloaded.
You do not need to start the download again. Please wait for the download to complete. Once finished, the translation feature will become available automatically.
You can check the download progress by opening:
chrome://on-device-translation-internals ${svgIcons({iconName: 'copy'})}
. Click on the URL to copy it, then open a new window and paste this URL in Chrome to view the status.
What to do next:
Wait for the download to finish. The status will change to Ready or Installed in the Language Packs section.
After the language pack is installed, you may need to reload or restart your browser for the changes to take effect.
`;
return { error: message };
}
if (status !== "readily" && status !== 'available') {
return { error: `
Language Pack Installation Required
Please ensure that the language pack for ${this.targetLangLabel} (${this.targetLang}) or ${this.sourceLangLabel} (${this.sourceLang}) is installed and set as a preferred language in your browser.
To install the language pack, visit chrome://on-device-translation-internals ${svgIcons({iconName: 'copy'})}. Click on the URL to copy it, then open a new window and paste this URL to access the settings.
If you encounter any issues, please refer to the documentation to check supported languages for further assistance.
` };
}
await this.createTranslator();
return true;
}
private languagePairAvality = async (source: string, target: string) => {
let status = "unavailable";
// @ts-ignore
if (window?.self?.translation) {
// @ts-ignore
status = await window?.self?.translation?.canTranslate({
sourceLanguage: source,
targetLanguage: target,
});
}
// @ts-ignore
if (window?.self?.ai?.translator) {
// @ts-ignore
const translatorCapabilities = await window?.self?.ai?.translator?.capabilities();
status = await translatorCapabilities.languagePairAvailable(source, target);
}
// @ts-ignore
if (window?.self?.Translator) {
// @ts-ignore
status = await window?.self?.Translator?.availability({
sourceLanguage: source,
targetLanguage: target,
});
}
// @ts-ignore
if(['unavailable', 'downloading', 'after-download', 'downloadable'].includes(status) && window?.self?.Translator){
try {
// @ts-ignore
const translator = await window?.self?.Translator?.create({
sourceLanguage: source,
targetLanguage: target,
monitor(m) {
m.addEventListener('downloadprogress', (e) => {
console.log(`Downloaded ${e.loaded * 100}%`);
});
},
});
// @ts-ignore
status = await window?.self?.Translator?.availability({
sourceLanguage: source,
targetLanguage: target,
});
} catch (err) { console.log('err', err) }
}
return status;
}
private AITranslator = async () => {
// @ts-ignore
if (window?.self?.translation) {
// @ts-ignore
this.translator = await window.self.translation.createTranslator({
sourceLanguage: this.sourceLang,
targetLanguage: this.targetLang,
});
return this.translator;
}
// @ts-ignore
if (window?.self?.ai?.translator) {
// @ts-ignore
this.translator = await window.self.ai.translator.create({
sourceLanguage: this.sourceLang,
targetLanguage: this.targetLang,
});
return this.translator;
}
// @ts-ignore
if ("Translator" in window?.self && "create" in window?.self?.Translator) {
// @ts-ignore
const translator = await window.self.Translator.create({
sourceLanguage: this.sourceLang,
targetLanguage: this.targetLang,
});
return translator;
}
return false;
}
private createTranslator = async () => {
if (!this.translator) {
// @ts-ignore
this.translator = await this.AITranslator();
return { error: false };
}
}
public startTranslation = async (
text: string,
): Promise => {
// Capture all leading and trailing whitespace (multiple, single, or none)
const startWhitespace = text.match(/^\s*/)?.[0] ?? '';
const endWhitespace = text.match(/\s*$/)?.[0] ?? '';
// Get the main content with whitespace trimmed from both ends
const coreText = text.slice(startWhitespace.length, text.length - endWhitespace.length);
// If the entire string is whitespace, just return it (don't call the translator)
if (coreText === '') {
return text;
}
// Translate only the core text
let translatedText = await this.translator.translate(coreText);
// Restore the original leading and trailing whitespace exactly
return `${startWhitespace}${translatedText}${endWhitespace}`;
};
}
export default Translator;