Skip to content

Commit a8a2f94

Browse files
author
Pranav Krishnamoorthy
committed
Merged PR 9371: Revive support for globalization and localization in Blazor WASM
Revive support for globalization and localization in Blazor WASM * Load icu and timezone data files * Unskip tests Fixes dotnet/aspnetcore#24174 Fixes dotnet/aspnetcore#22975 Fixes dotnet/aspnetcore#23260
1 parent d099750 commit a8a2f94

File tree

6 files changed

+53
-54
lines changed

6 files changed

+53
-54
lines changed

dist/Release/blazor.server.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/Release/blazor.webassembly.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Platform/Mono/MonoPlatform.ts

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import { attachDebuggerHotkey, hasDebuggingEnabled } from './MonoDebugger';
33
import { showErrorNotification } from '../../BootErrors';
44
import { WebAssemblyResourceLoader, LoadingResource } from '../WebAssemblyResourceLoader';
55
import { Platform, System_Array, Pointer, System_Object, System_String, HeapLock } from '../Platform';
6-
import { loadTimezoneData } from './TimezoneDataFile';
76
import { WebAssemblyBootResourceType } from '../WebAssemblyStartOptions';
87
import { initializeProfiling } from '../Profiling';
98

109
let mono_wasm_add_assembly: (name: string, heapAddress: number, length: number) => void;
1110
const appBinDirName = 'appBinDir';
11+
const icuDataResourceName = 'icudt.dat';
1212
const uint64HighOrderShift = Math.pow(2, 32);
1313
const maxSafeNumberHighPart = Math.pow(2, 21) - 1; // The high-order int32 from Number.MAX_SAFE_INTEGER
1414

@@ -244,14 +244,26 @@ function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourceLoade
244244
/* hash */ resourceLoader.bootConfig.resources.runtime[dotnetWasmResourceName],
245245
/* type */ 'dotnetwasm');
246246

247-
const dotnetTimeZoneResourceName = 'dotnet.timezones.dat';
247+
const dotnetTimeZoneResourceName = 'dotnet.timezones.blat';
248248
let timeZoneResource: LoadingResource | undefined;
249249
if (resourceLoader.bootConfig.resources.runtime.hasOwnProperty(dotnetTimeZoneResourceName)) {
250250
timeZoneResource = resourceLoader.loadResource(
251251
dotnetTimeZoneResourceName,
252252
`_framework/${dotnetTimeZoneResourceName}`,
253253
resourceLoader.bootConfig.resources.runtime[dotnetTimeZoneResourceName],
254-
'timezonedata');
254+
'globalization');
255+
}
256+
257+
let icuDataResource: LoadingResource | undefined;
258+
if (resourceLoader.bootConfig.resources.runtime.hasOwnProperty(icuDataResourceName)) {
259+
icuDataResource = resourceLoader.loadResource(
260+
icuDataResourceName,
261+
`_framework/${icuDataResourceName}`,
262+
resourceLoader.bootConfig.resources.runtime[icuDataResourceName],
263+
'globalization');
264+
} else {
265+
// Use invariant culture if the app does not carry icu data.
266+
MONO.mono_wasm_setenv("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1");
255267
}
256268

257269
// Override the mechanism for fetching the main wasm file so we can connect it to our cache
@@ -279,6 +291,10 @@ function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourceLoade
279291
loadTimezone(timeZoneResource);
280292
}
281293

294+
if (icuDataResource) {
295+
loadICUData(icuDataResource);
296+
}
297+
282298
// Fetch the assemblies and PDBs in the background, telling Mono to wait until they are loaded
283299
// Mono requires the assembly filenames to have a '.dll' extension, so supply such names regardless
284300
// of the extensions in the URLs. This allows loading assemblies with arbitrary filenames.
@@ -363,7 +379,11 @@ function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourceLoade
363379
resourceLoader.purgeUnusedCacheEntriesAsync(); // Don't await - it's fine to run in background
364380

365381
MONO.mono_wasm_setenv("MONO_URI_DOTNETRELATIVEORABSOLUTE", "true");
366-
MONO.mono_wasm_setenv("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1");
382+
let timeZone = "UTC";
383+
try {
384+
timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
385+
} catch { }
386+
MONO.mono_wasm_setenv("TZ", timeZone);
367387
const load_runtime = cwrap('mono_wasm_load_runtime', null, ['string', 'number']);
368388
// -1 enables debugging with logging disabled. 0 disables debugging entirely.
369389
load_runtime(appBinDirName, hasDebuggingEnabled() ? -1 : 0);
@@ -461,8 +481,27 @@ async function loadTimezone(timeZoneResource: LoadingResource) : Promise<void> {
461481

462482
const request = await timeZoneResource.response;
463483
const arrayBuffer = await request.arrayBuffer();
464-
loadTimezoneData(arrayBuffer)
465484

485+
Module['FS_createPath']('/', 'usr', true, true);
486+
Module['FS_createPath']('/usr/', 'share', true, true);
487+
Module['FS_createPath']('/usr/share/', 'zoneinfo', true, true);
488+
MONO.mono_wasm_load_data_archive(new Uint8Array(arrayBuffer), '/usr/share/zoneinfo/');
489+
490+
removeRunDependency(runDependencyId);
491+
}
492+
493+
async function loadICUData(icuDataResource: LoadingResource) : Promise<void> {
494+
const runDependencyId = `blazor:icudata`;
495+
addRunDependency(runDependencyId);
496+
497+
const request = await icuDataResource.response;
498+
const array = new Uint8Array(await request.arrayBuffer());
499+
500+
const offset = MONO.mono_wasm_load_bytes_into_heap(array);
501+
if (!MONO.mono_wasm_load_icu_data(offset))
502+
{
503+
throw new Error("Error loading ICU asset.");
504+
}
466505
removeRunDependency(runDependencyId);
467506
}
468507

src/Platform/Mono/MonoTypes.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ declare interface MONO {
66
loaded_files: string[];
77
mono_wasm_runtime_ready (): void;
88
mono_wasm_setenv (name: string, value: string): void;
9+
mono_wasm_load_data_archive(data: Uint8Array, prefix: string): void;
10+
mono_wasm_load_bytes_into_heap (data: Uint8Array): Pointer;
11+
mono_wasm_load_icu_data(heapAddress: Pointer): boolean;
912
}
1013

1114
// Mono uses this global to hold low-level interop APIs

src/Platform/Mono/TimezoneDataFile.ts

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/Platform/WebAssemblyStartOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ export interface WebAssemblyStartOptions {
1414
// This type doesn't have to align with anything in BootConfig.
1515
// Instead, this represents the public API through which certain aspects
1616
// of boot resource loading can be customized.
17-
export type WebAssemblyBootResourceType = 'assembly' | 'pdb' | 'dotnetjs' | 'dotnetwasm' | 'timezonedata';
17+
export type WebAssemblyBootResourceType = 'assembly' | 'pdb' | 'dotnetjs' | 'dotnetwasm' | 'globalization';

0 commit comments

Comments
 (0)