Denys Nykula 6 месяцев назад
Родитель
Сommit
6d0bec14e5

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
README.fr.md


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
README.md


+ 1 - 0
app/i18n/cs/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/de/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/el/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/en-us/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/en/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',
 		'sk' => 'Slovenčina',
 		'tr' => 'Türkçe',
+		'uk' => 'Українська',
 		'zh-cn' => '简体中文',
 		'zh-tw' => '正體中文',
 	),

+ 1 - 0
app/i18n/es/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/fa/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// TODO
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/fi/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/fr/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/he/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/hu/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/id/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/it/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/ja/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/ko/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/lv/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/nl/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/oc/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/pl/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/pt-br/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/pt-pt/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/ru/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/sk/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/tr/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 240 - 0
app/i18n/uk/admin.php

@@ -0,0 +1,240 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'auth' => array(
+		'allow_anonymous' => 'Дозволити анонімне читання статей типового користувача (%s)',
+		'allow_anonymous_refresh' => 'Дозволити анонімне оновлення статей',
+		'api_enabled' => 'Дозволити доступ через <abbr>API</abbr> <small>(треба для мобільних програм і поширення користувацьких запитів)</small>',
+		'form' => 'Вебформа (традиційно, треба JavaScript)',
+		'http' => 'HTTP (складно: за допомогою вебсервера, OIDC, SSO…)',
+		'none' => 'Нема (небезпечно)',
+		'title' => 'Вхід',
+		'token' => 'Головний токен входу',
+		'token_help' => 'Надає доступ до всіх RSS-видач користувача, а також дає змогу оновлювати стрічки без входу:',
+		'type' => 'Тип входу',
+		'unsafe_autologin' => 'Дозволити небезпечний автоматичний вхід у форматі: ',
+	),
+	'check_install' => array(
+		'cache' => array(
+			'nok' => 'Перевірте доступ до каталога <em>./data/cache</em>. HTTP-серверу треба дозвіл на запис.',
+			'ok' => 'Доступ до каталога кешу працює.',
+		),
+		'categories' => array(
+			'nok' => 'Таблицю категорій хибно налаштовано.',
+			'ok' => 'З таблицею категорій усе гаразд.',
+		),
+		'connection' => array(
+			'nok' => 'Не вдалося зʼєднатися з базою даних.',
+			'ok' => 'Доступ до бази даних працює.',
+		),
+		'ctype' => array(
+			'nok' => 'Не вдалося знайти необхідну бібліотеку перевірки типу символа (php-ctype).',
+			'ok' => 'У вас є необхідна бібліотека перевірки типу символа (ctype).',
+		),
+		'curl' => array(
+			'nok' => 'Не вдалося знайти бібліотеку cURL (пакунок php-curl).',
+			'ok' => 'У вас є бібліотека cURL.',
+		),
+		'data' => array(
+			'nok' => 'Перевірте доступ до каталога <em>./data</em>. HTTP-серверу треба дозвіл на запис.',
+			'ok' => 'Доступ до каталога даних працює.',
+		),
+		'database' => 'Встановлення бази даних',
+		'dom' => array(
+			'nok' => 'Не вдалося знайти необхідну бібліотеку роботи з DOM (пакунок php-xml).',
+			'ok' => 'У вас є необхідна бібліотека роботи з DOM.',
+		),
+		'entries' => array(
+			'nok' => 'Таблицю новин хибно налаштовано.',
+			'ok' => 'З таблицею новин усе гаразд.',
+		),
+		'favicons' => array(
+			'nok' => 'Перевірте доступ до каталога <em>./data/favicons</em>. HTTP-серверу треба дозвіл на запис.',
+			'ok' => 'Доступ до каталога піктограм працює.',
+		),
+		'feeds' => array(
+			'nok' => 'Таблицю стрічок хибно налаштовано.',
+			'ok' => 'З таблицею стрічок усе гаразд.',
+		),
+		'fileinfo' => array(
+			'nok' => 'Не вдалося знайти бібліотеку PHP fileinfo (пакунок fileinfo).',
+			'ok' => 'У вас є бібліотека fileinfo.',
+		),
+		'files' => 'Встановлення файлів',
+		'json' => array(
+			'nok' => 'Не вдалося знайти розширення JSON (пакунок php-json).',
+			'ok' => 'У вас є розширення JSON.',
+		),
+		'mbstring' => array(
+			'nok' => 'Не вдалося знайти бажаної бібліотеки mbstring для Юнікоду.',
+			'ok' => 'У вас є бажана бібліотека mbstring для Юнікоду.',
+		),
+		'pcre' => array(
+			'nok' => 'Не вдалося знайти необхідної бібліотеки регулярних виразів (php-pcre).',
+			'ok' => 'У вас є необхідна бібліотека регулярних виразів (PCRE).',
+		),
+		'pdo' => array(
+			'nok' => 'Не вдалося знайти PDO чи одного з підтримуваних драйверів (pdo_mysql, pdo_sqlite чи pdo_pgsql).',
+			'ok' => 'У вас є PDO та принаймні один підтримуваний драйвер (pdo_mysql, pdo_sqlite чи pdo_pgsql).',
+		),
+		'php' => array(
+			'_' => 'Встановлення PHP',
+			'nok' => 'У вас PHP версії %s, але для FreshRSS треба принаймні %s.',
+			'ok' => 'Версія PHP (%s) сумісна з FreshRSS.',
+		),
+		'tables' => array(
+			'nok' => 'У базі даних бракує принаймні одної таблиці.',
+			'ok' => 'Відповідні таблиці наявні в базі даних.',
+		),
+		'title' => 'Перевірка встановлення',
+		'tokens' => array(
+			'nok' => 'Перевірте доступ до каталога <em>./data/tokens</em>. HTTP-серверу треба дозвіл на запис',
+			'ok' => 'Доступ до каталога токенів працює.',
+		),
+		'users' => array(
+			'nok' => 'Перевірте доступ до каталога <em>./data/users</em>. HTTP-серверу треба дозвіл на запис',
+			'ok' => 'Доступ до користувацького каталога працює.',
+		),
+		'zip' => array(
+			'nok' => 'Не вдалося знайти ZIP-розширення (пакунок php-zip).',
+			'ok' => 'У вас є ZIP-розширення.',
+		),
+	),
+	'extensions' => array(
+		'author' => 'Автор',
+		'community' => 'Доступні розширення спільноти',
+		'description' => 'Опис',
+		'disabled' => 'Вимкнено',
+		'empty_list' => 'Розширень не встановлено',
+		'empty_list_help' => 'Щоб виявити причину порожнього списку розширень, перегляньте журнали.',
+		'enabled' => 'Увімкнено',
+		'latest' => 'Встановлено',
+		'name' => 'Назва',
+		'no_configure_view' => 'Розширення не налаштовується.',
+		'system' => array(
+			'_' => 'Системні розширення',
+			'no_rights' => 'Системне розширення (вам бракує дозволу)',
+		),
+		'title' => 'Розширення',
+		'update' => 'Наявне оновлення',
+		'user' => 'Користувацькі розширення',
+		'version' => 'Версія',
+	),
+	'stats' => array(
+		'_' => 'Статистика',
+		'all_feeds' => 'Всі стрічки',
+		'category' => 'Категорія',
+		'entry_count' => 'Кількість статей',
+		'entry_per_category' => 'Статей у категорії',
+		'entry_per_day' => 'Статей за день (минулі 30 днів)',
+		'entry_per_day_of_week' => 'За день тижня (в середньому повідомлень: %.2f)',
+		'entry_per_hour' => 'За годину (в середньому статей: %.2f)',
+		'entry_per_month' => 'За місяць (у середньому статей: %.2f)',
+		'entry_repartition' => 'Перерозподіл статей',
+		'feed' => 'Стрічка',
+		'feed_per_category' => 'Стрічок у категорії',
+		'idle' => 'Неактивні стрічки',
+		'main' => 'Основна статистика',
+		'main_stream' => 'Головний потік',
+		'no_idle' => 'Неактивних стрічок нема!',
+		'number_entries' => 'Статей: %d',
+		'overview' => 'Огляд',
+		'percent_of_total' => '% від загальної кількості',
+		'repartition' => 'Перерозподіл статей: %s',
+		'status_favorites' => 'Вподобано',
+		'status_read' => 'Прочитано',
+		'status_total' => 'Усього',
+		'status_unread' => 'Непрочитано',
+		'title' => 'Статистика',
+		'top_feed' => 'Десять найактивніших стрічок',
+	),
+	'system' => array(
+		'_' => 'Налаштування системи',
+		'auto-update-url' => 'URL-адреса сервера автоматичного оновлення',
+		'base-url' => array(
+			'_' => 'Базова URL-адреса',
+			'recommendation' => 'Автоматична порада: <kbd>%s</kbd>',
+		),
+		'cookie-duration' => array(
+			'help' => 'секунд',
+			'number' => 'Тривалість сеансу',
+		),
+		'force_email_validation' => 'Підтверджувати адресу електронної пошти',
+		'instance-name' => 'Назва сервера',
+		'max-categories' => 'Максимум категорій у користувача',
+		'max-feeds' => 'Максимум стрічок у користувача',
+		'registration' => array(
+			'number' => 'Максимум облікових записів',
+			'select' => array(
+				'label' => 'Форма реєстрації',
+				'option' => array(
+					'noform' => 'Вимкнено: форма реєстрації недоступна',
+					'nolimit' => 'Увімкнено: кількість облікових записів необмежена',
+					'setaccountsnumber' => 'Обмежити кількість облікових записів',
+				),
+			),
+			'status' => array(
+				'disabled' => 'Форму вимкнено',
+				'enabled' => 'Форму ввімкнено',
+			),
+			'title' => 'Форма користувацької реєстрації',
+		),
+		'sensitive-parameter' => 'Чутливий параметр. Відредагуйте вручну в <kbd>./data/config.php</kbd>',
+		'tos' => array(
+			'disabled' => 'вимкнено',
+			'enabled' => '<a href="./?a=tos">налаштовано</a>',
+			'help' => 'Як <a href="https://freshrss.github.io/FreshRSS/en/admins/12_User_management.html#enable-terms-of-service-tos" target="_blank">налаштувати умови надання послуг</a>',
+		),
+		'websub' => array(
+			'help' => 'Про <a href="https://freshrss.github.io/FreshRSS/en/users/WebSub.html" target="_blank">WebSub</a>',
+		),
+	),
+	'update' => array(
+		'_' => 'Оновити FreshRSS',
+		'apply' => 'Почати оновлення',
+		'changelog' => 'Журнал змін',
+		'check' => 'Пошукати оновлення',
+		'copiedFromURL' => 'update.php скопійовано з %s до ./data',
+		'current_version' => 'Поточна встановлена версія',
+		'last' => 'Минула перевірка',
+		'loading' => 'Оновлення…',
+		'none' => 'Нема доступних оновлень',
+		'releaseChannel' => array(
+			'_' => 'Канал випусків',
+			'edge' => 'Крайній випуск («edge»)',
+			'latest' => 'Стабільний випуск («latest»)',
+		),
+		'title' => 'Оновити FreshRSS',
+		'viaGit' => 'Розпочато оновлення за допомогою git і GitHub.com',
+	),
+	'user' => array(
+		'admin' => 'Адміністратор',
+		'article_count' => 'Статей',
+		'back_to_manage' => '← Повернутися до списку користувачів',
+		'create' => 'Створити користувача',
+		'database_size' => 'Розмір бази даних',
+		'email' => 'Адреса електронної пошти',
+		'enabled' => 'Увімкнено',
+		'feed_count' => 'Стрічок',
+		'is_admin' => 'Адміністратор',
+		'language' => 'Мова',
+		'last_user_activity' => 'Найновіша активність',
+		'list' => 'Список користувачів',
+		'number' => 'Створено %d обліковий запис',
+		'numbers' => 'Створено облікових записів: %d',
+		'password_form' => 'Пароль<br /><small>(для входу через вебформу)</small>',
+		'password_format' => 'Принаймні 7 символів',
+		'title' => 'Керувати користувачами',
+		'username' => 'Користувацьке імʼя',
+	),
+);

