From c058fa0fb22dc40ef0225b21a97578cddd0aaffa Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 14:51:05 +0100 Subject: unslug ru: move --- .../webextensions/internationalization/index.html | 405 +++++++++++++++++++++ .../webextensions/modify_a_web_page/index.html | 238 ++++++++++++ .../index.html" | 405 --------------------- .../index.html" | 238 ------------ .../index.html" | 218 ----------- 5 files changed, 643 insertions(+), 861 deletions(-) create mode 100644 files/ru/mozilla/add-ons/webextensions/internationalization/index.html create mode 100644 files/ru/mozilla/add-ons/webextensions/modify_a_web_page/index.html delete mode 100644 "files/ru/mozilla/add-ons/webextensions/\320\270\320\275\321\202\320\265\321\200\320\275\320\260\321\206\320\270\320\276\320\275\320\260\320\273\320\270\320\267\320\260\321\206\320\270\321\217/index.html" delete mode 100644 "files/ru/mozilla/add-ons/webextensions/\320\274\320\276\320\264\320\270\321\204\320\270\320\272\320\260\321\206\320\270\321\217_\320\262\320\265\320\261_\321\201\321\202\321\200\320\260\320\275\320\270\321\206\321\213/index.html" delete mode 100644 "files/ru/mozilla/add-ons/webextensions/\320\277\320\265\321\200\320\265\320\262\320\276\320\264/index.html" (limited to 'files/ru/mozilla/add-ons') diff --git a/files/ru/mozilla/add-ons/webextensions/internationalization/index.html b/files/ru/mozilla/add-ons/webextensions/internationalization/index.html new file mode 100644 index 0000000000..36a37820d9 --- /dev/null +++ b/files/ru/mozilla/add-ons/webextensions/internationalization/index.html @@ -0,0 +1,405 @@ +--- +title: Интернационализация +slug: Mozilla/Add-ons/WebExtensions/Интернационализация +translation_of: Mozilla/Add-ons/WebExtensions/Internationalization +--- +
{{AddonSidebar}}
+ +

API WebExtensions предоставляет полезный модуль для интернационализации расширений — i18n. В этой статье мы рассмотрим его особенности и пример его работы. Система для расширений, построенных с помощью API WebExtension, i18n похожа на библиотеки JavaScript для i18n, такие как i18n.js.

+ +
+

Расширение, используемое в этой статье в качестве примера, — notify-link-clicks-i18n — доступно на GitHub. Читая последующие секции этой статьи, Вы можете исследовать его исходный код.

+
+ +

Структура интернализированного расширения

+ +

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

+ + + +

Давайте отдельно рассмотрим каждый элемент — последующие секции представляют собой шаги, которым стоит следовать во время интернационализации вашего расширения.

+ +

Добавление локализованных строк в _locales

+ +
+
Вы можете определить тэг языка при помощи инструмента Find  на странице определения языковых тегов. Обратите внимание на то, что при поиске еужно использовать английское название языка
+
+ +

Каждая система i18n требует предоставить строки во всех локализациях, которые Вы хотите поддерживать. В расширениях они хранятся в директории  _locales, размещенной внутри корневой директории. Строки каждой локализации (также называемые сообщениями) хранятся в файле messages.json, находящемся в поддиректории _locales, название которой - тег языка локализации.

+ +

Стоит заметить, что если тег включает в себя и базовый язык, и его региональный вариант, то по конвенции эти язык и вариант разделяются дефисом: например, "en-US". Однако в поддиректориях _locales, вместо дефиса используется нижнее подчеркивание: "en_US".

+ +

Таким образом, в нашем примере существую директории "en" (английский), "de" (немецкий), "nl" (голландский), and "ja" (японский). Внутри каждой из них находится файл messages.json .

+ +

Давайте рассмотрим структуру одного из этих файлов (_locales/en/messages.json):

+ +
{
+  "extensionName": {
+    "message": "Notify link clicks i18n",
+    "description": "Name of the extension."
+  },
+
+  "extensionDescription": {
+    "message": "Shows a notification when the user clicks on links.",
+    "description": "Description of the extension."
+  },
+
+  "notificationTitle": {
+    "message": "Click notification",
+    "description": "Title of the click notification."
+  },
+
+  "notificationContent": {
+    "message": "You clicked $URL$.",
+    "description": "Tells the user which link they clicked.",
+    "placeholders": {
+      "url" : {
+        "content" : "$1",
+        "example" : "https://developer.mozilla.org"
+      }
+    }
+  }
+}
+ +

Это стандартный файл JSON — каждый из его элементов является объектом с именем, содержащим сообщение (message) и описание (description). Оба предмета - строки; $URL$ — это заполнитель, который заменяется подстрокой, когда элемент notificationContent вызывается расширением. Вы научитесь это делать в секции {{anch("Получение сообщений из JavaScript")}}.

+ +
+

Примечание: Вы можете найти больше информации о структуре messages.json здесь.

+
+ +

Интернационализация manifest.json

+ +

Для интернационализации файла manifest.json нужно предпринять несколько шагов.

+ +

Получение локализованных строк в манифестах

+ +

Ваш файл manifest.json содержит строки, отображаемые пользователю, такие как имя и описание расширения. Если Вы интернационализируете эти строки и поместите их переводы в messages.json, то эти переводы будут отображаться пользователю в зависимости от локализации его браузера.

+ +

Чтобы интернационализировать строки, их нужно указывать следующим образом:

+ +
"name": "__MSG_extensionName__",
+"description": "__MSG_extensionDescription__",
+ +

Здесь мы получаем сообщения, зависящие от локализации браузера, а не просто статические строки.

+ +

Чтобы получить строку сообщения, ее нужно указать следующим образом:

+ +
    +
  1. Два подчеркивания
  2. +
  3. Строка "MSG"
  4. +
  5. Одно подчеркивание
  6. +
  7. Имя сообщения так как оно указано в messages.json
  8. +
  9. Два подчеркивания
  10. +
+ +
__MSG_ + messageName + __
+ +

Локализация по умолчанию

+ +

Еше одно поле. которое нужно указать в manifest.json — это default_locale:

+ +
"default_locale": "en"
+ +

Этот параметр устанавливает локализацию по умолчанию, используемую, если расширение не поддерживает локализацию браузера пользователя. Любые сообщения, недоступные в текущей локализации, будут браться из той локализации, которая установлена по умолчанию. There are some more details to be aware of in terms of how the browser selects strings — see {{anch("Выбор локализованной строки")}}.

+ +

CSS, зависящий от локализации

+ +

Локализованные строки также можно получить из CSS-файлов расширения. Например, Вы можете создать поля CSS, зависящие от локализации, так:

+ +
header {
+  background-image: url(../images/__MSG_extensionName__/header.png);
+}
+ +

Этот функционал может быть полезен, однако, возможно, для этих целей стоит использовать {{anch("Заранее определенные сообщения")}}.

+ +

Получение сообщений из JavaScript

+ +

Допустим, Вы добавили сообщения в Ваш manifest.json. Чтобы Ваше расширение начало использовать правильные языки, соответствующие сообщения следует вызывать при помощи JavaScript. API i18n достаточно прост и содержит всего 4 основных метода:

+ + + +

