Skip to content

Commit

Permalink
Merge pull request #103 from OrchardCoreContrib/hishamco/cli
Browse files Browse the repository at this point in the history
Use CommandLineUtils
  • Loading branch information
hishamco authored Jan 16, 2025
2 parents d85eda7 + ccb0a95 commit 6e065e4
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 198 deletions.
29 changes: 15 additions & 14 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="Fluid.Core" Version="2.12.0" />
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.36" />
<PackageVersion Include="Microsoft.CodeAnalysis" Version="4.11.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="OrchardCore.DisplayManagement.Liquid" Version="2.0.0" />
<PackageVersion Include="xunit" Version="2.9.2" />
<PackageVersion Include="xunit.analyzers" Version="1.17.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="Fluid.Core" Version="2.12.0" />
<PackageVersion Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.36" />
<PackageVersion Include="Microsoft.CodeAnalysis" Version="4.11.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="OrchardCore.DisplayManagement.Liquid" Version="2.0.0" />
<PackageVersion Include="xunit" Version="2.9.2" />
<PackageVersion Include="xunit.analyzers" Version="1.17.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
<ItemGroup>
<None Include="../../images/icon.png" Pack="true" PackagePath="icon.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OrchardCoreContrib.PoExtractor.DotNet.CS\OrchardCoreContrib.PoExtractor.DotNet.CS.csproj" />
<ProjectReference Include="..\OrchardCoreContrib.PoExtractor.DotNet.VB\OrchardCoreContrib.PoExtractor.DotNet.VB.csproj" />
Expand Down
278 changes: 94 additions & 184 deletions src/OrchardCoreContrib.PoExtractor/Program.cs
Original file line number Diff line number Diff line change
@@ -1,230 +1,140 @@
using OrchardCoreContrib.PoExtractor.DotNet;
using McMaster.Extensions.CommandLineUtils;
using OrchardCoreContrib.PoExtractor.DotNet;
using OrchardCoreContrib.PoExtractor.DotNet.CS;
using OrchardCoreContrib.PoExtractor.DotNet.VB;
using OrchardCoreContrib.PoExtractor.Liquid;
using OrchardCoreContrib.PoExtractor.Razor;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace OrchardCoreContrib.PoExtractor;