+ 33 - 0
app/i18n/uk/api.php

@@ -0,0 +1,33 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'information' => array(
+		'address' => 'Адреса вашого API:',
+		'output' => array(
+			'encoding-support' => '⚠️ УВАГА: бракує підтримки <code>%2F</code>, деякі клієнти можуть не працювати!',
+			'invalid-configuration' => '⚠️ УВАГА: ймовірно хибна базова URL-адреса в ./data/config.php',
+			'pass' => '✔️ УСПІХ',
+			'unknown-error' => '❌ ',	// IGNORE
+		),
+		'test' => array(
+			'fever' => 'Перевірка налаштування Fever API:',
+			'greader' => 'Перевірка налаштування Google Reader API:',
+		),
+		'title' => array(
+			'_' => 'Ендпойнти API FreshRSS',
+			'extension' => 'API для розширень',
+			'fever' => 'API, сумісне з Fever',
+			'greader' => 'API, сумісне з Google Reader',
+		),
+	),
+);

+ 362 - 0
app/i18n/uk/conf.php

@@ -0,0 +1,362 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'archiving' => array(
+		'_' => 'Архівування',
+		'exception' => 'Винятки з видалення',
+		'help' => 'Більше опцій — у параметрах окремої стрічки',
+		'keep_favourites' => 'Ніколи не видаляти вподобаних',
+		'keep_labels' => 'Ніколи не видаляти міток',
+		'keep_max' => 'Максимум статей у стрічці',
+		'keep_min_by_feed' => 'Мінімум статей у стрічці',
+		'keep_period' => 'Тривалість зберігання статей',
+		'keep_unreads' => 'Ніколи не видаляти непрочитаних статей',
+		'maintenance' => 'Супровід',
+		'optimize' => 'Оптимізувати базу даних',
+		'optimize_help' => 'Запускайте час від часу, щоб зменшити розмір бази даних',
+		'policy' => 'Політика видалення',
+		'policy_warning' => 'Якщо політики видалення не встановлено, всі статті зберігатимуться.',
+		'purge_now' => 'Застосувати політику видалення',
+		'title' => 'Архівування',
+		'ttl' => 'Частота автоматичного оновлення',
+	),
+	'display' => array(
+		'_' => 'Оформлення',
+		'darkMode' => array(
+			'_' => 'Темний режим',
+			'auto' => 'Автоматично',
+			'help' => 'Лише для підтримуваних тем',
+			'no' => 'Вимкнено',
+		),
+		'icon' => array(
+			'bottom_line' => 'Нижній рядок',
+			'display_authors' => 'Автори',
+			'entry' => 'Піктограми статей',
+			'publication_date' => 'Дата оприлюднення',
+			'related_tags' => 'Теги статей',
+			'sharing' => 'Поширення',
+			'summary' => 'Підсумок',
+			'top_line' => 'Верхній рядок',
+		),
+		'language' => 'Мова',
+		'notif_html5' => array(
+			'seconds' => 'секунд (0 означає без тайм-ауту)',
+			'timeout' => 'Тайм-аут сповіщення HTML5',
+		),
+		'show_nav_buttons' => 'Показати кнопки навігації',
+		'theme' => array(
+			'_' => 'Тема',
+			'deprecated' => array(
+				'_' => 'Застаріла',
+				'description' => 'Тема більше не підтримується. Її буде вилучено з <a href="https://freshrss.github.io/FreshRSS/en/users/05_Configuration.html#theme" target="_blank">майбутнього випуску FreshRSS</a>',
+			),
+		),
+		'theme_not_available' => 'Тема «%s» більше не підтримується. Будь ласка, оберіть іншу тему.',
+		'thumbnail' => array(
+			'label' => 'Ілюстрація',
+			'landscape' => 'Горизонтальна',
+			'none' => 'Вимкнена',
+			'portrait' => 'Вертикальна',
+			'square' => 'Квадрат',
+		),
+		'timezone' => 'Часовий пояс',
+		'title' => 'Оформлення',
+		'website' => array(
+			'full' => 'Піктограма й назва',
+			'icon' => 'Лише піктограма',
+			'label' => 'Вебсайт',
+			'name' => 'Лише назва',
+			'none' => 'Вимкнено',
+		),
+		'width' => array(
+			'content' => 'Ширина тексту',
+			'large' => 'Велика',
+			'medium' => 'Середня',
+			'no_limit' => 'Повна',
+			'thin' => 'Мала',
+		),
+	),
+	'logs' => array(
+		'loglist' => array(
+			'level' => 'Важливість',
+			'message' => 'Повідомлення',
+			'timestamp' => 'Час',
+		),
+		'pagination' => array(
+			'first' => 'Перша',
+			'last' => 'Остання',
+			'next' => 'Наступна',
+			'previous' => 'Попередня',
+		),
+	),
+	'mark_read_button' => array(
+		'_' => 'Кнопка «Позначити все прочитаним»',
+		'big' => 'Велика',
+		'none' => 'Не показувати',
+		'small' => 'Мала',
+	),
+	'privacy' => array(
+		'_' => 'Приватність',
+		'retrieve_extension_list' => 'Завантажувати список розширень',
+	),
+	'profile' => array(
+		'_' => 'Керування профілем',
+		'api' => array(
+			'_' => 'Зовнішній доступ через API',
+			'api_not_set' => 'Пароля API не налаштовано',
+			'api_set' => 'Пароль API налаштовано',
+			'check_link' => 'Перевірте стан API: <kbd><a href="../api/" target="_blank">%s</a></kbd>',
+			'disabled' => 'Доступ через API вимкнено.',
+			'documentation_link' => 'Перегляньте <a href="https://freshrss.github.io/FreshRSS/en/users/06_Mobile_access.html#access-via-mobile-app" target="_blank">документацію та перелік відомих програм</a>',
+			'help' => 'Перегляньте <a href="http://freshrss.github.io/FreshRSS/en/users/06_Mobile_access.html#access-via-mobile-app" target=_blank>документацію</a>',
+		),
+		'change_password' => 'Змінити пароль',
+		'confirm_new_password' => 'Підтвердьте новий пароль',
+		'current_password' => 'Поточний пароль<br /><small>(для входу через вебформу)</small>',
+		'delete' => array(
+			'_' => 'Видалення облікового запису',
+			'warn' => 'Ваш обліковий запис і всі повʼязані дані буде видалено.',
+		),
+		'email' => 'Адреса електронної пошти',
+		'new_password' => 'Новий пароль',
+		'password_api' => 'Пароль API<br /><small>(наприклад, для мобільних програм)</small>',
+		'password_format' => 'Принаймні 7 символів',
+		'title' => 'Профіль',
+	),
+	'query' => array(
+		'_' => 'Користувацькі запити',
+		'deprecated' => 'Запит більше не чинний. Згадану категорію чи стрічку видалено.',
+		'description' => 'Опис',
+		'filter' => array(
+			'_' => 'Застосовано фільтр:',
+			'categories' => 'Показати категорію',
+			'feeds' => 'Показати стрічку',
+			'order' => 'Впорядкувати за датою',
+			'search' => 'Вираз',
+			'shareOpml' => 'Увімкнути OPML-поширення відповідних категорій і стрічок',
+			'shareRss' => 'Увімкнути поширення в форматі HTML і RSS',
+			'state' => 'Стан',
+			'tags' => 'Показати за тегом',
+			'type' => 'Тип',
+		),
+		'get_A' => 'Показати всі стрічки, зокрема показані в межах категорії',
+		'get_Z' => 'Показати всі стрічки, зокрема архівовані',
+		'get_all' => 'Показати всі статті',
+		'get_all_labels' => 'Показати статті з будь-якою міткою',
+		'get_category' => 'Показати категорію «%s»',
+		'get_favorite' => 'Показати вподобані статті',
+		'get_feed' => 'Показати стрічку «%s»',
+		'get_important' => 'Показати статті з важливих стрічок',
+		'get_label' => 'Показати статті з міткою «%s»',
+		'help' => 'Перегляньте <a href="https://freshrss.github.io/FreshRSS/en/users/user_queries.html" target="_blank">документацію користувацьких запитів і їх поширення в форматі HTML, RSS та OPML</a>.',
+		'image_url' => 'URL-адреса зображення',
+		'name' => 'Назва',
+		'no_filter' => 'Без фільтру',
+		'no_queries' => array(
+			'_' => 'Користувацьких запитів ще не збережено.',
+			'help' => 'Перегляньте <a href="https://freshrss.github.io/FreshRSS/en/users/user_queries.html" target="_blank">документацію</a>',
+		),
+		'number' => 'Запит №%d',
+		'order_asc' => 'Спершу старіші статті',
+		'order_desc' => 'Спершу новіші статті',
+		'search' => 'Пошук «%s»',
+		'share' => array(
+			'_' => 'Поширити запит за посиланням',
+			'disabled' => array(
+				'_' => 'вимкнено',
+				'title' => 'Поширення',
+			),
+			'greader' => 'Загальнодоступне посилання на JSON для GReader',
+			'help' => 'Щоб поділитися з кимось цим запитом, скопіюйте це посилання',
+			'html' => 'Загальнодоступне посилання на HTML-сторінку',
+			'opml' => 'Загальнодоступне посилання на OPML-список стрічок',
+			'rss' => 'Загальнодоступне посилання на RSS-стрічку',
+		),
+		'state_0' => 'Показати всі статті',
+		'state_1' => 'Показати прочитані статті',
+		'state_2' => 'Показати непрочитані статті',
+		'state_3' => 'Показати всі статті',
+		'state_4' => 'Показати вподобані статті',
+		'state_5' => 'Показати прочитані вподобані статті',
+		'state_6' => 'Показати непрочитані вподобані статті',
+		'state_7' => 'Показати вподобані статті',
+		'state_8' => 'Показати невподобані статті',
+		'state_9' => 'Показати прочитані невподобані статті',
+		'state_10' => 'Показати непрочитані невподобані статті',
+		'state_11' => 'Показати невподобані статті',
+		'state_12' => 'Показати всі статті',
+		'state_13' => 'Показати прочитані статті',
+		'state_14' => 'Показати непрочитані статті',
+		'state_15' => 'Показати всі статті',
+		'title' => 'Користувацькі запити',
+	),
+	'reading' => array(
+		'_' => 'Читання',
+		'after_onread' => 'Коли все позначено прочитаним,',
+		'always_show_favorites' => 'У вподобаних типово показувати всі статті',
+		'apply_to_individual_feed' => 'Застосовується до саме цієї стрічки',
+		'article' => array(
+			'authors_date' => array(
+				'_' => 'Автори й дата',
+				'both' => 'Вгорі й унизу',
+				'footer' => 'Внизу',
+				'header' => 'Вгорі',
+				'none' => 'Не показувати',
+			),
+			'feed_name' => array(
+				'above_title' => 'Над заголовком і тегами',
+				'none' => 'Не показувати',
+				'with_authors' => 'У рядку авторів і дати',
+			),
+			'feed_title' => 'Назва стрічки',
+			'icons' => array(
+				'_' => 'Піктограми статті<br /><small>(Тільки читацький показ)</small>',
+				'above_title' => 'Над заголовком',
+				'with_authors' => 'У рядку авторів і дати',
+			),
+			'tags' => array(
+				'_' => 'Теги',
+				'both' => 'Вгорі й унизу',
+				'footer' => 'Внизу',
+				'header' => 'Вгорі',
+				'none' => 'Не показувати',
+			),
+			'tags_max' => array(
+				'_' => 'Показувати тегів',
+				'help' => '0 означає показати всі теги й не згортати їх',
+			),
+		),
+		'articles_per_page' => 'Статей на сторінці',
+		'auto_load_more' => 'Завантажувати більше статей при прокручуванні',
+		'auto_remove_article' => 'Ховати статті після прочитання',
+		'confirm_enabled' => 'Перепитувати, чи позначати все прочитаним',
+		'display_articles_unfolded' => 'Розгортати статті типово',
+		'display_categories_unfolded' => 'Категорії для розгортання',
+		'headline' => array(
+			'articles' => 'Статті: відкриті/закриті',
+			'articles_header_footer' => 'Статті: верх/низ',
+			'categories' => 'Ліва навігація: категорії',
+			'mark_as_read' => 'Позначити статтю прочитаною',
+			'misc' => 'Різне',
+			'view' => 'Показ',
+		),
+		'hide_read_feeds' => 'Ховати категорії та стрічки, усі статті яких прочитано (не працює при виборі «Показати всі статті»)',
+		'img_with_lazyload' => 'Відкладати завантаження зображень до появи їх у видимій області',
+		'jump_next' => 'перейти до наступного непрочитаного поруч',
+		'mark_updated_article_unread' => 'Позначати оновленні статті непрочитаними',
+		'number_divided_when_reader' => 'Ділиться на 2 в читацькому показі.',
+		'read' => array(
+			'article_open_on_website' => 'при переході на сайт статті',
+			'article_viewed' => 'при відкритті статті',
+			'focus' => 'при фокусуванні (крім важливих стрічок)',
+			'keep_max_n_unread' => 'Максимум непрочитаних статей',
+			'scroll' => 'при гортанні (крім важливих стрічок)',
+			'upon_gone' => 'коли статті більше нема в оригінальній стрічці новин',
+			'upon_reception' => 'при отриманні статті',
+			'when' => 'Позначити статтю прочитаною…',
+			'when_same_title_in_category' => 'якщо котрась зі стількох найновіших статей категорії має такий самий заголовок',
+			'when_same_title_in_feed' => 'якщо котрась зі стількох найновіших статей стрічки має такий самий заголовок',
+		),
+		'show' => array(
+			'_' => 'Статті для показу',
+			'active_category' => 'Активна категорія',
+			'adaptive' => 'Показати непрочитані за наявності, інакше всі статті',
+			'all_articles' => 'Показати всі статті',
+			'all_categories' => 'Всі категорії',
+			'no_category' => 'Без категорії',
+			'remember_categories' => 'Памʼятати відкриті категорії',
+			'unread' => 'Показати непрочитані',
+			'unread_or_favorite' => 'Показати непрочитані та вподобані',
+		),
+		'show_fav_unread_help' => 'Впливає також на мітки',
+		'sides_close_article' => 'Натиск за межами тексту статті закриває статтю',
+		'sort' => array(
+			'_' => 'Порядок',
+			'newer_first' => 'Спершу новіші',
+			'older_first' => 'Спершу старіші',
+		),
+		'star' => array(
+			'when' => 'Вподобати статтю…',
+		),
+		'sticky_post' => 'Закріплювати статтю вгорі при відкритті',
+		'title' => 'Читання',
+		'view' => array(
+			'default' => 'Типовий показ',
+			'global' => 'Глобальний показ',
+			'normal' => 'Звичайний показ',
+			'reader' => 'Читацький показ',
+		),
+	),
+	'sharing' => array(
+		'_' => 'Поширення',
+		'add' => 'Додати спосіб поширення',
+		'bluesky' => 'Bluesky',	// IGNORE
+		'deprecated' => 'Цей сервіс більше не підтримується. Його буде вилучено з FreshRSS у <a href="https://freshrss.github.io/FreshRSS/en/users/08_sharing_services.html" title="Докладніше в документації" target="_blank">наступному випуску</a>.',
+		'diaspora' => 'Diaspora*',	// IGNORE
+		'email' => 'Email',	// IGNORE
+		'facebook' => 'Facebook',	// IGNORE
+		'more_information' => 'Докладніше',
+		'print' => 'Друк',
+		'raindrop' => 'Raindrop.io',	// IGNORE
+		'remove' => 'Вилучити спосіб поширення',
+		'shaarli' => 'Shaarli',	// IGNORE
+		'share_name' => 'Підпис у меню',
+		'share_url' => 'URL-адреса поширення',
+		'title' => 'Поширення',
+		'twitter' => 'Twitter',	// IGNORE
+		'wallabag' => 'wallabag',	// IGNORE
+	),
+	'shortcut' => array(
+		'_' => 'Клавіші',
+		'article_action' => 'Дії зі статею',
+		'auto_share' => 'Поширити',
+		'auto_share_help' => 'Якщо решим поширення лише один, використовується одразу він. Інакше обирайте режими їхніми номерами.',
+		'close_menus' => 'Закрити меню',
+		'collapse_article' => 'Згорнути',
+		'first_article' => 'Перша стаття',
+		'focus_search' => 'Пошук',
+		'global_view' => 'Глобальний показ',
+		'help' => 'Документація',
+		'javascript' => 'Щоб використовувати клавіші, слід увімкнути JavaScript',
+		'last_article' => 'Остання стаття',
+		'load_more' => 'Завантажити більше статей',
+		'mark_favorite' => 'Перемкнути вподобання',
+		'mark_read' => 'Перемкнути прочитаність',
+		'navigation' => 'Навігація',
+		'navigation_help' => 'При затисненій <kbd>⇧ Shift</kbd> клавіші навігації застосовуються до стрічок.<br/>При затисненій <kbd>Alt ⎇</kbd> клавіші навігації застосовуються до категорій.',
+		'navigation_no_mod_help' => 'Наступні клавіші навігації не підтримують описаного вгорі затиснення.',
+		'next_article' => 'Наступна стаття',
+		'next_unread_article' => 'Наступна непрочитана стаття',
+		'non_standard' => 'Деякі клавіші (<kbd>%s</kbd>) можуть не працювати.',
+		'normal_view' => 'Звичайний показ',
+		'other_action' => 'Інші дії',
+		'previous_article' => 'Попередня стаття',
+		'reading_view' => 'Читацький показ',
+		'rss_view' => 'Відкрити як RSS-стрічку',
+		'see_on_website' => 'Сайт оригіналу',
+		'shift_for_all_read' => 'Затисніть також <kbd>Alt ⎇</kbd>, щоб позначити попередні статті прочитаними<br />Затисніть також <kbd>⇧ Shift</kbd>, щоб позначити всі статті прочитаними',
+		'skip_next_article' => 'Сфокусувати наступну не відкриваючи',
+		'skip_previous_article' => 'Сфокусувати попередню не відкриваючи',
+		'title' => 'Клавіші',
+		'toggle_media' => 'Почати/зупинити відтворення',
+		'user_filter' => 'Користувацькі запити',
+		'user_filter_help' => 'Якщо користувацький запит лише один, використовується одразу він. Інакше обирайте запити їхніми номерами.',
+		'views' => 'Показ',
+	),
+	'user' => array(
+		'articles_and_size' => 'Статей: %s (%s)',
+		'current' => 'Поточний користувач',
+		'is_admin' => 'адміністратор',
+		'users' => 'Користувачі',
+	),
+);