В нашем примере notify-link-clicks-i18n , фоновый скрипт содержит следующие строки:

+ +
var title = browser.i18n.getMessage("notificationTitle");
+var content = browser.i18n.getMessage("notificationContent", message.url);
+ +

Первая из них получает поле notificationTitle message из доступного файла messages.json, соответствующее наиболее подходящей локализации . Вторая строка похожа на первую, но в ней метод принимает URL в качестве второго параметра. Зачем? С помощью этого параметра мы указываем, на что нужно заменить заполнитель $URL$ в поле notificationContent message:

+ +
"notificationContent": {
+  "message": "You clicked $URL$.",
+  "description": "Tells the user which link they clicked.",
+  "placeholders": {
+    "url" : {
+      "content" : "$1",
+      "example" : "https://developer.mozilla.org"
+    }
+  }
+}
+
+ +

Объект "placeholders"  определяет все заполнители и то, откуда их нужно получать. Заполнитель "url" указывает, что информация о нем должна содержаться в $1 — первое значение, заданное внутри второго параметра getMessage(). Поскольку заролнитель называется "url",  $URL$ используется для его вызова внутри сообщения (то есть для заполнителя "name" нужно использовать $NAME$, и т. д.). Если Вы хотите задать значения нескольких заполнителей, их можно передавать во второй аргумент {{WebExtAPIRef("i18n.getMessage()")}} в виде массива — массив [a, b, c] передает значения $1, $2 и $3, и т. д. внутрь messages.json.

+ +

Давайте посмотрим на пример: изначально сообщение notificationContent в файле en/messages.json такое:

+ +
You clicked $URL$.
+ +

Пусть эта ссылка указывает на https://developer.mozilla.org. После вызова {{WebExtAPIRef("i18n.getMessage()")}}, содержание второго параметра становится доступно в messages.json в качестве значения $1, замещающего $URL$, так как это указано в заполнителе  "url". Таким образом, итоговое значение строки:

+ +
You clicked https://developer.mozilla.org.
+ +

Прямое использование заполнителей

+ +

Переменные ($1, $2, $3, и т. д.) можно вставлять напрямую в сообщения. Например, можно переписать объект "notificationContent" следующим образом:

+ +
"notificationContent": {
+  "message": "You clicked $1.",
+  "description": "Tells the user which link they clicked."
+}
+ +

Этот метод может показаться более быстрым и простым, но другой способ (использование "placeholders") считается лучшей практикой. Это вызвано тем, что имена заполнителей (например "url") и примеры помогают понять, что означают заполнители — через неделю после написания кода Вы, наверное, забудете, что обозначают заполнители $1$8, что менее вероятно, если заполнители именованы.

+ +

Заданные замены

+ +

Значения заполнителей можно задавать вручную, если Вы хотите, чтобы каждый раз это значение было одним и тем же, а не определялось переменной в коде. Например:

+ +
"mdn_banner": {
+  "message": "For more information on web technologies, go to $MDN$.",
+  "description": "Tell the user about MDN",
+  "placeholders": {
+    "mdn": {
+      "content": "https://developer.mozilla.org/"
+    }
+  }
+}
+ +

В этом примере мы сами задаем значение заполнителя, а не получаем его из переменной, такой как $1. Это может быть полезно, если сообщение очень сложное, и Вы хотите разделить значения, чтобы сделать строки более читаемыми. К тому же, доступ к этим значениям можно получить внутри программы.

+ +

Вы также можете использовать такие замены для указания частей строки, не нуждающихся в переводе, таких как имена или названия.

+ +

Выбор локализованной строки

+ +

Локализации могут быть указаны с помощью кода языка, например fr или en. Они также могут содержать региональный код, например en_US или en_GB, описывающий региональный вариант языка. Когда вы запрашиваете строку у системы i18n, системы возвращает ее используя следующий алгоритм:

+ +
    +
  1. Если для текущей локализации существует файл messages.json, содержащий требуемую строку, возвращается она.
  2. +
  3. Иначе,если текущая локализация — региональный вариант (например en_US) и существует файл messages.json для этого языка, но без указания региона  (например en), содержащий строку, возвращается она.
  4. +
  5. Иначе, если существует файл messages.json для default_locale, указанной в manifest.json, и этот файл содержит нужную строку, возвращается она.
  6. +
  7. В противном случае возвращается пустая строка.
  8. +
+ +

Рассмотрим следующий пример:

+ + + +

Пусть default_locale установлен как fr, а текущая локализация браузера — en_GB:

+ + + +

Заранее определенные сообщения

+ +

Модуль i18n module предоставляет заранее определенные сообщения, которые можно вызвать таким же образом, как мы это делали в разделе {{anch("Интернационализация manifest.json")}}. Например:

+ +
__MSG_extensionName__
+ +

Заранее определенные сообщения используют такой же синтаксис, за исключением @@ перед именем сообщения, например:

+ +
__MSG_@@ui_locale__
+ +

Следующая таблица содержит различные заранее определенные сообщения:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Message nameDescription
@@extension_id +

Внутренний UUID расширения. Эту строку можно использовать для создания URL ресурсов внутри расширения.Даже нелокализованные расширения могут использовать это сообщения.

+ +

Это сообщения нельзя использовать в manifest.json.

+ +

Также стоит заметить, что этот ID — не ID аддона, которое возвращает {{WebExtAPIRef("runtime.id")}}, и которое может быть установлено с помощью ключа applications в manifest.json. Это сгенерированный UUID, содержащийся в URL аддона. Это означает, что данную величину нельзя использовать в качестве параметра extensionId  метода {{WebExtAPIRef("runtime.sendMessage()")}}, или для проверки поля id объекта {{WebExtAPIRef("runtime.MessageSender")}}.

+
@@ui_localeТекущая локализация; эту строку можно использовать для создания URL, зависящих от локализации.
@@bidi_dirНаправления чтения, либо "ltr" для языков, таких как английский, где текст читается слева направо, либо "rtl" для языков, считающихся справа налево, таких как арабский.
@@bidi_reversed_dirЕсли @@bidi_dir имеет значение "ltr", то возвращает "rtl"; иначе "ltr".
@@bidi_start_edgeЕсли @@bidi_dir имеет значение "ltr", то возвращает "left"; иначе "right".
@@bidi_end_edgeЕсли @@bidi_dir имеет значение "ltr", то возвращает "right"; иначе "left".
+ +

Возвращаясь к нашему примеру, лучше было бы написать:

+ +
header {
+  background-image: url(../images/__MSG_@@ui_locale__/header.png);
+}
+ +

Теперь мы можем хранить изображения в директориях поддерживаемых локализаций — en, de, и т. д. — что выглядит логичней.

+ +

Давайте рассмотрим пример использования сообщений @@bidi_* в файле CSS:

+ +
body {
+  direction: __MSG_@@bidi_dir__;
+}
+
+div#header {
+  margin-bottom: 1.05em;
+  overflow: hidden;
+  padding-bottom: 1.5em;
+  padding-__MSG_@@bidi_start_edge__: 0;
+  padding-__MSG_@@bidi_end_edge__: 1.5em;
+  position: relative;
+}
+ +

Для языков, в которых текст читается слева направо, таких как английский, правила CSS, использующие заранее определенные сообщения, сверху задают такие значения:

+ +
direction: ltr;
+padding-left: 0;
+padding-right: 1.5em;
+
+ +

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

+ +
direction: rtl;
+padding-right: 0;
+padding-left: 1.5em;
+ +

Тестирование расширения

+ +

Начиная с Firefox 45, расширения могут быть временно установлены с диска — подробнее об этом написано в статье Loading from disk. Сделайте это и попробуйте протестировать наше расширение notify-link-clicks-i18n. Перейдите на одну из Ваших любимых страниц и нажмите на ссылку, чтобы проверить, появляется ли сообщения, содержащее URL нажатой ссылки.

+ +

Затем измените локализацию Firefox на какую-либо поддерживающуюся расширением, которое Вы хотите протестировать.

+ +
    +
  1. Откройте "about:config" в Firefox, и найдите параметр intl.locale.requested (обратите внимание на версию Firefox: в версиях до Firefox 59 этот параметр называется general.useragent.locale).
  2. +
  3. Если параметр существует, нажмите на него дважды (или нажмите Return/Enter), чтобы выбрать его, введите языковой код локализации, которую Вы хотите протестировать и нажмите "OK" (или Return/Enter). Например, в нашем примере расширение поддерживает "en" (английский), "de" (немецкий), "nl" (голландский), and "ja" (японский). Вы также можете указать пустую строку ("") в качестве значения. В этом случае браузер выберет язык Вашей ОС по умолчанию.
  4. +
  5. Если параметр intl.locale.requested не существует, нажмите правой кнопкой мыши на список параметров (или откройте контекстное меню при помощи клавиатуры), и выберите "New", а затем "String". Введите intl.locale.requested как имя настройки и, "de", "nl", и т. д. как значение, как это описано в шаге 2.
  6. +
  7. Найдите intl.locale.matchOS и, если параметр существует и равен true, дважды нажмите на него и установите на false.
  8. +
  9. Перезапустите браузер, чтобы изменения вступили в силу.
  10. +
+ +
+

Примечание: Этот метод работает, даже если у Вас не установлен языковой пакет для выбранного языка. В этом случае UI браузера просто будет использовать Ваш язык по умолчанию.

+
+ +
    +
+ +
+

Примечание: Чтобы изменить результат getUILanguage требуется языковой пакет, поскольку он отражает язык UI браузера, а не язык сообщений расширения.

+
+ +

Еше раз загрузите расширение с диска и протестируйте локализацию:

+ + + +

{{EmbedYouTube("R7--fp5pPGg")}}

diff --git a/files/ru/mozilla/add-ons/webextensions/modify_a_web_page/index.html b/files/ru/mozilla/add-ons/webextensions/modify_a_web_page/index.html new file mode 100644 index 0000000000..0f58364706 --- /dev/null +++ b/files/ru/mozilla/add-ons/webextensions/modify_a_web_page/index.html @@ -0,0 +1,238 @@ +--- +title: Модификация веб страницы +slug: Mozilla/Add-ons/WebExtensions/модификация_веб_страницы +translation_of: Mozilla/Add-ons/WebExtensions/Modify_a_web_page +--- +

 

+ +
{{AddonSidebar}}
+ +

Одним из наиболее распространённых вариантов использования расширений является внесение изменение в веб-страницу. К примеру, расширение может изменить стиль, применённый к странице, скрыть существующие или вставить на страницу дополнительные DOM-узлы.

+ +

Существует два способа сделать это используя WebExtensions API:

+ + + +

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

+ + + +

В этой статье мы рассмотрим оба способа загрузки скрипта.

+ +

Модификация страниц, подпадающих под URL-шаблон

+ +

Прежде всего создадим новую директорию, назовём её "modify-page". В этой директории, создадим файл "manifest.json", со следующим содержимым:

+ +
{
+
+  "manifest_version": 2,
+  "name": "modify-page",
+  "version": "1.0",
+
+  "content_scripts": [
+    {
+      "matches": ["https://developer.mozilla.org/*"],
+      "js": ["page-eater.js"]
+    }
+  ]
+
+}
+ +

Ключ content_scripts - это как мы загружаем скрипты на страницы, соответстующие URL-шаблону. В нашем случае, content_scripts говорит браузеру загрузить скрипт "page-eater.js" на все страницы, начинающиеся с https://developer.mozilla.org/.

+ +
+

Поскольку свойство "js" ключа content_scripts это массив, вы можете использовать его, для внедрения более одного скрипта. Если вы сделаете это, страницы получат набор, как если бы эти скрипты были загружены самой страницей, они будут загружены в той же очерёдности, в которой они расположены в массиве.

+
+ +
+

Ключ content_scripts также имеет свойство  "css", которое вы можете использовать для вставки CSS-таблиц.

+
+ +

Далее, создадим файл "page-eater.js", внутри директории "modify-page":

+ +
document.body.textContent = "";
+
+var header = document.createElement('h1');
+header.textContent = "Эта страница была съедена";
+document.body.appendChild(header);
+ +

Теперь установим расширение, и перейдём на страницу https://developer.mozilla.org/:

+ +

{{EmbedYouTube("lxf2Tkg6U1M")}}

+ +
+

Обратите внимание, несмотря на то, что в указанном видео, на странице addons.mozilla.org всё работает нормально, на текущий момент, для этого сайта, контентные скрипты заблокированы.

+
+ +

Программная модификация страницы

+ +

Что, если вы всё еще хотите "съедать" страницы, но лишь в тех случаях, когда пользователь попросил об этом? Давайте обновим этот пример таким образом, чтобы мы внедряли контентный скрипт, когда пользователь выбирает соответствующий пункт контентного меню.

+ +

Для начала обновим "manifest.json":

+ +
{
+
+  "manifest_version": 2,
+  "name": "modify-page",
+  "version": "1.0",
+
+  "permissions": [
+    "activeTab",
+    "contextMenus"
+  ],
+
+  "background": {
+    "scripts": ["background.js"]
+  }
+
+}
+ +

Мы удалили ключ content_scripts и добавили два новых:

+ + + +

Давайте создадим этот файл. Создадим новый файл "background.js" в директории "modify-page" и поместим в него следующий код:

+ +
browser.contextMenus.create({
+  id: "eat-page",
+  title: "Съесть эту страницу"
+});
+
+browser.contextMenus.onClicked.addListener(function(info, tab) {
+  if (info.menuItemId == "eat-page") {
+    browser.tabs.executeScript({
+      file: "page-eater.js"
+    });
+  }
+});
+
+ +

В этом скрипте мы создаём элемент контекстного меню, передавая ему определённый идентификатор и заголовок (текст будет отображаться в элементе контекстного меню). Затем мы настраиваем обработчик событий таким образом, чтобы когда пользователь выбирает пункт контекстного меню, осуществлялась проверка, наш ли это элемент eat-page. Если это так - внедряем скрипт "page-eater.js" в текущую вкладку, используя tabs.executeScript() API. Это API опционально принимает идентификатор вкладки, в качестве аргумента. Мы опустили его, это означает, что скрипт будет внедряться в текущую активную вкладку.

+ +

На данном этапе расширение должно иметь следующий вид:

