Skip to content

Плагин i18n

npmJSRJSR Score

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

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

example

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

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

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

IMPORTANT

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

Установка

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

bash
npm install @gramio/i18n
bash
bun add @gramio/i18n
bash
yarn add @gramio/i18n
bash
pnpm add @gramio/i18n

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

bash
npm install @gramio/i18n @fluent/bundle
bash
bun add @gramio/i18n @fluent/bundle
bash
yarn add @gramio/i18n @fluent/bundle
bash
pnpm 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. См. инструкцию по использованию.

Npm:

npm
bash
npx fluent2ts

Bun:

bun
bash
bunx fluent2ts

Yarn:

yarn
bash
yarn dlx fluent2ts

Pnpm:

pnpm
bash
pnpm exec 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
();
t: <"shared-photos">(key: "shared-photos", args: {
    userName: FluentVariable;
    photoCount: FluentVariable;
    userGender: FluentVariable;
}) => string (+1 overload)

Format a Pattern to a string.

Format a raw Pattern into a string. args will be used to resolve references to variables passed as arguments to the translation.

In case of errors formatPattern will try to salvage as much of the translation as possible and will still return a string. For performance reasons, the encountered errors are not returned but instead are appended to the errors array passed as the third argument.

If errors is omitted, the first encountered error will be thrown.

@example
let errors = [];
bundle.addResource(
    new FluentResource("hello = Hello, {$name}!"));

let hello = bundle.getMessage("hello");
if (hello.value) {
    bundle.formatPattern(hello.value, {name: "Jane"}, errors);
    // Returns "Hello, Jane!" and `errors` is empty.

    bundle.formatPattern(hello.value, undefined, errors);
    // Returns "Hello, {$name}!" and `errors` is now:
    // [<ReferenceError: Unknown variable: name>]
}