translate¶
Multi-language translation with provider fallback, per-user language preferences, and daily usage limits.
File: Libs/translate.js · Access: Libs.translate.* · Async — always await · v1.0.0
What problem does it solve?¶
Bots serving international users need:
- Translate bot messages to the user's language
- Let users pick their language
- Fall back when one API is down
- Respect free-tier limits (MyMemory daily quota)
translate chains providers automatically: Google → MyMemory → Lingva → LibreTranslate.
Storage keys¶
| Key | Scope | Purpose |
|---|---|---|
user_lang | db.user | User's language code (e.g. "hi") |
translate_daily_usage | db.bot | { date, words } for MyMemory quota |
Supported languages¶
Built-in codes: en, hi, es, fr, de, it, pt, ru, ja, ko, zh, ar, bn, tr, vi, id, uk, pl, nl, th
Libs.translate.getSupportedLanguages() // { en: "English", hi: "Hindi", ... }
Libs.translate.listLanguages() // [{ code, name }, ...] sorted
Libs.translate.langName("hi") // "Hindi"
Libs.translate.isSupported("xx") // false
Quick start¶
// Save preference
await Libs.translate.setUserLang(user.id, "hi")
// Translate using saved lang (pass userId or rely on current user context)
let text = await Libs.translate.translate("Welcome to our bot!")
// or explicit target
let text2 = await Libs.translate.translate("Hello", { to: "es" })
// Shorthand
let text3 = await Libs.translate.t("Good morning", "fr")
Main translation APIs¶
translate(text, options) — throws on failure¶
try {
let msg = await Libs.translate.translate(params.text, {
to: "de",
from: "auto",
fallback: "Translation unavailable"
})
Bot.sendMessage(msg)
} catch (e) {
Bot.sendMessage("Could not translate.")
}
tryTranslate(text, options) — never throws¶
Returns:
{
ok: true,
text: "Hola",
provider: "google",
from: "auto",
to: "es",
words: 1
}
// or on failure
{
ok: false,
text: "Hello",
error: "All providers failed",
fallback: undefined,
from: "auto",
to: "es"
}
let result = await Libs.translate.tryTranslate("Hello world", { to: "hi" })
if (result.ok) {
Bot.sendMessage(result.text + " (via " + result.provider + ")")
} else {
Bot.sendMessage("Error: " + result.error)
}
Options¶
| Option | Default | Description |
|---|---|---|
to | user lang or "en" | Target language code |
from | "auto" | Source language |
userId | current user | Whose saved lang to use for to |
fallback | — | Return this string if all providers fail |
silent | false | On failure, return original text instead of throwing |
You can also pass a string as second arg: translate("Hi", "es") → { to: "es" }.
User language¶
await Libs.translate.setUserLang(user.id, "hi")
let lang = await Libs.translate.getUserLang(user.id) // "hi"
// Translate automatically to user's language
let welcome = await Libs.translate.translate("Welcome back!", { userId: user.id })
Usage limits¶
MyMemory has a daily word limit (default 1000 words/day, bot-wide).
let info = await Libs.translate.getUsageInfo()
// { wordsUsed, wordsRemaining, limit, resetDate, percentUsed }
let check = await Libs.translate.canTranslate("Long message here...")
// { ok: true/false, words: N, remaining: N }
await Libs.translate.resetUsage() // admin — reset counter
When MyMemory quota is exceeded, the provider chain skips MyMemory and tries Lingva/Libre.
Configure limits:
Libs.translate.configure({
dailyLimit: 2000,
maxLength: 500,
timeout: 10000,
providers: ["google", "lingva", "libre"], // skip mymemory
cfProxy: true // if needed for HTTP
})
Language picker UI¶
// /language command
let rows = Libs.translate.langButtons({
perRow: 2,
prefix: "lang_",
codes: ["en", "hi", "es", "fr", "de"] // optional subset
})
await Api.sendMessage({
text: "Choose your language:",
reply_markup: { inline_keyboard: rows }
})
Callback handler:
let code = Libs.translate.parseLangCallback(callback_data, "lang_")
if (code) {
await Libs.translate.setUserLang(user.id, code)
Bot.sendMessage("Language set to " + Libs.translate.langName(code))
}
Display all languages as text:
Batch translation¶
Translates sequentially (respects rate limits):
let lines = ["Hello", "Goodbye", "Thank you"]
let results = await Libs.translate.batch(lines, { to: "ja" })
for (let i = 0; i < results.length; i++) {
if (results[i].ok) {
Bot.sendMessage(lines[i] + " → " + results[i].text)
}
}
Stats bundle¶
let profile = await Libs.translate.stats(user.id)
// {
// lang: "hi",
// langName: "Hindi",
// usage: { wordsUsed, wordsRemaining, limit, resetDate, percentUsed }
// }
Full example — localized bot messages¶
// Helper in your command
async function say(text) {
let translated = await Libs.translate.tryTranslate(text, {
userId: user.id,
silent: true
})
Bot.sendMessage(translated.text)
}
await say("Your balance has been updated.")
await say("Daily bonus is ready!")
Full example — translate user input to English for moderation¶
let mod = await Libs.translate.tryTranslate(params, {
to: "en",
from: "auto"
})
if (mod.ok) {
await Api.sendMessage({
chat_id: adminChatId,
text: "User said: " + mod.text + " (from " + mod.from + ")"
})
}
Legacy¶
| Old | New |
|---|---|
autoTranslate(text, lang) | translate(text, { to: lang }) |
Common mistakes¶
// Wrong — translate throws and breaks command
Bot.sendMessage(await Libs.translate.translate(longText))
// Correct — pre-check length or use tryTranslate
let r = await Libs.translate.tryTranslate(longText, { to: "hi", silent: true })
Bot.sendMessage(r.text)
// Wrong — forgot setUserLang before relying on user preference
await Libs.translate.translate("Hi") // always uses default "en" for new users
// Correct — set on /start or language picker first
await Libs.translate.setUserLang(user.id, "hi")
Notes¶
- Max text length default 500 characters — configure with
maxLength. - Skips translation when target equals source or text looks English going to
en. - Uses
HTTPwithresponseType: "json"and checksres.ok. clearCache()resets in-command usage/lang session cache.