+ 152 - 0
app/i18n/uk/feedback.php

@@ -0,0 +1,152 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'access' => array(
+		'denied' => 'Бракує дозволу на доступ до цієї сторінки',
+		'not_found' => 'Шуканої сторінки не існує',
+	),
+	'admin' => array(
+		'optimization_complete' => 'Оптимізацію завершено',
+	),
+	'api' => array(
+		'password' => array(
+			'failed' => 'Не вдалося змінити пароль',
+			'updated' => 'Пароль змінено',
+		),
+	),
+	'auth' => array(
+		'login' => array(
+			'invalid' => 'Не вдалось увійти',
+			'success' => 'Вхід успішний',
+		),
+		'logout' => array(
+			'success' => 'Вихід успішний',
+		),
+	),
+	'conf' => array(
+		'error' => 'Не вдалося зберегти налаштування',
+		'query_created' => 'Запит «%s» створено.',
+		'shortcuts_updated' => 'Клавіші оновлено',
+		'updated' => 'Налаштування оновлено',
+	),
+	'extensions' => array(
+		'already_enabled' => '%s уже ввімкнено',
+		'cannot_remove' => 'Неможливо вилучити %s',
+		'disable' => array(
+			'ko' => 'Неможливо вимкнути %s. <a href="%s">Докладніше в журналах FreshRSS</a>.',
+			'ok' => '%s тепер вимкнено',
+		),
+		'enable' => array(
+			'ko' => 'Неможливо ввімкнути %s. <a href="%s">Докладніше в журналах FreshRSS</a>.',
+			'ok' => '%s тепер увімкнено',
+		),
+		'invalid_view_mode' => 'Хибний режим показу «%s»! Повернутися до «звичайного показу».',
+		'no_access' => 'Бракує доступу до %s',
+		'not_enabled' => '%s вимкнено',
+		'not_found' => '%s не існує',
+		'removed' => '%s вилучено',
+	),
+	'import_export' => array(
+		'export_no_zip_extension' => 'ZIP-розширення не встановлено на вашому сервері. Спробуйте експортувати файли поодинці.',
+		'feeds_imported' => 'Стрічки імпортовано. Якщо більше не потрібно нічого імпортувати, натисніть кнопку <i>Оновити стрічки</i>.',
+		'feeds_imported_with_errors' => 'Стрічки імпортовано, проте виникли помилки. Якщо більше не потрібно нічого імпортувати, натисніть кнопку <i>Оновити стрічки</i>.',
+		'file_cannot_be_uploaded' => 'Не вдалося вивантажити файл!',
+		'no_zip_extension' => 'На сервері бракує ZIP-розширення.',
+		'zip_error' => 'При обробці ZIP виникла помилка.',
+	),
+	'profile' => array(
+		'error' => 'Не вдалось оновити профіль',
+		'passwords_dont_match' => 'Паролі не збігаються',
+		'updated' => 'Профіль оновлено',
+	),
+	'sub' => array(
+		'actualize' => 'Оновлення',
+		'articles' => array(
+			'marked_read' => 'Вибрані статті позначено прочитаними.',
+			'marked_unread' => 'Статті позначено непрочитаними.',
+		),
+		'category' => array(
+			'created' => 'Створено категорію %s.',
+			'deleted' => 'Категорію видалено.',
+			'emptied' => 'Категорію спорожнено',
+			'error' => 'Не вдалося оновити категорію',
+			'name_exists' => 'Категорія з такою назвою вже існує.',
+			'no_id' => 'Слід вказати ідентифікатор категорії.',
+			'no_name' => 'Категорії слід мати назву.',
+			'not_delete_default' => 'Неможливо видалити типову категорію!',
+			'not_exist' => 'Категорія не існує!',
+			'over_max' => 'Ви вже маєте максимум дозволених категорій (%d)',
+			'updated' => 'Категорію оновлено.',
+		),
+		'feed' => array(
+			'actualized' => '<em>%s</em> оновлено',
+			'actualizeds' => 'RSS-стрічки оновлено',
+			'added' => 'Додано RSS-стрічку <em>%s</em>',
+			'already_subscribed' => 'Ви вже підписані на <em>%s</em>',
+			'cache_cleared' => 'Кеш <em>%s</em> очищено',
+			'deleted' => 'Стрічку видалено',
+			'error' => 'Не вдалося оновити стрічку',
+			'favicon' => array(
+				'too_large' => 'Завантажена піктограма завелика. Максимальний розмір файлу <em>%s</em>.',
+				'unsupported_format' => 'Формат зображення не підтримується!',
+			),
+			'internal_problem' => 'Не вдалося додати стрічку новин. <a href="%s">Докладніше в журналах FreshRSS</a>. Щоб спробувати примусове додання, допишіть <code>#force_feed</code> до URL-адреси.',
+			'invalid_url' => 'URL-адреса <em>%s</em> хибна',
+			'n_actualized' => 'Стрічки оновлено (%d)',
+			'n_entries_deleted' => 'Статті видалено (%d)',
+			'no_refresh' => 'Нема стрічок, які можна було б оновити',
+			'not_added' => 'Не вдалося додати <em>%s</em>',
+			'not_found' => 'Стрічки не знайдено',
+			'over_max' => 'Ви вже маєте максимум дозволених стрічок (%d)',
+			'reloaded' => '<em>%s</em> перезавантажено',
+			'selector_preview' => array(
+				'http_error' => 'Не вдалося завантажити сайт.',
+				'no_entries' => 'У стрічці нема статей. Щоб створити попередній перегляд, треба принаймні одна стаття.',
+				'no_feed' => 'Внутрішня помилка (стрічки не знайдено).',
+				'no_result' => 'Селектору ніщо не відповідає. Натомість буде показано початковий текст стрічки.',
+				'selector_empty' => 'Селектор порожній. Щоб створити попередній перегляд, налаштуйте селектор.',
+			),
+			'updated' => 'Стрічку оновлено',
+		),
+		'purge_completed' => 'Видалення завершено (видалено статей: %d)',
+	),
+	'tag' => array(
+		'created' => 'Мітку «%» створено.',
+		'error' => 'Не вдалося оновити мітку!',
+		'name_exists' => 'Мітка з такою назвою вже існує.',
+		'renamed' => 'Мітку «%s» перейменовано на «%s».',
+		'updated' => 'Мітку оновлено.',
+	),
+	'update' => array(
+		'can_apply' => 'Наявне оновлення FreshRSS: <strong>версія %s</strong>.',
+		'error' => 'При оновленні виникла помилка: %s',
+		'file_is_nok' => 'Наявне оновлення FreshRSS (<strong>версія %s</strong>), але перевірте доступи до каталога <em>%s</em>. HTTP-серверу потрібен дозвіл на запис',
+		'finished' => 'Оновлення завершено!',
+		'none' => 'Нема доступних оновлень',
+		'server_not_found' => 'Не вдалося знайти сервер оновлень. [%s]',
+	),
+	'user' => array(
+		'created' => array(
+			'_' => 'Користувача %s створено',
+			'error' => 'Не вдалося створити користувача %s',
+		),
+		'deleted' => array(
+			'_' => 'Користувача %s видалено',
+			'error' => 'Не вдалося видалити користувача %s',
+		),
+		'updated' => array(
+			'_' => 'Користувача %s оновлено',
+			'error' => 'Не вдалося оновити користувача %s',
+		),
+	),
+);

