Skip to content

Commit adca41b

Browse files
committed
Merge branch 'ADP-6100' into develop
# Conflicts: # astro.config.mjs # src/api-reference/specs/adapty-api.tr.yaml # src/components/Homepage.tsx # src/content/docs/version-3.0/arppu.mdx # src/content/docs/version-3.0/arpu.mdx # src/content/docs/version-3.0/arr.mdx # src/content/docs/version-3.0/mrr.mdx # src/content/docs/version-3.0/revenue.mdx # src/locales/tr/_sidebar-labels.json # src/locales/tr/arppu.mdx # src/locales/tr/arpu.mdx # src/locales/tr/arr.mdx # src/locales/tr/attribution-integration.mdx # src/locales/tr/autopilot.mdx # src/locales/tr/is-adapty-right-for-me.mdx # src/locales/tr/mrr.mdx # src/locales/tr/revenue.mdx # src/locales/tr/whats-new.mdx # src/pages/[locale]/[...slug].astro
2 parents 3b31285 + cf51294 commit adca41b

219 files changed

Lines changed: 3275 additions & 2017 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/localize/SKILL.md

Lines changed: 390 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,390 @@
1+
---
2+
name: localize
3+
description: Use when adding support for a new locale/language to the Adapty docs site. Covers all hardcoded and dynamic locale registration points, translation commands, sitemap setup, Algolia search config, and the step-by-step order to follow.
4+
---
5+
6+
# Adding a New Locale to Adapty Docs
7+
8+
## Overview
9+
10+
Adding a locale touches ~8 files plus new content/sitemap files. Miss any one and the locale will partially break (no search, broken auto-redirect, missing from sitemap, etc.). Follow this checklist in order.
11+
12+
**Active locales:** `zh` (Chinese), `tr` (Turkish). All examples use `{LOCALE}` as placeholder — replace with the actual code (e.g. `ja`, `ko`, `de`).
13+
14+
---
15+
16+
## Step 1 — Register the locale in source code
17+
18+
Edit these 6 files before running any translation:
19+
20+
### 1a. `src/data/locales.ts`
21+
22+
Add the locale code to `SUPPORTED_LOCALES` and `LOCALE_NAMES`:
23+
24+
```ts
25+
export const SUPPORTED_LOCALES = ['zh', 'tr', '{LOCALE}'] as const;
26+
export const LOCALE_NAMES: Record<Locale, string> = {
27+
zh: '中文',
28+
tr: 'Türkçe',
29+
'{LOCALE}': '{NativeName}', // e.g. ja: '日本語'
30+
};
31+
```
32+
33+
### 1b. `scripts/translate.mjs`
34+
35+
Add to both `LANGUAGE_NAMES` and `METADATA_TITLE_SUFFIXES`:
36+
37+
```js
38+
const LANGUAGE_NAMES = {
39+
zh: 'Simplified Chinese (zh-CN)',
40+
tr: 'Turkish (tr-TR)',
41+
'{LOCALE}': '{Full language name}', // e.g. ja: 'Japanese (ja-JP)'
42+
};
43+
44+
const METADATA_TITLE_SUFFIXES = {
45+
zh: '| Adapty 文档',
46+
tr: '| Adapty Dokümanları',
47+
'{LOCALE}': '| Adapty {LocaleDocWord}', // e.g. ja: '| Adapty ドキュメント'
48+
};
49+
```
50+
51+
### 1c. `src/locales/ui-strings.ts`
52+
53+
Add translations for every key in every group. Groups: `feedback`, `header`, `search`, `articleButtons`, `toc`, `mobileSidebar`, `footer`. Pattern:
54+
55+
```ts
56+
question: { en: 'Was this page helpful?', zh: '...', tr: '...', '{LOCALE}': '...' },
57+
```
58+
59+
### 1d. `src/locales/dictionary.json`
60+
61+
Add a `"{LOCALE}"` key to every term entry alongside existing `zh`, `ja`, `tr` keys:
62+
63+
```json
64+
"A/B test": {
65+
"_note": "...",
66+
"zh": "A/B 测试",
67+
"ja": "A/B テスト",
68+
"tr": "A/B testi",
69+
"{LOCALE}": "..."
70+
}
71+
```
72+
73+
### 1e. `src/components/Search.astro`
74+
75+
Add to `LOCALE_INDEX` mapping (lines 17-20) and to the data attributes on the `<input>` (lines 47-50):
76+
77+
```ts
78+
const LOCALE_INDEX: Record<string, string | undefined> = {
79+
zh: import.meta.env.PUBLIC_ALGOLIA_INDEX_NAME_ZH,
80+
tr: import.meta.env.PUBLIC_ALGOLIA_INDEX_NAME_TR,
81+
'{LOCALE}': import.meta.env.PUBLIC_ALGOLIA_INDEX_NAME_{LOCALE_UPPER},
82+
};
83+
```
84+
85+
```html
86+
data-index-name-{LOCALE}={import.meta.env.PUBLIC_ALGOLIA_INDEX_NAME_{LOCALE_UPPER} ?? ''}
87+
```
88+
89+
### 1f. `src/components/Homepage.tsx`
90+
91+
The homepage component has its own hardcoded `T` constant (lines 4–80) with strings for `en`, `zh`, and `tr`**separate from `ui-strings.ts` and not touched by the translate script**. Add a new locale key with all ~20 strings:
92+
93+
```ts
94+
const T = {
95+
en: { hero: "...", discoverTitle: "...", ... },
96+
zh: { ... },
97+
tr: { ... },
98+
'{LOCALE}': {
99+
hero: "...",
100+
discoverTitle: "...",
101+
discoverDesc: "...",
102+
quickstartTitle: "...",
103+
quickstartDesc: "...",
104+
quickstartBtn: "...",
105+
nextTitle: "...",
106+
abTitle: "...",
107+
abDesc: "...",
108+
analyticsTitle: "...",
109+
analyticsDesc: "...",
110+
integrationsTitle: "...",
111+
integrationsDesc: "...",
112+
paywallTitle: "...",
113+
paywallDesc: "...",
114+
platformsTitle: "...",
115+
ios: "...",
116+
android: "...",
117+
reactNative: "...",
118+
flutter: "...",
119+
unity: "...",
120+
kmp: "...",
121+
capacitor: "...",
122+
},
123+
} as const;
124+
```
125+
126+
### 1g. `src/components/Header.astro`
127+
128+
The header is `transition:persist` and uses two client-side JS objects (in the inline `<script>`) that mirror other locale files but must be updated independently:
129+
130+
**`LOCALE_NAMES_CLIENT`** (around line 387) — mirrors `src/data/locales.ts`:
131+
```js
132+
const LOCALE_NAMES_CLIENT: Record<string, string> = { zh: '中文', tr: 'Türkçe', '{LOCALE}': '{NativeName}' };
133+
```
134+
135+
**`UI_STRINGS_CLIENT`** (around line 390) — a subset of `ui-strings.ts` for client-side reactivity. Add a new locale key:
136+
```js
137+
'{LOCALE}': {
138+
documentation: '...',
139+
mobileSdk: '...',
140+
serverApi: '...',
141+
whatsNew: '...',
142+
supportForum: '...',
143+
signIn: '...',
144+
signUpFree: '...',
145+
searchPlaceholder: '...',
146+
searchNoResults: '...',
147+
},
148+
```
149+
150+
### 1h. `src/layouts/DocsLayout.astro`
151+
152+
Add auto-redirect logic to the inline script (around lines 87-95):
153+
154+
```js
155+
} else if (lang.startsWith('{LOCALE}')) {
156+
localStorage.setItem('preferred-locale', '{LOCALE}');
157+
var newPath = window.location.pathname.replace(/^(\/docs\/)/, '$1{LOCALE}/');
158+
if (newPath !== window.location.pathname) window.location.replace(newPath);
159+
}
160+
```
161+
162+
---
163+
164+
## Step 2 — Add env vars
165+
166+
In `.env` (and in the deployment environment / Vercel env vars):
167+
168+
```
169+
PUBLIC_ALGOLIA_INDEX_NAME_{LOCALE_UPPER}=adapty_{LOCALE}
170+
```
171+
172+
e.g. for Japanese: `PUBLIC_ALGOLIA_INDEX_NAME_JA=adapty_ja`
173+
174+
---
175+
176+
## Step 3 — Create sitemap files
177+
178+
Copy `src/pages/sitemap-tr.xml.ts``src/pages/sitemap-{LOCALE}.xml.ts` and change `tr``{LOCALE}`.
179+
180+
Copy `src/pages/sitemap-tr-index.xml.ts``src/pages/sitemap-{LOCALE}-index.xml.ts` and change the URLs inside to use `sitemap-{LOCALE}.xml`.
181+
182+
### Update `astro.config.mjs` sitemap filter
183+
184+
In the `sitemap({ filter: ... })` call (around line 90), add the new locale to the exclusion:
185+
186+
```js
187+
filter: (page) => !page.includes('/docs/zh/') && !page.includes('/docs/tr/') && !page.includes('/docs/{LOCALE}/'),
188+
```
189+
190+
---
191+
192+
## Step 4 — Add the `package.json` scripts (optional convenience)
193+
194+
```json
195+
"translate:{LOCALE}": "node scripts/translate.mjs --lang {LOCALE}",
196+
"translate:{LOCALE}:build": "node scripts/translate.mjs --lang {LOCALE} --incremental",
197+
```
198+
199+
---
200+
201+
## Step 5 — Create the locale content directory
202+
203+
```
204+
mkdir -p src/locales/{LOCALE}
205+
```
206+
207+
The translation script creates `.mdx` files and `.hashes/` automatically. You only need to create the directory.
208+
209+
---
210+
211+
## Step 6 — Translate content (run in this order)
212+
213+
> **Note on `CustomDocCardList`:** This component is already locale-aware — it reads titles from `_sidebar-labels.json` and descriptions from the translated article frontmatter automatically. No extra step is needed; it works correctly once sidebar labels (Step 6c `--sidebars`) and article translations are done.
214+
215+
All commands require `ANTHROPIC_API_KEY` to be set.
216+
217+
### 6a. Translate the dictionary first
218+
219+
The dictionary (`src/locales/dictionary.json`) should already have translations added manually in Step 1d. Review it before running article translations — the script uses it as a glossary.
220+
221+
```
222+
# Check dictionary for any missing {LOCALE} entries, then continue.
223+
```
224+
225+
### 6b. Translate tutorial sidebar first 7 articles
226+
227+
These are the entry-point articles every user sees first. Translate them as a batch:
228+
229+
```bash
230+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --ids "what-is-adapty,is-adapty-right-for-me,integrate-payments,quickstart-products,quickstart-paywalls,quickstart-sdk,quickstart-test"
231+
```
232+
233+
### 6c. Translate sidebar labels and step-by-step docs per sidebar
234+
235+
Translate one sidebar at a time — each command is independent and can be run, reviewed, and committed separately.
236+
237+
**Step-by-step sidebar labels only (all sidebars at once):**
238+
```bash
239+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --sidebars
240+
```
241+
242+
**Or one sidebar's labels at a time:**
243+
```bash
244+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --sidebar tutorial
245+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --sidebar ios
246+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --sidebar android
247+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --sidebar react-native
248+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --sidebar flutter
249+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --sidebar unity
250+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --sidebar kmp
251+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --sidebar capacitor
252+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --sidebar api
253+
```
254+
255+
**Article docs, one platform/sidebar at a time:**
256+
```bash
257+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --platform tutorial
258+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --platform ios
259+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --platform android
260+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --platform react-native
261+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --platform flutter
262+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --platform unity
263+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --platform kmp
264+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --platform capacitor
265+
```
266+
267+
### 6d. Translate API docs
268+
269+
```bash
270+
ANTHROPIC_API_KEY=sk-... node scripts/translate.mjs --lang {LOCALE} --api-specs
271+
```
272+
273+
---
274+
275+
## Step 7 — Algolia: update English crawler + create new locale crawler
276+
277+
### 7a. Add locale to the English crawler exclusion pattern
278+
279+
In the Algolia dashboard, open the **English crawler config** and add `/{LOCALE}/` to the URL exclusion pattern so English-only content is not contaminated with locale paths. The existing exclusion already covers `zh` and `tr` — add `{LOCALE}` alongside them.
280+
281+
### 7b. Create a new crawler for the locale
282+
283+
In Algolia, create a new crawler pointing to:
284+
- **Start URL:** `https://adapty.io/docs/{LOCALE}/`
285+
- **Sitemap:** `https://adapty.io/docs/sitemap-{LOCALE}-index.xml`
286+
- Index name: `adapty_{LOCALE}`
287+
288+
Use the existing `zh` or `tr` crawler config as a template — the only changes are the start URL, sitemap URL, and index name.
289+
290+
### 7c. Create the Algolia index
291+
292+
Create a new index named `adapty_{LOCALE}` in Algolia. Copy replica/ranking settings from the `adapty_zh` index to ensure consistent relevance tuning.
293+
294+
---
295+
296+
## Step 8 — Update GitHub Actions deploy workflows
297+
298+
The `translate.yml` workflow is locale-agnostic (uses `src/locales/*/` glob) — no changes needed there.
299+
300+
Both deploy workflows have `[zh, tr]` hardcoded and **must be updated** in multiple places each.
301+
302+
### `s3-deploy-production.yml`
303+
304+
**1. `build-locale-full` matrix** (line ~99):
305+
```yaml
306+
strategy:
307+
matrix:
308+
locale: [zh, tr, {LOCALE}]
309+
```
310+
311+
**2. `deploy-full` artifact downloads** (lines ~150–156) — add a new step alongside the existing `build-zh` and `build-tr` blocks:
312+
```yaml
313+
- uses: actions/download-artifact@v4
314+
with:
315+
name: build-{LOCALE}
316+
path: build/{LOCALE}/
317+
```
318+
319+
**3. `build-locale-only` matrix** (line ~183):
320+
```yaml
321+
strategy:
322+
matrix:
323+
locale: [zh, tr, {LOCALE}]
324+
```
325+
326+
**4. `deploy-translations` artifact downloads** (lines ~229–235) — add a new step alongside the existing `build-tr-only-zh` and `build-tr-only-tr` blocks:
327+
```yaml
328+
- uses: actions/download-artifact@v4
329+
with:
330+
name: build-tr-only-{LOCALE}
331+
path: build/{LOCALE}/
332+
```
333+
334+
**5. `deploy-translations` S3 sync** (lines ~241–242):
335+
```bash
336+
aws s3 sync build/{LOCALE}/ s3://${{ secrets.S3_BUCKET }}/{LOCALE}/ --delete
337+
```
338+
339+
**6. `deploy-translations` CloudFront invalidation** (lines ~246–248):
340+
```bash
341+
aws cloudfront create-invalidation \
342+
--distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
343+
--paths "/zh/*" "/tr/*" "/{LOCALE}/*"
344+
```
345+
346+
### `s3-deploy-development.yml`
347+
348+
**1. `build-locale` matrix** (line ~47):
349+
```yaml
350+
strategy:
351+
matrix:
352+
locale: [zh, tr, {LOCALE}]
353+
```
354+
355+
**2. `deploy` artifact downloads** (lines ~96–104) — add a new step:
356+
```yaml
357+
- uses: actions/download-artifact@v4
358+
with:
359+
name: build-{LOCALE}
360+
path: build/{LOCALE}/
361+
```
362+
363+
---
364+
365+
## Complete checklist
366+
367+
| # | What | File(s) |
368+
|---|------|---------|
369+
| 1a | Add to `SUPPORTED_LOCALES` + `LOCALE_NAMES` | `src/data/locales.ts` |
370+
| 1b | Add to `LANGUAGE_NAMES` + `METADATA_TITLE_SUFFIXES` | `scripts/translate.mjs` |
371+
| 1c | Add UI string translations for all groups | `src/locales/ui-strings.ts` |
372+
| 1d | Add dictionary translations | `src/locales/dictionary.json` |
373+
| 1e | Add to `LOCALE_INDEX` + `data-index-name-{LOCALE}` attr | `src/components/Search.astro` |
374+
| 1f | Add locale key to `T` object (~20 strings) | `src/components/Homepage.tsx` |
375+
| 1g | Add to `LOCALE_NAMES_CLIENT` + `UI_STRINGS_CLIENT` | `src/components/Header.astro` |
376+
| 1h | Add auto-redirect block | `src/layouts/DocsLayout.astro` |
377+
| 2 | Add env vars | `.env` + deployment config |
378+
| 3 | Create sitemap files + update astro.config.mjs | `src/pages/sitemap-{LOCALE}*.xml.ts`, `astro.config.mjs` |
379+
| 4 | Add npm scripts (optional) | `package.json` |
380+
| 5 | Create content directory | `src/locales/{LOCALE}/` |
381+
| 6a | Review/complete dictionary | `src/locales/dictionary.json` |
382+
| 6b | Translate first 7 tutorial articles | `--ids` command |
383+
| 6c | Translate sidebar labels + platform docs | `--sidebars` + `--platform` commands |
384+
| 6d | Translate API specs | `--api-specs` command |
385+
| 7a | Update English crawler exclusion | Algolia dashboard |
386+
| 7b | Create new locale crawler | Algolia dashboard |
387+
| 7c | Create new Algolia index | Algolia dashboard |
388+
| 8a | Add to `matrix: locale: [...]` (×2 jobs) | `s3-deploy-production.yml` |
389+
| 8b | Add artifact download + S3 sync + CloudFront invalidation | `s3-deploy-production.yml` |
390+
| 8c | Add to `matrix: locale: [...]` + artifact download | `s3-deploy-development.yml` |

0 commit comments

Comments
 (0)