+ +
modify-page/
+    background.js
+    manifest.json
+    page-eater.js
+ +

Теперь перезагрузим расширение, откроем страницу (на этот раз любую) активируем контекстное меню и выберем "Съесть эту страницу":

+ +

{{EmbedYouTube("zX4Bcv8VctA")}}

+ +
+

Обратите внимание, несмотря на то, что в указанном видео, на странице addons.mozilla.org всё работает нормально, на текущий момент, для этого сайта, контентные скрипты заблокированы.

+
+ +

Обмен сообщениями

+ +

Контентные и фоновые скрипты не могут на прямую взаимодействовать друг с другом. Не смотря на это они могут взаимодействовать с помощью обмена сообщениями. Для этого один конец создаёт обработчик сообщений, а другой - может посылать сообщения. В следующей таблице представлены API-интерфейсы, задействованные с каждой стороны:

+ + + + + + + + + + + + + + + + + + + +
В контентном скриптеВ фоновом скрипте
Отправка сообщенияbrowser.runtime.sendMessage()browser.tabs.sendMessage()
Получение сообщенияbrowser.runtime.onMessagebrowser.runtime.onMessage
+ +

Давайте обновим наш пример, чтобы посмотреть, как послать сообщение из фонового скрипта.

+ +

Изменим "background.js" :

+ +
browser.contextMenus.create({
+  id: "eat-page",
+  title: "Съесть эту страницу"
+});
+
+function messageTab(tabs) {
+  browser.tabs.sendMessage(tabs[0].id, {
+    replacement: "Message from the extension!"
+  });
+}
+
+browser.contextMenus.onClicked.addListener(function(info, tab) {
+  if (info.menuItemId == "eat-page") {
+    browser.tabs.executeScript({
+      file: "page-eater.js"
+    });
+
+    var querying = browser.tabs.query({
+      active: true,
+      currentWindow: true
+    });
+    querying.then(messageTab);
+  }
+});
+
+ +

Теперь, после внедрения "page-eater.js", мы используем tabs.query(), чтобы получить текущую открытую вкладку и используем tabs.sendMessage(), для отправки сообщения контентному скрипту, загруженному на этой вкладке. Сообщение несёт полезную нагрузку {replacement: "Message from the extension!"}.

+ +

Далее, обновим "page-eater.js":

+ +
function eatPage(request, sender, sendResponse) {
+  document.body.textContent = "";
+
+  var header = document.createElement('h1');
+  header.textContent = request.replacement;
+  document.body.appendChild(header);
+}
+
+browser.runtime.onMessage.addListener(eatPage);
+
+ +

Теперь, вместо простого "поедания страницы", контентный скрипт ждёт сообщение, используя runtime.onMessage. Когда сообщение получено, контентный скрипт выполняет в точности такой же код, как и а примере ранее, за исключением того, что заменяющий текст берётся из request.replacement.

+ +

Если мы хотим отправить сообщение наоборот, из контентного скрипта в фоновый, настройка будет обратной данному примеру, за исключением того, что мы будем использовать runtime.sendMessage() в контентном скрипте.

+ +
+

Все эти примеры внедряют JavaScript; вы можете программно внедрять стилевые таблицы CSS используя функцию tabs.insertCSS().

+
+ +

Узнать больше

+ + diff --git "a/files/ru/mozilla/add-ons/webextensions/\320\270\320\275\321\202\320\265\321\200\320\275\320\260\321\206\320\270\320\276\320\275\320\260\320\273\320\270\320\267\320\260\321\206\320\270\321\217/index.html" "b/files/ru/mozilla/add-ons/webextensions/\320\270\320\275\321\202\320\265\321\200\320\275\320\260\321\206\320\270\320\276\320\275\320\260\320\273\320\270\320\267\320\260\321\206\320\270\321\217/index.html" deleted file mode 100644 index 36a37820d9..0000000000 --- "a/files/ru/mozilla/add-ons/webextensions/\320\270\320\275\321\202\320\265\321\200\320\275\320\260\321\206\320\270\320\276\320\275\320\260\320\273\320\270\320\267\320\260\321\206\320\270\321\217/index.html" +++ /dev/null @@ -1,405 +0,0 @@ ---- -title: Интернационализация -slug: Mozilla/Add-ons/WebExtensions/Интернационализация -translation_of: Mozilla/Add-ons/WebExtensions/Internationalization ---- -
{{AddonSidebar}}
- -

API WebExtensions предоставляет полезный модуль для интернационализации расширений — i18n. В этой статье мы рассмотрим его особенности и пример его работы. Система для расширений, построенных с помощью API WebExtension, i18n похожа на библиотеки JavaScript для i18n, такие как i18n.js.

- -
-

Расширение, используемое в этой статье в качестве примера, — notify-link-clicks-i18n — доступно на GitHub. Читая последующие секции этой статьи, Вы можете исследовать его исходный код.

-
- -

Структура интернализированного расширения

- -

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

- - - -

Давайте отдельно рассмотрим каждый элемент — последующие секции представляют собой шаги, которым стоит следовать во время интернационализации вашего расширения.

- -

Добавление локализованных строк в _locales

- -
-
Вы можете определить тэг языка при помощи инструмента Find  на странице определения языковых тегов. Обратите внимание на то, что при поиске еужно использовать английское название языка
-
- -

Каждая система i18n требует предоставить строки во всех локализациях, которые Вы хотите поддерживать. В расширениях они хранятся в директории  _locales, размещенной внутри корневой директории. Строки каждой локализации (также называемые сообщениями) хранятся в файле messages.json, находящемся в поддиректории _locales, название которой - тег языка локализации.

- -

Стоит заметить, что если тег включает в себя и базовый язык, и его региональный вариант, то по конвенции эти язык и вариант разделяются дефисом: например, "en-US". Однако в поддиректориях _locales, вместо дефиса используется нижнее подчеркивание: "en_US".

- -

Таким образом, в нашем примере существую директории "en" (английский), "de" (немецкий), "nl" (голландский), and "ja" (японский). Внутри каждой из них находится файл messages.json .

- -

Давайте рассмотрим структуру одного из этих файлов (_locales/en/messages.json):

- -
{
-  "extensionName": {
-    "message": "Notify link clicks i18n",
-    "description": "Name of the extension."
-  },
-
-  "extensionDescription": {
-    "message": "Shows a notification when the user clicks on links.",
-    "description": "Description of the extension."
-  },
-
-  "notificationTitle": {
-    "message": "Click notification",
-    "description": "Title of the click notification."
-  },
-
-  "notificationContent": {
-    "message": "You clicked $URL$.",
-    "description": "Tells the user which link they clicked.",
-    "placeholders": {
-      "url" : {
-        "content" : "$1",
-        "example" : "https://developer.mozilla.org"
-      }
-    }
-  }
-}
- -

Это стандартный файл JSON — каждый из его элементов является объектом с именем, содержащим сообщение (message) и описание (description). Оба предмета - строки; $URL$ — это заполнитель, который заменяется подстрокой, когда элемент notificationContent вызывается расширением. Вы научитесь это делать в секции {{anch("Получение сообщений из JavaScript")}}.

- -
-

Примечание: Вы можете найти больше информации о структуре messages.json здесь.

-
- -

Интернационализация manifest.json

