toonvanstrijp / nestjs-i18n

The i18n module for nestjs.
https://nestjs-i18n.com
Other
646 stars 111 forks source link

Does not work with handlebars - TypeError Cannot read properties of undefined (reading 'split') #649

Closed afarah1 closed 1 month ago

afarah1 commented 1 month ago

Describe the bug

A basic "hello world" following the docs fails with hbs as view engine. Steps to reproduce:

npm init
npm install --save-dev @nestjs/cli
npx nest new test
cd test
npm install --save hbs
npm install --save nestjs-i18n
mkdir views
echo "{{ t index.hello }}" >views/index.hbs
mkdir -p src/i18n/en
echo '{ "hello": "hiya" }' >src/i18n/en/index.json

src/main.ts

import {NestFactory} from '@nestjs/core';
import {NestExpressApplication} from '@nestjs/platform-express';
import {join} from 'path';
import {AppModule} from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(
    AppModule,
  );

  app.useStaticAssets(join(__dirname, '..', 'public'));
  app.setBaseViewsDir(join(__dirname, '..', 'views'));
  app.setViewEngine('hbs');

  await app.listen(3000);
}
bootstrap();

src/app.controller.ts

import {Controller, Get, Render} from '@nestjs/common';

@Controller()
export class AppController {
  @Get()
  @Render('index')
  getIndex() {}
}

src/app.module.ts

import {Module} from '@nestjs/common';
import {AppController} from './app.controller';
import {AppService} from './app.service';
import {AcceptLanguageResolver, I18nModule, QueryResolver} from 'nestjs-i18n';
import * as path from 'path';

@Module({
  imports: [
    I18nModule.forRoot({
      fallbackLanguage: 'en',
      loaderOptions: {
        path: path.join(__dirname, '/i18n/'),
        watch: true,
      },
      resolvers: [
        {use: QueryResolver, options: ['lang']},
        AcceptLanguageResolver,
      ],
      viewEngine: 'hbs'
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }

nest-cli.json

{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "deleteOutDir": true,
    "assets": [
      { "include": "i18n/**/*", "watchAssets": true }
    ]
  }
}

Finally:

npm run build
npm run start

Result:

$ npm run start

> test@0.0.1 start
> nest start

[Nest] 20507  - 08/12/2024, 7:13:45 PM     LOG [NestFactory] Starting Nest application...
[Nest] 20507  - 08/12/2024, 7:13:45 PM     LOG [InstanceLoader] AppModule dependencies initialized +15ms
[Nest] 20507  - 08/12/2024, 7:13:45 PM     LOG [InstanceLoader] I18nModule dependencies initialized +10ms
[Nest] 20507  - 08/12/2024, 7:13:45 PM     LOG [RoutesResolver] AppController {/}: +7ms
[Nest] 20507  - 08/12/2024, 7:13:45 PM     LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 20507  - 08/12/2024, 7:13:46 PM     LOG [I18nService] Handlebars helper registered
[Nest] 20507  - 08/12/2024, 7:13:46 PM     LOG [NestApplication] Nest application successfully started +1ms
[Nest] 20507  - 08/12/2024, 7:13:47 PM   ERROR [ExceptionsHandler] /tmp/nest-test/test/views/index.hbs: Cannot read properties of undefined (reading 'split')
TypeError: /tmp/nest-test/test/views/index.hbs: Cannot read properties of undefined (reading 'split')
    at I18nService.translateObject (/tmp/nest-test/test/node_modules/nestjs-i18n/src/services/i18n.service.ts:207:22)
    at I18nService.translate (/tmp/nest-test/test/node_modules/nestjs-i18n/src/services/i18n.service.ts:97:30)
    at I18nService.t (/tmp/nest-test/test/node_modules/nestjs-i18n/src/services/i18n.service.ts:150:17)
    at Object.I18nService.hbsHelper (/tmp/nest-test/test/node_modules/nestjs-i18n/src/services/i18n.service.ts:197:17)
    at Object.wrapper (/tmp/nest-test/test/node_modules/handlebars/lib/handlebars/internal/wrapHelper.js:10:19)
    at Object.eval [as main] (eval at createFunctionContext (/tmp/nest-test/test/node_modules/handlebars/dist/cjs/handlebars/compiler/javascript-compiler.js:262:23), <anonymous>:10:138)
    at main (/tmp/nest-test/test/node_modules/handlebars/lib/handlebars/runtime.js:230:22)
    at ret (/tmp/nest-test/test/node_modules/handlebars/lib/handlebars/runtime.js:250:12)
    at ret (/tmp/nest-test/test/node_modules/handlebars/lib/handlebars/compiler/compiler.js:548:21)
    at /tmp/nest-test/test/node_modules/hbs/lib/hbs.js:93:19

Reproduction

Yes

System Info

System:
    OS: Linux 6.6 Gentoo Linux
    CPU: (4) x64 Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz
    Memory: 11.57 GB / 15.57 GB
    Container: Yes
    Shell: 5.2.26 - /bin/bash
  Binaries:
    Node: 22.3.0 - /usr/bin/node
    npm: 10.8.1 - /usr/bin/npm

Used Package Manager

npm

Validations

afarah1 commented 1 month ago

PS: The issue is only in the views.

Using the same sample project, if we empty index.hbd and change to translate at the controller:

src/app.controller.ts

import {Controller, Get, Render} from '@nestjs/common';
import {I18nService} from 'nestjs-i18n';

@Controller()
export class AppController {
  constructor(private readonly i18n: I18nService) { }
  @Get()
  @Render('index')
  getIndex() {
    console.log(this.i18n.t('index.hello'));
  }
}

It works... Result:

$ npm run start

> test@0.0.1 start
> nest start

[Nest] 21422  - 08/12/2024, 7:19:44 PM     LOG [NestFactory] Starting Nest application...
[Nest] 21422  - 08/12/2024, 7:19:44 PM     LOG [InstanceLoader] I18nModule dependencies initialized +23ms
[Nest] 21422  - 08/12/2024, 7:19:44 PM     LOG [InstanceLoader] AppModule dependencies initialized +1ms
[Nest] 21422  - 08/12/2024, 7:19:44 PM     LOG [RoutesResolver] AppController {/}: +6ms
[Nest] 21422  - 08/12/2024, 7:19:44 PM     LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 21422  - 08/12/2024, 7:19:44 PM     LOG [I18nService] Handlebars helper registered
[Nest] 21422  - 08/12/2024, 7:19:44 PM     LOG [NestApplication] Nest application successfully started +1ms
hiya
^C
afarah1 commented 1 month ago

Turns out the issue is the path must be quoted in the .hbs template, i.e. {{ t 'index.hello' }} not {{ t index.hello }}. Maybe the error could be better handled as to not fail with TypeError.