Skip to content

Commit 814a6b8

Browse files
Copilothotlong
andcommitted
refactor(i18n): extract loadLanguage into testable module
Move loadLanguage from inline in main.tsx to a separate loadLanguage.ts module. Test imports the actual production code instead of duplicating logic. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> Agent-Logs-Url: https://github.com/objectstack-ai/objectui/sessions/c9dec823-2a7f-43fa-a55e-6b357fefe3d5
1 parent 599890f commit 814a6b8

File tree

3 files changed

+29
-51
lines changed

3 files changed

+29
-51
lines changed

apps/console/src/__tests__/LoadLanguage.test.tsx

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,7 @@
77
*/
88

99
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
10-
11-
// ---------------------------------------------------------------------------
12-
// Re-implement the loadLanguage logic under test (mirrors apps/console/src/main.tsx)
13-
// ---------------------------------------------------------------------------
14-
async function loadLanguage(lang: string): Promise<Record<string, unknown>> {
15-
try {
16-
const res = await fetch(`/api/v1/i18n/translations/${lang}`);
17-
if (!res.ok) {
18-
console.warn(`[i18n] Failed to load translations for '${lang}': HTTP ${res.status}`);
19-
return {};
20-
}
21-
const json = await res.json();
22-
// Unwrap the spec REST API envelope when present
23-
if (json && typeof json === 'object' && json.data && json.data.translations && typeof json.data.translations === 'object') {
24-
return json.data.translations as Record<string, unknown>;
25-
}
26-
// Fallback: mock server / local dev returns flat translation objects
27-
return json;
28-
} catch (err) {
29-
console.warn(`[i18n] Failed to load translations for '${lang}':`, err);
30-
return {};
31-
}
32-
}
10+
import { loadLanguage } from '../loadLanguage';
3311

3412
// ---------------------------------------------------------------------------
3513
// Tests

apps/console/src/loadLanguage.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Load application-specific translations for a given language from the API.
3+
*
4+
* The @objectstack/spec REST API (`/api/v1/i18n/translations/:locale`) wraps
5+
* its response in the standard envelope: `{ data: { locale, translations } }`.
6+
* We extract `data.translations` when present, and fall back to the raw JSON
7+
* for mock / local-dev environments that may return flat translation objects.
8+
*/
9+
export async function loadLanguage(lang: string): Promise<Record<string, unknown>> {
10+
try {
11+
const res = await fetch(`/api/v1/i18n/translations/${lang}`);
12+
if (!res.ok) {
13+
console.warn(`[i18n] Failed to load translations for '${lang}': HTTP ${res.status}`);
14+
return {};
15+
}
16+
const json = await res.json();
17+
// Unwrap the spec REST API envelope when present
18+
if (json && typeof json === 'object' && json.data && json.data.translations && typeof json.data.translations === 'object') {
19+
return json.data.translations as Record<string, unknown>;
20+
}
21+
// Fallback: mock server / local dev returns flat translation objects
22+
return json;
23+
} catch (err) {
24+
console.warn(`[i18n] Failed to load translations for '${lang}':`, err);
25+
return {};
26+
}
27+
}

apps/console/src/main.tsx

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import './index.css';
1010
import { App } from './App';
1111
import { I18nProvider } from '@object-ui/i18n';
1212
import { MobileProvider } from '@object-ui/mobile';
13+
import { loadLanguage } from './loadLanguage';
1314

1415
// Register plugins (side-effect imports for ComponentRegistry)
1516
import '@object-ui/plugin-grid';
@@ -27,34 +28,6 @@ import '@object-ui/plugin-dashboard';
2728
import '@object-ui/plugin-report';
2829
import '@object-ui/plugin-markdown';
2930

30-
/**
31-
* Load application-specific translations for a given language from the API.
32-
*
33-
* The @objectstack/spec REST API (`/api/v1/i18n/translations/:locale`) wraps
34-
* its response in the standard envelope: `{ data: { locale, translations } }`.
35-
* We extract `data.translations` when present, and fall back to the raw JSON
36-
* for mock / local-dev environments that may return flat translation objects.
37-
*/
38-
async function loadLanguage(lang: string): Promise<Record<string, unknown>> {
39-
try {
40-
const res = await fetch(`/api/v1/i18n/translations/${lang}`);
41-
if (!res.ok) {
42-
console.warn(`[i18n] Failed to load translations for '${lang}': HTTP ${res.status}`);
43-
return {};
44-
}
45-
const json = await res.json();
46-
// Unwrap the spec REST API envelope when present
47-
if (json && typeof json === 'object' && json.data && json.data.translations && typeof json.data.translations === 'object') {
48-
return json.data.translations as Record<string, unknown>;
49-
}
50-
// Fallback: mock server / local dev returns flat translation objects
51-
return json;
52-
} catch (err) {
53-
console.warn(`[i18n] Failed to load translations for '${lang}':`, err);
54-
return {};
55-
}
56-
}
57-
5831
// Start MSW before rendering the app
5932
async function bootstrap() {
6033
// Initialize Mock Service Worker if enabled (lazy-loaded to keep production bundle lean)

0 commit comments

Comments
 (0)