+ 273 - 0
app/i18n/uk/gen.php

@@ -0,0 +1,273 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'action' => array(
+		'actualize' => 'Оновити стрічки',
+		'add' => 'Додати',
+		'back_to_rss_feeds' => '← Повернутися до RSS-стрічок',
+		'cancel' => 'Скасувати',
+		'close' => 'Закрити',
+		'create' => 'Створити',
+		'delete_all_feeds' => 'Видалити всі стрічки',
+		'delete_errored_feeds' => 'Видалити стрічки з помилками',
+		'delete_muted_feeds' => 'Видалити зупинені стрічки',
+		'demote' => 'Забрати повноваження',
+		'disable' => 'Вимкнути',
+		'download' => 'Завантажити',
+		'empty' => 'Спорожнити',
+		'enable' => 'Увімкнути',
+		'export' => 'Експортувати',
+		'filter' => 'Фільтрувати',
+		'import' => 'Імпортувати',
+		'load_default_shortcuts' => 'Відновити типові клавіші',
+		'manage' => 'Керувати',
+		'mark_read' => 'Позначити прочитаними',
+		'menu' => array(
+			'open' => 'Відкрити меню',
+		),
+		'nav_buttons' => array(
+			'next' => 'Наступна стаття',
+			'prev' => 'Попередня стаття',
+			'up' => 'Вгору',
+		),
+		'open_url' => 'Відкрити URL-адресу',
+		'promote' => 'Підвищити',
+		'purge' => 'Застосувати політику видалення',
+		'refresh_opml' => 'Оновити OPML',
+		'remove' => 'Вилучити',
+		'rename' => 'Перейменувати',
+		'see_website' => 'Переглянути вебсайт',
+		'submit' => 'Надіслати',
+		'truncate' => 'Видалити всі статті',
+		'update' => 'Оновити',
+	),
+	'auth' => array(
+		'accept_tos' => 'Погоджуюся з <a href="%s">умовами надання послуг</a>.',
+		'email' => 'Адреса електронної пошти',
+		'keep_logged_in' => 'Памʼятати мене <small>(%s днів)</small>',
+		'login' => 'Увійти',
+		'logout' => 'Вийти',
+		'password' => array(
+			'_' => 'Пароль',
+			'format' => '<small>Принаймні 7 символів</small>',
+		),
+		'reauth' => array(
+			'header' => 'Слід перезайти',
+			'tip' => 'Система не проситиме вас перезаходити найближчі <u>%d хвилин</u>',
+			'title' => 'Повторний вхід',
+		),
+		'registration' => array(
+			'_' => 'Новий обліковий запис',
+			'ask' => 'Створити обліковий запис?',
+			'title' => 'Створення облікового запису',
+		),
+		'username' => array(
+			'_' => 'Користувацьке імʼя',
+			'format' => '<small>Максимум 16 латинських літер або цифер</small>',
+		),
+	),
+	'date' => array(
+		'Apr' => '\\к\\в\\і\\т\\н\\я',
+		'Aug' => '\\с\\е\\р\\п\\н\\я',
+		'Dec' => '\\г\\р\\у\\д\\н\\я',
+		'Feb' => '\\л\\ю\\т\\о\\г\\о',
+		'Jan' => '\\с\\і\\ч\\н\\я',
+		'Jul' => '\\л\\и\\п\\н\\я',
+		'Jun' => '\\ч\\е\\р\\в\\н\\я',
+		'Mar' => '\\б\\е\\р\\е\\з\\н\\я',
+		'May' => '\\т\\р\\а\\в\\н\\я',
+		'Nov' => '\\л\\и\\с\\т\\о\\п\\а\\д\\а',
+		'Oct' => '\\ж\\о\\в\\т\\н\\я',
+		'Sep' => '\\в\\е\\р\\е\\с\\н\\я',
+		'apr' => 'кві',
+		'april' => 'квітня',
+		'aug' => 'сер',
+		'august' => 'серпня',
+		'before_yesterday' => 'Раніше за вчора',
+		'dec' => 'гру',
+		'december' => 'грудня',
+		'feb' => 'лют',
+		'february' => 'лютого',
+		'format_date' => 'j %s Y',	// IGNORE
+		'format_date_hour' => 'j %s Y \\о H\\:i',
+		'fri' => 'Пт',
+		'jan' => 'січ',
+		'january' => 'січня',
+		'jul' => 'лип',
+		'july' => 'липня',
+		'jun' => 'чер',
+		'june' => 'червня',
+		'last_2_year' => 'Минулі два роки',
+		'last_3_month' => 'Минулі три місяці',
+		'last_3_year' => 'Минулі три роки',
+		'last_5_year' => 'Минулі пʼять років',
+		'last_6_month' => 'Минулі шість місяців',
+		'last_month' => 'Минулий місяць',
+		'last_week' => 'Минулий тиждень',
+		'last_year' => 'Минулий рік',
+		'mar' => 'бер',
+		'march' => 'березня',
+		'may' => 'тра',
+		'may_' => 'травня',
+		'mon' => 'Пн',
+		'month' => 'місяці',
+		'nov' => 'лис',
+		'november' => 'листопада',
+		'oct' => 'жов',
+		'october' => 'жовтня',
+		'sat' => 'Сб',
+		'sep' => 'вер',
+		'september' => 'вересня',
+		'sun' => 'Нд',
+		'thu' => 'Чт',
+		'today' => 'Сьогодні',
+		'tue' => 'Вт',
+		'wed' => 'Ср',
+		'yesterday' => 'Вчора',
+	),
+	'dir' => 'ltr',	// IGNORE
+	'flag' => '🇺🇦',
+	'freshrss' => array(
+		'_' => 'FreshRSS',	// IGNORE
+		'about' => 'Про FreshRSS',
+	),
+	'js' => array(
+		'category_empty' => 'Порожня категорія',
+		'confirm_action' => 'Точно виконати цю дію? Її неможливо скасувати!',
+		'confirm_action_feed_cat' => 'Точно виконати цю дію? Ви втратите повʼязані вподобання й користувацькі запити. Дію неможливо скасувати!',
+		'confirm_exit_slider' => 'Точно відкинути незбережені параметри?',
+		'feedback' => array(
+			'body_new_articles' => 'Наявні нові статті (%%d) у FreshRSS.',
+			'body_unread_articles' => '(непрочитано: %%d)',
+			'request_failed' => 'Не вдалося виконати запит. Можливо, інтернет-зʼєднання нестабільне.',
+			'title_new_articles' => 'FreshRSS: нові статті!',
+		),
+		'labels_empty' => 'Міток нема',
+		'new_article' => 'Наявні нові статті. Натисніть, щоб оновити сторінку.',
+		'should_be_activated' => 'Слід увімкнути JavaScript',
+		'unsafe_csp_header' => 'Через використовуваний CSP-заголовок FreshRSS під загрозою XSS-атак. <a target="_blank" href="https://freshrss.github.io/FreshRSS/en/admins/10_ServerConfig.html#security">Переглянути документацію</a>',
+	),
+	'lang' => array(
+		'cs' => 'Čeština',	// IGNORE
+		'de' => 'Deutsch',	// IGNORE
+		'el' => 'Ελληνικά',	// IGNORE
+		'en' => 'English',	// IGNORE
+		'en-us' => 'English (United States)',	// IGNORE
+		'es' => 'Español',	// IGNORE
+		'fa' => 'فارسی',	// IGNORE
+		'fi' => 'Suomi',	// IGNORE
+		'fr' => 'Français',	// IGNORE
+		'he' => 'עברית',	// IGNORE
+		'hu' => 'Magyar',	// IGNORE
+		'id' => 'Bahasa Indonesia',	// IGNORE
+		'it' => 'Italiano',	// IGNORE
+		'ja' => '日本語',	// IGNORE
+		'ko' => '한국어',	// IGNORE
+		'lv' => 'Latviešu',	// IGNORE
+		'nl' => 'Nederlands',	// IGNORE
+		'oc' => 'Occitan',	// IGNORE
+		'pl' => 'Polski',	// IGNORE
+		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
+		'ru' => 'Русский',	// IGNORE
+		'sk' => 'Slovenčina',	// IGNORE
+		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
+		'zh-cn' => '简体中文',	// IGNORE
+		'zh-tw' => '正體中文',	// IGNORE
+	),
+	'menu' => array(
+		'about' => 'Про програму',
+		'account' => 'Обліковий запис',
+		'admin' => 'Адміністрування',
+		'archiving' => 'Архівування',
+		'authentication' => 'Вхід',
+		'check_install' => 'Перевірка встановлення',
+		'configuration' => 'Налаштування',
+		'display' => 'Оформлення',
+		'extensions' => 'Розширення',
+		'logs' => 'Журнали',
+		'privacy' => 'Приватність',
+		'queries' => 'Користувацькі запити',
+		'reading' => 'Читання',
+		'search' => 'Шукати слова або #теги',
+		'search_help' => 'Перегляньте документацію складніших <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">параметрів пошуку</a>',
+		'sharing' => 'Поширення',
+		'shortcuts' => 'Клавіші',
+		'stats' => 'Статистика',
+		'system' => 'Налаштування системи',
+		'update' => 'Оновити',
+		'user_management' => 'Керувати користувачами',
+		'user_profile' => 'Профіль',
+	),
+	'period' => array(
+		'days' => 'д.',
+		'hours' => 'год',
+		'months' => 'міс.',
+		'weeks' => 'тижд',
+		'years' => 'р.',
+	),
+	'share' => array(
+		'Known' => 'Сайти на Known',
+		'archiveIS' => 'archive.is',	// IGNORE
+		'archiveORG' => 'archive.org',	// IGNORE
+		'archivePH' => 'archive.ph',	// IGNORE
+		'bluesky' => 'Bluesky',	// IGNORE
+		'buffer' => 'Buffer',	// IGNORE
+		'clipboard' => 'Копіювати посилання',
+		'diaspora' => 'Diaspora*',	// IGNORE
+		'email' => 'Електронна пошта',
+		'email-webmail-firefox-fix' => 'Електронна пошта (веб-версія — виправлення для Firefox)',
+		'facebook' => 'Facebook',	// IGNORE
+		'gnusocial' => 'GNU social',	// IGNORE
+		'jdh' => 'Journal du hacker',	// IGNORE
+		'lemmy' => 'Lemmy',	// IGNORE
+		'linkding' => 'Linkding',	// IGNORE
+		'linkedin' => 'LinkedIn',	// IGNORE
+		'mastodon' => 'Mastodon',	// IGNORE
+		'movim' => 'Movim',	// IGNORE
+		'omnivore' => 'Omnivore',	// IGNORE
+		'pinboard' => 'Pinboard',	// IGNORE
+		'pinterest' => 'Pinterest',	// IGNORE
+		'pocket' => 'Pocket',	// IGNORE
+		'print' => 'Друк',
+		'raindrop' => 'Raindrop.io',	// IGNORE
+		'reddit' => 'Reddit',	// IGNORE
+		'shaarli' => 'Shaarli',	// IGNORE
+		'telegram' => 'Telegram',	// IGNORE
+		'twitter' => 'Twitter',	// IGNORE
+		'wallabag' => 'wallabag v1',	// IGNORE
+		'wallabagv2' => 'wallabag v2',	// IGNORE
+		'web-sharing-api' => 'Системне поширення',
+		'whatsapp' => 'Whatsapp',	// IGNORE
+		'xing' => 'Xing',	// IGNORE
+	),
+	'short' => array(
+		'attention' => 'Увага!',
+		'blank_to_disable' => 'Щоб вимкнути, залиште порожнім',
+		'by_author' => 'Від:',
+		'by_default' => 'Типово',
+		'damn' => 'Йой!',
+		'default_category' => 'Без категорії',
+		'no' => 'Ні',
+		'not_applicable' => 'Недоступно',
+		'ok' => 'Гаразд!',
+		'or' => 'чи',
+		'yes' => 'Так',
+	),
+	'stream' => array(
+		'load_more' => 'Завантажити більше статей',
+		'mark_all_read' => 'Позначити всі прочитаними',
+		'nothing_to_load' => 'Більше статей нема',
+	),
+);

