From 0e545ad5d88ba3c6d546b08e9b31160991a98492 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Mon, 25 Nov 2024 14:58:35 +0000 Subject: [PATCH 1/7] Update dependencies from https://github.com/dotnet/roslyn build 20241125.2 Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.Net.Compilers.Toolset From Version 4.13.0-2.24561.1 -> To Version 4.13.0-3.24575.2 --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7acb497a028..7f98b1e78ff 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -89,13 +89,13 @@ https://github.com/nuget/nuget.client ce95a567627472f8abd9d155047392e22142ff72 - + https://github.com/dotnet/roslyn - 543cb4568f28b0d2f2cfecdf2d56365b9252e848 + f86856dda7a9acbe86f2bbf356420596d9d72c23 - + https://github.com/dotnet/roslyn - 543cb4568f28b0d2f2cfecdf2d56365b9252e848 + f86856dda7a9acbe86f2bbf356420596d9d72c23 diff --git a/eng/Versions.props b/eng/Versions.props index 0d6f97b9da1..315dfafd867 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -51,7 +51,7 @@ $([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)..\global.json')), '"dotnet": "([^"]*)"').Groups.get_Item(1)) 4.2.0-1.22102.8 9.0.0-beta.24562.13 - 4.13.0-2.24561.1 + 4.13.0-3.24575.2 6.13.0-preview.1.62 From 755781254b7ffaaa2706ec46b17d5e732d5c07e6 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Wed, 27 Nov 2024 00:20:45 -0800 Subject: [PATCH 2/7] Localized file check-in by OneLocBuild Task: Build definition ID 9434: Build ID 10620354 (#11040) --- src/Build/Resources/xlf/Strings.cs.xlf | 4 ++-- src/Build/Resources/xlf/Strings.de.xlf | 4 ++-- src/Build/Resources/xlf/Strings.es.xlf | 4 ++-- src/Build/Resources/xlf/Strings.fr.xlf | 4 ++-- src/Build/Resources/xlf/Strings.it.xlf | 4 ++-- src/Build/Resources/xlf/Strings.ja.xlf | 4 ++-- src/Build/Resources/xlf/Strings.ko.xlf | 4 ++-- src/Build/Resources/xlf/Strings.pl.xlf | 4 ++-- src/Build/Resources/xlf/Strings.pt-BR.xlf | 4 ++-- src/Build/Resources/xlf/Strings.ru.xlf | 4 ++-- src/Build/Resources/xlf/Strings.tr.xlf | 4 ++-- src/Build/Resources/xlf/Strings.zh-Hans.xlf | 4 ++-- src/Build/Resources/xlf/Strings.zh-Hant.xlf | 4 ++-- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/Build/Resources/xlf/Strings.cs.xlf b/src/Build/Resources/xlf/Strings.cs.xlf index 7bb0ca3b544..ff12e0468af 100644 --- a/src/Build/Resources/xlf/Strings.cs.xlf +++ b/src/Build/Resources/xlf/Strings.cs.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + Projekt {0} odkazuje na výstup projektu {1}. Odkazovaná cesta: {2}. Místo toho by se měla použít položka ProjectReference. A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + Na projekt by se nemělo odkazovat přes Reference na jeho výstup, ale přímo přes ProjectReference. diff --git a/src/Build/Resources/xlf/Strings.de.xlf b/src/Build/Resources/xlf/Strings.de.xlf index 608c6dbff77..47fa3acb9b5 100644 --- a/src/Build/Resources/xlf/Strings.de.xlf +++ b/src/Build/Resources/xlf/Strings.de.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + Das Projekt "{0}" verweist auf die Ausgabe eines Projekts "{1}". Pfad, auf den verwiesen wird: {2}. Stattdessen sollte ProjectReference verwendet werden. A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + Auf ein Projekt darf nicht über "Reference" auf seine Ausgabe verwiesen werden, sondern direkt über "ProjectReference". diff --git a/src/Build/Resources/xlf/Strings.es.xlf b/src/Build/Resources/xlf/Strings.es.xlf index 78621bb768b..b2cf227eb21 100644 --- a/src/Build/Resources/xlf/Strings.es.xlf +++ b/src/Build/Resources/xlf/Strings.es.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + El proyecto {0} hace referencia a la salida de un proyecto {1}. Ruta de acceso a la que se hace referencia: {2}. En su lugar, se debe usar ProjectReference. A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + No se debe hacer referencia a un proyecto a través de "Reference" a su salida, sino directamente a través de "ProjectReference". diff --git a/src/Build/Resources/xlf/Strings.fr.xlf b/src/Build/Resources/xlf/Strings.fr.xlf index 3c8975404d5..80df3b188af 100644 --- a/src/Build/Resources/xlf/Strings.fr.xlf +++ b/src/Build/Resources/xlf/Strings.fr.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + Project {0} référence la sortie d’un projet {1}. Chemin d’accès référencé : {2}. ProjectReference doit être utilisé à la place. A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + Un projet ne doit pas être référencé via « Reference » à sa sortie, mais directement via « ProjectReference ». diff --git a/src/Build/Resources/xlf/Strings.it.xlf b/src/Build/Resources/xlf/Strings.it.xlf index 0a7afe4e9a8..7c1c3bf7557 100644 --- a/src/Build/Resources/xlf/Strings.it.xlf +++ b/src/Build/Resources/xlf/Strings.it.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + Il progetto {0} fa riferimento all'output di un progetto {1}. Percorso di riferimento: {2}. Usare invece ProjectReference. A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + Un progetto non può fare riferimento al relativo output tramite 'Reference', ma direttamente tramite 'ProjectReference'. diff --git a/src/Build/Resources/xlf/Strings.ja.xlf b/src/Build/Resources/xlf/Strings.ja.xlf index addb4c4369d..c2c57270135 100644 --- a/src/Build/Resources/xlf/Strings.ja.xlf +++ b/src/Build/Resources/xlf/Strings.ja.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + プロジェクト {0} は、プロジェクト {1} の出力を参照します。参照パス: {2}。代わりに ProjectReference を使用する必要があります。 A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + プロジェクトは、出力に対する 'Reference' を介して参照するのではなく、'ProjectReference' を介して直接参照する必要があります。 diff --git a/src/Build/Resources/xlf/Strings.ko.xlf b/src/Build/Resources/xlf/Strings.ko.xlf index cc5d4fc3d82..2649c525183 100644 --- a/src/Build/Resources/xlf/Strings.ko.xlf +++ b/src/Build/Resources/xlf/Strings.ko.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + {0} 프로젝트가 {1} 프로젝트의 출력을 참조합니다. 참조된 경로: {2}. ProjectReference를 대신 사용해야 합니다. A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + 프로젝트는 ''Reference''를 통해 출력을 참조하지 말고 ''ProjectReference''를 통해 직접 참조해야 합니다. diff --git a/src/Build/Resources/xlf/Strings.pl.xlf b/src/Build/Resources/xlf/Strings.pl.xlf index 15e7e3b1418..746b03ca198 100644 --- a/src/Build/Resources/xlf/Strings.pl.xlf +++ b/src/Build/Resources/xlf/Strings.pl.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + Projekt {0} odwołuje się do danych wyjściowych projektu {1}. Ścieżka, do której istnieje odwołanie: {2}. Zamiast tego należy użyć elementu ProjectReference. A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + Do projektu nie należy odwoływać się poprzez opcję „Odwołanie” do jego danych wyjściowych, ale raczej bezpośrednio poprzez opcję „Odwołanie do projektu”. diff --git a/src/Build/Resources/xlf/Strings.pt-BR.xlf b/src/Build/Resources/xlf/Strings.pt-BR.xlf index 9361e4b3f3b..2173625f9c1 100644 --- a/src/Build/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Build/Resources/xlf/Strings.pt-BR.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + O projeto {0} faz referência à saída de um projeto {1}. Caminho referenciado: {2}. Em vez disso, ProjectReference deve ser usado. A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + Um projeto não deve ser referenciado por meio de "Referência" à sua saída, mas diretamente por meio de "ProjectReference". diff --git a/src/Build/Resources/xlf/Strings.ru.xlf b/src/Build/Resources/xlf/Strings.ru.xlf index 8b581ae95a0..dd8154f048a 100644 --- a/src/Build/Resources/xlf/Strings.ru.xlf +++ b/src/Build/Resources/xlf/Strings.ru.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + Проект {0} ссылается на выходные данные проекта {1}. Указанный по ссылке путь: {2}. Вместо этого следует использовать ProjectReference. A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + На проект следует ссылаться не с помощью параметра "Reference" для его выходных данных, а непосредственно посредством "ProjectReference". diff --git a/src/Build/Resources/xlf/Strings.tr.xlf b/src/Build/Resources/xlf/Strings.tr.xlf index 08edf588636..497a5fd2043 100644 --- a/src/Build/Resources/xlf/Strings.tr.xlf +++ b/src/Build/Resources/xlf/Strings.tr.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + {0} projesi bir {1} projesinin çıkışına referans başvuru yapar. Başvurulan yol:{2}. Bunun yerine ProjectReference kullanılmalıdır. A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + Bir projeye, çıkışına 'Reference' aracılığıyla değil doğrudan 'ProjectReference' aracılığıyla başvurulmalıdır. diff --git a/src/Build/Resources/xlf/Strings.zh-Hans.xlf b/src/Build/Resources/xlf/Strings.zh-Hans.xlf index c26a7049d4f..7857453e19a 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hans.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + 项目 {0} 引用项目 {1} 的输出。引用的路径: {2}。应转而使用 ProjectReference。 A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + 不得通过 "Reference" 引用项目的输出来引用项目,而是应通过 "ProjectReference" 直接引用。 diff --git a/src/Build/Resources/xlf/Strings.zh-Hant.xlf b/src/Build/Resources/xlf/Strings.zh-Hant.xlf index f007b349550..6e819e34aee 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hant.xlf @@ -173,12 +173,12 @@ Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. - Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + 專案 {0} 會參照專案 {1} 的輸出。參照的路徑: {2}。應該改用 ProjectReference。 A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. - A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'. + 專案不應透過 'Reference' 來參照其輸出,而應直接透過 'ProjectReference'。 From bc2ad7fdf30ec404c4bc11cdc6d1002d988ee4a1 Mon Sep 17 00:00:00 2001 From: Jan Krivanek Date: Wed, 27 Nov 2024 09:44:28 +0100 Subject: [PATCH 3/7] EmbeddedResource Culture Check (#11023) * in progress work * Initial version of the Check * Add check documentation * Fix analyzers * Make the check report same extension as the AssighCulture task would * Reflect PR comments --- documentation/specs/BuildCheck/Codes.md | 26 +++- .../Checks/EmbeddedResourceCheck.cs | 115 +++++++++++++++++ .../BuildCheckManagerProvider.cs | 3 +- src/Build/Resources/Strings.resx | 8 ++ src/Build/Resources/xlf/Strings.cs.xlf | 10 ++ src/Build/Resources/xlf/Strings.de.xlf | 10 ++ src/Build/Resources/xlf/Strings.es.xlf | 10 ++ src/Build/Resources/xlf/Strings.fr.xlf | 10 ++ src/Build/Resources/xlf/Strings.it.xlf | 10 ++ src/Build/Resources/xlf/Strings.ja.xlf | 10 ++ src/Build/Resources/xlf/Strings.ko.xlf | 10 ++ src/Build/Resources/xlf/Strings.pl.xlf | 10 ++ src/Build/Resources/xlf/Strings.pt-BR.xlf | 10 ++ src/Build/Resources/xlf/Strings.ru.xlf | 10 ++ src/Build/Resources/xlf/Strings.tr.xlf | 10 ++ src/Build/Resources/xlf/Strings.zh-Hans.xlf | 10 ++ src/Build/Resources/xlf/Strings.zh-Hant.xlf | 10 ++ src/BuildCheck.UnitTests/EndToEndTests.cs | 108 +++++++++++++++- ...icrosoft.Build.BuildCheck.UnitTests.csproj | 4 + .../EntryProject/EntryProject.csproj | 13 ++ .../ReferencedProject.csproj | 31 +++++ .../ReferencedProject/Resource1.en.resx | 120 ++++++++++++++++++ .../ReferencedProject/Resource1.resx | 120 ++++++++++++++++++ src/Shared/StringExtensions.cs | 17 +++ ...Microsoft.Build.Utilities.UnitTests.csproj | 1 + 25 files changed, 691 insertions(+), 5 deletions(-) create mode 100644 src/Build/BuildCheck/Checks/EmbeddedResourceCheck.cs create mode 100644 src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/EntryProject/EntryProject.csproj create mode 100644 src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/ReferencedProject.csproj create mode 100644 src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/Resource1.en.resx create mode 100644 src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/Resource1.resx diff --git a/documentation/specs/BuildCheck/Codes.md b/documentation/specs/BuildCheck/Codes.md index 58b25712ae3..d2a518cedf6 100644 --- a/documentation/specs/BuildCheck/Codes.md +++ b/documentation/specs/BuildCheck/Codes.md @@ -4,15 +4,18 @@ Report codes are chosen to conform to suggested guidelines. Those guidelines are | Diagnostic Code | Default Severity | Default Scope | Available from SDK | Reason | |:-----|-------|-------|-------|----------| -| [BC0101](#bc0101---shared-output-path) | Warning | Project | 9.0.100 | Shared output path. | -| [BC0102](#bc0102---double-writes) | Warning | Project | 9.0.100 | Double writes. | +| [BC0101](#bc0101---shared-output-path) | Warning | N/A | 9.0.100 | Shared output path. | +| [BC0102](#bc0102---double-writes) | Warning | N/A | 9.0.100 | Double writes. | | [BC0103](#bc0103---used-environment-variable) | Suggestion | Project | 9.0.100 | Used environment variable. | -| [BC0104](#bc0104---projectreference-is-preferred-to-reference) | Warning | Project | 9.0.200 | ProjectReference is preferred to Reference. | +| [BC0104](#bc0104---projectreference-is-preferred-to-reference) | Warning | N/A | 9.0.200 | ProjectReference is preferred to Reference. | +| [BC0105](#bc0105---embeddedresource-should-specify-culture-metadata) | Warning | N/A | 9.0.200 | Culture specific EmbeddedResource should specify Culture metadata. | | [BC0201](#bc0201---usage-of-undefined-property) | Warning | Project | 9.0.100 | Usage of undefined property. | | [BC0202](#bc0202---property-first-declared-after-it-was-used) | Warning | Project | 9.0.100 | Property first declared after it was used. | | [BC0203](#bc0203----property-declared-but-never-used) | Suggestion | Project | 9.0.100 | Property declared but never used. | +Note: What does the 'N/A' scope mean? The scope of checks are only applicable and configurable in cases where evaluation-time data are being used and the source of the data is determinable and available. Otherwise the scope of whole build is always checked. + To enable verbose logging in order to troubleshoot issue(s), enable [binary logging](https://github.com/dotnet/msbuild/blob/main/documentation/wiki/Binary-Log.md#msbuild-binary-log-overview) _Cmd:_ @@ -58,6 +61,23 @@ It is not recommended to reference project outputs. Such practice leads to losin If you need to achieve more advanced dependency behavior - check [Controlling Dependencies Behavior](https://github.com/dotnet/msbuild/blob/main/documentation/wiki/Controlling-Dependencies-Behavior.md) document. If neither suits your needs - then you might need to disable this check for your build or for particular projects. + +## BC0105 - EmbeddedResource should specify Culture metadata. + +"It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation." + +[`EmbeddedResource` item](https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-items#embeddedresource) has a `Culture` and `WithCulture` metadata that are strongly recommended to be used - to prevent MSBuild to need to 'guess' the culture from the file extension - which may be dependent on the current OS/Runtime available cultures and hence it can lead to nondeterministic build. + +Examples: + * `` This indicates the culture to the MSBuild engine and the culture will be respected. No diagnostic (warning) is issued ([see below for exceptions](#RespectAlreadyAssignedItemCulture)). + * `` This indicates to the MSBuild engine that the file is culture neutral and the extension should not be treated as culture indicator. No diagnostic (warning) is issued. + * `` MSBuild infers the culture from the extra extension ('xyz') and if it is known to [`System.Globalization.CultureInfo`](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo) it is being used as the resource culture. The `BC0105` diagnostic is emitted (if BuildCheck is enabled and BC0105 is not disabled) + * `` MSBuild infers that the resource is culture neutral. No diagnostic (warning) is issued. + + +**Note:** In Full Framework version of MSBuild (msbuild.exe, Visual Studio) and in .NET SDK prior 9.0 a global or project specific property `RespectAlreadyAssignedItemCulture` needs to be set to `'true'` in order for the explicit `Culture` metadata to be respected. Otherwise the explicit culture will be overwritten by MSBuild engine and if different from the extension - a `MSB3002` warning is emitted (`"MSB3002: Explicitly set culture "{0}" for item "{1}" was overwritten with inferred culture "{2}", because 'RespectAlreadyAssignedItemCulture' property was not set."`) + + ## BC0201 - Usage of undefined property. diff --git a/src/Build/BuildCheck/Checks/EmbeddedResourceCheck.cs b/src/Build/BuildCheck/Checks/EmbeddedResourceCheck.cs new file mode 100644 index 00000000000..73c7e6af9ed --- /dev/null +++ b/src/Build/BuildCheck/Checks/EmbeddedResourceCheck.cs @@ -0,0 +1,115 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Collections.Generic; +using Microsoft.Build.Collections; +using Microsoft.Build.Construction; +using Microsoft.Build.Framework; +using Microsoft.Build.Shared; + +namespace Microsoft.Build.Experimental.BuildCheck.Checks; +internal class EmbeddedResourceCheck : Check +{ + private const string RuleId = "BC0105"; + public static CheckRule SupportedRule = new CheckRule(RuleId, "EmbeddedResourceCulture", + ResourceUtilities.GetResourceString("BuildCheck_BC0105_Title")!, + ResourceUtilities.GetResourceString("BuildCheck_BC0105_MessageFmt")!, + new CheckConfiguration() { RuleId = RuleId, Severity = CheckResultSeverity.Warning }); + + public override string FriendlyName => "MSBuild.EmbeddedResourceCulture"; + + public override IReadOnlyList SupportedRules { get; } = [SupportedRule]; + + public override void Initialize(ConfigurationContext configurationContext) + { + /* This is it - no custom configuration */ + } + + public override void RegisterActions(IBuildCheckRegistrationContext registrationContext) + { + registrationContext.RegisterEvaluatedItemsAction(EvaluatedItemsAction); + } + + internal override bool IsBuiltIn => true; + + private readonly HashSet _projects = new(MSBuildNameIgnoreCaseComparer.Default); + + private void EvaluatedItemsAction(BuildCheckDataContext context) + { + // Deduplication + if (!_projects.Add(context.Data.ProjectFilePath)) + { + return; + } + + foreach (ItemData itemData in context.Data.EnumerateItemsOfType("EmbeddedResource")) + { + string evaluatedEmbedItem = itemData.EvaluatedInclude; + bool hasDoubleExtension = HasDoubleExtension(evaluatedEmbedItem); + + if (!hasDoubleExtension) + { + continue; + } + + bool hasNeededMetadata = false; + foreach (KeyValuePair keyValuePair in itemData.EnumerateMetadata()) + { + if (MSBuildNameIgnoreCaseComparer.Default.Equals(keyValuePair.Key, ItemMetadataNames.culture)) + { + hasNeededMetadata = true; + break; + } + + if (MSBuildNameIgnoreCaseComparer.Default.Equals(keyValuePair.Key, ItemMetadataNames.withCulture) && + keyValuePair.Value.IsMSBuildFalseString()) + { + hasNeededMetadata = true; + break; + } + } + + if (!hasNeededMetadata) + { + context.ReportResult(BuildCheckResult.Create( + SupportedRule, + // Populating precise location tracked via https://github.com/orgs/dotnet/projects/373/views/1?pane=issue&itemId=58661732 + ElementLocation.EmptyLocation, + Path.GetFileName(context.Data.ProjectFilePath), + evaluatedEmbedItem, + GetSupposedCultureExtension(evaluatedEmbedItem))); + } + } + } + + private static bool HasDoubleExtension(string s) + { + const char extensionSeparator = '.'; + int firstIndex; + return + !string.IsNullOrEmpty(s) && + (firstIndex = s.IndexOf(extensionSeparator)) > -1 && + // We need at least 2 chars for this extension - separator and one char of extension, + // so next extension can start closest 2 chars from this one + // (this is to grace handle double dot - which is not double extension) + firstIndex + 2 <= s.Length && + s.IndexOf(extensionSeparator, firstIndex + 2) > -1; + } + + /// + /// Returns the extension that is supposed to implicitly denote the culture. + /// This is mimicking the behavior of Microsoft.Build.Tasks.Culture.GetItemCultureInfo + /// + private string GetSupposedCultureExtension(string s) + { + // If the item is defined as "Strings.en-US.resx", then we want to arrive to 'en-US' + + string extension = Path.GetExtension(Path.GetFileNameWithoutExtension(s)); + if (extension.Length > 1) + { + extension = extension.Substring(1); + } + return extension; + } +} diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs index 93107640538..824e7983143 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs @@ -148,7 +148,8 @@ internal readonly record struct BuiltInCheckFactory( new BuiltInCheckFactory([SharedOutputPathCheck.SupportedRule.Id], SharedOutputPathCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct), new BuiltInCheckFactory([PreferProjectReferenceCheck.SupportedRule.Id], PreferProjectReferenceCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct), new BuiltInCheckFactory([DoubleWritesCheck.SupportedRule.Id], DoubleWritesCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct), - new BuiltInCheckFactory([NoEnvironmentVariablePropertyCheck.SupportedRule.Id], NoEnvironmentVariablePropertyCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct) + new BuiltInCheckFactory([NoEnvironmentVariablePropertyCheck.SupportedRule.Id], NoEnvironmentVariablePropertyCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct), + new BuiltInCheckFactory([EmbeddedResourceCheck.SupportedRule.Id], EmbeddedResourceCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct), ], // BuildCheckDataSource.Execution diff --git a/src/Build/Resources/Strings.resx b/src/Build/Resources/Strings.resx index 3fe987a5066..2fae26dae65 100644 --- a/src/Build/Resources/Strings.resx +++ b/src/Build/Resources/Strings.resx @@ -2174,6 +2174,14 @@ Utilization: {0} Average Utilization: {1:###.0} Project {0} references output of a project {1}. Referenced path: {2}. ProjectReference should be used instead. + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + A property that is accessed should be declared first. diff --git a/src/Build/Resources/xlf/Strings.cs.xlf b/src/Build/Resources/xlf/Strings.cs.xlf index ff12e0468af..bc75b630e00 100644 --- a/src/Build/Resources/xlf/Strings.cs.xlf +++ b/src/Build/Resources/xlf/Strings.cs.xlf @@ -181,6 +181,16 @@ Na projekt by se nemělo odkazovat přes Reference na jeho výstup, ale přímo přes ProjectReference. + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. K vlastnosti: {0} bylo přistupováno, ale nebyla nikdy inicializována. diff --git a/src/Build/Resources/xlf/Strings.de.xlf b/src/Build/Resources/xlf/Strings.de.xlf index 47fa3acb9b5..b3788cf3d57 100644 --- a/src/Build/Resources/xlf/Strings.de.xlf +++ b/src/Build/Resources/xlf/Strings.de.xlf @@ -181,6 +181,16 @@ Auf ein Projekt darf nicht über "Reference" auf seine Ausgabe verwiesen werden, sondern direkt über "ProjectReference". + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. Auf die Eigenschaft „{0}“ wurde zugegriffen, sie wurde jedoch nie initialisiert. diff --git a/src/Build/Resources/xlf/Strings.es.xlf b/src/Build/Resources/xlf/Strings.es.xlf index b2cf227eb21..88418d418d2 100644 --- a/src/Build/Resources/xlf/Strings.es.xlf +++ b/src/Build/Resources/xlf/Strings.es.xlf @@ -181,6 +181,16 @@ No se debe hacer referencia a un proyecto a través de "Reference" a su salida, sino directamente a través de "ProjectReference". + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. Propiedad: se obtuvo acceso a "{0}", pero nunca se inicializó. diff --git a/src/Build/Resources/xlf/Strings.fr.xlf b/src/Build/Resources/xlf/Strings.fr.xlf index 80df3b188af..04314b909f1 100644 --- a/src/Build/Resources/xlf/Strings.fr.xlf +++ b/src/Build/Resources/xlf/Strings.fr.xlf @@ -181,6 +181,16 @@ Un projet ne doit pas être référencé via « Reference » à sa sortie, mais directement via « ProjectReference ». + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. Propriété : « {0} » a été consultée, mais elle n'a jamais été initialisée. diff --git a/src/Build/Resources/xlf/Strings.it.xlf b/src/Build/Resources/xlf/Strings.it.xlf index 7c1c3bf7557..7c6adae56d1 100644 --- a/src/Build/Resources/xlf/Strings.it.xlf +++ b/src/Build/Resources/xlf/Strings.it.xlf @@ -181,6 +181,16 @@ Un progetto non può fare riferimento al relativo output tramite 'Reference', ma direttamente tramite 'ProjectReference'. + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. È stato eseguito l'accesso alla proprietà '{0}', ma non è mai stata inizializzata. diff --git a/src/Build/Resources/xlf/Strings.ja.xlf b/src/Build/Resources/xlf/Strings.ja.xlf index c2c57270135..5f828d7124b 100644 --- a/src/Build/Resources/xlf/Strings.ja.xlf +++ b/src/Build/Resources/xlf/Strings.ja.xlf @@ -181,6 +181,16 @@ プロジェクトは、出力に対する 'Reference' を介して参照するのではなく、'ProjectReference' を介して直接参照する必要があります。 + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. プロパティ: '{0}' にアクセスしましたが、初期化されませんでした。 diff --git a/src/Build/Resources/xlf/Strings.ko.xlf b/src/Build/Resources/xlf/Strings.ko.xlf index 2649c525183..1d13a250913 100644 --- a/src/Build/Resources/xlf/Strings.ko.xlf +++ b/src/Build/Resources/xlf/Strings.ko.xlf @@ -181,6 +181,16 @@ 프로젝트는 ''Reference''를 통해 출력을 참조하지 말고 ''ProjectReference''를 통해 직접 참조해야 합니다. + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. 속성: '{0}'에 액세스했지만 초기화되지 않았습니다. diff --git a/src/Build/Resources/xlf/Strings.pl.xlf b/src/Build/Resources/xlf/Strings.pl.xlf index 746b03ca198..2477e49d045 100644 --- a/src/Build/Resources/xlf/Strings.pl.xlf +++ b/src/Build/Resources/xlf/Strings.pl.xlf @@ -181,6 +181,16 @@ Do projektu nie należy odwoływać się poprzez opcję „Odwołanie” do jego danych wyjściowych, ale raczej bezpośrednio poprzez opcję „Odwołanie do projektu”. + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. Właściwość: uzyskano dostęp do „{0}”, ale nigdy nie dokonano inicjacji. diff --git a/src/Build/Resources/xlf/Strings.pt-BR.xlf b/src/Build/Resources/xlf/Strings.pt-BR.xlf index 2173625f9c1..23b7eff2bb2 100644 --- a/src/Build/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Build/Resources/xlf/Strings.pt-BR.xlf @@ -181,6 +181,16 @@ Um projeto não deve ser referenciado por meio de "Referência" à sua saída, mas diretamente por meio de "ProjectReference". + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. Propriedade: "{0}" foi acessada, mas nunca foi inicializada. diff --git a/src/Build/Resources/xlf/Strings.ru.xlf b/src/Build/Resources/xlf/Strings.ru.xlf index dd8154f048a..a10fa1e92fb 100644 --- a/src/Build/Resources/xlf/Strings.ru.xlf +++ b/src/Build/Resources/xlf/Strings.ru.xlf @@ -181,6 +181,16 @@ На проект следует ссылаться не с помощью параметра "Reference" для его выходных данных, а непосредственно посредством "ProjectReference". + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. Свойство: к "{0}" получен доступ, но он не инициализирован. diff --git a/src/Build/Resources/xlf/Strings.tr.xlf b/src/Build/Resources/xlf/Strings.tr.xlf index 497a5fd2043..c3d3913867b 100644 --- a/src/Build/Resources/xlf/Strings.tr.xlf +++ b/src/Build/Resources/xlf/Strings.tr.xlf @@ -181,6 +181,16 @@ Bir projeye, çıkışına 'Reference' aracılığıyla değil doğrudan 'ProjectReference' aracılığıyla başvurulmalıdır. + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. '{0}' özelliğine erişildi, ancak hiç başlatılmadı. diff --git a/src/Build/Resources/xlf/Strings.zh-Hans.xlf b/src/Build/Resources/xlf/Strings.zh-Hans.xlf index 7857453e19a..9ee0178a376 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hans.xlf @@ -181,6 +181,16 @@ 不得通过 "Reference" 引用项目的输出来引用项目,而是应通过 "ProjectReference" 直接引用。 + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. 已访问属性“{0}”,但从未将其初始化过。 diff --git a/src/Build/Resources/xlf/Strings.zh-Hant.xlf b/src/Build/Resources/xlf/Strings.zh-Hant.xlf index 6e819e34aee..7de56db9590 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hant.xlf @@ -181,6 +181,16 @@ 專案不應透過 'Reference' 來參照其輸出,而應直接透過 'ProjectReference'。 + + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Terms in quotes are not to be translated. + + + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Terms in quotes are not to be translated. + Property: '{0}' was accessed, but it was never initialized. 已存取屬性: '{0}',但從未初始化。 diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index 93723e17b4c..8b240e10c76 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.Json.Nodes; using System.Text.RegularExpressions; using System.Xml; using Microsoft.Build.Experimental.BuildCheck; @@ -63,6 +64,112 @@ public void PropertiesUsageAnalyzerTest(bool buildInOutOfProcessNode) Regex.Matches(output, "BC0203 .* Property").Count.ShouldBe(2); } + // + + [Theory] + [InlineData( + "cs", + "cs", + """""", + "warning BC0105: .* 'Resource1\\.cs\\.resx'")] + // Following tests are prepared after the EmbeddedCulture handling fix is merged: https://github.com/dotnet/msbuild/pull/11000 + ////[InlineData( + //// "xyz", + //// "xyz", + //// """""", + //// "warning BC0105: .* 'Resource1\\.xyz\\.resx'")] + ////[InlineData( + //// "xyz", + //// "zyx", + //// """""", + //// "")] + public void EmbeddedResourceCheckTest(string culture, string resourceExtension, string resourceElement, string expectedDiagnostic) + { + EmbedResourceTestOutput output = RunEmbeddedResourceTest(resourceElement, resourceExtension); + + // each finding should be found just once - but reported twice, due to summary + if (!string.IsNullOrEmpty(expectedDiagnostic)) + { + Regex.Matches(output.LogOutput, expectedDiagnostic).Count.ShouldBe(2); + } + + AssertHasResourceForCulture("en"); + AssertHasResourceForCulture(culture); + output.DepsJsonResources.Count.ShouldBe(2); + + void AssertHasResourceForCulture(string culture) + { + KeyValuePair resource = output.DepsJsonResources.FirstOrDefault( + o => o.Value?["locale"]?.ToString().Equals(culture, StringComparison.Ordinal) ?? false); + resource.Equals(default(KeyValuePair)).ShouldBe(false, + $"Resource for culture {culture} was not found in deps.json:{Environment.NewLine}{output.DepsJsonResources.ToString()}"); + + resource.Key.ShouldBeEquivalentTo($"{culture}/ReferencedProject.resources.dll", + $"Unexpected resource for culture {culture} was found in deps.json:{Environment.NewLine}{output.DepsJsonResources.ToString()}"); + } + } + + private readonly record struct EmbedResourceTestOutput(String LogOutput, JsonObject DepsJsonResources); + + private EmbedResourceTestOutput RunEmbeddedResourceTest(string resourceXmlToAdd, string resourceExtension) + { + string testAssetsFolderName = "EmbeddedResourceTest"; + const string entryProjectName = "EntryProject"; + const string referencedProjectName = "ReferencedProject"; + const string templateToReplace = "###EmbeddedResourceToAdd"; + TransientTestFolder workFolder = _env.CreateFolder(createFolder: true); + + CopyFilesRecursively(Path.Combine(TestAssetsRootPath, testAssetsFolderName), workFolder.Path); + ReplaceStringInFile(Path.Combine(workFolder.Path, referencedProjectName, $"{referencedProjectName}.csproj"), + templateToReplace, resourceXmlToAdd); + File.Copy( + Path.Combine(workFolder.Path, referencedProjectName, "Resource1.resx"), + Path.Combine(workFolder.Path, referencedProjectName, $"Resource1.{resourceExtension}.resx")); + + _env.SetCurrentDirectory(Path.Combine(workFolder.Path, entryProjectName)); + + string output = RunnerUtilities.ExecBootstrapedMSBuild("-check -restore", out bool success); + _env.Output.WriteLine(output); + _env.Output.WriteLine("========================="); + success.ShouldBeTrue(); + + string[] depsFiles = Directory.GetFiles(Path.Combine(workFolder.Path, entryProjectName), $"{entryProjectName}.deps.json", SearchOption.AllDirectories); + depsFiles.Length.ShouldBe(1); + + JsonNode? depsJson = JsonObject.Parse(File.ReadAllText(depsFiles[0])); + + depsJson.ShouldNotBeNull("Valid deps.json file expected"); + + var resources = depsJson!["targets"]?.AsObject().First().Value?[$"{referencedProjectName}/1.0.0"]?["resources"]?.AsObject(); + + resources.ShouldNotBeNull("Expected deps.json with 'resources' section"); + + return new(output, resources); + + void ReplaceStringInFile(string filePath, string original, string replacement) + { + File.Exists(filePath).ShouldBeTrue($"File {filePath} expected to exist."); + string text = File.ReadAllText(filePath); + text = text.Replace(original, replacement); + File.WriteAllText(filePath, text); + } + } + + private static void CopyFilesRecursively(string sourcePath, string targetPath) + { + // First Create all directories + foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories)) + { + Directory.CreateDirectory(dirPath.Replace(sourcePath, targetPath)); + } + + // Then copy all the files & Replaces any files with the same name + foreach (string newPath in Directory.GetFiles(sourcePath, "*", SearchOption.AllDirectories)) + { + File.Copy(newPath, newPath.Replace(sourcePath, targetPath), true); + } + } + [Theory] [InlineData(true, true)] @@ -640,7 +747,6 @@ private void PrepareSampleProjectsAndConfig( _env.SetCurrentDirectory(Path.GetDirectoryName(projectFile.Path)); _env.SetEnvironmentVariable("MSBUILDNOINPROCNODE", buildInOutOfProcessNode ? "1" : "0"); - _env.SetEnvironmentVariable("MSBUILDLOGPROPERTIESANDITEMSAFTEREVALUATION", "1"); // Needed for testing check BC0103 _env.SetEnvironmentVariable("TestFromTarget", "FromTarget"); diff --git a/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj b/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj index 27bf2a1542b..92e73377603 100644 --- a/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj +++ b/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj @@ -46,4 +46,8 @@ + + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/EntryProject/EntryProject.csproj b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/EntryProject/EntryProject.csproj new file mode 100644 index 00000000000..1ac36d043de --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/EntryProject/EntryProject.csproj @@ -0,0 +1,13 @@ + + + + net9.0 + enable + enable + + + + + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/ReferencedProject.csproj b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/ReferencedProject.csproj new file mode 100644 index 00000000000..5191394acfe --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/ReferencedProject.csproj @@ -0,0 +1,31 @@ + + + + net9.0 + enable + enable + + + + + True + True + Resource1.resx + + + + + True + + + + + + + en + Test.en.resources + + ###EmbeddedResourceToAdd + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/Resource1.en.resx b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/Resource1.en.resx new file mode 100644 index 00000000000..1af7de150c9 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/Resource1.en.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/Resource1.resx b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/Resource1.resx new file mode 100644 index 00000000000..1af7de150c9 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/Resource1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Shared/StringExtensions.cs b/src/Shared/StringExtensions.cs index 7f7c41f8ebc..6ca90bbf3d1 100644 --- a/src/Shared/StringExtensions.cs +++ b/src/Shared/StringExtensions.cs @@ -92,5 +92,22 @@ public static void WriteLine(this TextWriter writer, ReadOnlySpan buffer) writer.WriteLine(buffer.ToString()); } #endif + + /// + /// Converts a string to a bool. We consider "true/false", "on/off", and + /// "yes/no" to be valid boolean representations in the XML. The '!' prefix for negation is allowed as well. + /// Unrecognized values lead to exception + /// + /// Thrown when given argument is unrecognized MSBuild boolean string. + public static bool IsMSBuildTrueString(this string msbuildString) => + ConversionUtilities.ConvertStringToBool(msbuildString, nullOrWhitespaceIsFalse: true); + + /// + /// Converts a string to a bool. We consider "true/false", "on/off", and + /// "yes/no" to be valid boolean representations in the XML. The '!' prefix for negation is allowed as well. + /// Unrecognized values lead to exception + /// + /// Thrown when given argument is unrecognized MSBuild boolean string. + public static bool IsMSBuildFalseString(this string msbuildString) => !IsMSBuildTrueString(msbuildString); } } diff --git a/src/Utilities.UnitTests/Microsoft.Build.Utilities.UnitTests.csproj b/src/Utilities.UnitTests/Microsoft.Build.Utilities.UnitTests.csproj index 3f86257bcfc..e29bd389537 100644 --- a/src/Utilities.UnitTests/Microsoft.Build.Utilities.UnitTests.csproj +++ b/src/Utilities.UnitTests/Microsoft.Build.Utilities.UnitTests.csproj @@ -29,6 +29,7 @@ + NativeMethods.cs From 04ef516f89ee6b5ac9c3e8137248b52391b0023f Mon Sep 17 00:00:00 2001 From: Jan Krivanek Date: Thu, 28 Nov 2024 16:39:36 +0100 Subject: [PATCH 4/7] Support custom culture in RAR (#11000) * Support custom culture * Add ChangeWave info * Warn on unintended culture overwrite * Fix the warning call * Add and fix unittests * Apply PR comments --- documentation/wiki/ChangeWaves.md | 1 + src/BuildCheck.UnitTests/EndToEndTests.cs | 100 +++++++++++++----- .../ReferencedProject.csproj | 5 +- src/Framework/StringUtils.cs | 20 ++++ .../AssemblyDependency/ReferenceTable.cs | 3 +- src/Tasks/AssignCulture.cs | 15 +++ src/Tasks/CreateCSharpManifestResourceName.cs | 22 +++- .../CreateVisualBasicManifestResourceName.cs | 23 +++- src/Tasks/Resources/Strings.resx | 7 ++ src/Tasks/Resources/xlf/Strings.cs.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.de.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.es.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.fr.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.it.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.ja.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.ko.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.pl.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.pt-BR.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.ru.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.tr.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.zh-Hans.xlf | 8 ++ src/Tasks/Resources/xlf/Strings.zh-Hant.xlf | 8 ++ 22 files changed, 263 insertions(+), 37 deletions(-) diff --git a/documentation/wiki/ChangeWaves.md b/documentation/wiki/ChangeWaves.md index 5ce6ed3dc8b..f90568b743e 100644 --- a/documentation/wiki/ChangeWaves.md +++ b/documentation/wiki/ChangeWaves.md @@ -26,6 +26,7 @@ A wave of features is set to "rotate out" (i.e. become standard functionality) t ### 17.14 - [.SLNX support - use the new parser for .sln and .slnx](https://github.com/dotnet/msbuild/pull/10836) - [TreatWarningsAsErrors, WarningsAsMessages, WarningsAsErrors, WarningsNotAsErrors are now supported on the engine side of MSBuild](https://github.com/dotnet/msbuild/pull/10942) +- [Support custom culture in RAR](https://github.com/dotnet/msbuild/pull/11000) ### 17.12 - [Log TaskParameterEvent for scalar parameters](https://github.com/dotnet/msbuild/pull/9908) diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index 8b240e10c76..6979d98e114 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -64,54 +64,102 @@ public void PropertiesUsageAnalyzerTest(bool buildInOutOfProcessNode) Regex.Matches(output, "BC0203 .* Property").Count.ShouldBe(2); } - // - [Theory] + // The culture is not set explicitly, but the extension is a known culture + // - a buildcheck warning will occur, but otherwise works [InlineData( "cs", "cs", """""", - "warning BC0105: .* 'Resource1\\.cs\\.resx'")] - // Following tests are prepared after the EmbeddedCulture handling fix is merged: https://github.com/dotnet/msbuild/pull/11000 - ////[InlineData( - //// "xyz", - //// "xyz", - //// """""", - //// "warning BC0105: .* 'Resource1\\.xyz\\.resx'")] - ////[InlineData( - //// "xyz", - //// "zyx", - //// """""", - //// "")] - public void EmbeddedResourceCheckTest(string culture, string resourceExtension, string resourceElement, string expectedDiagnostic) + false, + "warning BC0105: .* 'Resource1\\.cs\\.resx'", + true)] + // The culture is not set explicitly, and is not a known culture + // - a buildcheck warning will occur, and resource is not recognized as culture specific - won't be copied around + [InlineData( + "xyz", + "xyz", + """""", + false, + "warning BC0105: .* 'Resource1\\.xyz\\.resx'", + false)] + // The culture is explicitly set, and it is not a known culture, but $(RespectAlreadyAssignedItemCulture) is set to true + // - no warning will occur, and resource is recognized as culture specific - and copied around + [InlineData( + "xyz", + "xyz", + """""", + true, + "", + true)] + // The culture is explicitly set, and it is not a known culture and $(RespectAlreadyAssignedItemCulture) is not set to true + // - so culture is overwritten, and resource is not recognized as culture specific - won't be copied around + [InlineData( + "xyz", + "zyx", + """""", + false, + "warning MSB3002: Explicitly set culture .* was overwritten", + false)] + // The culture is explicitly set, and it is not a known culture, but $(RespectAlreadyAssignedItemCulture) is set to true + // - no warning will occur, and resource is recognized as culture specific - and copied around + [InlineData( + "xyz", + "zyx", + """""", + true, + "", + true)] + public void EmbeddedResourceCheckTest( + string culture, + string resourceExtension, + string resourceElement, + bool respectAssignedCulturePropSet, + string expectedDiagnostic, + bool resourceExpectedToBeRecognizedAsSatelite) { - EmbedResourceTestOutput output = RunEmbeddedResourceTest(resourceElement, resourceExtension); + EmbedResourceTestOutput output = RunEmbeddedResourceTest(resourceElement, resourceExtension, respectAssignedCulturePropSet); + int expectedWarningsCount = 0; // each finding should be found just once - but reported twice, due to summary if (!string.IsNullOrEmpty(expectedDiagnostic)) { Regex.Matches(output.LogOutput, expectedDiagnostic).Count.ShouldBe(2); + expectedWarningsCount = 1; } - AssertHasResourceForCulture("en"); - AssertHasResourceForCulture(culture); - output.DepsJsonResources.Count.ShouldBe(2); + AssertHasResourceForCulture("en", true); + AssertHasResourceForCulture(culture, resourceExpectedToBeRecognizedAsSatelite); + output.DepsJsonResources.Count.ShouldBe(resourceExpectedToBeRecognizedAsSatelite ? 2 : 1); + GetWarningsCount(output.LogOutput).ShouldBe(expectedWarningsCount); - void AssertHasResourceForCulture(string culture) + void AssertHasResourceForCulture(string culture, bool isResourceExpected) { KeyValuePair resource = output.DepsJsonResources.FirstOrDefault( o => o.Value?["locale"]?.ToString().Equals(culture, StringComparison.Ordinal) ?? false); - resource.Equals(default(KeyValuePair)).ShouldBe(false, - $"Resource for culture {culture} was not found in deps.json:{Environment.NewLine}{output.DepsJsonResources.ToString()}"); + // if not found - the KVP will be default + resource.Equals(default(KeyValuePair)).ShouldBe(!isResourceExpected, + $"Resource for culture {culture} was {(isResourceExpected ? "not " : "")}found in deps.json:{Environment.NewLine}{output.DepsJsonResources.ToString()}"); - resource.Key.ShouldBeEquivalentTo($"{culture}/ReferencedProject.resources.dll", - $"Unexpected resource for culture {culture} was found in deps.json:{Environment.NewLine}{output.DepsJsonResources.ToString()}"); + if (isResourceExpected) + { + resource.Key.ShouldBeEquivalentTo($"{culture}/ReferencedProject.resources.dll", + $"Unexpected resource for culture {culture} was found in deps.json:{Environment.NewLine}{output.DepsJsonResources.ToString()}"); + } + } + + int GetWarningsCount(string output) + { + Regex regex = new Regex(@"(\d+) Warning\(s\)"); + Match match = regex.Match(output); + match.Success.ShouldBeTrue("Expected Warnings section not found in the build output."); + return int.Parse(match.Groups[1].Value); } } private readonly record struct EmbedResourceTestOutput(String LogOutput, JsonObject DepsJsonResources); - private EmbedResourceTestOutput RunEmbeddedResourceTest(string resourceXmlToAdd, string resourceExtension) + private EmbedResourceTestOutput RunEmbeddedResourceTest(string resourceXmlToAdd, string resourceExtension, bool respectCulture) { string testAssetsFolderName = "EmbeddedResourceTest"; const string entryProjectName = "EntryProject"; @@ -128,7 +176,7 @@ private EmbedResourceTestOutput RunEmbeddedResourceTest(string resourceXmlToAdd, _env.SetCurrentDirectory(Path.Combine(workFolder.Path, entryProjectName)); - string output = RunnerUtilities.ExecBootstrapedMSBuild("-check -restore", out bool success); + string output = RunnerUtilities.ExecBootstrapedMSBuild("-check -restore /p:RespectCulture=" + (respectCulture ? "True" : "\"\""), out bool success); _env.Output.WriteLine(output); _env.Output.WriteLine("========================="); success.ShouldBeTrue(); diff --git a/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/ReferencedProject.csproj b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/ReferencedProject.csproj index 5191394acfe..3950740a4da 100644 --- a/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/ReferencedProject.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/ReferencedProject/ReferencedProject.csproj @@ -1,7 +1,8 @@ - net9.0 + + net8.0 enable enable @@ -15,7 +16,7 @@ - True + $(RespectCulture) diff --git a/src/Framework/StringUtils.cs b/src/Framework/StringUtils.cs index e5502ab7320..ad5b7bffc6f 100644 --- a/src/Framework/StringUtils.cs +++ b/src/Framework/StringUtils.cs @@ -31,4 +31,24 @@ internal static string GenerateRandomString(int length) string randomBase64String = Convert.ToBase64String(randomBytes).Replace('/', '_'); return randomBase64String.Substring(0, length); } + + /// + /// Removes last occurence of from , if present. + /// + /// String to be altered. + /// String to be removed. + /// The comparison to use for finding. + /// The original string (if no occurrences found) or a new string, with last instance of removed. + internal static string RemoveLastInstanceOf(this string fromString, string substring, StringComparison comparison = StringComparison.Ordinal) + { + int lastOccurrenceIndex = fromString.LastIndexOf(substring, comparison); + + if (lastOccurrenceIndex != -1) + { + fromString = fromString.Substring(0, lastOccurrenceIndex) + + fromString.Substring(lastOccurrenceIndex + substring.Length); + } + + return fromString; + } } diff --git a/src/Tasks/AssemblyDependency/ReferenceTable.cs b/src/Tasks/AssemblyDependency/ReferenceTable.cs index 6813f2d4ded..de1a4b26b20 100644 --- a/src/Tasks/AssemblyDependency/ReferenceTable.cs +++ b/src/Tasks/AssemblyDependency/ReferenceTable.cs @@ -971,7 +971,8 @@ private void FindSatellites( // Is there a candidate satellite in that folder? string cultureName = Path.GetFileName(subDirectory); - if (CultureInfoCache.IsValidCultureString(cultureName)) + // Custom or unknown cultures can be met as well + if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_14) || CultureInfoCache.IsValidCultureString(cultureName)) { string satelliteAssembly = Path.Combine(subDirectory, satelliteFilename); if (_fileExists(satelliteAssembly)) diff --git a/src/Tasks/AssignCulture.cs b/src/Tasks/AssignCulture.cs index d416f96b4c0..c5b39e5675c 100644 --- a/src/Tasks/AssignCulture.cs +++ b/src/Tasks/AssignCulture.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Microsoft.Build.Collections; #if DEBUG using System.Diagnostics; #endif @@ -158,6 +159,20 @@ public override bool Execute() // https://github.com/dotnet/msbuild/issues/3064 ConversionUtilities.ValidBooleanFalse(AssignedFiles[i].GetMetadata(ItemMetadataNames.withCulture))); + // The culture was explicitly specified, but not opted in via 'RespectAlreadyAssignedItemCulture' and different will be used + if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_14) && + !string.IsNullOrEmpty(existingCulture) && + !MSBuildNameIgnoreCaseComparer.Default.Equals(existingCulture, info.culture)) + { + Log.LogWarningWithCodeFromResources("AssignCulture.CultureOverwritten", + existingCulture, AssignedFiles[i].ItemSpec, info.culture); + // Remove the culture if it's not recognized + if (string.IsNullOrEmpty(info.culture)) + { + AssignedFiles[i].RemoveMetadata(ItemMetadataNames.culture); + } + } + if (!string.IsNullOrEmpty(info.culture)) { AssignedFiles[i].SetMetadata(ItemMetadataNames.culture, info.culture); diff --git a/src/Tasks/CreateCSharpManifestResourceName.cs b/src/Tasks/CreateCSharpManifestResourceName.cs index 7af1e8d5105..851865cbf8e 100644 --- a/src/Tasks/CreateCSharpManifestResourceName.cs +++ b/src/Tasks/CreateCSharpManifestResourceName.cs @@ -101,12 +101,26 @@ internal static string CreateManifestNameImpl( } dependentUponFileName = FileUtilities.FixFilePath(dependentUponFileName); - Culture.ItemCultureInfo info = Culture.GetItemCultureInfo(embeddedFileName, dependentUponFileName, treatAsCultureNeutral); + Culture.ItemCultureInfo info; - // If the item has a culture override, respect that. - if (!string.IsNullOrEmpty(culture)) + if (!string.IsNullOrEmpty(culture) && ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_14)) { - info.culture = culture; + info = new Culture.ItemCultureInfo() + { + culture = culture, + cultureNeutralFilename = + embeddedFileName.RemoveLastInstanceOf("." + culture, StringComparison.OrdinalIgnoreCase) + }; + } + else + { + info = Culture.GetItemCultureInfo(embeddedFileName, dependentUponFileName, treatAsCultureNeutral); + // If the item has a culture override, respect that. + // We need to recheck here due to changewave in condition above - after Wave17_14 removal, this should be unconditional. + if (!string.IsNullOrEmpty(culture)) + { + info.culture = culture; + } } var manifestName = StringBuilderCache.Acquire(); diff --git a/src/Tasks/CreateVisualBasicManifestResourceName.cs b/src/Tasks/CreateVisualBasicManifestResourceName.cs index b73a9a9f41d..0115685336f 100644 --- a/src/Tasks/CreateVisualBasicManifestResourceName.cs +++ b/src/Tasks/CreateVisualBasicManifestResourceName.cs @@ -99,12 +99,27 @@ internal static string CreateManifestNameImpl( embeddedFileName = fileName; } - Culture.ItemCultureInfo info = Culture.GetItemCultureInfo(embeddedFileName, dependentUponFileName, treatAsCultureNeutral); + dependentUponFileName = FileUtilities.FixFilePath(dependentUponFileName); + Culture.ItemCultureInfo info; - // If the item has a culture override, respect that. - if (!string.IsNullOrEmpty(culture)) + if (!string.IsNullOrEmpty(culture) && ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_14)) { - info.culture = culture; + info = new Culture.ItemCultureInfo() + { + culture = culture, + cultureNeutralFilename = + embeddedFileName.RemoveLastInstanceOf("." + culture, StringComparison.OrdinalIgnoreCase) + }; + } + else + { + info = Culture.GetItemCultureInfo(embeddedFileName, dependentUponFileName, treatAsCultureNeutral); + // If the item has a culture override, respect that. + // We need to recheck here due to changewave in condition above - after Wave17_14 removal, this should be unconditional. + if (!string.IsNullOrEmpty(culture)) + { + info.culture = culture; + } } var manifestName = StringBuilderCache.Acquire(); diff --git a/src/Tasks/Resources/Strings.resx b/src/Tasks/Resources/Strings.resx index 47a18ddf8a9..761ee13dfc0 100644 --- a/src/Tasks/Resources/Strings.resx +++ b/src/Tasks/Resources/Strings.resx @@ -149,6 +149,13 @@ Culture of "{0}" was assigned to file "{1}". + + MSB3002: Explicitly set culture "{0}" for item "{1}" was overwritten with inferred culture "{2}", because 'RespectAlreadyAssignedItemCulture' property was not set. + + {StrBegin="MSB3002: "} + 'RespectAlreadyAssignedItemCulture' should not be translated + + - - - %(ReferencePath.OriginalItemSpec) - - - - <_PackagesToPack Include="@(ResolvedProjectReference->'%(OutputPath)')"> - @(ResolvedProjectReference->'%(AssemblyName)') - - - - - + + - - - - <_PackagesToPack Remove="@(_PackagesToPack)" Condition="%(NuGetPackageId) == 'NETStandard.Library'" /> - <_PackagesToPack Remove="@(_PackagesToPack)" Condition="%(_PackagesToPack.IncludeInPackage) != 'true'" /> + + <_PackagesToPack Remove="@(_PackagesToPack)" Condition="'%(_PackagesToPack.IncludeInPackage)' != 'true'" /> - + @@ -37,5 +21,4 @@ - diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomCheck/CustomCheck.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomCheck/CustomCheck.csproj index fc81bc53eb5..b8481f7c7cf 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomCheck/CustomCheck.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/CustomCheck/CustomCheck.csproj @@ -9,9 +9,9 @@ - + - + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomCheck2/CustomCheck2.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomCheck2/CustomCheck2.csproj index 5d4396dea07..c5c53ea556a 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomCheck2/CustomCheck2.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/CustomCheck2/CustomCheck2.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/BuildCheck.UnitTests/TestAssets/ErrorCustomCheck/ErrorCustomCheck.csproj b/src/BuildCheck.UnitTests/TestAssets/ErrorCustomCheck/ErrorCustomCheck.csproj index 8bce5a83d8c..debf007db43 100644 --- a/src/BuildCheck.UnitTests/TestAssets/ErrorCustomCheck/ErrorCustomCheck.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/ErrorCustomCheck/ErrorCustomCheck.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/BuildCheck.UnitTests/TestAssets/InvalidCustomCheck/InvalidCustomCheck.csproj b/src/BuildCheck.UnitTests/TestAssets/InvalidCustomCheck/InvalidCustomCheck.csproj index 81c7c28efe7..ecffc920560 100644 --- a/src/BuildCheck.UnitTests/TestAssets/InvalidCustomCheck/InvalidCustomCheck.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/InvalidCustomCheck/InvalidCustomCheck.csproj @@ -9,7 +9,7 @@ - + diff --git a/template_feed/content/Microsoft.CheckTemplate/Company.CheckTemplate.csproj b/template_feed/content/Microsoft.CheckTemplate/Company.CheckTemplate.csproj index d042f74f8a1..ac2ba871161 100644 --- a/template_feed/content/Microsoft.CheckTemplate/Company.CheckTemplate.csproj +++ b/template_feed/content/Microsoft.CheckTemplate/Company.CheckTemplate.csproj @@ -12,12 +12,14 @@ - + - - + + + + From 0b397a482883a58bfe0b380c5d9d15b4b97c6d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Provazn=C3=ADk?= Date: Fri, 29 Nov 2024 11:58:25 +0100 Subject: [PATCH 6/7] Update triggers in VS insertion pipelines (#11037) --- azure-pipelines/vs-insertion.yml | 55 +++++++++++++++++++++--------- documentation/release-checklist.md | 5 +-- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/azure-pipelines/vs-insertion.yml b/azure-pipelines/vs-insertion.yml index 7e1a27f3ed7..16de6ced0f1 100644 --- a/azure-pipelines/vs-insertion.yml +++ b/azure-pipelines/vs-insertion.yml @@ -1,32 +1,46 @@ -# Create a VS insertion (DotNet-MSBuild-Trusted -> VS) from a build artifact on main or any servicing branch. +# Create a VS insertion (DotNet-MSBuild-Trusted -> VS) from a CI run on main or any servicing branch. +# To achieve insertion automation, this pipeline definition yml has to be on servicing branches and main. + + +# Runs in 3 modes: +# 1. daily main insertion from latest main CI. +# - can be disabled in the UI by adding a custom schedule for any branch. +# 2. trigger insert as a followup to a servicing CI run. +# - can be disabled in the UI by adding a custom CI trigger. +# 3. manual insertion - select manually the TargetBranch and inserted CI run. trigger: none +pr: none name: $(Date:yyyyMMdd).$(Rev:r) +schedules: + - cron: '0 3 * * 1-5' # Runs every weekday at 3AM UTC + displayName: Daily VS insertion main + branches: + include: + - main + always: false # Don't run if there are no code changes + resources: pipelines: - pipeline: 'MSBuild' project: 'DevDiv' source: 'MSBuild' + branch: main # for daily main scheduled insertion + trigger: + branches: + include: # trigger as a followup to servicing CI + - vs* repositories: - repository: 1ESPipelineTemplates type: git name: 1ESPipelineTemplates/1ESPipelineTemplates ref: refs/tags/release -schedules: - - cron: '0 3 * * *' # Runs every day at 3AM UTC - displayName: Daily VS insertion - branches: - include: - - main - - vs* - always: false # Don't run if there are no code changes - parameters: - name: TargetBranch default: auto type: string - displayName: 'Insertion Target Branch (recommended to use `auto`)' + displayName: 'Insertion Target Branch (select for manual insertion)' values: - auto - main @@ -88,6 +102,11 @@ variables: value: '$(ArtifactPackagesPath)/Microsoft.NET.StringTools*.nupkg' - name: ExternalAPIsPackagePattern value: '$(ArtifactPackagesPath)/VS.ExternalAPIs.*.nupkg' + # servicing branches until 17.12 also include Microsoft.Build.Engine and Microsoft.Build.Conversion.Core + - name: EngineIncludedProps + value: VS.ExternalAPIs.MSBuild=$(MSBuild_ExtApisPackageVersion);Microsoft.Build=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Conversion.Core=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Engine=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Framework=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Tasks.Core=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Utilities.Core=$(MicrosoftNETStringToolsPackageVersion);Microsoft.NET.StringTools=$(MicrosoftNETStringToolsPackageVersion) + - name: NoEngineProps + value: VS.ExternalAPIs.MSBuild=$(MSBuild_ExtApisPackageVersion);Microsoft.Build=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Framework=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Tasks.Core=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Utilities.Core=$(MicrosoftNETStringToolsPackageVersion);Microsoft.NET.StringTools=$(MicrosoftNETStringToolsPackageVersion) extends: template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates @@ -186,6 +205,14 @@ extends: $packageVersion = $packageFile.BaseName.TrimStart("Microsoft.NET.StringTools") Write-Host "Setting MicrosoftNETStringToolsPackageVersion to '$packageVersion'" Write-Host "##vso[task.setvariable variable=MicrosoftNETStringToolsPackageVersion]$($packageVersion)" + if ("$(InsertTargetBranch)" -in @("vs17.0", "vs17.3", "vs17.6", "vs17.8", "vs17.10", "vs17.11", "vs17.12")) + { + Write-Host "##vso[task.setvariable variable=InsertPackagePropsValues]$($EngineIncludedProps)" + } + else + { + Write-Host "##vso[task.setvariable variable=InsertPackagePropsValues]$($NoEngineProps)" + } - task: 1ES.PublishNuGet@1 displayName: 'Push MSBuild CoreXT packages' inputs: @@ -221,11 +248,7 @@ extends: TeamEmail: $(TeamEmail) TargetBranch: $(InsertTargetBranch) InsertionPayloadName: $(InsertPayloadName) - # servicing branches until 17.12 also include Microsoft.Build.Engine and Microsoft.Build.Conversion.Core - ${{ if or(eq(variables['Build.SourceBranchName'], 'vs17.0'), eq(variables['Build.SourceBranchName'], 'vs17.3'), eq(variables['Build.SourceBranchName'], 'vs17.6'), eq(variables['Build.SourceBranchName'], 'vs17.8'), eq(variables['Build.SourceBranchName'], 'vs17.10'), eq(variables['Build.SourceBranchName'], 'vs17.11'), eq(variables['Build.SourceBranchName'], 'vs17.12')) }}: - PackagePropsValues: VS.ExternalAPIs.MSBuild=$(MSBuild_ExtApisPackageVersion);Microsoft.Build=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Conversion.Core=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Engine=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Framework=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Tasks.Core=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Utilities.Core=$(MicrosoftNETStringToolsPackageVersion);Microsoft.NET.StringTools=$(MicrosoftNETStringToolsPackageVersion) - ${{ else }}: - PackagePropsValues: VS.ExternalAPIs.MSBuild=$(MSBuild_ExtApisPackageVersion);Microsoft.Build=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Framework=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Tasks.Core=$(MicrosoftNETStringToolsPackageVersion);Microsoft.Build.Utilities.Core=$(MicrosoftNETStringToolsPackageVersion);Microsoft.NET.StringTools=$(MicrosoftNETStringToolsPackageVersion) + PackagePropsValues: $(InsertPackagePropsValues) InsertionDescription: $(InsertDescription) ComponentJsonValues: $(InsertJsonValues) DefaultConfigValues: $(InsertConfigValues) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index 911c2c59a6e..fe64e8b61c2 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -14,9 +14,9 @@ ## At release time Before starting the process: - [ ] If the release is being cut more than a few days before the VS-side snap, run insertions manually OR redirect MSBuild release branch - - [ ] Disabling automated run of [MSBuild VS Insertion pipeline](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=24295) (our {{NEXT_VERSION}} builds don't have a place to go in VS yet) is done by: Edit -> ... -> Triggers -> add a schedule on a dead branch (this overrides the YAML defined once-per-day schedule). Manual pipeline run: select as input resource the inserted "MSBuild" pipeline run on branch `vs{{THIS_RELEASE_VERSION}}` and VS TargetBranch `main`. + - [ ] Disable scheduled run of [MSBuild VS Insertion pipeline](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=24295) (our {{NEXT_VERSION}} builds don't have a place to go in VS yet) by: Edit -> ... -> Triggers -> add a schedule on a dead branch (this overrides the YAML defined once-per-day schedule for main). Manual pipeline run: select as input resource the to-be-inserted "MSBuild" pipeline run on branch `vs{{THIS_RELEASE_VERSION}}` and VS TargetBranch `main`. OR - - [ ] If the release is being cut more than couple of weeks modify [YAML](https://github.com/dotnet/msbuild/tree/main/azure-pipelines/vs-insertion.yml) (and merge to affected MSBuild branches) of the [VS insertion pipeline](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=24295) so that it flows from MSBuild `vs{{THIS_RELEASE_VERSION}}` to VS `main` [in the MSBuild VS Insertion pipeline](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=24295) and keep scheduled insertions to simplify your workflow. + - [ ] If the release is being cut more than couple of weeks modify [YAML](https://github.com/dotnet/msbuild/tree/main/azure-pipelines/vs-insertion.yml) (and merge to affected MSBuild branches) of the [VS insertion pipeline](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=24295) so that it schedules insertions from MSBuild `vs{{THIS_RELEASE_VERSION}}` to VS `main`. Keep scheduled daily insertions to simplify your workflow and exclude `vs{{THIS_RELEASE_VERSION}}` from triggering insertion on each commit. ### Branching from main - [ ] If the new version's branch was created before the Visual Studio fork: fast-forward merge the correct commit (the one that is currently inserted to VS main) to the `vs{{THIS_RELEASE_VERSION}}` branch \ @@ -28,6 +28,7 @@ _(This is for the case where we create the branch too early and want it to be ba `dotnet pack MSBuild.Dev.slnf /p:ApiCompatGenerateSuppressionFile=true`. - [ ] When VS main snaps to {{THIS_RELEASE_VERSION}} and updates its version to {{NEXT_VERSION}}, modify the [MSBuild VS Insertion pipeline](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=24295) YAML so that it flows from MSBuild main to VS main. - [ ] Update AutoTargetBranch selection in the [YAML](https://github.com/dotnet/msbuild/tree/main/azure-pipelines/vs-insertion.yml) (add to parameters and make new AutoTargetBranch rule by copying it from existing ones) of the [MSBuild VS Insertion pipeline](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=24295) to insert MSBuild `vs{{THIS_RELEASE_VERSION}}` to the corresponding VS branch `rel/d{{THIS_RELEASE_VERSION}}`. + - [ ] Set scheduled insertion for main and remove exclusion of `vs{{THIS_RELEASE_VERSION}}` triggering on each commit if added earlier. - [ ] Merge {{NEXT_VERSION}} branding PR ### Adjust DARC channels and subscriptions From 3d1e2cfafd711312fc115d03eee15518d439a027 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Fri, 29 Nov 2024 04:54:28 -0800 Subject: [PATCH 7/7] Localized file check-in by OneLocBuild Task: Build definition ID 9434: Build ID 10634189 (#11046) --- src/Build/Resources/xlf/Strings.cs.xlf | 4 ++-- src/Build/Resources/xlf/Strings.fr.xlf | 4 ++-- src/Build/Resources/xlf/Strings.it.xlf | 4 ++-- src/Build/Resources/xlf/Strings.pl.xlf | 4 ++-- src/Build/Resources/xlf/Strings.pt-BR.xlf | 4 ++-- src/Build/Resources/xlf/Strings.ru.xlf | 4 ++-- src/Build/Resources/xlf/Strings.tr.xlf | 4 ++-- src/Build/Resources/xlf/Strings.zh-Hans.xlf | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Build/Resources/xlf/Strings.cs.xlf b/src/Build/Resources/xlf/Strings.cs.xlf index bc75b630e00..f365f60c21d 100644 --- a/src/Build/Resources/xlf/Strings.cs.xlf +++ b/src/Build/Resources/xlf/Strings.cs.xlf @@ -183,12 +183,12 @@ Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. - Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Projekt {0} určuje položku EmbeddedResource {1}, která má pravděpodobně příponu určující jazykovou verzi ({2}), ale nejsou zadána explicitní metadata Culture ani WithCulture=false. Terms in quotes are not to be translated. It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. - It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Doporučujeme u položky EmbeddedResource zadat explicitní metadata Culture nebo metadata WithCulture=false, aby se zabránilo chybnému nebo nedeterministickému odhadu jazykové verze. Terms in quotes are not to be translated. diff --git a/src/Build/Resources/xlf/Strings.fr.xlf b/src/Build/Resources/xlf/Strings.fr.xlf index 04314b909f1..cf96f53db33 100644 --- a/src/Build/Resources/xlf/Strings.fr.xlf +++ b/src/Build/Resources/xlf/Strings.fr.xlf @@ -183,12 +183,12 @@ Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. - Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Project {0} spécifie l’élément « EmbeddedResource »{1}« qui a éventuellement une extension de culture indiquant ( »{2}« ), mais les métadonnées explicites « Culture » et « WithCulture=false » ne sont pas spécifiées. Terms in quotes are not to be translated. It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. - It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Il est recommandé de spécifier des métadonnées 'Culture' explicites ou des métadonnées 'WithCulture=false' avec l’élément 'EmbeddedResource' afin d’éviter une estimation de culture incorrecte ou non déterministe. Terms in quotes are not to be translated. diff --git a/src/Build/Resources/xlf/Strings.it.xlf b/src/Build/Resources/xlf/Strings.it.xlf index 7c6adae56d1..83d495394f3 100644 --- a/src/Build/Resources/xlf/Strings.it.xlf +++ b/src/Build/Resources/xlf/Strings.it.xlf @@ -183,12 +183,12 @@ Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. - Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Il progetto {0} specifica l'elemento 'EmbeddedResource' '{1}', che potrebbe contenere un'estensione per la denotazione delle impostazioni cultura ('{2}'), tuttavia i metadati espliciti 'Culture' e 'WithCulture=false' non sono specificati. Terms in quotes are not to be translated. It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. - It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + È consigliabile specificare i metadati 'Culture' espliciti o i metadati 'WithCulture=false' con l'elemento 'EmbeddedResource' per evitare una stima errata o non deterministica delle impostazioni cultura. Terms in quotes are not to be translated. diff --git a/src/Build/Resources/xlf/Strings.pl.xlf b/src/Build/Resources/xlf/Strings.pl.xlf index 2477e49d045..82ae42982b7 100644 --- a/src/Build/Resources/xlf/Strings.pl.xlf +++ b/src/Build/Resources/xlf/Strings.pl.xlf @@ -183,12 +183,12 @@ Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. - Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Projekt {0} określa element „EmbeddedResource” „{1}”, który może mieć rozszerzenie oznaczające kulturę („{2}”), ale nie określono jawnych metadanych „Culture” ani „WithCulture=false”. Terms in quotes are not to be translated. It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. - It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Zaleca się określenie wyraźnych metadanych „Culture” lub metadanych „WithCulture=false” z elementem „EmbeddedResource” w celu uniknięcia błędnego lub niedeterministycznego oszacowania kultury. Terms in quotes are not to be translated. diff --git a/src/Build/Resources/xlf/Strings.pt-BR.xlf b/src/Build/Resources/xlf/Strings.pt-BR.xlf index 23b7eff2bb2..aaad42fd986 100644 --- a/src/Build/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Build/Resources/xlf/Strings.pt-BR.xlf @@ -183,12 +183,12 @@ Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. - Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + O projeto {0} especifica o item 'EmbeddedResource' '{1}', que possivelmente tem uma cultura que indica extensão ('{2}'), mas os metadados 'Culture' e 'WithCulture=false' explícitos não são especificados. Terms in quotes are not to be translated. It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. - It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + É recomendável especificar metadados explícitos de 'Culture' ou metadados 'WithCulture=false' com o item 'EmbeddedResource' para evitar estimativas de cultura incorretas ou não determinísticas. Terms in quotes are not to be translated. diff --git a/src/Build/Resources/xlf/Strings.ru.xlf b/src/Build/Resources/xlf/Strings.ru.xlf index a10fa1e92fb..16fc0d74ce5 100644 --- a/src/Build/Resources/xlf/Strings.ru.xlf +++ b/src/Build/Resources/xlf/Strings.ru.xlf @@ -183,12 +183,12 @@ Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. - Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + Проект {0} указывает элемент "EmbeddedResource" "{1}", который может содержать расширение для обозначения языка и региональных параметров ("{2}"), но явные метаданные "Culture" или "WithCulture=false" не указаны. Terms in quotes are not to be translated. It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. - It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Рекомендуется указать явные метаданные "Culture" или "WithCulture=false" с элементом "EmbeddedResource", чтобы избежать неверной или недетерминированной оценки языка и региональных параметров. Terms in quotes are not to be translated. diff --git a/src/Build/Resources/xlf/Strings.tr.xlf b/src/Build/Resources/xlf/Strings.tr.xlf index c3d3913867b..a9132ab6510 100644 --- a/src/Build/Resources/xlf/Strings.tr.xlf +++ b/src/Build/Resources/xlf/Strings.tr.xlf @@ -183,12 +183,12 @@ Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. - Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + {0} projesi büyük olasılıkla kültür belirtme uzantısı ('{2}') olan '{1}' 'EmbeddedResource' öğesini belirtiyor ancak açık 'Culture' veya 'WithCulture=false' meta verileri belirtilmedi. Terms in quotes are not to be translated. It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. - It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + Yanlış veya belirsiz kültür tahminlerini önlemek için 'EmbeddedResource' öğesiyle açık 'Culture' meta verisinin veya 'WithCulture=false' meta verisinin belirtilmesi önerilir. Terms in quotes are not to be translated. diff --git a/src/Build/Resources/xlf/Strings.zh-Hans.xlf b/src/Build/Resources/xlf/Strings.zh-Hans.xlf index 9ee0178a376..a3a86e7c8ec 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hans.xlf @@ -183,12 +183,12 @@ Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. - Project {0} specifies 'EmbeddedResource' item '{1}', that has possibly a culture denoting extension ('{2}'), but explicit 'Culture' nor 'WithCulture=false' metadata are not specified. + 项目 {0} 指定 "EmbeddedResource" 项“{1}”,该项可能有表示扩展(“{2}”)的区域性,但未指定显示 "Culture" 和 "WithCulture=false" 元数据。 Terms in quotes are not to be translated. It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. - It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation. + 建议在有 "EmbeddedResource" 项时指定显式 "Culture" 元数据或指定 "WithCulture=false" 元数据,以避免错误或不确定的区域性估计。 Terms in quotes are not to be translated.