Skip to main content
Home

Built and signed on GitHub Actions

i18n plugin for GramIO. This plugin provide internationalization for your bots with Fluent syntax.

This package works with Node.js, Deno, BunIt is unknown whether this package works with Cloudflare Workers, Browsers
It is unknown whether this package works with Cloudflare Workers
This package works with Node.js
This package works with Deno
This package works with Bun
It is unknown whether this package works with Browsers
JSR Score
47%
Published
4 months ago (1.3.0)

@gramio/i18n

npm npm downloads JSR JSR Score

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

Installation

For I18n-in-TS syntax

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.

example

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
    }.
Important

Fluent language support extensions for VSCode and WebStorm

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.

Warning

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();
Built and signed on
GitHub Actions

New Ticket: Report package

Please provide a reason for reporting this package. We will review your report and take appropriate action.

Please review the JSR usage policy before submitting a report.

Add Package

deno add jsr:@gramio/i18n

Import symbol

import * as i__n from "@gramio/i18n";
or

Import directly with a jsr specifier

import * as i__n from "jsr:@gramio/i18n";

Add Package

pnpm i jsr:@gramio/i18n
or (using pnpm 10.8 or older)
pnpm dlx jsr add @gramio/i18n

Import symbol

import * as i__n from "@gramio/i18n";

Add Package

yarn add jsr:@gramio/i18n
or (using Yarn 4.8 or older)
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";