# Internationalisation

The generated pages render many labels: section headings such as **Parameters** and
**Returns**, badges, table columns, the search box, and the permalink hint. Each label
comes from a translation table, not from your docstrings. The package ships with thirteen
languages, and you don't need to configure anything to use them.

The translation mechanism depends on the host. Under Starlight, the labels come from
Starlight's own translation system, and the plugin injects its tables into it. A plain
Astro project has no translation system, so its components take a `labels` prop instead.
This is why `<Autodoc>`, `<SymbolSearch>` and the other components have label props.

## Bundled locales

| Locale  | Language             | Locale  | Language             |
| ------- | -------------------- | ------- | -------------------- |
| `en`    | English (the source) | `nl`    | Dutch                |
| `de`    | German               | `no`    | Norwegian (Bokmål)   |
| `es`    | Spanish              | `pt-BR` | Portuguese (Brazil)  |
| `fr`    | French               | `ru`    | Russian              |
| `it`    | Italian              | `sv`    | Swedish              |
| `ja`    | Japanese             | `zh`    | Chinese (simplified) |
| `ko`    | Korean               |         |                      |

Each locale overlays only the keys it translates. English fills any gap, so a string
added in a new release is readable everywhere from the day it lands.

Labels that name a Python or pydantic construct stay in English in every locale:
`classmethod`, `staticmethod`, `async`, `abstract`, `cached`, `pydantic model`,
`pydantic field` and `pydantic validator`. These are the identifiers a reader sees in the
code, and translating them would name something that does not exist.

## In a Starlight site

The plugin injects its tables through Starlight's `i18n:setup` hook. Labels then follow
Starlight's own locale selection, with no extra configuration needed. A site with
`locales` configured serves each locale's pages with that locale's labels. A monolingual
site with `defaultLocale: 'fr'` gets French labels throughout.

```js title="astro.config.mjs" {9-10}
import starlight from '@astrojs/starlight';
import { defineConfig } from 'astro/config';
import starlightPydocs from 'starlight-pydocs';

export default defineConfig({
  integrations: [
    starlight({
      title: 'Mon projet',
      defaultLocale: 'fr',
      locales: { fr: { label: 'Français' }, en: { label: 'English' } },
      plugins: [starlightPydocs({ packages: [{ name: 'mypkg', search: ['../src'] }] })],
    }),
  ],
});
```

The generated pages themselves are not translated. There is one set of API pages, built
from one dump, and each page carries the labels of whichever locale the reader is
browsing. The docstrings stay in whatever language you wrote them in.

### Changing or adding a string

The keys share Starlight's global translation table, namespaced `starlightPydocs.`.
Overriding one key works the same as overriding any Starlight string. Starlight reads
these overrides from an `i18n` collection. A site that has never translated anything will
not have declared this collection yet:

```ts title="src/content.config.ts" {7} "i18nLoader" "i18nSchema"
import { docsLoader, i18nLoader } from '@astrojs/starlight/loaders';
import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
import { defineCollection } from 'astro:content';

export const collections = {
  docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
  i18n: defineCollection({ loader: i18nLoader(), schema: i18nSchema() }),
};
```

One JSON file per locale overrides whichever keys you name. The schema accepts keys it
does not recognise, so plugin keys need no extra declaration:

```json title="src/content/i18n/fr.json"
{
  "starlightPydocs.parameters": "Arguments",
  "starlightPydocs.viewSource": "Voir le code"
}
```

Use the same file to add a locale the package does not ship yet. If you translate a full
set of strings, please send a pull request that adds it to `translations.ts`. See
[Contributing](/starlight-pydocs/guides/contributing/).

## Without Starlight

A plain Astro project has no translation table to inject into. Every component that
renders a label takes a `labels` prop instead, carrying whichever keys you want to
override. This prop wins over every other source, and you can also use it to override
one string in one place inside a Starlight site:

```astro title="src/pages/report.astro"
---
import { Autodoc, SymbolSearch } from 'starlight-pydocs/components';
---

<Autodoc
  name="mypkg.Report"
  labels={{ parameters: 'Arguments', returns: 'Retourne', viewSource: 'Voir le code' }}
/>
<SymbolSearch
  labels={{ searchLabel: 'Rechercher un symbole', searchPlaceholder: 'Classes, fonctions, attributs…' }}
/>
```

In a vanilla site, the route renders the generated pages, not you, so there is no
`labels` prop to pass them. Instead, they read a translation function off `Astro.locals`.
This is the same mechanism Starlight's `t()` arrives through, so one middleware can
translate every generated page:

