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)