javascript · webextensions · chrome · ai · llm · переводчик · изучение языков · open source27 сентября в 10:33 · 6 мин

WordToast: Браузерный словарь с локальным переводом и интервальным повторением

Разработчик создал расширение WordToast, возрождающее принципы легендарного Dadda Translate. Новый проект работает во всех основных браузерах, используя встроенные API Chrome для локального перевода и позволяя подключать любые модели ИИ через личный API-ключ. Главное преимущество — приватность: данные о ваших словах никуда не отправляются, а интервальные повторения помогают эффективно запоминать новый лексику.

# Браузерный словарь нового поколения: как WordToast учит язык без потери приватности

Раньше существовало популярное китайское расширение Dadda Translate, которое позволяло выделять слова на странице, сохранять их в словарь и получать уведомления о повторении до тех пор, пока они не запомнятся. Однако проект был заброшен из-за изменений в API сторонних сервисов и ограниченности функционала. Разработчик переработал идею с нуля, создав WordToast — инструмент, совместимый с Firefox, Chrome и Edge, способный переводить текст на любой язык в браузере и объяснять смысл слов в контексте.

Локальный перевод и встроенные модели Chrome

Одной из ключевых особенностей расширения является использование встроенного Translator API, доступного в браузере Chrome с версии 138. В отличие от предыдущих решений, WordToast не отправляет ваш текст на внешние сервера для обработки. Вместо этого перевод происходит прямо в окне браузера.

Как это работает технически API обнаружения языка и перевода работает следующим образом:

1. Обнаружение языка: Модуль LanguageDetector анализирует выделенный текст и определяет его язык с определенной степенью уверенности. Если уверенность ниже порога 0.3, система автоматически откатывается к следующему движку в цепочке, не теряя время на попытки угадать язык с низкой точностью. 2. Проверка доступности: Перед созданием объекта переводчика система проверяет доступность пары языков через метод availability. Если выбранная пара недоступна, выводится четкая ошибка. 3. Перевод: После инициализации используется модуль Translator для получения результата.

javascript async function onDeviceTranslate(text: string, to: string) { const [best] = await (await globalThis.LanguageDetector.create()).detect(text); if (!best || best.confidence < 0.3 || best.detectedLanguage === "und") { throw new Error("language not detected"); } const from = best.detectedLanguage.split("-")[0]; const availability = await globalThis.Translator.availability({ sourceLanguage: from, targetLanguage: to }); if (availability === "unavailable") { throw new Error(${from}→${to} unsupported); } const translator = await globalThis.Translator.create({ sourceLanguage: from, targetLanguage: to }); return translator.translate(text); }

Ограничения и важные нюансы Несмотря на удобство, локальный API имеет ряд ограничений, которые разработатель учел при архитектуре расширения: * Service Worker: Доступ к API ограничен контекстом окон. Фон расширения (Service Worker в архитектуре MV3) не может напрямую вызывать эти функции. Поэтому перевод инициируется скриптом содержимого (content script) именно из того вкладки, где происходит выделение. * Первая загрузка: Скачивание модели языковой пары требует действия пользователя. Объекты переводчиков кешируются по паре языков, но создание нового переводчика после перезагрузки может потребовать повторного клика. * Неприсутствие в Firefox: В Firefox этот API скрыт и требует специальных настроек, поэтому в кроссплатформенном проекте он служит лишь одним из движков в цепочке отката, а не основным для всех браузеров.

Объяснение в контексте через вашу модель ИИ

Просто знать перевод слова недостаточно. Чтобы по-настоящему усвоить значение, нужно понимать контекст. WordToast предлагает функцию «Объяснить с ИИ», которая генерирует значение слова на основе полного предложения, где оно встретилось, а также примеров использования.

Интеграция с любыми провайдерами Разработчик сознательно отказался от использования готовых SDK, чтобы не раздувать размер расширения. Вместо этого реализована простая функция, строящая запрос для любого провайдера, совместимого с протоколом OpenAI. Поддерживаются: * OpenAI (GPT) * Claude (Anthropic) * Gemini * OpenRouter * Локальные модели через Ollama

