Skip to content

Conversation

@Apoorva2394
Copy link

@Apoorva2394 Apoorva2394 commented Jan 24, 2026

Supersedes #1875 (closed after feedback was addressed)

Summary

This PR adds a zero-config React localizer demo under the /community directory.
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

  • Automatic UI text translation
  • Locale switching using setLingoLocale
  • Zero translation keys or t() functions
  • Build-time localization via compiler
  • React 19 compatibility

Testing

  • Installed dependencies locally
  • Ran the demo using npm install and npm run dev
  • Verified language switching works correctly
  • Verified UI text updates without code changes

Visuals

  • Language selector UI with live switching
  • Demo page content translated across locales
    (Screenshots or demo video can be added if required)

Checklist

  • No breaking changes
  • Demo isolated to /community
  • Follows zero-config localization principles
  • Compatible with React 19

Summary by CodeRabbit

  • New Features
    • Added a zero‑config localizer demo app with language switching, interactive build-process visualization, bundle size comparison, code transformation inspector, and multiple example components (forms, nested/dynamic examples, original source preview).
  • Documentation
    • Added comprehensive README and demo instructions covering quick start, features, translation workflow, and troubleshooting.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 24, 2026

📝 Walkthrough

Walkthrough

Added a new zero-config localization demo: a Vite + React app that integrates the lingo.dev compiler, example components, visualizations, docs, and build tooling to demonstrate build-time translation and bundle generation.

Changes

Cohort / File(s) Summary
Project Metadata & Build
community/zero-config-localizer/package.json, community/zero-config-localizer/vite.config.js
New package manifest and Vite config wiring the lingo.dev compiler (sourceRoot, sourceLocale, targetLocales, dev pseudotranslator, conditional GROQ models), scripts for dev/build/translate.
Repo Ignore
community/zero-config-localizer/.gitignore
Added standard ignore patterns for node modules, build artifacts, env files, editor/OS files, logs, and temp files.
App Shell & Entry
community/zero-config-localizer/index.html, community/zero-config-localizer/src/main.jsx, community/zero-config-localizer/src/index.css
HTML entry, React bootstrap mounting App inside Lingo provider wrapper, and global CSS (reset, typography, spin utility).
Root App
community/zero-config-localizer/src/App.jsx
New default-exported App component: tabbed UI, locale switching via useLingoLocale, and layout that references demo sections/components.
Compiler / Visualization Components
community/zero-config-localizer/src/components/CompilerVisualization.jsx, .../BundleComparison.jsx, .../CodeInspector.jsx
New interactive components: animated compiler workflow (multi-step), bundle size bar chart and stats, and before/after code transformation inspector. Review animation timers, intervals, and chart responsiveness.
UI Display Component
community/zero-config-localizer/src/components/OriginalCode.jsx
New component rendering an example original source code block and checklist UI.
Example App Components
community/zero-config-localizer/src/examples/SimpleComponent.jsx, .../FormComponent.jsx, .../DynamicComponent.jsx, .../NestedComponent.jsx
Example components demonstrating static text, form validation, locale-aware date formatting, and nested dynamic content for the compiler to detect/transpile.
Documentation
community/zero-config-localizer/README.md
Comprehensive README describing demo purpose, zero-config vs traditional i18n, quick start, architecture, pseudotranslations, project structure, and troubleshooting.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Vite as Vite Build
    participant Compiler as lingo.dev Compiler
    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 Bundle Builder

    Dev->>Vite: start build / dev
    Vite->>Compiler: invoke compiler plugin
    Compiler->>Parser: parse source (JSX -> AST)
    Parser->>Detector: detect translatable nodes
    Detector->>FP: generate fingerprints & extracted strings
    FP->>API: request translations (per target locale)
    API-->>FP: translations response
    FP->>Injector: produce lookup code & optimized assets
    Injector->>Bundler: emit locale-specific bundles
    Bundler->>Dev: built artifacts (optimized language bundles)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🐰
I hop through JSX fields so bright,
I sniff the strings and set them right,
Build-time carrots, small and sweet,
Bundles lean—what a treat! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feat/zero config localizer demo' is directly related to the main change - adding a zero-config React localizer demo under the community directory.
Description check ✅ Passed The description covers the main objectives, testing performed, and verification steps, though it deviates from the template structure by not explicitly following the prescribed sections.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a 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 from data to 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 renders LingoProviderWrapper without a fallback, 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>}
+    >

Comment on lines 104 to 110
```
Welcome to our platform
```

**Pseudotranslation:**
```
[Ŵêƚçôɱê ţô ôûŕ þƚàţƒôŕɱ]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Comment on lines +89 to +101
<button
key={index}
onClick={() => setSelectedExample(index)}
style={{
padding: '12px 20px',
background: selectedExample === index ? '#667eea' : '#1e293b',
border: `1px solid ${selectedExample === index ? '#667eea' : '#334155'}`,
borderRadius: 8,
color: 'white',
cursor: 'pointer',
fontSize: 14,
fontWeight: 500
}}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Expose selection state to assistive tech.

The selector buttons are visually toggled but lack ARIA state. Add aria-pressed (and type="button" to prevent accidental form submits when nested).

🧩 Suggested update
-          <button
+          <button
+            type="button"
+            aria-pressed={selectedExample === index}
             key={index}
             onClick={() => setSelectedExample(index)}
             style={{
               padding: '12px 20px',
               background: selectedExample === index ? '#667eea' : '#1e293b',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button
key={index}
onClick={() => setSelectedExample(index)}
style={{
padding: '12px 20px',
background: selectedExample === index ? '#667eea' : '#1e293b',
border: `1px solid ${selectedExample === index ? '#667eea' : '#334155'}`,
borderRadius: 8,
color: 'white',
cursor: 'pointer',
fontSize: 14,
fontWeight: 500
}}
<button
type="button"
aria-pressed={selectedExample === index}
key={index}
onClick={() => setSelectedExample(index)}
style={{
padding: '12px 20px',
background: selectedExample === index ? '#667eea' : '#1e293b',
border: `1px solid ${selectedExample === index ? '#667eea' : '#334155'}`,
borderRadius: 8,
color: 'white',
cursor: 'pointer',
fontSize: 14,
fontWeight: 500
}}
🤖 Prompt for AI Agents
In `@community/zero-config-localizer/src/components/CodeInspector.jsx` around
lines 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.

@Apoorva2394
Copy link
Author

Hi! I’ve addressed all feedback from CodeRabbit and updated the PR accordingly.
All checks are now passing on my side.

Noted that remaining workflow approvals require maintainer permissions.
Thanks for taking a look!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant