diff --git a/site/docs/.vitepress/configs/locales/en.ts b/site/docs/.vitepress/configs/locales/en.ts
index bf05d4c98..8f2cd7cc1 100644
--- a/site/docs/.vitepress/configs/locales/en.ts
+++ b/site/docs/.vitepress/configs/locales/en.ts
@@ -267,6 +267,10 @@ const pluginThirdparty = {
text: "Autoquote",
link: "/plugins/autoquote",
},
+ {
+ text: "Entity Parser",
+ link: "/plugins/entity-parser",
+ },
{
text: "[Submit your PR!]",
link: "/plugins/#create-your-own-plugins",
diff --git a/site/docs/.vitepress/configs/locales/es.ts b/site/docs/.vitepress/configs/locales/es.ts
index 202bc3abc..54a74d765 100644
--- a/site/docs/.vitepress/configs/locales/es.ts
+++ b/site/docs/.vitepress/configs/locales/es.ts
@@ -234,6 +234,10 @@ const pluginThirdparty = {
text: "Citar automáticamente",
link: "/es/plugins/autoquote",
},
+ {
+ text: "Analizador de entidades",
+ link: "/es/plugins/entity-parser",
+ },
{
text: "[¡Envíe su PR!]",
link: "/es/plugins/#crear-tus-propios-plugins",
diff --git a/site/docs/.vitepress/configs/locales/id.ts b/site/docs/.vitepress/configs/locales/id.ts
index 98064e1f9..5480951d5 100644
--- a/site/docs/.vitepress/configs/locales/id.ts
+++ b/site/docs/.vitepress/configs/locales/id.ts
@@ -230,6 +230,10 @@ const pluginThirdparty = {
text: "Autoquote",
link: "/id/plugins/autoquote",
},
+ {
+ text: "Entity Parser",
+ link: "/id/plugins/entity-parser",
+ },
{
text: "[Kirim PR-mu!]",
link: "/id/plugins/#buat-plugin-mu-sendiri",
diff --git a/site/docs/.vitepress/configs/locales/ru.ts b/site/docs/.vitepress/configs/locales/ru.ts
index 5808491f1..d03eed8e5 100644
--- a/site/docs/.vitepress/configs/locales/ru.ts
+++ b/site/docs/.vitepress/configs/locales/ru.ts
@@ -234,6 +234,10 @@ const pluginThirdparty = {
text: "Автоцитата",
link: "/ru/plugins/autoquote",
},
+ {
+ text: "Парсер сущностей",
+ link: "/ru/plugins/entity-parser",
+ },
{
text: "[Создайте свой PR!]",
link: "/ru/plugins/#create-your-own-plugins",
diff --git a/site/docs/.vitepress/configs/locales/uk.ts b/site/docs/.vitepress/configs/locales/uk.ts
index 0c9aebfdc..59c8b4133 100644
--- a/site/docs/.vitepress/configs/locales/uk.ts
+++ b/site/docs/.vitepress/configs/locales/uk.ts
@@ -234,6 +234,10 @@ const pluginThirdparty = {
text: "Автоматичне встановлення відповіді",
link: "/uk/plugins/autoquote",
},
+ {
+ text: "Парсер сутностей",
+ link: "/uk/plugins/entity-parser",
+ },
{
text: "[Відправте свій PR!]",
link: "/uk/plugins/#створюите-власні-плагіни",
diff --git a/site/docs/.vitepress/configs/locales/zh.ts b/site/docs/.vitepress/configs/locales/zh.ts
index f24c5775b..edb1c0d69 100644
--- a/site/docs/.vitepress/configs/locales/zh.ts
+++ b/site/docs/.vitepress/configs/locales/zh.ts
@@ -234,6 +234,10 @@ const pluginThirdparty = {
text: "自动引用",
link: "/zh/plugins/autoquote",
},
+ {
+ text: "实体解析器 (Entity Parser)",
+ link: "/zh/plugins/entity-parser",
+ },
{
text: "[提交你的 PR!]",
link: "/zh/plugins/#创建你自己的插件",
diff --git a/site/docs/es/plugins/entity-parser.md b/site/docs/es/plugins/entity-parser.md
new file mode 100644
index 000000000..3d0bc14cc
--- /dev/null
+++ b/site/docs/es/plugins/entity-parser.md
@@ -0,0 +1,273 @@
+---
+prev: false
+next: false
+---
+
+# Analizador de entidades (`entity-parser`)
+
+Convierte
+[entidades de Telegram](https://core.telegram.org/bots/api#messageentity) a HTML
+semántico.
+
+## ¿Cuándo debo usar esto?
+
+Probablemente ¡NUNCA!
+
+Aunque este plugin puede generar HTML, generalmente es mejor enviar el texto y
+las entidades de vuelta a Telegram.
+
+Convertirlos a HTML sólo es necesario en raros casos en los que necesites usar
+texto con formato de Telegram **fuera** de Telegram mismo, como mostrar mensajes
+de Telegram en un sitio web.
+
+Mira la sección
+[_Casos en los que es mejor no usar este paquete_](#casos-en-los-que-es-mejor-no-utilizar-este-paquete)
+para determinar si tienes un problema similar que resolver.
+
+Si no estás seguro de si este plugin es el adecuado para tu caso de uso, no
+dudes en preguntar en nuestro [grupo de Telegram](https://t.me/grammyjs). En la
+mayoría de los casos, la gente descubre que no necesita este complemento para
+resolver sus problemas.
+
+## Instalación
+
+Ejecute el siguiente comando en su terminal en función de su tiempo de ejecución
+o gestor de paquetes:
+
+::: code-group
+
+```sh:no-line-numbers [Deno]
+deno add jsr:@qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Bun]
+bunx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [pnpm]
+pnpm dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Yarn]
+yarn dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [npm]
+npx jsr add @qz/telegram-entities-parser
+```
+
+:::
+
+## Uso sencillo
+
+El uso de este plugin es muy sencillo. He aquí un ejemplo rápido:
+
+```ts
+import { EntitiesParser } from "@qz/telegram-entities-parser";
+import type { Message } from "@qz/telegram-entities-parser/types";
+
+// Para un mejor rendimiento, cree la instancia fuera de la función.
+const entitiesParser = new EntitiesParser();
+const parse = (message: Message) => entitiesParser.parse({ message });
+
+bot.on(":text", (ctx) => {
+ const html = parse(ctx.msg); // Convertir texto en cadena HTML
+});
+
+bot.on(":photo", (ctx) => {
+ const html = parse(ctx.msg); // Convertir pie de foto en cadena HTML
+});
+```
+
+## Uso avanzado
+
+### Personalización de la etiqueta HTML de salida
+
+Este paquete convierte entidades en HTML semántico, adhiriéndose lo más posible
+a las mejores prácticas y estándares. Sin embargo, la salida proporcionada puede
+no ser siempre la esperada.
+
+Para solucionarlo, puede utilizar su propio `renderer` para personalizar los
+elementos HTML que rodean al texto de acuerdo con sus reglas. Puedes modificar
+reglas específicas extendiendo el
+[`RendererHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts)
+por defecto o anular todas las reglas implementando el
+[`Renderer`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts).
+
+Para extender el `renderer` existente, haz lo siguiente:
+
+```ts
+import { EntitiesParser, RendererHtml } from "@qz/telegram-entities-parser";
+import type {
+ CommonEntity,
+ RendererOutput,
+} from "@qz/telegram-entities-parser/types";
+
+// Cambiar la regla para la entidad de tipo negrita,
+// pero deja el resto de los tipos como están definidos por `RendererHtml`.
+class MyRenderer extends RendererHtml {
+ override bold(
+ options: { text: string; entity: CommonEntity },
+ ): RendererOutput {
+ return {
+ prefix: '',
+ suffix: "",
+ };
+ }
+}
+
+const entitiesParser = new EntitiesParser({ renderer: new MyRenderer() });
+```
+
+El parámetro `options` acepta un objeto con `text` y `entity`.
+
+- `text`: El texto específico al que se refiere la entidad actual.
+- `entity`: Puede estar representada por varias interfaces dependiendo del tipo
+ de entidad, como `CommonEntity`, `CustomEmojiEntity`, `PreEntity`,
+ `TextLinkEntity`, o `TextMentionEntity`. Por ejemplo, el tipo `bold` tiene una
+ entidad con la interfaz `CommonEntity`, mientras que el tipo `text_link` puede
+ tener una entidad con la interfaz `TextLinkEntity`, ya que incluye propiedades
+ adicionales como `url`.
+
+Aquí está la lista completa de interfaces y la salida para cada tipo de entidad:
+
+| Entity Type | Interface | Result |
+| ----------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `blockquote` | `CommonEntity` | `
...
` |
+| `bold` | `CommonEntity` | ` ... ` |
+| `bot_command` | `CommonEntity` | ` ... ` |
+| `cashtag` | `CommonEntity` | ` ... ` |
+| `code` | `CommonEntity` | ` ...
` |
+| `custom_emoji` | `CustomEmojiEntity` | ` ... ` |
+| `email` | `CommonEntity` | ` ... ` |
+| `expandable_blockquote` | `CommonEntity` | ` ...
` |
+| `hashtag` | `CommonEntity` | ` ... ` |
+| `italic` | `CommonEntity` | ` ... ` |
+| `mention` | `CommonEntity` | ` ... ` |
+| `phone_number` | `CommonEntity` | ` ... ` |
+| `pre` | `PreEntity` | ` ...
` o ` ...
` |
+| `spoiler` | `CommonEntity` | ` ... ` |
+| `strikethrough` | `CommonEntity` | ` ... ` |
+| `text_link` | `TextLinkEntity` | ` ... ` |
+| `text_mention` | `TextMentionEntity` | ` ... ` o ` ... ` |
+| `underline` | `CommonEntity` | ` ... ` |
+| `url` | `CommonEntity` | ` ... ` |
+
+Si no está seguro de cuál es la interfaz correcta, consulte cómo se implementa
+[Renderer](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts)
+o
+[RendererHtml](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts).
+
+### Personalizar el sanitizador de texto
+
+El texto de salida se desinfecta de forma predeterminada para garantizar la
+correcta representación del HTML y evitar vulnerabilidades XSS.
+
+| Input | Output |
+| ----- | -------- |
+| `&` | `&` |
+| `<` | `<` |
+| `>` | `>` |
+| `"` | `"` |
+| `'` | `'` |
+
+Por ejemplo, el resultado `Negrita & Cursiva` se saneará a
+`Negrita & Cursiva`.
+
+Puede anular este comportamiento especificando un `textSanitizer` al crear una
+instancia de
+[`EntitiesParser`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/mod.ts):
+
+- Si no especifica `textSanitizer`, se utilizará de manera predeterminada
+ [`sanitizerHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/utils/sanitizer_html.ts)
+ como sanitizador.
+- Si establece el valor en `false`, se omitirá la sanitización y se mantendrá el
+ texto de salida como el original. Esto no se recomienda, ya que puede generar
+ una representación incorrecta y hacer que su aplicación sea vulnerable a
+ ataques XSS. Asegúrese de manipularlo correctamente si elige esta opción.
+- Si proporciona una función, se utilizará en lugar del desinfectante
+ predeterminado.
+
+```ts
+const myTextSanitizer: TextSanitizer = (options: TextSanitizerOption): string =>
+ // Sustituir carácter peligroso
+ options.text.replaceAll(/[&<>"']/, (match) => {
+ switch (match) {
+ case "&":
+ return "&";
+ case "<":
+ return "<";
+ case ">":
+ return ">";
+ case '"':
+ return """;
+ case "'":
+ return "'";
+ default:
+ return match;
+ }
+ });
+
+// Aplique el desinfectante.
+const entitiesParser = new EntitiesParser({ textSanitizer: myTextSanitizer });
+```
+
+## Casos en los que es mejor no utilizar este paquete
+
+Si se enfrenta a problemas similares a los que se enumeran a continuación, es
+posible que pueda resolverlos sin utilizar este paquete.
+
+### Copiar y reenviar el mismo mensaje
+
+Utiliza [`forwardMessage`](https://core.telegram.org/bots/api#forwardmessage)
+para reenviar mensajes de cualquier tipo.
+
+También puedes utilizar la API
+[`copyMessage`](https://core.telegram.org/bots/api#copymessage), que realiza la
+misma acción pero no incluye un enlace al mensaje original.
+[`copyMessage`](https://core.telegram.org/bots/api#copymessage) se comporta como
+copiar el mensaje y enviarlo de vuelta a Telegram, haciendo que aparezca como un
+mensaje normal en lugar de uno reenviado.
+
+```ts
+bot.on(":text", async (ctx) => {
+ // El identificador de chat de destino que se enviará.
+ const chatId = -946659600;
+ // Reenvía el mensaje actual sin un enlace al mensaje original.
+ await ctx.copyMessage(chatId);
+ // Reenvía el mensaje actual con un enlace al mensaje original.
+ await ctx.forwardMessage(chatId);
+});
+```
+
+### Responder a mensajes con formato de texto modificado
+
+Puede responder fácilmente a los mensajes entrantes utilizando HTML, Markdown o
+entidades.
+
+```ts
+bot.on(":text", async (ctx) => {
+ // Responder con HTML
+ await ctx.reply("bold italic", { parse_mode: "HTML" });
+ // Responder usando Telegram Markdown V2
+ await ctx.reply("*bold* _italic_", { parse_mode: "MarkdownV2" });
+ // Responder con entidades
+ await ctx.reply("bold italic", {
+ entities: [
+ { offset: 0, length: 5, type: "bold" },
+ { offset: 5, length: 6, type: "italic" },
+ ],
+ });
+});
+```
+
+::: tip Use parse-mode para una mejor experiencia de formateo
+
+Utiliza el plugin oficial [`parse-mode`](./parse-mode) para una mejor
+experiencia en la construcción de mensajes formateados. :::
+
+## Resumen del plugin
+
+- Nombre: `entity-parser`
+- [Fuente](https://jsr.io/@qz/telegram-entities-parser)
+- [Referencia](https://github.com/quadratz/telegram-entities-parser)
diff --git a/site/docs/id/plugins/entity-parser.md b/site/docs/id/plugins/entity-parser.md
new file mode 100644
index 000000000..a1df652ca
--- /dev/null
+++ b/site/docs/id/plugins/entity-parser.md
@@ -0,0 +1,238 @@
+---
+prev: false
+next: false
+---
+
+# Entity Parser (`entity-parser`)
+
+Mengubah [Telegram entities](https://core.telegram.org/bots/api#messageentity) menjadi semantic HTML.
+
+## Kapan Plugin Ini Diperlukan?
+
+Kemungkinan besar kamu TIDAK AKAN PERNAH membutuhkannya sama sekali!
+
+Meski plugin ini mampu menghasilkan HTML, namun, pada umumnya, mengirim teks beserta entity-nya kembali ke Telegram jauh lebih baik.
+
+Pengonversian ke HTML hanya dibutuhkan untuk kondisi khusus ketika kamu perlu menggunakan teks pemformatan Telegram **di luar** ekosistem Telegram itu sendiri, misalnya menampilkan pesan Telegram di suatu website.
+
+Silahkan lihat bagian [_Contoh-Contoh Kasus yang Sebaiknya Tidak Menggunakan Plugin Ini_](#contoh-contoh-kasus-yang-sebaiknya-tidak-menggunakan-plugin-ini) untuk menemukan solusi yang lebih baik ketika kamu memiliki permasalahan yang serupa.
+
+Jika kamu masih ragu apakah plugin ini sesuai, jangan ragun untuk bertanya di [grup Telegram](https://t.me/grammyjs) kami.
+Dalam kebanyakan kasus, sebagian besar orang sebenarnya tidak terlalu memerlukan plugin untuk menyelesaikan permasalahan mereka!
+
+## Penginstalan
+
+Jalankan perintah berikut di terminal.
+Sesuaikan dengan runtime atau package manager yang kamu gunakan:
+
+::: code-group
+
+```sh:no-line-numbers [Deno]
+deno add jsr:@qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Bun]
+bunx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [pnpm]
+pnpm dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Yarn]
+yarn dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [npm]
+npx jsr add @qz/telegram-entities-parser
+```
+
+:::
+
+## Penggunaan Sederhana
+
+Menggunakan plugin ini cukup simpel.
+Berikut contohnya:
+
+```ts
+import { EntitiesParser } from "@qz/telegram-entities-parser";
+import type { Message } from "@qz/telegram-entities-parser/types";
+
+// Agar tidak mempengaruhi performa, buat instansiasi di luar function terkait.
+const entitiesParser = new EntitiesParser();
+const parse = (message: Message) => entitiesParser.parse({ message });
+
+bot.on(":text", (ctx) => {
+ const html = parse(ctx.msg); // Konversi teks menjadi string HTML
+});
+
+bot.on(":photo", (ctx) => {
+ const html = parse(ctx.msg); // Konversi caption menjadi string HTML
+});
+```
+
+## Penggunaan Tingkat Lanjut
+
+### Menyesuaikan Keluaran Tag HTML
+
+Plugin ini mengonversi entity menjadi semantic HTML sesuai dengan standar dan praktik terbaik sebisa mungkin.
+Namun, keluaran yang dihasilkan mungkin tidak sesuai dengan harapan kamu.
+
+Untuk mengatasinya, kamu bisa menggunakan `renderer`-mu sendiri untuk menyesuaikan element HTML yang membungkus teks terkait sesuai dengan aturan yang telah diterapkan.
+Kamu bisa memodifikasi aturan tertentu dengan cara meng-extend [`RendererHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts) bawaan ataupun menimpa semua aturan dengan cara mengimplementasikan [`Renderer`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts).
+
+Untuk meng-extend `renderer` yang sudah ada, lakukan hal berikut:
+
+```ts
+import { EntitiesParser, RendererHtml } from "@qz/telegram-entities-parser";
+import type {
+ CommonEntity,
+ RendererOutput,
+} from "@qz/telegram-entities-parser/types";
+
+// Gunakan aturan yang diterapkan oleh `RendererHtml`,
+// tetapi khusus untuk entity bold, gunakan aturan berikut:
+class MyRenderer extends RendererHtml {
+ override bold(
+ options: { text: string; entity: CommonEntity },
+ ): RendererOutput {
+ return {
+ prefix: '',
+ suffix: "",
+ };
+ }
+}
+
+const entitiesParser = new EntitiesParser({ renderer: new MyRenderer() });
+```
+
+Parameter `options` menerima sebuah object berupa `text` dan `entity`.
+
+- `text`: Porsi teks yang direferensikan oleh entity terkait.
+- `entity`: Paramater ini memiliki beragam interface sesuai dengan tipe entity-nya, entah itu `CommonEntity`, `CustomEmojiEntity`, `PreEntity`, `TextLinkEntity`, ataupun `TextMentionEntity`.
+ Contohnya, tipe `bold` memiliki entity dengan interface `CommonEntity`, sementara tipe `text_link` interface-nya berupa `TextLinkEntity` karena mengandung property tambahan seperti `url`.
+
+Berikut daftar lengkap interface beserta keluaran untuk masing-masing tipe entity:
+
+| Tipe Entity | Interface | Keluaran |
+| ----------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `blockquote` | `CommonEntity` | ` ...
` |
+| `bold` | `CommonEntity` | ` ... ` |
+| `bot_command` | `CommonEntity` | ` ... ` |
+| `cashtag` | `CommonEntity` | ` ... ` |
+| `code` | `CommonEntity` | ` ...
` |
+| `custom_emoji` | `CustomEmojiEntity` | ` ... ` |
+| `email` | `CommonEntity` | ` ... ` |
+| `expandable_blockquote` | `CommonEntity` | ` ...
` |
+| `hashtag` | `CommonEntity` | ` ... ` |
+| `italic` | `CommonEntity` | ` ... ` |
+| `mention` | `CommonEntity` | ` ... ` |
+| `phone_number` | `CommonEntity` | ` ... ` |
+| `pre` | `PreEntity` | ` ...
` atau ` ...
` |
+| `spoiler` | `CommonEntity` | ` ... ` |
+| `strikethrough` | `CommonEntity` | ` ... ` |
+| `text_link` | `TextLinkEntity` | ` ... ` |
+| `text_mention` | `TextMentionEntity` | ` ... ` atau ` ... ` |
+| `underline` | `CommonEntity` | ` ... ` |
+| `url` | `CommonEntity` | ` ... ` |
+
+Jika kamu ragu interface mana yang benar, silahkan lihat pengimplentasian [Renderer](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts) dan [RendererHtml](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts).
+
+### Menyesuaikan Pembersih Teks (Text Sanitizer)
+
+Secara bawaan, keluaran teks dibersihkan agar HTML bisa di-render dengan baik dan menghindari kerentanan XSS.
+
+| Masukan | Keluaran |
+| ------- | -------- |
+| `&` | `&` |
+| `<` | `<` |
+| `>` | `>` |
+| `"` | `"` |
+| `'` | `'` |
+
+Sebagai contoh, hasil keluaran `Tebal & Miring` akan dibersihkan menjadi `Tebal & Miring`.
+
+Kamu bisa mengubah perilaku tersebut dengan cara menentukan `textSanitizer` ketika menginisiasi [`EntitiesParser`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/mod.ts):
+
+- Jika `textSanitizer` tidak ditentukan, ia secara bawaan akan menggunakan [`sanitizerHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/utils/sanitizer_html.ts) sebagai pembersihnya.
+- Jika nilai `false` diberikan, pembersihan tidak akan dilakukan, sehingga keluaran teks yang dihasilkan apa adanya.
+ Langkah ini tidak disarankan karena dapat menyebabkan kesalahan pe-render-an dan membuat aplikasimu rentan terhadap serangan XSS.
+ Pastikan penanganan dilakukan dengan baik jika kamu memilih opsi ini.
+- Jika sebuah function diberikan, function tersebut akan digunakan sebagai pembersih bawaannya.
+
+```ts
+const myTextSanitizer: TextSanitizer = (options: TextSanitizerOption): string =>
+ // Ganti karakter-karakter yang berbahaya
+ options.text.replaceAll(/[&<>"']/, (match) => {
+ switch (match) {
+ case "&":
+ return "&";
+ case "<":
+ return "<";
+ case ">":
+ return ">";
+ case '"':
+ return """;
+ case "'":
+ return "'";
+ default:
+ return match;
+ }
+ });
+
+// Terapkan pembersihnya (sanitizer).
+const entitiesParser = new EntitiesParser({ textSanitizer: myTextSanitizer });
+```
+
+## Contoh-Contoh Kasus yang Sebaiknya Tidak Menggunakan Plugin Ini
+
+Jika menghadapi permasalahan serupa dengan berikut, kamu kemungkinan besar bisa menyelesaikannya tanpa menggunakan plugin ini.
+
+### Menyalin dan Meneruskan Pesan yang Sama
+
+Gunakan [`forwardMessage`](https://core.telegram.org/bots/api#forwardmessage) untuk meneruskan pesan apapun.
+
+Kamu juga bisa menggunakan API [`copyMessage`](https://core.telegram.org/bots/api#copymessage) untuk melakukan aksi yang serupa tanpa menyertakan link ke pesan aslinya.
+[`copyMessage`](https://core.telegram.org/bots/api#copymessage) memiliki perilaku layaknya menyalin lalu mengirim ulang pesan tersebut ke Telegram, sehingga wujudnya berupa pesan biasa alih-alih pesan terusan.
+
+```ts
+bot.on(":text", async (ctx) => {
+ // Id chat tujuan.
+ const chatId = -946659600;
+ // Teruskan pesan berikut tanpa menyertakan link ke pesan aslinya.
+ await ctx.copyMessage(chatId);
+ // Teruskan pesan berikut dengan menyertakan link ke pesan aslinya.
+ await ctx.forwardMessage(chatId);
+});
+```
+
+### Membalas Pesan Menggunakan Format Teks yang Telah Dimodifikasi
+
+Kamu juga bisa dengan mudah membalas pesan yang datang menggunakan HTML, Markdown, atau entity.
+
+```ts
+bot.on(":text", async (ctx) => {
+ // Balas dengan HTML
+ await ctx.reply("tebal miring", { parse_mode: "HTML" });
+ // Balas dengan Telegram Markdown V2
+ await ctx.reply("*tebal* _miring_", { parse_mode: "MarkdownV2" });
+ // Balas dengan entity
+ await ctx.reply("tebal miring", {
+ entities: [
+ { offset: 0, length: 5, type: "bold" },
+ { offset: 6, length: 6, type: "italic" },
+ ],
+ });
+});
+```
+
+::: tip Gunakan parse-mode untuk Pengalaman Pemformatan yang Lebih Baik
+
+Gunakan plugin resmi [`parse-mode`](./parse-mode) untuk memformat pesan dengan cara yang lebih elegan.
+:::
+
+## Ringkasan Plugin
+
+- Nama: `entity-parser`
+- [Package](https://jsr.io/@qz/telegram-entities-parser)
+- [Sumber](https://github.com/quadratz/telegram-entities-parser)
diff --git a/site/docs/plugins/entity-parser.md b/site/docs/plugins/entity-parser.md
new file mode 100644
index 000000000..04cdc9ccf
--- /dev/null
+++ b/site/docs/plugins/entity-parser.md
@@ -0,0 +1,237 @@
+---
+prev: false
+next: false
+---
+
+# Entity Parser (`entity-parser`)
+
+Converts [Telegram entities](https://core.telegram.org/bots/api#messageentity) to semantic HTML.
+
+## When Should I Use This?
+
+Probably NEVER!
+
+While this plugin can generate HTML, it's generally best to send the text and entities back to Telegram.
+
+Converting them to HTML is only necessary in rare cases where you need to use Telegram-formatted text **outside** of Telegram itself, such as displaying Telegram messages on a website.
+
+See the [_Cases When It's Better Not to Use This Package_](#cases-when-it-s-better-not-to-use-this-package) section to determine if you have a similar problem to solve.
+
+If you're unsure whether this plugin is the right fit for your use case, please don't hesitate to ask in our [Telegram group](https://t.me/grammyjs).
+In most cases, people find they don't actually need this plugin to solve their problems!
+
+## Installation
+
+Run the following command in your terminal based on your runtime or package manager:
+
+::: code-group
+
+```sh:no-line-numbers [Deno]
+deno add jsr:@qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Bun]
+bunx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [pnpm]
+pnpm dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Yarn]
+yarn dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [npm]
+npx jsr add @qz/telegram-entities-parser
+```
+
+:::
+
+## Simple Usage
+
+Using this plugin is straightforward.
+Here's a quick example:
+
+```ts
+import { EntitiesParser } from "@qz/telegram-entities-parser";
+import type { Message } from "@qz/telegram-entities-parser/types";
+
+// For better performance, create the instance outside the function.
+const entitiesParser = new EntitiesParser();
+const parse = (message: Message) => entitiesParser.parse({ message });
+
+bot.on(":text", (ctx) => {
+ const html = parse(ctx.msg); // Convert text to HTML string
+});
+
+bot.on(":photo", (ctx) => {
+ const html = parse(ctx.msg); // Convert caption to HTML string
+});
+```
+
+## Advanced Usage
+
+### Customizing the Output HTML Tag
+
+This package converts entities into semantic HTML, adhering to best practices and standards as closely as possible.
+However, the provided output might not always be what you expect.
+
+To address this, you can use your own `renderer` to customize the HTML elements surrounding the text according to your rules.
+You can modify specific rules by extending the default [`RendererHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts) or override all the rules by implementing the [`Renderer`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts).
+
+To extend the existing `renderer`, do the following:
+
+```ts
+import { EntitiesParser, RendererHtml } from "@qz/telegram-entities-parser";
+import type {
+ CommonEntity,
+ RendererOutput,
+} from "@qz/telegram-entities-parser/types";
+
+// Change the rule for bold type entity,
+// but leave the rest of the types as defined by `RendererHtml`.
+class MyRenderer extends RendererHtml {
+ override bold(
+ options: { text: string; entity: CommonEntity },
+ ): RendererOutput {
+ return {
+ prefix: '',
+ suffix: "",
+ };
+ }
+}
+
+const entitiesParser = new EntitiesParser({ renderer: new MyRenderer() });
+```
+
+The `options` parameter accepts an object with `text` and `entity`.
+
+- `text`: The specific text that the current entity refers to.
+- `entity`: This may be represented by various interfaces depending on the entity type, such as `CommonEntity`, `CustomEmojiEntity`, `PreEntity`, `TextLinkEntity`, or `TextMentionEntity`.
+ For instance, the `bold` type has an entity with the `CommonEntity` interface, while the `text_link` type may have an entity with the `TextLinkEntity` interface, as it includes additional properties like `url`.
+
+Here is the full list of interfaces and the output for each entity type:
+
+| Entity Type | Interface | Result |
+| ----------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `blockquote` | `CommonEntity` | ` ...
` |
+| `bold` | `CommonEntity` | ` ... ` |
+| `bot_command` | `CommonEntity` | ` ... ` |
+| `cashtag` | `CommonEntity` | ` ... ` |
+| `code` | `CommonEntity` | ` ...
` |
+| `custom_emoji` | `CustomEmojiEntity` | ` ... ` |
+| `email` | `CommonEntity` | ` ... ` |
+| `expandable_blockquote` | `CommonEntity` | ` ...
` |
+| `hashtag` | `CommonEntity` | ` ... ` |
+| `italic` | `CommonEntity` | ` ... ` |
+| `mention` | `CommonEntity` | ` ... ` |
+| `phone_number` | `CommonEntity` | ` ... ` |
+| `pre` | `PreEntity` | ` ...
` or ` ...
` |
+| `spoiler` | `CommonEntity` | ` ... ` |
+| `strikethrough` | `CommonEntity` | ` ... ` |
+| `text_link` | `TextLinkEntity` | ` ... ` |
+| `text_mention` | `TextMentionEntity` | ` ... ` or ` ... ` |
+| `underline` | `CommonEntity` | ` ... ` |
+| `url` | `CommonEntity` | ` ... ` |
+
+If you are unsure which interface is correct, refer to how the [Renderer](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts) or [RendererHtml](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts) is implemented.
+
+### Customize the Text Sanitizer
+
+The output text is sanitized by default to ensure proper HTML rendering and prevent XSS vulnerabilities.
+
+| Input | Output |
+| ----- | -------- |
+| `&` | `&` |
+| `<` | `<` |
+| `>` | `>` |
+| `"` | `"` |
+| `'` | `'` |
+
+For example, the result `Bold & Italic` will be sanitized to `Bold & Italic`.
+
+You can override this behavior by specifying a `textSanitizer` when instantiating the [`EntitiesParser`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/mod.ts):
+
+- If you do not specify `textSanitizer`, it will default to using [`sanitizerHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/utils/sanitizer_html.ts) as the sanitizer.
+- Setting the value to `false` will skip sanitization, keeping the output text as the original.
+ This is not recommended, as it may result in incorrect rendering and make your application vulnerable to XSS attacks.
+ Ensure proper handling if you choose this option.
+- If you provide a function, it will be used instead of the default sanitizer.
+
+```ts
+const myTextSanitizer: TextSanitizer = (options: TextSanitizerOption): string =>
+ // Replace dangerous character
+ options.text.replaceAll(/[&<>"']/, (match) => {
+ switch (match) {
+ case "&":
+ return "&";
+ case "<":
+ return "<";
+ case ">":
+ return ">";
+ case '"':
+ return """;
+ case "'":
+ return "'";
+ default:
+ return match;
+ }
+ });
+
+// Implement the sanitizer.
+const entitiesParser = new EntitiesParser({ textSanitizer: myTextSanitizer });
+```
+
+## Cases When It's Better Not to Use This Package
+
+If you face problems similar to those listed below, you might be able to resolve them without using this package.
+
+### Copying and Forwarding the Same Message
+
+Use [`forwardMessage`](https://core.telegram.org/bots/api#forwardmessage) to forward messages of any kind.
+
+You can also use the [`copyMessage`](https://core.telegram.org/bots/api#copymessage) API, which performs the same action but does not include a link to the original message.
+[`copyMessage`](https://core.telegram.org/bots/api#copymessage) behaves like copying the message and sending it back to Telegram, making it appear as a regular message rather than a forwarded one.
+
+```ts
+bot.on(":text", async (ctx) => {
+ // The target chat id to send.
+ const chatId = -946659600;
+ // Forward the current message without a link to the original message.
+ await ctx.copyMessage(chatId);
+ // Forward the current message with a link to the original message.
+ await ctx.forwardMessage(chatId);
+});
+```
+
+### Replying to Messages with Modified Text Format
+
+You can easily reply to incoming messages using HTML, Markdown, or entities.
+
+```ts
+bot.on(":text", async (ctx) => {
+ // Reply using HTML
+ await ctx.reply("bold italic", { parse_mode: "HTML" });
+ // Reply using Telegram Markdown V2
+ await ctx.reply("*bold* _italic_", { parse_mode: "MarkdownV2" });
+ // Reply with entities
+ await ctx.reply("bold italic", {
+ entities: [
+ { offset: 0, length: 5, type: "bold" },
+ { offset: 5, length: 6, type: "italic" },
+ ],
+ });
+});
+```
+
+::: tip Use parse-mode for a Better Formatting Experience
+
+Use the official [`parse-mode`](./parse-mode) plugin for a better experience constructing formatted messages.
+:::
+
+## Plugin Summary
+
+- Name: `entity-parser`
+- [Package](https://jsr.io/@qz/telegram-entities-parser)
+- [Source](https://github.com/quadratz/telegram-entities-parser)
diff --git a/site/docs/ru/plugins/entity-parser.md b/site/docs/ru/plugins/entity-parser.md
new file mode 100644
index 000000000..0801f05f8
--- /dev/null
+++ b/site/docs/ru/plugins/entity-parser.md
@@ -0,0 +1,236 @@
+---
+prev: false
+next: false
+---
+
+# Парсер сущностей (`entity-parser`)
+
+Преобразует [сущности Telegram](https://core.telegram.org/bots/api#messageentity) в семантический HTML.
+
+## Когда стоит это использовать?
+
+Вероятно, НИКОГДА!
+
+Хотя этот плагин может генерировать HTML, в большинстве случаев лучше передавать текст и сущности обратно в Telegram.
+
+Преобразование в HTML требуется только в редких случаях, например, если вам нужно использовать текст с форматированием Telegram **вне** самого Telegram, например, для отображения сообщений на сайте.
+
+Посмотрите раздел [_Случаи, когда лучше не использовать этот пакет_](#случаи-когда-лучше-не-использовать-этот-пакет), чтобы понять, сталкиваетесь ли вы с аналогичной задачей.
+
+Если вы не уверены, подходит ли этот плагин для вашего случая, не стесняйтесь задавать вопросы в наших [англоязычном](https://t.me/grammyjs) и [русскоязычном](https://t.me/grammyjs_ru) чатах.
+В большинстве случаев выясняется, что для решения ваших задач этот плагин не нужен!
+
+## Уставнока
+
+Выполните следующую команду в вашем терминале, исходя из используемого пакетного менеджера:
+
+::: code-group
+
+```sh:no-line-numbers [Deno]
+deno add jsr:@qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Bun]
+bunx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [pnpm]
+pnpm dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Yarn]
+yarn dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [npm]
+npx jsr add @qz/telegram-entities-parser
+```
+
+:::
+
+## Простое использование
+
+Использовать этот плагин очень просто.
+Вот краткий пример:
+
+```ts
+import { EntitiesParser } from "@qz/telegram-entities-parser";
+import type { Message } from "@qz/telegram-entities-parser/types";
+
+// Для повышения производительности создайте парсер вне функции.
+const entitiesParser = new EntitiesParser();
+const parse = (message: Message) => entitiesParser.parse({ message });
+
+bot.on(":text", (ctx) => {
+ const html = parse(ctx.msg); // Преобразует текст в строку HTML
+});
+
+bot.on(":photo", (ctx) => {
+ const html = parse(ctx.msg); // Преобразует подпись к фото в строку HTML
+});
+```
+
+## Расширенное использование
+
+### Настройка выходного HTML тега
+
+Этот пакет преобразует сущности в семантический HTML, следуя лучшим практикам и стандартам настолько близко, насколько это возможно.
+Однако предоставленный результат может не всегда соответствовать вашим ожиданиям.
+
+Чтобы это исправить, вы можете использовать собственный `renderer` для настройки HTML тегов, окружающих текст, в соответствии с вашими правилами.
+Вы можете изменить конкретные правила, расширив стандартный [`RendererHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts), или переопределить все правила, реализовав собственный [`Renderer`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts).
+
+Чтобы расширить существующий `renderer`, выполните следующие шаги:
+
+```ts
+import { EntitiesParser, RendererHtml } from "@qz/telegram-entities-parser";
+import type {
+ CommonEntity,
+ RendererOutput,
+} from "@qz/telegram-entities-parser/types";
+
+// Изменение правила для жирного текста,
+// оставив остальные типы, определенные в `RendererHtml`.
+class MyRenderer extends RendererHtml {
+ override bold(
+ options: { text: string; entity: CommonEntity },
+ ): RendererOutput {
+ return {
+ prefix: '',
+ suffix: "",
+ };
+ }
+}
+
+const entitiesParser = new EntitiesParser({ renderer: new MyRenderer() });
+```
+
+Параметр `options` принимает объект с полями `text` и `entity`.
+
+- `text`: Конкретный текст, к которому относится текущая сущность.
+- `entity`: Может быть представлен различными интерфейсами в зависимости от типа сущности, такими как `CommonEntity`, `CustomEmojiEntity`, `PreEntity`, `TextLinkEntity` или `TextMentionEntity`.
+ Например, сущность типа `bold` имеет интерфейс `CommonEntity`, тогда как тип `text_link` может иметь интерфейс `TextLinkEntity`, так как включает дополнительные свойства, такие как `url`.
+
+Вот полный список интерфейсов и выходных данных для каждого типа сущности:
+
+| Тип сущности | Интерфейс | Результат |
+| ----------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `blockquote` | `CommonEntity` | ` ...
` |
+| `bold` | `CommonEntity` | ` ... ` |
+| `bot_command` | `CommonEntity` | ` ... ` |
+| `cashtag` | `CommonEntity` | ` ... ` |
+| `code` | `CommonEntity` | ` ...
` |
+| `custom_emoji` | `CustomEmojiEntity` | ` ... ` |
+| `email` | `CommonEntity` | ` ... ` |
+| `expandable_blockquote` | `CommonEntity` | ` ...
` |
+| `hashtag` | `CommonEntity` | ` ... ` |
+| `italic` | `CommonEntity` | ` ... ` |
+| `mention` | `CommonEntity` | ` ... ` |
+| `phone_number` | `CommonEntity` | ` ... ` |
+| `pre` | `PreEntity` | ` ...
` или ` ...
` |
+| `spoiler` | `CommonEntity` | ` ... ` |
+| `strikethrough` | `CommonEntity` | ` ... ` |
+| `text_link` | `TextLinkEntity` | ` ... ` |
+| `text_mention` | `TextMentionEntity` | ` ... ` или ` ... ` |
+| `underline` | `CommonEntity` | ` ... ` |
+| `url` | `CommonEntity` | ` ... ` |
+
+Если вы не уверены, какой интерфейс использовать, обратитесь к реализации [Renderer](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts) или [RendererHtml](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts).
+
+### Настройка санитайзера текста
+
+Выводимый текст по умолчанию проходит санитизацию для обеспечения корректного HTML-рендеринга и предотвращения XSS уязвимостей.
+
+| Ввод | Вывод |
+| ---- | -------- |
+| `&` | `&` |
+| `<` | `<` |
+| `>` | `>` |
+| `"` | `"` |
+| `'` | `'` |
+
+Например, результат `Bold & Italic` будет санитизирован в `Bold & Italic`.
+
+Вы можете изменить это поведение, указав `textSanitizer` при создании экземпляра [`EntitiesParser`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/mod.ts):
+
+- Если вы не укажете `textSanitizer`, по умолчанию будет использоваться [`sanitizerHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/utils/sanitizer_html.ts) для санитизации.
+- Установка значения в `false` отключит санитизацию, сохраняя текст вывода в исходном виде.
+ Это не рекомендуется, так как может привести к некорректному рендерингу и сделать ваше приложение уязвимым для XSS атак.
+ Если вы выбираете этот вариант, убедитесь в правильной обработке данных.
+- Если вы предоставите функцию, она будет использована вместо стандартного санитайзера.
+
+```ts
+const myTextSanitizer: TextSanitizer = (options: TextSanitizerOption): string =>
+ // Замените опасные символы
+ options.text.replaceAll(/[&<>"']/, (match) => {
+ switch (match) {
+ case "&":
+ return "&";
+ case "<":
+ return "<";
+ case ">":
+ return ">";
+ case '"':
+ return """;
+ case "'":
+ return "'";
+ default:
+ return match;
+ }
+ });
+
+// Используйте собственный санитайзер
+const entitiesParser = new EntitiesParser({ textSanitizer: myTextSanitizer });
+```
+
+## Случаи, когда лучше не использовать этот пакет
+
+Если вы сталкиваетесь с проблемами, подобными перечисленным ниже, возможно, вы сможете решить их без использования этого пакета.
+
+### Копирование и пересылка одного и того же сообщения
+
+Используйте метод [`forwardMessage`](https://core.telegram.org/bots/api#forwardmessage) для пересылки сообщений любого типа.
+
+Вы также можете воспользоваться методом [`copyMessage`](https://core.telegram.org/bots/api#copymessage), который выполняет ту же задачу, но без ссылки на оригинальное сообщение.
+Метод [`copyMessage`](https://core.telegram.org/bots/api#copymessage) работает как копирование сообщения и отправка его обратно в Telegram, что делает его похожим на обычное сообщение, а не на пересланное.
+
+```ts
+bot.on(":text", async (ctx) => {
+ // ID целевого чата для отправки.
+ const chatId = -946659600;
+ // Копировать текущее сообщение без ссылки на оригинальное.
+ await ctx.copyMessage(chatId);
+ // Переслать текущее сообщение с ссылкой на оригинальное.
+ await ctx.forwardMessage(chatId);
+});
+```
+
+### Ответ на сообщения с изменённым форматом текста
+
+Вы можете легко отвечать на входящие сообщения, используя HTML, Markdown или сущности.
+
+```ts
+bot.on(":text", async (ctx) => {
+ // Ответ с использованием HTML
+ await ctx.reply("жирный курсив", { parse_mode: "HTML" });
+ // Ответ с использованием Telegram Markdown V2
+ await ctx.reply("*жирный* _курсив_", { parse_mode: "MarkdownV2" });
+ // Ответ с использованием сущностей
+ await ctx.reply("жирный курсив", {
+ entities: [
+ { offset: 0, length: 6, type: "bold" },
+ { offset: 7, length: 6, type: "italic" },
+ ],
+ });
+});
+```
+
+::: tip Используйте parse-mode для улучшенного форматирования
+Используйте официальный плагин [`parse-mode`](./parse-mode) для более удобного создания форматированных сообщений.
+:::
+
+## Краткая информация о плагине
+
+- Название: `entity-parser`
+- [Пакет](https://jsr.io/@qz/telegram-entities-parser)
+- [Исходник](https://github.com/quadratz/telegram-entities-parser)
diff --git a/site/docs/uk/plugins/entity-parser.md b/site/docs/uk/plugins/entity-parser.md
new file mode 100644
index 000000000..402294cd5
--- /dev/null
+++ b/site/docs/uk/plugins/entity-parser.md
@@ -0,0 +1,238 @@
+---
+prev: false
+next: false
+---
+
+# Парсер сутностей (`entity-parser`)
+
+Перетворює [сутності Telegram](https://core.telegram.org/bots/api#messageentity) у семантичний HTML.
+
+## Коли мені слід використовувати це?
+
+Напевно, ніколи!
+
+Хоча цей плагін може генерувати HTML, зазвичай краще надсилати до Telegram безпосередньо текст і сутності.
+
+Перетворення в HTML необхідне лише в рідкісних випадках, коли вам потрібно використовувати текст у форматі Telegram **поза межами** самого Telegram, наприклад, для відображення повідомлень Telegram на вебсайті.
+
+Перегляньте розділ [_Випадки, коли краще не використовувати цей пакет_](#випадки-коли-краще-не-використовувати-цеи-пакет), щоб визначити, чи є у вас подібна проблема, яку потрібно вирішити.
+
+Якщо ви не впевнені, чи підходить цей плагін для вашого випадку використання, будь ласка, не соромтеся запитувати в нашій [групі в Telegram](https://t.me/grammyjs).
+У більшості випадків люди приходять до висновку, що їм насправді не потрібен цей плагін для вирішення їхніх проблем!
+
+## Встановлення
+
+Запустіть наступну команду у вашому терміналі на основі вашого середовища виконання або пакетного менеджера:
+
+::: code-group
+
+```sh:no-line-numbers [Deno]
+deno add jsr:@qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Bun]
+bunx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [pnpm]
+pnpm dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Yarn]
+yarn dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [npm]
+npx jsr add @qz/telegram-entities-parser
+```
+
+:::
+
+## Просте використання
+
+Використовувати цей плагін дуже просто.
+Ось короткий приклад:
+
+```ts
+import { EntitiesParser } from "@qz/telegram-entities-parser";
+import type { Message } from "@qz/telegram-entities-parser/types";
+
+// Для кращої продуктивності створіть екземпляр поза функцією.
+const entitiesParser = new EntitiesParser();
+const parse = (message: Message) => entitiesParser.parse({ message });
+
+bot.on(":text", (ctx) => {
+ const html = parse(ctx.msg); // Перетворення тексту в рядок HTML.
+});
+
+bot.on(":photo", (ctx) => {
+ const html = parse(ctx.msg); // Перетворення підпису в рядок HTML.
+});
+```
+
+## Просунуте використання
+
+### Налаштування вихідного тегу HTML
+
+Цей пакет перетворює сутності у семантичний HTML, дотримуючись найкращих практик і стандартів, наскільки це можливо.
+Однак, результат може не завжди відповідати вашим очікуванням.
+
+Щоб вирішити цю проблему, ви можете використати власний `renderer` для налаштування елементів HTML, що оточують текст, відповідно до ваших правил.
+Ви можете змінити певні правила, розширивши стандартний [`RendererHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts) або перевизначити всі правила, застосувавши [`Renderer`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts).
+
+Щоб розширити існуючий `renderer`, зробіть наступне:
+
+```ts
+import { EntitiesParser, RendererHtml } from "@qz/telegram-entities-parser";
+import type {
+ CommonEntity,
+ RendererOutput,
+} from "@qz/telegram-entities-parser/types";
+
+// Змініть правило для сутності з жирним шрифтом,
+// залишивши решту типів, як визначено у `RendererHtml`.
+class MyRenderer extends RendererHtml {
+ override bold(
+ options: { text: string; entity: CommonEntity },
+ ): RendererOutput {
+ return {
+ prefix: '',
+ suffix: "",
+ };
+ }
+}
+
+const entitiesParser = new EntitiesParser({ renderer: new MyRenderer() });
+```
+
+Параметр `options` приймає обʼєкт з `text` та `entity`.
+
+- `text`: конкретний текст, на який посилається поточна сутність.
+- `entity`: залежно від типу сутності може бути представлений різними інтерфейсами, як-от `CommonEntity`, `CustomEmojiEntity`, `PreEntity`, `TextLinkEntity` або `TextMentionEntity`.
+ Наприклад, тип `bold` має сутність з інтерфейсом `CommonEntity`, тоді як тип `text_link` може мати сутність з інтерфейсом `TextLinkEntity`, оскільки він включає додаткові властивості, наприклад, `url`.
+
+Ось повний список інтерфейсів та результати для кожного типу сутності:
+
+| Тип сутності | Інтерфейс | Результат |
+| ----------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `blockquote` | `CommonEntity` | ` ...
` |
+| `bold` | `CommonEntity` | ` ... ` |
+| `bot_command` | `CommonEntity` | ` ... ` |
+| `cashtag` | `CommonEntity` | ` ... ` |
+| `code` | `CommonEntity` | ` ...
` |
+| `custom_emoji` | `CustomEmojiEntity` | ` ... ` |
+| `email` | `CommonEntity` | ` ... ` |
+| `expandable_blockquote` | `CommonEntity` | ` ...
` |
+| `hashtag` | `CommonEntity` | ` ... ` |
+| `italic` | `CommonEntity` | ` ... ` |
+| `mention` | `CommonEntity` | ` ... ` |
+| `phone_number` | `CommonEntity` | ` ... ` |
+| `pre` | `PreEntity` | ` ...
` або ` ...
` |
+| `spoiler` | `CommonEntity` | ` ... ` |
+| `strikethrough` | `CommonEntity` | ` ... ` |
+| `text_link` | `TextLinkEntity` | ` ... ` |
+| `text_mention` | `TextMentionEntity` | ` ... ` або ` ... ` |
+| `underline` | `CommonEntity` | ` ... ` |
+| `url` | `CommonEntity` | ` ... ` |
+
+Якщо ви не впевнені, який інтерфейс правильний, зверніться до того, як реалізовано [Renderer](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts) або [RendererHtml](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts).
+
+### Редагування та очищення тексту
+
+Вихідний текст за замовчуванням очищується, щоб забезпечити правильне відображення HTML і запобігти XSS-вразливостям.
+
+| Вхідний символ | Вихідна сутність HTML |
+| -------------- | --------------------- |
+| `&` | `&` |
+| `<` | `<` |
+| `>` | `>` |
+| `"` | `"` |
+| `'` | `'` |
+
+Наприклад, результат `Жирний & Курсив` буде перетворений в `Жирний & Курсив`.
+
+Ви можете змінити цю поведінку, вказавши `textSanitizer` при створенні екземпляра [`EntitiesParser`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/mod.ts):
+
+- Якщо ви не вкажете `textSanitizer`, буде використано [`sanitizerHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/utils/sanitizer_html.ts) як типовий очищувач.
+- Якщо вказати значення `false`, очищення буде пропущено, а виведений текст буде збережено як оригінал.
+ Це не рекомендується, оскільки може призвести до некоректного рендерингу і зробити вашу програму вразливою до XSS-атак.
+ Якщо ви вибрали цю опцію, забезпечте належну обробку результату.
+- Якщо ви надасте функцію, вона буде використовуватися замість типового очищувача.
+
+```ts
+const myTextSanitizer: TextSanitizer = (options: TextSanitizerOption): string =>
+ // Замінюємо небезпечні символи.
+ options.text.replaceAll(/[&<>"']/, (match) => {
+ switch (match) {
+ case "&":
+ return "&";
+ case "<":
+ return "<";
+ case ">":
+ return ">";
+ case '"':
+ return """;
+ case "'":
+ return "'";
+ default:
+ return match;
+ }
+ });
+
+// Застосовуємо очищувач.
+const entitiesParser = new EntitiesParser({ textSanitizer: myTextSanitizer });
+```
+
+## Випадки, коли краще не використовувати цей пакет
+
+Якщо ви зіткнулися з проблемами, подібними до наведених нижче, можливо, вам вдасться вирішити їх без використання цього пакету.
+
+### Копіювання та пересилання одного і того ж повідомлення
+
+Використовуйте [`forwardMessage`](https://core.telegram.org/bots/api#forwardmessage) для пересилання повідомлень будь-якого типу.
+
+Ви також можете використовувати [`copyMessage`](https://core.telegram.org/bots/api#copymessage), який виконає ту ж саму дію, але не міститиме посилання на оригінальне повідомлення.
+[`copyMessage`](https://core.telegram.org/bots/api#copymessage) поводиться так, ніби копіює повідомлення і надсилає його назад у Telegram, при цьому воно відображається як звичайне повідомлення, а не як переслане.
+
+```ts
+bot.on(":text", async (ctx) => {
+ // Ідентифікатор цільового чату для надсилання.
+ const chatId = -946659600;
+ // Пересилаємо поточне повідомлення без посилання на початкове повідомлення.
+ await ctx.copyMessage(chatId);
+ // Пересилаємо поточне повідомлення з посиланням на початкове повідомлення.
+ await ctx.forwardMessage(chatId);
+});
+```
+
+### Відповідь на повідомлення зі зміненим форматуванням тексту
+
+Ви можете легко відповідати на вхідні повідомлення за допомогою HTML, Markdown або сутностей.
+
+```ts
+bot.on(":text", async (ctx) => {
+ // Відповідаємо за допомогою HTML.
+ await ctx.reply("жирний курсив", { parse_mode: "HTML" });
+ // Відповідаємо за допомогою Telegram Markdown V2.
+ await ctx.reply("*жирний* _курсив_", { parse_mode: "MarkdownV2" });
+ // Відповідаємо за допомогою сутностей.
+ await ctx.reply("жирний курсив", {
+ entities: [
+ { offset: 0, length: 6, type: "bold" },
+ { offset: 7, length: 6, type: "italic" },
+ ],
+ });
+});
+```
+
+::: tip Просунуте форматування
+
+Використовуйте офіційний плагін [`parse-mode`](./parse-mode) для кращого досвіду створення форматованих повідомлень.
+
+:::
+
+## Загальні відомості про плагін
+
+- Назва: `entity-parser`
+- [Пакет](https://jsr.io/@qz/telegram-entities-parser)
+- [Джерело](https://github.com/quadratz/telegram-entities-parser)
diff --git a/site/docs/zh/plugins/entity-parser.md b/site/docs/zh/plugins/entity-parser.md
new file mode 100644
index 000000000..09fe9a00e
--- /dev/null
+++ b/site/docs/zh/plugins/entity-parser.md
@@ -0,0 +1,237 @@
+---
+prev: false
+next: false
+---
+
+# 实体解析器 (`entity-parser`)
+
+将 [Telegram 实体 (entities)](https://core.telegram.org/bots/api#messageentity) 转换为语义 HTML。
+
+## 我应该在什么时候用这个插件?
+
+最好**永远别用**!
+
+虽然这个插件可以生成 HTML,但一般而言最好将文本和实体发送回 Telegram。
+
+仅在极少数情况下才需要将实体转换为 HTML,即你需要在 Telegram **之外**使用带 Telegram 格式的文本,例如在网站上显示 Telegram 消息。
+
+请参阅 [_最好不要使用这个包的情况_](#最好不要使用这个包的情况) 部分,确认你是不是有类似的问题要解决。
+
+如果你不确定在你的情况下使用此插件是否合适,请随时在我们的 [Telegram 群组](https://t.me/grammyjs) 中提问。
+在大多数情况下,人们会发现他们实际上并不需要这个插件来解决他们的问题!
+
+## 安装
+
+根据你的运行时或包管理器在终端中运行以下命令:
+
+::: code-group
+
+```sh:no-line-numbers [Deno]
+deno add jsr:@qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Bun]
+bunx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [pnpm]
+pnpm dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [Yarn]
+yarn dlx jsr add @qz/telegram-entities-parser
+```
+
+```sh:no-line-numbers [npm]
+npx jsr add @qz/telegram-entities-parser
+```
+
+:::
+
+## 基本用法
+
+使用此插件非常简单。
+这是一个简单的示例:
+
+```ts
+import { EntitiesParser } from "@qz/telegram-entities-parser";
+import type { Message } from "@qz/telegram-entities-parser/types";
+
+// 为了获得更好的性能,请在函数外部创建实例。
+const entitiesParser = new EntitiesParser();
+const parse = (message: Message) => entitiesParser.parse({ message });
+
+bot.on(":text", (ctx) => {
+ const html = parse(ctx.msg); // 将文本转换为 HTML 字符串
+});
+
+bot.on(":photo", (ctx) => {
+ const html = parse(ctx.msg); // 将标题转换为 HTML 字符串
+});
+```
+
+## 高级用法
+
+### 自定义输出的 HTML 标签
+
+这个包将实体转换为语义 HTML,尽可能地遵循最佳实践和标准。
+但是,提供的输出可能并不总是你所期望的。
+
+为了解决这个问题,你可以使用自己的 `renderer` 根据规则自定义环绕文本的 HTML 元素。
+你可以通过扩展默认的 [`RendererHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts) 来修改特定规则,或者通过实现 [`Renderer`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts) 来覆盖所有规则。
+
+要扩展现有的 `renderer`,请执行以下操作:
+
+```ts
+import { EntitiesParser, RendererHtml } from "@qz/telegram-entities-parser";
+import type {
+ CommonEntity,
+ RendererOutput,
+} from "@qz/telegram-entities-parser/types";
+
+// 更改粗体类型实体的规则,
+// 但保留 `RendererHtml` 定义的其余类型。
+class MyRenderer extends RendererHtml {
+ override bold(
+ options: { text: string; entity: CommonEntity },
+ ): RendererOutput {
+ return {
+ prefix: '',
+ suffix: "",
+ };
+ }
+}
+
+const entitiesParser = new EntitiesParser({ renderer: new MyRenderer() });
+```
+
+`options` 参数接受带有 `text` 和 `entity` 参数的对象。
+
+- `text`:当前实体引用的特定文本。
+- `entity`:根据实体类型以不同接口表示,例如 `CommonEntity`、`CustomEmojiEntity`、`PreEntity`、`TextLinkEntity` 或 `TextMentionEntity`。
+ 例如,`bold` 实体符合 `CommonEntity` 接口,而 `text_link` 实体则符合 `TextLinkEntity` 接口,因为它包含其他额外属性,例如 `url`。
+
+以下是接口的完整列表以及每种实体类型的输出:
+
+| 实体类型 | 接口 | 结果 |
+| ----------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `blockquote` | `CommonEntity` | ` ...
` |
+| `bold` | `CommonEntity` | ` ... ` |
+| `bot_command` | `CommonEntity` | ` ... ` |
+| `cashtag` | `CommonEntity` | ` ... ` |
+| `code` | `CommonEntity` | ` ...
` |
+| `custom_emoji` | `CustomEmojiEntity` | ` ... ` |
+| `email` | `CommonEntity` | ` ... ` |
+| `expandable_blockquote` | `CommonEntity` | ` ...
` |
+| `hashtag` | `CommonEntity` | ` ... ` |
+| `italic` | `CommonEntity` | ` ... ` |
+| `mention` | `CommonEntity` | ` ... ` |
+| `phone_number` | `CommonEntity` | ` ... ` |
+| `pre` | `PreEntity` | ` ...
` 或 ` ...
` |
+| `spoiler` | `CommonEntity` | ` ... ` |
+| `strikethrough` | `CommonEntity` | ` ... ` |
+| `text_link` | `TextLinkEntity` | ` ... ` |
+| `text_mention` | `TextMentionEntity` | ` ... ` 或 ` ... ` |
+| `underline` | `CommonEntity` | ` ... ` |
+| `url` | `CommonEntity` | ` ... ` |
+
+如果你不确定哪个接口是正确的,请参考 [Renderer](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer.ts) 或 [RendererHtml](https://github.com/quadratz/telegram-entities-parser/blob/main/src/renderers/renderer_html.ts) 的实现方式。
+
+### 自定义文本清理器
+
+默认情况下,输出文本经过清理,以确保正确呈现 HTML 并防止 XSS 漏洞。
+
+| 输入 | 输出 |
+| ---- | -------- |
+| `&` | `&` |
+| `<` | `<` |
+| `>` | `>` |
+| `"` | `"` |
+| `'` | `'` |
+
+例如,结果 `粗体 & 斜体` 将被清理为 `粗体 & 斜体`。
+
+你可以在实例化 [`EntitiesParser`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/mod.ts) 时指定 `textSanitizer` 来覆盖此行为:
+
+- 如果你未指定 `textSanitizer`,它将默认使用 [`sanitizerHtml`](https://github.com/quadratz/telegram-entities-parser/blob/main/src/utils/sanitizer_html.ts) 作为清理程序。
+- 将值设置为 `false` 将跳过清理,保持输出文本为原始文本。
+ 不建议这样做,因为它可能会导致渲染不正确,并使你的应用程序容易受到 XSS 攻击。
+ 如果选择此选项,请确保你正确处理输出文本。
+- 如果你提供一个函数,它将被用来代替默认清理程序。
+
+```ts
+const myTextSanitizer: TextSanitizer = (options: TextSanitizerOption): string =>
+ // 替换危险的字符
+ options.text.replaceAll(/[&<>"']/, (match) => {
+ switch (match) {
+ case "&":
+ return "&";
+ case "<":
+ return "<";
+ case ">":
+ return ">";
+ case '"':
+ return """;
+ case "'":
+ return "'";
+ default:
+ return match;
+ }
+ });
+
+// 实施清理。
+const entitiesParser = new EntitiesParser({ textSanitizer: myTextSanitizer });
+```
+
+## 最好不要使用这个包的情况
+
+如果你遇到的问题和下面列出的问题类似,你可能不需要使用这个包就能解决问题。
+
+### 复制和转发同一条消息
+
+使用 [`forwardMessage`](https://core.telegram.org/bots/api#forwardmessage) 即可转发任何类型的消息。
+
+你还可以使用 [`copyMessage`](https://core.telegram.org/bots/api#copymessage) API。该 API 会执行同样的操作,但不包含指向原始消息的链接。
+[`copyMessage`](https://core.telegram.org/bots/api#copymessage) 的行为类似于复制消息并将其发送回 Telegram,使其显示为常规消息而不是转发的消息。
+
+```ts
+bot.on(":text", async (ctx) => {
+ // 要发送消息的对话的 ID。
+ const chatId = -946659600;
+ // 转发当前消息,不包含原始消息的链接。
+ await ctx.copyMessage(chatId);
+ // 转发当前消息,包含原始消息的链接。
+ await ctx.forwardMessage(chatId);
+});
+```
+
+### 回复修改了文本格式的消息
+
+你可以轻松使用 HTML、Markdown 或实体 (`entities`) 来回复消息。
+
+```ts
+bot.on(":text", async (ctx) => {
+ // 使用 HTML 回复
+ await ctx.reply("bold italic", { parse_mode: "HTML" });
+ // 使用 Telegram Markdown V2 回复
+ await ctx.reply("*bold* _italic_", { parse_mode: "MarkdownV2" });
+ // 使用实体回复
+ await ctx.reply("bold italic", {
+ entities: [
+ { offset: 0, length: 5, type: "bold" },
+ { offset: 5, length: 6, type: "italic" },
+ ],
+ });
+});
+```
+
+::: tip 使用 parse-mode 获得更好的格式化体验
+
+使用官方 [`parse-mode` (解析模式)](./parse-mode) 插件获得更好的格式化消息构建体验。
+:::
+
+## 插件概述
+
+- 名称: `entity-parser`
+- [包](https://jsr.io/@qz/telegram-entities-parser)
+- [源码](https://github.com/quadratz/telegram-entities-parser)