thingsboard-memoizeit

Details

diff --git a/ui/src/app/app.config.js b/ui/src/app/app.config.js
index 659f53e..5a5b6b3 100644
--- a/ui/src/app/app.config.js
+++ b/ui/src/app/app.config.js
@@ -17,6 +17,7 @@ import injectTapEventPlugin from 'react-tap-event-plugin';
 import UrlHandler from './url.handler';
 import addLocaleKorean from './locale/locale.constant-ko';
 import addLocaleChinese from './locale/locale.constant-zh';
+import addLocaleRussian from './locale/locale.constant-ru';
 
 /* eslint-disable import/no-unresolved, import/default */
 
@@ -52,6 +53,8 @@ export default function AppConfig($provide,
 
     addLocaleKorean(locales);
     addLocaleChinese(locales);
+    addLocaleRussian(locales);
+
     var $window = angular.injector(['ng']).get('$window');
     var lang = $window.navigator.language || $window.navigator.userLanguage;
     if (lang === 'ko') {
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index c7cef44..1768f67 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -811,7 +811,8 @@ export default angular.module('thingsboard.locale', [])
                     "language": "Language",
                     "en_US": "English",
                     "ko_KR": "Korean",
-                    "zh_CN": "Chinese"
+                    "zh_CN": "Chinese",
+                    "ru_RU": "Russian"
                 }
             }
         }
diff --git a/ui/src/app/locale/locale.constant-ko.js b/ui/src/app/locale/locale.constant-ko.js
index ec194f7..cda7d9a 100644
--- a/ui/src/app/locale/locale.constant-ko.js
+++ b/ui/src/app/locale/locale.constant-ko.js
@@ -776,7 +776,8 @@ export default function addLocaleKorean(locales) {
             "language": "언어",
             "en_US": "영어",
             "ko_KR": "한글",
-            "zh_CN": "중국어"
+            "zh_CN": "중국어",
+            "ru_RU": "러시아어"
         }
     };
     angular.extend(locales, {'ko_KR': ko_KR});
