DEV Community

ILshat Khamitov
ILshat Khamitov

Posted on

4 2

Add different multilingual settings for FactsGeneratorModule in NestJS Telegram bot

Links

https://github.com/EndyKaufman/kaufman-bot - source code of bot

https://telegram.me/DevelopKaufmanBot - current bot in telegram

https://dev.to/endykaufman/series/17029 - series about custom injector

Description of work

The fact generator is based on the ScraperModule, we will not introduce the logic of supporting different configurations for different languages into this module.

For different options for working for different languages, we will add a duplicate ScraperModule import with a different configuration and create a language-specific command handler.

In order for the logic of two different ScraperModules not to overlap, we will wrap its import in CustomInjectorModule.forFeature.

Update facts-generator

Create new service for Russian language

libs/facts-generator/server/src/lib/facts-generator-services/ru-facts-generator.service.ts

import {
  BotCommandsEnum,
  BotCommandsProvider,
  BotCommandsProviderActionMsg,
  BotCommandsProviderActionResultType,
  BotСommandsToolsService,
} from '@kaufman-bot/core/server';
import { ScraperService } from '@kaufman-bot/html-scraper/server';
import { Injectable } from '@nestjs/common';

@Injectable()
export class RuFactsGeneratorService implements BotCommandsProvider {
  constructor(
    private readonly scraperService: ScraperService,
    private readonly botСommandsToolsService: BotСommandsToolsService
  ) {}

  async onHelp<
    TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
  >(msg: TMsg) {
    const locale = msg.from?.language_code;
    if (!locale?.includes('ru')) {
      return null;
    }
    return await this.scraperService.onHelp(msg);
  }

  async onMessage<
    TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
  >(msg: TMsg): Promise<BotCommandsProviderActionResultType<TMsg>> {
    const locale = msg.from?.language_code;
    if (!locale?.includes('ru')) {
      return null;
    }
    if (
      this.botСommandsToolsService.checkCommands(
        msg.text,
        [...Object.keys(BotCommandsEnum)],
        locale
      )
    ) {
      const result = await this.scraperService.onMessage(msg);
      try {
        if (result?.type === 'text') {
          return {
            type: 'text',
            text: result.text.split('\\"').join('"').split('\n').join(' '),
          };
        }
        return result;
      } catch (err) {
        console.debug(result);
        console.error(err, err.stack);
        throw err;
      }
    }
    return null;
  }
}

Enter fullscreen mode Exit fullscreen mode

Update old service for English language

libs/facts-generator/server/src/lib/facts-generator-services/facts-generator.service.ts

import {
  BotCommandsEnum,
  BotCommandsProvider,
  BotCommandsProviderActionMsg,
  BotCommandsProviderActionResultType,
  BotСommandsToolsService,
} from '@kaufman-bot/core/server';
import { ScraperService } from '@kaufman-bot/html-scraper/server';
import { Injectable } from '@nestjs/common';

@Injectable()
export class FactsGeneratorService implements BotCommandsProvider {
  constructor(
    private readonly scraperService: ScraperService,
    private readonly botСommandsToolsService: BotСommandsToolsService
  ) {}

  async onHelp<
    TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
  >(msg: TMsg) {
    const locale = msg.from?.language_code;
    if (locale?.includes('ru')) {
      return null;
    }
    return await this.scraperService.onHelp(msg);
  }

  async onMessage<
    TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
  >(msg: TMsg): Promise<BotCommandsProviderActionResultType<TMsg>> {
    const locale = msg.from?.language_code;
    if (locale?.includes('ru')) {
      return null;
    }
    if (
      this.botСommandsToolsService.checkCommands(
        msg.text,
        [...Object.keys(BotCommandsEnum)],
        locale
      )
    ) {
      const result = await this.scraperService.onMessage(msg);
      try {
        if (result?.type === 'text') {
          return {
            type: 'text',
            text: result.text
              .replace('\n\nTweet [http://twitter.com/share]', '')
              .split('\\"')
              .join('"')
              .split('\n')
              .join(' '),
          };
        }
        return result;
      } catch (err) {
        console.debug(result);
        console.error(err, err.stack);
        throw err;
      }
    }
    return null;
  }
}

Enter fullscreen mode Exit fullscreen mode

Update FactsGeneratorModule

libs/facts-generator/server/src/lib/facts-generator.module.ts

import {
  BotCommandsModule,
  BOT_COMMANDS_PROVIDER,
} from '@kaufman-bot/core/server';
import { ScraperModule } from '@kaufman-bot/html-scraper/server';
import { DynamicModule, Module } from '@nestjs/common';
import { getText } from 'class-validator-multi-lang';
import { CustomInjectorModule } from 'nestjs-custom-injector';
import { TranslatesModule } from 'nestjs-translates';
import { FactsGeneratorService } from './facts-generator-services/facts-generator.service';
import { RuFactsGeneratorService } from './facts-generator-services/ru-facts-generator.service';

@Module({
  imports: [TranslatesModule, BotCommandsModule],
  exports: [TranslatesModule, BotCommandsModule],
})
export class FactsGeneratorModule {
  static forRoot(): DynamicModule {
    return {
      module: FactsGeneratorModule,
      imports: [
        CustomInjectorModule.forFeature({
          imports: [
            ScraperModule.forRoot({
              name: getText('Facts generator'),
              descriptions: getText(
                'Command to generate text with a random fact'
              ),
              usage: [getText('get facts'), getText('facts help')],
              contentSelector: '#z',
              spyWords: [getText('facts')],
              removeWords: [getText('get'), getText('please')],
              uri: 'http://randomfactgenerator.net/',
            }),
          ],
          providers: [
            {
              provide: BOT_COMMANDS_PROVIDER,
              useClass: FactsGeneratorService,
            },
          ],
          exports: [ScraperModule],
        }),
        CustomInjectorModule.forFeature({
          imports: [
            ScraperModule.forRoot({
              name: getText('Facts generator'),
              descriptions: getText(
                'Command to generate text with a random fact'
              ),
              usage: [getText('get facts'), getText('facts help')],
              contentSelector: '#fact > table > tbody > tr > td',
              spyWords: [getText('facts')],
              removeWords: [getText('get'), getText('please')],
              uri: 'https://randstuff.ru/fact/',
              contentCodepage: 'utf8',
            }),
          ],
          providers: [
            {
              provide: BOT_COMMANDS_PROVIDER,
              useClass: RuFactsGeneratorService,
            },
          ],
          exports: [ScraperModule],
        }),
      ],
    };
  }
}

Enter fullscreen mode Exit fullscreen mode

Prepare files and append translates if need

npm run generate

Because nothing to changed, we may commit code and test it from telegram
nothing to changed

Check new logic in telegram bot

Common help message

Common help message

Common help message in Russian language

Common help message in Russian language

Get fact in English language

Get fact in English language

Get fact in Russian language

Get fact in Russian language

In the next post, I will add people quotes and jokes for English and Russian languages...

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay