# Optionen

`lintTemplate`, `lintAccessibility`, `lintStructure`, `lintLinks`, `lintDeliverability`, `lintCompatibility` und `lintLocalization` akzeptieren alle dieselbe `LintOptions`-Struktur. Jedes Feld ist optional.

```ts
interface LintOptions {
  disabled?: boolean;
  locale?: string;
  contentLocale?: string;
  customBlocks?: CustomBlockDefinition[];
  mergeTagSyntax?: SyntaxPresetName | SyntaxPreset;
  accessibility?: false | AccessibilityLintOptions;
  structure?: false | StructureLintOptions;
  links?: false | LinksLintOptions;
  deliverability?: false | DeliverabilityLintOptions;
  compatibility?: false | CompatibilityLintOptions;
  localization?: false | LocalizationLintOptions;
}

interface LocalizationLintOptions {
  rules?: RuleOverrides;
}

interface AccessibilityLintOptions {
  rules?: Record<string, Severity>;
  thresholds?: Partial<LintThresholds>;
}

interface StructureLintOptions {
  rules?: Record<string, Severity>;
}

interface LinksLintOptions {
  rules?: Record<string, Severity>;
  nonProductionHosts?: string[];
}

interface CompatibilityThresholds {
  maxHtmlBytes: number;
}

interface CompatibilityLintOptions {
  rules?: RuleOverrides;
  thresholds?: Partial<CompatibilityThresholds>;
}

interface DeliverabilityThresholds {
  minTextLength: number;
}

interface DeliverabilityLintOptions {
  rules?: RuleOverrides;
  thresholds?: Partial<DeliverabilityThresholds>;
  shortenerHosts?: string[];
}

type Severity = "error" | "warning" | "info" | "off";
type RuleOverrides = Record<string, Severity>;
```

Dasselbe Objekt steuert auch die `init({ lint })`-Konfiguration des Editors — jede Option hier wirkt sich über das geteilte `useTemplateLint`-Composable auf jeden Linter aus.

Schweregrad-Overrides und tool-spezifische Stellschrauben (`thresholds`, `nonProductionHosts`, `shortenerHosts`) sind unter ihrem jeweiligen Linter namensraum-getrennt, sodass jeder Linter nur die für ihn relevante Konfiguration sieht.

## `disabled`

| Standard | `false` |
|---|---|

Bei `true`:

- Der Editor **lädt `@templatical/quality` nicht nach** — sein Chunk wird nie geladen.
- Der Issues-Sidebar-Tab wird **nicht registriert**.
- Die Canvas-Badges erzeugen **kein DOM**.

Sinnvoll, wenn ein Mandant ausdrücklich verzichtet hat oder das Standard-Editor-Bundle möglichst klein bleiben soll. Es gibt kein Soft-Disable — `disabled: true` ist eine vollständige, pro Instanz nicht rückgängig zu machende Abschaltung.

::: tip Jeden Linter einzeln zu deaktivieren hat denselben Effekt
Der Editor behandelt `{ accessibility: false, structure: false, links: false, deliverability: false, compatibility: false, localization: false }` wie `{ disabled: true }`: kein Chunk-Download, kein Sidebar-Tab, keine Canvas-Badges. Wenn jeder Linter bereits aus ist, brauchen Sie das globale Flag nicht zusätzlich.
:::

## `locale`

| Standard (headless) | `'en'` |
|---|---|
| Editor | folgt immer `init({ locale })` |

Steuert die Nachrichtentemplates des Linters (eine Datei pro Locale pro Linter) und wird von den lokal-aware Barrierefreiheits-Regeln genutzt (`a11y.link-vague-text`, `a11y.button-vague-label`, `a11y.img-linked-no-context`). Fällt auf `en` zurück, wenn die Locale (oder ihre Basissprache) nicht gebündelt ist.

```ts
// Headless — explizit setzen
lintAccessibility(content, { locale: "de" });
lintStructure(content, { locale: "de" });
lintLinks(content, { locale: "de" });
lintDeliverability(content, { locale: "de" });
lintCompatibility(content, { locale: "de" });
lintLocalization(content, { contentLocale: "de", locale: "de" });

// Editor — Linter folgt automatisch der Editor-Locale
init({ locale: "de" });
```

::: warning Im Editor-Modus wird `lint.locale` ignoriert
Im Editor-Modus wird die Linter-Locale **erzwungen** auf den `locale`-Wert aus `init({ locale })`. `lint.locale` zu setzen, hat keinen Effekt — es wird auf dem Weg überschrieben.

Headless-Aufrufer (`lintTemplate(...)` oder `lintAccessibility(...)` / `lintStructure(...)` / `lintLinks(...)` / `lintDeliverability(...)` direkt) behalten volle Kontrolle.
:::

