From a90f30391cc8a2a7c892031da5d9a2ab46ac31b4 Mon Sep 17 00:00:00 2001 From: Konstantin <32730812+kkovaletp@users.noreply.github.com> Date: Sun, 24 Mar 2024 23:42:44 +0200 Subject: [PATCH] Add Ukrainian translation (#875) --- api/graphql/models/generated.go | 4 +- api/graphql/schema.graphql | 1 + ui/src/Pages/SettingsPage/UserPreferences.tsx | 6 + ui/src/__generated__/globalTypes.ts | 1 + .../extractedTranslations/ua/translation.json | 359 ++++++++++++++++++ ui/src/localization.ts | 6 + 6 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 ui/src/extractedTranslations/ua/translation.json diff --git a/api/graphql/models/generated.go b/api/graphql/models/generated.go index b7401e8c..f0ec10b6 100644 --- a/api/graphql/models/generated.go +++ b/api/graphql/models/generated.go @@ -108,6 +108,7 @@ const ( LanguageTranslationDanish LanguageTranslation = "Danish" LanguageTranslationSpanish LanguageTranslation = "Spanish" LanguageTranslationPolish LanguageTranslation = "Polish" + LanguageTranslationUkrainian LanguageTranslation = "Ukrainian" LanguageTranslationGerman LanguageTranslation = "German" LanguageTranslationRussian LanguageTranslation = "Russian" LanguageTranslationTraditionalChinese LanguageTranslation = "TraditionalChinese" @@ -125,6 +126,7 @@ var AllLanguageTranslation = []LanguageTranslation{ LanguageTranslationDanish, LanguageTranslationSpanish, LanguageTranslationPolish, + LanguageTranslationUkrainian, LanguageTranslationGerman, LanguageTranslationRussian, LanguageTranslationTraditionalChinese, @@ -136,7 +138,7 @@ var AllLanguageTranslation = []LanguageTranslation{ func (e LanguageTranslation) IsValid() bool { switch e { - case LanguageTranslationEnglish, LanguageTranslationFrench, LanguageTranslationItalian, LanguageTranslationSwedish, LanguageTranslationDanish, LanguageTranslationSpanish, LanguageTranslationPolish, LanguageTranslationGerman, LanguageTranslationRussian, LanguageTranslationTraditionalChinese, LanguageTranslationSimplifiedChinese, LanguageTranslationPortuguese, LanguageTranslationBasque, LanguageTranslationTurkish: + case LanguageTranslationEnglish, LanguageTranslationFrench, LanguageTranslationItalian, LanguageTranslationSwedish, LanguageTranslationDanish, LanguageTranslationSpanish, LanguageTranslationPolish, LanguageTranslationUkrainian, LanguageTranslationGerman, LanguageTranslationRussian, LanguageTranslationTraditionalChinese, LanguageTranslationSimplifiedChinese, LanguageTranslationPortuguese, LanguageTranslationBasque, LanguageTranslationTurkish: return true } return false diff --git a/api/graphql/schema.graphql b/api/graphql/schema.graphql index 2fed2e1e..f6c3d576 100644 --- a/api/graphql/schema.graphql +++ b/api/graphql/schema.graphql @@ -294,6 +294,7 @@ enum LanguageTranslation { Danish, Spanish, Polish, + Ukrainian, German, Russian, TraditionalChinese, diff --git a/ui/src/Pages/SettingsPage/UserPreferences.tsx b/ui/src/Pages/SettingsPage/UserPreferences.tsx index 2667fd3b..42f9c76f 100644 --- a/ui/src/Pages/SettingsPage/UserPreferences.tsx +++ b/ui/src/Pages/SettingsPage/UserPreferences.tsx @@ -59,6 +59,12 @@ const languagePreferences = [ flag: 'tr', value: LanguageTranslation.Turkish, }, + { + key: 15, + label: 'Українська', + flag: 'ua', + value: LanguageTranslation.Ukrainian, + }, ] const themePreferences = (t: TranslationFn) => [ diff --git a/ui/src/__generated__/globalTypes.ts b/ui/src/__generated__/globalTypes.ts index 3019a75e..782711c7 100644 --- a/ui/src/__generated__/globalTypes.ts +++ b/ui/src/__generated__/globalTypes.ts @@ -25,6 +25,7 @@ export enum LanguageTranslation { Swedish = 'Swedish', TraditionalChinese = 'TraditionalChinese', Turkish = 'Turkish', + Ukrainian = 'Ukrainian', } export enum MediaType { diff --git a/ui/src/extractedTranslations/ua/translation.json b/ui/src/extractedTranslations/ua/translation.json new file mode 100644 index 00000000..801f4b58 --- /dev/null +++ b/ui/src/extractedTranslations/ua/translation.json @@ -0,0 +1,359 @@ +{ + "album_filter": { + "only_favorites": "Показати тільки улюблені", + "sort": "Сортування", + "sort_by": "Сортувати за", + "sorting_options": { + "date_imported": "Дата імпортування", + "date_shot": "Дата фотографування", + "title": "Назва", + "type": "Тип" + } + }, + "general": { + "action": { + "add": "Додати", + "cancel": "Відмінити", + "remove": "Видалити", + "save": "Зберегти" + }, + "loading": { + "album": "Завантаження альбому", + "default": "Завантаження...", + "page": "Завантаження сторінки", + "paginate": { + "faces": "Завантаження ще людей", + "media": "Завантаження ще медіафайлів" + }, + "shares": "Завантаження спільних ресурсів..." + } + }, + "header": { + "search": { + "loading": "Завантаження результатів...", + "no_results": "Результатів не знайдено", + "placeholder": "Пошук", + "result_type": { + "albums": "Альбоми", + "media": "Медіафайли" + } + } + }, + "login_page": { + "field": { + "password": "Пароль", + "submit": "Увійти", + "username": "Імʼя користувача" + }, + "initial_setup": { + "field": { + "photo_path": { + "label": "Шлях до медіафайлів", + "placeholder": "/шлях/до/медіафайлів" + }, + "submit": "Налаштувати Photoview" + }, + "title": "Початкове налаштування" + }, + "welcome": "Ласкаво просимо до Photoview" + }, + "meta": { + "description": "Проста та зручна фотогалерея для персональних серверів" + }, + "people_page": { + "action_label": { + "change_label": "Змінити мітку", + "detach_images": "Від’єднати обличчя", + "merge_people": "Обʼєднати обличчя", + "move_faces": "Перемістити обличчя" + }, + "face_group": { + "label_placeholder": "Мітка", + "unlabeled": "Без мітки", + "unlabeled_person": "Людина без мітки" + }, + "modal": { + "action": { + "merge": "Обʼєднати" + }, + "detach_image_faces": { + "action": { + "detach": "Від’єднати світлини з обличчями", + "select_images": "Вибрати світлини для від’єднання" + }, + "description": "Від’єднати обрані світлини цієї групи обличь та перемістити їх до нових груп", + "title": "Від’єднати світлини з обличчями" + }, + "merge_face_groups": { + "description": "Усі світлини цієї групи обличь будуть обʼєднані з обраною групою.", + "destination_table": { + "title": "Оберіть обличчя призначення" + }, + "title": "Об’єднати групи обличь" + }, + "move_image_faces": { + "description": "Перемістити вибрані світлини цієї групи обличь до іншої групи обличь", + "destination_face_group_table": { + "move_action": "Перемістити світлини обличь", + "title": "Оберіть групу обличь призначення" + }, + "image_select_table": { + "next_action": "Далі", + "title": "Оберіть світлини для переміщення" + }, + "title": "Перемістити світлини обличь" + } + }, + "recognize_unlabeled_faces_button": "Розпізнати обличчя без міток", + "tableselect_face_group": { + "search_faces_placeholder": "Шукати обличчя..." + }, + "tableselect_image_faces": { + "search_images_placeholder": "Шукати світлини..." + } + }, + "photos_page": { + "title": "Хронологія" + }, + "places_page": { + "title": "Місця" + }, + "routes": { + "page_not_found": "Сторінку не знайдено" + }, + "settings": { + "concurrent_workers": { + "description": "Максимальна кількість завдань сканування, які можна запускати одночасно", + "title": "Кількість одночасних оброблювачів завдань" + }, + "logout": "Завершити сесію користувача", + "periodic_scanner": { + "checkbox_label": "Увімкнути періодичне сканування", + "field": { + "description": "Як часто сканер повинен виконувати автоматичне сканування для всіх користувачів", + "label": "Періодичний інтервал сканування" + }, + "interval_unit": { + "days": "Дні", + "hour": "Години", + "minutes": "Хвилини", + "months": "Місяці", + "seconds": "Секунди" + }, + "title": "Періодичне сканування" + }, + "scanner": { + "description": "Сканує всіх користувачів на наявність нових або оновлених медіафайлів", + "scan_all_users": "Сканувати всіх користувачів", + "title": "Сканер" + }, + "user_preferences": { + "change_language": { + "description": "Змінити мову сайту для цього користувача", + "label": "Мова сайту" + }, + "language_selector": { + "placeholder": "Обрати мову" + }, + "theme": { + "auto": { + "label": "Така-ж, як в системі" + }, + "dark": { + "label": "Темна" + }, + "description": "Змінити зовнішній вигляд сайту", + "light": { + "label": "Світла" + }, + "title": "Налаштування теми" + }, + "title": "Налаштування користувача" + }, + "users": { + "add_user": { + "submit": "Додати користувача" + }, + "confirm_delete_user": { + "action": "Видалити {{user}}", + "description": "<0>Ви впевнені, що бажаєте видалити <1>1>?0>
Цю дію не можна буде скасувати
", + "title": "Видалити користувача" + }, + "password_reset": { + "description": "Зміна пароля для <1>{{username}}1>", + "form": { + "label": "Новий пароль", + "placeholder": "пароль", + "submit": "Змінити пароль" + }, + "title": "Зміна пароля" + }, + "table": { + "column_names": { + "action": "Дія", + "capabilities": "Можливості", + "photo_path": "Шлях до медіафайлів", + "username": "Імʼя користувача" + }, + "new_user": "Новий користувач", + "row": { + "action": { + "change_password": "Змінити пароль", + "delete": "Видалити", + "edit": "Редагувати", + "scan": "Сканувати" + } + } + }, + "title": "Користувачі" + }, + "version_info": { + "build_date_title": "Дата збірки", + "title": "Версія Photoview", + "version_title": "Версія релізу" + } + }, + "share_page": { + "media": { + "title": "Спільні медіатеки" + }, + "protected_share": { + "description": "Ця спільна медіатека захищена паролем.", + "password_required_error": "Пароль потрібен", + "title": "Захищена медіатека" + }, + "share_not_found": "Спільну медіатеку не знайдено", + "share_not_found_description": "Можливо, спільний доступ закінчився або його було видалено.", + "wrong_password": "Неправильний пароль, спробуйте ще раз." + }, + "sidebar": { + "album": { + "album_cover": "Обкладинка альбому", + "download": { + "high-resolutions": { + "description": "JPEG-файли високої роздільної здатності RAW-зображень", + "title": "Висока роздільна здатність" + }, + "originals": { + "description": "Оригінальні світлини та відео", + "title": "Оригінали" + }, + "thumbnails": { + "description": "Зображення з низькою роздільною здатністю, без відео", + "title": "Мініатюри" + }, + "web-videos": { + "description": "Відео, оптимізовані для Інтернету", + "title": "Конвертовані відео" + } + }, + "reset_cover": "Скинути обкладинку", + "set_cover": "Встановити як обкладинку альбому", + "title_placeholder": "Назва альбому" + }, + "download": { + "filesize": { + "byte_one": "{{count}} Байт", + "byte_other": "{{count}} Байтів", + "giga_byte_one": "{{count}} ГБ", + "giga_byte_other": "{{count}} ГБ", + "kilo_byte_one": "{{count}} КБ", + "kilo_byte_other": "{{count}} КБ", + "mega_byte_one": "{{count}} МБ", + "mega_byte_other": "{{count}} МБ", + "tera_byte_one": "{{count}} ТБ", + "tera_byte_other": "{{count}} ТБ" + }, + "table_columns": { + "dimensions": "Габарити", + "file_size": "Розмір", + "file_type": "Тип", + "name": "Імʼя" + }, + "title": "Завантажити" + }, + "location": { + "title": "Місцезнаходження" + }, + "media": { + "album_path": "Шлях до альбому", + "exif": { + "exposure_program": { + "action_program": "Програма дії", + "aperture_priority": "Пріоритет діафрагми", + "bulb": "Лампочка", + "creative_program": "Творча програма", + "landscape_mode": "Альбомний режим", + "manual": "Ручний", + "normal_program": "Нормальна програма", + "not_defined": "Не визначений", + "portrait_mode": "Портретний режим", + "shutter_priority": "Пріоритет витримки" + }, + "flash": { + "auto": "Автоматичний", + "did_not_fire": "Не стріляв", + "fired": "Стріляв", + "no_flash": "Без спалаху", + "no_flash_function": "Немає функції спалаху", + "off": "Вимкнено", + "on": "Увімкнено", + "red_eye_reduction": "Зменшення ефекту червоних очей", + "return_detected": "Повернення виявлено", + "return_not_detected": "Повернення не виявлено" + }, + "name": { + "aperture": "Діафрагма", + "camera": "Камера", + "coordinates": "Координати", + "date_shot": "Дата зйомки", + "exposure": "Експозиція", + "exposure_program": "Експозиційна програма", + "flash": "Спалах", + "focal_length": "Фокусна відстань", + "iso": "ISO", + "lens": "Об'єктив", + "maker": "Виробник" + } + } + }, + "people": { + "action_label": { + "detach_image": "Від’єднати зображення", + "merge_face": "Об'єднати обличчя", + "move_face": "Перемістити обличчя" + }, + "confirm_image_detach": "Ви впевнені, що бажаєте від’єднати це зображення?", + "title": "Люди" + }, + "sharing": { + "add_share": "Додати спільний доступ", + "copy_link": "Копіювати посилання", + "delete": "Видалити", + "more": "Більше", + "no_shares_found": "Спільних доступів не знайдено", + "public_link": "Публічне посилання", + "title": "Параметри спільного доступу" + } + }, + "sidemenu": { + "albums": "Альбоми", + "people": "Люди", + "photos": "Хронологія", + "places": "Місця", + "settings": "Налаштування" + }, + "timeline_filter": { + "date": { + "dropdown_all": "Від сьогодні", + "dropdown_year": "{{year}} та раніше", + "label": "Дата" + } + }, + "title": { + "loading_album": "Завантаження альбому", + "login": "Логін", + "people": "Люди", + "settings": "Налаштування" + } +} diff --git a/ui/src/localization.ts b/ui/src/localization.ts index bb76e30b..93722172 100644 --- a/ui/src/localization.ts +++ b/ui/src/localization.ts @@ -97,6 +97,12 @@ export const loadTranslations = () => { i18n.changeLanguage('pl') }) return + case LanguageTranslation.Ukrainian: + import('./extractedTranslations/ua/translation.json').then(language => { + i18n.addResourceBundle('ua', 'translation', language) + i18n.changeLanguage('ua') + }) + return case LanguageTranslation.German: import('./extractedTranslations/de/translation.json').then(language => { i18n.addResourceBundle('de', 'translation', language)