`duxt.sources` est une liste d’entrées de source ; `duxt.sourceOptions` dit
comment elles deviennent des URL. Les deux sont lues à la compilation. Ce
qu’elles génèrent, et pourquoi, est dans [Sources](/concepts/sources).

Les refs exigent un `repo` explicite, même pour publier un autre ref de ce
dépôt. Sans `repo`, une source lit le checkout local actuel et refuse `refs` (y
compris `latest`) ainsi que les substitutions locales de `ref` par langue.
`origin.repo` et `origin.ref` fournissent uniquement des liens de provenance ;
ils ne sélectionnent aucun contenu. Une langue ayant son propre `repo` explicite
peut choisir son propre `ref`. Pour les versions locales, utilisez `version` sur
des sources avec des dossiers distincts ou les `versions` par fichier d’une
section générée.

## Une entrée de source

| Champ     | Type                     | Remarques                                                        |
| :-------- | :----------------------- | :---------------------------------------------------------------- |
| `path`    | `string`                 | Dossier contenant le Markdown, relatif à la racine du dépôt        |
| `repo`    | `string`                 | `owner/name` ou une URL git. **Omis signifie le checkout local**         |
| `refs`    | liste de refs            | Refs à publier comme versions ; exigent un `repo` explicite   |
| `releases` | `{ select, prereleases? }` | Découvrir les tags de version à publier — voir plus bas |
| `tagComponent` | `string`            | Ne publier que les tags `<name>@vX.Y.Z` d’un paquet — voir [Tags par composant](#tags-par-composant) |
| `version` | `string`                 | La version que cette source représente elle-même |
| `label`   | texte                    | Affiché dans le sélecteur et utilisé dans l’URL ; par défaut la ref |
| `name`    | texte                    | Comment cette source **s’appelle** là où le site la nomme. Affichage seul — voir plus bas |
| `slug`    | `string`                 | Le segment d’URL de cette source. **La déclarer, c’est la réclamer** — voir plus bas |
| `status`  | statut                   | Cycle de vie de chaque version que cette entrée publie             |
| `statusDefaults` | `{ latest?, branch?, tag? }` | Cycle de vie par défaut selon le type de ref |
| `origin`  | `{ repo, ref?, path? }`  | Où vivent les pages lues sur le disque, pour les liens de retour   |
| `history` | `boolean`                | Lire l’historique git de cette source                              |
| `content` | `boolean`                | `false` si la source ne porte que du contenu généré |
| `exclude` | `{ drafts?, partials? }` | Globs propres à la source pour brouillons et fragments |
| `flavor`  | `'tfplugindocs'`         | Interpréter l’arbre Markdown comme un dialecte pris en charge |
| `locales` | liste de locales         | Langues dans lesquelles cette source existe — voir ci-dessous      |
| `generated` | liste de sections       | Artefacts publiés en pages à côté du Markdown — voir plus bas    |

Deux champs se confondent facilement et coûtent cher quand on se trompe :

- **`repo` télécharge, `origin` ne fait que lier.** Nommer votre propre dépôt
  dans `repo` fait cloner à la compilation le checkout dans lequel elle se
  trouve déjà.
- **`origin.path` est le dossier sur la forge.** Renseignez-le lorsque le
  dossier sur le disque est une copie — contenu copié dans un contexte de build,
  checkout voisin lu via `../` — afin que « Edit this page » ouvre `docs/…` et
  non le chemin de la copie. Les dossiers de langue sont mappés à travers le
  `path` de la source et doivent donc se trouver dessous.
- **`history` coûte un clone complet.** Content clone un dépôt distant avec
  `--depth 1` : son checkout ne contient qu’un commit et chaque fichier paraît
  écrit par la personne qui a coupé la pointe — données fausses, pas données
  manquantes. L’activer complète le clone une fois. Une source lue sur le disque
  est déjà un checkout complet et est lue quoi qu’il arrive.

**`slug` réclame un segment.** Une source n’en reçoit normalement un que lorsque
la liste nomme plus d’un dépôt — tout ou rien, pour le site entier. Une source
qui écrit son propre `slug` est servie dessous de toute façon, et celles qui n’en
écrivent aucun ne bougent pas : c’est ce qui permet à une chose de vivre sous
`/demo` à côté d’une documentation qui garde la racine.


**`name` est un nom, `label` et `slug` sont des adresses.** La boîte de dialogue
de recherche légende chaque résultat avec la source dont il provient, et avant
cette clé elle ne pouvait la lire que dans l’URL : une documentation servie à la
racine s’annonçait donc comme `/`, et une source dont le segment est une
abréviation comme `tf`. `name` sert uniquement à l’affichage : il n’atteint
aucune collection, aucun préfixe, aucune version ni le classement — c’est
précisément pour cela qu’il peut être de la prose et peut être traduit.

```ts
sources: [
  // Un enregistrement de locales, car le nom est un substantif qui se traduit.
  {
    repo: 'acme/docs',
    path: 'docs',
    name: { 'en-GB': 'Handbook', de: 'Handbuch', fr: 'Manuel' }
  },
  // Un littéral simple, car un nom de produit est le même mot partout.
  { repo: 'acme/terraform-provider-acme', path: 'docs', slug: 'tf', name: 'Terraform Provider' }
]
```

Non renseigné, le nom retombe sur le segment de la source (`demo` → **Demo**)
puis sur `duxt.title`, qui est lui-même le libellé localisé **Documentation**
sur un site sans titre. À renseigner partout où le segment est une abréviation.
Deux sources différentes qui aboutiraient à un seul nom sont distinguées
automatiquement, par leur dépôt ou leur dossier.

### Contenu, exclusions et dialectes de source

`content: false` évite de publier les pages Markdown ordinaires de la source,
mais conserve ses déclarations `generated`. `exclude.drafts` et
`exclude.partials` remplacent les globs propres à cette source lorsqu’un dépôt
suit d’autres conventions.

`flavor: 'tfplugindocs'` interprète les dossiers, titres et catégories d’un
arbre Markdown produit par tfplugindocs. Les pages restent des pages Content
ordinaires pour la recherche, les versions, les locales et les lecteurs
machines. Voir
[Publier la documentation d’un provider Terraform](/guides/publish-terraform-provider-docs).

## Refs

Une chaîne nue est une **branche**. Un tag doit le dire : git garde les branches
et les tags dans des espaces de noms séparés, et demander un tag sous
`refs/heads` fait échouer la compilation avec `Could not find refs/heads/…`.

```ts
refs: [
  'main',                                     // une branche
  { branch: 'next', status: 'upcoming' },     // la même, avec un cycle de vie
  { tag: 'v2.0.0', label: 'v2' },             // un tag
  'latest'                                    // le tag semver le plus récent, résolu à la compilation
]
```

`'latest'` est réservé. Une branche réellement nommée `latest` exige la forme
`{ branch }`.

## Releases

`releases` découvre les tags au lieu d’entretenir un long historique dans la
configuration. La découverte est opt-in et indique toujours sa sélection : il
n’existe pas de « toutes les versions » implicite, car les URL qui restent
accessibles relèvent d’une décision du site.

```ts
{
  repo: 'acme/sdk',
  path: 'docs',
  releases: { select: 'minor' }
}
```

| `select`  | Publie                                            |
| :-------- | :------------------------------------------------ |
| `'all'`   | chaque version                                    |
| `'minor'` | la version la plus récente de chaque ligne mineure |
| `'major'` | la version la plus récente de chaque ligne majeure |

Les préversions restent exclues sauf avec `prereleases: true`. La version
sélectionnée la plus récente est utilisée par défaut ; une ref avec
`default: true` ou `sourceOptions.defaultRef` reste prioritaire.

Le cycle de vie ne change pas : le statut de la source ou `statusDefaults.tag`
s’applique à chaque tag découvert. Rien n’est déduit de l’âge d’une version.

`refs` reste disponible avec `releases`. Une entrée visant un tag découvert
remplace son libellé, son statut, sa valeur par défaut et ses locales ; les autres
sont publiées à côté.

```ts
{
  repo: 'acme/sdk',
  releases: { select: 'major' },
  refs: [
    { tag: 'v1.4.2', label: 'v1', status: 'deprecated' },
    { branch: 'main', status: 'upcoming' }
  ]
}
```

Une sélection sans tag correspondant arrête le build en nommant la source et la
sélection. Un dépôt illisible est signalé séparément comme une erreur Git. La
même distinction vaut pour `latest`.

### Tags par composant

Un monorepo qui publie plusieurs paquets séparément étiquette chacun par son
**composant** — release-please écrit `duxt@v0.4.0` à côté de
`duxt-typesense@v0.1.0`. Les deux formes sont des versions : `latest`,
`releases` et l’ordre du sélecteur lisent `<name>@vX.Y.Z` exactement comme
`vX.Y.Z`, et le libellé comme le segment d’URL n’affichent que la version —
`v0.4.0`, jamais `duxt@v0.4.0`. La ref garde le tag complet, car c’est le nom que
git connaît.

Quand le dépôt étiquette plus d’un paquet, « le tag le plus récent » ne veut rien
dire tant qu’il ne précise pas lequel. `tagComponent` nomme le paquet :

```ts
{
  repo: 'kirchDev/duxt',
  path: 'docs',
  tagComponent: 'duxt',
  refs: [{ tag: 'latest', default: true }]   // duxt@v…, jamais duxt-typesense@v…
}
```

**Les tags `vX.Y.Z` simples comptent toujours** : ce sont les versions du paquet
antérieures aux tags par composant, et les écarter les dépublierait toutes. Les
tags d’un autre composant ne comptent jamais. Sans `tagComponent`, tout tag qui
se lit comme une version est candidat, préfixé ou non.

## Locales

Omis, la source a une langue et une collection. Listées, chaque entrée devient
une collection à part.

```ts
locales: [
  'en-GB',                                              // la valeur par défaut : docs/ lui-même
  'de',                                                 // docs/de/
  { locale: 'fr', path: 'translations/fr' },            // ailleurs dans ce dépôt
  { locale: 'es', repo: 'acme/docs-es', path: 'docs' }  // un autre dépôt
]
```

Une chaîne est un dossier à l’intérieur du `path` de la source. La forme objet
remplace `path`, `repo` et `ref` pour cette langue seule — et c’est ce qui
permet à une traduction de vivre dans son propre dépôt, avec ses mainteneurs et
son calendrier de publication.

**La locale par défaut est l’arbre de `path` lui-même et ne prend aucun
dossier.** Laquelle c’est vient de `sourceOptions.defaultLocale`, et elle doit
concorder avec `i18n.defaultLocale` — la compilation échoue si elles diffèrent,
car `content.config.ts` résout les collections sans accès à la configuration
Nuxt.

Une ref peut porter ses propres `locales`, remplaçant ceux de la source
exactement comme le fait `status`. C’est la forme habituelle : la version
courante est traduite, les précédentes non.

```ts
refs: [
  { tag: 'v2.0.0' },                     // hérite des locales de la source
  { tag: 'v1.0.0', locales: ['en-GB'] }  // l’original seulement
]
```

Nommez un dossier par **langue** là où la région n’ajoute rien : `docs/pt/` sert
à la fois `pt-PT` et `pt-BR`, parce qu’une page retombe sur sa langue de base.
La même règle que suivent les fichiers de locale de la couche.

## Statut

`statusDefaults` fournit un cycle de vie par type de ref lorsque la ref ne le
précise pas : `latest` pour le tag choisi par l’entrée réservée, `branch` pour les
branches et `tag` pour les tags explicites ou découverts. Un statut explicite sur
la ref prévaut ; celui de la source sert de fallback commun.

```ts
statusDefaults: {
  latest: 'current',
  branch: 'upcoming',
  tag: 'deprecated'
}
```

| Valeur       | Signifie                                              |
| :----------- | :---------------------------------------------------- |
| `upcoming`   | Pas encore publiée — peut encore changer               |
| `current`    | La documentation à lire                                |
| `maintained` | Plus ancienne, toujours prise en charge                |
| `deprecated` | Plus ancienne, et le lecteur devrait mettre à jour     |
| `eol`        | Morte — signalée, et hors du sitemap                   |

Ce que chacune coûte à une page est dans
[URL et versions](/concepts/urls-and-versions).

## Sections générées

`generated` liste les artefacts qui ne sont pas du Markdown et le type qui lit
chacun d’eux en pages. Ce qu’est le mécanisme, et les deux politiques auxquelles
un type répond, se trouve dans
[Sections générées](/concepts/generated-sections) ; les champs ci-dessous sont
les mêmes quel que soit le type qui les lit.

| Champ        | Type                     | Notes                                                        |
| :----------- | :----------------------- | :------------------------------------------------------------ |
| `type`       | `string`                 | La clé de registre du type — `changelog`, `openapi`, `bruno`, le vôtre  |
| `path`       | `string`                 | L’artefact, relatif à la racine propre de la source            |
| `label`      | `string`                 | L’entrée de la barre et — slugifiée — le segment d’URL         |
| `slug`       | `string`                 | Remplace le segment que le libellé produirait                  |
| `options`    | objet                    | Les réglages qu’offre ce type ; chaque type valide les siens   |
| `versions`   | liste de versions        | Les versions de cet artefact — voir ci-dessous                 |
| `locales`    | `Record<string, string>` | Un artefact par langue, lu par un type `per-locale` seulement  |
| `navigation` | placement                | `'sections'` (par défaut), `'navigation'` ou `false`           |
| `icon`       | `string`                 | Retombe sur l’icône propre du type                             |

**`path` est un chemin et jamais une URL.** Pour une source que Content clone, il
est relatif à la racine de ce checkout, donc l’artefact voyage avec la version à
laquelle il appartient — une règle dans les deux sens. Un emplacement arbitraire
permettrait d’aller chercher un artefact n’importe où et rouvrirait la question du
réseau au moment du build, que `sources` a déjà refermée.

**`label` est une chaîne simple et non un texte traduit**, pour la même raison que
le libellé d’une version en est une : un texte traduit n’est pas une URL stable.

### Une section avec ses propres versions

Une version est normalement un **checkout** : `refs` sur la source publie chaque
section une fois par ref. Une API conserve en revanche souvent
`openapi/v1.yaml` à côté de `openapi/v2.yaml` dans le même dépôt et se versionne
par **fichier**. Sans `versions`, ce seraient deux sections indépendantes et deux
entrées de navigation.

```ts [app/app.config.ts]
generated: [
  {
    type: 'openapi',
    label: 'API',
    path: 'openapi/v2.yaml',
    versions: [
      { version: 'v2', path: 'openapi/v2.yaml' },
      { version: 'v1', path: 'openapi/v1.yaml', status: 'deprecated' }
    ]
  }
]
```

| Champ     | Notes                                                             |
| :-------- | :---------------------------------------------------------------- |
| `version` | Affichée dans le sélecteur et utilisée dans l’URL                 |
| `path`    | L’artefact de cette version ; par défaut, celui de la déclaration |
| `locales` | Les artefacts par locale pour cette version                       |
| `status`  | Cycle de vie — `deprecated`, `eol`, `upcoming`                    |
| `default` | Servie sans segment de version ; première entrée par défaut       |

La version par défaut est servie sous `/api`, les autres sous leur propre
segment comme `/v1/api`. Le sélecteur les propose comme les refs d’une source,
avec le bandeau, `noindex` et le canonical d’une version non courante.

Elles sont réunies **dans une déclaration plutôt que deux sources** à dessein :
seules les variantes produites par une même déclaration sont proposées comme
versions l’une de l’autre. Une source par version d’API publierait aussi deux
fois l’arbre documentaire.

Ne les placez **jamais à côté de `refs` sur la même source**. Les deux réclament
le même segment d’URL et le build refuse la combinaison. Un type `global` les
refuse également puisqu’il publie une histoire unique sous une URL neutre. Un
changelog n’est pas global : il est publié par version et accepte `versions`
comme une référence d’API.

### Quelle version est laquelle ?

Trois choses portent le nom de version autour d’une page de référence, mais deux
seulement appartiennent à duxt :

- **La version dans l’URL et le sélecteur** est une ref ou une valeur `version`
  déclarée ci-dessus. Le badge indique la variante lue.
- **`duxt.version`** est la chaîne propre au site. Elle n’apparaît dans le badge
  que lorsqu’il n’y a rien à sélectionner.
- **`info.version` d’un document OpenAPI** est la déclaration du document sur
  l’API décrite. Elle apparaît comme **Version d’API** sur la page de référence,
  jamais dans le badge du sélecteur.

Les nombres se ressemblent souvent mais restent des faits distincts ; duxt ne
déduit aucun de l’autre.

`options` est opaque à tout sauf au type qui les lit — une granularité veut dire
quelque chose pour un journal des versions et rien pour une référence d’API. Une
clé que le type ne connaît pas fait échouer le build au lieu d’être ignorée, parce
qu’une option mal orthographiée est un site qui n’obtient silencieusement pas ce
qu’il a configuré.


## Options de source

| Champ           | Par défaut          | Ce qu’il fait                                              |
| :-------------- | :------------------ | :---------------------------------------------------------- |
| `showRepo`      | désactivé           | Force un segment de dépôt avec un dépôt unique               |
| `showVersion`   | désactivé           | Force un segment de version avec une version unique          |
| `defaultRef`    | la première ref     | La ref servie sans préfixe de version                        |
| `defaultLocale` | la première locale  | La locale servie depuis `path` lui-même, sans dossier        |

## Le manifeste résolu

La compilation transforme la liste ci-dessus en `duxt.resolvedSources`, et c’est
ce que lit le thème. `useDuxtCollection()` l’expose ; chaque entrée porte le nom
de la collection, le `prefix` d’URL, `repo`, `version`, `name`, `isDefault`,
`locale`,
`isDefaultLocale`, `status`, le dépôt et la ref d’où viennent les pages, et si
son `history` a été lu.

La locale est délibérément absente de `prefix` : i18n la place déjà devant le
chemin, si bien que toutes les langues d’une source partagent un préfixe et ne
diffèrent que par la collection.

## Médias de documentation

Les images générées se placent dans `docs/_assets/`. Les références sont relatives au fichier Markdown : `docs/1.guides/1.demo.md` utilise `../_assets/demo.gif`. Le préfixe `/_assets/` désigne la racine de documentation de la source. La même règle vaut pour l'attribut d'image `dark`.

duxt publie automatiquement les images PNG, JPEG, GIF, SVG, WebP, AVIF, APNG et ICO, y compris les sources distantes à leur ref sélectionnée. Les URL séparent dépôt, racine de documentation et ref ; les liens de page et le fournisseur d'images sont conservés. `_assets/` ne devient ni section ni page. Les tapes, scripts, Dockerfiles et autres sources de capture ne sont pas publiés.

Les images sans texte localisé restent dans `_assets/` partagé. Une page dans `docs/de/` peut utiliser `../_assets/demo.gif` ; une variante allemande produite explicitement dans `docs/de/_assets/` utilise `_assets/demo.gif`. Les images viennent du dépôt et de la ref de la page. Un dépôt de traduction peut partager les images de son checkout, sans récupérer implicitement celles d'un autre dépôt. Traduisez les textes alternatifs et légendes avec la page.