```ts title="src/middleware.ts" {10}
import { defineMiddleware } from 'astro:middleware';

const fr: Record<string, string> = {
  'starlightPydocs.parameters': 'Arguments',
  'starlightPydocs.viewSource': 'Voir le code',
  'starlightPydocs.onPage': 'Sur cette page',
};

export const onRequest = defineMiddleware((context, next) => {
  context.locals.t = (key: string) => fr[key] ?? key;
  return next();
});
```

Keys are namespaced exactly as in a Starlight table. Returning the key unchanged means "no
translation" and falls back to English. Without this middleware, a vanilla site's
generated pages use the English defaults.

`locals.t` is your own addition to `App.Locals`. Declare it once for the type-checker:

```ts title="src/env.d.ts"
declare namespace App {
  interface Locals {
    t: (key: string) => string;
  }
}
```

## The keys

Every label resolves in this order: the `labels` prop, then the host's translation for
`starlightPydocs.<key>`, then the bundled English default below. `lib/strings.ts` in the
package holds the full list of keys, and the unit tests check that every locale's keys
exist in it.

**Member group headings**, for the sections listing what a module or class contains:

| Key           | English default |
| ------------- | --------------- |
| `attributes`  | Attributes      |
| `properties`  | Properties      |
| `classes`     | Classes         |
| `functions`   | Functions       |
| `methods`     | Methods         |
| `modules`     | Modules         |
| `typeAliases` | Type aliases    |

**Docstring section headings**, one per section Griffe parses out of a docstring:

| Key               | English default  |
| ----------------- | ---------------- |
| `parameters`      | Parameters       |
| `otherParameters` | Other parameters |
| `typeParameters`  | Type parameters  |
| `returns`         | Returns          |
| `yields`          | Yields           |
| `receives`        | Receives         |
| `raises`          | Raises           |
| `warns`           | Warns            |
| `examples`        | Examples         |

**Signature and member metadata:**

| Key               | English default  |
| ----------------- | ---------------- |
| `bases`           | Bases            |
| `default`         | default          |
| `required`        | required         |
| `inheritedFrom`   | Inherited from   |
| `reexportedFrom`  | Re-exported from |
| `aliasOf`         | Alias of         |
| `deprecated`      | Deprecated       |
| `deprecatedSince` | Deprecated since |
| `addedIn`         | Added in         |
| `viewSource`      | View source      |
| `openDocsAt`      | Open docs at     |
| `showMore`        | Show more        |
| `showLess`        | Show less        |

`openDocsAt` is the tooltip on an annotation that links to another documentation site, followed by
that site's host name. `showMore` and `showLess` label the toggle under an attribute value too long
to show whole.

**Table columns**, used by the parameter and attribute tables:

| Key                 | English default |
| ------------------- | --------------- |
| `columnName`        | Name            |
| `columnType`        | Type            |
| `columnDescription` | Description     |
| `columnDefault`     | Default         |

**Object kinds**, for badges and for grouping symbol search results:

| Key             | English default |
| --------------- | --------------- |
| `kindModule`    | module          |
| `kindClass`     | class           |
| `kindFunction`  | function        |
| `kindMethod`    | method          |
| `kindAttribute` | attribute       |
| `kindProperty`  | property        |
| `kindAlias`     | alias           |

**Badges** for the labels Griffe attaches to an object. The first five keys and the three
pydantic keys are the constructs named above. No locale translates them:

| Key                      | English default    |
| ------------------------ | ------------------ |
| `labelClassmethod`       | classmethod        |
| `labelStaticmethod`      | staticmethod       |
| `labelAsync`             | async              |
| `labelAbstract`          | abstract           |
| `labelCached`            | cached             |
| `labelReadOnly`          | read-only          |
| `labelWritable`          | writable           |
| `labelInstanceAttribute` | instance attribute |
| `labelClassAttribute`    | class attribute    |
| `labelModuleAttribute`   | module attribute   |
| `labelPydanticModel`     | pydantic model     |
| `labelPydanticField`     | pydantic field     |
| `labelPydanticValidator` | pydantic validator |

**Symbol search**, the plugin's own search box. See
[Search](/starlight-pydocs/guides/search/):

| Key                 | English default                        |
| ------------------- | -------------------------------------- |
| `searchLabel`       | Search symbols                         |
| `searchPlaceholder` | Search classes, functions, attributes… |
| `searchNoResults`   | No matching symbols                    |
| `searchResults`     | Results                                |
| `searchHint`        | Type part of a name or a dotted path   |

**Page furniture**: the strings around the objects rather than on them. `permalink` is the
accessible name of an anchor heading's link, followed by the object path. `overview` is
the sidebar link to a package's root page:

| Key            | English default        |
| -------------- | ---------------------- |
| `permalink`    | Permalink to           |
| `overview`     | Overview               |
| `onPage`       | On this page           |
| `noMembers`    | No documented members. |
| `undocumented` | No description.        |