Для подключения используется собственный API-ключ, который хранится локально в storage.local браузера и никогда не покидает устройство.

#### Работа с Claude и CORS Особый случай представляет API от Anthropic (Claude). Браузеры строго следят за политикой безопасности (CORS), и прямые вызовы из контекста расширения могут быть заблокированы. Чтобы обойти это, необходимо явно указать заголовок подтверждения риска:

javascript headers: { "content-type": "application/json", "x-api-key": cfg.apiKey, "anthropic-version": "2023-06-01", "anthropic-dangerous-direct-browser-access": "true" }

Отправка ключа в открытом виде всегда несет риск: если ваш браузер скомпрометирован, ключ будет перехвачен. Однако в данном случае он идет только провайдеру модели, минуя сторонние сервера расширений.

Безопасность кода В отличие от оригинала Dadda Translate, который рискованно использовал eval() для выполнения чужих скриптов для получения токенов, WordToast полностью свободен от внешних скриптов. Весь код выполняется только вами и провайдерами модели.

Карточки, устойчивые к чужому CSS

Всплывающие карточки с переводом и повторениями должны появляться поверх любого контента на странице, не ломая верстку сайта. Поскольку эти элементы живут в чужом DOM, они подвержены влиянию чужих стилей, ограниченных контента (CSP) и жестких правил.

Решение основано на использовании Shadow DOM: 1. Изоляция: Создается собственный корневой элемент <wordtoast-root> со своим shadow root. Стили страницы не проникают внутрь, а внутренние стили не влияют на остальной сайт. 2. CSS и CSP: Используется механизм adoptedStyleSheets. Это позволяет внедрить таблицы стилей динамически. Если сайт имеет жесткую политику безопасности (style-src без unsafe-inline), обычные вставки тега <style> будут заблокированы. Однако динамически созданные таблицы стилей через API обходят эту проверку.

javascript const root = host.attachShadow({ mode: "open" }); try { const sheet = new CSSStyleSheet(); sheet.replaceSync(css); root.adoptedStyleSheets = [sheet]; } catch { // Запасной вариант для поддержки старых браузеров const style = document.createElement("style"); style.textContent = css; root.appendChild(style); }

Также реализуется логика инверсии: если места для карточки снизу недостаточно, она переворачивается вверх, занимая свободное пространство.

Интервальные повторения и экспорт данных

Словарь в WordToast работает по классической схеме интервального повторения: 1. Вы запоминаете слово, и оно сохраняется вместе с предложением и ссылкой на страницу. 2. Спустя определенное время всплывает карточка-напоминание с кнопками «Помню» и «Забыл». 3. Интервалы растут экспоненциально: 5 минут, 30 минут, 12 часов, 1 день, 3 дня, 7 дней, 21 день и т.д.

В архитектуре браузера это реализовано через таймеры, срабатывающие в фоновом процессе. Поскольку в Service Worker нет долгоживущих таймеров, используется механизм chrome.alarms, который раз в минуту проверяет состояние и отправляет задачи в активную вкладку.

Данные легко экспортируются в популярные форматы для изучения языка, такие как Anki (формат TSV), CSV или JSON. Также предусмотрена возможность добавления тегов для лучшей организации словаря.

Заключение

WordToast представляет собой современную реализацию идеи «выдели слово — выучи слово». Проект сочетает в себе преимущества локальной обработки данных для конфиденциальности с гибкостью облачных мощностей ИИ для глубокого понимания контекста. Открытый код, отсутствие обязательной регистрации и поддержка множественных движков делают его надежным инструментом для самостоятельного изучения иностранных языков.

Код проекта доступен на GitHub: [https://github.com/Perruer/wordtoast](https://github.com/Perruer/wordtoast)

Первоисточники

Habr AI ↗
← Вернуться в эфир