Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursor/rules/localization-workflow.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ alwaysApply: true
- `scripts/localize-mdx-paths.mjs` rewrites: `<locale>/components/*.jsx` for the active locale; `from ".../snippets/..."`; and JSX `src=".../assets/..."` so `../` depth matches the file’s path. Run after Lingo in `translate:generate` and translate-on-main; CI checks via `translate:localize-mdx-paths:check`.
- Shared MDX snippets live under repo-root `snippets/` (not per-locale). Import with relative paths from each page; do not add shared MDX snippets to Lingo `i18n.json` buckets unless you intend to translate them.
- Locale-aware React components that can contain text live under `components/*.jsx` for default language and `<locale>/components/*.jsx` for targets, and are manually maintained per locale (do not add them to Lingo `i18n.json` buckets; do not keep these in shared `snippets/`).
- Keep a **single** OpenAPI document at repo-root `openapi.yml` (not under `en/` or `es/`). Endpoint and webhook MDX must use Mintlify’s form `openapi: openapi.yml <method> <path>` or `openapi: openapi.yml webhook <eventKey>`. Do not translate the `openapi:` line.
- Keep OpenAPI specs under repo-root `openapi/` (not under locale folders). Endpoint and webhook MDX must use Mintlify’s form `openapi: openapi/<spec>.yml <method> <path>` or `openapi: openapi/<spec>.yml webhook <eventKey>`. Do not translate the `openapi:` line.
- English **nav titles** for those pages come from OpenAPI **`summary`** via `scripts/sync-openapi-titles.mjs` (`npm run translate:sync-openapi-titles`). It runs at the start of `translate:generate` and on the translate-on-main workflow. Lingo translates the `title` field for target locales; the script only fills a missing target `title` with English (bootstrap)—it does not overwrite existing translations.
- Mintlify custom heading IDs use markdown `## Title {#slug}` (see Mintlify docs). Slugs are aligned from English source root files via `scripts/sync-heading-anchors.mjs`. Never translate or alter `{#…}`; sync runs after Lingo in PIT/CI. Do not merge heading-count drift between source root and target locales without fixing structure first.
- For Mintlify `<Accordion>` components that may be deep-linked, always set explicit `id` values (do not rely on title-derived hashes) and keep those `id`s identical across locales.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/validate-translations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
paths:
- "docs.json"
- "i18n.json"
- "openapi.yml"
- "openapi/**"
- "package.json"
- "account/**"
- "admin-api/**"
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ Notes:
- `lingo/glossary.csv`: Terms that must stay fixed or use specific translations.
- `lingo/brand-voice.md`: Single brand voice used for all locales.
- `scripts/translate-docs-json.mjs`: Translates language-specific `docs.json` navigation labels directly in the source-of-truth `docs.json`. Prefer `npm run translate:docs-json -- --target <locale>`.
- `scripts/localize-internal-links.mjs`: Rewrites internal absolute **navigation** links in each locale’s MDX for whatever locale is being processed (`--target`, `--all`, or default targets): bare paths get that locale’s prefix (e.g. `/platform/points` → `/es/platform/points` when processing `es/`), and any path already prefixed with **another** locale from `i18n.json` (`en`, `es`, future `fr`, etc.) is re-prefixed to the active locale (so `/en/...` or stale `/es/...` on a `fr/` page become `/fr/...`). Longer codes are matched first (e.g. `en-US` before `en`). It does **not** change relative image or video `src` paths or MDX `import` paths (those are normalized by `scripts/localize-mdx-paths.mjs` after translation: components, `snippets/`, and repo-root `assets/`). Prefer `npm run translate:localize-links --` with `--target`, `--all`, or `--all --check`.
- `scripts/localize-internal-links.mjs`: Rewrites internal absolute **navigation** links in each locale’s MDX for whatever locale is being processed (`--target`, `--all`, or default targets): bare paths get that locale’s prefix (e.g. `/features/points` → `/es/features/points` when processing `es/`), and any path already prefixed with **another** locale from `i18n.json` (`en`, `es`, future `fr`, etc.) is re-prefixed to the active locale (so `/en/...` or stale `/es/...` on a `fr/` page become `/fr/...`). Longer codes are matched first (e.g. `en-US` before `en`). It does **not** change relative image or video `src` paths or MDX `import` paths (those are normalized by `scripts/localize-mdx-paths.mjs` after translation: components, `snippets/`, and repo-root `assets/`). Prefer `npm run translate:localize-links --` with `--target`, `--all`, or `--all --check`.
- `scripts/localize-mdx-paths.mjs`: Rewrites MDX paths for locale docs: (1) `.../<locale>/components/...jsx` for the active locale, (2) `import ... ".../snippets/..."` depth to repo-root `snippets/`, and (3) JSX `src=".../assets/..."` depth to repo-root `assets/` (Lingo copies English relative paths). Use `--target`, `--all`, or default targets; `translate:generate` and translate-on-main run it after Lingo.
- **Shared MDX snippets (`snippets/*.mdx`)**: Reusable MDX blocks stay in repo-root `snippets/` (not per-locale). Import them with relative paths from each page (for example `../../snippets/foo.mdx` from `locale/<section>/<page>.mdx`, or more `../` segments for deeper pages). They are excluded from Lingo buckets in `i18n.json` so they stay English and identical everywhere.
- **Localized React components (`components/*.jsx` for default language, `<locale>/components/*.jsx` for targets)**: UI components that can contain locale text are stored per locale (for example `components/rate-limit-badge.jsx`, `es/components/rate-limit-badge.jsx`) and manually maintained per locale (not translated by PIT/CI automation).
- **Media paths**: Default-language pages live at repo root paths like `<section>/<page>.mdx` and target locales live under `<locale>/<section>/<page>.mdx`; shared files sit in repo-root `assets/`. Prefer relative `src="../assets/..."` (or more `../`) from English source; `scripts/localize-mdx-paths.mjs` rewrites `assets/` `src` depth for each target locale file.
- **`openapi.yml`**: One OpenAPI 3.1 spec at the **repository root** (alongside `docs.json`). API and webhook pages reference it explicitly in frontmatter, for example `openapi: openapi.yml get /users/{id}` or `openapi: openapi.yml webhook points.changed`. Do not duplicate the YAML under locale folders; Lingo must not alter `openapi:` lines.
- **`scripts/sync-openapi-titles.mjs`**: Copies each operation/webhook **`summary`** from `openapi.yml` into the English page’s **`title:`** frontmatter (Mintlify’s default when `title` is omitted). Target locales get an English `title` only if missing (bootstrap); run **`npm run translate:generate`** so Lingo translates those titles. Runs automatically at the start of `translate:generate` and in translate-on-main before Lingo.
- **`openapi/`**: Split OpenAPI 3.1 specs at the **repository root** (for example `openapi/application.yml`, `openapi/admin.yml`). API and webhook pages reference a spec explicitly in frontmatter, for example `openapi: openapi/application.yml get /users/{id}` or `openapi: openapi/application.yml webhook points.changed`. Do not duplicate the YAML under locale folders; Lingo must not alter `openapi:` lines.
- **`scripts/sync-openapi-titles.mjs`**: Copies each operation/webhook **`summary`** from the referenced spec into the English page’s **`title:`** frontmatter (Mintlify’s default when `title` is omitted). Target locales get an English `title` only if missing (bootstrap); run **`npm run translate:generate`** so Lingo translates those titles. Runs automatically at the start of `translate:generate` and in translate-on-main before Lingo.
- `scripts/sync-heading-anchors.mjs`: Writes Mintlify [custom heading IDs](https://www.mintlify.com/docs/create/text#custom-heading-ids) as **`## Title {#slug}`** markdown. Slugs match Mintlify’s auto rules from the **English** title so hashes like `#pro-plan` stay stable across locales. Run `npm run translate:sync-anchors` after bulk heading edits; translation pipelines run it automatically (see **Heading anchors and Lingo** below). The script can also migrate one-line **`<h2 id="slug">…</h2>`** left from older tooling back to `{#slug}` syntax.
- `scripts/validate-glossary-csv.mjs`: Validates glossary schema and duplicate canonical keys. Prefer `npm run lingo:validate-glossary`.

Expand All @@ -92,7 +92,7 @@ Use `npm run <script> -- <args>` when a script needs CLI flags (the `--` forward
| `translate:localize-mdx-paths:check` | CI-style check: fail if any of the above is wrong for its locale/path. |
| `translate:sync-anchors` | Apply English-derived `{#slug}` on default-language root MDX and target locales (see `i18n.json` `locale.targets`). |
| `translate:sync-anchors:check` | Fail if any MDX needs re-sync (CI). |
| `translate:sync-openapi-titles` | Set default-language API & webhook `title:` from `openapi.yml` summaries; bootstrap missing target `title` from English. |
| `translate:sync-openapi-titles` | Set default-language API & webhook `title:` from `openapi/*.yml` summaries; bootstrap missing target `title` from English. |
| `translate:sync-openapi-titles:check` | CI: fail if any OpenAPI-backed page title differs from the spec. |
| `lingo:validate-glossary` | Validate `lingo/glossary.csv`. |
| `translate:validate` | MDX parity and frontmatter checks (source root -> target locales, e.g. `es`). No `.env` required. |
Expand Down Expand Up @@ -164,7 +164,7 @@ Glossary sync workflow (manual via Cursor + MCP):
- In `locale.targets`, append the locale code (for example `fr` or `de`).
3. Create the language content directory:
- Mirror the root default-language structure under `<locale>/` with the same filenames.
- Example: `platform/overview.mdx` -> `fr/platform/overview.mdx`.
- Example: `platform/overview.mdx` -> `fr/features/overview.mdx`.
- Keep MDX snippets shared in repo-root `snippets/` (no per-locale snippet trees).
- Keep React components locale-local under `<locale>/components/*.jsx` and mirror updates manually across locales (not via Lingo automation).
4. Configure Lingo.dev engine controls for the new locale:
Expand Down
18 changes: 9 additions & 9 deletions account/billing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Trophy follows a usage-based pricing model where customers only pay for the unit

## Monthly Active Users (MAUs) {#monthly-active-users-maus}

Trophy defines an MAU as a single user that sends at least one [metric event](/platform/events) to Trophy in a given month.
Trophy defines an MAU as a single user that sends at least one [metric event](/features/events) to Trophy in a given month.

<Tip>
Bear in mind **you never pay for churned users**. If a user signs up for your
Expand Down Expand Up @@ -83,21 +83,21 @@ Here's a list of all Trophy features and the plan they become available on:

<PlanBadge plan="free" />

- [Achievements](/platform/achievements)
- [Streaks](/platform/streaks)
- [Points](/platform/points)
- [Leaderboards](/platform/leaderboards)
- [Emails](/platform/emails)
- [Push Notifications](/platform/push-notifications)
- [Achievements](/features/achievements)
- [Streaks](/features/streaks)
- [Points](/features/points)
- [Leaderboards](/features/leaderboards)
- [Emails](/features/emails)
- [Push Notifications](/features/push-notifications)

<PlanBadge plan="starter" />

- [DNS Verification](/platform/emails#dns-verification-advanced)
- [DNS Verification](/features/emails#dns-verification-advanced)

<PlanBadge plan="pro" />

- [Webhooks](/webhooks)
- [Custom Attributes](/platform/users#custom-user-attributes)
- [Custom Attributes](/features/users#custom-user-attributes)

## Custom Contracts {#custom-contracts}

Expand Down
2 changes: 1 addition & 1 deletion account/branding.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ icon: palette

## Configure Branding {#configure-branding}

The [branding page](https://app.trophy.so/branding) in the Trophy dashboard allows you to configure the following account-level settings. These setting will be used in any communications you configure Trophy to send to users, like [Emails](/platform/emails).
The [branding page](https://app.trophy.so/branding) in the Trophy dashboard allows you to configure the following account-level settings. These setting will be used in any communications you configure Trophy to send to users, like [Emails](/features/emails).

<Frame>
<img height="200" noZoom src="../assets/account/branding/branding_page.png" />
Expand Down
2 changes: 1 addition & 1 deletion admin-api/endpoints/metrics/get-a-metric.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Get a metric
title: Get a metric by ID
openapi: openapi/admin.yml get /metrics/{id}
---

Expand Down
2 changes: 1 addition & 1 deletion admin-api/endpoints/points/delete-boosts.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Delete points boosts
title: Delete multiple points boosts
Comment thread
cbrinicombe13 marked this conversation as resolved.
openapi: openapi/admin.yml delete /points/{systemId}/boosts
---

Expand Down
2 changes: 1 addition & 1 deletion admin-api/endpoints/points/delete-levels.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Delete points levels
title: Delete multiple points levels
openapi: openapi/admin.yml delete /points/{systemId}/levels
---

Expand Down
2 changes: 1 addition & 1 deletion admin-api/endpoints/points/get-a-boost.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Get a points boost
title: Get a points boost by ID
openapi: openapi/admin.yml get /points/{systemId}/boosts/{id}
---

Expand Down
2 changes: 1 addition & 1 deletion admin-api/endpoints/points/get-a-level.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Get a points level
title: Get a points level by ID
openapi: openapi/admin.yml get /points/{systemId}/levels/{id}
---

Expand Down
2 changes: 1 addition & 1 deletion admin-api/endpoints/points/get-a-points-system.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Get a points system
title: Get a points system by ID
openapi: openapi/admin.yml get /points/{id}
---

Expand Down
2 changes: 1 addition & 1 deletion admin-api/endpoints/points/get-a-points-trigger.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Get a points trigger
title: Get a points trigger by ID
openapi: openapi/admin.yml get /points/{systemId}/triggers/{id}
---

Expand Down
2 changes: 1 addition & 1 deletion admin-api/endpoints/points/update-boosts.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Update points boosts
title: Update multiple points boosts
openapi: openapi/admin.yml patch /points/{systemId}/boosts
---

Expand Down
2 changes: 1 addition & 1 deletion admin-api/endpoints/points/update-levels.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Update points levels
title: Update multiple points levels
openapi: openapi/admin.yml patch /points/{systemId}/levels
---

Expand Down
10 changes: 10 additions & 0 deletions admin-api/endpoints/tenants/create-tenants.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Create tenants
openapi: openapi/admin.yml post /tenants
---

import { RateLimitBadge } from "../../../components/rate-limit-badge.jsx";

**Rate Limits**

<RateLimitBadge tier={1} />
10 changes: 10 additions & 0 deletions admin-api/endpoints/tenants/delete-tenants.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Delete tenants
openapi: openapi/admin.yml delete /tenants
---

import { RateLimitBadge } from "../../../components/rate-limit-badge.jsx";

**Rate Limits**

<RateLimitBadge tier={1} />
10 changes: 10 additions & 0 deletions admin-api/endpoints/tenants/get-a-tenant.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Get a tenant
openapi: openapi/admin.yml get /tenants/{id}
---

import { RateLimitBadge } from "../../../components/rate-limit-badge.jsx";

**Rate Limits**

<RateLimitBadge tier={1} />
10 changes: 10 additions & 0 deletions admin-api/endpoints/tenants/list-tenants.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: List tenants
openapi: openapi/admin.yml get /tenants
---

import { RateLimitBadge } from "../../../components/rate-limit-badge.jsx";

**Rate Limits**

<RateLimitBadge tier={1} />
10 changes: 10 additions & 0 deletions admin-api/endpoints/tenants/update-tenants.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Update tenants
openapi: openapi/admin.yml patch /tenants
---

import { RateLimitBadge } from "../../../components/rate-limit-badge.jsx";

**Rate Limits**

<RateLimitBadge tier={1} />
4 changes: 4 additions & 0 deletions admin-api/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ The Admin API is accessible through **the same SDKs** as the Application API or,
https://admin.trophy.so/v1
```

<Tip>
The full API reference is available publicly at [/openapi](https://admin.trophy.so/v1/openapi).
</Tip>

## Get Started {#get-started}

Learn more about how to integrate with the Trophy Admin API below.
Expand Down
2 changes: 1 addition & 1 deletion api-reference/idempotency.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ When Trophy detects an idempotency key has been sent with an event, it will firs
- If instead Trophy detects the user hasn't used the idempotency key before, it will process the event as usual, returning a `201 Created` response. Finally Trophy will store the idempotency key for lookup during any subsequent requests.

<Note>
All Trophy [metrics](/platform/metrics) manage idempotency in isolation.
All Trophy [metrics](/features/metrics) manage idempotency in isolation.
Trophy will accept a user using the same idempotency key for events against
different metrics as separate isolated requests.
</Note>
Expand Down
4 changes: 4 additions & 0 deletions api-reference/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ The Application API is accessible through [SDKs](/api-reference/client-libraries
https://api.trophy.so/v1
```

<Tip>
The full API reference is available publicly at [/openapi](https://api.trophy.so/v1/openapi).
</Tip>

## Get Started {#get-started}

Learn more about how to integrate with the Trophy Application API below.
Expand Down
Binary file added assets/platform/environments/copying_changes.mp4
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added assets/platform/environments/viewing_changes.mp4
Binary file not shown.
Loading
Loading