From f88086e649f24b31992851d7999216df6da7b4d1 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:48:11 +0000 Subject: [PATCH] fix(@angular/ssr): improve locale handling in app-engine Refactor app-engine to correctly handle single locale configurations and update manifest type definitions. Add new test cases for localized apps with a single locale. closes #31675 --- packages/angular/ssr/src/app-engine.ts | 5 +- packages/angular/ssr/src/manifest.ts | 2 +- packages/angular/ssr/test/app-engine_spec.ts | 60 ++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/packages/angular/ssr/src/app-engine.ts b/packages/angular/ssr/src/app-engine.ts index 0ce5d23c30d1..dd204a4b595f 100644 --- a/packages/angular/ssr/src/app-engine.ts +++ b/packages/angular/ssr/src/app-engine.ts @@ -191,9 +191,10 @@ export class AngularAppEngine { * @returns A promise that resolves to the entry point exports or `undefined` if not found. */ private getEntryPointExportsForUrl(url: URL): Promise | undefined { - const { basePath } = this.manifest; + const { basePath, supportedLocales } = this.manifest; + if (this.supportedLocales.length === 1) { - return this.getEntryPointExports(''); + return this.getEntryPointExports(supportedLocales[this.supportedLocales[0]]); } const potentialLocale = getPotentialLocaleIdFromUrl(url, basePath); diff --git a/packages/angular/ssr/src/manifest.ts b/packages/angular/ssr/src/manifest.ts index 8fc415546033..0de603bba104 100644 --- a/packages/angular/ssr/src/manifest.ts +++ b/packages/angular/ssr/src/manifest.ts @@ -73,7 +73,7 @@ export interface AngularAppEngineManifest { * - `key`: The locale identifier (e.g., 'en', 'fr'). * - `value`: The url segment associated with that locale. */ - readonly supportedLocales: Readonly>; + readonly supportedLocales: Readonly>; } /** diff --git a/packages/angular/ssr/test/app-engine_spec.ts b/packages/angular/ssr/test/app-engine_spec.ts index 966edadce843..b08931b9400b 100644 --- a/packages/angular/ssr/test/app-engine_spec.ts +++ b/packages/angular/ssr/test/app-engine_spec.ts @@ -157,6 +157,66 @@ describe('AngularAppEngine', () => { }); }); + describe('Localized app with single locale', () => { + beforeAll(() => { + setAngularAppEngineManifest({ + entryPoints: { + it: createEntryPoint('it'), + }, + supportedLocales: { 'it': 'it' }, + basePath: '/', + }); + + appEngine = new AngularAppEngine(); + }); + + describe('handle', () => { + it('should return null for requests to unknown pages', async () => { + const request = new Request('https://example.com/unknown/page'); + const response = await appEngine.handle(request); + expect(response).toBeNull(); + }); + + it('should return a rendered page with correct locale', async () => { + const request = new Request('https://example.com/it/ssr'); + const response = await appEngine.handle(request); + expect(await response?.text()).toContain('SSR works IT'); + }); + + it('should correctly render the content when the URL ends with "index.html" with correct locale', async () => { + const request = new Request('https://example.com/it/ssr/index.html'); + const response = await appEngine.handle(request); + expect(await response?.text()).toContain('SSR works IT'); + expect(response?.headers?.get('Content-Language')).toBe('it'); + }); + + it('should return a serve prerendered page with correct locale', async () => { + const request = new Request('https://example.com/it/ssg'); + const response = await appEngine.handle(request); + expect(await response?.text()).toContain('SSG works IT'); + expect(response?.headers?.get('Content-Language')).toBe('it'); + }); + + it('should correctly serve the prerendered content when the URL ends with "index.html" with correct locale', async () => { + const request = new Request('https://example.com/it/ssg/index.html'); + const response = await appEngine.handle(request); + expect(await response?.text()).toContain('SSG works IT'); + }); + + it('should return null for requests to unknown pages in a locale', async () => { + const request = new Request('https://example.com/it/unknown/page'); + const response = await appEngine.handle(request); + expect(response).toBeNull(); + }); + + it('should return null for requests to file-like resources in a locale', async () => { + const request = new Request('https://example.com/it/logo.png'); + const response = await appEngine.handle(request); + expect(response).toBeNull(); + }); + }); + }); + describe('Non-localized app', () => { beforeAll(() => { @Component({