From 1c9fa201913cef28b9522fab74294e52ef63ba62 Mon Sep 17 00:00:00 2001 From: Danila Khodjaef Date: Thu, 13 Aug 2026 12:45:44 +0300 Subject: [PATCH] Localise timeline and movement chart captions in English and Russian. Co-authored-by: Cursor --- client/src/components/MovementBands.tsx | 4 +++- client/src/components/MovementTree.tsx | 5 +++-- client/src/components/Timeline.tsx | 4 +++- client/src/components/VerticalMovementBands.tsx | 4 +++- client/src/components/VerticalTimeline.tsx | 4 +++- client/src/locales/en/home.json | 5 +++++ client/src/locales/ru/home.json | 5 +++++ 7 files changed, 25 insertions(+), 6 deletions(-) diff --git a/client/src/components/MovementBands.tsx b/client/src/components/MovementBands.tsx index db6e456..c3c3bb8 100644 --- a/client/src/components/MovementBands.tsx +++ b/client/src/components/MovementBands.tsx @@ -1,4 +1,5 @@ import { useMemo, useRef, useCallback, useEffect, useLayoutEffect, useState, memo } from 'react'; +import { useTranslation } from 'react-i18next'; import type { ArtMovement, Artist } from '../types'; import { portraitThumbUrl } from '../api/client'; import { useQueuedImageSrc } from '../hooks/useQueuedImageSrc'; @@ -1695,6 +1696,7 @@ export default function MovementBands({ onArtistHover, onPortraitsLoadingChange, }: Props) { + const { t } = useTranslation('home'); const canvasRef = useRef(null); const pendingPortraitsRef = useRef(0); const [portraitsLoading, setPortraitsLoading] = useState(false); @@ -2193,7 +2195,7 @@ export default function MovementBands({ return (

- Scroll to zoom · drag to pan · each movement stream is a solid colour band through history + {t('captionClassicFlow')}

(null); const [canvas, setCanvas] = useState({ w: 900, h: 600 }); const [panning, setPanning] = useState(false); @@ -534,8 +536,7 @@ export default function MovementTree({ return (

- Roots at the bottom, living movements at the crown · scroll to zoom · drag to - pan · click a branch to enter its gallery + {t('captionTreeFlow')}

(null); const [dragging, setDragging] = useState<'left' | 'right' | 'pan' | null>(null); const [containerWidth, setContainerWidth] = useState(800); @@ -365,7 +367,7 @@ export default function Timeline({ eras, viewStart, viewEnd, onViewChange, absol

- Click an era or event to zoom · Scroll to zoom · Drag to pan + {t('captionClassicTimeline')}

); diff --git a/client/src/components/VerticalMovementBands.tsx b/client/src/components/VerticalMovementBands.tsx index 6878148..03c3ef1 100644 --- a/client/src/components/VerticalMovementBands.tsx +++ b/client/src/components/VerticalMovementBands.tsx @@ -1,4 +1,5 @@ import { useMemo, useRef, useCallback, useEffect, useLayoutEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import type { ArtMovement } from '../types'; import { MOVEMENT_LINEAGE } from '../data/movement-lineage'; import { panTimelineView, zoomTimelineView } from '../utils/timelineView'; @@ -364,6 +365,7 @@ export default function VerticalMovementBands({ onViewChange, onMovementClick, }: Props) { + const { t } = useTranslation('home'); const canvasRef = useRef(null); const [canvasSize, setCanvasSize] = useState({ w: 800, h: 600 }); const [panning, setPanning] = useState(false); @@ -631,7 +633,7 @@ export default function VerticalMovementBands({ return (

- Bottom → top through history · scroll to zoom · drag to pan · click a stream + {t('captionVerticalFlow')}

(null); const [dragging, setDragging] = useState<'start' | 'end' | 'pan' | null>(null); const [containerHeight, setContainerHeight] = useState(600); @@ -409,7 +411,7 @@ export default function VerticalTimeline({ />
-

Bottom → top · Scroll to zoom · Drag to pan

+

{t('captionVerticalTimeline')}

); } diff --git a/client/src/locales/en/home.json b/client/src/locales/en/home.json index d3df91d..72d4c35 100644 --- a/client/src/locales/en/home.json +++ b/client/src/locales/en/home.json @@ -22,6 +22,11 @@ "layoutHorizontal": "Classic timeline →", "layoutVertical": "↑ Vertical timeline", "layoutTree": "🌳 Tree of art", + "captionClassicTimeline": "Click an era or event to zoom · Scroll to zoom · Drag to pan", + "captionClassicFlow": "Scroll to zoom · drag to pan · each movement stream is a solid colour band through history", + "captionVerticalTimeline": "Bottom → top · Scroll to zoom · Drag to pan", + "captionVerticalFlow": "Bottom → top through history · scroll to zoom · drag to pan · click a stream", + "captionTreeFlow": "Roots at the bottom, living movements at the crown · scroll to zoom · drag to pan · click a branch to enter its gallery", "openingTourGallery": "Opening guided tour…", "tourEmpty": "This tour has no paintings yet.", "tourLoadFailed": "Failed to load the tour.", diff --git a/client/src/locales/ru/home.json b/client/src/locales/ru/home.json index c58a596..16d248e 100644 --- a/client/src/locales/ru/home.json +++ b/client/src/locales/ru/home.json @@ -22,6 +22,11 @@ "layoutHorizontal": "Классическая шкала →", "layoutVertical": "↑ Вертикальная шкала", "layoutTree": "🌳 Древо искусства", + "captionClassicTimeline": "Щёлкните эпоху или событие для приближения · Колесо — масштаб · Перетащите для панорамы", + "captionClassicFlow": "Колесо — масштаб · перетащите для панорамы · каждое направление — цветная полоса сквозь историю", + "captionVerticalTimeline": "Снизу вверх · Колесо — масштаб · Перетащите для панорамы", + "captionVerticalFlow": "Снизу вверх по истории · колесо — масштаб · перетащите для панорамы · щёлкните поток", + "captionTreeFlow": "Корни внизу, живые направления в кроне · колесо — масштаб · перетащите для панорамы · щёлкните ветвь, чтобы войти в зал", "openingTourGallery": "Открытие экскурсии…", "tourEmpty": "В этой экскурсии пока нет картин.", "tourLoadFailed": "Не удалось загрузить экскурсию.",