admin管理员组

文章数量:1291735

Following the step by step of this question Angular 17: SSR with i18n alongside

The solved issue from angular 17 is breaking in angular 19

Angular 19, is building different server.mjs and now if I update the proxy-server.mjs as follow

import  serverEn  from './server/en/server.mjs';
import  serverFr  from './server/fr/server.mjs';

const express = require('express');

function getPreferredLanguage(req) {
  const acceptedLanguages = req.acceptsLanguages(['fr', 'en']);
  return acceptedLanguages || 'fr'; // Default to 'fr' if no match is found
}

function run() {
  const port = process.env.PORT || 4000;
  const server = express();
  // Redirect root requests to the preferred language
  server.get('/', (req, res) => {
    const lang = getPreferredLanguage(req);
    res.redirect(`/${lang}`);
  });

  // Serve the language-specific servers
  server.use('/fr', serverFr());
  server.use('/en', serverEn());

  // Handle unmatched routes
  server.use((req, res) => {
    res.status(404).send('Page not found');
  });
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

run();

the new build server.mjs file break : TypeError: Cannot read properties of undefined (reading 'method')

Do we have a standard way to integrate i18n with Angular 19 ?

Following the step by step of this question Angular 17: SSR with i18n alongside

The solved issue from angular 17 is breaking in angular 19

Angular 19, is building different server.mjs and now if I update the proxy-server.mjs as follow

import  serverEn  from './server/en/server.mjs';
import  serverFr  from './server/fr/server.mjs';

const express = require('express');

function getPreferredLanguage(req) {
  const acceptedLanguages = req.acceptsLanguages(['fr', 'en']);
  return acceptedLanguages || 'fr'; // Default to 'fr' if no match is found
}

function run() {
  const port = process.env.PORT || 4000;
  const server = express();
  // Redirect root requests to the preferred language
  server.get('/', (req, res) => {
    const lang = getPreferredLanguage(req);
    res.redirect(`/${lang}`);
  });

  // Serve the language-specific servers
  server.use('/fr', serverFr());
  server.use('/en', serverEn());

  // Handle unmatched routes
  server.use((req, res) => {
    res.status(404).send('Page not found');
  });
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

run();

the new build server.mjs file break : TypeError: Cannot read properties of undefined (reading 'method')

Do we have a standard way to integrate i18n with Angular 19 ?

Share Improve this question asked Feb 13 at 12:44 mbagiellambagiella 3623 silver badges17 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 1

Error: The original error was due to attempting to call serverFr() as a function, whereas serverFr and serverEn are instances of Express applications (or objects), not functions.

Solution: The solution is to use the Express application instances (serverFr and serverEn) directly as middleware in my main server.

My corrected proxy-server.mjs, however I think we could do something more dynamic with the new generated file angular-app-engine-manifest.mjs, but there is no doc about it. If someone knows I'm interested :)

import serverEn from './server/en/server.mjs';
import serverFr from './server/fr/server.mjs';

const express = require('express');

function getPreferredLanguage(req) {
  const acceptedLanguages = req.acceptsLanguages(['fr', 'en']);
  return acceptedLanguages || 'fr'; // Default to 'fr' if no     match is found
}

function run() {
  const port = process.env.PORT || 4000;
  const server = express();
  // Redirect root requests to the preferred language
  server.get('/', (req, res) => {
    const lang = getPreferredLanguage(req);
    res.redirect(`/${lang}`);
  });

  // Serve the language-specific servers
  server.use('/fr', serverFr);
  server.use('/en', serverEn);

  // Handle unmatched routes
  server.use((req, res) => {
    res.status(404).send('Page not found');
  });
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

run();

The server.ts that I'm currently using

import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine, isMainModule } from '@angular/ssr/node';
import express from 'express';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import bootstrap from './main.server';
import { LOCALE_ID } from '@angular/core';
import { REQUEST, RESPONSE } from './express.tokens';

const serverDistFolder = dirname(fileURLToPath(import.meta.url));
const indexHtml = join(serverDistFolder, 'index.server.html');
const app = express();
const commonEngine = new CommonEngine();

// Function to detect the locale from the request
function getLocale(req: express.Request): string {
  const supportedLocales = ['fr', 'en']; // Add your supported locales here
  const localeFromUrl = req.originalUrl.split('/')[1]; // Extract locale from URL
  return supportedLocales.includes(localeFromUrl) ? localeFromUrl : 'en'; // Default to 'en'
}

// Serve static files from the correct localized folder
app.get(
  '**',
  (req, res, next) => {
    const lang = getLocale(req);
    const browserDistFolder = resolve(serverDistFolder, `../../browser/${lang}`);
    express.static(browserDistFolder, {
      maxAge: '1y',
      index: 'index.html'
    })(req, res, next);
  }
);

// Handle all other requests by rendering the Angular application
app.get('**', (req, res, next) => {
  const { protocol, originalUrl, headers } = req;
  const lang = getLocale(req);
  const langPath = `/${lang}/`;
  const browserDistFolder = resolve(serverDistFolder, `../../browser/${lang}`);

  commonEngine
    .render({
      bootstrap,
      documentFilePath: indexHtml,
      url: `${protocol}://${headers.host}${originalUrl}`,
      publicPath: browserDistFolder,
      providers: [
        { provide: APP_BASE_HREF, useValue: langPath },
        { provide: LOCALE_ID, useValue: lang },
        { provide: RESPONSE, useValue: res },
        { provide: REQUEST, useValue: req },
      ],
    })
    .then((html) => res.send(html))
    .catch((err) => next(err));
});

// Start the server
if (isMainModule(import.meta.url)) {
  const port = process.env['PORT'] || 4000;
  app.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

export default app;

I followed this post and the related links to implement i18n on Angular 19 with SSR and ended up with the same TypeError: Cannot read properties of undefined (reading 'method') error.

Since I didn't understand what the Solution on the previous Answer meant doing I searched a bit more for it and found the following gist with the code that fixed this problem.

https://gist.github/agarciar/4645d32d125db8e93599d4fe152979c1

I was missing the update to the server.ts file.

import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine } from '@angular/ssr';
import express from 'express';
import { fileURLToPath } from 'node:url';
import { basename, dirname, join, resolve } from 'node:path';
import bootstrap from './src/main.server';
import { LOCALE_ID } from '@angular/core';
import { REQUEST, RESPONSE } from '@animajobs/express.tokens';

export function app(): express.Express {
  const server = express();
  const serverDistFolder = dirname(fileURLToPath(import.meta.url));
  const lang = basename(serverDistFolder);
  const langPath = `/${lang}/`;
  const browserDistFolder = resolve(serverDistFolder, '../../browser');
  const indexHtml = join(serverDistFolder, 'index.server.html');

  const commonEngine = new CommonEngine();

  server.set('view engine', 'html');
  server.set('views', browserDistFolder);

  // Serve static files from /browser
  server.get(
    `*.*`,
    express.static(browserDistFolder + langPath, {
      maxAge: '1y',
    })
  );

  // All regular routes use the Angular engine
  server.get(`*`, (req, res, next) => {
    const { protocol, originalUrl, headers } = req;
    commonEngine
      .render({
        bootstrap,
        documentFilePath: indexHtml,
        url: `${protocol}://${headers.host}${originalUrl}`,
        publicPath: browserDistFolder,
        providers: [
          { provide: APP_BASE_HREF, useValue: langPath },
          { provide: LOCALE_ID, useValue: lang },
          { provide: RESPONSE, useValue: res },
          { provide: REQUEST, useValue: req },
        ],
      })
      .then((html) => res.send(html))
      .catch((err) => next(err));
  });

  return server;
}

it's help me a lot to config angular 19 ssr on Cpanel . Thank you !

import express from 'express';
import fs from 'fs';
import path from 'path';
import { createApp as createAppRo } from './dist/folder/server/ro/server.mjs';
import { createApp as createAppEn } from './dist/folder/server/en/server.mjs';
import { createApp as createAppRu } from './dist/folder/server/ru/server.mjs';

const logFile = fs.createWriteStream(path.join(process.cwd(), 'server.log'), { flags: 'a' });

const originalLog = console.log;
console.log = function() {
    logFile.write(new Date().toISOString() + ': ' + Array.from(arguments).join(' ') + '\n');
    originalLog.apply(console, arguments);
};

const mainApp = express();



mainApp.use('/en', (req, res, next) => {
    console.log('Accessing English route');
    createAppEn('en')(req, res, next);  
});

mainApp.use('/ru', (req, res, next) => {
    console.log('Accessing Russian route');
    createAppRu('ru')(req, res, next);  
});


mainApp.use('/', (req, res, next) => {
    console.log('Accessing root route (RO)');
    createAppRo('ro')(req, res, next);  
});



const port = process.env.PORT || 3000;
mainApp.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
});

export default mainApp;

本文标签: internationalizationAngular 19 SSR with i18n alongsideStack Overflow