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
+9 -6
View File
@@ -1,4 +1,5 @@
import { useEffect, useState, type FormEvent } from 'react';
import { useTranslation } from 'react-i18next';
import './CuratorLoginModal.css';
interface Props {
@@ -8,6 +9,8 @@ interface Props {
}
export default function CuratorLoginModal({ open, onClose, onLogin }: Props) {
const { t } = useTranslation('debug');
const { t: tc } = useTranslation('common');
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState<string | null>(null);
@@ -32,7 +35,7 @@ export default function CuratorLoginModal({ open, onClose, onLogin }: Props) {
await onLogin(username.trim(), password);
onClose();
} catch (err) {
setError(err instanceof Error ? err.message : 'Login failed');
setError(err instanceof Error ? err.message : t('loginFailed'));
} finally {
setSubmitting(false);
}
@@ -47,13 +50,13 @@ export default function CuratorLoginModal({ open, onClose, onLogin }: Props) {
aria-modal="true"
onMouseDown={(e) => e.stopPropagation()}
>
<h2 id="curator-login-title">Curator login</h2>
<h2 id="curator-login-title">{t('loginTitle')}</h2>
<p className="curator-login-hint">
Debug tools and catalog edits require a curator account.
</p>
<form onSubmit={handleSubmit}>
<label className="curator-login-field">
<span>Username</span>
<span>{t('username')}</span>
<input
type="text"
autoComplete="username"
@@ -64,7 +67,7 @@ export default function CuratorLoginModal({ open, onClose, onLogin }: Props) {
/>
</label>
<label className="curator-login-field">
<span>Password</span>
<span>{t('password')}</span>
<input
type="password"
autoComplete="current-password"
@@ -77,10 +80,10 @@ export default function CuratorLoginModal({ open, onClose, onLogin }: Props) {
{error && <p className="curator-login-error">{error}</p>}
<div className="curator-login-actions">
<button type="button" className="curator-login-cancel" onClick={onClose} disabled={submitting}>
Cancel
{tc('cancel')}
</button>
<button type="submit" className="curator-login-submit" disabled={submitting}>
{submitting ? 'Signing in…' : 'Sign in'}
{submitting ? t('saving') : t('signIn')}
</button>
</div>
</form>