Skip to content

Плагин i18n

npmJSRJSR Score

Плагин i18n для GramIO.

Этот плагин помогает добавить многоязычность в ваши боты с помощью синтаксиса Fluent.

example

Вы можете настроить типо-безопасность для него.

Плагин i18n для GramIO.

Этот плагин предоставляет удобный способ добавить многоязычность в ваши боты! Его можно использовать без GramIO, но он всегда будет учитывать его особенности.

IMPORTANT

Начиная с версии 1.0.0, у нас есть два способа написания локализации: I18n-in-TS и Fluent

Установка

Для синтаксиса I18n-in-TS

::: pm-add @gramio/i18n :::

Для синтаксиса Fluent

::: pm-add @gramio/i18n @fluent/bundle :::

Синтаксис I18n-in-TS

Этот синтаксис позволяет вам писать локализацию, не выходя из файлов .ts, и не требует генерации кода для типо-безопасности, а также обеспечивает удобную интеграцию с Format API из коробки!

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 покажет ошибку при отсутствии ключей
// 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) => {
        // вы можете взять язык из базы данных или любого другого источника и привязать его к контексту, не теряя типо-безопасности
        return {
            t: i18n.buildT(context.from?.languageCode),
        };
    })
    .on("message", (context) => {
        return context.send(
            context.t("greeting", context.from?.firstName ?? "World")
        );
    });

Множественные числа

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 помогает извлечь типы языков из экземпляра i18n.

ts
type EnLocalization = ExtractLanguages<typeof i18n>["en"];
type EnLocalizationKeys = keyof ExtractLanguages<typeof i18n>["en"];

type EnGreetingArgs = ExtractArgsParams<EnLocalization["greeting"]>;

Синтаксис Fluent

Этот плагин помогает добавить многоязычность в ваши боты с помощью синтаксиса Fluent.

example

Вы можете настроить типо-безопасность для него.

Использование

Создайте папку locales с файлом ru.ftl

ftl
# Простые вещи просты.
hello-user = Привет, {$userName}!

# Сложные вещи возможны.
shared-photos =
    {$userName} {$photoCount ->
        [one] добавил новую фотографию
        [few] добавил {$photoCount} новые фотографии
       *[other] добавил {$photoCount} новых фотографий
    } в {$userGender ->
        [male] свою ленту
        [female] свою ленту
       *[other] свою ленту
    }.

IMPORTANT

Есть расширения с поддержкой языка Fluent для VSCode и WebStorm

Использование плагина

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: "Анна",
                userGender: "female",
                photoCount: 3,
            })
        );
    })
    .onError(console.error)
    .onStart(console.log);

bot.start();

Опции

КлючТипПо умолчаниюОписание
defaultLocale?string"en"Язык по умолчанию
directory?string"locales"Путь к папке с файлами *.ftl
Или предоставьте клиент
ts
import { Bot } from "gramio";
import { getFluentClient, i18n } from "@gramio/i18n/fluent";

// или getFluentClient<TypedFluentBundle>()
const client = getFluentClient({
    defaultLocale: "ru",
    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: "Анна" }));
    });

IMPORTANT

См. Типо-безопасность. Для обеспечения типо-безопасности нужно указать дженерик для getFluentClient.

Методы

t

С помощью этого метода вы можете получить текст на выбранном языке.

Например:

ftl
hello-user = Привет, {$userName}!
ts
context.t("hello-user", { userName: "Анна" }); // Привет, Анна!

setLocale

Вы можете установить язык пользователя методом setLocale.

WARNING

На данный момент нет интеграции с сессиями, поэтому после сообщения язык снова станет таким, какой указан в defaultLocale

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

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

Типо-безопасность

Вы можете использовать этот плагин с fluent2ts, который генерирует типы TypeScript из ваших файлов .ftl. См. инструкцию по использованию.

::: pm-dlx fluent2ts :::

В результате вы получите сгенерированный файл locales.types.ts в папке src, который экспортирует интерфейс TypedFluentBundle. Устанавливаем этот тип как дженерик для плагина i18n - и вот у нас есть типо-безопасность!

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(createFluentClient<TypedFluentBundle>()))
    .extend(i18n<TypedFluentBundle>())
    .command("start", async (context) => {
        const firstMsg = context.t("hello-user");
        //
        //
        //

        const secondMsg = context.t("shared-photos", {
            userName: "Анна",
            userGender: "female",
            photoCount: 3,
        });
        //
        //
        //
        //

        return context.send(secondMsg);
    })
    .onError(console.error)
    .onStart(console.log);

bot.start();