feat: i18n

This commit is contained in:
Senko-san
2026-06-06 15:23:07 +03:00
parent bbd59cc225
commit e45bcef3a5
21 changed files with 613 additions and 163 deletions
+13 -17
View File
@@ -1,5 +1,6 @@
import { useState } from 'react';
import { useNavigate } from 'react-router';
import { useTranslation } from 'react-i18next';
import { Card, TextField, Button, Callout, Badge } from '@olly/modern-sk';
import { Icon } from '../../components/common/Icon';
import { useAppDispatch } from '../../hooks/useAppDispatch';
@@ -14,10 +15,10 @@ import {
import type { User } from '../../api/types';
export function ConnectPage() {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const navigate = useNavigate();
// Re-read on each render trigger; instance ops below force a remount via state.
const [rev, setRev] = useState(0);
const instances = listInstances();
const activeId = getActiveInstanceId();
@@ -26,8 +27,6 @@ export function ConnectPage() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
// Switching to a saved backend reloads the app so every slice re-initialises
// from that instance's namespaced storage (its own session, prefs, cache).
const switchTo = (id: string) => {
setActiveInstanceId(id);
window.location.assign('/');
@@ -38,11 +37,9 @@ export function ConnectPage() {
setRev((r) => r + 1);
};
// STUB: no backend yet. Register the instance, then fake a session so the rest
// of the app is reachable. Replace with the real useLoginMutation() flow later.
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setApiBaseUrl(apiUrl); // upsert + activate this backend
setApiBaseUrl(apiUrl);
const fakeUser: User = {
id: 'dev-user',
@@ -114,7 +111,7 @@ export function ConnectPage() {
}}
>
<span className="msk-label" style={{ marginBottom: '0.25rem' }}>
Saved instances
{t('connect.savedInstances')}
</span>
{instances.map((inst) => (
<div
@@ -165,21 +162,21 @@ export function ConnectPage() {
</div>
</div>
{inst.id === activeId ? (
<Badge variant="lime">active</Badge>
<Badge variant="lime">{t('connect.active')}</Badge>
) : (
<Button
variant="ghost"
size="sm"
onClick={() => switchTo(inst.id)}
>
Use
{t('connect.use')}
</Button>
)}
<button
type="button"
className="iconbtn sm"
onClick={() => forget(inst.id)}
title="Forget this instance"
title={t('connect.forgetTitle')}
>
<Icon name="trash" />
</button>
@@ -199,9 +196,9 @@ export function ConnectPage() {
padding: '1.5rem',
}}
>
<span className="msk-label">Connect to a backend</span>
<span className="msk-label">{t('connect.form.title')}</span>
<div>
<label style={labelStyle}>Server URL</label>
<label style={labelStyle}>{t('connect.form.serverUrl')}</label>
<TextField
value={apiUrl}
onChange={(e) => setApiUrl(e.target.value)}
@@ -210,7 +207,7 @@ export function ConnectPage() {
/>
</div>
<div>
<label style={labelStyle}>Username</label>
<label style={labelStyle}>{t('connect.form.username')}</label>
<TextField
value={username}
onChange={(e) => setUsername(e.target.value)}
@@ -220,7 +217,7 @@ export function ConnectPage() {
/>
</div>
<div>
<label style={labelStyle}>Password</label>
<label style={labelStyle}>{t('connect.form.password')}</label>
<TextField
type="password"
value={password}
@@ -231,15 +228,14 @@ export function ConnectPage() {
/>
</div>
<Callout variant="warning">
Stub mode backend not wired. Connect signs in with a fake admin
session, scoped to this instance.
{t('connect.form.stubNote')}
</Callout>
<Button
type="submit"
variant="primary"
style={{ marginTop: '0.5rem' }}
>
Connect
{t('connect.form.submit')}
</Button>
</form>
</Card>