Add Russian i18n with DB translations, locale API, and curator review UI.

UI chrome via react-i18next, catalog text in entity_translations with ru.wikipedia seeding, locale-aware search, and Translations page for publish workflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Danila Khodjaef
2026-07-15 11:51:46 +03:00
co-authored by Cursor
parent f247b418d8
commit ca58c43648
51 changed files with 2252 additions and 101 deletions
+10
View File
@@ -0,0 +1,10 @@
{
"title": "Art history notes",
"readSource": "Read source",
"categoryTechnique": "Technique",
"categoryComposition": "Composition",
"categorySubject": "Subject",
"categorySymbolism": "Symbolism",
"categoryHistorical": "Historical context",
"categoryOther": "Notes"
}
+6
View File
@@ -0,0 +1,6 @@
{
"enterGallery": "Enter Gallery",
"noBio": "No biography available yet.",
"wikipediaSource": "Text adapted from Wikipedia",
"backToTimeline": "← Back to Timeline"
}
+13
View File
@@ -0,0 +1,13 @@
{
"loading": "Loading…",
"close": "Close",
"back": "Back",
"save": "Save",
"cancel": "Cancel",
"yes": "Yes",
"no": "No",
"error": "Something went wrong",
"localeEn": "EN",
"localeRu": "RU",
"language": "Language"
}
+14
View File
@@ -0,0 +1,14 @@
{
"checked": "Checked",
"fixIt": "Fix it",
"more": "More",
"clear": "Clear",
"upload": "Upload",
"searching": "Searching…",
"saving": "Saving…",
"loginTitle": "Curator login",
"username": "Username",
"password": "Password",
"signIn": "Sign in",
"loginFailed": "Login failed"
}
+14
View File
@@ -0,0 +1,14 @@
{
"backToTimeline": "← Back to Timeline",
"exitToTimeline": "Exit to Timeline",
"loadingGallery": "Loading gallery…",
"instructionsTitle": "Gallery controls",
"instructionMove": "Drag to look around",
"instructionZoom": "Scroll to zoom",
"instructionClick": "Click a painting to view details",
"wingOf": "Wing {{current}} of {{total}}",
"exitConfirmTitle": "Leave gallery?",
"exitConfirmBody": "Return to the timeline or stay in the hall.",
"stay": "Stay",
"exit": "Exit"
}
+20
View File
@@ -0,0 +1,20 @@
{
"title": "Virtual Art Gallery",
"subtitle": "Explore art history on an interactive timeline — enter 3D galleries and discover connections between artists and masterpieces.",
"loadingArtHistory": "Loading art history…",
"loadingPortraits": "Loading portraits…",
"openingArtistGallery": "Opening artist gallery…",
"openingMovementGallery": "Opening movement gallery…",
"backToTimeline": "← Back to Timeline",
"backToGallery": "← Back to Gallery",
"curatorLogin": "Curator login",
"curatorLogout": "Log out",
"signedInAs": "Signed in as {{username}}",
"debugMode": "Debug mode",
"showMoreDebug": "Show more (debug)",
"checkup": "Checkup",
"translations": "Translations",
"curatorRequiredTitle": "Curator access required",
"curatorRequiredBody": "Sign in as a curator to use this tool.",
"backToGalleryBtn": "Back to gallery"
}
+11
View File
@@ -0,0 +1,11 @@
{
"aboutArtist": "About {{name}}",
"influencedBy": "Influenced By",
"influenced": "Influenced",
"noInfluences": "No documented influences for this work.",
"noInfluencedWorks": "No documented works influenced by this painting yet.",
"catalogPosition": "Catalog position",
"lightboxHint": "Click anywhere to close",
"prevPainting": "Previous painting",
"nextPainting": "Next painting"
}
+10
View File
@@ -0,0 +1,10 @@
{
"label": "Search",
"placeholder": "Search artists, paintings, movements…",
"resultsLabel": "Search results",
"noMatches": "No matches found.",
"groupArtist": "Artists",
"groupMovement": "Movements",
"groupPainting": "Paintings",
"searchFailed": "Search failed"
}
+20
View File
@@ -0,0 +1,20 @@
{
"title": "Translation review",
"back": "← Back to gallery",
"locale": "Locale",
"entityType": "Entity type",
"status": "Status",
"all": "All",
"draft": "Draft",
"reviewed": "Reviewed",
"published": "Published",
"coverage": "Coverage",
"artistsBio": "Artists with bio (ru)",
"paintingsTitle": "Paintings with title alias (ru)",
"canonical": "English (canonical)",
"translation": "Translation",
"saveDraft": "Save draft",
"publish": "Publish",
"noRows": "No translation rows match the filter.",
"loadFailed": "Failed to load translations"
}
+10
View File
@@ -0,0 +1,10 @@
{
"title": "Историко-художественные заметки",
"readSource": "Источник",
"categoryTechnique": "Техника",
"categoryComposition": "Композиция",
"categorySubject": "Сюжет",
"categorySymbolism": "Символика",
"categoryHistorical": "Исторический контекст",
"categoryOther": "Заметки"
}
+6
View File
@@ -0,0 +1,6 @@
{
"enterGallery": "Войти в галерею",
"noBio": "Биография пока недоступна.",
"wikipediaSource": "Текст адаптирован из Википедии",
"backToTimeline": "← На шкалу времени"
}
+13
View File
@@ -0,0 +1,13 @@
{
"loading": "Загрузка…",
"close": "Закрыть",
"back": "Назад",
"save": "Сохранить",
"cancel": "Отмена",
"yes": "Да",
"no": "Нет",
"error": "Что-то пошло не так",
"localeEn": "EN",
"localeRu": "RU",
"language": "Язык"
}
+14
View File
@@ -0,0 +1,14 @@
{
"checked": "Проверено",
"fixIt": "Исправить",
"more": "Ещё",
"clear": "Очистить",
"upload": "Загрузить",
"searching": "Поиск…",
"saving": "Сохранение…",
"loginTitle": "Вход куратора",
"username": "Имя пользователя",
"password": "Пароль",
"signIn": "Войти",
"loginFailed": "Ошибка входа"
}
+14
View File
@@ -0,0 +1,14 @@
{
"backToTimeline": "← На шкалу времени",
"exitToTimeline": "Выход на шкалу времени",
"loadingGallery": "Загрузка галереи…",
"instructionsTitle": "Управление",
"instructionMove": "Перетаскивайте для обзора",
"instructionZoom": "Колёсико — масштаб",
"instructionClick": "Нажмите на картину для подробностей",
"wingOf": "Крыло {{current}} из {{total}}",
"exitConfirmTitle": "Покинуть галерею?",
"exitConfirmBody": "Вернуться на шкалу времени или остаться в зале.",
"stay": "Остаться",
"exit": "Выход"
}
+20
View File
@@ -0,0 +1,20 @@
{
"title": "Виртуальная художественная галерея",
"subtitle": "Исследуйте историю искусства на интерактивной шкале времени — входите в 3D-залы и открывайте связи между художниками и шедеврами.",
"loadingArtHistory": "Загрузка истории искусства…",
"loadingPortraits": "Загрузка портретов…",
"openingArtistGallery": "Открытие галереи художника…",
"openingMovementGallery": "Открытие галереи направления…",
"backToTimeline": "← На шкалу времени",
"backToGallery": "← В галерею",
"curatorLogin": "Вход куратора",
"curatorLogout": "Выйти",
"signedInAs": "Вы вошли как {{username}}",
"debugMode": "Режим отладки",
"showMoreDebug": "Показать больше (отладка)",
"checkup": "Проверка",
"translations": "Переводы",
"curatorRequiredTitle": "Требуется доступ куратора",
"curatorRequiredBody": "Войдите как куратор, чтобы использовать этот инструмент.",
"backToGalleryBtn": "Вернуться в галерею"
}
+11
View File
@@ -0,0 +1,11 @@
{
"aboutArtist": "О {{name}}",
"influencedBy": "Под влиянием",
"influenced": "Влияние на",
"noInfluences": "Для этой работы нет задокументированных влияний.",
"noInfluencedWorks": "Пока нет задокументированных работ под влиянием этой картины.",
"catalogPosition": "Позиция в каталоге",
"lightboxHint": "Нажмите в любом месте, чтобы закрыть",
"prevPainting": "Предыдущая картина",
"nextPainting": "Следующая картина"
}
+10
View File
@@ -0,0 +1,10 @@
{
"label": "Поиск",
"placeholder": "Художники, картины, направления…",
"resultsLabel": "Результаты поиска",
"noMatches": "Ничего не найдено.",
"groupArtist": "Художники",
"groupMovement": "Направления",
"groupPainting": "Картины",
"searchFailed": "Ошибка поиска"
}
+20
View File
@@ -0,0 +1,20 @@
{
"title": "Проверка переводов",
"back": "← В галерею",
"locale": "Язык",
"entityType": "Тип объекта",
"status": "Статус",
"all": "Все",
"draft": "Черновик",
"reviewed": "Проверено",
"published": "Опубликовано",
"coverage": "Охват",
"artistsBio": "Художники с биографией (ru)",
"paintingsTitle": "Картины с русским названием",
"canonical": "Английский (оригинал)",
"translation": "Перевод",
"saveDraft": "Сохранить черновик",
"publish": "Опубликовать",
"noRows": "Нет строк по выбранному фильтру.",
"loadFailed": "Не удалось загрузить переводы"
}