Wiki
猫Localization
Russian version: Localization-RU
Localization in Laniakea is centered around L10n, a small key-based translation store with fallback behavior. It is designed to keep handler code simple: handlers ask for keys, and the bot resolves the best available translation for the current user.
Overview
The localization flow has three main parts:
- create an
L10nstore with a fallback language; - add translation entries keyed by stable identifiers;
- attach the store to the bot with
SetL10n(...).
Inside handlers, the most convenient lookup is ctx.Translate(key).
Creating a localization store
Create the store with NewL10n(fallbackLanguage).
l10n := laniakea.NewL10n("en")
The fallback language is used when:
- the user's language has no translation for the key;
- the user language is unknown but a fallback translation exists.
Adding translations
Translations are stored per key with AddDictEntry(...).
l10n.AddDictEntry("greeting", laniakea.DictEntry{
"en": "Hello",
"ru": "Privet",
})
Each key should represent meaning, not a specific language string. Good keys are stable names such as:
greetingerrors.not_allowedmenu.settings
Avoid using the source-language sentence itself as the key. Stable keys are easier to refactor and reuse.
Fallback behavior
L10n.Translate(lang, key) uses this order:
- exact match for
lang; - fallback language configured in
NewL10n(...); - the key itself.
That means a missing translation degrades predictably instead of returning an empty string.
Example:
l10n := laniakea.NewL10n("en").
AddDictEntry("greeting", laniakea.DictEntry{
"en": "Hello",
"ru": "Privet",
})
l10n.Translate("ru", "greeting") // "Privet"
l10n.Translate("es", "greeting") // "Hello"
l10n.Translate("es", "unknown") // "unknown"
Attaching localization to the bot
After building the store, attach it with Bot.SetL10n(...).
bot.SetL10n(l10n)
From then on:
bot.L10n(lang, key)is available for manual lookups;MessageContext.Translate(key)becomes the ergonomic handler-level helper.
If SetL10n(nil) is called, the bot logs a warning and keeps the existing localization provider unchanged.
MessageContext.Translate
ctx.Translate(key) is the usual choice inside handlers.
It:
- reads the current user's language code from
ctx.From; - falls back to the bot's configured fallback language when needed;
- returns the key itself when no translation is available.
Example:
func start(ctx *laniakea.MessageContext, db *App) error {
ctx.Answer(ctx.Translate("greeting"))
return nil
}
One subtle point:
- if
ctx.Fromisnil,ctx.Translate(key)returns the key directly.
That can happen for some update shapes where there is no user object in context.
Direct lookups with bot.L10n(...)
Use bot.L10n(lang, key) when you need a translation outside handler flow or when the language choice is explicit.
Examples:
- preparing background-runner messages;
- rendering text for stored user preferences;
- translating outside
MessageContext.
Concurrency and mutation safety
L10n is safe for concurrent use.
The implementation protects access with a mutex, so concurrent translation reads and dictionary updates do not require external synchronization.
Also, AddDictEntry(...) copies the provided DictEntry map before storing it. That means later external mutation of your original map does not silently rewrite the localization store.
Organizing dictionaries
For small bots, a single l10n.go or translations.go file is often enough.
For larger bots, a good pattern is:
- keep one section or file per domain, such as
auth,menu,errors,admin; - keep keys stable and descriptive;
- group related translations together;
- use the same key names across all languages.
Example structure:
l10n.
AddDictEntry("menu.start", laniakea.DictEntry{"en": "Start", "ru": "Старт"}).
AddDictEntry("menu.help", laniakea.DictEntry{"en": "Help", "ru": "Помощь"}).
AddDictEntry("errors.denied", laniakea.DictEntry{"en": "Access denied", "ru": "Доступ запрещен"})
Recommendations
- Pick one fallback language and keep it complete.
- Prefer stable semantic keys over sentence-as-key schemes.
- Use
ctx.Translate(...)in handlers unless you have a strong reason to do manual lookup. - Treat missing translations as a documentation problem and keep the fallback language authoritative.
Related pages
- Getting-Started for basic bot setup
- MessageContext for handler helpers
- Recipes for localized handler examples
Navigation
Start here
Runtime and Architecture
- Bot-Lifecycle
- Webhook-Runtime
- Middleware
- Runners
- Error-Handling
- Logging
- Update-Routing-Model
- Policies
- Scenes
Interaction and Telegram API
- Inline-Keyboards-and-Payloads
- Auto-Generated-Commands
- Drafts
- Rich-Messages
- Localization
- Rate-Limiting
- tgapi-Overview