UNPKG

bhashantarh

Version:

Tiny translation wrapper with fallbacks (LibreTranslate -> MyMemory) and detection with franc fallback.

125 lines (101 loc) 3.28 kB
const axios = require('axios'); const getSupportedLanguages = require('./supportedLanguages'); const { iso3ToIso1 } = require('./supportedLanguages'); const FALLBACK_URL = 'https://libretranslate.de'; // Lazy-load franc-min for CJS let cachedFranc = null; async function getFranc() { if (cachedFranc) return cachedFranc; try { const mod = await import('franc-min'); cachedFranc = mod.franc; return cachedFranc; } catch (e) { console.error('Failed to load franc-min:', e.message); return null; } } // Script-based guess function guessByScript(text) { const ranges = { hi: /[\u0900-\u097F]/, mr: /[\u0900-\u097F]/, bn: /[\u0980-\u09FF]/, gu: /[\u0A80-\u0AFF]/, ta: /[\u0B80-\u0BFF]/, te: /[\u0C00-\u0C7F]/, ml: /[\u0D00-\u0D7F]/, ar: /[\u0600-\u06FF]/, ur: /[\u0600-\u06FF]/, ru: /[\u0400-\u04FF]/, zh: /[\u4E00-\u9FFF]/, ja: /[\u3040-\u309F\u30A0-\u30FF]/ }; const priority = ['zh', 'ja', 'ru', 'ar', 'ur', 'bn', 'gu', 'ta', 'te', 'ml', 'hi', 'mr']; for (const code of priority) { if (ranges[code]?.test(text)) return code; } return null; } async function tryLibreDetect(text) { const res = await axios.post(`${FALLBACK_URL}/detect`, { q: text }, { headers: { 'Content-Type': 'application/json' }, timeout: 8000 }); if (Array.isArray(res.data) && res.data[0]?.language) { return res.data[0].language; } return 'unknown'; } function isSupported(code) { return !!getSupportedLanguages()[code]; } async function detectLanguage(text) { const cleaned = (text || '').replace(/[0-9]/g, '').trim(); // 1) Try LibreTranslate.de try { const lt = await tryLibreDetect(cleaned); if (lt && isSupported(lt)) return lt; } catch (err) { console.error('LibreTranslate.de detect error:', err.message); } // add near the top, below guessByScript() function guessLatinByCommonWords(text) { if (!text) return null; const t = text.toLowerCase(); // Spanish if (/\bhola\b/.test(t) || /\bamigo(s)?\b/.test(t) || /\b¿?c(ó|o)mo\b/.test(t)) return 'es'; // French if (/\bbonjour\b/.test(t) || /\bsalut\b/.test(t) || /\bmerci\b/.test(t)) return 'fr'; // Italian if (/\bciao\b/.test(t) || /\bgrazie\b/.test(t)) return 'it'; // Portuguese if (/\bol[áa]\b/.test(t) || /\bobrigado(a)?\b/.test(t)) return 'pt'; // German if (/\bhallo\b/.test(t) || /\bdanke\b/.test(t)) return 'de'; // English if (/\bhello\b/.test(t) || /\bhi\b/.test(t) || /\bthanks\b/.test(t)) return 'en'; return null; } // 2) Script guess const scriptGuess = guessByScript(cleaned); if (scriptGuess && isSupported(scriptGuess)) return scriptGuess; // 2.5) Latin common-words guess (helps short phrases like "Hola amigo") const latinGuess = guessLatinByCommonWords(cleaned); if (latinGuess && isSupported(latinGuess)) return latinGuess; // 3) franc-min try { const franc = await getFranc(); if (franc) { const iso3 = franc(cleaned, { minLength: 1 }); if (iso3 && iso3 !== 'und') { const iso1 = iso3ToIso1(iso3); if (iso1 && isSupported(iso1)) return iso1; } } } catch (e) { console.error('franc detect error:', e.message); } return 'unknown'; } module.exports = detectLanguage;