Інтернаціоналізація (i18n
)
Плагін інтернаціоналізації дозволяє вашому боту розмовляти кількома мовами.
Не плутайте
Не плутайте це з fluent.
Цей плагін є покращеною версією fluent, яка працює на Deno та Node.js.
Пояснення інтернаціоналізації
У цьому розділі пояснюється, що таке інтернаціоналізація, навіщо вона потрібна, що в ній складного, як вона повʼязана з локалізацією й навіщо для всього цього потрібен плагін. Якщо ви вже знаєте це, прокрутіть до початку роботи.
По-перше, “internationalization” — дуже довге слово. Тому люди полюбляють писати першу й останню літеру: “i” та “n” відповідно. Потім вони рахують усі літери, що залишилися: “nternationalizatio” (18 літер), і ставлять це число між “i” та “n”, отримуючи в результаті i18n. Не питайте нас чому. Отже, i18n — це просто дивна абревіатура слова “internationalization” (інтернаціоналізація).
Те саме робиться зі словом “localization” (локалізація), яке перетворюється на l10n.
Що таке локалізація?
Локалізація означає створення бота, який може розмовляти кількома мовами. Він повинен автоматично підлаштовувати свою мову під мову користувача.
Локалізувати потрібно не лише мову. Ви також можете врахувати культурні відмінності або інші стандарти: наприклад, формати дати й часу. Ось ще кілька прикладів речей, які відрізняються у різних країнах світу:
- Дати
- Час
- Числа
- Одиниці вимірювання
- Множинність
- Статі
- Переноси
- Великі літери
- Вирівнювання
- Символи та іконки
- Сортування
… тощо.
Всі ці речі разом визначають локаль користувача. Локалі часто отримують двобуквені коди: наприклад, en
для англійської, de
для німецької, uk
для української тощо. Якщо ви хочете дізнатися код вашої локалі, перегляньте цей список.
Що таке інтернаціоналізація?
У двох словах, інтернаціоналізація означає написання коду, який може підлаштовуватися під локаль користувача. Інакше кажучи, інтернаціоналізація — це те, що дозволяє здійснювати локалізацію (дивіться вище). Це означає, що хоча ваш бот фактично працює однаково для всіх, конкретні повідомлення, які він надсилає, відрізняються від користувача до користувача, тому бот може розмовляти різними мовами.
Ви здійснюєте інтернаціоналізацію, якщо не жорстко прописуєте в коді тексти, які надсилає ваш бот, а динамічно зчитуєте їх з файлу. Ви здійснюєте інтернаціоналізацію, якщо не жорстко прописуєте в коді спосіб представлення дат і часу, а використовуєте бібліотеку, яка адаптує ці значення відповідно до різних стандартів. Ви зрозуміли ідею: не варто жорстко прописувати в коді те, що має змінюватися залежно від місця проживання користувача або мови, якою він розмовляє.
Навіщо потрібен цей плагін?
Цей плагін може допомогти вам протягом усього процесу інтернаціоналізації. Він базується на Fluent — системі локалізації від Mozilla. Ця система має дуже потужний і вишуканий синтаксис, який дозволяє ефективно створювати переклади з природнім звучанням.
По суті, ви можете витягти те, що має адаптуватися до локалі користувача, у текстові файли, які ви додаєте до вашого коду. Потім ви можете використовувати цей плагін для завантаження цих локалізацій. Плагін автоматично визначить локаль користувача та вибере для вашого бота правильну мову для спілкування.
Нижче ми будемо називати ці текстові файли файлами перекладу. Вони повинні відповідати синтаксису Fluent.
Початок роботи
У цьому розділі описано, як налаштувати структуру вашого проєкту і де зберігати файли перекладу. Якщо ви знайомі з цим, пропустіть цей розділ, щоб дізнатися, як встановити і використовувати плагін.
Існує кілька способів додати більше мов до вашого бота. Найпростіший спосіб — створити каталог з файлами перекладів для Fluent. Зазвичай цей каталог називається locales
. Файли перекладу повинні мати розширення .ftl
(fluent).
Ось приклад структури проєкту:
.
├── bot.ts
└── locales/
├── de.ftl
├── en.ftl
├── it.ftl
└── uk.ftl
Якщо ви не знайомі з синтаксисом Fluent, ви можете прочитати їхній посібник: https://
Ось приклад файлу перекладу для української мови, який називається locales
:
start = Привіт, чим я можу вам допомогти (/help)?
help =
Надішліть мені текст, і я зроблю його жирним для вас.
Ви можете змінити мою мову за допомогою команди /language.
2
3
4
Англійський еквівалент називатиметься locales
і виглядатиме наступним чином:
start = Hi, how can I /help you?
help =
Send me some text, and I can make it bold for you.
You can change my language using the /language command.
2
3
4
Тепер ви можете використовувати ці переклади у своєму боті за допомогою плагіна. Він зробить їх доступними через ctx
:
bot.command("start", async (ctx) => {
await ctx.reply(ctx.t("start"));
});
bot.command("help", async (ctx) => {
await ctx.reply(ctx.t("help"));
});
2
3
4
5
6
7
Щоразу, коли ви викликаєте ctx
, локаль поточного обʼєкта контексту ctx
використовується для пошуку правильного перекладу. Пошук правильного перекладу здійснюється за допомогою узгоджувача локалі. У найпростішому випадку він просто повертає ctx
.
У результаті користувачі з різними локалями зможуть читати повідомлення кожен своєю мовою.
Використання
Плагін визначає локаль користувача з багатьох різних факторів. Одним з них є ctx
, який буде надано клієнтом користувача.
Однак, існує багато інших способів визначення локалі користувача. Наприклад, ви можете зберігати локаль користувача у вашій сесії. Отже, існує два основних способи використання цього плагіна: з сесіями та без сесій.
Без сесій
Плагін простіше використовувати і налаштовувати без сесій. Його основним недоліком буде те, що ви не зможете зберігати мови, які обирають користувачі.
Як було сказано вище, локаль, яка буде використовуватися для користувача, буде визначатися за допомогою ctx
, який надходить від клієнта користувача. Але якщо у вас немає перекладу цієї мови, буде використано мову за замовчуванням. Іноді ваш бот може не бачити бажану мову користувача, надану його клієнтом, тому в цьому випадку також буде використано мову за замовчуванням.
ctx
буде доступним лише в тому випадку, якщо користувач раніше починав приватну розмову з вашим ботом.
import { Bot, Context } from "grammy";
import { I18n, I18nFlavor } from "@grammyjs/i18n";
// Для підтримки TypeScript та автодоповнення
// розширимо контекст за допомогою розширювача для контексту з плагіну i18n:
type MyContext = Context & I18nFlavor;
// Створюємо бота, як ми зазвичай це робимо.
// Не забуваємо розширити контекст.
const bot = new Bot<MyContext>("");
// Створюємо екземпляр`I18n`.
// Продовжуйте читати, щоб дізнатися, як налаштувати екземпляр.
const i18n = new I18n<MyContext>({
defaultLocale: "uk", // дивіться нижче для отримання додаткової інформації
directory: "locales", // завантажуємо всі файли перекладу з каталогу locales/
});
// Нарешті, реєструємо екземпляр i18n у боті,
// щоб повідомлення перекладалися!
bot.use(i18n);
// Зараз все налаштовано.
// Можемо отримати доступ до перекладів за допомогою `t` або `translate`.
bot.command("start", async (ctx) => {
await ctx.reply(ctx.t("start-msg"));
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const { Bot } = require("grammy");
const { I18n } = require("@grammyjs/i18n");
// Створюємо бота, як ми зазвичай це робимо.
const bot = new Bot("");
// Створюємо екземпляр`I18n`.
// Продовжуйте читати, щоб дізнатися, як налаштувати екземпляр.
const i18n = new I18n({
defaultLocale: "uk", // дивіться нижче для отримання додаткової інформації
directory: "locales", // завантажуємо всі файли перекладу з каталогу locales/
});
// Нарешті, реєструємо екземпляр i18n у боті,
// щоб повідомлення перекладалися!
bot.use(i18n);
// Зараз все налаштовано.
// Можемо отримати доступ до перекладів за допомогою `t` або `translate`.
bot.command("start", async (ctx) => {
await ctx.reply(ctx.t("start-msg"));
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Bot, Context } from "https://deno.land/x/grammy@v1.30.0/mod.ts";
import { I18n, I18nFlavor } from "https://deno.land/x/grammy_i18n@v1.1.0/mod.ts";
// Для підтримки TypeScript та автодоповнення
// розширимо контекст за допомогою розширювача для контексту з плагіну i18n:
type MyContext = Context & I18nFlavor;
// Створюємо бота, як ми зазвичай це робимо.
// Не забуваємо розширити контекст.
const bot = new Bot<MyContext>("");
// Створюємо екземпляр`I18n`.
// Продовжуйте читати, щоб дізнатися, як налаштувати екземпляр.
const i18n = new I18n<MyContext>({
defaultLocale: "uk", // дивіться нижче для отримання додаткової інформації
// Завантажуємо всі файли перекладу з каталогу locales/, але це не спрацює у Deno Deploy.
directory: "locales",
});
// Завантажені наступним чином файли перекладу працюватимуть й у Deno Deploy.
// await i18n.loadLocalesDir("locales");
// Нарешті, реєструємо екземпляр i18n у боті,
// щоб повідомлення перекладалися!
bot.use(i18n);
// Зараз все налаштовано.
// Можемо отримати доступ до перекладів за допомогою `t` або `translate`.
bot.command("start", async (ctx) => {
await ctx.reply(ctx.t("start-msg"));
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ctx
повертає перекладений текст для вказаного ключа. Вам не потрібно турбуватися про мову, оскільки плагін вибере її автоматично.
Вітаємо! Ваш бот тепер розмовляє кількома мовами! 🌍🎉
З сесіями
Припустимо, що ваш бот має команду /language
. Загалом, у grammY ми можемо використовувати сесії для зберігання даних користувачів кожного чату. Щоб ваш екземпляр інтернаціоналізації знав, що сесії увімкнено, ви маєте встановити use
у значення true
в параметрах I18n
.
Ось приклад з простою командою /language
:
import { Bot, Context, session, SessionFlavor } from "grammy";
import { I18n, I18nFlavor } from "@grammyjs/i18n";
interface SessionData {
__language_code?: string;
}
type MyContext = Context & SessionFlavor<SessionData> & I18nFlavor;
const bot = new Bot<MyContext>("");
const i18n = new I18n<MyContext>({
defaultLocale: "uk",
useSession: true, // чи зберігати мову користувача у сесії
directory: "locales", // завантажуємо всі файли перекладу з каталогу locales/
});
// Не забуваємо зареєструвати проміжний обробник `session`
// перед реєстрацією проміжного обробника екземпляра i18n.
bot.use(
session({
initial: () => {
return {};
},
}),
);
// Реєструємо проміжний обробник i18n.
bot.use(i18n);
bot.command("start", async (ctx) => {
await ctx.reply(ctx.t("greeting"));
});
bot.command("language", async (ctx) => {
if (ctx.match === "") {
return await ctx.reply(ctx.t("language.specify-a-locale"));
}
// `i18n.locales` містить всі локалі, які були зареєстровані
if (!i18n.locales.includes(ctx.match)) {
return await ctx.reply(ctx.t("language.invalid-locale"));
}
// `ctx.i18n.getLocale` повертає локаль, яка наразі використовується.
if ((await ctx.i18n.getLocale()) === ctx.match) {
return await ctx.reply(ctx.t("language.already-set"));
}
await ctx.i18n.setLocale(ctx.match);
await ctx.reply(ctx.t("language.language-set"));
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const { Bot, session } = require("grammy");
const { I18n } = require("@grammyjs/i18n");
const bot = new Bot("");
const i18n = new I18n({
defaultLocale: "uk",
useSession: true, // чи зберігати мову користувача у сесії
directory: "locales", // завантажуємо всі файли перекладу з каталогу locales/
});
// Не забуваємо зареєструвати проміжний обробник `session`
// перед реєстрацією проміжного обробника екземпляра i18n.
bot.use(
session({
initial: () => {
return {};
},
}),
);
// Реєструємо проміжний обробник i18n.
bot.use(i18n);
bot.command("start", async (ctx) => {
await ctx.reply(ctx.t("greeting"));
});
bot.command("language", async (ctx) => {
if (ctx.match === "") {
return await ctx.reply(ctx.t("language.specify-a-locale"));
}
// `i18n.locales` містить всі локалі, які були зареєстровані
if (!i18n.locales.includes(ctx.match)) {
return await ctx.reply(ctx.t("language.invalid-locale"));
}
// `ctx.i18n.getLocale` повертає локаль, яка наразі використовується.
if ((await ctx.i18n.getLocale()) === ctx.match) {
return await ctx.reply(ctx.t("language.already-set"));
}
await ctx.i18n.setLocale(ctx.match);
await ctx.reply(ctx.t("language.language-set"));
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import {
Bot,
Context,
session,
SessionFlavor,
} from "https://deno.land/x/grammy@v1.30.0/mod.ts";
import { I18n, I18nFlavor } from "https://deno.land/x/grammy_i18n@v1.1.0/mod.ts";
interface SessionData {
__language_code?: string;
}
type MyContext = Context & SessionFlavor<SessionData> & I18nFlavor;
const bot = new Bot<MyContext>("");
const i18n = new I18n<MyContext>({
defaultLocale: "uk",
useSession: true, // чи зберігати мову користувача у сесії
// НЕ працюватиме у Deno Deploy
directory: "locales",
});
// Завантажені наступним чином файли перекладу працюватимуть й у Deno Deploy.
// await i18n.loadLocalesDir("locales");
// Не забуваємо зареєструвати проміжний обробник `session`
// перед реєстрацією проміжного обробника екземпляра i18n.
bot.use(
session({
initial: () => {
return {};
},
}),
);
// Реєструємо проміжний обробник i18n.
bot.use(i18n);
bot.command("start", async (ctx) => {
await ctx.reply(ctx.t("greeting"));
});
bot.command("language", async (ctx) => {
if (ctx.match === "") {
return await ctx.reply(ctx.t("language.specify-a-locale"));
}
// `i18n.locales` містить всі локалі, які були зареєстровані
if (!i18n.locales.includes(ctx.match)) {
return await ctx.reply(ctx.t("language.invalid-locale"));
}
// `ctx.i18n.getLocale` повертає локаль, яка наразі використовується.
if ((await ctx.i18n.getLocale()) === ctx.match) {
return await ctx.reply(ctx.t("language.already-set"));
}
await ctx.i18n.setLocale(ctx.match);
await ctx.reply(ctx.t("language.language-set"));
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Коли сесії увімкнено, під час вибору мови буде використовуватися властивість _
у сесії замість ctx
, яка надається клієнтом Telegram. Коли ваш бот надсилає повідомлення, локаль вибирається з ctx
.
Існує метод set
, за допомогою якого ви можете встановити потрібну мову. Він збереже це значення у вашій сесії.
await ctx.i18n.setLocale("de");
Це еквівалентно ручному налаштуванню сесії, а потім повторному узгодженню локалі:
ctx.session.__language_code = "de";
await ctx.i18n.renegotiateLocale();
2
Узгодження локалі
Якщо ви використовуєте сесії або щось інше, крім ctx
для вибору власної локалі для користувача, існують ситуації, коли ви можете змінити мову під час обробки оновлення. Наприклад, погляньте на наведений вище приклад з використанням сесій.
Якщо ви зробите лише це
ctx.session.__language_code = "de";
то поточна локаль в екземплярі I18n
не оновиться. Натомість буде оновлено виключно сесію. Отже, зміни відбудуться лише при наступному оновленні.
Якщо ви не можете почекати до наступного оновлення, вам може знадобитися оновити зміни після оновлення локалі користувача. У таких випадках використовуйте метод renegotiate
.
ctx.session.__language_code = "de";
await ctx.i18n.renegotiateLocale();
2
Після цього щоразу, коли ми використовуватимемо метод t
, бот намагатиметься відповісти німецьким перекладом цього повідомлення, вказаним у файлі locales
.
Також памʼятайте, що якщо ви використовуєте вбудовані сесії, ви можете досягти того ж результату за допомогою методу set
.
Встановлення локалі, коли сесії не використовуються
У випадку без використання сесій, якщо вам потрібно встановити локаль для користувача, ви можете зробити це за допомогою методу use
.
await ctx.i18n.useLocale("de");
Встановлює вказану локаль, яка буде використовуватися для майбутніх перекладів. Ефект діє лише під час поточного оновлення, тому не зберігається. Ви можете використовувати цей метод для зміни локалі перекладу посеред оновлення: наприклад, коли користувач змінює мову.
Власне узгодження локалі
Ви можете використовувати параметр locale
, щоб вказати власного узгоджувача локалі. Цей параметр корисний, якщо ви хочете вибрати локаль на основі зовнішніх джерел: наприклад, баз даних, або в інших ситуаціях, коли ви хочете контролювати, яку локаль буде використано.
Нижче наведено типовий порядок, у якому плагін обирає локаль:
Якщо сесії увімкнено, спробує зчитати
_
із сесії. Якщо він повертає правильну локаль, її буде використано. Якщо нічого не буде отримано або локаль буде незареєстрованою, переходить до 2-го кроку._language _code Спробує зчитати з
ctx
. Якщо він повертає правильну локаль, її буде використано. Якщо нічого не буде отримано або локаль буде незареєстрованою, переходить до 3-го кроку..from .language _code Зверніть увагу, що
ctx
доступний лише якщо користувач запустив бота. Це означає, що якщо бот побачить користувача у групі або будь-де, але користувач не запустив бота, він не отримає доступ до.from .language _code ctx
..from .language _code Спробує використати мову за замовчуванням, задану в параметрах
I18n
. Якщо встановлена правильна локаль, її буде використано. Якщо вона не вказана або вказана локаль незареєстрована, переходить до 4-го кроку.Спробує використати англійську (
en
). Плагін сам встановлює цю локаль як резервну. Хоча це резервна локаль, і ми рекомендуємо мати переклад, це не є обовʼязковою вимогою. Якщо англійська локаль не передбачена, перейде до 5-го кроку.Якщо все вищезазначене не спрацювало, використає
{ідентифікатор}
замість перекладу. Ми наполегливо рекомендуємо встановити локаль, яка існує серед ваших перекладів, якdefault
у параметрахLocale I18n
.
Узгодження локалі
Узгодження локалі відбувається лише один раз під час обробки оновлення Telegram, як правило. Однак ви можете запустити ctx
, щоб знову викликати узгоджувача і визначити нову локаль. Це корисно, якщо локаль змінюється під час обробки одного оновлення.
Ось приклад locale
, де ми використовуємо locale
з сесії замість _
. У цьому випадку вам не потрібно встановлювати use
у значення true
у параметрах I18n
.
const i18n = new I18n<MyContext>({
localeNegotiator: (ctx) =>
ctx.session.locale ?? ctx.from?.language_code ?? "uk",
});
2
3
4
const i18n = new I18n({
localeNegotiator: (ctx) =>
ctx.session.locale ?? ctx.from?.language_code ?? "uk",
});
2
3
4
Якщо власний узгоджувач локалі поверне неправильну локаль, він повернеться назад і вибере локаль, дотримуючись наведеного вище порядку.
Рендеринг перекладених повідомлень
Розглянемо докладніше рендеринг повідомлень.
bot.command("start", async (ctx) => {
// Викличемо метод `translate` або `t`, щоб перекласти повідомлення,
// вказавши його ідентифікатор та додаткові параметри:
await ctx.reply(ctx.t("welcome"));
});
2
3
4
5
Тепер можемо виконати команду `/start’, щоб запустити бота. Він повинен надіслати наступне повідомлення:
Усім привіт!
Підставлення змінних
Іноді вам може знадобитися розмістити всередині рядків такі значення, як числа та імена. Це можна зробити за допомогою підставлення змінних.
bot.command("cart", async (ctx) => {
// Можемо передати обʼєкт змінних для підстановки як другий аргумент
await ctx.reply(ctx.t("cart-msg", { items: 10 }));
});
2
3
4
Обʼєкт { items:
називається контекстом перекладу рядка cart
.
Тепер за допомогою команди /cart
бот надішле наступне повідомлення:
Наразі у вашому кошику 10 товарів.
Спробуйте змінити значення змінної items
і подивіться, як зміниться отримане повідомлення! Також ознайомтеся з документацією Fluent, особливо з документацією підставлення змінних.
Глобальні змінні підстановки
Буває корисно вказати певну кількість змінних підстановки, які мають бути доступними для всіх перекладів. Наприклад, якщо ви повторно використовуєте імʼя користувача у багатьох повідомленнях, то може бути досить втомливо передавати всюди контекст перекладу { name:
.
На допомогу приходять глобальні змінні підстановки! Розглянемо наступний приклад:
const i18n = new I18n<MyContext>({
defaultLocale: "uk",
directory: "locales",
// Визначемо глобально доступні змінні підстановки:
globalTranslationContext(ctx) {
return { name: ctx.from?.first_name ?? "" };
},
});
bot.use(i18n);
bot.command("start", async (ctx) => {
// Можемо використовувати `name` без повторного вказування!
await ctx.reply(ctx.t("welcome"));
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Потенційні проблеми з форматуванням
Типово Fluent використовує для інтерполяції розділові знаки Unicode.
Якщо ви використовуєте змінні підстановки всередині тегів або сутностей, наявність ізоляційних знаків може призвести до неправильного форматування, наприклад, звичайний текст замість очікуваного посилання або кештега.
Щоб виправити це, скористайтеся наступними налаштуваннями:
const i18n = new I18n({
fluentBundleOptions: { useIsolating: false },
});
2
3
Додавання перекладів
Існує три основні способи завантаження перекладів.
Завантаження локалей за допомогою параметра directory
Найпростіший спосіб додати переклади до екземпляра I18n
— це розмістити всі ваші переклади в каталозі й вказати назву каталогу у параметрах.
const i18n = new I18n({
directory: "locales",
});
2
3
Завантаження локалей з каталогу
Цей спосіб — те саме, що вказати directory
у параметрах. Просто покладіть їх усі до каталогу та завантажте їх наступним чином:
const i18n = new I18n();
await i18n.loadLocalesDir("locales"); // асинхронна версія
i18n.loadLocalesDirSync("locales-2"); // синхронна версія
2
3
4
Зауважте, що деякі середовища вимагають використання саме асинхронної версії. Наприклад, Deno Deploy не підтримує синхронні операції з файлами.
Завантаження однієї локалі
Також можна додати до екземпляра один переклад. Ви можете вказати шлях до файлу з перекладом за допомогою
const i18n = new I18n();
await i18n.loadLocale("uk", { filePath: "locales/uk.ftl" }); // асинхронна версія
i18n.loadLocaleSync("en", { filePath: "locales/en.ftl" }); // синхронна версія
2
3
4
або ви можете безпосередньо завантажити дані перекладу у вигляді рядка на кшталт цього:
const i18n = new I18n();
// async version
await i18n.loadLocale("uk", {
source: `greeting = Привіт, { $name }!
language-set = Мову встановлено на українську!`,
});
// sync version
i18n.loadLocaleSync("en", {
source: `greeting = Hello { $name }!
language-set = Language has been set to English!`,
});
2
3
4
5
6
7
8
9
10
11
12
13
Оброблення локалізованого тексту
Ми змогли надіслати користувачеві локалізовані повідомлення. Тепер давайте подивимося, як обробляти повідомлення, надіслані користувачем. У grammY ми зазвичай використовуємо обробник bot
для оброблення вхідних повідомлень. Але оскільки ми говоримо про інтернаціоналізацію, у цьому розділі ми розглянемо, як обробляти локалізовані вхідні повідомлення.
Ця функція стане у нагоді, якщо ваш бот має власні клавіатури, що містять локалізований текст.
Ось короткий приклад оброблення локалізованого текстового повідомлення, надісланого за допомогою власної клавіатури. Замість обробника bot
ми використовуємо bot
у поєднанні з проміжним обробником hears
, який надається цим плагіном.
import { hears } from "@grammyjs/i18n";
bot.filter(hears("back-to-menu-btn"), async (ctx) => {
await ctx.reply(ctx.t("main-menu-msg"));
});
2
3
4
5
const { hears } = require("@grammyjs/i18n");
bot.filter(hears("back-to-menu-btn"), async (ctx) => {
await ctx.reply(ctx.t("main-menu-msg"));
});
2
3
4
5
import { hears } from "https://deno.land/x/grammy_i18n@v1.1.0/mod.ts";
bot.filter(hears("back-to-menu-btn"), async (ctx) => {
await ctx.reply(ctx.t("main-menu-msg"));
});
2
3
4
5
Допоміжна функція hears
дозволяє вашому боту обробляти повідомлення, написані мовою користувача.
Подальші кроки
- Повністю прочитайте документацію Fluent, особливо посібник по синтаксису.
- Ознайомтеся з відповідними прикладами цього плагіна для Deno та Node.js.
Загальні відомості про плагін
- Назва:
i18n
- Джерело
- Довідка API