::: tip Vague-Text-Dictionaries sind sprachübergreifend
Das Dictionary ist eine Vereinigung aller registrierten Locales — eine deutschsprachige E-Mail mit englischem `Click here`-Button schlägt `a11y.link-vague-text` / `a11y.button-vague-label` trotzdem aus, und ein deutsches `Jetzt kaufen`-Alt auf einem verlinkten Bild in englischer Locale erfüllt den Action-Hint-Check von `a11y.img-linked-no-context`. Die `locale`-Option gated das Matching nicht — sie steuert nur den Nachrichtentext.
:::

## `contentLocale`

Wählt die von `lintTemplate` geprüfte Template-Sprachversion, standardmäßig `content.settings.locale`. `locale` wählt weiterhin die Meldungssprache. Im Editor folgt `contentLocale` der aktiven Template-Sprache und `locale` der UI. Wörterbücher für vage Texte bleiben eine Vereinigung aller Sprachen; `contentLocale` ändert sie nicht. Eine unbekannte Inhalts-Locale wirft `SdkError` mit Code `unknown_locale`.

`customBlocks?: CustomBlockDefinition[]` erkennt benutzerdefinierte `text`- und `textarea`-Felder für Lokalisierungsprüfungen (ohne Angabe keine Erkennung). `mergeTagSyntax?: SyntaxPresetName | SyntaxPreset` wählt die Merge-Tag-Syntax dieser Prüfungen; Standard ist Liquid.

## `localization`

Für Nichtstandardversionen standardmäßig aktiv. `localization: false` unterdrückt diese Prüfungen; `localization.rules` überschreibt mit vollständigen Regel-IDs den Schweregrad (`"error"`, `"warning"`, `"info"`, `"off"`). `lintLocalization(content, options?)` und `LOCALIZATION_RULES` sind für gezielte Prüfungen exportiert; bevorzugen Sie `lintTemplate` für die Projektion und alle Kategorien.

| Regel | Standard | Bedeutung |
| --- | --- | --- |
| `localization.untranslated` | `warning` | Ein nichtleeres Standardtextfeld hat keine Übersetzung |
| `localization.stale` | `warning` | Der `sourceHash` eines übersetzten Felds stimmt nicht mehr mit dem Standard überein |
| `localization.merge-tags-differ` | `warning` | Die Merge-Tag-Multimenge im übersetzten Text weicht vom Standard ab |