- -

Для интернационализации файла manifest.json нужно предпринять несколько шагов.

- -

Получение локализованных строк в манифестах

- -

Ваш файл manifest.json содержит строки, отображаемые пользователю, такие как имя и описание расширения. Если Вы интернационализируете эти строки и поместите их переводы в messages.json, то эти переводы будут отображаться пользователю в зависимости от локализации его браузера.

- -

Чтобы интернационализировать строки, их нужно указывать следующим образом:

- -
"name": "__MSG_extensionName__",
-"description": "__MSG_extensionDescription__",
- -

Здесь мы получаем сообщения, зависящие от локализации браузера, а не просто статические строки.

- -

Чтобы получить строку сообщения, ее нужно указать следующим образом:

- -
    -
  1. Два подчеркивания
  2. -
  3. Строка "MSG"
  4. -
  5. Одно подчеркивание
  6. -
  7. Имя сообщения так как оно указано в messages.json
  8. -
  9. Два подчеркивания
  10. -
- -
__MSG_ + messageName + __
- -

Локализация по умолчанию

- -

Еше одно поле. которое нужно указать в manifest.json — это default_locale:

- -
"default_locale": "en"
- -

Этот параметр устанавливает локализацию по умолчанию, используемую, если расширение не поддерживает локализацию браузера пользователя. Любые сообщения, недоступные в текущей локализации, будут браться из той локализации, которая установлена по умолчанию. There are some more details to be aware of in terms of how the browser selects strings — see {{anch("Выбор локализованной строки")}}.

- -

CSS, зависящий от локализации

- -

Локализованные строки также можно получить из CSS-файлов расширения. Например, Вы можете создать поля CSS, зависящие от локализации, так:

- -
header {
-  background-image: url(../images/__MSG_extensionName__/header.png);
-}
- -

Этот функционал может быть полезен, однако, возможно, для этих целей стоит использовать {{anch("Заранее определенные сообщения")}}.

- -

Получение сообщений из JavaScript

- -

Допустим, Вы добавили сообщения в Ваш manifest.json. Чтобы Ваше расширение начало использовать правильные языки, соответствующие сообщения следует вызывать при помощи JavaScript. API i18n достаточно прост и содержит всего 4 основных метода:

- - - -

В нашем примере notify-link-clicks-i18n , фоновый скрипт содержит следующие строки:

- -
var title = browser.i18n.getMessage("notificationTitle");
-var content = browser.i18n.getMessage("notificationContent", message.url);
- -

Первая из них получает поле notificationTitle message из доступного файла messages.json, соответствующее наиболее подходящей локализации . Вторая строка похожа на первую, но в ней метод принимает URL в качестве второго параметра. Зачем? С помощью этого параметра мы указываем, на что нужно заменить заполнитель $URL$ в поле notificationContent message:

- -
"notificationContent": {
-  "message": "You clicked $URL$.",
-  "description": "Tells the user which link they clicked.",
-  "placeholders": {
-    "url" : {
-      "content" : "$1",
-      "example" : "https://developer.mozilla.org"
-    }
-  }
-}
-
- -

Объект "placeholders"  определяет все заполнители и то, откуда их нужно получать. Заполнитель "url" указывает, что информация о нем должна содержаться в $1 — первое значение, заданное внутри второго параметра getMessage(). Поскольку заролнитель называется "url",  $URL$ используется для его вызова внутри сообщения (то есть для заполнителя "name" нужно использовать $NAME$, и т. д.). Если Вы хотите задать значения нескольких заполнителей, их можно передавать во второй аргумент {{WebExtAPIRef("i18n.getMessage()")}} в виде массива — массив [a, b, c] передает значения $1, $2 и $3, и т. д. внутрь messages.json.

- -

Давайте посмотрим на пример: изначально сообщение notificationContent в файле en/messages.json такое:

- -
You clicked $URL$.
- -

Пусть эта ссылка указывает на https://developer.mozilla.org. После вызова {{WebExtAPIRef("i18n.getMessage()")}}, содержание второго параметра становится доступно в messages.json в качестве значения $1, замещающего $URL$, так как это указано в заполнителе  "url". Таким образом, итоговое значение строки:

- -
You clicked https://developer.mozilla.org.
- -

Прямое использование заполнителей

- -

Переменные ($1, $2, $3, и т. д.) можно вставлять напрямую в сообщения. Например, можно переписать объект "notificationContent" следующим образом:

- -
"notificationContent": {
-  "message": "You clicked $1.",
-  "description": "Tells the user which link they clicked."
-}
- -

Этот метод может показаться более быстрым и простым, но другой способ (использование "placeholders") считается лучшей практикой. Это вызвано тем, что имена заполнителей (например "url") и примеры помогают понять, что означают заполнители — через неделю после написания кода Вы, наверное, забудете, что обозначают заполнители $1$8, что менее вероятно, если заполнители именованы.

- -

Заданные замены

- -

Значения заполнителей можно задавать вручную, если Вы хотите, чтобы каждый раз это значение было одним и тем же, а не определялось переменной в коде. Например:

- -
"mdn_banner": {
-  "message": "For more information on web technologies, go to $MDN$.",
-  "description": "Tell the user about MDN",
-  "placeholders": {
-    "mdn": {
-      "content": "https://developer.mozilla.org/"
-    }
-  }
-}
- -

В этом примере мы сами задаем значение заполнителя, а не получаем его из переменной, такой как $1. Это может быть полезно, если сообщение очень сложное, и Вы хотите разделить значения, чтобы сделать строки более читаемыми. К тому же, доступ к этим значениям можно получить внутри программы.

- -

Вы также можете использовать такие замены для указания частей строки, не нуждающихся в переводе, таких как имена или названия.

- -

Выбор локализованной строки

- -

Локализации могут быть указаны с помощью кода языка, например fr или en. Они также могут содержать региональный код, например en_US или en_GB, описывающий региональный вариант языка. Когда вы запрашиваете строку у системы i18n, системы возвращает ее используя следующий алгоритм:

- -
    -
  1. Если для текущей локализации существует файл messages.json, содержащий требуемую строку, возвращается она.
  2. -
  3. Иначе,если текущая локализация — региональный вариант (например en_US) и существует файл messages.json для этого языка, но без указания региона  (например en), содержащий строку, возвращается она.
  4. -
  5. Иначе, если существует файл messages.json для default_locale, указанной в manifest.json, и этот файл содержит нужную строку, возвращается она.
  6. -
  7. В противном случае возвращается пустая строка.
  8. -
- -

Рассмотрим следующий пример:

- - - -

Пусть default_locale установлен как fr, а текущая локализация браузера — en_GB:

- - - -

Заранее определенные сообщения

- -

Модуль i18n module предоставляет заранее определенные сообщения, которые можно вызвать таким же образом, как мы это делали в разделе {{anch("Интернационализация manifest.json")}}. Например:

- -
__MSG_extensionName__
- -

Заранее определенные сообщения используют такой же синтаксис, за исключением @@ перед именем сообщения, например:

- -
__MSG_@@ui_locale__
- -

Следующая таблица содержит различные заранее определенные сообщения:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Message nameDescription
@@extension_id -