+ 110 - 0
app/i18n/uk/index.php

@@ -0,0 +1,110 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'about' => array(
+		'_' => 'Про програму',
+		'agpl3' => '<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL 3</a>',	// IGNORE
+		'bug_reports' => array(
+			'environment_information' => array(
+				'_' => 'Дані про систему',
+				'browser' => 'Браузер',
+				'database' => 'База даних',
+				'server_software' => 'Серверне ПЗ',
+				'version_curl' => 'Версія cURL',
+				'version_frss' => 'Версія FreshRSS',
+				'version_php' => 'Версія PHP',
+			),
+		),
+		'bugs_reports' => 'Звіти про вади',
+		'documentation' => 'Документація',
+		'freshrss_description' => 'FreshRSS — це агрегатор і читач RSS-стрічок, який можна встановити на власному сервері. Це надає змогу підписуватись на декілька сайтів новин і читати їх в одній стрічці, не перемикаючись між сайтами. FreshRSS — ощадлива й проста у використанні програма, гнучка в налаштуванні.',
+		'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">на GitHub</a>',
+		'license' => 'Ліцензія',
+		'project_website' => 'Сайт проєкту',
+		'title' => 'Про програму',
+		'version' => 'Версія',
+	),
+	'feed' => array(
+		'empty' => 'Нема статей для показу.',
+		'received' => array(
+			'before_yesterday' => 'Отримано раніше за вчора',
+			'today' => 'Отримано сьогодні',
+			'yesterday' => 'Отримано вчора',
+		),
+		'rss_of' => 'RSS-стрічка %s',
+		'title' => 'Головний потік',
+		'title_fav' => 'Вподобані',
+		'title_global' => 'Глобальний показ',
+	),
+	'log' => array(
+		'_' => 'Журнали',
+		'clear' => 'Очистити журнали',
+		'empty' => 'Файл журналів порожній',
+		'title' => 'Журнали',
+	),
+	'menu' => array(
+		'about' => 'Про FreshRSS',
+		'before_one_day' => 'Старіші за день',
+		'before_one_week' => 'Старіші за тиждень',
+		'bookmark_query' => 'Додати поточний запит у закладки',
+		'favorites' => 'Вподобані (%s)',
+		'global_view' => 'Загальний показ',
+		'important' => 'Важливі стрічки',
+		'main_stream' => 'Головний потік',
+		'mark_all_read' => 'Позначити всі прочитаними',
+		'mark_cat_read' => 'Позначити категорію прочитаною',
+		'mark_feed_read' => 'Позначити стрічку прочитаною',
+		'mark_selection_unread' => 'Позначити вибрані непрочитаними',
+		'mylabels' => 'Мої мітки',
+		'newer_first' => 'Спершу новіші',
+		'non-starred' => 'Показати невподобані',
+		'normal_view' => 'Звичайний показ',
+		'older_first' => 'Спершу старіші',
+		'queries' => 'Користувацькі запити',
+		'read' => 'Показати прочитані',
+		'reader_view' => 'Читацький показ',
+		'rss_view' => 'RSS-стрічка',
+		'search_short' => 'Пошук',
+		'sort' => array(
+			'_' => 'Критерії впорядкування',
+			'c' => array(
+				'name_asc' => 'Заголовки категорії та стрічки А→Я',
+				'name_desc' => 'Заголовки категорії та стрічки Я→А',
+			),
+			'date_asc' => 'Дата оприлюднення 1→9',
+			'date_desc' => 'Дата оприлюднення 9→1',
+			'f' => array(
+				'name_asc' => 'Назва стрічки A→Z',
+				'name_desc' => 'Назва стрічки Z→A',
+			),
+			'id_asc' => 'Спершу найдавніше отримані',
+			'id_desc' => 'Спершу щойно отримані',
+			'link_asc' => 'Посилання А→Я',
+			'link_desc' => 'Посилання Я→А',
+			'rand' => 'Довільний порядок',
+			'title_asc' => 'Заголовок А→Я',
+			'title_desc' => 'Заголовок Я→А',
+		),
+		'starred' => 'Показати вподобані',
+		'stats' => 'Статистика',
+		'subscription' => 'Керування підписками',
+		'unread' => 'Показати непрочитані',
+	),
+	'share' => 'Поширити',
+	'tag' => array(
+		'related' => 'Теги статей',
+	),
+	'tos' => array(
+		'title' => 'Умови надання послуг',
+	),
+);

