-
Notifications
You must be signed in to change notification settings - Fork 828
Feat/zero config localizer demo #1878
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Feat/zero config localizer demo #1878
Conversation
📝 WalkthroughWalkthroughAdded a zero‑config localization demo: a Vite + React app integrating the lingo.dev compiler, with demo UI, example components, build tooling, README, and assets demonstrating build‑time translation, pseudotranslation, and per‑locale bundle generation. Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as Developer
participant Vite as Vite
participant Plugin as lingo.dev Compiler Plugin
participant Parser as JSX Parser
participant Detector as Content Detector
participant FP as Fingerprint Generator
participant API as Translation API
participant Injector as Lookup Injector
participant Bundler as Bundler
Dev->>Vite: start dev/build
Vite->>Plugin: invoke compiler plugin
Plugin->>Parser: parse source (JSX → AST)
Parser->>Detector: detect translatable strings/nodes
Detector->>FP: generate fingerprints & extract strings
FP->>API: request translations for target locales
API-->>FP: return translations
FP->>Injector: generate lookup code & inject translations
Injector->>Bundler: emit optimized locale bundles
Bundler->>Dev: deliver built artifacts
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@community/zero-config-localizer/README.md`:
- Around line 104-110: Update README.md to satisfy markdownlint: add language
specifier "text" to the fenced code blocks for the "Original Text" block and the
"Pseudotranslation" block (both occurrences referenced as the pseudotranslation
and original text code blocks in README.md), replace the bare URL
"https://console.groq.com" with an inline-autolink <https://console.groq.com>,
and remove `.env.example` from the project tree listing under the
zero-config-localizer file tree so the listed files match the repository tree.
In `@community/zero-config-localizer/src/components/CodeInspector.jsx`:
- Around line 89-101: The selector buttons currently toggle visually but lack
ARIA state and a button type; update the JSX for the elements rendered in the
CodeInspector component (the button elements that call setSelectedExample and
read selectedExample) to include type="button" and aria-pressed={selectedExample
=== index} so assistive tech can observe the pressed state and to prevent
accidental form submissions.
In `@community/zero-config-localizer/vite.config.js`:
- Around line 6-21: The build currently forces real translations by calling
lingoCompiler.vite with models set to 'groq:llama-3.3-70b-versatile' and
buildMode: 'translate', which will fail when GROQ_API_KEY is not present; update
the lingoCompiler.vite invocation to detect process.env.GROQ_API_KEY (or read
from dotenv) and, if it's missing, switch to a safe fallback: set buildMode to
'cache-only' (or change models to a non-Groq/pseudotranslator entry) so
translations are not attempted, otherwise keep the Groq model and buildMode
'translate'; target the lingoCompiler.vite call and the models and buildMode
properties when implementing this conditional.
🧹 Nitpick comments (4)
community/zero-config-localizer/src/examples/FormComponent.jsx (1)
18-33: Add basic a11y wiring for the error state.
This improves screen-reader feedback with minimal change.♿️ Suggested update
<input id="email" type="email" placeholder="Enter your email" value={email} onChange={(e) => setEmail(e.target.value)} + aria-invalid={Boolean(error)} + aria-describedby={error ? 'email-error' : undefined} required /> - {error && <span style={{ color: 'red' }}>{error}</span>} + {error && ( + <span id="email-error" role="alert" style={{ color: 'red' }}> + {error} + </span> + )}community/zero-config-localizer/src/examples/DynamicComponent.jsx (1)
1-10: Stabilize the creation date to avoid render-time drift.
new Date()in render will change across re-renders (and after locale updates), which makes the “account created on” value shift. Consider memoizing the date or passing it as a prop so the output stays stable.♻️ Suggested update
-import { useLingoLocale } from 'lingo.dev/react/client'; +import { useMemo } from 'react'; +import { useLingoLocale } from 'lingo.dev/react/client'; export default function DynamicComponent({ userName, messageCount }) { const locale = useLingoLocale(); - const createdOn = new Date().toLocaleDateString(locale ?? undefined); + const createdOn = useMemo(() => new Date(), []); + const createdOnLabel = useMemo( + () => createdOn.toLocaleDateString(locale ?? undefined), + [createdOn, locale] + ); return ( <div> <h2>Hello, {userName}!</h2> <p>You have {messageCount} new messages</p> - <p>Your account was created on {createdOn}</p> + <p>Your account was created on {createdOnLabel}</p> </div> ); }community/zero-config-localizer/src/components/BundleComparison.jsx (1)
5-52: Derive card metrics fromdatato prevent drift.The stat cards (234 KB, 97 KB, 58.5%) are hard-coded while the chart uses
data. If the data changes, the cards can drift. Consider computing the numbers from the same source.♻️ Suggested update
export default function BundleComparison() { const data = [ { name: 'react-i18next', bundle: 145, dictionaries: 89, total: 234 }, @@ total: 97 } ]; + const traditionalTotal = + data.find((d) => d.name === 'react-i18next')?.total ?? data[0]?.total ?? 0; + const lingoTotal = + data.find((d) => d.name === 'Lingo.dev')?.total ?? data[data.length - 1]?.total ?? 0; + const sizeReduction = traditionalTotal + ? ((1 - lingoTotal / traditionalTotal) * 100).toFixed(1) + : '0.0'; return ( <div> @@ <StatCard icon={Package} title="Traditional i18n" - value="234 KB" + value={`${traditionalTotal} KB`} description="Runtime library + translation files" color="#ef4444" /> <StatCard icon={Package} title="Lingo.dev Compiler" - value="97 KB" + value={`${lingoTotal} KB`} description="No runtime overhead" color="#10b981" /> <StatCard icon={TrendingDown} title="Size Reduction" - value="58.5%" + value={`${sizeReduction}%`} description="Smaller bundles, faster loads" color="#667eea" />community/zero-config-localizer/src/main.jsx (1)
7-11: Consider adding a small Suspense fallback while dictionaries load.
Line 9 rendersLingoProviderWrapperwithout afallback, so the app can be blank during initial dictionary fetch. A lightweight fallback improves UX for the demo.♻️ Possible tweak
- <LingoProviderWrapper loadDictionary={(locale) => loadDictionary(locale)}> + <LingoProviderWrapper + loadDictionary={(locale) => loadDictionary(locale)} + fallback={<div style={{ padding: 24, color: '#94a3b8' }}>Loading translations…</div>} + >
| ``` | ||
| Welcome to our platform | ||
| ``` | ||
|
|
||
| **Pseudotranslation:** | ||
| ``` | ||
| [Ŵêƚçôɱê ţô ôûŕ þƚàţƒôŕɱ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix markdownlint violations and sync the project tree.
Line 104/109/178 need fenced languages (MD040). Line 127 has a bare URL (MD034). Line 185 lists .env.example; if it was removed, the tree should be updated.
✅ Suggested doc fixes
-**Original Text:**
-```
+**Original Text:**
+```text
Welcome to our platform-Pseudotranslation:
- +**Pseudotranslation:** +text
[Ŵêƚçôɱê ţô ôûŕ þƚàţƒôŕɱ]
-1. Visit https://console.groq.com
+1. Visit <https://console.groq.com>
-```
+```text
zero-config-localizer/
├── README.md
├── package.json
├── vite.config.js
├── index.html
├── .gitignore
-├── .env.example
├── src/
│ ├── main.jsx
Also applies to: 127-127, 178-186
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
104-104: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
109-109: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In `@community/zero-config-localizer/README.md` around lines 104 - 110, Update
README.md to satisfy markdownlint: add language specifier "text" to the fenced
code blocks for the "Original Text" block and the "Pseudotranslation" block
(both occurrences referenced as the pseudotranslation and original text code
blocks in README.md), replace the bare URL "https://console.groq.com" with an
inline-autolink <https://console.groq.com>, and remove `.env.example` from the
project tree listing under the zero-config-localizer file tree so the listed
files match the repository tree.
|
Hi! I’ve addressed all feedback from CodeRabbit and updated the PR accordingly. Noted that remaining workflow approvals require maintainer permissions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@community/zero-config-localizer/src/examples/DynamicComponent.jsx`:
- Around line 11-16: The displayed "created on" date uses new Date() so
createdOn always shows today's date; change DynamicComponent to accept a
createdAt prop (e.g., createdAt) and compute createdOn with new
Date(createdAt).toLocaleDateString(locale ?? undefined) in place of new Date(),
or alternatively update the copy to something like "Today's date" if you don't
want to add a prop; update references to createdOn in the JSX (and document the
new createdAt prop) so the UI shows a real/mocked creation date instead of the
current date.
In `@community/zero-config-localizer/src/examples/NestedComponent.jsx`:
- Line 20: The JSX currently renders a hardcoded dollar sign around
product.price which breaks localization; update the rendering in NestedComponent
(where product.price is used) to format the price with Intl.NumberFormat (e.g.,
new Intl.NumberFormat(locale, { style: 'currency', currency })) using a
locale/currency prop or context, or if intentionally left as a limitation add a
clear inline comment above the JSX noting the hardcoded $ is deliberate for the
example; ensure you reference the product.price usage and the component name
NestedComponent when making the change.
- Around line 7-12: The NestedComponent currently accesses product.name and
product.sku without guarding against product being null/undefined; update the
component (NestedComponent) to defensively handle a missing product by either
providing a default value in the parameter (e.g., product = {}), adding an early
guard/conditional render (e.g., return null or a placeholder when product is
falsy), or using optional chaining when reading properties (product?.name,
product?.sku) so no TypeError is thrown.
♻️ Duplicate comments (1)
community/zero-config-localizer/src/components/CodeInspector.jsx (1)
99-114: Addtype="button"andaria-pressedfor accessibility.The selector buttons visually toggle but lack ARIA state for assistive technologies, and missing
type="button"could cause unintended form submissions if nested.🧩 Suggested fix
<button + type="button" + aria-pressed={selectedExample === index} key={index} onClick={() => setSelectedExample(index)} style={{
🧹 Nitpick comments (5)
community/zero-config-localizer/src/components/OriginalCode.jsx (1)
1-4: Remove extra blank lines at the start of the file.Lines 1-2 are unnecessary blank lines before the imports.
🧹 Suggested cleanup
- - import { Code } from 'lucide-react';community/zero-config-localizer/src/components/CodeInspector.jsx (1)
147-158: Hide decorative arrow from assistive technologies.The arrow is purely decorative and should be hidden from screen readers to avoid confusion.
🧩 Suggested fix
<div style={{ width: 48, height: 48, borderRadius: '50%', background: 'linear-gradient(135deg, `#667eea` 0%, `#764ba2` 100%)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 - }}> + }} + aria-hidden="true" + > <ArrowRight size={24} /> </div>community/zero-config-localizer/src/examples/DynamicComponent.jsx (2)
7-19: Inconsistent indentation throughout the file.The import statement on line 7 has no indentation, but the function definition (lines 9-19) is indented by 2 spaces. This appears to be an accidental formatting issue.
🛠️ Suggested fix
import { useLingoLocale } from 'lingo.dev/react/client'; - - export default function DynamicComponent({ userName, messageCount }) { - const locale = useLingoLocale(); - const createdOn = new Date().toLocaleDateString(locale ?? undefined); - return ( - <div> - <h2>Hello, {userName}!</h2> - <p>You have {messageCount} new messages</p> - <p>Your account was created on {createdOn}</p> - </div> - ); - } - - + +export default function DynamicComponent({ userName, messageCount }) { + const locale = useLingoLocale(); + const createdOn = new Date().toLocaleDateString(locale ?? undefined); + return ( + <div> + <h2>Hello, {userName}!</h2> + <p>You have {messageCount} new messages</p> + <p>Your account was created on {createdOn}</p> + </div> + ); +}
1-5: JSDoc is incomplete—missing@paramtags for props.The JSDoc documents the return type but omits the
userNameandmessageCountprops. For a demo component meant to showcase patterns, complete documentation would be helpful.📝 Suggested fix
/** - * React component example. + * Dynamic component example demonstrating locale-aware date formatting. * + * `@param` {Object} props - Component props + * `@param` {string} props.userName - The user's display name + * `@param` {number} props.messageCount - Number of new messages * `@returns` {JSX.Element} */community/zero-config-localizer/src/examples/NestedComponent.jsx (1)
1-5: JSDoc is missing@paramfor theproductprop.Consider documenting the expected shape of the
productobject to help consumers of this component.📝 Suggested documentation improvement
/** * React component example. * + * `@param` {Object} props - Component props + * `@param` {Object} props.product - Product data object + * `@param` {string} props.product.name - Product name + * `@param` {string} props.product.sku - Product SKU + * `@param` {string} props.product.description - Product description + * `@param` {number} props.product.price - Product price + * `@param` {number} props.product.stock - Available stock count * `@returns` {JSX.Element} */
community/zero-config-localizer/src/examples/DynamicComponent.jsx
Outdated
Show resolved
Hide resolved
community/zero-config-localizer/src/examples/NestedComponent.jsx
Outdated
Show resolved
Hide resolved
community/zero-config-localizer/src/examples/NestedComponent.jsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@community/zero-config-localizer/src/examples/DynamicComponent.jsx`:
- Around line 13-16: The createdOn calculation in DynamicComponent uses new
Date(createdAt) which treats 'YYYY-MM-DD' as UTC and can cause timezone drift;
detect if createdAt is a date-only ISO string (e.g., /^\d{4}-\d{2}-\d{2}$/) and,
if so, parse into a local Date using components (new Date(year, month-1, day))
before calling toLocaleDateString; otherwise continue to use new Date(createdAt)
as-is, and keep useLingoLocale() for formatting.
🧹 Nitpick comments (1)
community/zero-config-localizer/src/examples/NestedComponent.jsx (1)
11-14: Consider usinguseLingoLocale()for consistency with other demo components.The
localeprop approach works, butDynamicComponent.jsxuses theuseLingoLocale()hook directly. For a cohesive demo showcasing the lingo.dev compiler's zero-config philosophy, consider whether all components should follow the same pattern.If intentional to demonstrate multiple approaches, a brief inline comment would clarify this design choice.
Summary
This PR adds a zero-config React localizer demo under the
/communitydirectory.The demo showcases how lingo.dev automatically localizes UI text and formatting
at build time without translation keys, runtime libraries, or code changes.
What this demo shows
setLingoLocalet()functionsTesting
npm installandnpm run devVisuals
(Screenshots or demo video can be added if required)
Checklist
/communitySummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.