diff --git a/packages/angular_devkit/build_angular/src/tools/esbuild/application-code-bundle.ts b/packages/angular_devkit/build_angular/src/tools/esbuild/application-code-bundle.ts index 3a54023b4c69..fa81c7ffed0d 100644 --- a/packages/angular_devkit/build_angular/src/tools/esbuild/application-code-bundle.ts +++ b/packages/angular_devkit/build_angular/src/tools/esbuild/application-code-bundle.ts @@ -308,6 +308,23 @@ export function createServerCodeBundleOptions( polyfills.push(`import '@angular/platform-server/init';`); + // Add Angular's global locale data if i18n options are present. + let needLocaleDataPlugin = false; + if (options.i18nOptions.shouldInline) { + // Add locale data for all active locales + for (const locale of options.i18nOptions.inlineLocales) { + polyfills.unshift(`import 'angular:locale/data:${locale}';`); + } + needLocaleDataPlugin = true; + } else if (options.i18nOptions.hasDefinedSourceLocale) { + // When not inlining and a source local is present, use the source locale data directly + polyfills.unshift(`import 'angular:locale/data:${options.i18nOptions.sourceLocale}';`); + needLocaleDataPlugin = true; + } + if (needLocaleDataPlugin) { + buildOptions.plugins.push(createAngularLocaleDataPlugin()); + } + buildOptions.plugins.push( createVirtualModulePlugin({ namespace: mainServerNamespace, diff --git a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-ssr.ts b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-ssr.ts index e17732a1e1dc..1977c2e3eae1 100644 --- a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-ssr.ts +++ b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-ssr.ts @@ -1,12 +1,10 @@ import { readFileSync, readdirSync } from 'node:fs'; import { getGlobalVariable } from '../../utils/env'; -import { copyFile, expectFileToMatch, replaceInFile, writeFile } from '../../utils/fs'; import { installWorkspacePackages, uninstallPackage } from '../../utils/packages'; import { ng } from '../../utils/process'; import { updateJsonFile, useSha } from '../../utils/project'; -import { readNgVersion } from '../../utils/version'; - -const snapshots = require('../../ng-snapshot/package.json'); +import { langTranslations, setupI18nConfig } from './setup'; +import { expectFileToMatch } from '../../utils/fs'; export default async function () { const useWebpackBuilder = !getGlobalVariable('argv')['esbuild']; @@ -15,12 +13,28 @@ export default async function () { return; } - const isSnapshotBuild = getGlobalVariable('argv')['ng-snapshots']; - await updateJsonFile('package.json', (packageJson) => { - const dependencies = packageJson['dependencies']; - dependencies['@angular/localize'] = isSnapshotBuild - ? snapshots.dependencies['@angular/localize'] - : readNgVersion(); + // Setup i18n tests and config. + await setupI18nConfig(); + + // Update angular.json + await updateJsonFile('angular.json', (workspaceJson) => { + const appProject = workspaceJson.projects['test-project']; + // tslint:disable-next-line: no-any + const i18n: Record = appProject.i18n; + + i18n.sourceLocale = { + baseHref: '', + }; + + i18n.locales['fr'] = { + translation: i18n.locales['fr'], + baseHref: '', + }; + + i18n.locales['de'] = { + translation: i18n.locales['de'], + baseHref: '', + }; }); // forcibly remove in case another test doesn't clean itself up @@ -31,65 +45,12 @@ export default async function () { await useSha(); await installWorkspacePackages(); - // Set configurations for each locale. - const langTranslations = [ - { lang: 'en-US', translation: 'Hello i18n!' }, - { lang: 'fr', translation: 'Bonjour i18n!' }, - ]; - - await updateJsonFile('angular.json', (workspaceJson) => { - const appProject = workspaceJson.projects['test-project']; - const appArchitect = appProject.architect || appProject.targets; - const buildOptions = appArchitect['build'].options; - - // Enable localization for all locales - buildOptions.localize = true; - - // Add locale definitions to the project - const i18n: Record = (appProject.i18n = { locales: {} }); - for (const { lang } of langTranslations) { - if (lang == 'en-US') { - i18n.sourceLocale = lang; - } else { - i18n.locales[lang] = `src/locale/messages.${lang}.xlf`; - } - } - }); - - // Add a translatable element - // Extraction of i18n only works on browser targets. - // Let's add the same translation that there is in the app-shell - await writeFile( - 'src/app/app.component.html', - '

Hello i18n!

', - ); - - // Extract the translation messages and copy them for each language. - await ng('extract-i18n', '--output-path=src/locale'); - await expectFileToMatch('src/locale/messages.xlf', `source-language="en-US"`); - await expectFileToMatch('src/locale/messages.xlf', `An introduction header for this sample`); - - for (const { lang, translation } of langTranslations) { - if (lang != 'en-US') { - await copyFile('src/locale/messages.xlf', `src/locale/messages.${lang}.xlf`); - await replaceInFile( - `src/locale/messages.${lang}.xlf`, - 'source-language="en-US"', - `source-language="en-US" target-language="${lang}"`, - ); - await replaceInFile( - `src/locale/messages.${lang}.xlf`, - 'Hello i18n!', - `Hello i18n!\n${translation}`, - ); - } - } - // Build each locale and verify the output. await ng('build', '--output-hashing=none'); for (const { lang, translation } of langTranslations) { let foundTranslation = false; + let foundLocaleData = false; // The translation may be in any of the lazy-loaded generated chunks for (const entry of readdirSync(`dist/test-project/server/${lang}/`)) { @@ -98,8 +59,13 @@ export default async function () { } const contents = readFileSync(`dist/test-project/server/${lang}/${entry}`, 'utf-8'); - foundTranslation ||= contents.includes(translation); - if (foundTranslation) { + + // Check for translated content + foundTranslation ||= contents.includes(translation.helloPartial); + // Check for the locale data month name to be present + foundLocaleData ||= contents.includes(translation.date); + + if (foundTranslation && foundLocaleData) { break; } } @@ -107,5 +73,9 @@ export default async function () { if (!foundTranslation) { throw new Error(`Translation not found in 'dist/test-project/server/${lang}/'`); } + + if (!foundLocaleData) { + throw new Error(`Locale data not found in 'dist/test-project/server/${lang}/'`); + } } }