Внутренний UUID расширения. Эту строку можно использовать для создания URL ресурсов внутри расширения.Даже нелокализованные расширения могут использовать это сообщения.

- -

Это сообщения нельзя использовать в manifest.json.

- -

Также стоит заметить, что этот ID — не ID аддона, которое возвращает {{WebExtAPIRef("runtime.id")}}, и которое может быть установлено с помощью ключа applications в manifest.json. Это сгенерированный UUID, содержащийся в URL аддона. Это означает, что данную величину нельзя использовать в качестве параметра extensionId  метода {{WebExtAPIRef("runtime.sendMessage()")}}, или для проверки поля id объекта {{WebExtAPIRef("runtime.MessageSender")}}.

-
@@ui_localeТекущая локализация; эту строку можно использовать для создания URL, зависящих от локализации.
@@bidi_dirНаправления чтения, либо "ltr" для языков, таких как английский, где текст читается слева направо, либо "rtl" для языков, считающихся справа налево, таких как арабский.
@@bidi_reversed_dirЕсли @@bidi_dir имеет значение "ltr", то возвращает "rtl"; иначе "ltr".
@@bidi_start_edgeЕсли @@bidi_dir имеет значение "ltr", то возвращает "left"; иначе "right".
@@bidi_end_edgeЕсли @@bidi_dir имеет значение "ltr", то возвращает "right"; иначе "left".
- -

Возвращаясь к нашему примеру, лучше было бы написать:

- -
header {
-  background-image: url(../images/__MSG_@@ui_locale__/header.png);
-}
- -

Теперь мы можем хранить изображения в директориях поддерживаемых локализаций — en, de, и т. д. — что выглядит логичней.

- -

Давайте рассмотрим пример использования сообщений @@bidi_* в файле CSS:

- -
body {
-  direction: __MSG_@@bidi_dir__;
-}
-
-div#header {
-  margin-bottom: 1.05em;
-  overflow: hidden;
-  padding-bottom: 1.5em;
-  padding-__MSG_@@bidi_start_edge__: 0;
-  padding-__MSG_@@bidi_end_edge__: 1.5em;
-  position: relative;
-}
- -

Для языков, в которых текст читается слева направо, таких как английский, правила CSS, использующие заранее определенные сообщения, сверху задают такие значения:

- -
direction: ltr;
-padding-left: 0;
-padding-right: 1.5em;
-
- -

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

- -
direction: rtl;
-padding-right: 0;
-padding-left: 1.5em;
- -

Тестирование расширения

- -

Начиная с Firefox 45, расширения могут быть временно установлены с диска — подробнее об этом написано в статье Loading from disk. Сделайте это и попробуйте протестировать наше расширение notify-link-clicks-i18n. Перейдите на одну из Ваших любимых страниц и нажмите на ссылку, чтобы проверить, появляется ли сообщения, содержащее URL нажатой ссылки.

- -

Затем измените локализацию Firefox на какую-либо поддерживающуюся расширением, которое Вы хотите протестировать.

- -
    -
  1. Откройте "about:config" в Firefox, и найдите параметр intl.locale.requested (обратите внимание на версию Firefox: в версиях до Firefox 59 этот параметр называется general.useragent.locale).
  2. -
  3. Если параметр существует, нажмите на него дважды (или нажмите Return/Enter), чтобы выбрать его, введите языковой код локализации, которую Вы хотите протестировать и нажмите "OK" (или Return/Enter). Например, в нашем примере расширение поддерживает "en" (английский), "de" (немецкий), "nl" (голландский), and "ja" (японский). Вы также можете указать пустую строку ("") в качестве значения. В этом случае браузер выберет язык Вашей ОС по умолчанию.
  4. -
  5. Если параметр intl.locale.requested не существует, нажмите правой кнопкой мыши на список параметров (или откройте контекстное меню при помощи клавиатуры), и выберите "New", а затем "String". Введите intl.locale.requested как имя настройки и, "de", "nl", и т. д. как значение, как это описано в шаге 2.
  6. -
  7. Найдите intl.locale.matchOS и, если параметр существует и равен true, дважды нажмите на него и установите на false.
  8. -
  9. Перезапустите браузер, чтобы изменения вступили в силу.
  10. -
- -
-

Примечание: Этот метод работает, даже если у Вас не установлен языковой пакет для выбранного языка. В этом случае UI браузера просто будет использовать Ваш язык по умолчанию.

-
- -
    -
- -
-

Примечание: Чтобы изменить результат getUILanguage требуется языковой пакет, поскольку он отражает язык UI браузера, а не язык сообщений расширения.

-
- -

Еше раз загрузите расширение с диска и протестируйте локализацию:

- - - -

{{EmbedYouTube("R7--fp5pPGg")}}

diff --git "a/files/ru/mozilla/add-ons/webextensions/\320\274\320\276\320\264\320\270\321\204\320\270\320\272\320\260\321\206\320\270\321\217_\320\262\320\265\320\261_\321\201\321\202\321\200\320\260\320\275\320\270\321\206\321\213/index.html" "b/files/ru/mozilla/add-ons/webextensions/\320\274\320\276\320\264\320\270\321\204\320\270\320\272\320\260\321\206\320\270\321\217_\320\262\320\265\320\261_\321\201\321\202\321\200\320\260\320\275\320\270\321\206\321\213/index.html" deleted file mode 100644 index 0f58364706..0000000000 --- "a/files/ru/mozilla/add-ons/webextensions/\320\274\320\276\320\264\320\270\321\204\320\270\320\272\320\260\321\206\320\270\321\217_\320\262\320\265\320\261_\321\201\321\202\321\200\320\260\320\275\320\270\321\206\321\213/index.html" +++ /dev/null @@ -1,238 +0,0 @@ ---- -title: Модификация веб страницы -slug: Mozilla/Add-ons/WebExtensions/модификация_веб_страницы -translation_of: Mozilla/Add-ons/WebExtensions/Modify_a_web_page ---- -

 

- -
{{AddonSidebar}}
- -

Одним из наиболее распространённых вариантов использования расширений является внесение изменение в веб-страницу. К примеру, расширение может изменить стиль, применённый к странице, скрыть существующие или вставить на страницу дополнительные DOM-узлы.

- -

Существует два способа сделать это используя WebExtensions API:

- - - -

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

- - - -

В этой статье мы рассмотрим оба способа загрузки скрипта.

- -

Модификация страниц, подпадающих под URL-шаблон

- -

Прежде всего создадим новую директорию, назовём её "modify-page". В этой директории, создадим файл "manifest.json", со следующим содержимым:

- -
{
-
-  "manifest_version": 2,
-  "name": "modify-page",
-  "version": "1.0",
-
-  "content_scripts": [
-    {
-      "matches": ["https://developer.mozilla.org/*"],
-      "js": ["page-eater.js"]
-    }
-  ]
-
-}
- -

Ключ content_scripts - это как мы загружаем скрипты на страницы, соответстующие URL-шаблону. В нашем случае, content_scripts говорит браузеру загрузить скрипт "page-eater.js" на все страницы, начинающиеся с https://developer.mozilla.org/.

- -
-

Поскольку свойство "js" ключа content_scripts это массив, вы можете использовать его, для внедрения более одного скрипта. Если вы сделаете это, страницы получат набор, как если бы эти скрипты были загружены самой страницей, они будут загружены в той же очерёдности, в которой они расположены в массиве.

