All checks were successful
CI / Lint, typecheck, test (push) Successful in 3m7s
CI / Build container images (push) Has been skipped
CD / Build and push images (push) Successful in 3m14s
CD / Deploy to Test (push) Successful in 12s
CD / Smoke tests against Test (push) Successful in 1m16s
CD / Promote to Int (push) Successful in 9s
CI / Auth e2e pack (push) Successful in 5m9s
CI / Import/export fidelity gate (push) Successful in 45s
Imprint and privacy policy are two new Markdown instance settings (legal.imprint, legal.privacyPolicy), edited by Site Admins in a new "Legal pages" admin section with a toggleable rendered preview. The preview uses the same shared pipeline the server renders with (markdown → schema doc → escaped HTML), so stored markup can never smuggle script to visitors. The pages render publicly at /legal/imprint and /legal/privacy — as an SPA route plus, like #56, a self-contained server-rendered HTML document under /api/v1/legal/:kind. The endpoints are setup-exempt: legal information stays reachable even while the first-run wizard is pending. Unconfigured pages show a localized notice instead of 404ing, and Site Admins additionally get a warning banner linking to the settings. A new footer with both links appears on every SPA view (editor, auth screens, public pages) and in the server-rendered documents, whose shared shell moved to public/html-shell.ts and now renders its chrome in the instance default locale (ADR 0012). docs/self-hosting/legal-template.md ships imprint and privacy-policy templates in English and German whose sections mirror Dorfteich's actual processing activities (accounts, sessions, rate-limit IPs, proxy logs, transactional mail, content, export, deletion, no third-party requests), with a review checklist tied to security.md §Privacy. New `legal` i18n namespace (de+en); api and web e2e coverage including a new CI legal pack (footer navigation, notice vs. admin banner, and the admin form publishing a text end to end). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
109 lines
4.2 KiB
TypeScript
109 lines
4.2 KiB
TypeScript
import deAccess from '@dorfteich/shared/i18n/de/access.json';
|
|
import deAuth from '@dorfteich/shared/i18n/de/auth.json';
|
|
import deCommon from '@dorfteich/shared/i18n/de/common.json';
|
|
import deEditor from '@dorfteich/shared/i18n/de/editor.json';
|
|
import deErrors from '@dorfteich/shared/i18n/de/errors.json';
|
|
import deExport from '@dorfteich/shared/i18n/de/export.json';
|
|
import deFiles from '@dorfteich/shared/i18n/de/files.json';
|
|
import deFont from '@dorfteich/shared/i18n/de/font.json';
|
|
import deImport from '@dorfteich/shared/i18n/de/import.json';
|
|
import deLabels from '@dorfteich/shared/i18n/de/labels.json';
|
|
import deLegal from '@dorfteich/shared/i18n/de/legal.json';
|
|
import deLinks from '@dorfteich/shared/i18n/de/links.json';
|
|
import deMembers from '@dorfteich/shared/i18n/de/members.json';
|
|
import dePlugins from '@dorfteich/shared/i18n/de/plugins.json';
|
|
import dePublic from '@dorfteich/shared/i18n/de/public.json';
|
|
import deQuotas from '@dorfteich/shared/i18n/de/quotas.json';
|
|
import deSearch from '@dorfteich/shared/i18n/de/search.json';
|
|
import deSetup from '@dorfteich/shared/i18n/de/setup.json';
|
|
import deUsers from '@dorfteich/shared/i18n/de/users.json';
|
|
import deSettings from '@dorfteich/shared/i18n/de/settings.json';
|
|
import enAccess from '@dorfteich/shared/i18n/en/access.json';
|
|
import enAuth from '@dorfteich/shared/i18n/en/auth.json';
|
|
import enCommon from '@dorfteich/shared/i18n/en/common.json';
|
|
import enEditor from '@dorfteich/shared/i18n/en/editor.json';
|
|
import enErrors from '@dorfteich/shared/i18n/en/errors.json';
|
|
import enExport from '@dorfteich/shared/i18n/en/export.json';
|
|
import enFiles from '@dorfteich/shared/i18n/en/files.json';
|
|
import enFont from '@dorfteich/shared/i18n/en/font.json';
|
|
import enImport from '@dorfteich/shared/i18n/en/import.json';
|
|
import enLabels from '@dorfteich/shared/i18n/en/labels.json';
|
|
import enLegal from '@dorfteich/shared/i18n/en/legal.json';
|
|
import enLinks from '@dorfteich/shared/i18n/en/links.json';
|
|
import enMembers from '@dorfteich/shared/i18n/en/members.json';
|
|
import enPlugins from '@dorfteich/shared/i18n/en/plugins.json';
|
|
import enPublic from '@dorfteich/shared/i18n/en/public.json';
|
|
import enQuotas from '@dorfteich/shared/i18n/en/quotas.json';
|
|
import enSearch from '@dorfteich/shared/i18n/en/search.json';
|
|
import enSetup from '@dorfteich/shared/i18n/en/setup.json';
|
|
import enUsers from '@dorfteich/shared/i18n/en/users.json';
|
|
import enSettings from '@dorfteich/shared/i18n/en/settings.json';
|
|
import i18n from 'i18next';
|
|
import LanguageDetector from 'i18next-browser-languagedetector';
|
|
import { initReactI18next } from 'react-i18next';
|
|
|
|
/**
|
|
* Translation resources are bundled (no async loading): the whole catalog
|
|
* is small, and the offline-capable editor (ADR 0003) must not depend on
|
|
* fetching language files. Detection: ?lng=… wins, then the browser
|
|
* language; the user-profile setting (issue #17) will be layered on top.
|
|
*/
|
|
void i18n
|
|
.use(LanguageDetector)
|
|
.use(initReactI18next)
|
|
.init({
|
|
resources: {
|
|
en: {
|
|
common: enCommon,
|
|
errors: enErrors,
|
|
access: enAccess,
|
|
auth: enAuth,
|
|
settings: enSettings,
|
|
editor: enEditor,
|
|
export: enExport,
|
|
files: enFiles,
|
|
font: enFont,
|
|
import: enImport,
|
|
labels: enLabels,
|
|
legal: enLegal,
|
|
links: enLinks,
|
|
members: enMembers,
|
|
plugins: enPlugins,
|
|
public: enPublic,
|
|
quotas: enQuotas,
|
|
search: enSearch,
|
|
setup: enSetup,
|
|
users: enUsers,
|
|
},
|
|
de: {
|
|
common: deCommon,
|
|
errors: deErrors,
|
|
access: deAccess,
|
|
auth: deAuth,
|
|
settings: deSettings,
|
|
editor: deEditor,
|
|
export: deExport,
|
|
files: deFiles,
|
|
font: deFont,
|
|
import: deImport,
|
|
labels: deLabels,
|
|
legal: deLegal,
|
|
links: deLinks,
|
|
members: deMembers,
|
|
plugins: dePlugins,
|
|
public: dePublic,
|
|
quotas: deQuotas,
|
|
search: deSearch,
|
|
setup: deSetup,
|
|
users: deUsers,
|
|
},
|
|
},
|
|
defaultNS: 'common',
|
|
fallbackLng: 'en',
|
|
supportedLngs: ['de', 'en'],
|
|
interpolation: { escapeValue: false }, // React already escapes.
|
|
detection: { order: ['querystring', 'navigator'], lookupQuerystring: 'lng', caches: [] },
|
|
});
|
|
|
|
export default i18n;
|