Ausgeblendete Blöcke und ihre Nachfahren sind ausgeschlossen. Die Standardsprache erzeugt keine Lokalisierungsbefunde. Siehe [Fehlende Werte](/de/guide/localized-templates#missing-values), [Veraltete Werte](/de/guide/localized-templates#out-of-date-values) und [Merge-Tags](/de/guide/localized-templates#merge-tags). `validate --locale` der CLI behandelt abweichende Merge-Tags auch als Warnung blockierend.

## `accessibility`

| Standard | `{}` (Linter aktiv, Defaults für jede Stellschraube) |
|---|---|

Konfiguration für `lintAccessibility`. Setzen Sie auf `false`, um den gesamten Barrierefreiheits-Linter zu deaktivieren, ohne Regeln einzeln aufzählen zu müssen.

```ts
// Gesamten Barrierefreiheits-Linter abschalten
lintAccessibility(content, { accessibility: false });
```

### `accessibility.rules`

| Standard | `{}` |
|---|---|

Schweregrad-Override pro Regel für Barrierefreiheits-Regeln. Setzen Sie eine Regel auf `'off'`, um sie komplett zu deaktivieren. Setzen Sie sie auf einen anderen Schweregrad, um die Standardklassifikation zu verbiegen:

```ts
lintAccessibility(content, {
  accessibility: {
    rules: {
      "a11y.img-missing-alt": "warning",   // herabstufen
      "a11y.text-all-caps": "off",         // deaktivieren
      "a11y.missing-preheader": "warning", // info → warning hochstufen
    },
  },
});
```

Override-Schlüssel verwenden die volle, mit Präfix versehene Regel-ID (`a11y.*`) — dieselbe ID, die auf `LintIssue.ruleId` erscheint. Werte aus einem ausgegebenen Issue lassen sich direkt einsetzen. Standardschweregrade pro Regel: [Barrierefreiheit-Katalog](./accessibility/rule-catalog).

### `accessibility.thresholds`

| Standard | Siehe unten |
|---|---|

Numerische Stellschrauben, die einige Barrierefreiheits-Regeln konsultieren.

| Threshold | Standard | Verwendet von |
|---|---|---|
| `altMaxLength` | `125` | `a11y.img-alt-too-long` |
| `minFontSize` | `14` | `a11y.text-too-small` |
| `allCapsMinLength` | `20` | `a11y.text-all-caps` |
| `minTouchTargetPx` | `44` | `a11y.button-touch-target` |

Einen Wert überschreiben, ohne die anderen zu verlieren — partielles Merging ist eingebaut:

```ts
lintAccessibility(content, {
  accessibility: { thresholds: { minFontSize: 16 } },
});
```

Die Konstante `DEFAULT_A11Y_THRESHOLDS` wird ebenfalls exportiert, falls Sie die Baseline programmatisch referenzieren wollen.

## `structure`

| Standard | `{}` |
|---|---|

Konfiguration für `lintStructure`. Setzen Sie auf `false`, um den gesamten Struktur-Linter zu deaktivieren.

```ts
lintStructure(content, { structure: false });
```

### `structure.rules`

Schweregrad-Override pro Regel für Struktur-Regeln:

```ts
lintStructure(content, {
  structure: {
    rules: { "structure.empty-column": "info" }, // warning → info
  },
});
```

Schlüssel verwenden das `structure.*`-Präfix. Siehe [Struktur-Regelkatalog](./structure/rule-catalog).

## `links`

| Standard | `{}` |
|---|---|

Konfiguration für `lintLinks`. Setzen Sie auf `false`, um den gesamten Links-Linter zu deaktivieren.

```ts
lintLinks(content, { links: false });
```

### `links.rules`

Schweregrad-Override pro Regel für Link-Regeln:

```ts
lintLinks(content, {
  links: {
    rules: { "link.localhost-or-staging": "error" }, // vor Versand hochstufen
  },
});
```

Schlüssel verwenden das `link.*`-Präfix. Siehe [Link-Regelkatalog](./links/rule-catalog).

### `links.nonProductionHosts`

| Standard | `['localhost', '127.0.0.1', '0.0.0.0', '*.local', '*.staging.*', '*.dev.*']` |
|---|---|

Glob-Muster, die gegen den URL-Host abgeglichen werden. `*` matcht eine beliebige Zeichenfolge (auch über `.` hinweg) — `*.staging.*` matcht also `app.staging.example.com` und `*.local` matcht `acme.local` oder `a.b.c.local`. Muster sind verankert; `*.local` matcht damit NICHT `acme.local-tools`. Groß-/Kleinschreibung wird ignoriert.

```ts
lintLinks(content, {
  links: { nonProductionHosts: ["*.preview.*"] },
});

// Oder die Regel still schalten, ohne sie zu deaktivieren:
lintLinks(content, { links: { nonProductionHosts: [] } });
```

`DEFAULT_NON_PRODUCTION_HOSTS` wird als Baseline exportiert. Mehr in der [Links-Übersicht](./links/).

## `deliverability`

| Standard | `{}` |
|---|---|

Konfiguration für `lintDeliverability`. Mit `deliverability: false` deaktivieren Sie diese Kategorie.

```ts
lintDeliverability(content, { deliverability: false, compatibility: false });
```

### `deliverability.rules`

Die Schlüssel sind vollständige `deliverability.*`-Regel-IDs. Ein Wert `"off"` deaktiviert nur diese Regel; andere Schweregrade überschreiben den Standard. Siehe [Zustellbarkeits-Regelkatalog](./deliverability/rule-catalog).

```ts
lintDeliverability(content, {
  deliverability: { rules: { "deliverability.low-text": "off" } },
});
```

### `deliverability.thresholds.minTextLength`

Standard `200` sichtbare Zeichen. `deliverability.low-text` meldet bei einem bilderzeugenden Block weniger Text als diese Grenze. Die partielle Konfiguration erhält andere Standards:

```ts
lintDeliverability(content, {
  deliverability: { thresholds: { minTextLength: 250 } },
});
```

`DEFAULT_DELIVERABILITY_THRESHOLDS` exportiert den Standard.

### `deliverability.shortenerHosts`

Ersetzt `DEFAULT_SHORTENER_HOSTS`. Erweitern Sie die Liste durch Spread, wenn die Standardhosts erhalten bleiben sollen:

```ts
import { DEFAULT_SHORTENER_HOSTS, lintDeliverability } from "@templatical/quality";

const issues = lintDeliverability(content, {
  deliverability: { shortenerHosts: [...DEFAULT_SHORTENER_HOSTS, "go.example.com"] },
});
```

## `compatibility`

Standardmäßig aktiv. `compatibility: false` deaktiviert die Client-Kompatibilitätsprüfung. Vollständige `compat.*`-IDs in `compatibility.rules` erlauben Schweregrad-Overrides einschließlich `"off"`. `compatibility.thresholds.maxHtmlBytes` beträgt standardmäßig `92_160` Byte (90 KiB) für `lintCompiledHtml`. Siehe den [Kompatibilitätskatalog](./compatibility/rule-catalog).