+ 128 - 0
app/i18n/uk/install.php

@@ -0,0 +1,128 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'action' => array(
+		'finish' => 'Завершити встановлення',
+		'fix_errors_before' => 'Перш ніж почати наступний крок, слід виправити всі помилки.',
+		'keep_install' => 'Зберегти попереднє налаштування',
+		'next_step' => 'Почати наступний крок',
+		'reinstall' => 'Перевстановити FreshRSS',
+	),
+	'bdd' => array(
+		'_' => 'База даних',
+		'conf' => array(
+			'_' => 'Налаштування бази даних',
+			'ko' => 'Перевірте налаштування бази даних.',
+			'ok' => 'Налаштування бази даних збережено.',
+		),
+		'host' => 'Хост',
+		'password' => 'Пароль до бази даних',
+		'prefix' => 'Префікс таблиць',
+		'type' => 'Тип бази даних',
+		'username' => 'Користувацьке імʼя бази даних',
+	),
+	'check' => array(
+		'_' => 'Перевірки',
+		'already_installed' => 'Виявлено вже встановлену FreshRSS!',
+		'cache' => array(
+			'nok' => 'Перевірте доступ до каталога <em>%1$s</em> для користувача <em>%2$s</em>. HTTP-серверу потрібен дозвіл на запис.',
+			'ok' => 'Доступ до каталога кешу працює.',
+		),
+		'ctype' => array(
+			'nok' => 'Не вдалося знайти необхідної бібліотеки перевірки типу символа (php-ctype).',
+			'ok' => 'У вас є необхідна бібліотека перевірки типу символа (ctype).',
+		),
+		'curl' => array(
+			'nok' => 'Не вдалося знайти бібліотеку cURL (пакунок php-curl).',
+			'ok' => 'У вас є бібліотека cURL.',
+		),
+		'data' => array(
+			'nok' => 'Перевірте доступ до каталога <em>%1$s</em> для користувача <em>%2$s</em>. HTTP-серверу потрібен дозвіл на запис.',
+			'ok' => 'Доступ до каталога даних працює.',
+		),
+		'dom' => array(
+			'nok' => 'Не вдалося знайти необхідну бібліотеку роботи з DOM.',
+			'ok' => 'У вас є необхідна бібліотека роботи з DOM.',
+		),
+		'favicons' => array(
+			'nok' => 'Перевірте доступ до каталога <em>%1$s</em> для користувача <em>%2$s</em>. HTTP-серверу потрібен дозвіл на запис.',
+			'ok' => 'Доступ до каталога favicons працює.',
+		),
+		'fileinfo' => array(
+			'nok' => 'Не вдалося знайти бібліотеку PHP fileinfo (пакунок fileinfo).',
+			'ok' => 'У вас є бібліотека fileinfo.',
+		),
+		'json' => array(
+			'nok' => 'Не вдалося знайти бажану бібліотеку розпізнання JSON.',
+			'ok' => 'У вас є бажана бібліотека розпізнання JSON.',
+		),
+		'mbstring' => array(
+			'nok' => 'Не вдалося знайти бажану бібліотеку mbstring для Юнікоду.',
+			'ok' => 'У вас є бажана бібліотека mbstring для Юнікоду.',
+		),
+		'pcre' => array(
+			'nok' => 'Не вдалося знайти необхідну бібліотеку регулярних виразів (php-pcre).',
+			'ok' => 'У вас є необхідна бібліотека регулярних виразів (PCRE).',
+		),
+		'pdo' => array(
+			'nok' => 'Не вдалося знайти PDO чи один із підтримуваних драйверів (pdo_mysql, pdo_sqlite чи pdo_pgsql).',
+			'ok' => 'У вас є PDO та принаймні один із підтримуваних драйверів (pdo_mysql, pdo_sqlite чи pdo_pgsql).',
+		),
+		'php' => array(
+			'nok' => 'У вас PHP версії %s, проте для FreshRSS треба принаймні %s.',
+			'ok' => 'Ваша версія PHP, %s, сумісна з FreshRSS.',
+		),
+		'reload' => 'Повторити перевірку',
+		'tmp' => array(
+			'nok' => 'Перевірте доступ до каталога <em>%1$s</em> для користувача <em>%2$s</em>. HTTP-серверу потрібен дозвіл на запис.',
+			'ok' => 'Доступ до тимчасового каталога працює.',
+		),
+		'unknown_process_username' => 'невідомо',
+		'users' => array(
+			'nok' => 'Перевірте доступ до каталога <em>%1$s</em> для користувача <em>%2$s</em>. HTTP-серверу потрібен дозвіл на запис.',
+			'ok' => 'Доступ до користувацького каталога працює.',
+		),
+		'xml' => array(
+			'nok' => 'Не вдалося знайти необхідну бібліотеку розпізнання XML.',
+			'ok' => 'У вас є необхідна бібліотека розпізнання XML.',
+		),
+	),
+	'conf' => array(
+		'_' => 'Загальне налаштування',
+		'ok' => 'Загальне налаштування збережено.',
+	),
+	'congratulations' => 'Вітаємо!',
+	'default_user' => array(
+		'_' => 'Імʼя типового користувача',
+		'max_char' => 'максимум 16 латинських літер і цифр',
+	),
+	'fix_errors_before' => 'Перш ніж перейти до наступного кроку, слід виправити помилки.',
+	'javascript_is_better' => 'FreshRSS зручніше, коли JavaScript увімкнено',
+	'js' => array(
+		'confirm_reinstall' => 'Перевстановлення FreshRSS призведе до втрати налаштувань. Точно продовжити?',
+	),
+	'language' => array(
+		'_' => 'Мова',
+		'choose' => 'Оберіть мову FreshRSS',
+		'defined' => 'Мову визначено.',
+	),
+	'missing_applied_migrations' => 'Щось пішло не так; створіть порожній файл <em>%s</em> вручну.',
+	'ok' => 'Встановлення успішне.',
+	'session' => array(
+		'nok' => 'Схоже, вебсервер має хибні налаштування кукі для PHP-сеансів!',
+	),
+	'step' => 'крок %d',
+	'steps' => 'Кроки',
+	'this_is_the_end' => 'Готово',
+	'title' => 'Встановлення · FreshRSS',
+);