public class Program
{
private static readonly string _defaultLanguage = Language.CSharp;
private static readonly string _defaultTemplateEngine = TemplateEngine.Both;

public static void Main(string[] args)
{
if (args.Length < 2 || args.Length > 10 || args.Length % 2 == 1)
{
ShowHelp();
var app = new CommandLineApplication();

return;
}
app.HelpOption();

var inputPath = new DirectoryInfo(args[0]).FullName;
var outputPath = new DirectoryInfo(args[1]).FullName;
// Arguments
var inputPath = app.Argument("Input Path", "The path to the input directory, all projects at the the path will be processed.")
.IsRequired();
var outputPath = app.Argument("Output Path", "The path to a directory where POT files will be generated.")
.IsRequired();

if (!Directory.Exists(inputPath))
// Options
var language = app.Option("-l|--language <LANGUAGE>", "Specifies the code language to extracts translatable strings from.", CommandOptionType.SingleValue, options =>
{
ShowHelp();

return;
}

(string language, string templateEngine, string singleOutputFile) = GetCliOptions(args);

if (language == null || templateEngine == null)
options.Accepts(cfg => cfg.Values("C#", "VB"));
options.DefaultValue = "C#";
});
var template = app.Option("-t|--template <TEMPLATE>", "Specifies the template engine to extract the translatable strings from.", CommandOptionType.SingleValue, options =>
options.Accepts(cfg => cfg.Values("Razor", "Liquid"))
);
var ignoredProjects = app.Option("-i|--ignore <IGNORED_PROJECTS>", "Ignores extracting PO files from a given project(s).", CommandOptionType.MultipleValue);
var localizers = app.Option("--localizer <LOCALIZERS>", "Specifies the name of the localizer(s) that will be used during the extraction process.", CommandOptionType.MultipleValue);
var single = app.Option("-s|--single <FILE_NAME>", "Specifies the single output file.", CommandOptionType.SingleValue);

app.OnExecute(() =>
{
ShowHelp();

return;
}
if (!Directory.Exists(inputPath.Value))
{
Console.WriteLine($"The input path '{inputPath.Value}' does not exist.");

var projectFiles = new List<string>();
var projectProcessors = new List<IProjectProcessor>();
return;
}

if (language == Language.CSharp)
{
projectProcessors.Add(new CSharpProjectProcessor());
foreach (var ignoredProject in ignoredProjects.Values)
{
IgnoredProject.Add(ignoredProject);
}

projectFiles.AddRange(Directory
.EnumerateFiles(inputPath, $"*{ProjectExtension.CS}", SearchOption.AllDirectories)
.OrderBy(f => f));
}
else
{
projectProcessors.Add(new VisualBasicProjectProcessor());
LocalizerAccessors.LocalizerIdentifiers = [.. localizers.Values];

projectFiles.AddRange(Directory
.EnumerateFiles(inputPath, $"*{ProjectExtension.VB}", SearchOption.AllDirectories)
.OrderBy(f => f));
}
var projectFiles = new List<string>();
var projectProcessors = new List<IProjectProcessor>();

if (templateEngine == TemplateEngine.Both)
{
projectProcessors.Add(new RazorProjectProcessor());
projectProcessors.Add(new LiquidProjectProcessor());
}
else if (templateEngine == TemplateEngine.Razor)
{
projectProcessors.Add(new RazorProjectProcessor());
}
else if (templateEngine == TemplateEngine.Liquid)
{
projectProcessors.Add(new LiquidProjectProcessor());
}
if (language.Value() == Language.CSharp)
{
projectProcessors.Add(new CSharpProjectProcessor());

var isSingleFileOutput = !string.IsNullOrEmpty(singleOutputFile);
var localizableStrings = new LocalizableStringCollection();
foreach (var projectFile in projectFiles)
{
var projectPath = Path.GetDirectoryName(projectFile);
var projectBasePath = Path.GetDirectoryName(projectPath) + Path.DirectorySeparatorChar;
var projectRelativePath = projectPath[projectBasePath.Length..];
var rootedProject = projectPath[(projectPath.IndexOf(inputPath) + inputPath.Length + 1)..];
if (IgnoredProject.ToList().Any(p => rootedProject.StartsWith(p)))
projectFiles.AddRange(Directory
.EnumerateFiles(inputPath.Value, $"*{ProjectExtension.CS}", SearchOption.AllDirectories)
.OrderBy(f => f));
}
else
{
continue;
projectProcessors.Add(new VisualBasicProjectProcessor());

projectFiles.AddRange(Directory
.EnumerateFiles(inputPath.Value, $"*{ProjectExtension.VB}", SearchOption.AllDirectories)
.OrderBy(f => f));
}

foreach (var projectProcessor in projectProcessors)
if (template.Value() == TemplateEngine.Both)
{
projectProcessor.Process(projectPath, projectBasePath, localizableStrings);
projectProcessors.Add(new RazorProjectProcessor());
projectProcessors.Add(new LiquidProjectProcessor());
}

if (!isSingleFileOutput)
else if (template.Value() == TemplateEngine.Razor)
{
if (localizableStrings.Values.Any())
{
var potPath = Path.Combine(outputPath, Path.GetFileNameWithoutExtension(projectFile) + PoWriter.PortaleObjectTemplateExtension);

Directory.CreateDirectory(Path.GetDirectoryName(potPath));

using var potFile = new PoWriter(potPath);
potFile.WriteRecord(localizableStrings.Values);
}

Console.WriteLine($"{Path.GetFileName(projectPath)}: Found {localizableStrings.Values.Count()} strings.");
localizableStrings.Clear();
projectProcessors.Add(new RazorProjectProcessor());
}
}

if (isSingleFileOutput)
{
if (localizableStrings.Values.Any())
else if (template.Value() == TemplateEngine.Liquid)
{
var potPath = Path.Combine(outputPath, singleOutputFile);

Directory.CreateDirectory(Path.GetDirectoryName(potPath));

using var potFile = new PoWriter(potPath);
potFile.WriteRecord(localizableStrings.Values);
projectProcessors.Add(new LiquidProjectProcessor());
}

Console.WriteLine($"Found {localizableStrings.Values.Count()} strings.");
}
}

private static (string language, string templateEngine, string singleOutputFile) GetCliOptions(string[] args)
{
var language = _defaultLanguage;
var templateEngine = _defaultTemplateEngine;
string singleOutputFile = null;
for (int i = 4; i <= args.Length; i += 2)
{
switch (args[i - 2])
var isSingleFileOutput = !string.IsNullOrEmpty(single.Value());
var localizableStrings = new LocalizableStringCollection();
foreach (var projectFile in projectFiles)
{
case "-l":
case "--language":
if (args[i - 1].Equals(Language.CSharp, StringComparison.CurrentCultureIgnoreCase))
{
language = Language.CSharp;
}
else if (args[i - 1].Equals(Language.VisualBasic, StringComparison.CurrentCultureIgnoreCase))
{
language = Language.VisualBasic;
}
else
{
language = null;
}
var projectPath = Path.GetDirectoryName(projectFile);
var projectBasePath = Path.GetDirectoryName(projectPath) + Path.DirectorySeparatorChar;
var projectRelativePath = projectPath[projectBasePath.Length..];
var rootedProject = projectPath[(projectPath.IndexOf(inputPath.Value) + inputPath.Value.Length + 1)..];
if (IgnoredProject.ToList().Any(p => rootedProject.StartsWith(p)))
{
continue;
}

break;
case "-t":
case "--template":
if (args[i - 1].Equals(TemplateEngine.Razor, StringComparison.CurrentCultureIgnoreCase))
{
templateEngine = TemplateEngine.Razor;
}
else if (args[i - 1].Equals(TemplateEngine.Liquid, StringComparison.CurrentCultureIgnoreCase))
{
templateEngine = TemplateEngine.Liquid;
}
else
{
templateEngine = null;
}
foreach (var projectProcessor in projectProcessors)
{
projectProcessor.Process(projectPath, projectBasePath, localizableStrings);
}

break;
case "-i":
case "--ignore":
if (!string.IsNullOrEmpty(args[i - 1]))
if (isSingleFileOutput)
{
if (localizableStrings.Values.Any())
{
var ignoredProjects = args[i - 1].Split(',', StringSplitOptions.RemoveEmptyEntries);
var potPath = Path.Combine(outputPath.Value, Path.GetFileNameWithoutExtension(projectFile) + PoWriter.PortaleObjectTemplateExtension);

foreach (var ignoredProject in ignoredProjects)
{
IgnoredProject.Add(ignoredProject);
}
Directory.CreateDirectory(Path.GetDirectoryName(potPath));

using var potFile = new PoWriter(potPath);
potFile.WriteRecord(localizableStrings.Values);
}

break;
case "--localizer":
if (!string.IsNullOrEmpty(args[i - 1]))
{
var localizerIdentifiers = args[i - 1].Split(',', StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine($"{Path.GetFileName(projectPath)}: Found {localizableStrings.Values.Count()} strings.");
localizableStrings.Clear();
}
}

LocalizerAccessors.LocalizerIdentifiers = localizerIdentifiers;
}
if (isSingleFileOutput)
{
if (localizableStrings.Values.Any())
{
var potPath = Path.Combine(outputPath.Value, single.Value());

break;
case "-s":
case "--single":
if (!string.IsNullOrEmpty(args[i - 1]))
{
singleOutputFile = args[i - 1];
}
Directory.CreateDirectory(Path.GetDirectoryName(potPath));

break;
default:
language = null;
templateEngine = null;
break;
}
}
using var potFile = new PoWriter(potPath);
potFile.WriteRecord(localizableStrings.Values);
}

return (language, templateEngine, singleOutputFile);
}
Console.WriteLine($"Found {localizableStrings.Values.Count()} strings.");
}
});

private static void ShowHelp()
{
Console.WriteLine("Usage:");
Console.WriteLine(" extractpo <INPUT_PATH> <OUTPUT_PATH> [options]");
Console.WriteLine();
Console.WriteLine("Arguments:");
Console.WriteLine(" <INPUT_PATH> The path to the input directory, all projects at the the path will be processed.");
Console.WriteLine(" <OUTPUT_PATH> The path to a directory where POT files will be generated.");
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine(" -l, --language <C#|VB> Specifies the code language to extracts translatable strings from.");
Console.WriteLine(" Default: C# language");
Console.WriteLine(" -t, --template <Razor|Liquid> Specifies the template engine to extract the translatable strings from.");
Console.WriteLine(" Default: Razor & Liquid templates");
Console.WriteLine(" -i, --ignore project1,project2 Ignores extracting PO filed from a given project(s).");
Console.WriteLine(" --localizer localizer1,localizer2 Specifies the name of the localizer(s) that will be used during the extraction process.");
Console.WriteLine(" -s, --single <FILE_NAME> Specifies the single output file.");
app.Execute(args);
}
}

0 comments on commit 6e065e4

Please sign in to comment.