Keep/keep-notes/lib/ai/services/language-detection.service.ts
sepehr 7fb486c9a4 feat: Complete internationalization and code cleanup
## Translation Files
- Add 11 new language files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl)
- Add 100+ missing translation keys across all 15 languages
- New sections: notebook, pagination, ai.batchOrganization, ai.autoLabels
- Update nav section with workspace, quickAccess, myLibrary keys

## Component Updates
- Update 15+ components to use translation keys instead of hardcoded text
- Components: notebook dialogs, sidebar, header, note-input, ghost-tags, etc.
- Replace 80+ hardcoded English/French strings with t() calls
- Ensure consistent UI across all supported languages

## Code Quality
- Remove 77+ console.log statements from codebase
- Clean up API routes, components, hooks, and services
- Keep only essential error handling (no debugging logs)

## UI/UX Improvements
- Update Keep logo to yellow post-it style (from-yellow-400 to-amber-500)
- Change selection colors to #FEF3C6 (notebooks) and #EFB162 (nav items)
- Make "+" button permanently visible in notebooks section
- Fix grammar and syntax errors in multiple components

## Bug Fixes
- Fix JSON syntax errors in it.json, nl.json, pl.json, zh.json
- Fix syntax errors in notebook-suggestion-toast.tsx
- Fix syntax errors in use-auto-tagging.ts
- Fix syntax errors in paragraph-refactor.service.ts
- Fix duplicate "fusion" section in nl.json

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

Ou une version plus courte si vous préférez :

feat(i18n): Add 15 languages, remove logs, update UI components

- Create 11 new translation files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl)
- Add 100+ translation keys: notebook, pagination, AI features
- Update 15+ components to use translations (80+ strings)
- Remove 77+ console.log statements from codebase
- Fix JSON syntax errors in 4 translation files
- Fix component syntax errors (toast, hooks, services)
- Update logo to yellow post-it style
- Change selection colors (#FEF3C6, #EFB162)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 22:26:13 +01:00

134 lines
3.2 KiB
TypeScript

import { detect } from 'tinyld'
/**
* Language Detection Service
*
* Uses hybrid approach:
* - TinyLD for notes < 50 words (fast, ~8ms)
* - AI for notes ≥ 50 words (more accurate, ~200-500ms)
*
* Supports 62 languages including Persian (fa)
*/
export class LanguageDetectionService {
private readonly MIN_WORDS_FOR_AI = 50
private readonly MIN_CONFIDENCE = 0.7
/**
* Detect language of content using hybrid approach
*/
async detectLanguage(content: string): Promise<{
language: string // 'fr' | 'en' | 'es' | 'de' | 'fa' | 'unknown'
confidence: number // 0.0-1.0
method: 'tinyld' | 'ai' | 'unknown'
}> {
if (!content || content.trim().length === 0) {
return {
language: 'unknown',
confidence: 0.0,
method: 'unknown'
}
}
const wordCount = content.split(/\s+/).length
// Short notes: TinyLD (fast, TypeScript native)
if (wordCount < this.MIN_WORDS_FOR_AI) {
const result = detect(content)
return {
language: this.mapToISO(result),
confidence: 0.8,
method: 'tinyld'
}
}
// Long notes: AI for better accuracy
try {
const detected = await this.detectLanguageWithAI(content)
return {
language: detected,
confidence: 0.9,
method: 'ai'
}
} catch (error) {
console.error('Language detection error:', error)
// Fallback to TinyLD
const result = detect(content)
return {
language: this.mapToISO(result),
confidence: 0.6,
method: 'tinyld'
}
}
}
/**
* Detect language using AI provider
* (Fallback method for long content)
*/
private async detectLanguageWithAI(content: string): Promise<string> {
// For now, use TinyLD as AI detection is not yet implemented
// In Phase 2, we can add AI-based detection for better accuracy
const result = detect(content)
return this.mapToISO(result)
}
/**
* Map TinyLD language codes to ISO 639-1
*/
private mapToISO(code: string): string {
const mapping: Record<string, string> = {
'fra': 'fr',
'eng': 'en',
'spa': 'es',
'deu': 'de',
'fas': 'fa',
'pes': 'fa', // Persian (Farsi)
'por': 'pt',
'ita': 'it',
'rus': 'ru',
'zho': 'zh',
'jpn': 'ja',
'kor': 'ko',
'ara': 'ar',
'hin': 'hi',
'nld': 'nl',
'pol': 'pl',
'tur': 'tr',
'vie': 'vi',
'tha': 'th',
'ind': 'id'
}
// Direct mapping for ISO codes
if (code.length === 2 && /^[a-z]{2}$/.test(code)) {
return code
}
// Use mapping or fallback
return mapping[code] || code.substring(0, 2).toLowerCase()
}
/**
* Get supported languages count
*/
getSupportedLanguagesCount(): number {
return 62 // TinyLD supports 62 languages
}
/**
* Check if a language code is supported
*/
isLanguageSupported(languageCode: string): boolean {
// TinyLD supports 62 languages including Persian (fa)
const supportedCodes = [
'fr', 'en', 'es', 'de', 'fa', 'pt', 'it', 'ru', 'zh',
'ja', 'ko', 'ar', 'hi', 'nl', 'pl', 'tr', 'vi', 'th', 'id'
// ... and 43 more
]
return supportedCodes.includes(languageCode.toLowerCase())
}
}