-
- -
-

Ключ content_scripts также имеет свойство  "css", которое вы можете использовать для вставки CSS-таблиц.

-
- -

Далее, создадим файл "page-eater.js", внутри директории "modify-page":

- -
document.body.textContent = "";
-
-var header = document.createElement('h1');
-header.textContent = "Эта страница была съедена";
-document.body.appendChild(header);
- -

Теперь установим расширение, и перейдём на страницу https://developer.mozilla.org/:

- -

{{EmbedYouTube("lxf2Tkg6U1M")}}

- -
-

Обратите внимание, несмотря на то, что в указанном видео, на странице addons.mozilla.org всё работает нормально, на текущий момент, для этого сайта, контентные скрипты заблокированы.

-
- -

Программная модификация страницы

- -

Что, если вы всё еще хотите "съедать" страницы, но лишь в тех случаях, когда пользователь попросил об этом? Давайте обновим этот пример таким образом, чтобы мы внедряли контентный скрипт, когда пользователь выбирает соответствующий пункт контентного меню.

- -

Для начала обновим "manifest.json":

- -
{
-
-  "manifest_version": 2,
-  "name": "modify-page",
-  "version": "1.0",
-
-  "permissions": [
-    "activeTab",
-    "contextMenus"
-  ],
-
-  "background": {
-    "scripts": ["background.js"]
-  }
-
-}
- -

Мы удалили ключ content_scripts и добавили два новых:

- - - -

Давайте создадим этот файл. Создадим новый файл "background.js" в директории "modify-page" и поместим в него следующий код:

- -
browser.contextMenus.create({
-  id: "eat-page",
-  title: "Съесть эту страницу"
-});
-
-browser.contextMenus.onClicked.addListener(function(info, tab) {
-  if (info.menuItemId == "eat-page") {
-    browser.tabs.executeScript({
-      file: "page-eater.js"
-    });
-  }
-});
-
- -

В этом скрипте мы создаём элемент контекстного меню, передавая ему определённый идентификатор и заголовок (текст будет отображаться в элементе контекстного меню). Затем мы настраиваем обработчик событий таким образом, чтобы когда пользователь выбирает пункт контекстного меню, осуществлялась проверка, наш ли это элемент eat-page. Если это так - внедряем скрипт "page-eater.js" в текущую вкладку, используя tabs.executeScript() API. Это API опционально принимает идентификатор вкладки, в качестве аргумента. Мы опустили его, это означает, что скрипт будет внедряться в текущую активную вкладку.

- -

На данном этапе расширение должно иметь следующий вид:

- -
modify-page/
-    background.js
-    manifest.json
-    page-eater.js
- -

Теперь перезагрузим расширение, откроем страницу (на этот раз любую) активируем контекстное меню и выберем "Съесть эту страницу":

- -

{{EmbedYouTube("zX4Bcv8VctA")}}

- -
-

Обратите внимание, несмотря на то, что в указанном видео, на странице addons.mozilla.org всё работает нормально, на текущий момент, для этого сайта, контентные скрипты заблокированы.

-
- -

Обмен сообщениями

- -

Контентные и фоновые скрипты не могут на прямую взаимодействовать друг с другом. Не смотря на это они могут взаимодействовать с помощью обмена сообщениями. Для этого один конец создаёт обработчик сообщений, а другой - может посылать сообщения. В следующей таблице представлены API-интерфейсы, задействованные с каждой стороны:

- - - - - - - - - - - - - - - - - - - -
В контентном скриптеВ фоновом скрипте
Отправка сообщенияbrowser.runtime.sendMessage()browser.tabs.sendMessage()
Получение сообщенияbrowser.runtime.onMessagebrowser.runtime.onMessage
- -

Давайте обновим наш пример, чтобы посмотреть, как послать сообщение из фонового скрипта.

- -

Изменим "background.js" :

- -
browser.contextMenus.create({
-  id: "eat-page",
-  title: "Съесть эту страницу"
-});
-
-function messageTab(tabs) {
-  browser.tabs.sendMessage(tabs[0].id, {
-    replacement: "Message from the extension!"
-  });
-}
-
-browser.contextMenus.onClicked.addListener(function(info, tab) {
-  if (info.menuItemId == "eat-page") {
-    browser.tabs.executeScript({
-      file: "page-eater.js"
-    });
-
-    var querying = browser.tabs.query({
-      active: true,
-      currentWindow: true
-    });
-    querying.then(messageTab);
-  }
-});
-
- -

Теперь, после внедрения "page-eater.js", мы используем tabs.query(), чтобы получить текущую открытую вкладку и используем tabs.sendMessage(), для отправки сообщения контентному скрипту, загруженному на этой вкладке. Сообщение несёт полезную нагрузку {replacement: "Message from the extension!"}.

- -

Далее, обновим "page-eater.js":

- -
function eatPage(request, sender, sendResponse) {
-  document.body.textContent = "";
-
-  var header = document.createElement('h1');
-  header.textContent = request.replacement;
-  document.body.appendChild(header);
-}
-
-browser.runtime.onMessage.addListener(eatPage);
-
- -

Теперь, вместо простого "поедания страницы", контентный скрипт ждёт сообщение, используя runtime.onMessage. Когда сообщение получено, контентный скрипт выполняет в точности такой же код, как и а примере ранее, за исключением того, что заменяющий текст берётся из request.replacement.

- -

Если мы хотим отправить сообщение наоборот, из контентного скрипта в фоновый, настройка будет обратной данному примеру, за исключением того, что мы будем использовать runtime.sendMessage() в контентном скрипте.

- -
-

Все эти примеры внедряют JavaScript; вы можете программно внедрять стилевые таблицы CSS используя функцию tabs.insertCSS().

-
- -

Узнать больше

- - diff --git "a/files/ru/mozilla/add-ons/webextensions/\320\277\320\265\321\200\320\265\320\262\320\276\320\264/index.html" "b/files/ru/mozilla/add-ons/webextensions/\320\277\320\265\321\200\320\265\320\262\320\276\320\264/index.html" deleted file mode 100644 index 4ceb3eab28..0000000000 --- "a/files/ru/mozilla/add-ons/webextensions/\320\277\320\265\321\200\320\265\320\262\320\276\320\264/index.html" +++ /dev/null @@ -1,218 +0,0 @@ ---- -title: Отладка -slug: Mozilla/Add-ons/WebExtensions/Перевод -tags: - - Firefox - - Mozilla - - Отладка - - Пособие - - Предоставление Веб-страниц -translation_of: Mozilla/Add-ons/WebExtensions/Debugging ---- -
{{AddonSidebar}}
- -
This article explains how you can use the Firefox developer tools to debug extensions built with WebExtension APIs.
- -

An extension can consist of various different pieces — background scripts, popups, options pages, content scripts, sidebars — and you'll need to use a slightly different workflow to debug each piece. So each piece gets a top-level section in this article, and the intention is that these sections can be read in isolation. We'll begin by introducing the Add-on Debugger, which you'll use to debug most of the pieces of your extension.

- - - -

The Add-on Debugger

- -

