Built and signed on GitHub ActionsBuilt and signed on GitHub Actions
i18n plugin for GramIO. This plugin provide internationalization for your bots with Fluent syntax.
@gramio/i18n
i18n
plugin for GramIO.
This plugin provide good way to add internationalization for your bots! It can be used without GramIO, but it will always keep it in mind.
Since 1.0.0
, we have two ways to write localization: I18n-in-TS
and Fluent
Installation
npm install @gramio/i18n
For Fluent syntax
npm install @gramio/i18n @fluent/bundle
I18n-in-TS syntax
This syntax allows you to write localization without leaving .ts
files and does not require code-generation for type-safety, as well as provides convenient integration with the Format API out of the box!
import { format, Bot } from "gramio"; import { defineI18n, type LanguageMap, type ShouldFollowLanguage, } from "@gramio/i18n"; const en = { greeting: (name: string) => format`Hello, ${name}!`, and: { some: { nested: "Hi!!!", }, }, } satisfies LanguageMap; const ru = { greeting: (name: string) => format`Привет, ${name}!`, and: { some: { nested: "Hi!!!", }, }, } satisfies ShouldFollowLanguage<typeof en>; // Strict will show error on missing keys // satisfies ShouldFollowLanguageStrict<typeof en>; const i18n = defineI18n({ primaryLanguage: "en", languages: { en, ru, }, }); i18n.t("en", "greeting", "World"); // Hello, World! i18n.t("en", "and.some.nested"); // Hi!!! const bot = new Bot(process.env.BOT_TOKEN as string) .derive("message", (context) => { // u can take language from database or whatever u want and bind it to context without loosing type-safety return { t: i18n.buildT(context.from?.languageCode ?? "en"), }; }) .on("message", (context) => { return context.send( context.t("greeting", context.from?.firstName ?? "World") ); });
Plurals
import { pluralizeEnglish, pluralizeRussian } from "@gramio/i18n"; const count = 5; console.log(`You have ${count} ${pluralizeEnglish(count, "apple", "apples")}.`); // You have 5 apples. console.log( `У вас ${count} ${pluralizeRussian(count, "яблоко", "яблока", "яблок")}.` ); // У вас 5 яблок.
ExtractLanguages
helps you extract languages types from i18n instance.
type EnLocalization = ExtractLanguages<typeof i18n>["en"]; type EnLocalizationKeys = keyof ExtractLanguages<typeof i18n>["en"]; type EnGreetingArgs = ExtractArgsParams<EnLocalization["greeting"]>;
Fluent syntax
This plugin provide internationalization for your bots with Fluent syntax.
You can setup type-safety for it.
Usage
Create locales
folder with en.ftl
file
# Simple things are simple. hello-user = Hello, {$userName}! # Complex things are possible. shared-photos = {$userName} {$photoCount -> [one] added a new photo *[other] added {$photoCount} new photos } to {$userGender -> [male] his stream [female] her stream *[other] their stream }.
Use plugin
// src/index.ts import { Bot } from "gramio"; import { i18n } from "@gramio/i18n/fluent"; const bot = new Bot(process.env.BOT_TOKEN as string) .extend(i18n()) .command("start", async (context) => { return context.send( context.t("shared-photos", { userName: "Anna", userGender: "female", photoCount: 3, }) ); }) .onError(console.error) .onStart(console.log); bot.start();
Options
Key | Type | Default | Description |
---|---|---|---|
defaultLocale? | string | first loaded language | Default locale |
directory? | string | "locales" | The path to the folder with *.ftl files |
Or provide an client
// ... import { getFluentClient, i18n } from "@gramio/i18n/fluent"; const client = getFluentClient({ defaultLocale: "en", directory: "locales", }); const bot = new Bot(process.env.BOT_TOKEN as string) .extend(i18n(client)) .command("start", async (context) => { return context.send(context.t("hello-user", { userName: "Anna" })); });
Methods
t
Using this method, you can get the text in your chosen language.
For example:
hello-user = Hello, {$userName}!
context.t("hello-user", { userName: "Anna" }); // Hello, Anna!
i18n.setLocale
You can set user locale by setLocale
method.
At the moment, there is no integration with sessions, and therefore, after the message, the language will again become the one that defaultLocale
bot.command("start", async (context) => { context.i18n.setLocale("ru"); // if ru not found fallback to defaultLocale // context.i18n.setLocale("ru", true); if ru not found throw error return context.send( context.t("shared-photos", { userName: "Anna", userGender: "female", photoCount: 3, }) ); });
i18n.locale
Get current user locale.
bot.command("lang", async (context) => { return context.send(context.i18n.locale); });
i18n.locales
Get loaded locales
bot.command("languages", async (context) => { return context.send(context.i18n.locales.join(", ")); });
Type-safety
You can use this plugin with fluent2ts which code-generates typescript types from your .ftl
files.
See usage.
Npm:
npx fluent2ts
Bun:
bunx fluent2ts
Yarn:
yarn dlx fluent2ts
Pnpm:
pnpm exec fluent2ts
And so we have a generated locales.types.ts
file in src
folder that exports the TypedFluentBundle
interface.
We set this type as a generic for the i18n
plugin. And now we have type-safety!
import type { TypedFluentBundle } from "./locales.types"; import { Bot } from "gramio"; import { i18n } from "@gramio/i18n/fluent"; const bot = new Bot(process.env.BOT_TOKEN as string) // or i18n(getFluentClient<TypedFluentBundle>()) .extend(i18n<TypedFluentBundle>()) .command("start", async (context) => { return context.send( context.t("shared-photos", { userName: "Anna", userGender: "female", photoCount: 3, }) ); }) .onError(console.error) .onStart(console.log); bot.start();
Add Package
deno add jsr:@gramio/i18n
Import symbol
import * as i__n from "@gramio/i18n";
Import directly with a jsr specifier
import * as i__n from "jsr:@gramio/i18n";
Add Package
pnpm i jsr:@gramio/i18n
pnpm dlx jsr add @gramio/i18n
Import symbol
import * as i__n from "@gramio/i18n";
Add Package
yarn add jsr:@gramio/i18n
yarn dlx jsr add @gramio/i18n
Import symbol
import * as i__n from "@gramio/i18n";
Add Package
vlt install jsr:@gramio/i18n
Import symbol
import * as i__n from "@gramio/i18n";
Add Package
npx jsr add @gramio/i18n
Import symbol
import * as i__n from "@gramio/i18n";
Add Package
bunx jsr add @gramio/i18n
Import symbol
import * as i__n from "@gramio/i18n";