mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-10-30 21:13:28 +01:00 
			
		
		
		
	Merge remote-tracking branch 'origin/main' into dev
This commit is contained in:
		| @@ -167,7 +167,7 @@ | ||||
|     "lastUpdateCheckX": "Vérification de la dernière mise à jour : {}", | ||||
|     "remove": "Retirer", | ||||
|     "yesMarkUpdated": "Oui, marquer comme mis à jour", | ||||
|     "fdroid": "F-Droïde Officiel", | ||||
|     "fdroid": "F-Droid Officiel", | ||||
|     "appIdOrName": "ID ou nom de l'application", | ||||
|     "appId": "ID de l'application", | ||||
|     "appWithIdOrNameNotFound": "Aucune application n'a été trouvée avec cet identifiant ou ce nom", | ||||
|   | ||||
| @@ -281,14 +281,14 @@ | ||||
|     "parallelDownloads": "Párhuzamos letöltéseket enged", | ||||
|     "installMethod": "Telepítési mód", | ||||
|     "normal": "Normál", | ||||
|     "root": "Gyökér", | ||||
|     "root": "Root", | ||||
|     "shizukuBinderNotFound": "A Shizuku nem fut", | ||||
|     "useSystemFont": "Használja a rendszer betűtípusát", | ||||
|     "systemFontError": "Hiba a rendszer betűtípusának betöltésekor: {}", | ||||
|     "useVersionCodeAsOSVersion": "Az app verziókód használata a rendszer által észlelt verzióként", | ||||
|     "requestHeader": "Kérelem fejléc", | ||||
|     "useLatestAssetDateAsReleaseDate": "Használja a legújabb tartalomfeltöltést megjelenési dátumként", | ||||
|     "defaultPseudoVersioningMethod": "Alapértelmezett álversziós módszer", | ||||
|     "defaultPseudoVersioningMethod": "Alapértelmezett álverziós módszer", | ||||
|     "partialAPKHash": "Részleges APK Hash", | ||||
|     "APKLinkHash": "APK Link Hash", | ||||
|     "directAPKLink": "Közvetlen APK Link", | ||||
|   | ||||
							
								
								
									
										359
									
								
								assets/translations/uk.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								assets/translations/uk.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,359 @@ | ||||
