# Languages

> Ask for an association's copy in another language with ?locale=, tell from locale and locales what was served, say which language to write to a person in. Never a machine translation.

URL: https://developers.vimine.network/en/guides/languages/

An association writes its copy in Italian and, if it wants to, **in another language too**, among those Vimine
speaks — `it`, `en`, `zh-Hans`, `zh-Hant`, `fr`, `es`, `de` and `pt-BR` today. Not everything gets translated, and nothing is translated by a machine: where the
association wrote no translation, the API serves its Italian text and **tells you so**.

This guide is what changes for an integration: how to ask for a language, how to read the answer, how to tell Vimine
which language to write to a person in.

## Asking for a language

Every read that returns an association's copy takes `?locale=`:

| Read | |
|---|---|
| `GET /v1/aps/{slug}` | membership types, payment instructions, privacy notice |
| `GET /v1/aps/{slug}/events`, `GET /v1/aps/{slug}/events/{event}` | public events |
| `GET /v1/events`, `GET /v1/events/{slug}` | events with a token, members-only ones included |

```js
const event = await vimine.public.events.get('circolo-aurora', 'festa-di-primavera', { locale: 'en' });
event.title;   // "Spring party" — if the association wrote it
event.locale;  // "en": the title is in English. "it": there is no translation, you have the Italian text
event.locales; // ["it", "en"]: the languages in which this event has a title
```

Without `?locale=` the language is decided, in order, by: the language the member chose (with a member token), the
`Accept-Language` header, the association's language. A value Vimine does not speak (`?locale=ja`) is **ignored**, it
is not an error: you get Italian, with `locale: "it"`.

A regional tag (`en-GB`) is accepted too: it is reduced to its language.

## Reading the answer

- **`locale`** is the language the main text — an event's title — came in. When it is not the one you asked for, the
  association wrote no translation.
- **`locales`** are the languages in which that text exists: use them to show a switcher only where it is useful.
- The replacement happens **field by field**: an event may have an English title and an Italian description. We
  never mix two languages inside the same text, and we never make translations up.

On `GET /v1/aps/{slug}`, `locale` is the language of the answer and `locales` the languages the association offers.

The association's name, the identifiers (`slug`, `cod`) and legal documents are never translated: the statuto is a
legal act, and it is in Italian.

Public reads answer with `Content-Language` and, when `Accept-Language` decided, with `Vary: Accept-Language`: if you
put a cache in front of the API, honour it — or always pass `?locale=`.

## The privacy notice has one version per language

The association's privacy notice exists once per language, and **each language has its own version**. If you read the
profile with `?locale=en` and the association published an English notice, `privacy_notice` is that one — with
`locale: "en"`. When you enrol the person, send back what you showed them, language included:

```js
const profile = await vimine.public.association('circolo-aurora', { locale: 'en' });

await vimineServer.enroll({
    // …
    locale: 'en',
    privacy_notice: {
        version: profile.privacy_notice.version,
        sha256: profile.privacy_notice.sha256,
        locale: profile.privacy_notice.locale
    }
});
```

The proof we record names **that** document: the one the person actually read.

## Saying which language to write to a person in

`POST /v1/signup`, `POST /v1/enroll` and event registrations take `locale`: the language of the page the person
filled in on your site.

- It decides the language of the **mails that follow** (address confirmation, welcome, registration confirmation).
- It becomes the preference of a **new** account. An account that already exists keeps its own.
- For a **guest** — someone who registers for an event without an account — it is all we know: every mail they
  receive is in that language.

```js
await vimineServer.registrations.guest('festa-di-primavera', {
    email: 'marie.dupont@example.org',
    first_name: 'Marie',
    last_name: 'Dupont',
    registration_type: type.uid,
    locale: 'en'
});
```

In mails, the association's own copy (the event's title, the payment instructions) follows the same rule as the
reads: in English where the association wrote it, in Italian otherwise.

## The member's language

`GET /v1/me` returns `locale`: the language the person chose, or `null` if they never chose one. With the
`profile:write` scope you can change it:

```js
await vimine.me.update({ locale: 'en' }); // null clears the choice
```

Here — and only here — a language Vimine does not speak is an error: `422` with `code: "unsupported"` on the
`locale` field. Write it only when the person chose it: do not infer it from the browser.

## Sign in with Vimine

`ui_locales` on the authorization request is a preference list, in order (`ui_locales=ja en`): the first language
Vimine speaks wins. If you name none, the consent page follows the browser's language, then the association's.