+ 306 - 0
app/i18n/uk/sub.php

@@ -0,0 +1,306 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'api' => array(
+		'documentation' => 'Скопіюйте наступну URL-адресу для використання зі сторонньою програмою.',
+		'title' => 'API',	// IGNORE
+	),
+	'bookmarklet' => array(
+		'documentation' => 'Посуньте цю кнопку до вашої панелі закладок або натисніть її правою кнопкою мишки та оберіть «Додати посилання до закладок». Тоді натисніть закладку «Підписатися» на будь-якій сторінці, на яку бажаєте підписатись.',
+		'label' => 'Підписатися',
+		'title' => 'Закладка-скрипт',
+	),
+	'category' => array(
+		'_' => 'Категорія',
+		'add' => 'Додати категорію',
+		'archiving' => 'Архівування',
+		'dynamic_opml' => array(
+			'_' => 'Динамічний OPML',
+			'help' => 'Щоб динамічно заповнювати цю категорію стрічками, вкажіть URL-адресу <a href="http://opml.org/" target="_blank">OPML-файлу</a>',
+		),
+		'empty' => 'Порожня категорія',
+		'expand' => 'Розгорнути категорію',
+		'information' => 'Інформація',
+		'open' => 'Відкрити категорію',
+		'opml_url' => 'URL-адреса OPML',
+		'position' => 'Пріоритет показу',
+		'position_help' => 'Визначає порядок категорій',
+		'title' => 'Заголовок',
+	),
+	'feed' => array(
+		'accept_cookies' => 'Приймати кукі',
+		'accept_cookies_help' => 'Дозволити серверу стрічки призначати кукі (зберігаються в памʼяті лише на час запиту)',
+		'add' => 'Додати стрічку',
+		'advanced' => 'Особливості',
+		'archiving' => 'Архівування',
+		'auth' => array(
+			'configuration' => 'Авторизація',
+			'help' => 'Дає змогу читати RSS-стрічки, захищені за допомогою HTTP-авторизації',
+			'http' => 'HTTP-автентифікація',
+			'password' => 'Пароль HTTP',
+			'username' => 'Користувацьке імʼя HTTP',
+		),
+		'change_favicon' => 'Змінити…',
+		'clear_cache' => 'Завжди чистити кеш',
+		'content_action' => array(
+			'_' => 'Дія з текстом при завантаженні тексту статті',
+			'append' => 'Додати після наявного тексту',
+			'prepend' => 'Додати перед наявним текстом',
+			'replace' => 'Замінити наявний текст',
+		),
+		'content_retrieval' => 'Завантаження тексту',
+		'css_cookie' => 'Використовувати кукі при завантаженні тексту статті',
+		'css_cookie_help' => 'Наприклад, <kbd>foo=bar; gdpr_consent=true; cookie=value</kbd>',
+		'css_help' => 'Завантажує скорочені RSS-стрічки (обережно, це повільніше!)',
+		'css_path' => 'CSS-селектор статті на вебсайті',
+		'css_path_filter' => array(
+			'_' => 'CSS-селектор видалення елементів',
+			'help' => 'CSS-селектор може бути списком, наприклад <kbd>footer, aside, p[data-sanitized-class~="menu"]</kbd>',
+		),
+		'description' => 'Опис',
+		'empty' => 'Стрічка порожня. Перевірте, чи її все ще ведуть.',
+		'error' => 'Зі стрічкою виникла проблема. Якщо це повторюватиметься, перевірте, чи стрічка все ще доступна.',
+		'export-as-opml' => array(
+			'download' => 'Завантажити',
+			'help' => 'XML-файл (підмножина даних. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">Перегляньте документацію</a>)',
+			'label' => 'Експорт у форматі OPML',
+		),
+		'ext_favicon' => 'Налаштувати автоматично',
+		'favicon_changed_by_ext' => 'Піктограму налаштовано розширенням <b>%s</b>.',
+		'filteractions' => array(
+			'_' => 'Автоматичний фільтр',
+			'help' => 'По одному фільтру на рядок. Перегляньте <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">документацію операторів</a>.',
+		),
+		'http_headers' => 'HTTP-заголовки',
+		'http_headers_help' => 'По заголовку на рядок. Назву й значення відокремлено двокрапкою (наприклад, <kbd><code>Accept: application/atom+xml<br />Authorization: Bearer деякий-токен</code></kbd>).',
+		'icon' => 'Піктограма',
+		'information' => 'Інформація',
+		'keep_min' => 'Мінімум збережених статей',
+		'kind' => array(
+			'_' => 'Тип джерела стрічки',
+			'html_json' => array(
+				'_' => 'HTML + XPath + JSON із крапковою нотацією (JSON в HTML)',
+				'xpath' => array(
+					'_' => 'XPath-селектор JSON в HTML',
+					'help' => 'Приклад: <code>normalize-space(//script[@type="application/json"])</code> (єдиний JSON)<br />або: <code>//script[@type="application/ld+json"]</code> (по одному JSON-обʼєкту на статтю)',
+				),
+			),
+			'html_xpath' => array(
+				'_' => 'HTML + XPath (скрейпінг)',
+				'feed_title' => array(
+					'_' => 'заголовка стрічки',
+					'help' => 'Наприклад, <code>//title</code> або статичний рядок <code>"Моя власна стрічка"</code>',
+				),
+				'help' => '<dfn><a href="https://www.w3.org/TR/xpath-10/" target="_blank">XPath 1.0</a></dfn> — це стандартна мова запитів, за допомогою яких FreshRSS може скрейпити вебсайти.',
+				'item' => array(
+					'_' => 'знаходження <strong>новин</strong><br /><small>(найважливіше)</small>',
+					'help' => 'Наприклад, <code>//div[@class="news-item"]</code>',
+				),
+				'item_author' => array(
+					'_' => 'автора новини',
+					'help' => 'Може також бути статичним рядком, наприклад <code>"Anonymous"</code>',
+				),
+				'item_categories' => 'тегів новини',
+				'item_content' => array(
+					'_' => 'тексту новини',
+					'help' => 'Приклад для виділення цілої новини: <code>.</code>',
+				),
+				'item_thumbnail' => array(
+					'_' => 'ілюстрації новини',
+					'help' => 'Наприклад, <code>descendant::img/@src</code>',
+				),
+				'item_timeFormat' => array(
+					'_' => 'Особливий формат дати й часу',
+					'help' => 'Необовʼязково. Формат мусить підтримуватись <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a>, наприклад <code>d-m-Y H:i:s</code>',
+				),
+				'item_timestamp' => array(
+					'_' => 'дати новини',
+					'help' => 'Результат буде розпізнано за допомогою <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>',
+				),
+				'item_title' => array(
+					'_' => 'заголовка новини',
+					'help' => 'Використовуйте зокрема <a href="https://developer.mozilla.org/docs/Web/XPath/Axes" target="_blank">вісь XPath</a> <code>descendant::</code>, наприклад <code>descendant::h2</code>',
+				),
+				'item_uid' => array(
+					'_' => 'унікального ідентифікатора новини',
+					'help' => 'Необовʼязково. Наприклад, <code>descendant::div/@data-uri</code>',
+				),
+				'item_uri' => array(
+					'_' => 'URL-адреси новини',
+					'help' => 'Наприклад, <code>descendant::a/@href</code>',
+				),
+				'relative' => 'XPath (відносно новини) до:',
+				'xpath' => 'XPath для:',
+			),
+			'json_dotnotation' => array(
+				'_' => 'JSON (крапкова нотація)',
+				'feed_title' => array(
+					'_' => 'назви стрічки',
+					'help' => 'Наприклад, <code>meta.title</code> або статичний рядок: <code>"Моя власна стрічка"</code>',
+				),
+				'help' => 'У JSON-розмітці з крапковою нотацією між обʼєктами стоять крапки, а масиви позначаються квадратними дужками (наприклад, <code>data.items[0].title</code>)',
+				'item' => array(
+					'_' => 'знаходження <strong>новин</strong><br /><small>(найважливіше)</small>',
+					'help' => 'JSON-шлях до масива, що містить новини, наприклад <code>$</code> чи <code>newsItems</code>',
+				),
+				'item_author' => 'автора новини',
+				'item_categories' => 'тегів новини',
+				'item_content' => array(
+					'_' => 'тексту новини',
+					'help' => 'Ключ, за яким знаходиться текст, наприклад <code>content</code>',
+				),
+				'item_thumbnail' => array(
+					'_' => 'ілюстрації новини',
+					'help' => 'Наприклад, <code>image</code>',
+				),
+				'item_timeFormat' => array(
+					'_' => 'Особливий формат дати й часу',
+					'help' => 'Необовʼязково. Формат мусить підтримуватись <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a>, наприклад <code>d-m-Y H:i:s</code>',
+				),
+				'item_timestamp' => array(
+					'_' => 'дати новини',
+					'help' => 'Результат буде розпізнано за допомогою <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>',
+				),
+				'item_title' => 'заголовка новини',
+				'item_uid' => 'унікального ідентифікатора новини',
+				'item_uri' => array(
+					'_' => 'URL-адреси новини',
+					'help' => 'Наприклад, <code>permalink</code>',
+				),
+				'json' => 'крапкова нотація для:',
+				'relative' => 'шлях у крапковій нотації (відносно новини) до:',
+			),
+			'jsonfeed' => 'JSON-стрічка',
+			'rss' => 'RSS/Atom (типово)',
+			'xml_xpath' => 'XML + XPath',	// IGNORE
+		),
+		'maintenance' => array(
+			'clear_cache' => 'Очистити кеш',
+			'clear_cache_help' => 'Спорожнити кеш стрічки.',
+			'reload_articles' => 'Перезавантажити статті',
+			'reload_articles_help' => 'Перезавантажити стільки статей і завантажити повний текст, якщо визначено селектор.',
+			'title' => 'Супровід',
+		),
+		'max_http_redir' => 'Максимум HTTP-переспрямувань',
+		'max_http_redir_help' => '0 або порожнє поле — вимкнути; щоб не обмежувати переспрямувань, -1',
+		'method' => array(
+			'_' => 'HTTP-метод',
+		),
+		'method_help' => 'POST-тіло автоматично набуває формату <code>application/x-www-form-urlencoded</code> чи <code>application/json</code>',
+		'method_postparams' => 'Тіло POST-запиту',
+		'moved_category_deleted' => 'При видаленні категорії її стрічки переходять до списку «<em>%s</em>».',
+		'mute' => array(
+			'_' => 'зупинено',
+			'state_is_muted' => 'Стрічку зупинено',
+		),
+		'no_selected' => 'Стрічки не обрано.',
+		'number_entries' => 'Статей: %d',
+		'open_feed' => 'Відкрити стрічку %s',
+		'path_entries_conditions' => 'Умови завантаження тексту',
+		'priority' => array(
+			'_' => 'Видимість',
+			'archived' => 'Не показувати (архівовано)',
+			'category' => 'Показати в категорії',
+			'important' => 'Показати у важливих стрічках',
+			'main_stream' => 'Показати в головному потоці',
+		),
+		'proxy' => 'Налаштувати проксі для завантаження стрічки',
+		'proxy_help' => 'Оберіть протокол (наприклад, SOCKS5) і введіть адресу проксі (наприклад, <kbd>127.0.0.1:1080</kbd> чи <kbd>логін:пароль@127.0.0.1:1080</kbd>)',
+		'reset_favicon' => 'Відновити типову',
+		'selector_preview' => array(
+			'show_raw' => 'Показати початковий код',
+			'show_rendered' => 'Показати текст',
+		),
+		'show' => array(
+			'all' => 'Усі стрічки',
+			'error' => 'Лише стрічки з помилками',
+		),
+		'showing' => array(
+			'error' => 'Показано лише стрічки з помилками',
+		),
+		'ssl_verify' => 'Перевіряти SSL-захист',
+		'stats' => 'Статистика',
+		'think_to_add' => 'Можете додати кілька стрічок.',
+		'timeout' => 'Тайм-аут у секундах',
+		'title' => 'Заголовок',
+		'title_add' => 'Додати RSS-стрічку',
+		'ttl' => 'Частота автоматичного оновлення',
+		'unicityCriteria' => array(
+			'_' => 'Критерій унікальності статей',
+			'forced' => '<span title="Заблокувати критерій унікальності, навіть якщо в стрічці є дублі статей">примусово</span>',
+			'help' => 'Стосується некоректних стрічок.<br />⚠️ Зміна політики призведе до появи дублів.',
+			'id' => 'Стандартний ідентифікатор (типово)',
+			'link' => 'Посилання',
+			'sha1:content' => 'Текст',
+			'sha1:content_published' => 'Текст і дата',
+			'sha1:link_published' => 'Посилання й дата',
+			'sha1:link_published_title' => 'Посилання, дата й заголовок',
+			'sha1:link_published_title_content' => 'Посилання, дата, заголовок і текст',
+			'sha1:published' => 'Дата',
+			'sha1:title' => 'Заголовок',
+			'sha1:title_published' => 'Заголовок і дата',
+			'sha1:title_published_content' => 'Заголовок, дата й текст',
+		),
+		'url' => 'URL-адреса стрічки',
+		'useragent' => 'Налаштувати користувацький агент для завантаження стрічки',
+		'useragent_help' => 'Наприклад, <kbd>Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0)</kbd>',
+		'validator' => 'Перевірити коректність стрічки',
+		'website' => 'URL-адреса вебсайту',
+		'websub' => 'Негайні сповіщення за допомогою WebSub',
+	),
+	'import_export' => array(
+		'export' => array(
+			'_' => 'Експорт',
+			'sqlite' => 'Завантажити користувацьку базу даних у форматі SQLite',
+		),
+		'export_labelled' => 'Статті з мітками',
+		'export_opml' => 'Перелік стрічок (OPML)',
+		'export_starred' => 'Вподобані',
+		'feed_list' => 'Список статей %s',
+		'file_to_import' => 'Файл для імпорту<br />(OPML, JSON або ZIP)',
+		'file_to_import_no_zip' => 'Файл для імпорту<br />(OPML або JSON)',
+		'import' => 'Імпорт',
+		'starred_list' => 'Список вподобаних статей',
+		'title' => 'Імпорт/експорт',
+	),
+	'menu' => array(
+		'add' => 'Додати стрічку чи категорію',
+		'import_export' => 'Імпорт/експорт',
+		'label_management' => 'Керування мітками',
+		'stats' => array(
+			'idle' => 'Неактивні стрічки',
+			'main' => 'Основна статистика',
+			'repartition' => 'Перерозподіл статей',
+		),
+		'subscription_management' => 'Керування підписками',
+		'subscription_tools' => 'Засоби підписки',
+	),
+	'tag' => array(
+		'auto_label' => 'Додавати мітку до нових статей',
+		'name' => 'Назва',
+		'new_name' => 'Нова назва',
+		'old_name' => 'Стара назва',
+	),
+	'title' => array(
+		'_' => 'Керування підписками',
+		'add' => 'Додати стрічку чи категорію',
+		'add_category' => 'Додати категорію',
+		'add_dynamic_opml' => 'Додати динамічний OPML',
+		'add_feed' => 'Додати стрічку',
+		'add_label' => 'Додати мітку',
+		'add_opml_category' => 'Назва категорії OPML',
+		'delete_label' => 'Видалити мітку',
+		'feed_management' => 'Керування RSS-стрічками',
+		'subscription_tools' => 'Засоби підписки',
+	),
+);