For most of this article we'll use the Add-on Debugger. To open the Add-on Debugger:

- - - -

You'll then see a new window open. The main Firefox window will be switched into the foreground, so you'll have to click on the new window to bring it in front.

- -

{{EmbedYouTube("G2a65ewjfj0")}}

- -

This new window is sometimes called a "toolbox" and contains the debugging tools we'll use. It has a tabbed interface: the row of tabs along the top lets you switch between the different tools:

- -

- -

In this article we'll use three debugging tools:

- - - -

Debugging background scripts

- -
-

The examples in this section use the "notify-link-clicks-l10n" example extension. If you'd like to play along, you can find this example in the webextensions-examples repository.

-
- -

Background scripts stay loaded for the lifetime of the extension. They're loaded inside an invisible "background page": by default this is an empty HTML document, but you can specify your own HTML content using the "background" key in "manifest.json".

- -

You can debug background scripts using the Add-on Debugger.

- -

In the Add-on Debugger's Console you'll see logged output, including calls to console.log() from your own background scripts and any errors the browser raises as it executes them. Note that at the moment, the console shows all errors raised by the browser, not just errors related to your extensions code.

- -

For example, the notify-link-clicks-i18n example extension logs a message from its background script when it receives a message from one of its content scripts:

- -

{{EmbedYouTube("WDQsBU-rpN0")}}

- -

Using the Console's command line, you can access and modify the objects created by your background scripts.

- -

For example, here we call the notify() function defined in the extension's background script:

- -

{{EmbedYouTube("g-Qgf8Mc2wg")}}

- -

If you switch to the Debugger, you'll see all your extension's background scripts. You can set breakpoints, step through code, and do everything else you'd expect to be able to do in a debugger.

- -

{{EmbedYouTube("MNeaz2jdmzY")}}

- -

If you press the Escape key while you're in the Debugger, the toolbox will be split, with the bottom half now occupied by the Console. While you're at a breakpoint, you can now modify the program's state using the console. See Split console for more on this.

- -

Debugging options pages

- -

Options pages are HTML pages that the extension developer can supply, that contain options for the extension. They are typically displayed in an iframe in the Add-ons Manager (to see the Add-ons Manager, visit the "about:addons" page).

- -

To debug options pages:

- - - -

Any JavaScript sources it includes are then listed in the Debugger:

- -

{{EmbedYouTube("BUMG-M8tFF4")}}

- -
-

This video uses the favourite-colour example extension.

-
- -

You'll also see any messages logged by your code in the Add-on Debugger's Console.

- -

You can also use the Add-on Debugger to debug the page's HTML and CSS. First, though, you need to point the tools at the iframe that hosts the options page. To do this: open the options page, click the icon highlighted in the screenshot below, and select the options page from the drop-down list:

- -

- -

Now switch to the Inspector tab, and you'll be able to examine and edit HTML and CSS for the page:

- -

{{EmbedYouTube("-2m3ubFAU94")}}

- -

Debugging popups

- -

Popups are dialogs that are attached to browser actions or page actions. They are specified using an HTML document that can include CSS and JavaScript sources for styling and behavior. Whenever the popup is visible, you can use the Add-on Debugger to debug its code.

- -

One problem with popups is that if a popup is open and you click outside the popup, the popup is closed and its code is unloaded. This obviously makes them impossible to debug. To suppress this behavior, select Disable Popup Auto-Hide from the Elipsis menu as shown below:

- -

- -

Now, when you open a popup it will stay open until you press Escape.

- -
-

Note: This change applies to built-in browser popups, like the Elipsis menu (...), as well as extension popups.

- -

The setting does not persist across sessions. When you close the window, the setting reverts to auto-hide popups.

-Internally, this button just toggles the ui.popup.disable_autohide preference, which you can toggle manually using about:config.
- -

When the popup is open, its JavaScript sources will be listed in the Debugger. You can set breakpoints and modify the program's internal state:

- -

{{EmbedYouTube("hzwnR8qoz2I")}}

- -
-

This video uses the beastify example extension.

-
- -

You can also use the Add-on Debugger to debug the popup's HTML and CSS. First, though, you need to point the tools at the popup's document. To do this: open the popup, then click the icon highlighted in the screenshot below and select the popup's page from the drop-down list:

- -

Now switch to the Inspector, and you'll be able to examine and edit the popup's HTML and CSS:

- -

{{EmbedYouTube("6lvdm7jaq7Y")}}

- -

Debugging content scripts

- -

You can use the Add-on Debugger to debug background pages, options pages, and popups. However, you can't use it to debug content scripts. This is because, in multiprocess Firefox, content scripts run in a different process from the other parts of your extension. The browser console has similar limitations.

- -

To debug content scripts attached to a web page, use the normal web developer tools for that page:

- - - -

{{EmbedYouTube("f46hMLELyaI")}}

- -

By default, the tools are shown attached to the bottom of browser tab, to reflect the fact that they are attached to this tab. You'll see any output from console.log() statements in your content scripts. You will also see your content scripts listed in the Debugger, where you'll be able to set breakpoints, step through the code, and so on.

- -

{{EmbedYouTube("Hx3GU_fEPeo")}}

- -
-

This video uses the notify-link-clicks-i18n example extension.

-
- -
-

If the developer tools tab was not already open when the content script was injected, sometimes the content script is not listed in the debugger panel. If you experience this, reloading the page with the developer tools tab open should fix the problem.

-
- -

Debugging sidebars

- -

Sidebars are HTML pages opened as a sidebar in the browser UI that the extension developer can supply.

- -

To debug sidebars:

- - - -

Any JavaScript sources it includes are then listed in the Debugger.

- -

You'll also see any messages logged by your code in the Add-on Debugger's Console.

- -

You can also use the Add-on Debugger to debug the page's HTML and CSS. First, though, you need to point the tools at the iframe that hosts the options page. To do this: open the sidebar, click the icon highlighted in the screenshot below, and select the sidebar from the drop-down list:

- -

- -

Debug runtime permission requests

- -

 

- -

Runtime permissions granted in your extension are persistent. Therefore, if you want to test cases where the permission has not been granted you will need to add a feature to programmatically remove the permission, use the Extensions Permission Manager, or give your extension a new ID. For more information, see Retest runtime permission grants in Test permission requests.

- -

 

- -

Debugging developer tools pages & panels

- -

Developer tools are extended by loading a hidden HTML page when devtools are opened and developer tools panels are HTML pages displayed as a developer tool in the browser UI that the extension developer can supply.

- -

To debug the developer tools page:

- - - -

To debug developer tools panels:

- - - -

Any JavaScript sources it includes are then listed in the Debugger.

- -

You'll also see any messages logged by your code in the Add-on Debugger's Console.

- -

You can also use the Add-on Debugger to debug the page's HTML and CSS. First, though, you need to point the tools at the iframe that hosts the options page. To do this: open the sidebar, click the icon highlighted in the screenshot below, and select the sidebar from the drop-down list:

- -

- -

Debugging Browser Restarts

- -

If your extension is active in ways that might be affected by the browser restarting, such as a session being restored, then you may want to do extra testing to ensure your code works as expected in those conditions.

- -

See Testing persistent and restart features for more details.

-- cgit v1.2.3-54-g00ecf