fix(frontend): align Settings desktop labels on French (#78)

UX decision (carnet #78): the human UI of IdeA is French by default,
uniform per surface — proper nouns and technical acronyms (URL, LAN,
IP/CIDR, HTTPS, API, CLI…) stay as-is. Settings mixed English (AI
Profiles, Deployment) with French (Appareils, frozen by UX for #77).

Renames the Settings menu/nav, the Profils IA and Déploiement panels
(titles, actions, states, help text) to French, per the carnet's
exhaustive list. Updates the affected tests accordingly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-18 14:53:32 +02:00
parent a69c5db093
commit 6e92536d84
6 changed files with 94 additions and 90 deletions

View File

@ -39,30 +39,30 @@ interface ModeOption {
const MODE_OPTIONS: ModeOption[] = [
{
mode: "localOnly",
title: "This computer only",
title: "Cet ordinateur uniquement",
description:
"For using IdeA on this desktop only. Remote devices cannot connect.",
"Pour utiliser IdeA uniquement sur cet ordinateur. Les appareils distants ne peuvent pas se connecter.",
},
{
mode: "remoteProxyLocal",
title: "Remote access, proxy on this computer",
title: "Accès distant, proxy sur cet ordinateur",
description:
"Use this when your HTTPS proxy runs on the same machine as IdeA Desktop.",
"À utiliser quand le proxy HTTPS tourne sur la même machine qu'IdeA Desktop.",
},
{
mode: "remoteProxyOtherMachine",
title: "Remote access, proxy on another machine",
title: "Accès distant, proxy sur une autre machine",
description:
"Use this when the HTTPS proxy runs on another machine. IdeA will only accept traffic from that proxy.",
"À utiliser quand le proxy HTTPS tourne sur une autre machine. IdeA n'acceptera que le trafic provenant de ce proxy.",
},
];
const STATE_LABEL: Record<string, string> = {
stopped: "Stopped",
starting: "Starting…",
running: "Running",
stopping: "Stopping…",
failed: "Failed",
stopped: "Arrêté",
starting: "Démarrage…",
running: "En cours d'exécution",
stopping: "Arrêt…",
failed: "Échec",
};
/** Copy-to-clipboard button; degrades to disabled where the API is absent. */
@ -86,7 +86,7 @@ function CopyButton({ value, label }: { value: string; label: string }) {
);
}}
>
{copied ? "Copied" : "Copy"}
{copied ? "Copié" : "Copier"}
</Button>
);
}
@ -108,8 +108,8 @@ export function DeploymentSettings() {
if (!vm.ready || !vm.settings) {
return (
<Panel aria-label="deployment settings" title="Deployment">
<p className="text-sm text-muted">Loading</p>
<Panel aria-label="deployment settings" title="Déploiement">
<p className="text-sm text-muted">Chargement</p>
</Panel>
);
}
@ -124,7 +124,7 @@ export function DeploymentSettings() {
<div aria-label="deployment settings" className="flex flex-col gap-4">
{/* ── Status ────────────────────────────────────────────────────────── */}
<Panel
title="Server"
title="Serveur"
actions={
running || status.state === "stopping" ? (
<Button
@ -132,7 +132,7 @@ export function DeploymentSettings() {
onClick={() => void vm.stop()}
disabled={vm.busy || transitioning}
>
Stop
Arrêter
</Button>
) : (
<Button
@ -140,7 +140,7 @@ export function DeploymentSettings() {
onClick={() => void vm.start()}
disabled={vm.busy || transitioning}
>
Start
Démarrer
</Button>
)
}
@ -161,12 +161,12 @@ export function DeploymentSettings() {
{status.localUrl && (
<p className="text-xs text-muted">
Local URL: <code className="font-mono text-content">{status.localUrl}</code>
URL locale : <code className="font-mono text-content">{status.localUrl}</code>
</p>
)}
{status.publicUrl && (
<p className="text-xs text-muted">
Public URL: <code className="font-mono text-content">{status.publicUrl}</code>
URL publique : <code className="font-mono text-content">{status.publicUrl}</code>
</p>
)}
@ -184,12 +184,12 @@ export function DeploymentSettings() {
</div>
</Panel>
{/* ── Exposure ──────────────────────────────────────────────────────── */}
<Panel title="Exposure">
{/* ── Exposure (ticket #78 — "Accès réseau" per UX) ────────────────── */}
<Panel title="Accès réseau">
<div className="flex flex-col gap-4">
<div
role="radiogroup"
aria-label="exposure mode"
aria-label="mode d'accès réseau"
className="flex flex-col gap-2"
>
{MODE_OPTIONS.map((option) => {
@ -234,7 +234,7 @@ export function DeploymentSettings() {
</Field>
{remote && (
<Field label="Public origin" hint="Example: https://idea.example.com">
<Field label="Origine publique" hint="Exemple : https://idea.example.com">
{({ id, describedBy }) => (
<Input
id={id}
@ -251,8 +251,8 @@ export function DeploymentSettings() {
<>
{/* Addresses come from the backend probe — never invented here. */}
<Field
label="LAN address to bind"
hint="The address on this machine that the proxy will connect to."
label="Adresse LAN d'écoute"
hint="L'adresse de cette machine à laquelle le proxy se connectera."
>
{({ id, describedBy }) =>
vm.candidateLanAddresses.length > 0 ? (
@ -263,7 +263,7 @@ export function DeploymentSettings() {
value={settings.lanBindAddress ?? ""}
onChange={(e) => vm.setLanBindAddress(e.target.value)}
>
<option value="">Select an address</option>
<option value="">Sélectionner une adresse</option>
{vm.candidateLanAddresses.map((address) => (
<option key={address} value={address}>
{address}
@ -283,8 +283,8 @@ export function DeploymentSettings() {
</Field>
<Field
label="Authorized proxy IP/CIDR"
hint="This is not where IdeA listens. It is the machine allowed to contact IdeA."
label="IP/CIDR du proxy autorisé"
hint="Ce n'est pas l'adresse d'écoute d'IdeA. C'est la machine autorisée à contacter IdeA."
>
{({ id, describedBy }) => (
<Input
@ -298,8 +298,8 @@ export function DeploymentSettings() {
</Field>
<p className="rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-warning">
If your proxy is not on this computer, choose this mode.
Otherwise the proxy may time out without an IdeA error.
Si votre proxy n'est pas sur cet ordinateur, choisissez ce mode.
Sinon, le proxy peut expirer sans erreur IdeA.
</p>
</>
)}
@ -321,16 +321,16 @@ export function DeploymentSettings() {
{/* ── Proxy setup: the upstream to paste, backend-provided ──────────── */}
{remote && (
<Panel title="Proxy setup">
<Panel title="Configuration du proxy">
<div className="flex flex-col gap-2">
<p className="text-xs text-muted">
Point your HTTPS reverse proxy at this upstream.
Faites pointer votre proxy inverse HTTPS vers cet upstream.
</p>
{vm.upstreamUrl ? (
<ReadOnlyValue value={vm.upstreamUrl} copyLabel="copy upstream url" />
<ReadOnlyValue value={vm.upstreamUrl} copyLabel="copier l'URL upstream" />
) : (
<p className="text-xs text-faint">
Complete the settings above to get the upstream URL.
Complétez les paramètres ci-dessus pour obtenir l'URL upstream.
</p>
)}
</div>
@ -338,10 +338,11 @@ export function DeploymentSettings() {
)}
{/* ── Pairing moved to its own surface (#77) — leave a signpost ─────── */}
<Panel title="Pairing">
<Panel title="Appairage">
<p className="text-sm text-muted">
Pairing is managed in <span className="text-content">Settings Appareils</span>,
where you can generate a code and revoke devices.
L'appairage est géré dans{" "}
<span className="text-content">Paramètres Appareils</span>,
vous pouvez générer un code et révoquer des appareils.
</p>
</Panel>
</div>