+ 54 - 0
app/i18n/uk/user.php

@@ -0,0 +1,54 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'email' => array(
+		'feedback' => array(
+			'invalid' => 'Хибна адреса електронної пошти.',
+			'required' => 'Адреса електронної пошти обовʼязкова.',
+		),
+		'validation' => array(
+			'change_email' => 'Можете змінити адресу електронної пошти <a href="%s">на сторінці профілю</a>.',
+			'email_sent_to' => 'На <strong>%s</strong> надіслано лист. Щоб підтвердити вашу адресу, виконайте інструкції з нього.',
+			'feedback' => array(
+				'email_failed' => 'Не вдалося надіслати вам лист через помилку налаштування сервера.',
+				'email_sent' => 'На вашу адресу надіслано лист.',
+				'error' => 'Не вдалося підтвердити адресу електронної пошти.',
+				'ok' => 'Адресу електронної пошти підтверджено.',
+				'unnecessary' => 'Цю адресу електронної пошти вже було підтверджено.',
+				'wrong_token' => 'Не вдалося підтвердити адресу електронної пошти через хибний токен.',
+			),
+			'need_to' => 'Перш ніж почати користуватися %s, підтвердьте адресу електронної пошти %s.',
+			'resend_email' => 'Надіслати лист повторно',
+			'title' => 'Підтвердження адреси електронної пошти',
+		),
+	),
+	'mailer' => array(
+		'email_need_validation' => array(
+			'body' => 'Ви щойно зареєструвались у %s, але спершу вам слід підтвердити адресу електронної пошти. Для цього перейдіть за посиланням:',
+			'title' => 'Слід підтвердити реєстрацію',
+			'welcome' => 'Вітаємо, %s,',
+		),
+	),
+	'password' => array(
+		'invalid' => 'Хибний пароль.',
+	),
+	'tos' => array(
+		'feedback' => array(
+			'invalid' => 'Щоб зареєструватись, необхідно прийняти умови надання послуг.',
+		),
+	),
+	'username' => array(
+		'invalid' => 'Хибне користувацьке імʼя.',
+		'taken' => 'Користувацьке імʼя %s зайнято.',
+	),
+);

+ 1 - 0
app/i18n/zh-cn/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '简体中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 1 - 0
app/i18n/zh-tw/gen.php

@@ -182,6 +182,7 @@ return array(
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE
+		'uk' => 'Українська',	// IGNORE
 		'zh-cn' => '簡體中文',	// IGNORE
 		'zh-tw' => '正體中文',	// IGNORE
 	),

+ 7 - 0
docs/i18n/flags/gen/uk.svg

@@ -0,0 +1,7 @@
+<!-- This file is automatically generated by `cli/check.translation.php -g` -->
+<svg xmlns="http://www.w3.org/2000/svg" width="70" height="20">
+	<g fill="white" font-size="12" font-family="Verdana" text-anchor="middle">
+		<rect rx="3" width="70" height="20" fill="green" />
+		<text x="34" y="14">🇺🇦 100%</text>
+	</g>
+</svg>

Некоторые файлы не были показаны из-за большого количества измененных файлов