| { | ||||
|     "invalidURLForSource": "Неправильна URL-адреса для джерела застосунку {}", | ||||
|     "noReleaseFound": "Не вдалося знайти відповідне видання", | ||||
|     "noVersionFound": "Не вдалося визначити версію видання", | ||||
|     "urlMatchesNoSource": "URL не відповідає відомому джерелу", | ||||
|     "cantInstallOlderVersion": "Не можна встановити старішу версію застосунку", | ||||
|     "appIdMismatch": "Ідентифікатор пакета, завантажений, не відповідає ідентифікатору існуючого застосунку", | ||||
|     "functionNotImplemented": "Цей клас не реалізував цю функцію", | ||||
|     "placeholder": "Заповнювач", | ||||
|     "someErrors": "Виникла деяка помилка", | ||||
|     "unexpectedError": "Неочікувана помилка", | ||||
|     "ok": "Добре", | ||||
|     "and": "та", | ||||
|     "githubPATLabel": "Персональний ключ доступу GitHub (збільшує обмеження на швидкість)", | ||||
|     "includePrereleases": "Включити попередні видання", | ||||
|     "fallbackToOlderReleases": "Повернутися до старіших видань", | ||||
|     "filterReleaseTitlesByRegEx": "Фільтрувати заголовки видань за допомогою регулярного виразу", | ||||
|     "invalidRegEx": "Неприпустимий регулярний вираз", | ||||
|     "noDescription": "Немає опису", | ||||
|     "cancel": "Скасувати", | ||||
|     "continue": "Продовжити", | ||||
|     "requiredInBrackets": "(Обов'язково)", | ||||
|     "dropdownNoOptsError": "ПОМИЛКА: В ВИПАДАЮЧОМУ СПИСКУ МАЄ БУТИ ХОЧА Б ОДИН ЕЛЕМЕНТ", | ||||
|     "colour": "Колір", | ||||
|     "githubStarredRepos": "Відзначені репозиторії GitHub", | ||||
|     "uname": "Ім'я користувача", | ||||
|     "wrongArgNum": "Надано неправильну кількість аргументів", | ||||
|     "xIsTrackOnly": "{} - тільки відстежування", | ||||
|     "source": "Джерело", | ||||
|     "app": "застосунок", | ||||
|     "appsFromSourceAreTrackOnly": "Додатки з цього джерела є лише для відстежування.", | ||||
|     "youPickedTrackOnly": "Ви вибрали опцію лише для відстежування.", | ||||
|     "trackOnlyAppDescription": "Застосунок буде відстежуватися для оновлень, але Obtainium не зможе його завантажити або встановити.", | ||||
|     "cancelled": "Скасовано", | ||||
|     "appAlreadyAdded": "Застосунок вже додано", | ||||
|     "alreadyUpToDateQuestion": "Застосунок вже оновлено?", | ||||
|     "addApp": "Додати Застосунок", | ||||
|     "appSourceURL": "URL-адреса джерела застосунку", | ||||
|     "error": "Помилка", | ||||
|     "add": "Додати", | ||||
|     "searchSomeSourcesLabel": "Пошук (Лише деякі джерела)", | ||||
|     "search": "Пошук", | ||||
|     "additionalOptsFor": "Додаткові опції для {}", | ||||
|     "supportedSources": "Підтримувані джерела", | ||||
|     "trackOnlyInBrackets": "(Тільки для відстеження)", | ||||
|     "searchableInBrackets": "(Можливий пошук)", | ||||
|     "appsString": "Додатки", | ||||
|     "noApps": "Додатків немає", | ||||
|     "noAppsForFilter": "Додатків для фільтрації немає", | ||||
|     "byX": "За {}", | ||||
|     "percentProgress": "Прогрес: {}%", | ||||
|     "pleaseWait": "Будь ласка, зачекайте", | ||||
|     "updateAvailable": "Доступно оновлення", | ||||
|     "notInstalled": "Не встановлено", | ||||
|     "pseudoVersion": "псевдо-версія", | ||||
|     "selectAll": "Вибрати все", | ||||
|     "deselectX": "Скасувати вибір {}", | ||||
|     "xWillBeRemovedButRemainInstalled": "{} буде видалено з Obtainium, але залишиться встановленим на пристрої.", | ||||
|     "removeSelectedAppsQuestion": "Видалити вибрані додатки?", | ||||
|     "removeSelectedApps": "Видалити вибрані додатки", | ||||
|     "updateX": "Оновити {}", | ||||
|     "installX": "Встановити {}", | ||||
|     "markXTrackOnlyAsUpdated": "Позначити {}\n(Тільки відстежування)\nяк оновлено", | ||||
|     "changeX": "Змінити {}", | ||||
|     "installUpdateApps": "Встановити/Оновити додатки", | ||||
|     "installUpdateSelectedApps": "Встановити/Оновити вибрані додатки", | ||||
|     "markXSelectedAppsAsUpdated": "Позначити {} вибрані додатки як оновлені?", | ||||
|     "no": "Ні", | ||||
|     "yes": "Так", | ||||
|     "markSelectedAppsUpdated": "Позначити вибрані додатки як оновлені", | ||||
|     "pinToTop": "Закріпити угорі", | ||||
|     "unpinFromTop": "Відкріпити зверху", | ||||
|     "resetInstallStatusForSelectedAppsQuestion": "Скинути статус встановлення для вибраних додатків?", | ||||
|     "installStatusOfXWillBeResetExplanation": "Статус встановлення будь-яких вибраних додатків буде скинутий.\n\nЦе може допомогти, коли версія застосунку, відображена в Obtainium, є неправильною через невдалі оновлення або інші проблеми.", | ||||
|     "customLinkMessage": "Ці посилання працюють на пристроях з встановленим Obtainium", | ||||
|     "shareAppConfigLinks": "Поділитися посиланнями на конфігурацію Застосунку як HTML", | ||||
|     "shareSelectedAppURLs": "Поділитися вибраними URL-адресами додатків", | ||||
|     "resetInstallStatus": "Скинути статус встановлення", | ||||
|     "more": "Більше", | ||||
|     "removeOutdatedFilter": "Видалити фільтр застарілих додатків", | ||||
|     "showOutdatedOnly": "Показати лише застарілі додатки", | ||||
|     "filter": "Фільтр", | ||||
|     "filterApps": "Фільтрувати додатки", | ||||
|     "appName": "Назва застосунку", | ||||
|     "author": "Автор", | ||||
|     "upToDateApps": "Актуальні додатки", | ||||
|     "nonInstalledApps": "Невстановлені додатки", | ||||
|     "importExport": "Імпорт/Експорт", | ||||
|     "settings": "Налаштування", | ||||
|     "exportedTo": "Експортовано в {}", | ||||
|     "obtainiumExport": "Експорт з Obtainium", | ||||
|     "invalidInput": "Недійсний ввід", | ||||
|     "importedX": "Імпортовано {}", | ||||
|     "obtainiumImport": "Імпорт в Obtainium", | ||||
|     "importFromURLList": "Імпорт зі списку URL-адрес", | ||||
|     "searchQuery": "Пошуковий запит", | ||||
|     "appURLList": "Список URL-адрес додатків", | ||||
|     "line": "Лінія", | ||||
|     "searchX": "Пошук {}", | ||||
|     "noResults": "Результати відсутні", | ||||
|     "importX": "Імпорт {}", | ||||
|     "importedAppsIdDisclaimer": "Імпортовані додатки можуть неправильно відображатися як \"Не встановлені\".\nДля виправлення цього перевстановіть їх через Obtainium.\nЦе не повинно вплинути на дані додатків.\n\nПов'язано лише з URL-адресами та імпортом від третіх сторін.", | ||||
|     "importErrors": "Помилки імпорту", | ||||
|     "importedXOfYApps": "Імпортовано {} з {} додатків.", | ||||
|     "followingURLsHadErrors": "Помилки в наступних URL-адресах:", | ||||
|     "selectURL": "Вибрати URL", | ||||
|     "selectURLs": "Вибрати URL-адреси", | ||||
|     "pick": "Вибрати", | ||||
|     "theme": "Тема", | ||||
|     "dark": "Темна", | ||||
|     "light": "Світла", | ||||
|     "followSystem": "Дотримуватися системи", | ||||
|     "useBlackTheme": "Використовувати чисто чорну темну тему", | ||||
|     "appSortBy": "Сортувати додатки за", | ||||
|     "authorName": "Автор/Назва", | ||||
|     "nameAuthor": "Назва/Автор", | ||||
|     "asAdded": "За додаванням", | ||||
|     "appSortOrder": "Порядок сортування додатків", | ||||
|     "ascending": "За зростанням", | ||||
|     "descending": "За спаданням", | ||||
|     "bgUpdateCheckInterval": "Інтервал перевірки оновлень у фоновому режимі", | ||||
|     "neverManualOnly": "Ніколи - Тільки вручну", | ||||
|     "appearance": "Вигляд", | ||||
|     "showWebInAppView": "Показати джерело застосунку у вигляді веб-сторінки", | ||||
|     "pinUpdates": "Закріпити оновлення у верхній частині вигляду додатків", | ||||
|     "updates": "Оновлення", | ||||
|     "sourceSpecific": "Певне джерело", | ||||
|     "appSource": "Джерело застосунку", | ||||
|     "noLogs": "Немає логів", | ||||
|     "appLogs": "Лог застосунку", | ||||
|     "close": "Закрити", | ||||
|     "share": "Поділитися", | ||||
|     "appNotFound": "Застосунок не знайдено", | ||||
|     "obtainiumExportHyphenatedLowercase": "експорт з Obtainium", | ||||
|     "pickAnAPK": "Вибрати APK", | ||||
|     "appHasMoreThanOnePackage": "{} має більше одного пакету:", | ||||
|     "deviceSupportsXArch": "Ваш пристрій підтримує архітектуру процесора {}.", | ||||
|     "deviceSupportsFollowingArchs": "Ваш пристрій підтримує наступні архітектури процесора:", | ||||
|     "warning": "Попередження", | ||||
|     "sourceIsXButPackageFromYPrompt": "Джерело застосунку - '{}' але пакет випуску походить з '{}'. Продовжити?", | ||||
|     "updatesAvailable": "Доступні оновлення", | ||||
|     "updatesAvailableNotifDescription": "Повідомляє користувача, що доступні оновлення для одного чи декількох додатків, які відстежує Obtainium", | ||||
|     "noNewUpdates": "Немає нових оновлень.", | ||||
|     "xHasAnUpdate": "{} має оновлення.", | ||||
|     "appsUpdated": "Додатки оновлено", | ||||
|     "appsUpdatedNotifDescription": "Повідомляє користувача, що оновлення одного чи декількох додатків було застосовано в фоновому режимі", | ||||
|     "xWasUpdatedToY": "{} було оновлено до {}.", | ||||
|     "errorCheckingUpdates": "Помилка перевірки оновлень", | ||||
|     "errorCheckingUpdatesNotifDescription": "Повідомлення, яке з'являється, коли перевірка оновлень в фоновому режимі завершується невдачею", | ||||
|     "appsRemoved": "Додатки видалено", | ||||
|     "appsRemovedNotifDescription": "Повідомляє користувача, що один чи декілька додатків були видалені через помилки при завантаженні", | ||||
|     "xWasRemovedDueToErrorY": "{} було видалено через цю помилку: {}", | ||||
|     "completeAppInstallation": "Завершення установки застосунку", | ||||
|     "obtainiumMustBeOpenToInstallApps": "Для встановлення додатків Obtainium має бути відкритий", | ||||
|     "completeAppInstallationNotifDescription": "Прохання користувача повернутися до Obtainium для завершення установки застосунку", | ||||
|     "checkingForUpdates": "Перевірка оновлень", | ||||
|     "checkingForUpdatesNotifDescription": "Тимчасове повідомлення, яке з'являється при перевірці оновлень", | ||||
|     "pleaseAllowInstallPerm": "Будь ласка, дозвольте Obtainium встановлювати додатки", | ||||
|     "trackOnly": "Тільки відстеження", | ||||
|     "errorWithHttpStatusCode": "Помилка {} HTTP-коду", | ||||
|     "versionCorrectionDisabled": "Виправлення версії вимкнено (здається, плагін не працює)", | ||||
|     "unknown": "Невідомо", | ||||
|     "none": "Нічого", | ||||
|     "never": "Ніколи", | ||||
|     "latestVersionX": "Остання версія: {}", | ||||
|     "installedVersionX": "Встановлено: {}", | ||||
|     "lastUpdateCheckX": "Остання перевірка оновлень: {}", | ||||
|     "remove": "Видалити", | ||||
|     "yesMarkUpdated": "Так, позначити як оновлене", | ||||
|     "fdroid": "F-Droid Офіційний", | ||||
|     "appIdOrName": "Ідентифікатор або назва застосунку", | ||||
|     "appId": "Ідентифікатор застосунку", | ||||
|     "appWithIdOrNameNotFound": "Застосунок з таким ідентифікатором або назвою не знайдено", | ||||
|     "reposHaveMultipleApps": "Сховища можуть містити кілька додатків", | ||||
|     "fdroidThirdPartyRepo": "F-Droid Стороннє сховище", | ||||
|     "steamMobile": "Мобільний Steam", | ||||
|     "steamChat": "Чат Steam", | ||||
|     "install": "Встановити", | ||||
|     "markInstalled": "Позначити як встановлене", | ||||
|     "update": "Оновити", | ||||
|     "markUpdated": "Позначити як оновлене", | ||||
|     "additionalOptions": "Додаткові опції", | ||||
|     "disableVersionDetection": "Вимкнути визначення версії", | ||||
|     "noVersionDetectionExplanation": "Цю опцію слід використовувати лише для додатків, де визначення версії працює неправильно.", | ||||
|     "downloadingX": "Завантаження {}", | ||||
|     "downloadNotifDescription": "Повідомляє користувача про прогрес завантаження застосунку", | ||||
|     "noAPKFound": "APK не знайдено", | ||||
|     "noVersionDetection": "Визначення версії відключено", | ||||
|     "categorize": "Категоризувати", | ||||
|     "categories": "Категорії", | ||||
|     "category": "Категорія", | ||||
|     "noCategory": "Без категорії", | ||||
|     "noCategories": "Немає категорій", | ||||
|     "deleteCategoriesQuestion": "Видалити категорії?", | ||||
|     "categoryDeleteWarning": "Усі додатки у видалених категоріях будуть переведені у некатегоризовані.", | ||||
|     "addCategory": "Додати категорію", | ||||
|     "label": "Мітка", | ||||
|     "language": "Мова", | ||||
|     "copiedToClipboard": "Скопійовано в буфер обміну", | ||||
|     "storagePermissionDenied": "Відмовлено у дозволі на доступ до сховища", | ||||
|     "selectedCategorizeWarning": "Це замінить будь-які існуючі налаштування категорій для вибраних додатків.", | ||||
|     "filterAPKsByRegEx": "Фільтрувати APK за регулярним виразом", | ||||
|     "removeFromObtainium": "Видалити з Obtainium", | ||||
|     "uninstallFromDevice": "Видалити з пристрою", | ||||
|     "onlyWorksWithNonVersionDetectApps": "Працює лише з застосунками з вимкненим визначенням версії.", | ||||
|     "releaseDateAsVersion": "Використовувати дату випуску як рядок версії", | ||||
|     "releaseDateAsVersionExplanation": "Цю опцію слід використовувати лише для додатків, де визначення версії працює неправильно, але є дата випуску.", | ||||
|     "changes": "Зміни", | ||||
|     "releaseDate": "Дата випуску", | ||||
|     "importFromURLsInFile": "Імпорт з URL-адрес у файлі (наприклад, OPML)", | ||||
|     "versionDetectionExplanation": "Порівняти рядок версії з версією, визначеною операційною системою", | ||||
|     "versionDetection": "Визначення версії", | ||||
|     "standardVersionDetection": "Стандартне визначення версії", | ||||
|     "groupByCategory": "Групувати за категоріями", | ||||
|     "autoApkFilterByArch": "Спробувати фільтрувати APK за архітектурою ЦП, якщо можливо", | ||||
|     "overrideSource": "Перевизначити джерело", | ||||
|     "dontShowAgain": "Не показувати це знову", | ||||
|     "dontShowTrackOnlyWarnings": "Не показувати попередження про 'Тільки відстеження'", | ||||
|     "dontShowAPKOriginWarnings": "Не показувати попередження про походження APK", | ||||
|     "moveNonInstalledAppsToBottom": "Перемістити невстановлені додатки вниз у перегляді додатків", | ||||
|     "gitlabPATLabel": "Особистий токен GitLab (Увімкнення пошуку та краще виявлення APK)", | ||||
|     "about": "Про програму", | ||||
|     "requiresCredentialsInSettings": "{} потребує додаткових облікових даних (у налаштуваннях)", | ||||
|     "checkOnStart": "Перевірити наявність оновлень при запуску", | ||||
|     "tryInferAppIdFromCode": "Спробувати вивести ідентифікатор застосунку з вихідного коду", | ||||
|     "removeOnExternalUninstall": "Автоматично видаляти додатки, які було видалено зовнішнім чином", | ||||
|     "pickHighestVersionCode": "Автоматично вибрати APK з найвищим кодом версії", | ||||
|     "checkUpdateOnDetailPage": "Перевіряти наявність оновлень при відкритті сторінки деталей застосунку", | ||||
|     "disablePageTransitions": "Вимкнути анімації переходів між сторінками", | ||||
|     "reversePageTransitions": "Зворотні анімації переходів між сторінками", | ||||
|     "minStarCount": "Мінімальна кількість зірок", | ||||
|     "addInfoBelow": "Додати цю інформацію нижче.", | ||||
|     "addInfoInSettings": "Додати цю інформацію у налаштуваннях.", | ||||
|     "githubSourceNote": "Лімітування швидкості GitHub можна уникнути, використовуючи ключ API.", | ||||
|     "gitlabSourceNote": "Вилучення APK з GitLab може не працювати без ключа API.", | ||||
|     "sortByLastLinkSegment": "Сортувати лише за останнім сегментом посилання", | ||||
|     "filterReleaseNotesByRegEx": "Фільтрувати примітки до релізу за регулярним виразом", | ||||
|     "customLinkFilterRegex": "Фільтр кастомного посилання на APK за регулярним виразом (за замовчуванням '.apk$')", | ||||
|     "appsPossiblyUpdated": "Оновлення додатків спробовано", | ||||
|     "appsPossiblyUpdatedNotifDescription": "Повідомляє користувача, що оновлення одного або декількох додатків можливо були застосовані в фоновому режимі", | ||||
|     "xWasPossiblyUpdatedToY": "{} можливо було оновлено до {}.", | ||||
|     "enableBackgroundUpdates": "Увімкнути оновлення в фоновому режимі", | ||||
|     "backgroundUpdateReqsExplanation": "Оновлення в фоновому режимі може бути неможливим для всіх додатків.", | ||||
|     "backgroundUpdateLimitsExplanation": "Успіх фонової установки може бути визначений лише після відкриття Obtainium.", | ||||
|     "verifyLatestTag": "Перевірити тег 'latest'", | ||||
|     "intermediateLinkRegex": "Фільтр для 'Проміжного' Посилання для Відвідування", | ||||
|     "filterByLinkText": "Фільтрувати посилання за текстом посилання", | ||||
|     "intermediateLinkNotFound": "Проміжне посилання не знайдено", | ||||
|     "intermediateLink": "Проміжне посилання", | ||||
|     "exemptFromBackgroundUpdates": "Виключено з фонових оновлень (якщо ввімкнено)", | ||||
|     "bgUpdatesOnWiFiOnly": "Вимкнути фонові оновлення поза Wi-Fi", | ||||
|     "autoSelectHighestVersionCode": "Автоматичний вибір APK з найвищим кодом версії", | ||||
|     "versionExtractionRegEx": "Регулярний вираз для вилучення рядка версії", | ||||
|     "matchGroupToUse": "Група співпадінь для використання в регулярному виразі вилучення версії", | ||||
|     "highlightTouchTargets": "Підсвічувати менш очевидні області дотику", | ||||
|     "pickExportDir": "Вибрати каталог експорту", | ||||
|     "autoExportOnChanges": "Автоматичний експорт при змінах", | ||||
|     "includeSettings": "Включити налаштування", | ||||
|     "filterVersionsByRegEx": "Фільтрувати версії за регулярним виразом", | ||||
|     "trySelectingSuggestedVersionCode": "Спробуйте вибрати запропонований код версії APK", | ||||
|     "dontSortReleasesList": "Зберігати порядок випуску з API", | ||||
|     "reverseSort": "Зворотне сортування", | ||||
|     "takeFirstLink": "Вибрати перше посилання", | ||||
|     "skipSort": "Пропустити сортування", | ||||
|     "debugMenu": "Меню налагодження", | ||||
|     "bgTaskStarted": "Запущено фонове завдання - перевірте журнали.", | ||||
|     "runBgCheckNow": "Запустити перевірку оновлень в фоновому режимі зараз", | ||||
|     "versionExtractWholePage": "Застосувати регулярний вираз вилучення версії до всієї сторінки", | ||||
|     "installing": "Встановлення", | ||||
|     "skipUpdateNotifications": "Пропустити сповіщення про оновлення", | ||||
|     "updatesAvailableNotifChannel": "Доступні оновлення", | ||||
|     "appsUpdatedNotifChannel": "Додатки оновлені", | ||||
|     "appsPossiblyUpdatedNotifChannel": "Спроба оновлення додатків", | ||||
|     "errorCheckingUpdatesNotifChannel": "Помилка перевірки оновлень", | ||||
|     "appsRemovedNotifChannel": "Додатки видалені", | ||||
|     "downloadingXNotifChannel": "Завантаження {}", | ||||
|     "completeAppInstallationNotifChannel": "Завершення встановлення застосунку", | ||||
|     "checkingForUpdatesNotifChannel": "Перевірка оновлень", | ||||
|     "onlyCheckInstalledOrTrackOnlyApps": "Перевіряти лише встановлені та додатки, які відстежуються для оновлень", | ||||
|     "supportFixedAPKURL": "Підтримка фіксованих посилань на APK", | ||||
|     "selectX": "Вибрати {}", | ||||
|     "parallelDownloads": "Дозволити паралельні завантаження", | ||||
|     "installMethod": "Метод встановлення", | ||||
|     "normal": "Звичайний", | ||||
|     "root": "Root", | ||||
|     "shizukuBinderNotFound": "Сумісний сервіс Shizuku не було знайдено", | ||||
|     "useSystemFont": "Використовувати системний шрифт", | ||||
|     "systemFontError": "Помилка завантаження системного шрифту: {}", | ||||
|     "useVersionCodeAsOSVersion": "Використовувати код версії застосунку як версію, визначену операційною системою", | ||||
|     "requestHeader": "Заголовок запиту", | ||||
|     "useLatestAssetDateAsReleaseDate": "Використовувати останню дату завантаження ресурсу як дату випуску", | ||||
|     "defaultPseudoVersioningMethod": "Метод за замовчуванням псевдо-версіонування", | ||||
|     "partialAPKHash": "Хеш часткового APK", | ||||
|     "APKLinkHash": "Хеш посилання на APK", | ||||
|     "directAPKLink": "Пряме посилання на APK", | ||||
|     "pseudoVersionInUse": "Використовується псевдо-версія", | ||||
|     "installed": "Встановлено", | ||||
|     "latest": "Остання", | ||||
|     "invertRegEx": "Інвертувати регулярний вираз", | ||||
|     "note": "Примітка", | ||||
|     "selfHostedNote": "Випадаючий список \"{}\" може використовуватися для доступу до власних/призначених для самостійного використання екземплярів будь-якого джерела.", | ||||
|     "badDownload": "APK не вдалося розпарсити (несумісний або часткове завантаження)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Видалити Застосунок?", | ||||
|         "other": "Видалити додатки?" | ||||
|     }, | ||||
|     "tooManyRequestsTryAgainInMinutes": { | ||||
|         "one": "Забагато запитів (обмеження швидкості) - повторіть спробу через {} хвилину", | ||||
|         "other": "Забагато запитів (обмеження швидкості) - повторіть спробу через {} хвилин" | ||||
|     }, | ||||
|     "bgUpdateGotErrorRetryInMinutes": { | ||||
|         "one": "Помилка перевірки оновлень у фоновому режимі - спробую знову через {} хвилину", | ||||
|         "other": "Помилка перевірки оновлень у фоновому режимі - спробую знову через {} хвилин" | ||||
|     }, | ||||
|     "bgCheckFoundUpdatesWillNotifyIfNeeded": { | ||||
|         "one": "Фонова перевірка оновлень знайшла {} оновлення - сповістить користувача, якщо це необхідно", | ||||
|         "other": "Фонова перевірка оновлень знайшла {} оновлень - сповістить користувача, якщо це необхідно" | ||||
|     }, | ||||
|     "apps": { | ||||
|         "one": "{} Застосунок", | ||||
|         "other": "{} Додатки" | ||||
|     }, | ||||
|     "url": { | ||||
|         "one": "{} URL", | ||||
|         "other": "{} URL-адреси" | ||||
|     }, | ||||
|     "minute": { | ||||
|         "one": "{} Хвилина", | ||||
|         "other": "{} Хвилин" | ||||
|     }, | ||||
|     "hour": { | ||||
|         "one": "{} Година", | ||||
|         "other": "{} Годин" | ||||
|     }, | ||||
|     "day": { | ||||
|         "one": "{} День", | ||||
|         "other": "{} Днів" | ||||
|     }, | ||||
|     "clearedNLogsBeforeXAfterY": { | ||||
|         "one": "Очищено {n} журнал (до = {before}, після = {after})", | ||||
|         "other": "Очищено {n} журналів (до = {before}, після = {after})" | ||||
|     }, | ||||
|     "xAndNMoreUpdatesAvailable": { | ||||
|         "one": "{} і 1 інше Застосунок мають оновлення.", | ||||
|         "other": "{} і {} інших додатки мають оновлення." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesInstalled": { | ||||
|         "one": "{} і 1 інше Застосунок було оновлено.", | ||||
|         "other": "{} і {} інших додатків було оновлено." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesPossiblyInstalled": { | ||||
|         "one": "{} і 1 інше Застосунок можливо було оновлено.", | ||||
|         "other": "{} і {} інших додатків можливо було оновлено." | ||||
|     }, | ||||
|     "apk": { | ||||
|         "one": "{} APK", | ||||
|         "other": "{} APK-файли" | ||||
|     } | ||||
| } | ||||
| @@ -52,7 +52,7 @@ | ||||
|     "pleaseWait": "请稍候", | ||||
|     "updateAvailable": "更新可用", | ||||
|     "notInstalled": "未安装", | ||||
|     "pseudoVersion": "伪版本", | ||||
|     "pseudoVersion": "虚拟版本号", | ||||
|     "selectAll": "全选", | ||||
|     "deselectX": "取消选择 {}", | ||||
|     "xWillBeRemovedButRemainInstalled": "“{}”将从 Obtainium 中删除,但仍安装在您的设备中。", | ||||
| @@ -208,7 +208,7 @@ | ||||
|     "changes": "更新日志", | ||||
|     "releaseDate": "发行日期", | ||||
|     "importFromURLsInFile": "从文件中的 URL 导入(如 OPML)", | ||||
|     "versionDetectionExplanation": "将版本字符串与操作系统检测到的版本进行协调", | ||||
|     "versionDetectionExplanation": "使发行版本号与应用定义的版本号一致", | ||||
|     "versionDetection": "版本检测", | ||||
|     "standardVersionDetection": "常规版本检测", | ||||
|     "groupByCategory": "按类别分组显示", | ||||
| @@ -224,7 +224,7 @@ | ||||
|     "checkOnStart": "启动时进行一次检查", | ||||
|     "tryInferAppIdFromCode": "尝试从源代码推断应用 ID", | ||||
|     "removeOnExternalUninstall": "自动删除列表中已卸载的应用", | ||||
|     "pickHighestVersionCode": "自动选择版本号最高的 APK 文件", | ||||
|     "pickHighestVersionCode": "自动选取内部版本号最高的 APK 文件", | ||||
|     "checkUpdateOnDetailPage": "打开应用详情页时进行检查", | ||||
|     "disablePageTransitions": "禁用页面过渡动画效果", | ||||
|     "reversePageTransitions": "反转页面过渡动画效果", | ||||
| @@ -248,7 +248,7 @@ | ||||
|     "intermediateLink": "中转链接", | ||||
|     "exemptFromBackgroundUpdates": "禁用后台更新(如果已经全局启用)", | ||||
|     "bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新", | ||||
|     "autoSelectHighestVersionCode": "自动选择版本号最高的 APK 文件", | ||||
|     "autoSelectHighestVersionCode": "自动选择内部版本号最高的 APK 文件", | ||||
|     "versionExtractionRegEx": "版本号提取规则(正则表达式)", | ||||
|     "matchGroupToUse": "引用的捕获组", | ||||
|     "highlightTouchTargets": "突出展示不明显的触摸区域", | ||||
| @@ -285,20 +285,20 @@ | ||||
|     "shizukuBinderNotFound": "未发现兼容的 Shizuku 服务", | ||||
|     "useSystemFont": "使用系统字体", | ||||
|     "systemFontError": "加载系统字体出错:{}", | ||||
|     "useVersionCodeAsOSVersion": "使用应用程序版本代码作为操作系统检测到的版本", | ||||
|     "useVersionCodeAsOSVersion": "使用内部版本号代替应用定义的版本号", | ||||
|     "requestHeader": "请求标头", | ||||
|     "useLatestAssetDateAsReleaseDate": "使用最新资产上传作为发布日期", | ||||
|     "defaultPseudoVersioningMethod": "默认伪版本控制方法", | ||||
|     "partialAPKHash": "部分 APK 哈希值", | ||||
|     "APKLinkHash": "APK 链接哈希", | ||||
|     "directAPKLink": "直接 APK 链接", | ||||
|     "pseudoVersionInUse": "伪版本正在使用", | ||||
|     "installed": "已安装", | ||||
|     "latest": "最新的", | ||||
|     "invertRegEx": "反转正则表达式", | ||||
|     "useLatestAssetDateAsReleaseDate": "使用最近文件上传时间作为发行日期", | ||||
|     "defaultPseudoVersioningMethod": "默认虚拟版本方案", | ||||
|     "partialAPKHash": "APK 文件散列值片段", | ||||
|     "APKLinkHash": "APK 文件链接散列值", | ||||
|     "directAPKLink": "APK 文件直链", | ||||
|     "pseudoVersionInUse": "正在使用虚拟版本号", | ||||
|     "installed": "当前版本", | ||||
|     "latest": "最新版本", | ||||
|     "invertRegEx": "反转匹配", | ||||
|     "note": "备注", | ||||
|     "selfHostedNote": "{}\"下拉菜单可用于访问任何来源的自托管/自定义实例。", | ||||
|     "badDownload": "无法解析 APK(不兼容或部分下载)", | ||||
|     "selfHostedNote": "可以通过“{}”下拉菜单来指向任意来源的自托管/自定义实例。", | ||||
|     "badDownload": "无法解析 APK 文件(不兼容或文件不完整)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "是否删除应用?", | ||||
|         "other": "是否删除应用?" | ||||
|   | ||||
| @@ -2,7 +2,6 @@ import 'dart:convert'; | ||||
| import 'dart:io'; | ||||
|  | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/app_sources/github.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| @@ -117,91 +116,58 @@ class GitLab extends AppSource { | ||||
|     String standardUrl, | ||||
|     Map<String, dynamic> additionalSettings, | ||||
|   ) async { | ||||
|     bool fallbackToOlderReleases = | ||||
|         additionalSettings['fallbackToOlderReleases'] == true; | ||||
|     // Prepare request params | ||||
|     var names = GitHub().getAppNames(standardUrl); | ||||
|     String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {}); | ||||
|     Iterable<APKDetails> apkDetailsList = []; | ||||
|     if (PAT != null) { | ||||
|       var names = GitHub().getAppNames(standardUrl); | ||||
|       Response res = await sourceRequest( | ||||
|           'https://${hosts[0]}/api/v4/projects/${names.author}%2F${names.name}/releases?private_token=$PAT', | ||||
|           additionalSettings); | ||||
|       if (res.statusCode != 200) { | ||||
|         throw getObtainiumHttpError(res); | ||||
|       } | ||||
|       var json = jsonDecode(res.body) as List<dynamic>; | ||||
|       apkDetailsList = json.map((e) { | ||||
|         var apkUrlsFromAssets = (e['assets']?['links'] as List<dynamic>? ?? []) | ||||
|             .map((e) { | ||||
|               return (e['direct_asset_url'] ?? e['url'] ?? '') as String; | ||||
|             }) | ||||
|             .where((s) => s.isNotEmpty) | ||||
|             .toList(); | ||||
|         List<String> uploadedAPKsFromDescription = | ||||
|             ((e['description'] ?? '') as String) | ||||
|                 .split('](') | ||||
|                 .join('\n') | ||||
|                 .split('.apk)') | ||||
|                 .join('.apk\n') | ||||
|                 .split('\n') | ||||
|                 .where((s) => s.startsWith('/uploads/') && s.endsWith('apk')) | ||||
|                 .map((s) => '$standardUrl$s') | ||||
|                 .toList(); | ||||
|         var apkUrlsSet = apkUrlsFromAssets.toSet(); | ||||
|         apkUrlsSet.addAll(uploadedAPKsFromDescription); | ||||
|         var releaseDateString = e['released_at'] ?? e['created_at']; | ||||
|         DateTime? releaseDate = releaseDateString != null | ||||
|             ? DateTime.parse(releaseDateString) | ||||
|             : null; | ||||
|         return APKDetails( | ||||
|             e['tag_name'] ?? e['name'], | ||||
|             getApkUrlsFromUrls(apkUrlsSet.toList()), | ||||
|             GitHub().getAppNames(standardUrl), | ||||
|             releaseDate: releaseDate); | ||||
|       }); | ||||
|     } else { | ||||
|       Response res = await sourceRequest( | ||||
|           '$standardUrl/-/tags?format=atom', additionalSettings); | ||||
|       if (res.statusCode != 200) { | ||||
|         throw getObtainiumHttpError(res); | ||||
|       } | ||||
|       var standardUri = Uri.parse(standardUrl); | ||||
|       var parsedHtml = parse(res.body); | ||||
|       apkDetailsList = parsedHtml.querySelectorAll('entry').map((entry) { | ||||
|         var entryContent = parse( | ||||
|             parseFragment(entry.querySelector('content')!.innerHtml).text); | ||||
|         var apkUrls = [ | ||||
|           ...getLinksFromParsedHTML( | ||||
|               entryContent, | ||||
|               RegExp( | ||||
|                   '^${standardUri.path.replaceAllMapped(RegExp(r'[.*+?^${}()|[\]\\]'), (x) { | ||||
|                     return '\\${x[0]}'; | ||||
|                   })}/uploads/[^/]+/[^/]+\\.apk\$', | ||||
|                   caseSensitive: false), | ||||
|               standardUri.origin), | ||||
|           // GitLab releases may contain links to externally hosted APKs | ||||
|           ...getLinksFromParsedHTML(entryContent, | ||||
|                   RegExp('/[^/]+\\.apk\$', caseSensitive: false), '') | ||||
|               .where((element) => Uri.parse(element).host != '') | ||||
|         ]; | ||||
|         var entryId = entry.querySelector('id')?.innerHtml; | ||||
|         var version = | ||||
|             entryId == null ? null : Uri.parse(entryId).pathSegments.last; | ||||
|         var releaseDateString = entry.querySelector('updated')?.innerHtml; | ||||
|         DateTime? releaseDate = releaseDateString != null | ||||
|             ? DateTime.parse(releaseDateString) | ||||
|             : null; | ||||
|         if (version == null) { | ||||
|           throw NoVersionError(); | ||||
|         } | ||||
|         return APKDetails(version, getApkUrlsFromUrls(apkUrls), | ||||
|             GitHub().getAppNames(standardUrl), | ||||
|             releaseDate: releaseDate); | ||||
|       }); | ||||
|     String optionalAuth = (PAT != null) ? 'private_token=$PAT' : ''; | ||||
|  | ||||
|     // Request data from REST API | ||||
|     Response res = await sourceRequest( | ||||
|         'https://${hosts[0]}/api/v4/projects/${names.author}%2F${names.name}/releases?$optionalAuth', | ||||
|         additionalSettings); | ||||
|     if (res.statusCode != 200) { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|  | ||||
|     // Extract .apk details from received data | ||||
|     Iterable<APKDetails> apkDetailsList = []; | ||||
|     var json = jsonDecode(res.body) as List<dynamic>; | ||||
|     apkDetailsList = json.map((e) { | ||||
|       var apkUrlsFromAssets = (e['assets']?['links'] as List<dynamic>? ?? []) | ||||
|           .map((e) { | ||||
|             return (e['direct_asset_url'] ?? e['url'] ?? '') as String; | ||||
|           }) | ||||
|           .where((s) => s.isNotEmpty) | ||||
|           .toList(); | ||||
|       List<String> uploadedAPKsFromDescription = | ||||
|           ((e['description'] ?? '') as String) | ||||
|               .split('](') | ||||
|               .join('\n') | ||||
|               .split('.apk)') | ||||
|               .join('.apk\n') | ||||
|               .split('\n') | ||||
|               .where((s) => s.startsWith('/uploads/') && s.endsWith('apk')) | ||||
|               .map((s) => '$standardUrl$s') | ||||
|               .toList(); | ||||
|       var apkUrlsSet = apkUrlsFromAssets.toSet(); | ||||
|       apkUrlsSet.addAll(uploadedAPKsFromDescription); | ||||
|       var releaseDateString = e['released_at'] ?? e['created_at']; | ||||
|       DateTime? releaseDate = releaseDateString != null | ||||
|           ? DateTime.parse(releaseDateString) | ||||
|           : null; | ||||
|       return APKDetails( | ||||
|           e['tag_name'] ?? e['name'], | ||||
|           getApkUrlsFromUrls(apkUrlsSet.toList()), | ||||
|           GitHub().getAppNames(standardUrl), | ||||
|           releaseDate: releaseDate); | ||||
|     }); | ||||
|     if (apkDetailsList.isEmpty) { | ||||
|       throw NoReleasesError(); | ||||
|     } | ||||
|  | ||||
|     // Fallback procedure | ||||
|     bool fallbackToOlderReleases = | ||||
|         additionalSettings['fallbackToOlderReleases'] == true; | ||||
|     if (fallbackToOlderReleases) { | ||||
|       if (additionalSettings['trackOnly'] != true) { | ||||
|         apkDetailsList = | ||||
| @@ -211,6 +177,7 @@ class GitLab extends AppSource { | ||||
|         throw NoReleasesError(); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return apkDetailsList.first; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -38,6 +38,7 @@ List<MapEntry<Locale, String>> supportedLocales = const [ | ||||
|   MapEntry(Locale('nl'), 'Nederlands'), | ||||
|   MapEntry(Locale('vi'), 'Tiếng Việt'), | ||||
|   MapEntry(Locale('tr'), 'Türkçe'), | ||||
|   MapEntry(Locale('uk'), 'Українська'), | ||||
| ]; | ||||
| const fallbackLocale = Locale('en'); | ||||
| const localeDir = 'assets/translations'; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user