diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs
index 5e15cc53841ad..3acee24e88536 100644
--- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs
+++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs
@@ -11,6 +11,7 @@
using Microsoft.Playwright;
using Xunit.Abstractions;
using Xunit;
+using System.Xml.Linq;
#nullable enable
@@ -38,4 +39,44 @@ public async Task LoadSatelliteAssembly()
m => Assert.Equal("es-ES with satellite: hola", m)
);
}
+
+ [Fact]
+ public async Task LoadSatelliteAssemblyFromReference()
+ {
+ CopyTestAsset("WasmBasicTestApp", "SatelliteLoadingTestsFromReference", "App");
+
+ // Replace ProjectReference with Reference
+ var appCsprojPath = Path.Combine(_projectDir!, "WasmBasicTestApp.csproj");
+ var appCsproj = XDocument.Load(appCsprojPath);
+
+ var projectReference = appCsproj.Descendants("ProjectReference").Where(pr => pr.Attribute("Include")?.Value?.Contains("ResourceLibrary") ?? false).Single();
+ var itemGroup = projectReference.Parent!;
+ projectReference.Remove();
+
+ var reference = new XElement("Reference");
+ reference.SetAttributeValue("Include", "..\\ResourceLibrary\\bin\\Release\\net9.0\\ResourceLibrary.dll");
+ itemGroup.Add(reference);
+
+ appCsproj.Save(appCsprojPath);
+
+ // Build the library
+ var libraryCsprojPath = Path.GetFullPath(Path.Combine(_projectDir!, "..", "ResourceLibrary"));
+ new DotNetCommand(s_buildEnv, _testOutput)
+ .WithWorkingDirectory(libraryCsprojPath)
+ .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir)
+ .ExecuteWithCapturedOutput("build -c Release")
+ .EnsureSuccessful();
+
+ // Publish the app and assert
+ PublishProject("Release");
+
+ var result = await RunSdkStyleAppForPublish(new(Configuration: "Release", TestScenario: "SatelliteAssembliesTest"));
+ Assert.Collection(
+ result.TestOutput,
+ m => Assert.Equal("default: hello", m),
+ m => Assert.Equal("es-ES without satellite: hello", m),
+ m => Assert.Equal("default: hello", m),
+ m => Assert.Equal("es-ES with satellite: hola", m)
+ );
+ }
}
diff --git a/src/mono/wasm/build/WasmApp.Common.targets b/src/mono/wasm/build/WasmApp.Common.targets
index 2641a239ac4e5..cee4e3c1bea03 100644
--- a/src/mono/wasm/build/WasmApp.Common.targets
+++ b/src/mono/wasm/build/WasmApp.Common.targets
@@ -442,7 +442,7 @@
+ Properties="_WasmInNestedPublish_UniqueProperty_XYZ=true;;WasmBuildingForNestedPublish=true;DeployOnBuild=;_IsPublishing=;_WasmIsPublishing=$(_IsPublishing);ResolveAssemblyReferencesFindRelatedSatellites=true">
diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/SatelliteAssembliesTest.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/SatelliteAssembliesTest.cs
index b8dc5b0dbf884..23f3df8098cc5 100644
--- a/src/mono/wasm/testassets/WasmBasicTestApp/App/SatelliteAssembliesTest.cs
+++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/SatelliteAssembliesTest.cs
@@ -2,25 +2,19 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Globalization;
-using System.Threading.Tasks;
-using System.Resources;
using System.Runtime.InteropServices.JavaScript;
+using System.Threading.Tasks;
public partial class SatelliteAssembliesTest
{
[JSExport]
public static async Task Run()
{
- var rm = new ResourceManager("WasmBasicTestApp.words", typeof(Program).Assembly);
- TestOutput.WriteLine("default: " + rm.GetString("hello", CultureInfo.CurrentCulture));
- TestOutput.WriteLine("es-ES without satellite: " + rm.GetString("hello", new CultureInfo("es-ES")));
+ ResourceLibrary.ResourceAccessor.Read(TestOutput.WriteLine, false);
await LoadSatelliteAssemblies(new[] { "es-ES" });
- rm = new ResourceManager("WasmBasicTestApp.words", typeof(Program).Assembly);
- TestOutput.WriteLine("default: " + rm.GetString("hello", CultureInfo.CurrentCulture));
- TestOutput.WriteLine("es-ES with satellite: " + rm.GetString("hello", new CultureInfo("es-ES")));
+ ResourceLibrary.ResourceAccessor.Read(TestOutput.WriteLine, true);
}
[JSImport("INTERNAL.loadSatelliteAssemblies")]
diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/WasmBasicTestApp.csproj b/src/mono/wasm/testassets/WasmBasicTestApp/App/WasmBasicTestApp.csproj
index f93102b467a45..e16a8c4948ca5 100644
--- a/src/mono/wasm/testassets/WasmBasicTestApp/App/WasmBasicTestApp.csproj
+++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/WasmBasicTestApp.csproj
@@ -16,6 +16,7 @@
+
diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.cs b/src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.cs
index cd496b96a3fc9..d2cffde92c9e4 100644
--- a/src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.cs
+++ b/src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.cs
@@ -1,3 +1,6 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
using System.Text.Json;
using System.Text.Json.Serialization;
diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/ResourceLibrary/ResourceAccessor.cs b/src/mono/wasm/testassets/WasmBasicTestApp/ResourceLibrary/ResourceAccessor.cs
new file mode 100644
index 0000000000000..27073846c66ae
--- /dev/null
+++ b/src/mono/wasm/testassets/WasmBasicTestApp/ResourceLibrary/ResourceAccessor.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Globalization;
+using System.Threading.Tasks;
+using System.Resources;
+
+namespace ResourceLibrary;
+
+public static class ResourceAccessor
+{
+ public static void Read(Action testOuput, bool hasSatellites)
+ {
+ var rm = new ResourceManager("ResourceLibrary.words", typeof(ResourceAccessor).Assembly);
+ testOuput($"default: {rm.GetString("hello", CultureInfo.CurrentCulture)}");
+ testOuput($"es-ES {(hasSatellites ? "with" : "without")} satellite: {rm.GetString("hello", new CultureInfo("es-ES"))}");
+ }
+}
diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/ResourceLibrary/ResourceLibrary.csproj b/src/mono/wasm/testassets/WasmBasicTestApp/ResourceLibrary/ResourceLibrary.csproj
new file mode 100644
index 0000000000000..3d5e0e2093c1a
--- /dev/null
+++ b/src/mono/wasm/testassets/WasmBasicTestApp/ResourceLibrary/ResourceLibrary.csproj
@@ -0,0 +1,7 @@
+
+
+ net9.0
+ Library
+ true
+
+
diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/words.es-ES.resx b/src/mono/wasm/testassets/WasmBasicTestApp/ResourceLibrary/words.es-ES.resx
similarity index 100%
rename from src/mono/wasm/testassets/WasmBasicTestApp/App/words.es-ES.resx
rename to src/mono/wasm/testassets/WasmBasicTestApp/ResourceLibrary/words.es-ES.resx
diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/words.resx b/src/mono/wasm/testassets/WasmBasicTestApp/ResourceLibrary/words.resx
similarity index 100%
rename from src/mono/wasm/testassets/WasmBasicTestApp/App/words.resx
rename to src/mono/wasm/testassets/WasmBasicTestApp/ResourceLibrary/words.resx
diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs
index e8daa16e60813..cb070606f49c0 100644
--- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs
+++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs
@@ -110,7 +110,12 @@ public override bool Execute()
assetCandidate.SetMetadata("AssetTraitName", "Culture");
assetCandidate.SetMetadata("AssetTraitValue", inferredCulture);
assetCandidate.SetMetadata("RelativePath", $"_framework/{inferredCulture}/{satelliteAssembly.GetMetadata("FileName")}{satelliteAssembly.GetMetadata("Extension")}");
- assetCandidate.SetMetadata("RelatedAsset", Path.GetFullPath(Path.Combine(OutputPath, "wwwroot", "_framework", Path.GetFileName(assetCandidate.GetMetadata("ResolvedFrom")))));
+
+ var resolvedFrom = assetCandidate.GetMetadata("ResolvedFrom");
+ if (resolvedFrom == "{RawFileName}") // Satellite assembly found from `` element
+ resolvedFrom = candidate.GetMetadata("OriginalItemSpec");
+
+ assetCandidate.SetMetadata("RelatedAsset", Path.GetFullPath(Path.Combine(OutputPath, "wwwroot", "_framework", Path.GetFileName(resolvedFrom))));
assetCandidates.Add(assetCandidate);
continue;