# i18n (internationalization)

The Kotlin SDK is a **server SDK**. It does **not** have a runtime translation
helper (there is no `t()` / label-render API). Translation rendering happens in
the **browser**, via the Shipeasy client SDK's `t()` and a loader script.

What this SDK *does* provide is the **SSR wiring** so the browser SDK has the
right profile and the same bucketing on first paint, via two top-level functions
(both backed by the global `configure()` state):

- `i18nScriptTag(clientKey, profile)` — emits the i18n **loader** `<script>`
  tag. The loader fetches translations for the profile using the **public client
  key** (safe to embed in HTML).
- `bootstrapScriptTag(user, ..., i18nProfile)` — the bootstrap tag also carries
  the i18n profile in `data-i18n-profile`.

## Cross-SDK story

1. **Server (this SDK):** render the loader tag into your document `<head>`,
   passing the **public client key** and the `{{PROFILE}}` profile.

   ```kotlin
   import ai.shipeasy.i18nScriptTag

   val head = i18nScriptTag(clientKey, "{{PROFILE}}")
   ```

2. **Browser (client SDK):** the loader hydrates the translations for
   `{{PROFILE}}`; your front-end calls the client SDK's `t("key")` to render
   labels. There is no server-side `t()`.

> Use the **public client key** on the i18n tag — never the server key.

See [the i18n snippets](../snippets/i18n/setup.md) and the cross-SDK identity
contract in `18-identity-bucketing.md`.
