-
Notifications
You must be signed in to change notification settings - Fork 828
Add community demo: error localization engine (Closes #1761) #1880
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
Open
BhagyeshPatil2004
wants to merge
2
commits into
lingodotdev:main
Choose a base branch
from
BhagyeshPatil2004:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| LINGO_API_KEY=your_api_key_here | ||
| PORT=3000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| node_modules/ | ||
| .env | ||
| *.log | ||
| .DS_Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| # Error Message & Validation Localization Engine | ||
|
|
||
| A production-grade demo showing how to automatically localize backend error and validation messages using [Lingo.dev](https://lingo.dev). | ||
|
|
||
| ## π The Core Problem | ||
|
|
||
| Most applications translate UI labels but leave backend error messages in English. This creates a disjointed experience for international users (e.g., getting a "Password too short" error in English while browsing a Spanish site). | ||
|
|
||
| This usage fixes that by intercepting errors and dynamically localizing them before they reach the client. | ||
|
|
||
| ## π οΈ Tech Stack | ||
|
|
||
| - **Node.js**: Runtime environment. | ||
| - **Express**: Web server and routing. | ||
| - **Lingo.dev SDK**: AI-powered localization engine. | ||
|
|
||
| ## πββοΈ How to Run | ||
|
|
||
| 1. **Install Dependencies** | ||
| ```bash | ||
| npm install | ||
| ``` | ||
|
|
||
| 2. **Configure Environment** | ||
| Create a `.env` file and add your Lingo.dev API key: | ||
| ```bash | ||
| LINGO_API_KEY=your_api_key_here | ||
| ``` | ||
|
|
||
| 3. **Start the Server** | ||
| ```bash | ||
| npm start | ||
| ``` | ||
|
|
||
| 4. **Open the Demo** | ||
| - Open your browser and go to: `http://localhost:3000` | ||
| - Select a language from the dropdown | ||
| - Try the test cases to see localized errors! | ||
|
|
||
| ## π§ͺ Testing the API | ||
|
|
||
| The API detects language preference via: | ||
| 1. `?lang=xx` query parameter (High priority) | ||
| 2. `Accept-Language` header (Low priority) | ||
|
|
||
| ### 1. English (Default) | ||
| **Request:** | ||
| ```bash | ||
| curl -X POST http://localhost:3000/api/auth/signup \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"email": "invalid-email", "password": "123"}' | ||
| ``` | ||
| **Response:** | ||
| ```json | ||
| { | ||
| "error": "Validation Failed", | ||
| "message": "Please provide a valid email address." | ||
| } | ||
| ``` | ||
|
|
||
| ### 2. Spanish (via Query Param) | ||
| **Request:** | ||
| ```bash | ||
| curl -X POST "http://localhost:3000/api/auth/signup?lang=es" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"email": "invalid-email", "password": "123"}' | ||
| ``` | ||
| **Response (Localized):** | ||
| ```json | ||
| { | ||
| "error": "FallΓ³ la validaciΓ³n", | ||
| "message": "Por favor proporcione una direcciΓ³n de correo electrΓ³nico vΓ‘lida." | ||
| } | ||
| ``` | ||
|
|
||
| ### 3. French (via Header) | ||
| **Request:** | ||
| ```bash | ||
| curl -X POST http://localhost:3000/api/auth/signup \ | ||
| -H "Content-Type: application/json" \ | ||
| -H "Accept-Language: fr" \ | ||
| -d '{"email": "test@example.com", "password": "short"}' | ||
| ``` | ||
| **Response (Localized):** | ||
| ```json | ||
| { | ||
| "error": "Γchec de la validation", | ||
| "message": "Le mot de passe doit contenir au moins 6 caractères." | ||
| } | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| const { LingoDotDevEngine } = require("lingo.dev/sdk"); | ||
|
|
||
| // Initialize the Lingo.dev engine if KEY is present | ||
| const apiKey = process.env.LINGO_API_KEY; | ||
| let lingoDotDev = null; | ||
|
|
||
| if (apiKey && apiKey !== 'your_api_key_here') { | ||
| lingoDotDev = new LingoDotDevEngine({ apiKey }); | ||
| } | ||
|
|
||
| /** | ||
| * Localizes an error message or object to the target language. | ||
| * @param {string|object} content - The error message or object to localize. | ||
| * @param {string} targetLocale - The target language code (e.g., 'es', 'fr'). | ||
| * @returns {Promise<string|object>} - The localized content. | ||
| */ | ||
| async function localizeError(content, targetLocale) { | ||
| if (!targetLocale || targetLocale.startsWith('en')) { | ||
| return content; | ||
| } | ||
|
|
||
| // MOCK MODE: If no API key is set, return mock translations | ||
| if (!lingoDotDev) { | ||
| console.log(`[Mock] Localizing to ${targetLocale}:`, JSON.stringify(content)); | ||
| const isString = typeof content === 'string'; | ||
|
|
||
| // Simple mock translation function | ||
| const mockTranslate = (str) => `[${targetLocale}] ${str}`; | ||
|
|
||
| if (isString) { | ||
| return mockTranslate(content); | ||
| } else { | ||
| const translated = {}; | ||
| for (const [key, value] of Object.entries(content)) { | ||
| if (typeof value === 'string') { | ||
| translated[key] = mockTranslate(value); | ||
| } else { | ||
| translated[key] = value; | ||
| } | ||
| } | ||
| return translated; | ||
| } | ||
| } | ||
|
|
||
| try { | ||
| const isString = typeof content === 'string'; | ||
| const input = isString ? { message: content } : content; | ||
|
|
||
| const translated = await lingoDotDev.localizeObject(input, { | ||
| sourceLocale: "en", | ||
| targetLocale: targetLocale, | ||
| }); | ||
|
|
||
| return isString ? translated.message : translated; | ||
|
|
||
| } catch (error) { | ||
| console.error("Localization failed:", error.message); | ||
| return content; | ||
| } | ||
| } | ||
|
|
||
| module.exports = { localizeError }; |
28 changes: 28 additions & 0 deletions
28
community/error-localization-engine/middleware/localizer.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /** | ||
| * Middleware to extract the target language from the request. | ||
| * Prioritizes 'lang' query parameter over 'Accept-Language' header. | ||
| * Defaults to 'en' (English). | ||
| */ | ||
| function localizer(req, res, next) { | ||
| // 1. Check query param ?lang=xx | ||
| let lang = req.query.lang; | ||
|
|
||
| // 2. Check Accept-Language header | ||
| if (!lang && req.headers['accept-language']) { | ||
| // Simple parse: take the first language code (e.g., 'en-US,en;q=0.9' -> 'en-US') | ||
| // And maybe just take the first 2 chars or the full code. | ||
| // Lingo.dev likely supports standard BCP-47. | ||
| const acceptLang = req.headers['accept-language'].split(',')[0].trim(); | ||
| lang = acceptLang; | ||
| } | ||
|
|
||
| // 3. Default to English | ||
| req.targetLang = lang || 'en'; | ||
|
Comment on lines
+7
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normalize
π§ Proposed normalization- let lang = req.query.lang;
+ let lang = req.query.lang;
+ if (Array.isArray(lang)) lang = lang[0];
+ if (typeof lang === 'string') lang = lang.trim();
+ if (!lang) lang = undefined;
// 2. Check Accept-Language header
if (!lang && req.headers['accept-language']) {
- const acceptLang = req.headers['accept-language'].split(',')[0].trim();
+ const acceptLang = req.headers['accept-language']
+ .split(',')[0]
+ .split(';')[0]
+ .trim();
lang = acceptLang;
}π€ Prompt for AI Agents |
||
|
|
||
| // Log for debugging | ||
| console.log(`[Request] ${req.method} ${req.path} - Target Lang: ${req.targetLang}`); | ||
|
|
||
| next(); | ||
| } | ||
|
|
||
| module.exports = localizer; | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Clarify mockβmode output in the API examples.
If the demo runs without
LINGO_API_KEY, responses may be mockβlocalized (e.g., prefixed with[es]/[fr]) rather than fully translated. A short note here would reduce confusion for firstβtime testers.π Suggested doc note
π€ Prompt for AI Agents