Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions community/error-localization-engine/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
LINGO_API_KEY=your_api_key_here
PORT=3000
4 changes: 4 additions & 0 deletions community/error-localization-engine/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
.env
*.log
.DS_Store
90 changes: 90 additions & 0 deletions community/error-localization-engine/README.md
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."
}
```
62 changes: 62 additions & 0 deletions community/error-localization-engine/lingoClient.js
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 community/error-localization-engine/middleware/localizer.js
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';

// Log for debugging
console.log(`[Request] ${req.method} ${req.path} - Target Lang: ${req.targetLang}`);

next();
}

module.exports = localizer;
Loading
Loading