diff --git a/ui/src/app/locale/locale.constant-ru.js b/ui/src/app/locale/locale.constant-ru.js
new file mode 100644
index 0000000..15f1068
--- /dev/null
+++ b/ui/src/app/locale/locale.constant-ru.js
@@ -0,0 +1,817 @@
+/*
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export default function addLocaleRussian(locales) {
+    var ru_RU = {
+        "access": {
+            "unauthorized": "Неавторизированный",
+            "unauthorized-access": "Несанкционированный доступ",
+            "unauthorized-access-text": "Вы должны войти в систему для получения доступа к этому ресурсу!",
+            "access-forbidden": "Доступ запрещен",
+            "access-forbidden-text": "У вас нет прав доступа к этому ресурсу!<br/>Для получения доступа попробуйте войти под другим пользователем.",
+            "refresh-token-expired": "Сессия истекла",
+            "refresh-token-failed": "Не удалось обновить сессию"
+        },
+        "action": {
+            "activate": "Активировать",
+            "suspend": "Приостановить",
+            "save": "Сохранить",
+            "saveAs": "Сохранить как",
+            "cancel": "Отмена",
+            "ok": "ОК",
+            "delete": "Удалить",
+            "add": "Добавить",
+            "yes": "Да",
+            "no": "Нет",
+            "update": "Обновить",
+            "remove": "Удалить",
+            "search": "Поиск",
+            "assign": "Присвоить",
+            "unassign": "Отменить присвоение",
+            "share": "Поделиться",
+            "make-private": "Закрыть для общего доступа",
+            "apply": "Применить",
+            "apply-changes": "Применить изменения",
+            "edit-mode": "Режим редактирования",
+            "enter-edit-mode": "Режим редактирования",
+            "decline-changes": "Отменить изменения",
+            "close": "Закрыть",
+            "back": "Назад",
+            "run": "Запуск",
+            "sign-in": "Войти",
+            "edit": "Редактировать",
+            "view": "Просмотреть",
+            "create": "Создать",
+            "drag": "Переместить",
+            "refresh": "Обновить",
+            "undo": "Откатить",
+            "copy": "Копировать",
+            "paste": "Вставить",
+            "import": "Импортировать",
+            "export": "Экспортировать",
+            "share-via": "Поделиться в {{provider}}"
+        },
+        "aggregation": {
+            "aggregation": "Агрегация",
+            "function": "Тип агрегации данных",
+            "limit": "Максимальное значение",
+            "group-interval": "Интервал группировки",
+            "min": "Мин",
+            "max": "Maкс",
+            "avg": "Среднее",
+            "sum": "Сумма",
+            "count": "Количество",
+            "none": "Без агрегации"
+        },
+        "admin": {
+            "general": "Общие",
+            "general-settings": "Общие настройки",
+            "outgoing-mail": "Исходящая почта",
+            "outgoing-mail-settings": "Настройки исходящей почты",
+            "system-settings": "Системные настройки",
+            "test-mail-sent": "Пробное письмо успешно отправлено!",
+            "base-url": "Базовая URL",
+            "base-url-required": "Базовая URL обязательна.",
+            "mail-from": "Отправитель",
+            "mail-from-required": "Отправитель обязателен.",
+            "smtp-protocol": "SMTP протокол",
+            "smtp-host": "SMTP хост",
+            "smtp-host-required": "SMTP хост обязателен.",
+            "smtp-port": "SMTP порт",
+            "smtp-port-required": "SMTP порт обязателен.",
+            "smtp-port-invalid": "Недействительный SMTP порт.",
+            "timeout-msec": "Таймаут (мс)",
+            "timeout-required": "Таймаут обязателен.",
+            "timeout-invalid": "Недействительный таймаут.",
+            "enable-tls": "Включить TLS",
+            "send-test-mail": "Отправить пробное письмо"
+        },
+        "attribute": {
+            "attributes": "Атрибуты",
+            "latest-telemetry": "Последняя телеметрия",
+            "attributes-scope": "Контекст атрибутов устройства",
+            "scope-latest-telemetry": "Последняя телеметрия",
+            "scope-client": "Клиентские атрибуты",
+            "scope-server": "Серверные атрибуты",
+            "scope-shared": "Общие атрибуты",
+            "add": "Добавить атрибут",
+            "key": "Ключ",
+            "key-required": "Ключ атрибута обязателен.",
+            "value": "Значение",
+            "value-required": "Значение атрибута обязательно.",
+            "delete-attributes-title": "Вы уверенны, что хотите удалить { count, plural, one {1 атрибут} few {# атрибута} other {# атрибутов} }? ",
+            "delete-attributes-text": "Внимание, после подтверждения выбранные атрибуты будут удалены.",
+            "delete-attributes": "Удалить атрибуты",
+            "enter-attribute-value": "Введите значение атрибута",
+            "show-on-widget": "Показать на виджете",
+            "widget-mode": "Виджет-режим",
+            "next-widget": "Следующий виджет",
+            "prev-widget": "Предыдущий виджет",
+            "add-to-dashboard": "Добавить на дашборд",
+            "add-widget-to-dashboard": "Добавить виджет на дашборд",
+            "selected-attributes": "{ count, plural, 1 {Выбран} other {Выбраны} } { count, plural, one {1 атрибут} few {# атрибута} other {# атрибутов} }",
+            "selected-telemetry": "{ count, plural, 1 {Выбран} other {Выбраны} } { count, plural, 1 {1 параметр} few {# параметра} other {# параметров} } телеметрии"
+        },
+        "confirm-on-exit": {
+            "message": "У вас есть несохраненные изменения. Вы точно хотите покинуть эту страницу?",
+            "html-message": "У вас есть несохраненные изменения.<br/>Вы точно хотите покинуть эту страницу?",
+            "title": "Несохраненные изменения"
+        },
+        "contact": {
+            "country": "Страна",
+            "city": "Город",
+            "state": "Штат",
+            "postal-code": "Почтовый код",
+            "postal-code-invalid": "Допустимы только цифры",
+            "address": "Адрес",
+            "address2": "Адрес 2",
+            "phone": "Телефон",
+            "email": "Эл. адрес",
+            "no-address": "Адрес не указан"
+        },
+        "common": {
+            "username": "Имя пользователя",
+            "password": "Пароль",
+            "enter-username": "Введите имя пользователя",
+            "enter-password": "Введите пароль",
+            "enter-search": "Введите условие поиска"
+        },
+        "customer": {
+            "customers": "Клиенты",
+            "management": "Управление клиентами",
+            "dashboard": "Дашборд клиентов",
+            "dashboards": "Дашборды клиентов",
+            "devices": "Устройства клиента",
+            "public-dashboards": "Общедоступные дашборды",
+            "public-devices": "Общедоступные устройства",
+            "add": "Добавить клиента",
+            "delete": "Удалить клиента",
+            "manage-customer-users": "Управление пользователями клиента",
+            "manage-customer-devices": "Управление устройствами клиента",
+            "manage-customer-dashboards": "Управление дашбордами клиента",
+            "manage-public-devices": "Управление общедоступными устройствами",
+            "manage-public-dashboards": "Управление общедоступными дашбордами",
+            "add-customer-text": "Добавить нового клиента",
+            "no-customers-text": "Клиенты не найдены",
+            "customer-details": "Подробности о клиенте",
+            "delete-customer-title": "Вы точно хотите удалить клиента '{{customerTitle}}'?",
+            "delete-customer-text": "Внимание, после подтверждения клиент и вся связанная с ним информация будут безвозвратно утеряны.",
+            "delete-customers-title": "Вы точно хотите удалить { count, plural, one {1 клиента} other {# клиентов} }?",
+            "delete-customers-action-title": "Удалить { count, plural, one {1 клиента} other {# клиентов} } }",
+            "delete-customers-text": "Внимание, после подтверждения клиенты и вся связанная с ними информация будут безвозвратно утеряны.",
+            "manage-users": "Управление пользователями",
+            "manage-devices": "Управление устройствами",
+            "manage-dashboards": "Управление дашбордами",
+            "title": "Имя",
+            "title-required": "Название обязательно.",
+            "description": "Описание"
+        },
+        "datetime": {
+            "date-from": "Дата с",
+            "time-from": "Время с",
+            "date-to": "Дата до",
+            "time-to": "Время до"
+        },
+        "dashboard": {
+            "dashboard": "Дашборд",
+            "dashboards": "Дашборды",
+            "management": "Управление дашбордами",
+            "view-dashboards": "Просмотреть дашборды",
+            "add": "Добавить дашборд",
+            "assign-dashboard-to-customer": "Прикрепить дашборд(ы) к клиенту",
+            "assign-dashboard-to-customer-text": "Пожалуйста, выберите дашборды, которые нужно прикрепить к клиенту",
+            "assign-to-customer-text": "Пожалуйста, выберите клиента, к которому нужно прикрепить дашборд(ы)",
+            "assign-to-customer": "Прикрепить к клиенту",
+            "unassign-from-customer": "Открепить от клиента",
+            "make-public": "Открыть дашборд для общего доступа",
+            "make-private": "Закрыть дашборд для общего доступа",
+            "no-dashboards-text": "Дашборды не найдены",
+            "no-widgets": "Виджеты не сконфигурированы",
+            "add-widget": "Добавить новый виджет",
+            "title": "Название",
+            "select-widget-title": "Выберите виджет",
+            "select-widget-subtitle": "Список доступных виджетов",
+            "delete": "Удалить дашборд",
+            "title-required": "Название обязательно.",
+            "description": "Описание",
+            "details": "Подробности",
+            "dashboard-details": "Подробности о дашборде",
+            "add-dashboard-text": "Добавить новый дашборд",
+            "assign-dashboards": "Прикрепить дашборды",
+            "assign-new-dashboard": "Прикрепить новый дашборд",
+            "assign-dashboards-text": "Прикрепить { count, plural, 1 {1 дашборд} other {# дашборда} } к клиенту",
+            "delete-dashboards": "Удалить дашборды",
+            "unassign-dashboards": "Открепить дашборды",
+            "unassign-dashboards-action-title": "Открепить { count, plural, one {1 дашборд} few {# дашборда} other {# дашбордов} } от клиента",
+            "delete-dashboard-title": "Вы точно хотите удалить дашборд '{{dashboardTitle}}'?",
+            "delete-dashboard-text": "Внимание, после подтверждения дашборд и все связанные с ним данные будут безвозвратно утеряны.",
+            "delete-dashboards-title": "Вы точно хотите удалить { count, plural, one {1 дашборд} few {# дашборда} other {# дашбордов} }?",
+            "delete-dashboards-action-title": "Удалить { count, plural, one {1 дашборд} few {# дашборда} other {# дашбордов} }",
+            "delete-dashboards-text": "Внимание, после подтверждения дашборды и все связанные с ними данные будут безвозвратно утеряны.",
+            "unassign-dashboard-title": "Вы точно хотите открепить дашборд '{{dashboardTitle}}'?",
+            "unassign-dashboard-text": "После подтверждения дашборд не будет доступен клиенту.",
+            "unassign-dashboard": "Открепить дашборд",
+            "unassign-dashboards-title": "Вы точно хотите открепить { count, plural, one {1 дашборд} few {# дашборда} other {# дашбордов} }?",
+            "unassign-dashboards-text": "После подтверждения выбранные дашборды не будут доступны клиенту.",
+            "public-dashboard-title": "Теперь дашборд общедоступный",
+            "public-dashboard-text": "Теперь ваш дашборд <b>{{dashboardTitle}}</b> доступен всем по <a href='{{publicLink}}' target='_blank'>ссылке</a>:",
+            "public-dashboard-notice": "<b>Примечание:</b> Для получения доступа к данным устройства нужно открыть общий доступ к этому устройству.",
+            "make-private-dashboard-title": "Вы точно хотите закрыть общий доступ к дашборду '{{dashboardTitle}}'?",
+            "make-private-dashboard-text": "После подтверждения дашборд будет закрыт для общего доступа.",
+            "make-private-dashboard": "Закрыть дашборд для общего доступа",
+            "socialshare-text": "'{{dashboardTitle}}' сделано ThingsBoard",
+            "socialshare-title": "'{{dashboardTitle}}' сделано ThingsBoard",
+            "select-dashboard": "Выберите дашборд",
+            "no-dashboards-matching": "Дашборд '{{dashboard}}' не найден.",
+            "dashboard-required": "Дашборд обязателен.",
+            "select-existing": "Выберите существующий дашборд",
+            "create-new": "Создать новый дашборд",
+            "new-dashboard-title": "Новое название дашборда",
+            "open-dashboard": "Открыть дашборд",
+            "set-background": "Установить фон",
+            "background-color": "Фоновый цвет",
+            "background-image": "Фоновая картинка",
+            "background-size-mode": "Размер фона",
+            "no-image": "Картинка не выбрана",
+            "drop-image": "Перетащите картинку или кликните для выбора файла.",
+            "settings": "Настройки",
+            "columns-count": "Количество колонок",
+            "columns-count-required": "Количество колонок обязательно.",
+            "min-columns-count-message": "Минимальное число колонок - 10.",
+            "max-columns-count-message": "Максимальное число колонок - 1000.",
+            "widgets-margins": "Величина отступа между виджетами",
+            "horizontal-margin": "Величина горизонтального отступа",
+            "horizontal-margin-required": "Величина горизонтального отступа обязательна.",
+            "min-horizontal-margin-message": "Минимальная величина горизонтального отступа - 0.",
+            "max-horizontal-margin-message": "Максимальная величина горизонтального отступа - 50.",
+            "vertical-margin": "Величина вертикального отступа",
+            "vertical-margin-required": "Величина вертикального отступа обязательна.",
+            "min-vertical-margin-message": "Минимальная величина вертикального отступа - 0.",
+            "max-vertical-margin-message": "Максимальная величина вертикального отступа - 50.",
+            "display-title": "Показать название дашборда",
+            "title-color": "Цвет названия",
+            "display-device-selection": "Показать выборку устройств",
+            "display-dashboard-timewindow": "Показать временное окно",
+            "display-dashboard-export": "Показать экспорт",
+            "import": "Импортировать дашборд",
+            "export": "Экспортировать дашборд",
+            "export-failed-error": "Не удалось экспортировать дашборд: {{error}}",
+            "create-new-dashboard": "Создать новый дашборд",
+            "dashboard-file": "Файл дашборда",
+            "invalid-dashboard-file-error": "Не удалось импортировать дашборд: неизвестная схема данных дашборда.",
+            "dashboard-import-missing-aliases-title": "Конфигурировать псевдонимы импортированного дашборда",
+            "create-new-widget": "Создать новый виджет",
+            "import-widget": "Импортировать новый виджет",
+            "widget-file": "Файл виджета",
+            "invalid-widget-file-error": "Не удалось импортировать виджет: неизвестная схема данных виджета.",
+            "widget-import-missing-aliases-title": "Конфигурировать псевдонимы импортированного виджета",
+            "open-toolbar": "Открыть панель инструментов",
+            "close-toolbar": "Закрыть панель инструментов",
+            "configuration-error": "Ошибка конфигурирования",
+            "alias-resolution-error-title": "Ошибка конфигурирования псевдонимов дашборда",
+            "invalid-aliases-config": "Не удалось найти устройства, соответствующие фильтру псевдонимов.<br/>" +
+                                      "Пожалуйста, свяжитесь с администратором для устранения этой проблемы.",
+            "select-devices": "Выберите устройства",
+            "assignedToCustomer": "Прикреплен к клиенту",
+            "public": "Общедоступный",
+            "public-link": "Общедоступная ссылка",
+            "copy-public-link": "Скопировать общедоступную ссылку",
+            "public-link-copied-message": "Общедоступная ссылка на дашборд скопирована в буфер обмена"
+        },
+        "datakey": {
+            "settings": "Настройки",
+            "advanced": "Дополнительно",
+            "label": "Метка",
+            "color": "Цвет",
+            "data-generation-func": "Функция генерации данных",
+            "use-data-post-processing-func": "Использовать функцию пост-обработки данных",
+            "configuration": "Конфигурация ключа данных",
+            "timeseries": "Выборка по времени",
+            "attributes": "Атрибуты",
+            "timeseries-required": "Выборка по времени обязательна.",
+            "timeseries-or-attributes-required": "Выборка по времени/атрибуты обязательны.",
+            "function-types": "Тип функции",
+            "function-types-required": "Тип функции обязателен."
+        },
+        "datasource": {
+            "type": "Тип источника данных",
+            "add-datasource-prompt": "Пожалуйста, добавьте источник данных"
+        },
+        "details": {
+            "edit-mode": "Режим редактирования",
+            "toggle-edit-mode": "Режим редактирования"
+        },
+        "device": {
+            "device": "Устройство",
+            "device-required": "Устройство обязательно.",
+            "devices": "Устройства",
+            "management": "Управление устройствами",
+            "view-devices": "Просмотреть устройства",
+            "device-alias": "Псевдоним устройства",
+            "aliases": "Псевдонимы устройства",
+            "no-alias-matching": "'{{alias}}' не найден.",
+            "no-aliases-found": "Псевдонимы не найдены.",
+            "no-key-matching": "'{{key}}' не найден.",
+            "no-keys-found": "Ключи не найдены.",
+            "create-new-alias": "Создать новый!",
+            "create-new-key": "Создать новый!",
+            "duplicate-alias-error": "Найден дублирующийся псевдоним '{{alias}}'.<br>В рамках дашборда псевдонимы устройств должны быть уникальными.",
+            "configure-alias": "Конфигурировать '{{alias}}' псевдоним",
+            "no-devices-matching": "Устройство '{{device}}' не найдено.",
+            "alias": "Псевдоним",
+            "alias-required": "Псевдоним устройства обязателен.",
+            "remove-alias": "Удалить псевдоним устройства",
+            "add-alias": "Добавить псевдоним устройства",
+            "name-starts-with": "Название начинается с",
+            "device-list": "Список устройств",
+            "use-device-name-filter": "Использовать фильтр",
+            "device-list-empty": "Устройства не выбраны.",
+            "device-name-filter-required": "Фильтр названия устройства обязателен.",
+            "device-name-filter-no-device-matched": "Устройства, названия которых начинаются с '{{device}}', не найдены.",
+            "add": "Добавить устройство",
+            "assign-to-customer": "Присвоить клиенту",
+            "assign-device-to-customer": "Присвоить устройство(а) клиенту",
+            "assign-device-to-customer-text": "Пожалуйста, выберите устройства, которые нужно присвоить клиенту",
+            "make-public": "Открыть общий доступ к устройству",
+            "make-private": "Закрыть общий доступ к устройству",
+            "no-devices-text": "Устройства не найдены",
+            "assign-to-customer-text": "Пожалуйста, выберите клиента, которому нужно присвоить устройство(а)",
+            "device-details": "Подробности об устройстве",
+            "add-device-text": "Добавить новое устройство",
+            "credentials": "Учетные данные",
+            "manage-credentials": "Управление учетными данными",
+            "delete": "Удалить устройство",
+            "assign-devices": "Присвоить устройство",
+            "assign-devices-text": "Присвоить { count, plural, one {1 устройство} few {# устройства} other {# устройств} } клиенту",
+            "delete-devices": "Удалить устройства",
+            "unassign-from-customer": "Отменить присвоение клиенту",
+            "unassign-devices": "Отменить присвоение устройств",
+            "unassign-devices-action-title": "Отменить присвоение { count, plural, one {1 устройства} few {# устройств} other {# устройств} } клиенту",
+            "assign-new-device": "Присвоить новое устройство",
+            "make-public-device-title": "Вы точно хотите открыть общий доступ к устройству '{{deviceName}}'?",
+            "make-public-device-text": "После подтверждения устройство и все связанные с ним данные будут общедоступными.",
+            "make-private-device-title": "Вы точно хотите закрыть общий доступ к устройству '{{deviceName}}'",
+            "make-private-device-text": "После подтверждения устройство и все связанные с ним данные будут закрыты для общего доступа.",
+            "view-credentials": "Просмотреть учетные данные",
+            "delete-device-title": "Вы точно хотите удалить устройство '{{deviceName}}'?",
+            "delete-device-text": "Внимание, после подтверждения устройство и все связанные с ним данные будут безвозвратно утеряны.",
+            "delete-devices-title": "Вы точно хотите удалить { count, plural, one {1 устройство} few {# устройства} other {# устройств} }?",
+            "delete-devices-action-title": "Удалить { count, plural, one {1 устройство} few {# устройства} other {# устройств} } }",
+            "delete-devices-text": "Внимание, после подтверждения выбранные устройства и все связанные с ними данные будут безвозвратно утеряны..",
+            "unassign-device-title": "Вы точно хотите отменить присвоение устройства '{{deviceName}}'?",
+            "unassign-device-text": "После подтверждения устройство будет недоступно клиенту.",
+            "unassign-device": "Отменить присвоение устройства",
+            "unassign-devices-title": "Вы точно хотите отменить присвоение { count, plural, one {1 устройство} few {# устройства} other {# устройств} } }?",
+            "unassign-devices-text": "После подтверждения выбранные устройства будут недоступны клиенту.",
+            "device-credentials": "Учетные данные устройства",
+            "credentials-type": "Тип учетных данных",
+            "access-token": "Токен",
+            "access-token-required": "Токен обязателен.",
+            "access-token-invalid": "Длина токена должна быть от 1 до 20 символов.",
+            "rsa-key": "Открытый ключ RSA",
+            "rsa-key-required": "Открытый ключ RSA обязателен.",
+            "secret": "Секрет",
+            "secret-required": "Секрет обязателен.",
+            "name": "Название",
+            "name-required": "Название обязательно.",
+            "description": "Описание",
+            "events": "События",
+            "details": "Подробности",
+            "copyId": "Копировать идентификатор устройства",
+            "copyAccessToken": "Копировать токен",
+            "idCopiedMessage": "Идентификатор устройства скопирован в буфер обмена",
+            "accessTokenCopiedMessage": "Токен устройства скопирован в буфер обмена",
+            "assignedToCustomer": "Присвоен клиенту",
+            "unable-delete-device-alias-title": "Не удалось удалить псевдоним устройства",
+            "unable-delete-device-alias-text": "Не удалось удалить псевдоним '{{deviceAlias}}' устройства, т.к. он используется следующими виджетами:<br/>{{widgetsList}}",
+            "is-gateway": "Гейтвей",
+            "public": "Общедоступный",
+            "device-public": "Устройство общедоступно"
+        },
+        "dialog": {
+            "close": "Закрыть диалог"
+        },
+        "error": {
+            "unable-to-connect": "Не удалось подключиться к серверу! Пожалуйста, проверьте интернет-соединение.",
+            "unhandled-error-code": "Код необработанной ошибки: {{errorCode}}",
+            "unknown-error": "Неизвестная ошибка"
+        },
+        "event": {
+            "event-type": "Тип события",
+            "type-alarm": "Аварийное оповещение",
+            "type-error": "Ошибка",
+            "type-lc-event": "Событие жизненного цикла",
+            "type-stats": "Статистика",
+            "no-events-prompt": "События не найдены",
+            "error": "Ошибка",
+            "alarm": "Аварийное оповещение",
+            "event-time": "Время возникновения события",
+            "server": "Сервер",
+            "body": "Тело",
+            "method": "Метод",
+            "event": "Событие",
+            "status": "Статус",
+            "success": "Успех",
+            "failed": "Неудача",
+            "messages-processed": "Сообщения обработаны",
+            "errors-occurred": "Возникли ошибки"
+        },
+        "fullscreen": {
+            "expand": "Во весь экран",
+            "exit": "Выйти из полноэкранного режима",
+            "toggle": "Во весь экран",
+            "fullscreen": "Полноэкранный режим"
+        },
+        "function": {
+            "function": "Функция"
+        },
+        "grid": {
+            "delete-item-title": "Вы точно хотите удалить этот объект?",
+            "delete-item-text": "Внимание, после подтверждения объект и все связанные с ним данные будут безвозвратно утеряны.",
+            "delete-items-title": "Вы точно хотите удалить { count, plural, one {1 объект} few {# объекта} other {# объектов} }?",
+            "delete-items-action-title": "Удалить { count, plural, one {1 объект} few {# объекта} other {# объектов}",
+            "delete-items-text": "Внимание, после подтверждения выбранные объекты и все связанные с ними данные будут безвозвратно утеряны.",
+            "add-item-text": "Добавить новый объект",
+            "no-items-text": "Объекты не найдены",
+            "item-details": "Подробности об объекте",
+            "delete-item": "Удалить объект",
+            "delete-items": "Удалить объекты",
+            "scroll-to-top": "Прокрутка к началу"
+        },
+        "help": {
+            "goto-help-page": "Перейти к справке"
+        },
+        "home": {
+            "home": "Главная",
+            "profile": "Профиль",
+            "logout": "Выйти из системы",
+            "menu": "Меню",
+            "avatar": "Аватар",
+            "open-user-menu": "Открыть меню пользователя"
+        },
+        "import": {
+            "no-file": "Файл не выбран",
+            "drop-file": "Перетащите JSON файл или кликните для выбора файла."
+        },
+        "item": {
+            "selected": "Выбранные"
+        },
+        "js-func": {
+            "no-return-error": "Функция должна возвращать значение!",
+            "return-type-mismatch": "Функция должна возвращать значение типа '{{type}}'!"
+        },
+        "legend": {
+            "position": "Расположение легенды",
+            "show-max": "Показать максимальное значение",
+            "show-min": "Показать минимальное значение",
+            "show-avg": "Показать среднее значение",
+            "show-total": "Показать сумму",
+            "settings": "Настройки легенды",
+            "min": "Мин",
+            "max": "Макс",
+            "avg": "Среднее",
+            "total": "Сумма"
+        },
+        "login": {
+            "login": "Войти",
+            "request-password-reset": "Запрос на сброс пароля",
+            "reset-password": "Сбросить пароль",
+            "create-password": "Создать пароль",
+            "passwords-mismatch-error": "Введенные пароли должны быть одинаковыми!",
+            "password-again": "Введите пароль еще раз",
+            "sign-in": "Пожалуйста, войдите в систему",
+            "username": "Имя пользователя (эл. адрес)",
+            "remember-me": "Запомнить меня",
+            "forgot-password": "Забыли пароль?",
+            "password-reset": "Пароль сброшен",
+            "new-password": "Новый пароль",
+            "new-password-again": "Повторите новый пароль",
+            "password-link-sent-message": "Ссылка для сброса пароля была успешно отправлена!",
+            "email": "Эл. адрес"
+        },
+        "plugin": {
+            "plugins": "Плагины",
+            "delete": "Удалить плагин",
+            "activate": "Активировать плагин",
+            "suspend": "Приостановить плагин",
+            "active": "Активный",
+            "suspended": "Приостановлен",
+            "name": "Название",
+            "name-required": "Название обязательно.",
+            "description": "Описание",
+            "add": "Добавить плагин",
+            "delete-plugin-title": "Вы точно хотите удалить плагин '{{pluginName}}'?",
+            "delete-plugin-text": "Внимание, после подтверждения плагин и все связанные с ним данные будут безвозвратно утеряны.",
+            "delete-plugins-title": "Вы точно хотите удалить { count, plural, one {1 плагин} few {# плагина} other {# плагинов} }?",
+            "delete-plugins-action-title": "Удалить { count, plural, one {1 плагин} few {# плагина} other {# плагинов} } }",
+            "delete-plugins-text": "Внимание, после подтверждения выбранные плагины и все связанные с ними данные будут безвозвратно утеряны.",
+            "add-plugin-text": "Добавить новый плагин",
+            "no-plugins-text": "Плагины не найдены",
+            "plugin-details": "Подробности о плагине",
+            "api-token": "API токен",
+            "api-token-required": "API токен обязателен.",
+            "type": "Тип плагина",
+            "type-required": "Тип плагина обязателен.",
+            "configuration": "Настройки плагина",
+            "system": "Системный",
+            "select-plugin": "Выберите плагин",
+            "plugin": "Плагин",
+            "no-plugins-matching": "Плагин '{{plugin}}' не найден.",
+            "plugin-required": "Плагин обязателен.",
+            "plugin-require-match": "Пожалуйста, выберите существующий плагин.",
+            "events": "События",
+            "details": "Подробности",
+            "import": "Импортировать плагин",
+            "export": "Экспортировать плагин",
+            "export-failed-error": "Не удалось экспортировать плагин: {{error}}",
+            "create-new-plugin": "Создать новый плагин",
+            "plugin-file": "Файл плагина",
+            "invalid-plugin-file-error": "Не удалось импортировать плагин: неизвестная схема данных плагина."
+        },
+        "position": {
+            "top": "Верх",
+            "bottom": "Низ",
+            "left": "Левый край",
+            "right": "Правый край"
+        },
+        "profile": {
+            "profile": "Профиль",
+            "change-password": "Изменить пароль",
+            "current-password": "Текущий пароль"
+        },
+        "rule": {
+            "rules": "Правила",
+            "delete": "Удалить правило",
+            "activate": "Активировать правило",
+            "suspend": "Приостановить правило",
+            "active": "Активное",
+            "suspended": "Приостановлены",
+            "name": "Название",
+            "name-required": "Название обязательно.",
+            "description": "Описание",
+            "add": "Добавить правило",
+            "delete-rule-title": "Вы точно хотите удалить правило '{{ruleName}}'?",
+            "delete-rule-text": "Внимание, после подтверждения правило и все связанные с ним данные будут безвозвратно утеряны.",
+            "delete-rules-title": "Вы точно хотите удалить { count, plural, one {1 правило} few {# правила} other {# правил} }?",
+            "delete-rules-action-title": "Удалить { count, plural, one {1 правило} few {# правила} other {# правил} }",
+            "delete-rules-text": "Внимание, после подтверждения выбранные правила и все связанные с ними данные будут безвозвратно утеряны.",
+            "add-rule-text": "Добавить новое правило",
+            "no-rules-text": "Правила не найдены",
+            "rule-details": "Подробности о правиле",
+            "filters": "Фильтры",
+            "filter": "Фильтр",
+            "add-filter-prompt": "Пожалуйста, добавьте фильтр",
+            "remove-filter": "Удалить фильтр",
+            "add-filter": "Добавить фильтр",
+            "filter-name": "Название фильтра",
+            "filter-type": "Тип фильтра",
+            "edit-filter": "Редактировать фильтр",
+            "view-filter": "Просмотреть фильтр",
+            "component-name": "Название",
+            "component-name-required": "Название обязательно.",
+            "component-type": "Тип",
+            "component-type-required": "Тип обязателен.",
+            "processor": "Обработчик",
+            "no-processor-configured": "Обработчики не сконфигурированы",
+            "create-processor": "Создать обработчик",
+            "processor-name": "Название обработчика",
+            "processor-type": "Тип обработчика",
+            "plugin-action": "Действие плагина",
+            "action-name": "Название действия",
+            "action-type": "Тип действия",
+            "create-action-prompt": "Пожалуйста, создайте действие",
+            "create-action": "Создать действие",
+            "details": "Подробности",
+            "events": "События",
+            "system": "Системное",
+            "import": "Импортировать правило",
+            "export": "Экспортировать правило",
+            "export-failed-error": "Не удалось экспортировать правило: {{error}}",
+            "create-new-rule": "Создать новое правило",
+            "rule-file": "Файл правила",
+            "invalid-rule-file-error": "Не удалось импортировать правило: неизвестная схема данных правила."
+        },
+        "rule-plugin": {
+            "management": "Управление плагинами и правилами"
+        },
+        "tenant": {
+            "tenants": "Владельцы",
+            "management": "Управление владельцами",
+            "add": "Добавить владельца",
+            "admins": "Администраторы",
+            "manage-tenant-admins": "Управление администраторами владельца",
+            "delete": "Удалить владельца",
+            "add-tenant-text": "Добавить нового владельца",
+            "no-tenants-text": "Владельцы не найдены",
+            "tenant-details": "Подробности об владельце",
+            "delete-tenant-title": "Вы точно хотите удалить владельца '{{tenantTitle}}'?",
+            "delete-tenant-text": "Внимание, после подтверждения владелец и все связанные с ним данные будут безвозвратно утеряны.",
+            "delete-tenants-title": "Вы точно хотите удалить { count, plural, one {1 владельца}  other {# владельцев} }?",
+            "delete-tenants-action-title": "Удалить { count, plural, one {1 владельца}  other {# владельцев} }",
+            "delete-tenants-text": "Внимание, после подтверждения выбранные Владельцы и все связанные с ними данные будут безвозвратно утеряны.",
+            "title": "Имя",
+            "title-required": "Имя обязательно.",
+            "description": "Описание"
+        },
+        "timeinterval": {
+            "seconds-interval": "{ seconds, plural, one {1 секунда} few {# секунды} other {# секунд} }",
+            "minutes-interval": "{ minutes, plural, one {1 минута} few {# минуты} other {# минут} }",
+            "hours-interval": "{ hours, plural, one {1 час} few {# часа} other {# часов} }",
+            "days-interval": "{ days, plural, one {1 день} few {# дня} other {# дней} }",
+            "days": "Дни",
+            "hours": "Часы",
+            "minutes": "Минуты",
+            "seconds": "Секунды",
+            "advanced": "Дополнительно"
+        },
+        "timewindow": {
+            "days": "{ days, plural, one {1 день} few {# дня} other {# дней} }",
+            "hours": "{ hours, plural, one {1 час} few {# часа} other {# часов} }",
+            "minutes": "{ minutes, plural, one {1 минута} few {# минуты} other {# минут} }",
+            "seconds": "{ seconds, plural, one {1 секунда} few {# секунды} other {# секунд} }",
+            "realtime": "Режим реального времени",
+            "history": "История",
+            "last-prefix": "Последние",
+            "period": "с {{ startTime }} до {{ endTime }}",
+            "edit": "Изменить временное окно",
+            "date-range": "Диапазон дат",
+            "last": "Последние",
+            "time-period": "Период времени"
+        },
+        "user": {
+            "users": "Пользователи",
+            "customer-users": "Пользователи клиента",
+            "tenant-admins": "Администраторы владельца",
+            "sys-admin": "Системный администратор",
+            "tenant-admin": "Администратор владельца",
+            "customer": "Клиент",
+            "anonymous": "Аноним",
+            "add": "Добавить пользователя",
+            "delete": "Удалить пользователя",
+            "add-user-text": "Добавить нового пользователя",
+            "no-users-text": "Пользователи не найдены",
+            "user-details": "Подробности о пользователе",
+            "delete-user-title": "Вы точно хотите удалить пользователя '{{userEmail}}'?",
+            "delete-user-text": "Внимание, после подтверждения пользователь и все связанные с ним данные будут безвозвратно утеряны.",
+            "delete-users-title": "Вы точно хотите удалить { count, plural, one {1 пользователя} other {# пользователей} }?",
+            "delete-users-action-title": "Удалить { count, plural, one {1 пользователя} other {# пользователей} }",
+            "delete-users-text": "Внимание, после подтверждения выбранные пользователи и все связанные с ними данные будут безвозвратно утеряны.",
+            "activation-email-sent-message": "Активационное письмо успешно отправлено!",
+            "resend-activation": "Повторить отправку активационного письма",
+            "email": "Эл. адрес",
+            "email-required": "Эл. адрес обязателен.",
+            "first-name": "Имя",
+            "last-name": "Фамилия",
+            "description": "Описание",
+            "default-dashboard": "Дашборд по умолчанию",
+            "always-fullscreen": "Всегда во весь экран"
+        },
+        "value": {
+            "type": "Тип значения",
+            "string": "Строка",
+            "string-value": "Строковое значение",
+            "integer": "Целое число",
+            "integer-value": "Целочисленное значение",
+            "invalid-integer-value": "Неправильный формат целого числа",
+            "double": "Число двойной точности",
+            "double-value": "Значение двойной точности",
+            "boolean": "Логический тип",
+            "boolean-value": "Логическое значение",
+            "false": "Ложь",
+            "true": "Правда"
+        },
+        "widget": {
+            "widget-library": "Галерея виджетов",
+            "widget-bundle": "Набор виджетов",
+            "select-widgets-bundle": "Выберите набор виджетов",
+            "management": "Управление виджетами",
+            "editor": "Редактор виджетов",
+            "widget-type-not-found": "Ошибка при загрузке конфигурации виджета.<br>Возможно, связанный с ней\n    тип виджета уже удален.",
+            "widget-type-load-error": "Не удалось загрузить виджет по следующим причинам:",
+            "remove": "Удалить виджет",
+            "edit": "Редактировать виджет",
+            "remove-widget-title": "Вы точно хотите удалить виджет '{{widgetTitle}}'?",
+            "remove-widget-text": "Внимание, после подтверждения виджет и все связанные с ним данные будут безвозвратно утеряны.",
+            "timeseries": "Выборка по времени",
+            "latest-values": "Последние значения",
+            "rpc": "Управляющий виджет",
+            "static": "Статический виджет",
+            "select-widget-type": "Выберите тип виджета",
+            "missing-widget-title-error": "Укажите название виджета!",
+            "widget-saved": "Виджет сохранен",
+            "unable-to-save-widget-error": "Не удалось сохранить виджет! Виджет содержит ошибки!",
+            "save": "Сохранить виджет",
+            "saveAs": "Сохранить виджет как",
+            "save-widget-type-as": "Сохранить тип виджета как",
+            "save-widget-type-as-text": "Пожалуйста, введите название виджета и/или укажите целевой набор виджетов",
+            "toggle-fullscreen": "Во весь экран",
+            "run": "Запустить виджет",
+            "title": "Название виджета",
+            "title-required": "Название виджета обязательно.",
+            "type": "Тип виджета",
+            "resources": "Ресурсы",
+            "resource-url": "JavaScript/CSS URL",
+            "remove-resource": "Удалить ресурс",
+            "add-resource": "Добавить ресурс",
+            "html": "HTML",
+            "tidy": "Форматировать",
+            "css": "CSS",
+            "settings-schema": "Схема конфигурации",
+            "datakey-settings-schema": "Схема конфигурации ключа данных",
+            "javascript": "Javascript",
+            "remove-widget-type-title": "Вы точно хотите удалить виджет '{{widgetName}}'?",
+            "remove-widget-type-text": "Внимание, после подтверждения тип виджета и все связанные с ним данные будут безвозвратно утеряны.",
+            "remove-widget-type": "Удалить тип виджета",
+            "add-widget-type": "Добавить новый тип виджета",
+            "widget-type-load-failed-error": "Не удалось загрузить тип виджета!",
+            "widget-template-load-failed-error": "Не удалось загрузить шаблон виджета!",
+            "add": "Добавить виджет",
+            "undo": "Откатить изменения в виджете",
+            "export": "Экспортировать виджет"
+        },
+        "widgets-bundle": {
+            "current": "Текущий набор",
+            "widgets-bundles": "Наборы виджетов",
+            "add": "Добавить набор виджетов",
+            "delete": "Удалить набор виджетов",
+            "title": "Название",
+            "title-required": "Название обязательно.",
+            "add-widgets-bundle-text": "Добавить новый набор виджетов",
+            "no-widgets-bundles-text": "Наборы виджетов не найдены",
+            "empty": "Пустой набор виджетов",
+            "details": "Подробности",
+            "widgets-bundle-details": "Подробности о наборе виджетов",
+            "delete-widgets-bundle-title": "Вы точно хотите удалить набор виджетов '{{widgetsBundleTitle}}'?",
+            "delete-widgets-bundle-text": "Внимание, после подтверждения набор виджетов и все связанные с ним данные будут безвозвратно утеряны.",
+            "delete-widgets-bundles-title": "Вы точно хотите удалить { count, plural, one {1 набор виджетов} few {# набора виджетов} other {# наборов виджетов} }?",
+            "delete-widgets-bundles-action-title": "Удалить { count, plural, one {1 набор виджетов} few {# набора виджетов} other {# наборов виджетов} }",
+            "delete-widgets-bundles-text": "Внимание, после подтверждения выбранные наборы виджетов и все связанные с ними данные будут безвозвратно утеряны..",
+            "no-widgets-bundles-matching": "Набор виджетов '{{widgetsBundle}}' не найден.",
+            "widgets-bundle-required": "Набор виджетов обязателен.",
+            "system": "Системный",
+            "import": "Импортировать набор виджетов",
+            "export": "Экспортировать набор виджетов",
+            "export-failed-error": "Не удалось экспортировать набор виджетов: {{error}}",
+            "create-new-widgets-bundle": "Создать новый набор виджетов",
+            "widgets-bundle-file": "Файл набора виджетов",
+            "invalid-widgets-bundle-file-error": "Не удалось импортировать набор виджетов: неизвестная схема данных набора виджетов."
+        },
+        "widget-config": {
+            "data": "Данные",
+            "settings": "Настройки",
+            "advanced": "Дополнительно",
+            "title": "Название",
+            "general-settings": "Общие настройки",
+            "display-title": "Показать название",
+            "drop-shadow": "Тень",
+            "enable-fullscreen": "Во весь экран",
+            "background-color": "Цвет фона",
+            "text-color": "Цвет текста",
+            "padding": "Отступ",
+            "title-style": "Стиль названия",
+            "mobile-mode-settings": "Настройки мобильного режима",
+            "order": "Порядок",
+            "height": "Высота",
+            "units": "Специальный символ после значения",
+            "decimals": "Количество цифр после запятой",
+            "timewindow": "Временное окно",
+            "use-dashboard-timewindow": "Использовать временное окно дашборда",
+            "display-legend": "Показать легенду",
+            "datasources": "Источники данных",
+            "datasource-type": "Тип",
+            "datasource-parameters": "Параметры",
+            "remove-datasource": "Удалить источник данных",
+            "add-datasource": "Добавить источник данных",
+            "target-device": "Целевое устройство"
+        },
+        "widget-type": {
+            "import": "Импортировать тип виджета",
+            "export": "Экспортировать тип виджета",
+            "export-failed-error": "Не удалось экспортировать тип виджета: {{error}}",
+            "create-new-widget-type": "Создать новый тип виджета",
+            "widget-type-file": "Файл типа виджета",
+            "invalid-widget-type-file-error": "Не удалось импортировать виджет: неизвестная схема данных типа виджета."
+        },
+        "language": {
+            "language": "Язык",
+            "en_US": "Английский",
+            "ko_KR": "Корейский",
+            "zh_CN": "Китайский",
+            "ru_RU": "Русский"
+        }
+    };
+    angular.extend(locales, {'ru_RU': ru_RU});
+}
\ No newline at end of file
diff --git a/ui/src/app/locale/locale.constant-zh.js b/ui/src/app/locale/locale.constant-zh.js
index 0ded94a..af4b833 100644
--- a/ui/src/app/locale/locale.constant-zh.js
+++ b/ui/src/app/locale/locale.constant-zh.js
@@ -809,7 +809,8 @@ export default function addLocaleChinese(locales) {
             "language" : "语言",
             "en_US" : "英语",
             "ko_KR" : "韩语",
-            "zh_CN" : "汉语"
+            "zh_CN" : "汉语",
+            "ru_RU" : "俄语"
         }
     };
     angular.extend(locales, {
diff --git a/ui/src/app/profile/profile.controller.js b/ui/src/app/profile/profile.controller.js
index 0e0b5ac..4377966 100644
--- a/ui/src/app/profile/profile.controller.js
+++ b/ui/src/app/profile/profile.controller.js
@@ -30,7 +30,8 @@ export default function ProfileController(userService, $scope, $document, $mdDia
     vm.languageList = {
         en_US: {value : "en_US", name: "language.en_US"}, 
         ko_KR: {value : "ko_KR", name: "language.ko_KR"},
-        zh_CN: {value : "zh_CN", name: "language.zh_CN"}
+        zh_CN: {value : "zh_CN", name: "language.zh_CN"},
+        ru_RU: {value : "ru_RU", name: "language.ru_RU"}
     };
 
     loadProfile();