Entity Parser (entity-parser
)
Converts Telegram entities 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 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. 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:
deno add jsr:@qz/telegram-entities-parser
bunx jsr add @qz/telegram-entities-parser
pnpm dlx jsr add @qz/telegram-entities-parser
yarn dlx jsr add @qz/telegram-entities-parser
npx jsr add @qz/telegram-entities-parser
Simple Usage
Using this plugin is straightforward. Here’s a quick example:
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
});
2
3
4
5
6
7
8
9
10
11
12
13
14
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 Renderer
or override all the rules by implementing the Renderer
.
To extend the existing renderer
, do the following:
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: '<strong class="tg-bold">',
suffix: "</strong>",
};
}
}
const entitiesParser = new EntitiesParser({ renderer: new MyRenderer() });
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 asCommon
,Entity Custom
,Emoji Entity Pre
,Entity Text
, orLink Entity Text
. For instance, theMention Entity bold
type has an entity with theCommon
interface, while theEntity text
type may have an entity with the_link Text
interface, as it includes additional properties likeLink Entity url
.
Here is the full list of interfaces and the output for each entity type:
Entity Type | Interface | Result |
---|---|---|
blockquote | Common | <blockquote class |
bold | Common | <b class |
bot | Common | <span class |
cashtag | Common | <span class |
code | Common | <code class |
custom | Custom | <span class |
email | Common | <a class |
expandable | Common | <blockquote class |
hashtag | Common | <span class |
italic | Common | <i class |
mention | Common | <a class |
phone | Common | <a class |
pre | Pre | <pre class or <pre class |
spoiler | Common | <span class |
strikethrough | Common | <del class |
text | Text | <a class |
text | Text | <a class or <a class |
underline | Common | <span class |
url | Common | <a class |
If you are unsure which interface is correct, refer to how the Renderer or Renderer
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 <b>Bold<
will be sanitized to <b>Bold<
.
You can override this behavior by specifying a text
when instantiating the Entities
:
- If you do not specify
text
, it will default to usingSanitizer sanitizer
as the sanitizer.Html - 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.
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 });
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 forward
to forward messages of any kind.
You can also use the copy
API, which performs the same action but does not include a link to the original message. copy
behaves like copying the message and sending it back to Telegram, making it appear as a regular message rather than a forwarded one.
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);
});
2
3
4
5
6
7
8
Replying to Messages with Modified Text Format
You can easily reply to incoming messages using HTML, Markdown, or entities.
bot.on(":text", async (ctx) => {
// Reply using HTML
await ctx.reply("<b>bold</b> <i>italic</i>", { 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" },
],
});
});
2
3
4
5
6
7
8
9
10
11
12
13
Use parse-mode for a Better Formatting Experience
Use the official parse
plugin for a better experience constructing formatted messages.