Skip to content

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:

Bot.sendMessage(Libs.translate.formatLangList("•"))
// • Arabic (ar)
// • Bengali (bn)
// ...

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 HTTP with responseType: "json" and checks res.ok.
  • clearCache() resets in-command usage/lang session cache.