Skip to content

Commit eb2655a

Browse files
committed
feat: initial
1 parent 919d54d commit eb2655a

File tree

8 files changed

+100
-5
lines changed

8 files changed

+100
-5
lines changed

cmp/compiler/package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
"./vite": {
1313
"types": "./dist/vite.d.ts",
1414
"import": "./dist/vite.js"
15+
},
16+
"./react": {
17+
"types": "./dist/react.d.ts",
18+
"import": "./dist/react.js"
1519
}
1620
},
1721
"scripts": {
@@ -32,8 +36,13 @@
3236
"@types/babel__generator": "^7.6.8",
3337
"@types/babel__traverse": "^7.20.6",
3438
"@types/node": "^24.10.1",
39+
"@types/react": "^19.0.0",
40+
"react": "^19.0.0",
3541
"tsup": "^8.3.0",
3642
"typescript": "^5.6.0",
3743
"vite": "^7.2.4"
44+
},
45+
"peerDependencies": {
46+
"react": "^19.0.0"
3847
}
3948
}

cmp/compiler/src/react.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import {
2+
createContext,
3+
use,
4+
useContext,
5+
useMemo,
6+
type ReactNode,
7+
} from 'react';
8+
9+
interface LingoCompilerContextValue {
10+
locale: string;
11+
translations: Record<string, any>;
12+
}
13+
14+
const LingoCompilerContext = createContext<LingoCompilerContextValue | null>(null);
15+
16+
interface LingoCompilerProps {
17+
locale: string;
18+
children: ReactNode;
19+
}
20+
21+
// Cache to prevent duplicate fetches
22+
const translationCache = new Map<string, Promise<Record<string, any>>>();
23+
24+
function fetchTranslations(locale: string): Promise<Record<string, any>> {
25+
if (translationCache.has(locale)) {
26+
return translationCache.get(locale)!;
27+
}
28+
29+
const isDev = process.env.NODE_ENV === 'development';
30+
const url = isDev
31+
? `http://localhost:3001/i18n?locale=${locale}`
32+
: `/i18n/${locale}.json`;
33+
34+
const promise = fetch(url).then((res) => {
35+
if (!res.ok) {
36+
throw new Error(`Failed to fetch translations for locale: ${locale}`);
37+
}
38+
return res.json();
39+
});
40+
41+
translationCache.set(locale, promise);
42+
return promise;
43+
}
44+
45+
export function LingoCompiler({ locale, children }: LingoCompilerProps) {
46+
const i18nPromise = useMemo(() => fetchTranslations(locale), [locale]);
47+
const translations = use(i18nPromise);
48+
49+
return (
50+
<LingoCompilerContext.Provider value={{ locale, translations }}>
51+
{children}
52+
</LingoCompilerContext.Provider>
53+
);
54+
}
55+
56+
export function useLingoCompiler() {
57+
const context = useContext(LingoCompilerContext);
58+
if (!context) {
59+
throw new Error('useLingoCompiler must be used within LingoCompiler');
60+
}
61+
return context;
62+
}

cmp/compiler/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"compilerOptions": {
33
"target": "ES2020",
44
"module": "ESNext",
5-
"lib": ["ES2020"],
5+
"lib": ["ES2020", "DOM"],
6+
"jsx": "react-jsx",
67
"strict": true,
78
"esModuleInterop": true,
89
"skipLibCheck": true,

cmp/compiler/tsup.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { defineConfig } from 'tsup';
22

33
export default defineConfig({
4-
entry: ['src/index.ts', 'src/vite.ts'],
4+
entry: ['src/index.ts', 'src/vite.ts', 'src/react.tsx'],
55
format: ['esm'],
66
dts: true,
77
clean: true,
88
sourcemap: true,
9+
external: ['react', 'react-dom'],
910
});

cmp/demo/src/App.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { BrowserRouter, Routes, Route, Link, Outlet } from 'react-router';
2+
import { useLingoCompiler } from '@compiler/core/react';
23

34
function Layout() {
45
return (
@@ -14,7 +15,14 @@ function Layout() {
1415
}
1516

1617
function Home() {
17-
return <h1>Home Page</h1>;
18+
const { locale, translations } = useLingoCompiler();
19+
return (
20+
<div>
21+
<h1>Home Page</h1>
22+
<p>Current locale: {locale}</p>
23+
<p>Translations loaded: {JSON.stringify(translations)}</p>
24+
</div>
25+
);
1826
}
1927

2028
function About() {

cmp/demo/src/main.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
import { StrictMode } from 'react';
1+
import { StrictMode, Suspense } from 'react';
22
import { createRoot } from 'react-dom/client';
3+
import { LingoCompiler } from '@compiler/core/react';
34
import App from './App';
45

56
createRoot(document.getElementById('root')!).render(
67
<StrictMode>
7-
<App />
8+
<Suspense fallback={<div>Loading translations...</div>}>
9+
<LingoCompiler locale="en">
10+
<App />
11+
</LingoCompiler>
12+
</Suspense>
813
</StrictMode>
914
);

cmp/localizer/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { Hono } from 'hono';
2+
import { cors } from 'hono/cors';
23
import { serve } from '@hono/node-server';
34

45
const app = new Hono();
56

7+
app.use('*', cors());
8+
69
app.get('/i18n', (c) => {
710
return c.json({});
811
});

cmp/pnpm-lock.yaml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)