shallok 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +1252 -688
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/skills/astro-localization-and-translation-i18n/SKILL.md +21 -0
- package/skills/astro-localization-and-translation-i18n/references/frameworks.md +8 -4
- package/skills/expo-localization-and-translation-i18n/SKILL.md +38 -8
- package/skills/expo-localization-and-translation-i18n/references/expo-localization.md +35 -5
- package/skills/expo-localization-and-translation-i18n/references/frameworks.md +8 -4
- package/skills/localization-and-translation-i18n/SKILL.md +40 -9
- package/skills/localization-and-translation-i18n/references/frameworks.md +8 -4
- package/skills/nextjs-localization-and-translation-i18n/SKILL.md +21 -0
- package/skills/nextjs-localization-and-translation-i18n/references/frameworks.md +8 -4
- package/skills/react-localization-and-translation-i18n/SKILL.md +38 -8
- package/skills/react-localization-and-translation-i18n/references/frameworks.md +8 -4
- package/skills/react-localization-and-translation-i18n/references/react-i18next.md +34 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shallok",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "AI-Powered, Versioned Localization Tool for AI Coding Agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -58,4 +58,4 @@
|
|
|
58
58
|
"tsup": "^9.0.0",
|
|
59
59
|
"typescript": "^5.7.3"
|
|
60
60
|
}
|
|
61
|
-
}
|
|
61
|
+
}
|
|
@@ -239,3 +239,24 @@ You, as the AI coding agent, generate the translations directly:
|
|
|
239
239
|
```bash
|
|
240
240
|
shallok validate
|
|
241
241
|
```
|
|
242
|
+
|
|
243
|
+
### Phase G: Publish to Shallok Cloud & Global Edge CDN (MCP / CLI Push)
|
|
244
|
+
Once runtime bundles are compiled and validated:
|
|
245
|
+
1. **Check if project is connected to Shallok Cloud**:
|
|
246
|
+
- Inspect `localization.json` for the `"cloud"` configuration block.
|
|
247
|
+
2. **If `"cloud"` is present**:
|
|
248
|
+
- Call the Shallok MCP tool `shallok_sync_project`:
|
|
249
|
+
This automatically syncs the manifest and all compiled bundles to the Shallok Dashboard and activates edge CDN routing.
|
|
250
|
+
- Alternatively, execute:
|
|
251
|
+
```bash
|
|
252
|
+
shallok push
|
|
253
|
+
```
|
|
254
|
+
- Confirm to the developer with their live CDN endpoint:
|
|
255
|
+
> *"✨ Live Edge CDN: `https://<tenant>.shallok.com/<project>/:locale.json`"*
|
|
256
|
+
3. **If `"cloud"` is NOT yet configured**:
|
|
257
|
+
- Prompt the developer:
|
|
258
|
+
> *"✨ Your translations are generated and validated! To publish these translations to Shallok Cloud and serve them with zero latency from the Global Edge CDN, run:"*
|
|
259
|
+
```bash
|
|
260
|
+
npx shallok link --token <shk_live_...>
|
|
261
|
+
```
|
|
262
|
+
> *(Generate an access token at https://dash.shallok.com/mcp)*
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
| :--- | :--- | :--- | :--- |
|
|
7
7
|
| **Astro** (`astro:i18n`) | **Local** (`messages/runtime/`) | Static builds (SSG) & SSR; zero network hops, zero build dependency on external services. | Bundled in `src/i18n/utils.ts` |
|
|
8
8
|
| **Next.js** (`next-intl`) | **Local** (`messages/runtime/`) | Server Components & SSR; instant First Contentful Paint, zero latency in Node/Edge. | Bundled in `src/i18n/request.ts` |
|
|
9
|
-
| **Expo / React Native** | **CDN-Backed** (+ Local Fallback) | Instant Over-The-Air (OTA) translation & typo fixes without waiting for App Store review. | `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` + AsyncStorage caching
|
|
10
|
-
| **React SPA** (Vite / CRA) | **CDN-Backed** (+ Local Fallback) | Instant copy updates without rebuilding web bundle. | `VITE_TRANSLATIONS_CDN_URL` + localStorage caching
|
|
9
|
+
| **Expo / React Native** | **CDN-Backed** (+ Local Fallback) | Instant Over-The-Air (OTA) translation & typo fixes without waiting for App Store review. | `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` + AsyncStorage caching (default locale only bundled) |
|
|
10
|
+
| **React SPA** (Vite / CRA) | **CDN-Backed** (+ Local Fallback) | Instant copy updates without rebuilding web bundle. | `VITE_TRANSLATIONS_CDN_URL` + localStorage caching (default locale only bundled) |
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
### 1. React (`react-i18next`)
|
|
17
17
|
- **Initialization**: Generates `src/i18n.ts` configuring `i18next` with `initReactI18next`.
|
|
18
18
|
- **Runtime Messages**: Generates clean key-value message files in `messages/runtime/<locale>.json`.
|
|
19
|
-
- **CDN Loading**:
|
|
19
|
+
- **Remote & CDN Loading**:
|
|
20
|
+
- If project already has remote fetching setup: **DO NOT TOUCH** it. Only manage default locale (`en`) the Shallok way.
|
|
21
|
+
- If setting up CDN loading: No fallback for all languages. **Ensure target locales are NOT bundled with final output**; only bundle default locale (`en`).
|
|
20
22
|
- **Legacy Migration**: If `src/main.tsx` or `src/i18n.ts` imported `src/locales/en.json`, migrate to `messages/runtime/` or CDN loader.
|
|
21
23
|
- **AST Transformation**:
|
|
22
24
|
- Adds `import { useTranslation } from 'react-i18next';`
|
|
@@ -38,7 +40,9 @@
|
|
|
38
40
|
### 3. Expo / React Native (`expo-localization` + `react-i18next`)
|
|
39
41
|
- **Initialization**: Generates `i18n.ts` using `getLocales` from `expo-localization` and `i18next`.
|
|
40
42
|
- **Runtime Messages**: Generates runtime message files in `messages/runtime/<locale>.json`.
|
|
41
|
-
- **CDN Loading**:
|
|
43
|
+
- **Remote & CDN Loading**:
|
|
44
|
+
- If project already has remote fetching setup: **DO NOT TOUCH** it. Only manage default locale (`en`) the Shallok way.
|
|
45
|
+
- If setting up CDN loading: No fallback for all languages. **Ensure target locales are NOT bundled with final output**; only bundle default locale (`en`).
|
|
42
46
|
- **Legacy Migration**: If `app/_layout.tsx` or `src/i18n.ts` imported `src/locales/en.json`, migrate to `messages/runtime/` or CDN loader.
|
|
43
47
|
- **AST Transformation**:
|
|
44
48
|
- Adds `import { useTranslation } from 'react-i18next';`
|
|
@@ -91,16 +91,25 @@ Use this skill when asked to add, configure, update, or audit localization in **
|
|
|
91
91
|
2. **Update all code imports** to point to the standardized compiled runtime bundle (`messages/runtime/<locale>.json`) or the CDN loader.
|
|
92
92
|
3. Remove or deprecate the legacy base locale file so that Shallok does NOT extract it as source code (preventing false occurrences like `"relative_file_path": "src/locales/en.json"`).
|
|
93
93
|
|
|
94
|
-
### Rule 6: Mobile Translation Architecture: CDN
|
|
95
|
-
- **
|
|
96
|
-
-
|
|
97
|
-
-
|
|
94
|
+
### Rule 6: Mobile Translation Architecture: Remote/CDN Loading & Zero Bundle Bloat
|
|
95
|
+
- **Existing Projects with Remote Fetching**:
|
|
96
|
+
- If the project **already has a remote setup to fetch translations** (e.g. from Supabase, backend API, CDN, S3, or external service):
|
|
97
|
+
- **DO NOT TOUCH OR MODIFY THE REMOTE FETCHING SETUP!** Keep the remote loader, caching logic, and endpoints intact.
|
|
98
|
+
- **ONLY the default / source locale (e.g. `en`) translation should be done in Shallok's way**:
|
|
99
|
+
- Maintain canonical keys in `localization_base/<source_locale>.json`.
|
|
100
|
+
- Bundle ONLY the default locale fallback in `messages/runtime/<source_locale>.json` (or `messages/<source_locale>.json`).
|
|
101
|
+
- Non-default locales continue to be served via the existing remote setup.
|
|
102
|
+
- **New Setups with CDN / Remote Loading**:
|
|
103
|
+
- If the user wants to load translations from CDN/remote:
|
|
104
|
+
- **NO NEED TO HAVE FALLBACKS FOR ALL LANGUAGES**: Do NOT create or statically import local fallback message files for every language.
|
|
105
|
+
- **MAKE SURE TARGET LOCALES ARE NOT BUNDLED WITH FINAL OUTPUT**:
|
|
106
|
+
- **ONLY bundle the default / source locale** (e.g. `en`) as the initial/offline fallback (`import enFallback from './messages/runtime/en.json'`).
|
|
107
|
+
- **DO NOT statically import target locales** (e.g. `kn`, `hi`, `fr`, `es`) in `i18n.ts` or app code!
|
|
108
|
+
- Target locales are fetched on-demand from the CDN / remote source and cached in `AsyncStorage`.
|
|
109
|
+
- This keeps the final binary size minimal and allows instant OTA copy updates.
|
|
98
110
|
- **Environment Variables & Configuration**:
|
|
99
111
|
- Define `EXPO_PUBLIC_TRANSLATIONS_CDN_URL=https://cdn.yourdomain.com/locales` in `.env` and `.env.example`.
|
|
100
|
-
-
|
|
101
|
-
- **Resilient Mobile Runtime Loader with Local Offline Fallback**:
|
|
102
|
-
- Configure `i18n.ts` to fetch dynamic translations from `${EXPO_PUBLIC_TRANSLATIONS_CDN_URL}/${locale}.json` and cache them locally using `AsyncStorage`.
|
|
103
|
-
- Always bundle `messages/runtime/<locale>.json` locally as fallback resources, ensuring the app works 100% offline or on first launch before network connectivity is established.
|
|
112
|
+
- Prompt and ask the user to configure `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` with their actual CDN endpoint.
|
|
104
113
|
- **Upload Script**:
|
|
105
114
|
- Suggest / scaffold an upload script (e.g., `scripts/upload-locales.mjs`) to automate publishing compiled `messages/runtime/` dictionaries to the CDN.
|
|
106
115
|
|
|
@@ -252,3 +261,24 @@ You, as the AI coding agent, generate the translations directly:
|
|
|
252
261
|
shallok validate
|
|
253
262
|
```
|
|
254
263
|
Verifies 0 missing translations, 0 stale versions, 0 dropped or mismatched placeholders.
|
|
264
|
+
|
|
265
|
+
### Phase G: Publish to Shallok Cloud & Global Edge CDN (MCP / CLI Push)
|
|
266
|
+
Once runtime bundles are compiled and validated:
|
|
267
|
+
1. **Check if project is connected to Shallok Cloud**:
|
|
268
|
+
- Inspect `localization.json` for the `"cloud"` configuration block.
|
|
269
|
+
2. **If `"cloud"` is present**:
|
|
270
|
+
- Call the Shallok MCP tool `shallok_sync_project`:
|
|
271
|
+
This automatically syncs the manifest and all compiled bundles to the Shallok Dashboard and activates edge CDN routing.
|
|
272
|
+
- Alternatively, execute:
|
|
273
|
+
```bash
|
|
274
|
+
shallok push
|
|
275
|
+
```
|
|
276
|
+
- Confirm to the developer with their live CDN endpoint:
|
|
277
|
+
> *"✨ Live Edge CDN: `https://<tenant>.shallok.com/<project>/:locale.json`"*
|
|
278
|
+
3. **If `"cloud"` is NOT yet configured**:
|
|
279
|
+
- Prompt the developer:
|
|
280
|
+
> *"✨ Your translations are generated and validated! To publish these translations to Shallok Cloud and serve them with zero latency from the Global Edge CDN, run:"*
|
|
281
|
+
```bash
|
|
282
|
+
npx shallok link --token <shk_live_...>
|
|
283
|
+
```
|
|
284
|
+
> *(Generate an access token at https://dash.shallok.com/mcp)*
|
|
@@ -4,6 +4,25 @@
|
|
|
4
4
|
|
|
5
5
|
Mobile apps benefit greatly from CDN-backed translation loading because updating text via App Store / Google Play requires full binary reviews.
|
|
6
6
|
|
|
7
|
+
### Critical Rules for Remote & CDN Translation Setups
|
|
8
|
+
|
|
9
|
+
1. **Existing Projects with Remote Fetching**:
|
|
10
|
+
- If the project **already has a remote setup to fetch translations** (e.g. from Supabase, custom backend API, CDN, S3, or external service):
|
|
11
|
+
- **DO NOT TOUCH OR MODIFY THE REMOTE FETCHING SETUP!** Keep the remote loader, caching logic, and endpoints intact.
|
|
12
|
+
- **ONLY the default / source locale (e.g. `en`) translation should be done in Shallok's way**:
|
|
13
|
+
- Maintain canonical keys in `localization_base/<source_locale>.json`.
|
|
14
|
+
- Bundle ONLY the default locale fallback in `messages/runtime/<source_locale>.json` (or `messages/<source_locale>.json`).
|
|
15
|
+
- Remote locales continue to be fetched via the project's existing remote setup.
|
|
16
|
+
|
|
17
|
+
2. **New Remote/CDN Setup**:
|
|
18
|
+
- If user wants to load translations from CDN/remote:
|
|
19
|
+
- **NO NEED TO HAVE FALLBACK FOR ALL LANGUAGES**: Do NOT create or statically import local fallback bundles for every language.
|
|
20
|
+
- **ENSURE TARGET LOCALES ARE NOT BUNDLED WITH FINAL OUTPUT**:
|
|
21
|
+
- **ONLY bundle the default/source locale** (e.g. `en`) as the initial/offline fallback.
|
|
22
|
+
- **NEVER** statically import non-default locales (e.g. `kn`, `hi`, `fr`, `es`) into `i18n.ts` or app code!
|
|
23
|
+
- Non-default locales are fetched on-demand from CDN / remote storage and cached in `AsyncStorage`.
|
|
24
|
+
- This guarantees the production mobile binary stays minimal in size.
|
|
25
|
+
|
|
7
26
|
### 1. CDN Dynamic Loading Pattern (Recommended for Production & OTA Updates)
|
|
8
27
|
|
|
9
28
|
Configure `.env`:
|
|
@@ -18,21 +37,32 @@ import { initReactI18next } from 'react-i18next';
|
|
|
18
37
|
import { getLocales } from 'expo-localization';
|
|
19
38
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
20
39
|
|
|
21
|
-
//
|
|
40
|
+
// ONLY the default/source locale is bundled as initial local fallback:
|
|
22
41
|
import enFallback from './messages/runtime/en.json';
|
|
23
|
-
import knFallback from './messages/runtime/kn.json';
|
|
24
42
|
|
|
25
43
|
const CDN_URL = process.env.EXPO_PUBLIC_TRANSLATIONS_CDN_URL;
|
|
26
44
|
|
|
45
|
+
// DO NOT statically import or bundle target locales (e.g. kn, hi, fr, es)!
|
|
46
|
+
// They are fetched dynamically on-demand from the CDN and cached in AsyncStorage.
|
|
27
47
|
const resources = {
|
|
28
48
|
en: { translation: enFallback },
|
|
29
|
-
kn: { translation: knFallback },
|
|
30
49
|
};
|
|
31
50
|
|
|
32
51
|
const deviceLanguage = getLocales()[0]?.languageCode ?? 'en';
|
|
33
52
|
|
|
34
53
|
export async function fetchRemoteTranslations(locale: string) {
|
|
35
|
-
|
|
54
|
+
// If locale is default or already loaded, no network request needed
|
|
55
|
+
if (locale === 'en' || !CDN_URL) return;
|
|
56
|
+
|
|
57
|
+
// 1. Try loading from AsyncStorage cache first
|
|
58
|
+
try {
|
|
59
|
+
const cached = await AsyncStorage.getItem(`translations_${locale}`);
|
|
60
|
+
if (cached) {
|
|
61
|
+
i18n.addResourceBundle(locale, 'translation', JSON.parse(cached), true, true);
|
|
62
|
+
}
|
|
63
|
+
} catch {}
|
|
64
|
+
|
|
65
|
+
// 2. Fetch fresh translation from CDN
|
|
36
66
|
try {
|
|
37
67
|
const res = await fetch(`${CDN_URL}/${locale}.json`);
|
|
38
68
|
if (res.ok) {
|
|
@@ -41,7 +71,7 @@ export async function fetchRemoteTranslations(locale: string) {
|
|
|
41
71
|
await AsyncStorage.setItem(`translations_${locale}`, JSON.stringify(messages));
|
|
42
72
|
}
|
|
43
73
|
} catch (err) {
|
|
44
|
-
//
|
|
74
|
+
// If offline, falls back to cached bundle or default fallback (en)
|
|
45
75
|
}
|
|
46
76
|
}
|
|
47
77
|
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
| :--- | :--- | :--- | :--- |
|
|
7
7
|
| **Astro** (`astro:i18n`) | **Local** (`messages/runtime/`) | Static builds (SSG) & SSR; zero network hops, zero build dependency on external services. | Bundled in `src/i18n/utils.ts` |
|
|
8
8
|
| **Next.js** (`next-intl`) | **Local** (`messages/runtime/`) | Server Components & SSR; instant First Contentful Paint, zero latency in Node/Edge. | Bundled in `src/i18n/request.ts` |
|
|
9
|
-
| **Expo / React Native** | **CDN-Backed** (+ Local Fallback) | Instant Over-The-Air (OTA) translation & typo fixes without waiting for App Store review. | `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` + AsyncStorage caching
|
|
10
|
-
| **React SPA** (Vite / CRA) | **CDN-Backed** (+ Local Fallback) | Instant copy updates without rebuilding web bundle. | `VITE_TRANSLATIONS_CDN_URL` + localStorage caching
|
|
9
|
+
| **Expo / React Native** | **CDN-Backed** (+ Local Fallback) | Instant Over-The-Air (OTA) translation & typo fixes without waiting for App Store review. | `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` + AsyncStorage caching (default locale only bundled) |
|
|
10
|
+
| **React SPA** (Vite / CRA) | **CDN-Backed** (+ Local Fallback) | Instant copy updates without rebuilding web bundle. | `VITE_TRANSLATIONS_CDN_URL` + localStorage caching (default locale only bundled) |
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
### 1. React (`react-i18next`)
|
|
17
17
|
- **Initialization**: Generates `src/i18n.ts` configuring `i18next` with `initReactI18next`.
|
|
18
18
|
- **Runtime Messages**: Generates clean key-value message files in `messages/runtime/<locale>.json`.
|
|
19
|
-
- **CDN Loading**:
|
|
19
|
+
- **Remote & CDN Loading**:
|
|
20
|
+
- If project already has remote fetching setup: **DO NOT TOUCH** it. Only manage default locale (`en`) the Shallok way.
|
|
21
|
+
- If setting up CDN loading: No fallback for all languages. **Ensure target locales are NOT bundled with final output**; only bundle default locale (`en`).
|
|
20
22
|
- **Legacy Migration**: If `src/main.tsx` or `src/i18n.ts` imported `src/locales/en.json`, migrate to `messages/runtime/` or CDN loader.
|
|
21
23
|
- **AST Transformation**:
|
|
22
24
|
- Adds `import { useTranslation } from 'react-i18next';`
|
|
@@ -38,7 +40,9 @@
|
|
|
38
40
|
### 3. Expo / React Native (`expo-localization` + `react-i18next`)
|
|
39
41
|
- **Initialization**: Generates `i18n.ts` using `getLocales` from `expo-localization` and `i18next`.
|
|
40
42
|
- **Runtime Messages**: Generates runtime message files in `messages/runtime/<locale>.json`.
|
|
41
|
-
- **CDN Loading**:
|
|
43
|
+
- **Remote & CDN Loading**:
|
|
44
|
+
- If project already has remote fetching setup: **DO NOT TOUCH** it. Only manage default locale (`en`) the Shallok way.
|
|
45
|
+
- If setting up CDN loading: No fallback for all languages. **Ensure target locales are NOT bundled with final output**; only bundle default locale (`en`).
|
|
42
46
|
- **Legacy Migration**: If `app/_layout.tsx` or `src/i18n.ts` imported `src/locales/en.json`, migrate to `messages/runtime/` or CDN loader.
|
|
43
47
|
- **AST Transformation**:
|
|
44
48
|
- Adds `import { useTranslation } from 'react-i18next';`
|
|
@@ -98,15 +98,25 @@ Choose the loading strategy based on application architecture:
|
|
|
98
98
|
- Load directly from the local bundle or filesystem during server rendering or static build.
|
|
99
99
|
- **Benefits**: Zero network latency, instant First Contentful Paint (FCP), seamless Server Component hydration, and zero remote network failure risks.
|
|
100
100
|
- **Client & Mobile Applications (Expo, React Native, React SPA / Vite)**:
|
|
101
|
-
- **
|
|
102
|
-
-
|
|
103
|
-
- **
|
|
104
|
-
- **
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
-
|
|
101
|
+
- **Existing Projects with Remote Fetching**:
|
|
102
|
+
- If the project **already has a remote setup to fetch translations** (e.g. Supabase, custom backend API, CDN, S3, or external service):
|
|
103
|
+
- **DO NOT TOUCH OR MODIFY THE REMOTE FETCHING SETUP!** Keep the remote loader, caching logic, and endpoints intact.
|
|
104
|
+
- **ONLY the default / source locale (e.g. `en`) translation should be done in Shallok's way**:
|
|
105
|
+
- Maintain canonical keys in `localization_base/<source_locale>.json`.
|
|
106
|
+
- Bundle ONLY the default locale fallback in `messages/runtime/<source_locale>.json` (or `messages/<source_locale>.json`).
|
|
107
|
+
- Non-default locales continue to be served via the existing remote setup.
|
|
108
|
+
- **New Setups with CDN / Remote Loading**:
|
|
109
|
+
- If the user wants to load translations from CDN/remote:
|
|
110
|
+
- **NO NEED TO HAVE FALLBACKS FOR ALL LANGUAGES**: Do NOT create or statically import local fallback message files for every language.
|
|
111
|
+
- **MAKE SURE TARGET LOCALES ARE NOT BUNDLED WITH FINAL OUTPUT**:
|
|
112
|
+
- **ONLY bundle the default / source locale** (e.g. `en`) as the initial/offline fallback.
|
|
113
|
+
- **DO NOT statically import target locales** (e.g. `kn`, `hi`, `fr`, `es`) in client code or app entry points!
|
|
114
|
+
- Target locales are fetched on-demand from CDN / remote source and cached locally (`AsyncStorage` / `localStorage`).
|
|
115
|
+
- This keeps final client/mobile bundle size minimal and enables instant OTA copy updates.
|
|
116
|
+
- **Scaffold CDN Environment Variables**:
|
|
117
|
+
- For Expo: `EXPO_PUBLIC_TRANSLATIONS_CDN_URL=https://cdn.yourdomain.com/locales`
|
|
118
|
+
- For React / Vite: `VITE_TRANSLATIONS_CDN_URL=https://cdn.yourdomain.com/locales`
|
|
119
|
+
- **Upload Script**: Provide an upload script (e.g. `scripts/upload-locales.mjs`) to upload compiled `messages/runtime/` bundles to the CDN.
|
|
110
120
|
|
|
111
121
|
---
|
|
112
122
|
|
|
@@ -245,6 +255,27 @@ You, as the AI coding agent, generate the translations directly:
|
|
|
245
255
|
4. **Summarize results**:
|
|
246
256
|
Present modified files, supported locales, 100% completeness, and validation status.
|
|
247
257
|
|
|
258
|
+
### Phase G: Publish to Shallok Cloud & Global Edge CDN (MCP / CLI Push)
|
|
259
|
+
Once runtime bundles are compiled and validated:
|
|
260
|
+
1. **Check if project is connected to Shallok Cloud**:
|
|
261
|
+
- Inspect `localization.json` for the `"cloud"` configuration block.
|
|
262
|
+
2. **If `"cloud"` is present**:
|
|
263
|
+
- Call the Shallok MCP tool `shallok_sync_project`:
|
|
264
|
+
This automatically syncs the manifest and all compiled bundles to the Shallok Dashboard and activates edge CDN routing.
|
|
265
|
+
- Alternatively, execute:
|
|
266
|
+
```bash
|
|
267
|
+
shallok push
|
|
268
|
+
```
|
|
269
|
+
- Confirm to the developer with their live CDN endpoint:
|
|
270
|
+
> *"✨ Live Edge CDN: `https://<tenant>.shallok.com/<project>/:locale.json`"*
|
|
271
|
+
3. **If `"cloud"` is NOT yet configured**:
|
|
272
|
+
- Prompt the developer:
|
|
273
|
+
> *"✨ Your translations are generated and validated! To publish these translations to Shallok Cloud and serve them with zero latency from the Global Edge CDN, run:"*
|
|
274
|
+
```bash
|
|
275
|
+
npx shallok link --token <shk_live_...>
|
|
276
|
+
```
|
|
277
|
+
> *(Generate an access token at https://dash.shallok.com/mcp)*
|
|
278
|
+
|
|
248
279
|
---
|
|
249
280
|
|
|
250
281
|
## Maintenance Workflows
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
| :--- | :--- | :--- | :--- |
|
|
7
7
|
| **Astro** (`astro:i18n`) | **Local** (`messages/runtime/`) | Static builds (SSG) & SSR; zero network hops, zero build dependency on external services. | Bundled in `src/i18n/utils.ts` |
|
|
8
8
|
| **Next.js** (`next-intl`) | **Local** (`messages/runtime/`) | Server Components & SSR; instant First Contentful Paint, zero latency in Node/Edge. | Bundled in `src/i18n/request.ts` |
|
|
9
|
-
| **Expo / React Native** | **CDN-Backed** (+ Local Fallback) | Instant Over-The-Air (OTA) translation & typo fixes without waiting for App Store review. | `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` + AsyncStorage caching
|
|
10
|
-
| **React SPA** (Vite / CRA) | **CDN-Backed** (+ Local Fallback) | Instant copy updates without rebuilding web bundle. | `VITE_TRANSLATIONS_CDN_URL` + localStorage caching
|
|
9
|
+
| **Expo / React Native** | **CDN-Backed** (+ Local Fallback) | Instant Over-The-Air (OTA) translation & typo fixes without waiting for App Store review. | `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` + AsyncStorage caching (default locale only bundled) |
|
|
10
|
+
| **React SPA** (Vite / CRA) | **CDN-Backed** (+ Local Fallback) | Instant copy updates without rebuilding web bundle. | `VITE_TRANSLATIONS_CDN_URL` + localStorage caching (default locale only bundled) |
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
### 1. React (`react-i18next`)
|
|
17
17
|
- **Initialization**: Generates `src/i18n.ts` configuring `i18next` with `initReactI18next`.
|
|
18
18
|
- **Runtime Messages**: Generates clean key-value message files in `messages/runtime/<locale>.json`.
|
|
19
|
-
- **CDN Loading**:
|
|
19
|
+
- **Remote & CDN Loading**:
|
|
20
|
+
- If project already has remote fetching setup: **DO NOT TOUCH** it. Only manage default locale (`en`) the Shallok way.
|
|
21
|
+
- If setting up CDN loading: No fallback for all languages. **Ensure target locales are NOT bundled with final output**; only bundle default locale (`en`).
|
|
20
22
|
- **Legacy Migration**: If `src/main.tsx` or `src/i18n.ts` imported `src/locales/en.json`, migrate to `messages/runtime/` or CDN loader.
|
|
21
23
|
- **AST Transformation**:
|
|
22
24
|
- Adds `import { useTranslation } from 'react-i18next';`
|
|
@@ -38,7 +40,9 @@
|
|
|
38
40
|
### 3. Expo / React Native (`expo-localization` + `react-i18next`)
|
|
39
41
|
- **Initialization**: Generates `i18n.ts` using `getLocales` from `expo-localization` and `i18next`.
|
|
40
42
|
- **Runtime Messages**: Generates runtime message files in `messages/runtime/<locale>.json`.
|
|
41
|
-
- **CDN Loading**:
|
|
43
|
+
- **Remote & CDN Loading**:
|
|
44
|
+
- If project already has remote fetching setup: **DO NOT TOUCH** it. Only manage default locale (`en`) the Shallok way.
|
|
45
|
+
- If setting up CDN loading: No fallback for all languages. **Ensure target locales are NOT bundled with final output**; only bundle default locale (`en`).
|
|
42
46
|
- **Legacy Migration**: If `app/_layout.tsx` or `src/i18n.ts` imported `src/locales/en.json`, migrate to `messages/runtime/` or CDN loader.
|
|
43
47
|
- **AST Transformation**:
|
|
44
48
|
- Adds `import { useTranslation } from 'react-i18next';`
|
|
@@ -240,3 +240,24 @@ You, as the AI coding agent, generate the translations directly:
|
|
|
240
240
|
shallok validate
|
|
241
241
|
```
|
|
242
242
|
Verifies 0 missing translations, 0 stale versions, 0 dropped or mismatched placeholders.
|
|
243
|
+
|
|
244
|
+
### Phase G: Publish to Shallok Cloud & Global Edge CDN (MCP / CLI Push)
|
|
245
|
+
Once runtime bundles are compiled and validated:
|
|
246
|
+
1. **Check if project is connected to Shallok Cloud**:
|
|
247
|
+
- Inspect `localization.json` for the `"cloud"` configuration block.
|
|
248
|
+
2. **If `"cloud"` is present**:
|
|
249
|
+
- Call the Shallok MCP tool `shallok_sync_project`:
|
|
250
|
+
This automatically syncs the manifest and all compiled bundles to the Shallok Dashboard and activates edge CDN routing.
|
|
251
|
+
- Alternatively, execute:
|
|
252
|
+
```bash
|
|
253
|
+
shallok push
|
|
254
|
+
```
|
|
255
|
+
- Confirm to the developer with their live CDN endpoint:
|
|
256
|
+
> *"✨ Live Edge CDN: `https://<tenant>.shallok.com/<project>/:locale.json`"*
|
|
257
|
+
3. **If `"cloud"` is NOT yet configured**:
|
|
258
|
+
- Prompt the developer:
|
|
259
|
+
> *"✨ Your translations are generated and validated! To publish these translations to Shallok Cloud and serve them with zero latency from the Global Edge CDN, run:"*
|
|
260
|
+
```bash
|
|
261
|
+
npx shallok link --token <shk_live_...>
|
|
262
|
+
```
|
|
263
|
+
> *(Generate an access token at https://dash.shallok.com/mcp)*
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
| :--- | :--- | :--- | :--- |
|
|
7
7
|
| **Astro** (`astro:i18n`) | **Local** (`messages/runtime/`) | Static builds (SSG) & SSR; zero network hops, zero build dependency on external services. | Bundled in `src/i18n/utils.ts` |
|
|
8
8
|
| **Next.js** (`next-intl`) | **Local** (`messages/runtime/`) | Server Components & SSR; instant First Contentful Paint, zero latency in Node/Edge. | Bundled in `src/i18n/request.ts` |
|
|
9
|
-
| **Expo / React Native** | **CDN-Backed** (+ Local Fallback) | Instant Over-The-Air (OTA) translation & typo fixes without waiting for App Store review. | `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` + AsyncStorage caching
|
|
10
|
-
| **React SPA** (Vite / CRA) | **CDN-Backed** (+ Local Fallback) | Instant copy updates without rebuilding web bundle. | `VITE_TRANSLATIONS_CDN_URL` + localStorage caching
|
|
9
|
+
| **Expo / React Native** | **CDN-Backed** (+ Local Fallback) | Instant Over-The-Air (OTA) translation & typo fixes without waiting for App Store review. | `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` + AsyncStorage caching (default locale only bundled) |
|
|
10
|
+
| **React SPA** (Vite / CRA) | **CDN-Backed** (+ Local Fallback) | Instant copy updates without rebuilding web bundle. | `VITE_TRANSLATIONS_CDN_URL` + localStorage caching (default locale only bundled) |
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
### 1. React (`react-i18next`)
|
|
17
17
|
- **Initialization**: Generates `src/i18n.ts` configuring `i18next` with `initReactI18next`.
|
|
18
18
|
- **Runtime Messages**: Generates clean key-value message files in `messages/runtime/<locale>.json`.
|
|
19
|
-
- **CDN Loading**:
|
|
19
|
+
- **Remote & CDN Loading**:
|
|
20
|
+
- If project already has remote fetching setup: **DO NOT TOUCH** it. Only manage default locale (`en`) the Shallok way.
|
|
21
|
+
- If setting up CDN loading: No fallback for all languages. **Ensure target locales are NOT bundled with final output**; only bundle default locale (`en`).
|
|
20
22
|
- **Legacy Migration**: If `src/main.tsx` or `src/i18n.ts` imported `src/locales/en.json`, migrate to `messages/runtime/` or CDN loader.
|
|
21
23
|
- **AST Transformation**:
|
|
22
24
|
- Adds `import { useTranslation } from 'react-i18next';`
|
|
@@ -38,7 +40,9 @@
|
|
|
38
40
|
### 3. Expo / React Native (`expo-localization` + `react-i18next`)
|
|
39
41
|
- **Initialization**: Generates `i18n.ts` using `getLocales` from `expo-localization` and `i18next`.
|
|
40
42
|
- **Runtime Messages**: Generates runtime message files in `messages/runtime/<locale>.json`.
|
|
41
|
-
- **CDN Loading**:
|
|
43
|
+
- **Remote & CDN Loading**:
|
|
44
|
+
- If project already has remote fetching setup: **DO NOT TOUCH** it. Only manage default locale (`en`) the Shallok way.
|
|
45
|
+
- If setting up CDN loading: No fallback for all languages. **Ensure target locales are NOT bundled with final output**; only bundle default locale (`en`).
|
|
42
46
|
- **Legacy Migration**: If `app/_layout.tsx` or `src/i18n.ts` imported `src/locales/en.json`, migrate to `messages/runtime/` or CDN loader.
|
|
43
47
|
- **AST Transformation**:
|
|
44
48
|
- Adds `import { useTranslation } from 'react-i18next';`
|
|
@@ -91,16 +91,25 @@ Use this skill when asked to add, configure, update, or audit localization in **
|
|
|
91
91
|
2. **Update all code imports** to point to the standardized compiled runtime bundle (`messages/runtime/<locale>.json`) or the CDN loader.
|
|
92
92
|
3. Remove or deprecate the legacy base locale file so that Shallok does NOT extract it as source code (preventing false occurrences like `"relative_file_path": "src/locales/en.json"`).
|
|
93
93
|
|
|
94
|
-
### Rule 6: React Client Architecture: CDN
|
|
95
|
-
- **
|
|
96
|
-
-
|
|
97
|
-
-
|
|
94
|
+
### Rule 6: React Client Architecture: Remote/CDN Loading & Zero Bundle Bloat
|
|
95
|
+
- **Existing Projects with Remote Fetching**:
|
|
96
|
+
- If the project **already has a remote setup to fetch translations** (e.g. from backend API, Supabase, CDN, S3, or external service):
|
|
97
|
+
- **DO NOT TOUCH OR MODIFY THE REMOTE FETCHING SETUP!** Keep the remote loader, caching logic, and endpoints intact.
|
|
98
|
+
- **ONLY the default / source locale (e.g. `en`) translation should be done in Shallok's way**:
|
|
99
|
+
- Maintain canonical keys in `localization_base/<source_locale>.json`.
|
|
100
|
+
- Bundle ONLY the default locale fallback in `messages/runtime/<source_locale>.json` (or `messages/<source_locale>.json`).
|
|
101
|
+
- Remote locales continue to be served via the existing remote setup.
|
|
102
|
+
- **New Setups with CDN / Remote Loading**:
|
|
103
|
+
- If the user wants to load translations from CDN/remote:
|
|
104
|
+
- **NO NEED TO HAVE FALLBACKS FOR ALL LANGUAGES**: Do NOT create or statically import local fallback message files for every language.
|
|
105
|
+
- **MAKE SURE TARGET LOCALES ARE NOT BUNDLED WITH FINAL OUTPUT**:
|
|
106
|
+
- **ONLY bundle the default / source locale** (e.g. `en`) as the initial/offline fallback (`import enFallback from '../messages/runtime/en.json'`).
|
|
107
|
+
- **DO NOT statically import target locales** (e.g. `kn`, `hi`, `fr`, `es`) in `src/i18n.ts` or app code!
|
|
108
|
+
- Target locales are fetched on-demand from the CDN / remote source and cached in `localStorage`.
|
|
109
|
+
- This keeps the final web bundle size small and allows instant copy updates.
|
|
98
110
|
- **Environment Variables & Configuration**:
|
|
99
111
|
- Define `VITE_TRANSLATIONS_CDN_URL=https://cdn.yourdomain.com/locales` (or `REACT_APP_TRANSLATIONS_CDN_URL`) in `.env` and `.env.example`.
|
|
100
|
-
-
|
|
101
|
-
- **Resilient Runtime Loader with Local Offline Fallback**:
|
|
102
|
-
- Configure `src/i18n.ts` using `i18next-http-backend` or custom fetch to load from `${VITE_TRANSLATIONS_CDN_URL}/${locale}.json` with `localStorage` caching.
|
|
103
|
-
- Always bundle `messages/runtime/<locale>.json` locally as fallback resources, ensuring the application renders immediately before network requests complete.
|
|
112
|
+
- Prompt and ask the user to configure `VITE_TRANSLATIONS_CDN_URL` with their actual CDN endpoint.
|
|
104
113
|
- **Upload Script**:
|
|
105
114
|
- Suggest / scaffold an upload script (e.g., `scripts/upload-locales.mjs`) to publish compiled `messages/runtime/` dictionaries to the CDN.
|
|
106
115
|
|
|
@@ -270,6 +279,27 @@ You, as the AI coding agent, generate the translations directly:
|
|
|
270
279
|
5. **Summarize results**:
|
|
271
280
|
Present modified components, added locales, completeness, and verification state.
|
|
272
281
|
|
|
282
|
+
### Phase G: Publish to Shallok Cloud & Global Edge CDN (MCP / CLI Push)
|
|
283
|
+
Once runtime bundles are compiled and validated:
|
|
284
|
+
1. **Check if project is connected to Shallok Cloud**:
|
|
285
|
+
- Inspect `localization.json` for the `"cloud"` configuration block.
|
|
286
|
+
2. **If `"cloud"` is present**:
|
|
287
|
+
- Call the Shallok MCP tool `shallok_sync_project`:
|
|
288
|
+
This automatically syncs the manifest and all compiled bundles to the Shallok Dashboard and activates edge CDN routing.
|
|
289
|
+
- Alternatively, execute:
|
|
290
|
+
```bash
|
|
291
|
+
shallok push
|
|
292
|
+
```
|
|
293
|
+
- Confirm to the developer with their live CDN endpoint:
|
|
294
|
+
> *"✨ Live Edge CDN: `https://<tenant>.shallok.com/<project>/:locale.json`"*
|
|
295
|
+
3. **If `"cloud"` is NOT yet configured**:
|
|
296
|
+
- Prompt the developer:
|
|
297
|
+
> *"✨ Your translations are generated and validated! To publish these translations to Shallok Cloud and serve them with zero latency from the Global Edge CDN, run:"*
|
|
298
|
+
```bash
|
|
299
|
+
npx shallok link --token <shk_live_...>
|
|
300
|
+
```
|
|
301
|
+
> *(Generate an access token at https://dash.shallok.com/mcp)*
|
|
302
|
+
|
|
273
303
|
---
|
|
274
304
|
|
|
275
305
|
## React Code Patterns & Best Practices
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
| :--- | :--- | :--- | :--- |
|
|
7
7
|
| **Astro** (`astro:i18n`) | **Local** (`messages/runtime/`) | Static builds (SSG) & SSR; zero network hops, zero build dependency on external services. | Bundled in `src/i18n/utils.ts` |
|
|
8
8
|
| **Next.js** (`next-intl`) | **Local** (`messages/runtime/`) | Server Components & SSR; instant First Contentful Paint, zero latency in Node/Edge. | Bundled in `src/i18n/request.ts` |
|
|
9
|
-
| **Expo / React Native** | **CDN-Backed** (+ Local Fallback) | Instant Over-The-Air (OTA) translation & typo fixes without waiting for App Store review. | `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` + AsyncStorage caching
|
|
10
|
-
| **React SPA** (Vite / CRA) | **CDN-Backed** (+ Local Fallback) | Instant copy updates without rebuilding web bundle. | `VITE_TRANSLATIONS_CDN_URL` + localStorage caching
|
|
9
|
+
| **Expo / React Native** | **CDN-Backed** (+ Local Fallback) | Instant Over-The-Air (OTA) translation & typo fixes without waiting for App Store review. | `EXPO_PUBLIC_TRANSLATIONS_CDN_URL` + AsyncStorage caching (default locale only bundled) |
|
|
10
|
+
| **React SPA** (Vite / CRA) | **CDN-Backed** (+ Local Fallback) | Instant copy updates without rebuilding web bundle. | `VITE_TRANSLATIONS_CDN_URL` + localStorage caching (default locale only bundled) |
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
### 1. React (`react-i18next`)
|
|
17
17
|
- **Initialization**: Generates `src/i18n.ts` configuring `i18next` with `initReactI18next`.
|
|
18
18
|
- **Runtime Messages**: Generates clean key-value message files in `messages/runtime/<locale>.json`.
|
|
19
|
-
- **CDN Loading**:
|
|
19
|
+
- **Remote & CDN Loading**:
|
|
20
|
+
- If project already has remote fetching setup: **DO NOT TOUCH** it. Only manage default locale (`en`) the Shallok way.
|
|
21
|
+
- If setting up CDN loading: No fallback for all languages. **Ensure target locales are NOT bundled with final output**; only bundle default locale (`en`).
|
|
20
22
|
- **Legacy Migration**: If `src/main.tsx` or `src/i18n.ts` imported `src/locales/en.json`, migrate to `messages/runtime/` or CDN loader.
|
|
21
23
|
- **AST Transformation**:
|
|
22
24
|
- Adds `import { useTranslation } from 'react-i18next';`
|
|
@@ -38,7 +40,9 @@
|
|
|
38
40
|
### 3. Expo / React Native (`expo-localization` + `react-i18next`)
|
|
39
41
|
- **Initialization**: Generates `i18n.ts` using `getLocales` from `expo-localization` and `i18next`.
|
|
40
42
|
- **Runtime Messages**: Generates runtime message files in `messages/runtime/<locale>.json`.
|
|
41
|
-
- **CDN Loading**:
|
|
43
|
+
- **Remote & CDN Loading**:
|
|
44
|
+
- If project already has remote fetching setup: **DO NOT TOUCH** it. Only manage default locale (`en`) the Shallok way.
|
|
45
|
+
- If setting up CDN loading: No fallback for all languages. **Ensure target locales are NOT bundled with final output**; only bundle default locale (`en`).
|
|
42
46
|
- **Legacy Migration**: If `app/_layout.tsx` or `src/i18n.ts` imported `src/locales/en.json`, migrate to `messages/runtime/` or CDN loader.
|
|
43
47
|
- **AST Transformation**:
|
|
44
48
|
- Adds `import { useTranslation } from 'react-i18next';`
|
|
@@ -4,6 +4,25 @@
|
|
|
4
4
|
|
|
5
5
|
For React SPAs (Vite, Webpack), loading translations from a CDN allows continuous translation updates without redeploying the web frontend.
|
|
6
6
|
|
|
7
|
+
### Critical Rules for Remote & CDN Translation Setups
|
|
8
|
+
|
|
9
|
+
1. **Existing Projects with Remote Fetching**:
|
|
10
|
+
- If the project **already has a remote setup to fetch translations** (e.g. from backend API, Supabase, CDN, S3, or external service):
|
|
11
|
+
- **DO NOT TOUCH OR MODIFY THE REMOTE FETCHING SETUP!** Keep the remote loader, caching logic, and endpoints intact.
|
|
12
|
+
- **ONLY the default / source locale (e.g. `en`) translation should be done in Shallok's way**:
|
|
13
|
+
- Maintain canonical keys in `localization_base/<source_locale>.json`.
|
|
14
|
+
- Bundle ONLY the default locale fallback in `messages/runtime/<source_locale>.json` (or `messages/<source_locale>.json`).
|
|
15
|
+
- Remote locales continue to be fetched via the project's existing remote setup.
|
|
16
|
+
|
|
17
|
+
2. **New Remote/CDN Setup**:
|
|
18
|
+
- If user wants to load translations from CDN/remote:
|
|
19
|
+
- **NO NEED TO HAVE FALLBACK FOR ALL LANGUAGES**: Do NOT create or statically import local fallback bundles for every language.
|
|
20
|
+
- **ENSURE TARGET LOCALES ARE NOT BUNDLED WITH FINAL OUTPUT**:
|
|
21
|
+
- **ONLY bundle the default/source locale** (e.g. `en`) as the initial/offline fallback.
|
|
22
|
+
- **NEVER** statically import non-default locales (e.g. `kn`, `hi`, `fr`, `es`) into `src/i18n.ts` or app code!
|
|
23
|
+
- Non-default locales are fetched on-demand from CDN / remote storage and cached in `localStorage`.
|
|
24
|
+
- This guarantees the production web bundle stays small.
|
|
25
|
+
|
|
7
26
|
### 1. CDN Dynamic Loading Pattern (Recommended for Web SPAs)
|
|
8
27
|
|
|
9
28
|
Configure `.env`:
|
|
@@ -16,19 +35,29 @@ VITE_TRANSLATIONS_CDN_URL=https://cdn.yourdomain.com/locales
|
|
|
16
35
|
import i18n from 'i18next';
|
|
17
36
|
import { initReactI18next } from 'react-i18next';
|
|
18
37
|
|
|
19
|
-
//
|
|
38
|
+
// ONLY the default/source locale is bundled as initial local fallback:
|
|
20
39
|
import enFallback from '../messages/runtime/en.json';
|
|
21
|
-
import knFallback from '../messages/runtime/kn.json';
|
|
22
40
|
|
|
23
41
|
const CDN_URL = import.meta.env.VITE_TRANSLATIONS_CDN_URL;
|
|
24
42
|
|
|
43
|
+
// DO NOT statically import or bundle target locales (e.g. kn, hi, fr, es)!
|
|
44
|
+
// They are fetched dynamically on-demand from the CDN and cached in localStorage.
|
|
25
45
|
const resources = {
|
|
26
46
|
en: { translation: enFallback },
|
|
27
|
-
kn: { translation: knFallback },
|
|
28
47
|
};
|
|
29
48
|
|
|
30
49
|
export async function fetchRemoteTranslations(locale: string) {
|
|
31
|
-
if (!CDN_URL) return;
|
|
50
|
+
if (locale === 'en' || !CDN_URL) return;
|
|
51
|
+
|
|
52
|
+
// 1. Try localStorage cache first
|
|
53
|
+
try {
|
|
54
|
+
const cached = localStorage.getItem(`translations_${locale}`);
|
|
55
|
+
if (cached) {
|
|
56
|
+
i18n.addResourceBundle(locale, 'translation', JSON.parse(cached), true, true);
|
|
57
|
+
}
|
|
58
|
+
} catch {}
|
|
59
|
+
|
|
60
|
+
// 2. Fetch fresh translation from CDN
|
|
32
61
|
try {
|
|
33
62
|
const res = await fetch(`${CDN_URL}/${locale}.json`);
|
|
34
63
|
if (res.ok) {
|
|
@@ -37,7 +66,7 @@ export async function fetchRemoteTranslations(locale: string) {
|
|
|
37
66
|
localStorage.setItem(`translations_${locale}`, JSON.stringify(messages));
|
|
38
67
|
}
|
|
39
68
|
} catch (err) {
|
|
40
|
-
// Falls back seamlessly to
|
|
69
|
+
// Falls back seamlessly to cached bundle or default fallback (en)
|
|
41
70
|
}
|
|
42
71
|
}
|
|
43
72
|
|