Skip to content

I18n plugin

npmJSRJSR Score

i18n plugin for GramIO.

This plugin provide internationalization for your bots with Fluent syntax.

example

You can setup type-safety for it.

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.

IMPORTANT

Since 1.0.0, we have two ways to write localization: I18n-in-TS and Fluent

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!

ts
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
),
}; }) .
on
("message", (
context
) => {
return
context
.
send
(
context
.
t
("greeting",
context
.
from
?.
firstName
?? "World")
); });

Plurals

ts
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.

ts
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.

example

You can setup type-safety for it.

Usage

Create locales folder with en.ftl file

ftl
# 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
    }.

IMPORTANT

Fluent language support extensions for VSCode and WebStorm

Use plugin

ts
// @moduleResolution: NodeNext
// @module: NodeNext
// 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

KeyTypeDefaultDescription
defaultLocale?string"en"Default locale
directory?string"locales"The path to the folder with *.ftl files

Methods

t

Using this method, you can get the text in your chosen language.

For example:

ftl
hello-user = Hello, {$userName}!
ts
context.t("hello-user", { userName: "Anna" }); // Hello, Anna!

setLocale

You can set user locale by setLocale method.

WARNING

At the moment, there is no integration with sessions, and therefore, after the message, the language will again become the one that defaultLocale

ts
bot.command("start", async (context) => {
    context.setLocale("ru");

    return context.send(
        context.t("shared-photos", {
            userName: "Anna",
            userGender: "female",
            photoCount: 3,
        })
    );
});

Type-safety

You can use this plugin with fluent2ts which code-generates typescript types from your .ftl files. See usage.

Npm:

npm
bash
npx fluent2ts

Bun:

bun
bash
bunx fluent2ts

Yarn:

yarn
bash
yarn dlx fluent2ts

Pnpm:

pnpm
bash
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!

ts
import type { TypedFluentBundle } from "./locales.types.js";
import { 
Bot
} from "gramio";
import {
i18n
} from "@gramio/i18n/fluent";
const
bot
= new
Bot
(
process
.
env
.
BOT_TOKEN
as string)
.
extend
(
i18n
<TypedFluentBundle>())
.
command
("start", async (
context
) => {
const
firstMsg
=
context
.
t
("hello-user");
// // // const
secondMsg
=
context
.
t
("shared-photos", {
userName
: "Anna",
userGender
: "female",
photoCount
: 3,
}); // // // // return
context
.
send
(
secondMsg
);
}) .
onError
(
console
.
error
)
.
onStart
(
console
.
log
);
bot
.
start
();