From ce1c5778111c6a4c0c1e3d7943b85d9c8987279e Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Fri, 27 Jun 2025 16:16:30 -0700 Subject: [PATCH 1/7] Add a feature for injecting custom localized values into a compilation --- .vscode/launch.json | 4 +- .../main_2025-06-27-23-15.json | 10 ++ .../api/webpack5-localization-plugin.api.md | 28 ++++- .../webpack5-localization-plugin/README.md | 10 ++ .../src/AssetProcessor.ts | 118 +++++++++++------- .../src/LocalizationPlugin.ts | 86 ++++++++++--- .../webpack5-localization-plugin/src/index.ts | 10 +- .../src/test/LocalizedRuntimeTestBase.ts | 91 +++++++++++++- .../LocalizedRuntime.test.ts.snap | 52 ++++++-- ...edRuntimeDifferentHashLengths.test.ts.snap | 52 ++++++-- .../src/utilities/Constants.ts | 1 + 11 files changed, 375 insertions(+), 87 deletions(-) create mode 100644 common/changes/@rushstack/webpack5-localization-plugin/main_2025-06-27-23-15.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 2ca13c319af..196840c108c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -38,7 +38,9 @@ "--inspect-brk", "${workspaceFolder}/apps/heft/lib/start.js", "--debug", - "test-watch" + "test", + "--test-path-pattern", + "${fileBasenameNoExtension}" ], "skipFiles": ["/**"], "outFiles": [], diff --git a/common/changes/@rushstack/webpack5-localization-plugin/main_2025-06-27-23-15.json b/common/changes/@rushstack/webpack5-localization-plugin/main_2025-06-27-23-15.json new file mode 100644 index 00000000000..9c7b24a8b2a --- /dev/null +++ b/common/changes/@rushstack/webpack5-localization-plugin/main_2025-06-27-23-15.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/webpack5-localization-plugin", + "comment": "Add a feature for injecting custom localized values into a compilation via the `getCustomDataPlaceholderForValueFunction` function on an instance of the `LocalizationPlugin`.", + "type": "minor" + } + ], + "packageName": "@rushstack/webpack5-localization-plugin" +} \ No newline at end of file diff --git a/common/reviews/api/webpack5-localization-plugin.api.md b/common/reviews/api/webpack5-localization-plugin.api.md index 5870ff56ae1..07302e73cf2 100644 --- a/common/reviews/api/webpack5-localization-plugin.api.md +++ b/common/reviews/api/webpack5-localization-plugin.api.md @@ -14,6 +14,11 @@ import type { IPseudolocaleOptions } from '@rushstack/localization-utilities'; import type { LoaderContext } from 'webpack'; import type { WebpackPluginInstance } from 'webpack'; +// @internal (undocumented) +export interface _ICustomDataPlaceholder extends IValuePlaceholderBase { + valueForLocaleFn: ValueForLocaleFn; +} + // @public (undocumented) export interface IDefaultLocaleOptions { fillMissingTranslationStrings?: boolean; @@ -121,13 +126,13 @@ export interface IPseudolocalesOptions { export type IResolvedMissingTranslations = ReadonlyMap; // @public (undocumented) -export interface _IStringPlaceholder { +interface IStringPlaceholder extends IValuePlaceholderBase { locFilePath: string; stringName: string; - suffix: string; translations: ReadonlyMap>; - value: string; } +export { IStringPlaceholder } +export { IStringPlaceholder as _IStringPlaceholder } // @public (undocumented) export interface ITrueHashPluginOptions { @@ -135,6 +140,12 @@ export interface ITrueHashPluginOptions { stageOverride?: number; } +// @public (undocumented) +export interface IValuePlaceholderBase { + suffix: string; + value: string; +} + // @public export class LocalizationPlugin implements WebpackPluginInstance { constructor(options: ILocalizationPluginOptions); @@ -142,9 +153,13 @@ export class LocalizationPlugin implements WebpackPluginInstance { addDefaultLocFileAsync(context: LoaderContext<{}>, localizedFileKey: string, localizedResourceData: ILocalizationFile): Promise>; apply(compiler: Compiler): void; // @internal (undocumented) - getDataForSerialNumber(serialNumber: string): _IStringPlaceholder | undefined; + _getCustomDataForSerialNumber(suffix: string): _ICustomDataPlaceholder | undefined; + // (undocumented) + getCustomDataPlaceholderForValueFunction(valueForLocaleFn: ValueForLocaleFn): string; // (undocumented) - getPlaceholder(localizedFileKey: string, stringName: string): _IStringPlaceholder | undefined; + getPlaceholder(localizedFileKey: string, stringName: string): IStringPlaceholder | undefined; + // @internal (undocumented) + _getStringDataForSerialNumber(suffix: string): IStringPlaceholder | undefined; // @internal (undocumented) readonly _options: ILocalizationPluginOptions; } @@ -156,6 +171,9 @@ export class TrueHashPlugin implements WebpackPluginInstance { apply(compiler: Compiler): void; } +// @public (undocumented) +export type ValueForLocaleFn = (locale: string) => string; + // (No @packageDocumentation comment for this package) ``` diff --git a/webpack/webpack5-localization-plugin/README.md b/webpack/webpack5-localization-plugin/README.md index ffe6bc458ad..69de5d2d167 100644 --- a/webpack/webpack5-localization-plugin/README.md +++ b/webpack/webpack5-localization-plugin/README.md @@ -209,6 +209,16 @@ use the true hash of the content, rather than an intermediate hash that is share Note that this option is not compatible with the `runtimeLocaleExpression` option and will cause an error if both are set. +## Custom Localized Data + +If you need to provide custom localized data, you can use the `getCustomDataPlaceholderForValueFunction` method +of the plugin. This method takes a function that receives a locale name and returns a string that will be used as +a placeholder for the localized data. The provided function will be called for each locale that is used in the +build and the returned value will replace the returned placeholder in the output. + +Note that this may produce unexpected results if there are no other localized values in the chunk that the +placeholder is used in. + ## Links - [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/webpack/localization-plugin/CHANGELOG.md) - Find diff --git a/webpack/webpack5-localization-plugin/src/AssetProcessor.ts b/webpack/webpack5-localization-plugin/src/AssetProcessor.ts index f74de81575d..fe60d880ace 100644 --- a/webpack/webpack5-localization-plugin/src/AssetProcessor.ts +++ b/webpack/webpack5-localization-plugin/src/AssetProcessor.ts @@ -4,11 +4,19 @@ import type { Asset, AssetInfo, Chunk, Compilation, sources } from 'webpack'; import * as Constants from './utilities/Constants'; -import type { LocalizationPlugin, IStringPlaceholder } from './LocalizationPlugin'; +import type { + LocalizationPlugin, + IStringPlaceholder, + ValueForLocaleFn, + ICustomDataPlaceholder +} from './LocalizationPlugin'; import type { ILocalizedWebpackChunk, IAssetPathOptions } from './webpackInterfaces'; +const LOCALIZED_RECONSTRUCTION_ELEMENT_KIND: 1 = 1; +const DYNAMIC_RECONSTRUCTION_ELEMENT_KIND: 2 = 2; + interface ILocalizedReconstructionElement { - kind: 'localized'; + kind: typeof LOCALIZED_RECONSTRUCTION_ELEMENT_KIND; start: number; end: number; escapedBackslash: string; @@ -16,14 +24,13 @@ interface ILocalizedReconstructionElement { } interface IDynamicReconstructionElement { - kind: 'dynamic'; + kind: typeof DYNAMIC_RECONSTRUCTION_ELEMENT_KIND; start: number; end: number; valueFn: (locale: string) => string; } type IReconstructionElement = ILocalizedReconstructionElement | IDynamicReconstructionElement; -type FormatLocaleForFilenameFn = (locale: string) => string; interface IParseResult { issues: string[]; @@ -52,7 +59,7 @@ export interface IProcessNonLocalizedAssetOptions extends IProcessAssetOptionsBa fileName: string; hasUrlGenerator: boolean; noStringsLocaleName: string; - formatLocaleForFilenameFn: FormatLocaleForFilenameFn; + formatLocaleForFilenameFn: ValueForLocaleFn; } export interface IProcessLocalizedAssetOptions extends IProcessAssetOptionsBase { @@ -61,26 +68,16 @@ export interface IProcessLocalizedAssetOptions extends IProcessAssetOptionsBase defaultLocale: string; passthroughLocaleName: string | undefined; filenameTemplate: Parameters[0]; - formatLocaleForFilenameFn: FormatLocaleForFilenameFn; + formatLocaleForFilenameFn: ValueForLocaleFn; } -export interface IProcessAssetResult { - filename: string; - asset: sources.Source; -} - -export const PLACEHOLDER_REGEX: RegExp = new RegExp( - `${Constants.STRING_PLACEHOLDER_PREFIX}_([A-C])_(\\\\*)_([0-9a-f$]+)_`, - 'g' -); - -export interface IProcessedAsset { +interface IProcessedAsset { filename: string; source: sources.CachedSource; info: AssetInfo; } -export interface IProcessLocalizedAssetResult { +interface IProcessLocalizedAssetResult { localizedFiles: Record; processedAssets: IProcessedAsset[]; } @@ -124,12 +121,22 @@ export async function processLocalizedAssetCachedAsync( } export function processLocalizedAsset(options: IProcessLocalizedAssetOptions): IProcessLocalizedAssetResult { - const { compilation, asset, chunk, filenameTemplate, locales, formatLocaleForFilenameFn } = options; - + const { + compilation, + asset, + chunk, + filenameTemplate, + locales, + formatLocaleForFilenameFn, + plugin, + fillMissingTranslationStrings, + defaultLocale, + passthroughLocaleName + } = options; const { sources, WebpackError } = compilation.compiler.webpack; - const { source: originalSource } = asset; + const fallbackLocale: string | undefined = fillMissingTranslationStrings ? defaultLocale : undefined; const rawSource: sources.CachedSource = originalSource instanceof sources.CachedSource ? originalSource @@ -137,7 +144,7 @@ export function processLocalizedAsset(options: IProcessLocalizedAssetOptions): I const assetSource: string = rawSource.source().toString(); const parsedAsset: IParseResult = _parseStringToReconstructionSequence( - options.plugin, + plugin, assetSource, formatLocaleForFilenameFn ); @@ -158,8 +165,8 @@ export function processLocalizedAsset(options: IProcessLocalizedAssetOptions): I new sources.ReplaceSource(rawSource, locale), parsedAsset.reconstructionSeries, locale, - options.fillMissingTranslationStrings ? options.defaultLocale : undefined, - options.passthroughLocaleName + fallbackLocale, + passthroughLocaleName ); for (const issue of localeIssues) { @@ -312,9 +319,10 @@ function _reconstructLocalized( const issues: string[] = []; for (const element of reconstructionSeries) { - switch (element.kind) { - case 'localized': { - const { data } = element; + const { kind, start, end } = element; + switch (kind) { + case LOCALIZED_RECONSTRUCTION_ELEMENT_KIND: { + const { data, escapedBackslash } = element; const { stringName, translations } = data; let newValue: string | undefined = locale === passthroughLocale ? stringName : translations.get(locale)?.get(stringName); @@ -330,8 +338,6 @@ function _reconstructLocalized( newValue = '-- MISSING STRING --'; } - const escapedBackslash: string = element.escapedBackslash || '\\'; - if (newValue.includes('\\')) { // The vast majority of localized strings do not contain `\\`, so this check avoids an allocation. // Replace backslashes with the properly escaped backslash @@ -352,13 +358,13 @@ function _reconstructLocalized( ); } - result.replace(element.start, element.end - 1, newValue); + result.replace(start, end - 1, newValue); break; } - case 'dynamic': { + case DYNAMIC_RECONSTRUCTION_ELEMENT_KIND: { const newValue: string = element.valueFn(locale); - result.replace(element.start, element.end - 1, newValue); + result.replace(start, end - 1, newValue); break; } } @@ -379,7 +385,7 @@ function _reconstructNonLocalized( for (const element of reconstructionSeries) { switch (element.kind) { - case 'localized': { + case LOCALIZED_RECONSTRUCTION_ELEMENT_KIND: { issues.push( `The string "${element.data.stringName}" in "${element.data.locFilePath}" appeared in an asset ` + 'that is not expected to contain localized resources.' @@ -390,7 +396,7 @@ function _reconstructNonLocalized( break; } - case 'dynamic': { + case DYNAMIC_RECONSTRUCTION_ELEMENT_KIND: { const newValue: string = element.valueFn(noStringsLocaleName); result.replace(element.start, element.end - 1, newValue); break; @@ -407,12 +413,12 @@ function _reconstructNonLocalized( function _parseStringToReconstructionSequence( plugin: LocalizationPlugin, source: string, - formatLocaleForFilenameFn: FormatLocaleForFilenameFn + formatLocaleForFilenameFn: ValueForLocaleFn ): IParseResult { const issues: string[] = []; const reconstructionSeries: IReconstructionElement[] = []; - let jsonStringifyFormatLocaleForFilenameFn: FormatLocaleForFilenameFn | undefined; + let jsonStringifyFormatLocaleForFilenameFn: ValueForLocaleFn | undefined; let index: number = source.indexOf(Constants.STRING_PLACEHOLDER_PREFIX); const increment: number = Constants.STRING_PLACEHOLDER_PREFIX.length + 1; @@ -425,18 +431,18 @@ function _parseStringToReconstructionSequence( switch (elementLabel) { case Constants.STRING_PLACEHOLDER_LABEL: { const backslashEnd: number = source.indexOf('_', end); - const escapedBackslash: string = source.slice(end, backslashEnd); + const escapedBackslash: string = source.slice(end, backslashEnd) || '\\'; end = backslashEnd + 1; - const serialEnd: number = source.indexOf('_', end); - const serial: string = source.slice(end, serialEnd); - end = serialEnd + 1; + const suffixEnd: number = source.indexOf('_', end); + const suffix: string = source.slice(end, suffixEnd); + end = suffixEnd + 1; - const stringData: IStringPlaceholder | undefined = plugin.getDataForSerialNumber(serial); + const stringData: IStringPlaceholder | undefined = plugin._getStringDataForSerialNumber(suffix); if (!stringData) { - issues.push(`Missing placeholder ${serial}`); + issues.push(`Missing placeholder ${suffix}`); } else { const localizedElement: ILocalizedReconstructionElement = { - kind: 'localized', + kind: LOCALIZED_RECONSTRUCTION_ELEMENT_KIND, start, end, escapedBackslash, @@ -446,9 +452,10 @@ function _parseStringToReconstructionSequence( } break; } + case Constants.LOCALE_NAME_PLACEHOLDER_LABEL: { const dynamicElement: IDynamicReconstructionElement = { - kind: 'dynamic', + kind: DYNAMIC_RECONSTRUCTION_ELEMENT_KIND, start, end, valueFn: formatLocaleForFilenameFn @@ -456,11 +463,12 @@ function _parseStringToReconstructionSequence( reconstructionSeries.push(dynamicElement); break; } + case Constants.JSONP_PLACEHOLDER_LABEL: { jsonStringifyFormatLocaleForFilenameFn ||= (locale: string) => JSON.stringify(formatLocaleForFilenameFn(locale)); const dynamicElement: IDynamicReconstructionElement = { - kind: 'dynamic', + kind: DYNAMIC_RECONSTRUCTION_ELEMENT_KIND, start, end, valueFn: jsonStringifyFormatLocaleForFilenameFn @@ -468,6 +476,26 @@ function _parseStringToReconstructionSequence( reconstructionSeries.push(dynamicElement); break; } + + case Constants.CUSTOM_PLACEHOLDER_LABEL: { + const serialEnd: number = source.indexOf('_', end); + const serial: string = source.slice(end, serialEnd); + end = serialEnd + 1; + const customData: ICustomDataPlaceholder | undefined = plugin._getCustomDataForSerialNumber(serial); + if (!customData) { + issues.push(`Missing custom placeholder ${serial}`); + } else { + const dynamicElement: IDynamicReconstructionElement = { + kind: DYNAMIC_RECONSTRUCTION_ELEMENT_KIND, + start, + end, + valueFn: customData.valueForLocaleFn + }; + reconstructionSeries.push(dynamicElement); + } + break; + } + default: { throw new Error(`Unexpected label ${elementLabel} in pattern ${source.slice(start, end)}`); } diff --git a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts index 8af635859fa..8ee555a697b 100644 --- a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts +++ b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts @@ -36,33 +36,58 @@ import { chunkIsJs } from './utilities/chunkUtilities'; /** * @public */ -export interface IStringPlaceholder { +export type ValueForLocaleFn = (locale: string) => string; + +/** + * @public + */ +export interface IValuePlaceholderBase { /** * The literal string that will be injected for later replacement. */ value: string; + /** * The identifier for this particular placeholder, for lookup. */ suffix: string; +} + +/** + * @public + */ +export interface IStringPlaceholder extends IValuePlaceholderBase { /** * The values of this string in each output locale. */ translations: ReadonlyMap>; + /** * The key used to identify the source file containing the string. */ locFilePath: string; + /** * The identifier of the string within its original source file. */ stringName: string; } +/** + * @internal + */ +export interface ICustomDataPlaceholder extends IValuePlaceholderBase { + /** + * The function that will be invoked to get the value for this placeholder. + * The function will be invoked with the locale name as the first argument. + */ + valueForLocaleFn: ValueForLocaleFn; +} + export interface IFileTranslationInfo { placeholders: Map; translations: Map>; - renderedPlacholders: Record; + renderedPlaceholders: Record; } const PLUGIN_NAME: 'localization' = 'localization'; @@ -97,13 +122,19 @@ export class LocalizationPlugin implements WebpackPluginInstance { string, Map> > = new Map(); - private readonly _stringPlaceholderMap: Map = new Map(); + private readonly _stringPlaceholderBySuffix: Map = new Map(); + private readonly _customDataPlaceholderBySuffix: Map = new Map(); + private readonly _customDataPlaceholderByCustomValueFunction: WeakMap< + ValueForLocaleFn, + ICustomDataPlaceholder + > = new WeakMap(); private _passthroughLocaleName!: string; private _defaultLocale!: string; private _noStringsLocaleName!: string; private _fillMissingTranslationStrings!: boolean; private _formatLocaleForFilename!: (loc: string) => string; private readonly _pseudolocalizers: Map string> = new Map(); + private _customValueSuffixCounter: number = 0; /** * The set of locales that have translations provided. @@ -525,7 +556,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { markEntity(context._module!, true); - return fileInfo.renderedPlacholders; + return fileInfo.renderedPlaceholders; } /** @@ -539,11 +570,38 @@ export class LocalizationPlugin implements WebpackPluginInstance { return file.placeholders.get(stringName); } + /** + * @public + */ + public getCustomDataPlaceholderForValueFunction(valueForLocaleFn: ValueForLocaleFn): string { + let placeholder: ICustomDataPlaceholder | undefined = + this._customDataPlaceholderByCustomValueFunction.get(valueForLocaleFn); + if (!placeholder) { + const suffix: string = String(this._customValueSuffixCounter++); + placeholder = { + value: `${Constants.STRING_PLACEHOLDER_PREFIX}_${Constants.CUSTOM_PLACEHOLDER_LABEL}_${suffix}_`, + suffix, + valueForLocaleFn + }; + this._customDataPlaceholderBySuffix.set(suffix, placeholder); + this._customDataPlaceholderByCustomValueFunction.set(valueForLocaleFn, placeholder); + } + + return placeholder.value; + } + /** * @internal */ - public getDataForSerialNumber(serialNumber: string): IStringPlaceholder | undefined { - return this._stringPlaceholderMap.get(serialNumber); + public _getStringDataForSerialNumber(suffix: string): IStringPlaceholder | undefined { + return this._stringPlaceholderBySuffix.get(suffix); + } + + /** + * @internal + */ + public _getCustomDataForSerialNumber(suffix: string): ICustomDataPlaceholder | undefined { + return this._customDataPlaceholderBySuffix.get(suffix); } private _addLocFileAndGetPlaceholders( @@ -556,7 +614,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { fileInfo = { placeholders: new Map(), translations: new Map(), - renderedPlacholders: {} + renderedPlaceholders: {} }; this._locFiles.set(localizedFileKey, fileInfo); } @@ -572,32 +630,24 @@ export class LocalizationPlugin implements WebpackPluginInstance { placeholder = { value: `${Constants.STRING_PLACEHOLDER_PREFIX}_${Constants.STRING_PLACEHOLDER_LABEL}_\\_${suffix}_`, suffix, - translations, + translations: translations, locFilePath: localizedFileKey, stringName }; placeholders.set(stringName, placeholder); - this._stringPlaceholderMap.set(suffix, placeholder); + this._stringPlaceholderBySuffix.set(suffix, placeholder); } resultObject[stringName] = placeholder.value; } translations.set(localeName, localizedFileData); - fileInfo.renderedPlacholders = resultObject; + fileInfo.renderedPlaceholders = resultObject; return fileInfo; } - private _addTranslations( - localeName: string, - fileInfo: IFileTranslationInfo, - localizedFileData: ReadonlyMap - ): void { - fileInfo.translations.set(localeName, localizedFileData); - } - private _initializeAndValidateOptions( compiler: Compiler, isWebpackDevServer: boolean diff --git a/webpack/webpack5-localization-plugin/src/index.ts b/webpack/webpack5-localization-plugin/src/index.ts index ed20360a302..6d0227a0a6d 100644 --- a/webpack/webpack5-localization-plugin/src/index.ts +++ b/webpack/webpack5-localization-plugin/src/index.ts @@ -3,7 +3,15 @@ /// -export { LocalizationPlugin, type IStringPlaceholder as _IStringPlaceholder } from './LocalizationPlugin'; +export { + LocalizationPlugin, + // TODO: Remove this export in the next major version + type IStringPlaceholder as _IStringPlaceholder, + type IStringPlaceholder, + type ICustomDataPlaceholder as _ICustomDataPlaceholder, + type IValuePlaceholderBase, + type ValueForLocaleFn +} from './LocalizationPlugin'; export { TrueHashPlugin, type ITrueHashPluginOptions } from './TrueHashPlugin'; export type { diff --git a/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts index 2d1841c4ae8..048ef6649a8 100644 --- a/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts +++ b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts @@ -11,6 +11,85 @@ import { MemFSPlugin } from './MemFSPlugin'; import type { ILocalizationPluginOptions } from '../interfaces'; import { LocalizationPlugin } from '../LocalizationPlugin'; import { type ITrueHashPluginOptions, TrueHashPlugin } from '../TrueHashPlugin'; +import { markEntity } from '../utilities/EntityMarker'; + +class InjectCustomPlaceholderPlugin implements webpack.WebpackPluginInstance { + private readonly _localizationPlugin: LocalizationPlugin; + private readonly _localizedChunkNameByLocaleName: Map>; + + public constructor( + localizationPlugin: LocalizationPlugin, + localizedChunkNameByLocaleName: Map> + ) { + this._localizationPlugin = localizationPlugin; + this._localizedChunkNameByLocaleName = localizedChunkNameByLocaleName; + } + + public apply(compiler: Compiler): void { + const PLUGIN_NAME: 'inject-custom-placeholder' = 'inject-custom-placeholder'; + const printLocalizedChunkName: 'printLocalizedChunkName' = 'printLocalizedChunkName'; + + const { runtime, RuntimeModule, Template, RuntimeGlobals } = compiler.webpack; + const localizationPlugin: LocalizationPlugin = this._localizationPlugin; + const localizedChunkNameByLocaleName: Map> = this + ._localizedChunkNameByLocaleName; + + function getLocalizedChunkNamesString(locale: string): string { + return `/* ${locale} */ ${JSON.stringify(localizedChunkNameByLocaleName.get(locale))}`; + } + + class GetIntegrityHashRuntimeModule extends RuntimeModule { + public constructor() { + super('custom data module', -10); + this.fullHash = true; + } + + public override generate(): string { + const placeholder: string = localizationPlugin.getCustomDataPlaceholderForValueFunction( + getLocalizedChunkNamesString + ); + + return Template.asString([ + `var localizedChunkNames = ${placeholder};`, + `function ${printLocalizedChunkName}(chunkId) {`, + Template.indent([`console.log(localizedChunkNames[chunkId]);`]), + `}` + ]); + } + + public override shouldIsolate(): boolean { + return false; + } + } + + compiler.hooks.thisCompilation.tap({ name: PLUGIN_NAME, stage: 10 }, (compilation, data) => { + runtime.LoadScriptRuntimeModule.getCompilationHooks(compilation).createScript.tap( + PLUGIN_NAME, + (originalSource): string => { + return Template.asString([originalSource, '', `${printLocalizedChunkName}(chunkId);`]); + } + ); + + function integrityHandler(chunk: webpack.Chunk, set: Set): void { + markEntity(chunk, true); + set.add(printLocalizedChunkName); + } + + compilation.hooks.runtimeRequirementInTree + .for(printLocalizedChunkName) + .tap(PLUGIN_NAME, (chunk: webpack.Chunk, set: Set) => { + compilation.addRuntimeModule(chunk, new GetIntegrityHashRuntimeModule()); + return true; + }); + compilation.hooks.runtimeRequirementInTree + .for(RuntimeGlobals.loadScript) + .tap(PLUGIN_NAME, integrityHandler); + compilation.hooks.runtimeRequirementInTree + .for(RuntimeGlobals.preloadChunkHandlers) + .tap(PLUGIN_NAME, integrityHandler); + }); + } +} export function runTests(trueHashPluginOptions: ITrueHashPluginOptions = {}): void { async function testLocalizedRuntimeInner(minimize: boolean): Promise { @@ -51,6 +130,11 @@ export function runTests(trueHashPluginOptions: ITrueHashPluginOptions = {}): vo const localizationPlugin: LocalizationPlugin = new LocalizationPlugin(options); + const localizedChunkNameByLocaleName: Map> = new Map([ + ['LOCALE1', { async1: 'async1-LOCALE1-123456', async2: 'async2-LOCALE1-123456' }], + ['LOCALE2', { async1: 'async1-LOCALE2-abcdef', async2: 'async2-LOCALE2-abcdef' }] + ]); + const compiler: Compiler = webpack({ entry: { mainSingleChunk: '/a/entrySingleChunk.js', @@ -80,7 +164,12 @@ export function runTests(trueHashPluginOptions: ITrueHashPluginOptions = {}): vo }, context: '/', mode: 'production', - plugins: [localizationPlugin, trueHashPlugin, new MemFSPlugin(memoryFileSystem)] + plugins: [ + localizationPlugin, + new InjectCustomPlaceholderPlugin(localizationPlugin, localizedChunkNameByLocaleName), + trueHashPlugin, + new MemFSPlugin(memoryFileSystem) + ] }); const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap index dd38b8e8af6..101f7d0d3be 100644 --- a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap @@ -6,10 +6,10 @@ Object { "/release/chunks/async1-LOCALE2-1e57833357912f77511d.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test,a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", "/release/chunks/async2-LOCALE1-0c2f434469639436732a.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"something else\\"}}}]);", "/release/chunks/async2-LOCALE2-664388d6b7aa642fc965.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", - "/release/mainSingleChunk-LOCALE1-609ca833ca6d471a329e.js": "(()=>{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/async1-\\"+\\"LOCALE1\\"+\\"-44d1a3fadec3f8385e08.js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,c;if(void 0!==n)for(var l=document.getElementsByTagName(\\"script\\"),s=0;s{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),c&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={331:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),c=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,c,l]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);l&&l(o)}for(r&&r(t);s{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/async1-\\"+\\"LOCALE2\\"+\\"-1e57833357912f77511d.js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,c;if(void 0!==n)for(var l=document.getElementsByTagName(\\"script\\"),s=0;s{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),c&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={331:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),c=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,c,l]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);l&&l(o)}for(r&&r(t);s{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE1\\"+\\"-\\"+{230:\\"44d1a3fadec3f8385e08\\",421:\\"0c2f434469639436732a\\"}[e]+\\".js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,c;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),l=0;l{i.onerror=i.onload=null,clearTimeout(p);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},p=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),c&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={580:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),c=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,c,s]=t,l=0;if(i.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);s&&s(o)}for(r&&r(t);l{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE2\\"+\\"-\\"+{230:\\"1e57833357912f77511d\\",421:\\"664388d6b7aa642fc965\\"}[e]+\\".js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,c;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),l=0;l{i.onerror=i.onload=null,clearTimeout(p);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},p=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),c&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={580:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),c=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,c,s]=t,l=0;if(i.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);s&&s(o)}for(r&&r(t);l{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE1\\"+\\"-44d1a3fadec3f8385e08.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=d.bind(null,c.onerror),c.onload=d.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE2\\"+\\"-1e57833357912f77511d.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=d.bind(null,c.onerror),c.onload=d.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE1\\"+\\"-\\"+{230:\\"44d1a3fadec3f8385e08\\",421:\\"0c2f434469639436732a\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE2\\"+\\"-\\"+{230:\\"1e57833357912f77511d\\",421:\\"664388d6b7aa642fc965\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l { // webpackBootstrap + "/release/mainSingleChunk-LOCALE1-a09e66b038c209b52c2b.js": "/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({}); /************************************************************************/ /******/ // The module cache @@ -194,6 +194,12 @@ const strings = {\\"another\\":\\"some random translation\\"}; /******/ __webpack_require__.m = __webpack_modules__; /******/ /************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports @@ -272,6 +278,9 @@ const strings = {\\"another\\":\\"some random translation\\"}; /******/ /******/ /******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); /******/ } /******/ inProgress[url] = [done]; /******/ var onScriptComplete = (prev, event) => { @@ -420,7 +429,7 @@ var __webpack_exports__ = {}; __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\")); /******/ })() ;", - "/release/mainSingleChunk-LOCALE2-67b32b007b29ddb53f0b.js": "/******/ (() => { // webpackBootstrap + "/release/mainSingleChunk-LOCALE2-5382793b5c1b412e361b.js": "/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({}); /************************************************************************/ /******/ // The module cache @@ -451,6 +460,12 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ __webpack_require__.m = __webpack_modules__; /******/ /************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports @@ -529,6 +544,9 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ /******/ /******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); /******/ } /******/ inProgress[url] = [done]; /******/ var onScriptComplete = (prev, event) => { @@ -677,7 +695,7 @@ var __webpack_exports__ = {}; __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\")); /******/ })() ;", - "/release/mainTwoChunks-LOCALE1-cfdd1876abd4e14c70f8.js": "/******/ (() => { // webpackBootstrap + "/release/mainTwoChunks-LOCALE1-5efaa974620f14b4f849.js": "/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({}); /************************************************************************/ /******/ // The module cache @@ -708,6 +726,12 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ __webpack_require__.m = __webpack_modules__; /******/ /************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports @@ -786,6 +810,9 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ /******/ /******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); /******/ } /******/ inProgress[url] = [done]; /******/ var onScriptComplete = (prev, event) => { @@ -934,7 +961,7 @@ var __webpack_exports__ = {}; __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\"));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.bind(__webpack_require__, \\"./a/async2.js\\")); /******/ })() ;", - "/release/mainTwoChunks-LOCALE2-63de465a5cef8fc90a51.js": "/******/ (() => { // webpackBootstrap + "/release/mainTwoChunks-LOCALE2-621e175eb55ea9b3280f.js": "/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({}); /************************************************************************/ /******/ // The module cache @@ -965,6 +992,12 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ __webpack_require__.m = __webpack_modules__; /******/ /************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports @@ -1043,6 +1076,9 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ /******/ /******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); /******/ } /******/ inProgress[url] = [done]; /******/ var onScriptComplete = (prev, event) => { diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntimeDifferentHashLengths.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntimeDifferentHashLengths.test.ts.snap index cdc0c726246..198344d5846 100644 --- a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntimeDifferentHashLengths.test.ts.snap +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntimeDifferentHashLengths.test.ts.snap @@ -6,10 +6,10 @@ Object { "/release/chunks/async1-LOCALE2-fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test,a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", "/release/chunks/async2-LOCALE1-2878fc254efcf861ebdb1de8ffe2da978f78d90bdb657ca96126fe284386851a.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"something else\\"}}}]);", "/release/chunks/async2-LOCALE2-c2b6b66a1486798af745222597d7f7f64daf16f5566e28a3e34dda6da6f41f87.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", - "/release/mainSingleChunk-LOCALE1-179143d6cdf37c2d8ddf8bdec1e84471cf20bcf862e85158609ce777b1a5e0bc.js": "(()=>{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/async1-\\"+\\"LOCALE1\\"+\\"-9bd32294abc47c2bd95cbd4f4a64ac12f94cfd89dbb3cc1056c8ca83c94b3f83.js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,c;if(void 0!==n)for(var l=document.getElementsByTagName(\\"script\\"),s=0;s{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),c&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={331:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),c=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,c,l]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);l&&l(o)}for(r&&r(t);s{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/async1-\\"+\\"LOCALE2\\"+\\"-fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8.js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,c;if(void 0!==n)for(var l=document.getElementsByTagName(\\"script\\"),s=0;s{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),c&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={331:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),c=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,c,l]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);l&&l(o)}for(r&&r(t);s{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE1\\"+\\"-\\"+{230:\\"9bd32294abc47c2bd95cbd4f4a64ac12f94cfd89dbb3cc1056c8ca83c94b3f83\\",421:\\"2878fc254efcf861ebdb1de8ffe2da978f78d90bdb657ca96126fe284386851a\\"}[e]+\\".js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,c;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),l=0;l{i.onerror=i.onload=null,clearTimeout(p);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},p=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),c&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={580:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),c=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,c,s]=t,l=0;if(i.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);s&&s(o)}for(r&&r(t);l{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE2\\"+\\"-\\"+{230:\\"fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8\\",421:\\"c2b6b66a1486798af745222597d7f7f64daf16f5566e28a3e34dda6da6f41f87\\"}[e]+\\".js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,c;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),l=0;l{i.onerror=i.onload=null,clearTimeout(p);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},p=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),c&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={580:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),c=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,c,s]=t,l=0;if(i.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);s&&s(o)}for(r&&r(t);l{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE1\\"+\\"-9bd32294abc47c2bd95cbd4f4a64ac12f94cfd89dbb3cc1056c8ca83c94b3f83.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=d.bind(null,c.onerror),c.onload=d.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE2\\"+\\"-fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=d.bind(null,c.onerror),c.onload=d.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE1\\"+\\"-\\"+{230:\\"9bd32294abc47c2bd95cbd4f4a64ac12f94cfd89dbb3cc1056c8ca83c94b3f83\\",421:\\"2878fc254efcf861ebdb1de8ffe2da978f78d90bdb657ca96126fe284386851a\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE2\\"+\\"-\\"+{230:\\"fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8\\",421:\\"c2b6b66a1486798af745222597d7f7f64daf16f5566e28a3e34dda6da6f41f87\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l { // webpackBootstrap + "/release/mainSingleChunk-LOCALE1-d6fa89a28e2fa52fe9de08e06af1bbadddce89ce7bcef6c01d2709993630806b.js": "/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({}); /************************************************************************/ /******/ // The module cache @@ -194,6 +194,12 @@ const strings = {\\"another\\":\\"some random translation\\"}; /******/ __webpack_require__.m = __webpack_modules__; /******/ /************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports @@ -272,6 +278,9 @@ const strings = {\\"another\\":\\"some random translation\\"}; /******/ /******/ /******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); /******/ } /******/ inProgress[url] = [done]; /******/ var onScriptComplete = (prev, event) => { @@ -420,7 +429,7 @@ var __webpack_exports__ = {}; __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\")); /******/ })() ;", - "/release/mainSingleChunk-LOCALE2-b2e39e32c029a427c28af2e128dabbbbfbcd9f486499430fc62d0e900bc979ff.js": "/******/ (() => { // webpackBootstrap + "/release/mainSingleChunk-LOCALE2-6ce640a695a120867bdbd13eb91fa9cccb619aa0468f5f6997dc775abbdb8133.js": "/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({}); /************************************************************************/ /******/ // The module cache @@ -451,6 +460,12 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ __webpack_require__.m = __webpack_modules__; /******/ /************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports @@ -529,6 +544,9 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ /******/ /******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); /******/ } /******/ inProgress[url] = [done]; /******/ var onScriptComplete = (prev, event) => { @@ -677,7 +695,7 @@ var __webpack_exports__ = {}; __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\")); /******/ })() ;", - "/release/mainTwoChunks-LOCALE1-f7cd4b957f36ff5c60b9e4dfff02b4200b71e754ae1d9fe44edb8cc62950b59e.js": "/******/ (() => { // webpackBootstrap + "/release/mainTwoChunks-LOCALE1-88b9507279db4beebecf847e23c169f45022bf8fed391e23a91aeb3201799771.js": "/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({}); /************************************************************************/ /******/ // The module cache @@ -708,6 +726,12 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ __webpack_require__.m = __webpack_modules__; /******/ /************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports @@ -786,6 +810,9 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ /******/ /******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); /******/ } /******/ inProgress[url] = [done]; /******/ var onScriptComplete = (prev, event) => { @@ -934,7 +961,7 @@ var __webpack_exports__ = {}; __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\"));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.bind(__webpack_require__, \\"./a/async2.js\\")); /******/ })() ;", - "/release/mainTwoChunks-LOCALE2-aaf5ae131e791886ef6259d6318b94aa867c88c7913622857594843d03f2c039.js": "/******/ (() => { // webpackBootstrap + "/release/mainTwoChunks-LOCALE2-d7460ccdbe34a16a0224016e2120e797b3b1489308d88f1f5d9f2c6b1c4eb415.js": "/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({}); /************************************************************************/ /******/ // The module cache @@ -965,6 +992,12 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ __webpack_require__.m = __webpack_modules__; /******/ /************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports @@ -1043,6 +1076,9 @@ __webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind /******/ /******/ /******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); /******/ } /******/ inProgress[url] = [done]; /******/ var onScriptComplete = (prev, event) => { diff --git a/webpack/webpack5-localization-plugin/src/utilities/Constants.ts b/webpack/webpack5-localization-plugin/src/utilities/Constants.ts index a8870b4453b..0e01025361f 100644 --- a/webpack/webpack5-localization-plugin/src/utilities/Constants.ts +++ b/webpack/webpack5-localization-plugin/src/utilities/Constants.ts @@ -13,6 +13,7 @@ export const RESOURCE_FILE_NAME_REGEXP: RegExp = /\.(resx|resx\.json|loc\.json|r export const STRING_PLACEHOLDER_LABEL: 'A' = 'A'; export const LOCALE_NAME_PLACEHOLDER_LABEL: 'B' = 'B'; export const JSONP_PLACEHOLDER_LABEL: 'C' = 'C'; +export const CUSTOM_PLACEHOLDER_LABEL: 'D' = 'D'; // _LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_B_ export const LOCALE_NAME_PLACEHOLDER: `${typeof STRING_PLACEHOLDER_PREFIX}_${typeof LOCALE_NAME_PLACEHOLDER_LABEL}_` = `${STRING_PLACEHOLDER_PREFIX}_${LOCALE_NAME_PLACEHOLDER_LABEL}_`; From a4388f972e25f57c61ab99709ee5739d63302e14 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Fri, 27 Jun 2025 17:09:35 -0700 Subject: [PATCH 2/7] Include compilation and chunk. --- .../api/webpack5-localization-plugin.api.md | 2 +- .../webpack5-localization-plugin/README.md | 7 ++-- .../src/AssetProcessor.ts | 42 ++++++++++++------- .../src/LocalizationPlugin.ts | 2 +- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/common/reviews/api/webpack5-localization-plugin.api.md b/common/reviews/api/webpack5-localization-plugin.api.md index 07302e73cf2..58d73e6f567 100644 --- a/common/reviews/api/webpack5-localization-plugin.api.md +++ b/common/reviews/api/webpack5-localization-plugin.api.md @@ -172,7 +172,7 @@ export class TrueHashPlugin implements WebpackPluginInstance { } // @public (undocumented) -export type ValueForLocaleFn = (locale: string) => string; +export type ValueForLocaleFn = (locale: string, compilation: Compilation, chunk: Chunk) => string; // (No @packageDocumentation comment for this package) diff --git a/webpack/webpack5-localization-plugin/README.md b/webpack/webpack5-localization-plugin/README.md index 69de5d2d167..bed21af4fa1 100644 --- a/webpack/webpack5-localization-plugin/README.md +++ b/webpack/webpack5-localization-plugin/README.md @@ -212,9 +212,10 @@ both are set. ## Custom Localized Data If you need to provide custom localized data, you can use the `getCustomDataPlaceholderForValueFunction` method -of the plugin. This method takes a function that receives a locale name and returns a string that will be used as -a placeholder for the localized data. The provided function will be called for each locale that is used in the -build and the returned value will replace the returned placeholder in the output. +of the plugin. This method takes a function that receives a locale name, a webpack compilation instance, and the chunk +that the placeholder is used in and returns a string that will be used as a placeholder for the localized data. +The provided function will be called for each locale that is used in the build and the returned value will replace +the returned placeholder in the output. Note that this may produce unexpected results if there are no other localized values in the chunk that the placeholder is used in. diff --git a/webpack/webpack5-localization-plugin/src/AssetProcessor.ts b/webpack/webpack5-localization-plugin/src/AssetProcessor.ts index fe60d880ace..4d8dc8a2a0e 100644 --- a/webpack/webpack5-localization-plugin/src/AssetProcessor.ts +++ b/webpack/webpack5-localization-plugin/src/AssetProcessor.ts @@ -27,10 +27,16 @@ interface IDynamicReconstructionElement { kind: typeof DYNAMIC_RECONSTRUCTION_ELEMENT_KIND; start: number; end: number; - valueFn: (locale: string) => string; + valueFn: ValueForLocaleFn; } type IReconstructionElement = ILocalizedReconstructionElement | IDynamicReconstructionElement; +/** + * @remarks + * Include the `compilation` and `chunk` parameters so that the functions arity is the same as the + * `ValueForLocaleFn` type. + */ +type FormatLocaleForFilenameFn = (locale: string, compilation: unknown, chunk: unknown) => string; interface IParseResult { issues: string[]; @@ -59,7 +65,7 @@ export interface IProcessNonLocalizedAssetOptions extends IProcessAssetOptionsBa fileName: string; hasUrlGenerator: boolean; noStringsLocaleName: string; - formatLocaleForFilenameFn: ValueForLocaleFn; + formatLocaleForFilenameFn: FormatLocaleForFilenameFn; } export interface IProcessLocalizedAssetOptions extends IProcessAssetOptionsBase { @@ -68,7 +74,7 @@ export interface IProcessLocalizedAssetOptions extends IProcessAssetOptionsBase defaultLocale: string; passthroughLocaleName: string | undefined; filenameTemplate: Parameters[0]; - formatLocaleForFilenameFn: ValueForLocaleFn; + formatLocaleForFilenameFn: FormatLocaleForFilenameFn; } interface IProcessedAsset { @@ -166,7 +172,9 @@ export function processLocalizedAsset(options: IProcessLocalizedAssetOptions): I parsedAsset.reconstructionSeries, locale, fallbackLocale, - passthroughLocaleName + passthroughLocaleName, + compilation, + chunk ); for (const issue of localeIssues) { @@ -243,7 +251,7 @@ export async function processNonLocalizedAssetCachedAsync( } export function processNonLocalizedAsset(options: IProcessNonLocalizedAssetOptions): IProcessedAsset { - const { asset, fileName, compilation, formatLocaleForFilenameFn, hasUrlGenerator } = options; + const { asset, fileName, compilation, formatLocaleForFilenameFn, hasUrlGenerator, chunk } = options; const { sources, WebpackError } = compilation.compiler.webpack; @@ -267,7 +275,9 @@ export function processNonLocalizedAsset(options: IProcessNonLocalizedAssetOptio const { issues: localeIssues, result } = _reconstructNonLocalized( new sources.ReplaceSource(cachedSource, locale), parsedAsset.reconstructionSeries, - locale + locale, + compilation, + chunk ); for (const issue of localeIssues) { @@ -314,7 +324,9 @@ function _reconstructLocalized( reconstructionSeries: IReconstructionElement[], locale: string, fallbackLocale: string | undefined, - passthroughLocale: string | undefined + passthroughLocale: string | undefined, + compilation: Compilation, + chunk: Chunk ): ILocalizedReconstructionResult { const issues: string[] = []; @@ -363,7 +375,7 @@ function _reconstructLocalized( } case DYNAMIC_RECONSTRUCTION_ELEMENT_KIND: { - const newValue: string = element.valueFn(locale); + const newValue: string = element.valueFn(locale, compilation, chunk); result.replace(start, end - 1, newValue); break; } @@ -379,7 +391,9 @@ function _reconstructLocalized( function _reconstructNonLocalized( result: sources.ReplaceSource, reconstructionSeries: IReconstructionElement[], - noStringsLocaleName: string + noStringsLocaleName: string, + compilation: Compilation, + chunk: Chunk ): INonLocalizedReconstructionResult { const issues: string[] = []; @@ -397,7 +411,7 @@ function _reconstructNonLocalized( } case DYNAMIC_RECONSTRUCTION_ELEMENT_KIND: { - const newValue: string = element.valueFn(noStringsLocaleName); + const newValue: string = element.valueFn(noStringsLocaleName, compilation, chunk); result.replace(element.start, element.end - 1, newValue); break; } @@ -413,12 +427,12 @@ function _reconstructNonLocalized( function _parseStringToReconstructionSequence( plugin: LocalizationPlugin, source: string, - formatLocaleForFilenameFn: ValueForLocaleFn + formatLocaleForFilenameFn: FormatLocaleForFilenameFn ): IParseResult { const issues: string[] = []; const reconstructionSeries: IReconstructionElement[] = []; - let jsonStringifyFormatLocaleForFilenameFn: ValueForLocaleFn | undefined; + let jsonStringifyFormatLocaleForFilenameFn: FormatLocaleForFilenameFn | undefined; let index: number = source.indexOf(Constants.STRING_PLACEHOLDER_PREFIX); const increment: number = Constants.STRING_PLACEHOLDER_PREFIX.length + 1; @@ -465,8 +479,8 @@ function _parseStringToReconstructionSequence( } case Constants.JSONP_PLACEHOLDER_LABEL: { - jsonStringifyFormatLocaleForFilenameFn ||= (locale: string) => - JSON.stringify(formatLocaleForFilenameFn(locale)); + jsonStringifyFormatLocaleForFilenameFn ||= (locale: string, compilation: unknown, chunk: unknown) => + JSON.stringify(formatLocaleForFilenameFn(locale, undefined, undefined)); const dynamicElement: IDynamicReconstructionElement = { kind: DYNAMIC_RECONSTRUCTION_ELEMENT_KIND, start, diff --git a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts index 8ee555a697b..f22cdd7f087 100644 --- a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts +++ b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts @@ -36,7 +36,7 @@ import { chunkIsJs } from './utilities/chunkUtilities'; /** * @public */ -export type ValueForLocaleFn = (locale: string) => string; +export type ValueForLocaleFn = (locale: string, compilation: Compilation, chunk: Chunk) => string; /** * @public From 1938bc1e09e9321749643eccadceadbdb197d804 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Fri, 27 Jun 2025 19:11:42 -0700 Subject: [PATCH 3/7] Remove the compilation. --- .../api/webpack5-localization-plugin.api.md | 2 +- webpack/webpack5-localization-plugin/README.md | 2 +- .../src/AssetProcessor.ts | 14 ++++++-------- .../src/LocalizationPlugin.ts | 15 ++++++++++----- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/common/reviews/api/webpack5-localization-plugin.api.md b/common/reviews/api/webpack5-localization-plugin.api.md index 58d73e6f567..8df6d54da81 100644 --- a/common/reviews/api/webpack5-localization-plugin.api.md +++ b/common/reviews/api/webpack5-localization-plugin.api.md @@ -172,7 +172,7 @@ export class TrueHashPlugin implements WebpackPluginInstance { } // @public (undocumented) -export type ValueForLocaleFn = (locale: string, compilation: Compilation, chunk: Chunk) => string; +export type ValueForLocaleFn = (locale: string, chunk: Chunk) => string; // (No @packageDocumentation comment for this package) diff --git a/webpack/webpack5-localization-plugin/README.md b/webpack/webpack5-localization-plugin/README.md index bed21af4fa1..792b6e70a73 100644 --- a/webpack/webpack5-localization-plugin/README.md +++ b/webpack/webpack5-localization-plugin/README.md @@ -212,7 +212,7 @@ both are set. ## Custom Localized Data If you need to provide custom localized data, you can use the `getCustomDataPlaceholderForValueFunction` method -of the plugin. This method takes a function that receives a locale name, a webpack compilation instance, and the chunk +of the plugin. This method takes a function that receives a locale name and the chunk that the placeholder is used in and returns a string that will be used as a placeholder for the localized data. The provided function will be called for each locale that is used in the build and the returned value will replace the returned placeholder in the output. diff --git a/webpack/webpack5-localization-plugin/src/AssetProcessor.ts b/webpack/webpack5-localization-plugin/src/AssetProcessor.ts index 4d8dc8a2a0e..41622abd726 100644 --- a/webpack/webpack5-localization-plugin/src/AssetProcessor.ts +++ b/webpack/webpack5-localization-plugin/src/AssetProcessor.ts @@ -33,10 +33,10 @@ interface IDynamicReconstructionElement { type IReconstructionElement = ILocalizedReconstructionElement | IDynamicReconstructionElement; /** * @remarks - * Include the `compilation` and `chunk` parameters so that the functions arity is the same as the + * Include the `chunk` parameter so that the functions arity is the same as the * `ValueForLocaleFn` type. */ -type FormatLocaleForFilenameFn = (locale: string, compilation: unknown, chunk: unknown) => string; +type FormatLocaleForFilenameFn = (locale: string, chunk: unknown) => string; interface IParseResult { issues: string[]; @@ -276,7 +276,6 @@ export function processNonLocalizedAsset(options: IProcessNonLocalizedAssetOptio new sources.ReplaceSource(cachedSource, locale), parsedAsset.reconstructionSeries, locale, - compilation, chunk ); @@ -375,7 +374,7 @@ function _reconstructLocalized( } case DYNAMIC_RECONSTRUCTION_ELEMENT_KIND: { - const newValue: string = element.valueFn(locale, compilation, chunk); + const newValue: string = element.valueFn(locale, chunk); result.replace(start, end - 1, newValue); break; } @@ -392,7 +391,6 @@ function _reconstructNonLocalized( result: sources.ReplaceSource, reconstructionSeries: IReconstructionElement[], noStringsLocaleName: string, - compilation: Compilation, chunk: Chunk ): INonLocalizedReconstructionResult { const issues: string[] = []; @@ -411,7 +409,7 @@ function _reconstructNonLocalized( } case DYNAMIC_RECONSTRUCTION_ELEMENT_KIND: { - const newValue: string = element.valueFn(noStringsLocaleName, compilation, chunk); + const newValue: string = element.valueFn(noStringsLocaleName, chunk); result.replace(element.start, element.end - 1, newValue); break; } @@ -479,8 +477,8 @@ function _parseStringToReconstructionSequence( } case Constants.JSONP_PLACEHOLDER_LABEL: { - jsonStringifyFormatLocaleForFilenameFn ||= (locale: string, compilation: unknown, chunk: unknown) => - JSON.stringify(formatLocaleForFilenameFn(locale, undefined, undefined)); + jsonStringifyFormatLocaleForFilenameFn ||= (locale: string, chunk: unknown) => + JSON.stringify(formatLocaleForFilenameFn(locale, chunk)); const dynamicElement: IDynamicReconstructionElement = { kind: DYNAMIC_RECONSTRUCTION_ELEMENT_KIND, start, diff --git a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts index f22cdd7f087..01188340f03 100644 --- a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts +++ b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts @@ -36,7 +36,7 @@ import { chunkIsJs } from './utilities/chunkUtilities'; /** * @public */ -export type ValueForLocaleFn = (locale: string, compilation: Compilation, chunk: Chunk) => string; +export type ValueForLocaleFn = (locale: string, chunk: Chunk) => string; /** * @public @@ -132,7 +132,12 @@ export class LocalizationPlugin implements WebpackPluginInstance { private _defaultLocale!: string; private _noStringsLocaleName!: string; private _fillMissingTranslationStrings!: boolean; - private _formatLocaleForFilename!: (loc: string) => string; + /** + * @remarks + * Include the `chunk` parameter so that the functions arity is the same as the + * `ValueForLocaleFn` type. + */ + private _formatLocaleForFilename!: (loc: string, chunk: unknown) => string; private readonly _pseudolocalizers: Map string> = new Map(); private _customValueSuffixCounter: number = 0; @@ -277,7 +282,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { } if (chunkIdsWithStrings.size === 0) { - return this._formatLocaleForFilename(this._noStringsLocaleName); + return this._formatLocaleForFilename(this._noStringsLocaleName, undefined); } else if (chunkIdsWithoutStrings.size === 0) { return `" + ${localeExpression} + "`; } else { @@ -300,7 +305,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { } const noLocaleExpression: string = JSON.stringify( - this._formatLocaleForFilename(this._noStringsLocaleName) + this._formatLocaleForFilename(this._noStringsLocaleName, undefined) ); return `" + (${JSON.stringify(chunkMapping)}[chunkId]?${ @@ -321,7 +326,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { } return assetPath.replace( Constants.LOCALE_FILENAME_TOKEN_REGEX, - this._formatLocaleForFilename(locale) + this._formatLocaleForFilename(locale, undefined) ); } } else { From 31274ed531284907e0397984f57e71b58988bc84 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Fri, 27 Jun 2025 19:34:02 -0700 Subject: [PATCH 4/7] fixup! Remove the compilation. --- webpack/webpack5-localization-plugin/src/AssetProcessor.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/webpack/webpack5-localization-plugin/src/AssetProcessor.ts b/webpack/webpack5-localization-plugin/src/AssetProcessor.ts index 41622abd726..b9169c4c9a9 100644 --- a/webpack/webpack5-localization-plugin/src/AssetProcessor.ts +++ b/webpack/webpack5-localization-plugin/src/AssetProcessor.ts @@ -173,7 +173,6 @@ export function processLocalizedAsset(options: IProcessLocalizedAssetOptions): I locale, fallbackLocale, passthroughLocaleName, - compilation, chunk ); @@ -324,7 +323,6 @@ function _reconstructLocalized( locale: string, fallbackLocale: string | undefined, passthroughLocale: string | undefined, - compilation: Compilation, chunk: Chunk ): ILocalizedReconstructionResult { const issues: string[] = []; From 8e6a14e9982194e546d365ce9e36160089a5e0de Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 28 Jun 2025 15:50:51 -0700 Subject: [PATCH 5/7] Require a unique ID in getCustomDataPlaceholderForValueFunction. --- .../api/webpack5-localization-plugin.api.md | 2 +- .../src/LocalizationPlugin.ts | 24 ++++++++++++------- .../src/test/LocalizedRuntimeTestBase.ts | 3 ++- .../LocalizedRuntime.test.ts.snap | 4 ++-- ...edRuntimeDifferentHashLengths.test.ts.snap | 4 ++-- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/common/reviews/api/webpack5-localization-plugin.api.md b/common/reviews/api/webpack5-localization-plugin.api.md index 8df6d54da81..158d8baff09 100644 --- a/common/reviews/api/webpack5-localization-plugin.api.md +++ b/common/reviews/api/webpack5-localization-plugin.api.md @@ -155,7 +155,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { // @internal (undocumented) _getCustomDataForSerialNumber(suffix: string): _ICustomDataPlaceholder | undefined; // (undocumented) - getCustomDataPlaceholderForValueFunction(valueForLocaleFn: ValueForLocaleFn): string; + getCustomDataPlaceholderForValueFunction(valueForLocaleFn: ValueForLocaleFn, placeholderUniqueId: string): string; // (undocumented) getPlaceholder(localizedFileKey: string, stringName: string): IStringPlaceholder | undefined; // @internal (undocumented) diff --git a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts index 01188340f03..a33a0e53ab6 100644 --- a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts +++ b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts @@ -124,10 +124,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { > = new Map(); private readonly _stringPlaceholderBySuffix: Map = new Map(); private readonly _customDataPlaceholderBySuffix: Map = new Map(); - private readonly _customDataPlaceholderByCustomValueFunction: WeakMap< - ValueForLocaleFn, - ICustomDataPlaceholder - > = new WeakMap(); + private readonly _customDataPlaceholderByUniqueId: Map = new Map(); private _passthroughLocaleName!: string; private _defaultLocale!: string; private _noStringsLocaleName!: string; @@ -139,7 +136,6 @@ export class LocalizationPlugin implements WebpackPluginInstance { */ private _formatLocaleForFilename!: (loc: string, chunk: unknown) => string; private readonly _pseudolocalizers: Map string> = new Map(); - private _customValueSuffixCounter: number = 0; /** * The set of locales that have translations provided. @@ -578,18 +574,28 @@ export class LocalizationPlugin implements WebpackPluginInstance { /** * @public */ - public getCustomDataPlaceholderForValueFunction(valueForLocaleFn: ValueForLocaleFn): string { + public getCustomDataPlaceholderForValueFunction( + valueForLocaleFn: ValueForLocaleFn, + placeholderUniqueId: string + ): string { let placeholder: ICustomDataPlaceholder | undefined = - this._customDataPlaceholderByCustomValueFunction.get(valueForLocaleFn); + this._customDataPlaceholderByUniqueId.get(placeholderUniqueId); if (!placeholder) { - const suffix: string = String(this._customValueSuffixCounter++); + const suffix: string = Buffer.from(placeholderUniqueId + valueForLocaleFn.name, 'utf-8').toString( + 'hex' + ); placeholder = { value: `${Constants.STRING_PLACEHOLDER_PREFIX}_${Constants.CUSTOM_PLACEHOLDER_LABEL}_${suffix}_`, suffix, valueForLocaleFn }; this._customDataPlaceholderBySuffix.set(suffix, placeholder); - this._customDataPlaceholderByCustomValueFunction.set(valueForLocaleFn, placeholder); + this._customDataPlaceholderByUniqueId.set(placeholderUniqueId, placeholder); + } else if (placeholder.valueForLocaleFn !== valueForLocaleFn) { + throw new Error( + `${this.getCustomDataPlaceholderForValueFunction.name} has already been called with "${placeholderUniqueId}" ` + + `and a different valueForLocaleFn.` + ); } return placeholder.value; diff --git a/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts index 048ef6649a8..08c5df649bf 100644 --- a/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts +++ b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts @@ -46,7 +46,8 @@ class InjectCustomPlaceholderPlugin implements webpack.WebpackPluginInstance { public override generate(): string { const placeholder: string = localizationPlugin.getCustomDataPlaceholderForValueFunction( - getLocalizedChunkNamesString + getLocalizedChunkNamesString, + printLocalizedChunkName ); return Template.asString([ diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap index 101f7d0d3be..54e4d692756 100644 --- a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap @@ -6,8 +6,8 @@ Object { "/release/chunks/async1-LOCALE2-1e57833357912f77511d.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test,a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", "/release/chunks/async2-LOCALE1-0c2f434469639436732a.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"something else\\"}}}]);", "/release/chunks/async2-LOCALE2-664388d6b7aa642fc965.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", - "/release/mainSingleChunk-LOCALE1-cc757d83ebe52349b038.js": "(()=>{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE1\\"+\\"-44d1a3fadec3f8385e08.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=d.bind(null,c.onerror),c.onload=d.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE2\\"+\\"-1e57833357912f77511d.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=d.bind(null,c.onerror),c.onload=d.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE1\\"+\\"-44d1a3fadec3f8385e08.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE2\\"+\\"-1e57833357912f77511d.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE1\\"+\\"-\\"+{230:\\"44d1a3fadec3f8385e08\\",421:\\"0c2f434469639436732a\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE2\\"+\\"-\\"+{230:\\"1e57833357912f77511d\\",421:\\"664388d6b7aa642fc965\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test,a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", "/release/chunks/async2-LOCALE1-2878fc254efcf861ebdb1de8ffe2da978f78d90bdb657ca96126fe284386851a.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"something else\\"}}}]);", "/release/chunks/async2-LOCALE2-c2b6b66a1486798af745222597d7f7f64daf16f5566e28a3e34dda6da6f41f87.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", - "/release/mainSingleChunk-LOCALE1-4dd9af55b9b4dc329b0f6ae0211f819906d777d637770381b57fd7064ce81684.js": "(()=>{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE1\\"+\\"-9bd32294abc47c2bd95cbd4f4a64ac12f94cfd89dbb3cc1056c8ca83c94b3f83.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=d.bind(null,c.onerror),c.onload=d.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE2\\"+\\"-fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(d.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=d.bind(null,c.onerror),c.onload=d.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE1\\"+\\"-9bd32294abc47c2bd95cbd4f4a64ac12f94cfd89dbb3cc1056c8ca83c94b3f83.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE2\\"+\\"-fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE1\\"+\\"-\\"+{230:\\"9bd32294abc47c2bd95cbd4f4a64ac12f94cfd89dbb3cc1056c8ca83c94b3f83\\",421:\\"2878fc254efcf861ebdb1de8ffe2da978f78d90bdb657ca96126fe284386851a\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE2\\"+\\"-\\"+{230:\\"fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8\\",421:\\"c2b6b66a1486798af745222597d7f7f64daf16f5566e28a3e34dda6da6f41f87\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l Date: Sat, 28 Jun 2025 16:01:21 -0700 Subject: [PATCH 6/7] fixup! Require a unique ID in getCustomDataPlaceholderForValueFunction. --- .../webpack5-localization-plugin/src/LocalizationPlugin.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts index a33a0e53ab6..e47ee9921bc 100644 --- a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts +++ b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts @@ -581,9 +581,8 @@ export class LocalizationPlugin implements WebpackPluginInstance { let placeholder: ICustomDataPlaceholder | undefined = this._customDataPlaceholderByUniqueId.get(placeholderUniqueId); if (!placeholder) { - const suffix: string = Buffer.from(placeholderUniqueId + valueForLocaleFn.name, 'utf-8').toString( - 'hex' - ); + // Get a hash of the unique ID to make sure its value doesn't interfere with our placeholder tokens + const suffix: string = Buffer.from(placeholderUniqueId, 'utf-8').toString('hex'); placeholder = { value: `${Constants.STRING_PLACEHOLDER_PREFIX}_${Constants.CUSTOM_PLACEHOLDER_LABEL}_${suffix}_`, suffix, From c4f49c4ad5e92d83027e30b46947e287bf9e73fb Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 28 Jun 2025 19:41:53 -0700 Subject: [PATCH 7/7] Mark getCustomDataPlaceholderForValueFunction as beta. --- common/reviews/api/webpack5-localization-plugin.api.md | 2 +- webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/reviews/api/webpack5-localization-plugin.api.md b/common/reviews/api/webpack5-localization-plugin.api.md index 158d8baff09..b985e49c966 100644 --- a/common/reviews/api/webpack5-localization-plugin.api.md +++ b/common/reviews/api/webpack5-localization-plugin.api.md @@ -154,7 +154,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { apply(compiler: Compiler): void; // @internal (undocumented) _getCustomDataForSerialNumber(suffix: string): _ICustomDataPlaceholder | undefined; - // (undocumented) + // @beta (undocumented) getCustomDataPlaceholderForValueFunction(valueForLocaleFn: ValueForLocaleFn, placeholderUniqueId: string): string; // (undocumented) getPlaceholder(localizedFileKey: string, stringName: string): IStringPlaceholder | undefined; diff --git a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts index e47ee9921bc..1848be90f98 100644 --- a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts +++ b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts @@ -572,7 +572,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { } /** - * @public + * @beta */ public getCustomDataPlaceholderForValueFunction( valueForLocaleFn: ValueForLocaleFn,