Localise timeline and movement chart captions in English and Russian.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
44092d102b
commit
1c9fa20191
@@ -1,4 +1,5 @@
|
|||||||
import { useMemo, useRef, useCallback, useEffect, useLayoutEffect, useState, memo } from 'react';
|
import { useMemo, useRef, useCallback, useEffect, useLayoutEffect, useState, memo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import type { ArtMovement, Artist } from '../types';
|
import type { ArtMovement, Artist } from '../types';
|
||||||
import { portraitThumbUrl } from '../api/client';
|
import { portraitThumbUrl } from '../api/client';
|
||||||
import { useQueuedImageSrc } from '../hooks/useQueuedImageSrc';
|
import { useQueuedImageSrc } from '../hooks/useQueuedImageSrc';
|
||||||
@@ -1695,6 +1696,7 @@ export default function MovementBands({
|
|||||||
onArtistHover,
|
onArtistHover,
|
||||||
onPortraitsLoadingChange,
|
onPortraitsLoadingChange,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const { t } = useTranslation('home');
|
||||||
const canvasRef = useRef<HTMLDivElement>(null);
|
const canvasRef = useRef<HTMLDivElement>(null);
|
||||||
const pendingPortraitsRef = useRef(0);
|
const pendingPortraitsRef = useRef(0);
|
||||||
const [portraitsLoading, setPortraitsLoading] = useState(false);
|
const [portraitsLoading, setPortraitsLoading] = useState(false);
|
||||||
@@ -2193,7 +2195,7 @@ export default function MovementBands({
|
|||||||
return (
|
return (
|
||||||
<div className="movements-flow">
|
<div className="movements-flow">
|
||||||
<p className="movements-flow-caption">
|
<p className="movements-flow-caption">
|
||||||
Scroll to zoom · drag to pan · each movement stream is a solid colour band through history
|
{t('captionClassicFlow')}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import type { ArtMovement } from '../types';
|
import type { ArtMovement } from '../types';
|
||||||
import {
|
import {
|
||||||
branchOriginYear,
|
branchOriginYear,
|
||||||
@@ -179,6 +180,7 @@ export default function MovementTree({
|
|||||||
onViewChange,
|
onViewChange,
|
||||||
onMovementClick,
|
onMovementClick,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const { t } = useTranslation('home');
|
||||||
const canvasRef = useRef<HTMLDivElement>(null);
|
const canvasRef = useRef<HTMLDivElement>(null);
|
||||||
const [canvas, setCanvas] = useState({ w: 900, h: 600 });
|
const [canvas, setCanvas] = useState({ w: 900, h: 600 });
|
||||||
const [panning, setPanning] = useState(false);
|
const [panning, setPanning] = useState(false);
|
||||||
@@ -534,8 +536,7 @@ export default function MovementTree({
|
|||||||
return (
|
return (
|
||||||
<div className="mtree">
|
<div className="mtree">
|
||||||
<p className="mtree-caption">
|
<p className="mtree-caption">
|
||||||
Roots at the bottom, living movements at the crown · scroll to zoom · drag to
|
{t('captionTreeFlow')}
|
||||||
pan · click a branch to enter its gallery
|
|
||||||
</p>
|
</p>
|
||||||
<div
|
<div
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useRef, useState, useCallback, useEffect, useMemo, useLayoutEffect } from 'react';
|
import { useRef, useState, useCallback, useEffect, useMemo, useLayoutEffect } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import type { HistoricalEra } from '../types';
|
import type { HistoricalEra } from '../types';
|
||||||
import {
|
import {
|
||||||
HISTORICAL_EVENTS,
|
HISTORICAL_EVENTS,
|
||||||
@@ -38,6 +39,7 @@ function formatYear(year: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Timeline({ eras, viewStart, viewEnd, onViewChange, absoluteMin, absoluteMax, lifespanHighlight }: Props) {
|
export default function Timeline({ eras, viewStart, viewEnd, onViewChange, absoluteMin, absoluteMax, lifespanHighlight }: Props) {
|
||||||
|
const { t } = useTranslation('home');
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const [dragging, setDragging] = useState<'left' | 'right' | 'pan' | null>(null);
|
const [dragging, setDragging] = useState<'left' | 'right' | 'pan' | null>(null);
|
||||||
const [containerWidth, setContainerWidth] = useState(800);
|
const [containerWidth, setContainerWidth] = useState(800);
|
||||||
@@ -365,7 +367,7 @@ export default function Timeline({ eras, viewStart, viewEnd, onViewChange, absol
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="timeline-hint">
|
<p className="timeline-hint">
|
||||||
Click an era or event to zoom · Scroll to zoom · Drag to pan
|
{t('captionClassicTimeline')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useMemo, useRef, useCallback, useEffect, useLayoutEffect, useState } from 'react';
|
import { useMemo, useRef, useCallback, useEffect, useLayoutEffect, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import type { ArtMovement } from '../types';
|
import type { ArtMovement } from '../types';
|
||||||
import { MOVEMENT_LINEAGE } from '../data/movement-lineage';
|
import { MOVEMENT_LINEAGE } from '../data/movement-lineage';
|
||||||
import { panTimelineView, zoomTimelineView } from '../utils/timelineView';
|
import { panTimelineView, zoomTimelineView } from '../utils/timelineView';
|
||||||
@@ -364,6 +365,7 @@ export default function VerticalMovementBands({
|
|||||||
onViewChange,
|
onViewChange,
|
||||||
onMovementClick,
|
onMovementClick,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const { t } = useTranslation('home');
|
||||||
const canvasRef = useRef<HTMLDivElement>(null);
|
const canvasRef = useRef<HTMLDivElement>(null);
|
||||||
const [canvasSize, setCanvasSize] = useState({ w: 800, h: 600 });
|
const [canvasSize, setCanvasSize] = useState({ w: 800, h: 600 });
|
||||||
const [panning, setPanning] = useState(false);
|
const [panning, setPanning] = useState(false);
|
||||||
@@ -631,7 +633,7 @@ export default function VerticalMovementBands({
|
|||||||
return (
|
return (
|
||||||
<div className="vflow">
|
<div className="vflow">
|
||||||
<p className="vflow-caption">
|
<p className="vflow-caption">
|
||||||
Bottom → top through history · scroll to zoom · drag to pan · click a stream
|
{t('captionVerticalFlow')}
|
||||||
</p>
|
</p>
|
||||||
<div
|
<div
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useRef, useState, useCallback, useEffect, useMemo, useLayoutEffect } from 'react';
|
import { useRef, useState, useCallback, useEffect, useMemo, useLayoutEffect } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import type { HistoricalEra } from '../types';
|
import type { HistoricalEra } from '../types';
|
||||||
import {
|
import {
|
||||||
HISTORICAL_EVENTS,
|
HISTORICAL_EVENTS,
|
||||||
@@ -60,6 +61,7 @@ export default function VerticalTimeline({
|
|||||||
absoluteMax,
|
absoluteMax,
|
||||||
lifespanHighlight,
|
lifespanHighlight,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const { t } = useTranslation('home');
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const [dragging, setDragging] = useState<'start' | 'end' | 'pan' | null>(null);
|
const [dragging, setDragging] = useState<'start' | 'end' | 'pan' | null>(null);
|
||||||
const [containerHeight, setContainerHeight] = useState(600);
|
const [containerHeight, setContainerHeight] = useState(600);
|
||||||
@@ -409,7 +411,7 @@ export default function VerticalTimeline({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="vtimeline-hint">Bottom → top · Scroll to zoom · Drag to pan</p>
|
<p className="vtimeline-hint">{t('captionVerticalTimeline')}</p>
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,11 @@
|
|||||||
"layoutHorizontal": "Classic timeline →",
|
"layoutHorizontal": "Classic timeline →",
|
||||||
"layoutVertical": "↑ Vertical timeline",
|
"layoutVertical": "↑ Vertical timeline",
|
||||||
"layoutTree": "🌳 Tree of art",
|
"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…",
|
"openingTourGallery": "Opening guided tour…",
|
||||||
"tourEmpty": "This tour has no paintings yet.",
|
"tourEmpty": "This tour has no paintings yet.",
|
||||||
"tourLoadFailed": "Failed to load the tour.",
|
"tourLoadFailed": "Failed to load the tour.",
|
||||||
|
|||||||
@@ -22,6 +22,11 @@
|
|||||||
"layoutHorizontal": "Классическая шкала →",
|
"layoutHorizontal": "Классическая шкала →",
|
||||||
"layoutVertical": "↑ Вертикальная шкала",
|
"layoutVertical": "↑ Вертикальная шкала",
|
||||||
"layoutTree": "🌳 Древо искусства",
|
"layoutTree": "🌳 Древо искусства",
|
||||||
|
"captionClassicTimeline": "Щёлкните эпоху или событие для приближения · Колесо — масштаб · Перетащите для панорамы",
|
||||||
|
"captionClassicFlow": "Колесо — масштаб · перетащите для панорамы · каждое направление — цветная полоса сквозь историю",
|
||||||
|
"captionVerticalTimeline": "Снизу вверх · Колесо — масштаб · Перетащите для панорамы",
|
||||||
|
"captionVerticalFlow": "Снизу вверх по истории · колесо — масштаб · перетащите для панорамы · щёлкните поток",
|
||||||
|
"captionTreeFlow": "Корни внизу, живые направления в кроне · колесо — масштаб · перетащите для панорамы · щёлкните ветвь, чтобы войти в зал",
|
||||||
"openingTourGallery": "Открытие экскурсии…",
|
"openingTourGallery": "Открытие экскурсии…",
|
||||||
"tourEmpty": "В этой экскурсии пока нет картин.",
|
"tourEmpty": "В этой экскурсии пока нет картин.",
|
||||||
"tourLoadFailed": "Не удалось загрузить экскурсию.",
|
"tourLoadFailed": "Не удалось загрузить экскурсию.",
|
||||||
|
|||||||
Reference in New Issue
Block a user