diff --git a/felsokning/app/src/App.tsx b/felsokning/app/src/App.tsx index 69409a9..4ec660c 100644 --- a/felsokning/app/src/App.tsx +++ b/felsokning/app/src/App.tsx @@ -33,6 +33,7 @@ import AlvaAbonnemang from "./pages/alva/Abonnemang"; import AlvaGarantier from "./pages/alva/Garantier"; import AlvaImpressum from "./pages/alva/Impressum"; import AlvaUtgavor from "./pages/alva/Utgavor"; +import AlvaSprak from "./pages/alva/Sprak"; import AlvaForsakring from "./pages/alva/Forsakring"; import AlvaSupport from "./pages/alva/Support"; import { Portalvakt } from "./pages/alva/Portalvakt"; @@ -76,6 +77,7 @@ function AppContent() { en del av kravet, inte en placering. */} } /> } /> + } /> {/* Portalen är stängd utan giltig plattformssession — se Portalvakt. Utan konfigurerad plattform finns ingen session att kräva, och vyerna är då märkta som demonstration. */} diff --git a/felsokning/app/src/pages/alva/Ram.tsx b/felsokning/app/src/pages/alva/Ram.tsx index 83a9ea9..6693d85 100644 --- a/felsokning/app/src/pages/alva/Ram.tsx +++ b/felsokning/app/src/pages/alva/Ram.tsx @@ -127,6 +127,7 @@ export function Ram({ children, portal = false }: { children: ReactNode; portal? ["/alva/dataskydd", "Privacy"], ["/alva/villkor", "Terms"], ["/alva/tillganglighet", "Accessibility"], + ["/alva/sprak", "Languages"], ["/alva/utgavor", "Release notes"], ].map(([till, text]) => (
  • diff --git a/felsokning/app/src/pages/alva/Sprak.tsx b/felsokning/app/src/pages/alva/Sprak.tsx new file mode 100644 index 0000000..6b9058a --- /dev/null +++ b/felsokning/app/src/pages/alva/Sprak.tsx @@ -0,0 +1,217 @@ +// ALVA-SPEC-060 · Språksidan. +// +// Sidan finns i foten och inte i portalens navigation, av två skäl. Den +// är dokumentation snarare än ett arbetsverktyg, och portalraden har +// redan tio poster — en elfte hade brutit raden till ytterligare en rad +// på telefon utan att någon sökt sig dit oftare. +// +// ---- Vad sidan gör som en språkmeny inte gör ----------------------------- +// +// En vanlig språkväljare påstår att produkten finns på tio språk och +// slutar där. Den här redovisar i stället skillnaden mellan att en text +// ÄR översatt och att den är GRANSKAD av någon som kan yrket, och den +// visar det på de strängar där skillnaden faktiskt betyder något: +// grindens hinder, alltså de meningar som nekar en tekniker att avsluta +// ett ärende. +// +// Det är ett obekvämt sätt att presentera sin egen produkt, och det är +// hela poängen. En verkstadschef i Rumänien som får veta att metodiken +// inte är fackgranskad på rumänska kan planera för det. Samma chef som +// får veta det av en tekniker som missförstått en säkerhetsinstruktion +// kan inte. + +import { useState } from "react"; +import { SPRAK, metodikvarning, oversattare, tackning } from "../../../../services/gemensam/sprak/index.mjs"; +import { Block, Etikett, FARG, Rubrik, Tabell } from "@/alva/komponenter"; +import { Ram } from "./Ram"; + +type Sprakpost = { kod: string; namn: string; egetNamn: string; granskat: boolean }; +const SPRAKEN = SPRAK as Sprakpost[]; + +// De strängar som väljs för förhandsvisningen är inte slumpvis valda. +// Var och en är en mening som nekar ett avslut, och därmed en mening som +// måste gå att förstå av den som blir nekad. +const PROV = [ + "grind.objekt", + "grind.historik", + "grind.matarstallning.ej_foto", + "grind.hogvolt.spanningslos", + "slutsats.utan_slutsats", +]; + +function Sektion({ etikett, rubrik, children }: { etikett: string; rubrik: string; children: React.ReactNode }) { + return ( +
    +
    + {etikett} +
    + {rubrik} +
    + {children} +
    +
    + ); +} + +export default function Sprak() { + const [valt, setValt] = useState("de"); + const t = oversattare(valt) as (nyckel: string) => string; + const post = SPRAKEN.find((s) => s.kod === valt)!; + const varning = metodikvarning(valt) as string | null; + + return ( + +
    +
    + Localization +
    + Languages +
    +

    + English is the default and the source language. Nine translations follow. What the platform does + not do is claim that a translated interface means a translated method. +

    +
    +
    + + {/* ---- Den avgränsning som styr allt annat ---- */} + +
    + +

    + Labels, buttons, statuses. Finite, rarely changed. An English string reaching a German user is + an irritation, not a hazard — so a missing translation falls back to English without comment. +

    +
    + +

    + Instructions for work on a vehicle. Here an unreviewed translation is worse than a foreign + language one — because English looks foreign, while a bad translation looks like an + instruction. It is shown in English and marked, with the language named. +

    +
    +
    + +

    + The method itself is never translated. Phase names and status words are ALVA’s structure and + read identically in every country, so an auditor can read a Romanian and a German case record + without knowing which language the workshop works in. +

    +
    + + {/* ---- Redovisningen ---- */} + + [ + `${s.namn} — ${s.egetNamn}`, + `${Math.round((tackning(s.kod) as number) * 100)} %`, + s.granskat ? "Yes" : "No — procedure text shown in English", + ])} + /> +

    + Interface coverage is measured, not estimated: a test fails the build if any key is missing from + any language. Review status is a statement about people, not about files, and is set by hand. +

    +
    + + {/* ---- Beviset ---- */} + +

    + These are the sentences that refuse to let a technician close a case. A refusal nobody understands + is a refusal with no way through — so they are the right strings to judge a translation by. +

    + + {/* Rutnät, inte flexradbrytning. Tio språk bryts av flex till nio + plus ett ensamt, och den ensamma knappen läser sig som en + eftertanke i stället för som ett språk bland tio. Fem kolumner + och två gör tio jämnt i båda riktningarna. */} +
    + {SPRAKEN.map((s) => ( + + ))} +
    + +
      + {PROV.map((nyckel) => ( +
    • +
      + {nyckel} +
      +
      + {t(nyckel)} +
      +
    • + ))} +
    + + {/* Varningen står under provet, inte över det. Den som just läst + fem meningar på sitt eget språk ska mötas av vad de INTE + garanterar — inte varnas i förväg och sedan lugnas av att + texten ser bra ut. */} + {varning && ( +
    + Not reviewed — {post.egetNamn} +

    + {varning} +

    +
    + )} + {!varning && ( +
    + Reviewed — {post.egetNamn} +

    + Procedure text in {post.egetNamn} has been read by a specialist working in the trade. Steps and + checks are shown in {post.egetNamn} throughout. +

    +
    + )} +
    + + {/* ---- Hur språket väljs ---- */} + +
      + {[ + ["User preference", "What the individual has selected."], + ["Organization setting", "The workshop's documentation language."], + ["Browser language", "The first language the platform recognises."], + ["English", "The default, and the source."], + ].map(([rubrik, text], i) => ( +
    1. + + {String(i + 1).padStart(2, "0")} + +
      +
      + {rubrik} +
      +
      + {text} +
      +
      +
    2. + ))} +
    +

    + The organization ranks above the browser deliberately. A workshop in Germany with a Polish + technician needs one documentation language — the case record must not change language depending on + who happened to write the line. +

    +
    +
    + ); +} diff --git a/felsokning/services/gemensam/version.mjs b/felsokning/services/gemensam/version.mjs index feb2fa2..db3be8a 100644 --- a/felsokning/services/gemensam/version.mjs +++ b/felsokning/services/gemensam/version.mjs @@ -21,6 +21,19 @@ // TÜV-härdningen ändrade vad loggen garanterar. export const UTGAVOR = [ + { + version: "3.2", + datum: "2026-08-06", + commit: "af27275", + rubrik: "Engelska som standard, tio EU-språk, och en regel som gällde på ett", + andringar: [ + "Engelska är standard- och källspråk. Nio översättningar: tyska, franska, spanska, italienska, polska, nederländska, portugisiska, rumänska och svenska.", + "Gränssnittstext faller tillbaka på engelska tyst. Metodikinnehåll gör det aldrig tyst — en ogranskad översättning av en säkerhetsinstruktion är sämre än en engelsk, därför att engelska SYNS som ett annat språk.", + "Metodens struktur översätts inte. Fasnamn och statusord står likadant i varje land, så att en revisor kan läsa en rumänsk och en tysk rapport utan att veta vilket språk verkstaden arbetar på.", + "Kvalitetsgrindens hinder följer organisationens språk. En spärr på fel språk är en spärr utan väg förbi.", + "ALVA-RULE-200 gällde bara på svenska: en tekniker som skrev \"erledigt\" eller \"done\" i motiveringsfältet passerade filtret för icke-svar. Rättat på tio språk — det var ett hål i regeln, inte en översättningsbrist.", + ], + }, { version: "3.1", datum: "2026-08-06",