diff --git a/SourceLink.sln b/SourceLink.sln
index 61cf926b..3e183f4c 100644
--- a/SourceLink.sln
+++ b/SourceLink.sln
@@ -53,6 +53,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.AzureD
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.AzureDevOpsServer.Git.UnitTests", "src\SourceLink.AzureDevOpsServer.Git.UnitTests\Microsoft.SourceLink.AzureDevOpsServer.Git.UnitTests.csproj", "{79371F26-FB84-408D-A4A1-B142B247C288}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.GitWeb", "src\SourceLink.GitWeb\Microsoft.SourceLink.GitWeb.csproj", "{C78DD3EF-9D20-4E00-8237-E871BB53F840}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.GitWeb.UnitTests", "src\SourceLink.GitWeb.UnitTests\Microsoft.SourceLink.GitWeb.UnitTests.csproj", "{50503A43-08C0-493B-B8CC-F368983644C1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -135,6 +139,14 @@ Global
{79371F26-FB84-408D-A4A1-B142B247C288}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79371F26-FB84-408D-A4A1-B142B247C288}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79371F26-FB84-408D-A4A1-B142B247C288}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C78DD3EF-9D20-4E00-8237-E871BB53F840}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C78DD3EF-9D20-4E00-8237-E871BB53F840}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C78DD3EF-9D20-4E00-8237-E871BB53F840}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C78DD3EF-9D20-4E00-8237-E871BB53F840}.Release|Any CPU.Build.0 = Release|Any CPU
+ {50503A43-08C0-493B-B8CC-F368983644C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {50503A43-08C0-493B-B8CC-F368983644C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {50503A43-08C0-493B-B8CC-F368983644C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {50503A43-08C0-493B-B8CC-F368983644C1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/SourceLink.GitWeb.UnitTests/GetSourceLinkUrlTests.cs b/src/SourceLink.GitWeb.UnitTests/GetSourceLinkUrlTests.cs
new file mode 100644
index 00000000..82da152f
--- /dev/null
+++ b/src/SourceLink.GitWeb.UnitTests/GetSourceLinkUrlTests.cs
@@ -0,0 +1,58 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See
+// License.txt in the project root for license information.
+using Microsoft.Build.Tasks.SourceControl;
+using TestUtilities;
+using Xunit;
+using static TestUtilities.KeyValuePairUtils;
+
+namespace Microsoft.SourceLink.GitWeb.UnitTests
+{
+ public class GetSourceLinkUrlTests
+ {
+ [Fact]
+ public void EmptyHosts()
+ {
+ var engine = new MockEngine();
+
+ var task = new GetSourceLinkUrl()
+ {
+ BuildEngine = engine,
+ SourceRoot = new MockItem("x", KVP("RepositoryUrl", "http://abc.com"), KVP("SourceControl", "git")),
+ };
+
+ bool result = task.Execute();
+
+ AssertEx.AssertEqualToleratingWhitespaceDifferences(
+ "ERROR : " + string.Format(CommonResources.AtLeastOneRepositoryHostIsRequired, "SourceLinkGitWebHost", "GitWeb"), engine.Log);
+
+ Assert.False(result);
+ }
+
+ [Theory]
+ [InlineData("", "")]
+ [InlineData("", "/")]
+ [InlineData("/", "")]
+ [InlineData("/", "/")]
+ public void BuildSourceLinkUrl(string s1, string s2)
+ {
+ var engine = new MockEngine();
+
+ var task = new GetSourceLinkUrl()
+ {
+ BuildEngine = engine,
+ SourceRoot = new MockItem("/src/", KVP("RepositoryUrl", "ssh://git@src.intranet.company.com/root_dir_name/sub_dirs/reponame.git" + s1), KVP("SourceControl", "git"), KVP("RevisionId", "0123456789abcdefABCDEF000000000000000000")),
+ Hosts = new[]
+ {
+ // NOTE: i don't know what the spec parameter is for. but for all the other
+ // tests like this for various providers it is the domain of the Repo URL.
+ new MockItem("src.intranet.company.com", KVP("ContentUrl", "https://src.intranet.company.com/gitweb" + s2)),
+ }
+ };
+
+ bool result = task.Execute();
+ AssertEx.AssertEqualToleratingWhitespaceDifferences("", engine.Log);
+ AssertEx.AreEqual("https://src.intranet.company.com/gitweb/?p=root_dir_name/sub_dirs/reponame.git;a=blob_plain;hb=0123456789abcdefABCDEF000000000000000000;f=*", task.SourceLinkUrl);
+ Assert.True(result);
+ }
+ }
+}
diff --git a/src/SourceLink.GitWeb.UnitTests/Microsoft.SourceLink.GitWeb.UnitTests.csproj b/src/SourceLink.GitWeb.UnitTests/Microsoft.SourceLink.GitWeb.UnitTests.csproj
new file mode 100644
index 00000000..16608152
--- /dev/null
+++ b/src/SourceLink.GitWeb.UnitTests/Microsoft.SourceLink.GitWeb.UnitTests.csproj
@@ -0,0 +1,9 @@
+
+
+ net461;netcoreapp2.0
+
+
+
+
+
+
diff --git a/src/SourceLink.GitWeb.UnitTests/TranslateRepositoryUrlsTests.cs b/src/SourceLink.GitWeb.UnitTests/TranslateRepositoryUrlsTests.cs
new file mode 100644
index 00000000..1e88cbb6
--- /dev/null
+++ b/src/SourceLink.GitWeb.UnitTests/TranslateRepositoryUrlsTests.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See
+// License.txt in the project root for license information.
+using System.Linq;
+using TestUtilities;
+using Xunit;
+using static TestUtilities.KeyValuePairUtils;
+
+namespace Microsoft.SourceLink.GitWeb.UnitTests
+{
+ public class TranslateRepositoryUrlsTests
+ {
+ [Fact]
+ public void Translate()
+ {
+ var engine = new MockEngine();
+
+ var task = new TranslateRepositoryUrls()
+ {
+ BuildEngine = engine,
+ RepositoryUrl = "ssh://git@src.intranet.company.com/root_dir_name/sub_dirs/reponame.git",
+ IsSingleProvider = true,
+ SourceRoots = new[]
+ {
+ new MockItem("/1/", KVP("SourceControl", "git"), KVP("ScmRepositoryUrl", "ssh://git@src.intranet.company.com/root_dir_name/sub_dirs/reponame.git")),
+ new MockItem("/2/", KVP("SourceControl", "tfvc"), KVP("ScmRepositoryUrl", "ssh://git@src.intranet.company1.com/root_dir_name/sub_dirs/reponame.git")),
+ new MockItem("/2/", KVP("SourceControl", "git"), KVP("ScmRepositoryUrl", "ssh://git@src.intranet.company1.com/root_dir_name/sub_dirs/reponame.git")),
+ new MockItem("/2/", KVP("SourceControl", "tfvc"), KVP("ScmRepositoryUrl", "ssh://git@src.intranet.company2.com/root_dir_name/sub_dirs/reponame.git")),
+ },
+ Hosts = new[]
+ {
+ new MockItem("src.intranet.company1.com")
+ }
+ };
+
+ bool result = task.Execute();
+ AssertEx.AssertEqualToleratingWhitespaceDifferences("", engine.Log);
+
+ AssertEx.AreEqual("https://src.intranet.company.com/root_dir_name/sub_dirs/reponame.git", task.TranslatedRepositoryUrl);
+
+ AssertEx.Equal(new[]
+ {
+ "https://src.intranet.company.com/root_dir_name/sub_dirs/reponame.git",
+ "ssh://git@src.intranet.company1.com/root_dir_name/sub_dirs/reponame.git",
+ "https://src.intranet.company1.com/root_dir_name/sub_dirs/reponame.git",
+ "ssh://git@src.intranet.company2.com/root_dir_name/sub_dirs/reponame.git",
+ }, task.TranslatedSourceRoots.Select(r => r.GetMetadata("ScmRepositoryUrl")));
+
+ Assert.True(result);
+ }
+ }
+}
diff --git a/src/SourceLink.GitWeb/GetSourceLinkUrl.cs b/src/SourceLink.GitWeb/GetSourceLinkUrl.cs
new file mode 100644
index 00000000..a971fc8a
--- /dev/null
+++ b/src/SourceLink.GitWeb/GetSourceLinkUrl.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See
+// License.txt in the project root for license information.
+
+using System;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Tasks.SourceControl;
+
+namespace Microsoft.SourceLink.GitWeb
+{
+ ///
+ /// The task calculates SourceLink URL for a given SourceRoot. If the SourceRoot is associated
+ /// with a git repository with a recognized domain the output
+ /// property is set to the content URL corresponding to the domain, otherwise it is set to
+ /// string "N/A".
+ ///
+ public sealed class GetSourceLinkUrl : GetSourceLinkUrlGitTask
+ {
+ protected override string HostsItemGroupName => "SourceLinkGitWebHost";
+ protected override string ProviderDisplayName => "GitWeb";
+
+ protected override string BuildSourceLinkUrl(Uri contentUri, Uri gitUri, string relativeUrl, string revisionId, ITaskItem hostItem)
+ {
+ var trimLeadingSlash = relativeUrl.TrimStart('/', '\\');
+ var trimmedContentUrl = contentUri.ToString().TrimEnd('/', '\\');
+
+ /* p = project/path
+ * a = action
+ * hb = SHA/revision
+ * f = repo file path
+ */
+ var gitwebRawUrl = $"{trimmedContentUrl}/?p={trimLeadingSlash}.git;a=blob_plain;hb={revisionId};f=*";
+ return gitwebRawUrl;
+ }
+ }
+}
diff --git a/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.csproj b/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.csproj
new file mode 100644
index 00000000..3b148c05
--- /dev/null
+++ b/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.csproj
@@ -0,0 +1,32 @@
+
+
+ net461;netcoreapp2.0
+ true
+
+
+ true
+ $(MSBuildProjectName).nuspec
+ $(OutputPath)
+
+ Generates source link for Git repositories using a GitWeb server.
+ MSBuild Tasks GitWeb source link
+ true
+
+
+
+
+
+
+
+ Microsoft.Build.Tasks.SourceControl
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.nuspec b/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.nuspec
new file mode 100644
index 00000000..3df879b5
--- /dev/null
+++ b/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.nuspec
@@ -0,0 +1,17 @@
+
+
+
+ $CommonMetadataElements$
+
+
+
+
+
+
+ $CommonFileElements$
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/TranslateRepositoryUrls.cs b/src/SourceLink.GitWeb/TranslateRepositoryUrls.cs
new file mode 100644
index 00000000..e5f34c2f
--- /dev/null
+++ b/src/SourceLink.GitWeb/TranslateRepositoryUrls.cs
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See
+// License.txt in the project root for license information.
+
+using Microsoft.Build.Tasks.SourceControl;
+
+namespace Microsoft.SourceLink.GitWeb
+{
+ public sealed class TranslateRepositoryUrls : TranslateRepositoryUrlsGitTask
+ {
+ }
+}
diff --git a/src/SourceLink.GitWeb/build/SourceLink.GitWeb.targets b/src/SourceLink.GitWeb/build/SourceLink.GitWeb.targets
new file mode 100644
index 00000000..6c0e30ad
--- /dev/null
+++ b/src/SourceLink.GitWeb/build/SourceLink.GitWeb.targets
@@ -0,0 +1,65 @@
+
+
+
+ <_SourceLinkGitWebAssemblyFile Condition="'$(MSBuildRuntimeType)' != 'Core'">$(MSBuildThisFileDirectory)..\tools\net461\Microsoft.SourceLink.GitWeb.dll
+ <_SourceLinkGitWebAssemblyFile Condition="'$(MSBuildRuntimeType)' == 'Core'">$(MSBuildThisFileDirectory)..\tools\netcoreapp2.0\Microsoft.SourceLink.GitWeb.dll
+
+
+
+
+
+
+ $(SourceLinkUrlInitializerTargets);_InitializeGitWebSourceLinkUrl
+ $(SourceControlManagerUrlTranslationTargets);TranslateGitWebUrlsInSourceControlInformation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_TranslatedSourceRoot Remove="@(_TranslatedSourceRoot)" />
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/SourceLink.GitWeb/buildMultiTargeting/SourceLink.GitWeb.targets b/src/SourceLink.GitWeb/buildMultiTargeting/SourceLink.GitWeb.targets
new file mode 100644
index 00000000..84afbc37
--- /dev/null
+++ b/src/SourceLink.GitWeb/buildMultiTargeting/SourceLink.GitWeb.targets
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/SourceLink.GitWeb/xlf/Resources.cs.xlf b/src/SourceLink.GitWeb/xlf/Resources.cs.xlf
new file mode 100644
index 00000000..0e6540e3
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.cs.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ Skupina položek {0} je prázdná. Kvůli generování zdrojového odkazu se vyžaduje alespoň jeden hostitel úložiště {1}.
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ {0} určuje neplatnou adresu URL: {1}.
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ Hodnota {0} s identitou {1} je neplatná: {2}"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ Hodnota {0} s identitou {1} není platná hodnota hash potvrzení: {2}"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ Hodnota předaná parametru úlohy {0} není platný název hostitele: {1}.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.de.xlf b/src/SourceLink.GitWeb/xlf/Resources.de.xlf
new file mode 100644
index 00000000..dcc9a38f
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.de.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ Die Elementgruppe "{0}" ist leer. Mindestens ein {1}-Repositoryhost wird benötigt, um SourceLink zu generieren.
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ "{0}" gibt eine ungültige URL an: {1}
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ Der Wert von "{0}" mit der Identität "{1}" ist ungültig: "{2}"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ Der Wert von "{0}" mit der Identität "{1}" ist kein gültiger Commithash: "{2}"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ Der an den Taskparameter "{0}" übergebene Wert ist kein gültiger Hostname: "{1}"
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.es.xlf b/src/SourceLink.GitWeb/xlf/Resources.es.xlf
new file mode 100644
index 00000000..17b78f7c
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.es.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ El grupo de elementos {0} está vacío. Se requiere al menos un repositorio {1} a fin de generar SourceLink.
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ {0} especifica una dirección URL no válida: "{1}"
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ El valor de {0} con identidad '{1}' no es válido '{2}'"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ El valor de {0} con identidad '{1}' no es un hash de confirmación válido '{2}'"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ El valor pasado al parámetro de tarea {0} no es un nombre de host válido: "{1}"
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.fr.xlf b/src/SourceLink.GitWeb/xlf/Resources.fr.xlf
new file mode 100644
index 00000000..21751341
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.fr.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ Le groupe d'éléments {0} est vide. Au moins un hôte de dépôt {1} est nécessaire pour générer SourceLink.
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ {0} spécifie une URL non valide : '{1}'
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ La valeur de {0} avec l'identité '{1}' n'est pas valide : '{2}'"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ La valeur de {0} avec l'identité '{1}' n'est pas un hachage de validation valide : '{2}'"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ La valeur passée au paramètre de tâche {0} n'est pas un nom d'hôte valide : '{1}'
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.it.xlf b/src/SourceLink.GitWeb/xlf/Resources.it.xlf
new file mode 100644
index 00000000..f6f3cb05
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.it.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ Il gruppo di elementi {0} è vuoto. Per generare SourceLink, è necessario almeno un host di repository di {1}.
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ {0} specifica un URL non valido: '{1}'
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ Il valore di {0} con identità '{1}' non è valido: '{2}'"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ Il valore di {0} con identità '{1}' non è un hash commit valido: '{2}'"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ Il valore passato al parametro {0} dell'attività non è un nome host valido: '{1}'
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.ja.xlf b/src/SourceLink.GitWeb/xlf/Resources.ja.xlf
new file mode 100644
index 00000000..98145efd
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.ja.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ {0} 項目グループが空です。SourceLink を生成するには、少なくとも 1 つの {1} リポジトリ ホストが必要です。
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ {0} は無効な URL を指定しています: '{1}'
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ ID '{1}' の {0} の値は無効です: '{2}'"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ ID '{1}' の {0} の値は有効なコミット ハッシュではありません: '{2}'"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ タスク パラメーター {0} に渡された値は有効なホスト名ではありません: '{1}'
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.ko.xlf b/src/SourceLink.GitWeb/xlf/Resources.ko.xlf
new file mode 100644
index 00000000..ce5571ba
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.ko.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ {0} 항목 그룹이 비어 있습니다. SourceLink를 생성하려면 {1} 리포지토리 호스트가 하나 이상 필요합니다.
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ {0}이(가) 잘못된 URL을 지정합니다. '{1}'
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ ID가 '{1}'인 {0}의 값이 잘못되었습니다. '{2}'"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ ID가 '{1}'인 {0}의 값이 유효한 커밋 해시가 아닙니다. '{2}'"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ 작업 매개 변수 {0}에 전달되는 값이 유효한 호스트 이름이 아닙니다. '{1}'
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.pl.xlf b/src/SourceLink.GitWeb/xlf/Resources.pl.xlf
new file mode 100644
index 00000000..5f2e9268
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.pl.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ Grupa elementów {0} jest pusta. Wymagany jest co najmniej jeden host repozytorium {1} w celu wygenerowania elementu SourceLink.
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ Element {0} określa nieprawidłowy adres URL: „{1}”
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ Wartość elementu {0} z tożsamością „{1}” jest nieprawidłowa: „{2}”"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ Wartość elementu {0} z tożsamością „{1}” nie jest prawidłowym skrótem zatwierdzenia: „{2}”"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ Wartość przekazana do parametru zadania {0} nie jest prawidłową nazwą hosta: „{1}”
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.pt-BR.xlf b/src/SourceLink.GitWeb/xlf/Resources.pt-BR.xlf
new file mode 100644
index 00000000..4a461578
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.pt-BR.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ O grupo de itens {0} está vazio. Pelo menos um host de repositório {1} é necessário para gerar o SourceLink.
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ {0} especifica uma URL inválida: '{1}'
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ O valor de {0} com a identidade '{1}' é inválido: '{2}'"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ O valor de {0} com a identidade '{1}' não é um hash de confirmação válido: '{2}'"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ O valor passado para o parâmetro de tarefa {0} não é um nome de host válido: '{1}'
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.ru.xlf b/src/SourceLink.GitWeb/xlf/Resources.ru.xlf
new file mode 100644
index 00000000..8683b5a7
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.ru.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ Группа элементов {0} пуста. Для создания SourceLink нужно указать хотя бы один хост репозитория {1}.
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ В {0} указан недопустимый URL-адрес: "{1}"
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ Значение {0} с идентификатором "{1}" недопустимо: "{2}"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ Значение {0} с идентификатором "{1}" не является допустимым хэш-кодом фиксации: "{2}"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ Значение, передаваемое параметру задачи {0}, не является допустимым именем узла: "{1}"
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.tr.xlf b/src/SourceLink.GitWeb/xlf/Resources.tr.xlf
new file mode 100644
index 00000000..cb9305b8
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.tr.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ {0} öğe grubu boş. SourceLink oluşturmak için en az bir {1} depo konağı gereklidir.
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ {0} geçersiz bir URL belirtiyor: '{1}'
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ '{1}' kimliğine sahip {0} değeri geçersiz: '{2}'"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ '{1}' kimliğine sahip {0} değeri geçerli bir işleme karması değil: '{2}'"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ {0} görev parametresine geçirilen değer geçerli bir konak adı değil: '{1}'
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.zh-Hans.xlf b/src/SourceLink.GitWeb/xlf/Resources.zh-Hans.xlf
new file mode 100644
index 00000000..e4a4010d
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.zh-Hans.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ {0} 项目组为空。至少需要一个 {1} 存储库主机才能生成 SourceLink。
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ {0} 指定无效的 URL:“{1}”
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ 带有 '{1}' 标识的 {0} 的值无效: '{2}'"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ 带有 '{1}' 标识的 {0} 的值不是有效的提交哈希: '{2}'"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ 传递给任务参数 {0} 的值不是有效的主机名:“{1}”
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SourceLink.GitWeb/xlf/Resources.zh-Hant.xlf b/src/SourceLink.GitWeb/xlf/Resources.zh-Hant.xlf
new file mode 100644
index 00000000..ab6c29b8
--- /dev/null
+++ b/src/SourceLink.GitWeb/xlf/Resources.zh-Hant.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink.
+ {0} 項目群組是空的。至少需要一個 {1} 存放庫主機,才可產生 SourceLink。
+
+
+
+ {0} specifies an invalid URL: '{1}'
+ {0} 指定的 URL 無效: '{1}'
+
+
+
+ The value of {0} with identity '{1}' is invalid: '{2}'"
+ 識別為 {1} 之 {0} 的值無效: '{2}'"
+
+
+
+ The value of {0} with identity '{1}' is not a valid commit hash: '{2}'"
+ 識別為 {1} 之 {0} 的值不是有效的認可雜湊: '{2}'"
+
+
+
+ The value passed to task parameter {0} is not a valid host name: '{1}'
+ 傳遞給工作參數 {0} 的值並非有效的主機名稱: '{1}'
+
+
+
+
+
\ No newline at end of file