File: Tasks\GatherXlf.cs
Web Access
Project: Microsoft.DotNet.XliffTasks.csproj (Microsoft.DotNet.XliffTasks)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System.IO;
using System;
using System.Collections.Generic;

namespace XliffTasks.Tasks;

[MSBuildMultiThreadableTask]
public sealed class GatherXlf : XlfTask
{
    [Required]
    public ITaskItem[] Sources { get; set; }

    [Required]
    public string[] Languages { get; set; }

    [Required]
    public string TranslatedOutputDirectory { get; set; }

    [Output]
    public ITaskItem[] Outputs { get; private set; }

    protected override void ExecuteCore()
    {
        List<ITaskItem> outputs = new();
        HashSet<string> outputPaths = new(StringComparer.OrdinalIgnoreCase);

        foreach (ITaskItem source in Sources)
        {
            string sourceDocumentPath = source.GetMetadataOrDefault(MetadataKey.SourceDocumentPath, source.ItemSpec);

            foreach (string language in Languages)
            {
                // The neutral .xlf file is not a translation and produces no satellite assembly.
                if (XlfTask.IsNeutralLanguage(language))
                {
                    continue;
                }

                string xlfPath = XlfTask.GetXlfPath(sourceDocumentPath, language);
                TaskItem xlf = new(source) { ItemSpec = xlfPath };
                xlf.SetMetadata(MetadataKey.XlfSource, source.ItemSpec);
                xlf.SetMetadata(MetadataKey.XlfTranslatedFullPath, GetTranslatedOutputPath(source, language, outputPaths));
                xlf.SetMetadata(MetadataKey.XlfLanguage, language);
                outputs.Add(xlf);
            }
        }

        Outputs = outputs.ToArray();
    }

    private string GetTranslatedOutputPath(ITaskItem source, string language, HashSet<string> outputPaths)
    {
        bool preserveFileName = string.Equals(source.GetMetadata(MetadataKey.XlfPreserveFileName), "true", StringComparison.OrdinalIgnoreCase);

        string translatedFileName = source.GetMetadata(MetadataKey.XlfTranslatedFilename);
        if (string.IsNullOrEmpty(translatedFileName))
        {
            translatedFileName = Path.GetFileNameWithoutExtension(source.ItemSpec);
            source.SetMetadata(MetadataKey.XlfTranslatedFilename, translatedFileName);
        }

        string sourceDocumentPath = source.GetMetadataOrDefault(MetadataKey.SourceDocumentPath, source.ItemSpec);
        string extension = Path.GetExtension(source.ItemSpec);

        string outputPath = preserveFileName ?
            Path.Combine(TranslatedOutputDirectory, language, $"{translatedFileName}{extension}") :
            Path.Combine(TranslatedOutputDirectory, $"{translatedFileName}.{language}{extension}");

        if (!outputPaths.Add(outputPath))
        {
            throw new BuildErrorException(
                $"Two or more source files to be translated in the same project are named {Path.GetFileName(sourceDocumentPath)}. " +
                $"Give them unique names or set unique {MetadataKey.XlfTranslatedFilename} metadata.");
        }

        return outputPath;
    }
}