docs icon indicating copy to clipboard operation
docs copied to clipboard

SatelliteResourceLanguages clarifications for listing multiple languages

Open KalleOlaviNiemitalo opened this issue 3 years ago • 1 comments

I'd like to request two clarifications to the documentation of the SatelliteResourceLanguages property:

  1. Change the example to show how to list more than one language, specifically that semicolons must be used as separators. https://github.com/dotnet/docs/blob/ff7e3568e4bfb7283be4bbdb65c2b0024e8169bb/docs/core/project-sdk/msbuild-props.md?plain=1#L386-L390
  2. Extend the note to explicitly recommend against using the MSBuild command-line option -property:name=value to set this property, because it is not possible to list more than one language that way. https://github.com/dotnet/docs/blob/ff7e3568e4bfb7283be4bbdb65c2b0024e8169bb/docs/core/project-sdk/msbuild-props.md?plain=1#L392-L393

Context

I tried to set SatelliteResourceLanguages on the dotnet publish command line, using .NET SDK 6.0.302 on Windows:

PS> dotnet publish -o "$(Get-Location)/bin/net6.0" --no-self-contained --configuration Release --framework net6.0 -p:SatelliteResourceLanguages="en;de"
Microsoft (R) Build Engine version 17.2.0+41abc5629 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

MSBUILD : error MSB1006: Property is not valid.
Switch: de

For switch syntax, type "MSBuild -help"

It didn't work, because the -p option parsed the semicolon as terminating the property value and starting another property name, regardless of the quotation marks. Next, I tried encoding the semicolon as %3B, as listed in MSBuild special characters:

PS> dotnet publish -o "$(Get-Location)/bin/net6.0" --no-self-contained --configuration Release --framework net6.0 -p:SatelliteResourceLanguages="en%3Ade"
Microsoft (R) Build Engine version 17.2.0+41abc5629 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  Restored C:\MyApp\src\MyApp\MyApp.csproj (in 542 ms).
  MyApp -> C:\MyApp\src\MyApp\bin\Release\net6.0\MyApp.dll
  MyApp -> C:\MyApp\bin\net6.0\

That appeared to succeed, but .NET SDK did not copy the "de" satellite assembly to C:\MyApp\bin\net6.0\de\System.CommandLine.resources.dll. I think the reason is that the SatelliteResourceLanguages parameter of the ResolvePackageAssets task is defined as ITaskItem[] rather than string, so when the ResolvePackageAssets target passes $(SatelliteResourceLanguages) to that parameter, MSBuild has to split the string value to items, but if the semicolon was encoded, then MSBuild doesn't treat it as a list separator.

Finally, I set the property in Directory.Build.props, to make it apply to all projects in the solution

<Project>
  <PropertyGroup>
    <SatelliteResourceLanguages>en;de</SatelliteResourceLanguages>
  </PropertyGroup>
</Project>

and ran dotnet publish without the -property:SatelliteResourceLanguages=value option, and that worked fine.


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

KalleOlaviNiemitalo avatar Jul 29 '22 16:07 KalleOlaviNiemitalo

2. Extend the note to explicitly recommend against using the MSBuild command-line option -property:name=value to set this property, because it is not possible to list more than one language that way.

This might have changed recently; see https://github.com/dotnet/sdk/issues/27059. However, that was reported as a bug.

KalleOlaviNiemitalo avatar Aug 10 '22 09:08 KalleOlaviNiemitalo

Thanks @KalleOlaviNiemitalo. I'm not going to add the note about no. 2) since it was confirmed yesterday that this is a bug.

gewarren avatar Aug 11 '22 21:08 gewarren

Well, it seems possible to list multiple languages in -p:SatelliteResourceLanguages= after all, but it requires some gymnastics.

The following project demonstrates how MSBuild converts the value of a property to items. I believe MSBuild uses the same kind of conversion when the .NET SDK passes $(SatelliteResourceLanguages) to the ResolvePackageAssets task:

<Project>
  <ItemGroup>
    <Item Include="$(Prop)" />
  </ItemGroup>
  <Target Name="Build">
    <Message Importance="high" Text="Property: [$(Prop)]" />
    <Message Importance="high" Text="Items: @(Item->'[%(Identity)]')" />
  </Target>
</Project>

Using cmd.exe on Windows to run "Microsoft (R) Build Engine version 17.2.0+41abc5629 for .NET" via .NET SDK 6.0.303, which does not have the bug https://github.com/dotnet/sdk/issues/27059:

  • The property value cannot contain a plain semicolon because that gets treated as a separator between name=value pairs.
    dotnet msbuild multi.msbuildproj -nologo -p:Prop=de;en
    MSBUILD : error MSB1006: Property is not valid.
    Switch: en
    
    For switch syntax, type "MSBuild -help"
    
  • A semicolon encoded as %3B is accepted, but the conversion to items does not treat it as a delimiter.
    dotnet msbuild multi.msbuildproj -nologo -p:Prop=de%3Ben
      Property: [de;en]
      Items: [de;en]
    
  • A pair of quotation marks around the property value makes no difference.
    dotnet msbuild multi.msbuildproj -nologo -p:Prop="de;en"
    MSBUILD : error MSB1006: Property is not valid.
    Switch: en
    
    For switch syntax, type "MSBuild -help"
    
  • Two pairs don't work either.
    dotnet msbuild multi.msbuildproj -nologo -p:Prop=""de;en""
    MSBUILD : error MSB1006: Property is not valid.
    Switch: en
    
    For switch syntax, type "MSBuild -help"
    
  • Three pairs of quotation marks make it work; the semicolon is parsed as a item separator, but not as a name=value separator.
    dotnet msbuild multi.msbuildproj -nologo -p:Prop="""de;en"""
      Property: [de;en]
      Items: [de];[en]
    

So yeah, I was wrong and it's possible to specify multiple languages using -p. However, the triply double-quoted syntax is rather unobvious and shell-dependent (PowerShell on Windows seems to require --% for it). If you have a docs page for how to correctly quote MSBuild command-line options, then it would be good to link to that from there.

KalleOlaviNiemitalo avatar Aug 11 '22 22:08 KalleOlaviNiemitalo

This works in PowerShell 7.2.5 on Windows

dotnet msbuild multi.msbuildproj -nologo '-p:Prop="""de;en"""'

KalleOlaviNiemitalo avatar Aug 11 '22 22:08 KalleOlaviNiemitalo

This works in bash shipped with Git for Windows 2.36.0

dotnet msbuild multi.msbuildproj -nologo -p:Prop='"de;en"'

KalleOlaviNiemitalo avatar Aug 11 '22 22:08 KalleOlaviNiemitalo

Reopening to document the triple quote syntax that's required to specify multiple languages on the command line.

gewarren avatar Aug 12 '22 20:08 gewarren