Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions docfx/articles/ltr/LTR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# LTR - LocalizablesToResx

LocalizablesToResx is a simple tool, which is used to acquire localized strings within `.razor` files and automatically generate `.resx` file based on these strings. This tool intends to simplify creation of .resx files from .razor files.


## Example

Let's have following .razor file with localized strings
```html

<h1>@Localizer["Home"]</h1>
<p>@Localizer["Welcome"]</p>
<p>@Localizer["This is example app"]</span>

```

We can call this script:

`ltr -f test.razor -o test.resx`

Following resx file will be generated:

![example](../../images/example-resx.png)

## Installation

dotnet tool install AXSharp.ltr --prerelease --local


## Parameters

This cli tool can be used with following parameters:

- -i (--identifier)
- identifier which represent localizer, which is used to locate localized strings (default is `Localizer`)
- not required
- -o (--output)
- output resx file
- mandatory
- -f (--file)
- source file, where localized string are located
- not required if -d is present
- -d (--directory)
- source directory, which files are enumerated and localized string are then located
- not required if -f is present
Binary file added docfx/images/example-resx.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 5 additions & 4 deletions src/AXSharp-L1-tests.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
"solution": {
"path": "AXSharp.sln",
"projects": [
"AXSharp.blazor\\tests\\sandbox\\ComponentsExamples\\ComponentsExamples.csproj",
"AXSharp.blazor\\tests\\sandbox\\AXSharp.RenderableContent.Tests\\AXSharp.RenderableContent.Tests.csproj",
"AXSharp.blazor\\tests\\sandbox\\ax-blazor-example\\ix\\ax-blazor-example.csproj",
"AXSharp.compiler\\tests\\AXSharp.CompilerTests\\AXSharp.CompilerTests.csproj",
"AXSharp.blazor\\tests\\sandbox\\ComponentsExamples\\ComponentsExamples.csproj",
"AXSharp.compiler\\tests\\AXSharp.Compiler.CsTests\\AXSharp.Compiler.CsTests.csproj",
"AXSharp.compiler\\tests\\AXSharp.CompilerTests\\AXSharp.CompilerTests.csproj",
"AXSharp.compiler\\tests\\AXSharp.ixc.Tests\\AXSharp.ixc.Tests.csproj",
"AXSharp.compiler\\tests\\AXSharp.ixr.Tests\\AXSharp.ixr.Tests.csproj",
"AXSharp.connectors\\tests\\AXSharp.ConnectorLegacyTests\\AXSharp.ConnectorLegacyTests.csproj",
"AXSharp.connectors\\tests\\AXSharp.ConnectorTests\\AXSharp.ConnectorTests\\AXSharp.ConnectorTests.csproj"
"AXSharp.connectors\\tests\\AXSharp.ConnectorTests\\AXSharp.ConnectorTests\\AXSharp.ConnectorTests.csproj",
"AXSharp.tools\\tests\\AXSharp.LocalizablesToResx.Tests\\AXSharp.LocalizablesToResx.Tests.csproj",
"AXSharp.tools\\tests\\AXSharp.nuget.update.Tests\\AXSharp.nuget.update.Tests.csproj"
]
}
}
3 changes: 2 additions & 1 deletion src/AXSharp-L2-tests.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"AXSharp.connectors\\tests\\ax-test-project\\ix\\ax_test_project.csproj",
"AXSharp.connectors\\tests\\exploring\\Webserver.Api.Exploratory\\Webserver.Api.Exploratory.csproj",
"AXSharp.connectors\\tests\\exploring\\exploratory.consoleapp\\exploratory.consoleapp.csproj",
"AXSharp.tools\\tests\\AXSharp.nuget.update.Tests\\AXSharp.nuget.update.Tests.csproj"
"AXSharp.tools\\tests\\AXSharp.nuget.update.Tests\\AXSharp.nuget.update.Tests.csproj",
"AXSharp.tools\\tests\\AXSharp.LocalizablesToResx.Tests\\AXSharp.LocalizablesToResx.Tests.csproj"
]
}
}
1 change: 1 addition & 0 deletions src/AXSharp-L3-tests.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"AXSharp.templates\\working\\templates\\ixconsole\\ixconsole.twin\\ixconsole.csproj",
"AXSharp.templates\\working\\templates\\ixconsole\\ixconsole\\ixconsole.app.csproj",
"AXSharp.templates\\working\\templates\\ixtwin\\ixtwin.csproj",
"AXSharp.tools\\tests\\AXSharp.LocalizablesToResx.Tests\\AXSharp.LocalizablesToResx.Tests.csproj"
"AXSharp.tools\\src\\AXSharp.nuget.update\\AXSharp.nuget.update.csproj",
"AXSharp.tools\\tests\\AXSharp.nuget.update.Tests\\AXSharp.nuget.update.Tests.csproj",
"sanbox\\integration\\ix-integration-blazor\\ix-integration-blazor.csproj",
Expand Down
3 changes: 2 additions & 1 deletion src/AXSharp-packable-only.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"AXSharp.compiler\\src\\ixd\\AXSharp.ixd.csproj",
"AXSharp.compiler\\src\\ixr\\AXSharp.ixr.csproj",
"AXSharp.connectors\\src\\AXSharp.Connector.S71500.WebAPI\\AXSharp.Connector.S71500.WebAPI.csproj",
"AXSharp.connectors\\src\\AXSharp.Connector\\AXSharp.Connector.csproj"
"AXSharp.connectors\\src\\AXSharp.Connector\\AXSharp.Connector.csproj",
"AXSharp.tools\\tests\\AXSharp.LocalizablesToResx.Tests\\AXSharp.LocalizablesToResx.Tests.csproj"
]
}
}
30 changes: 30 additions & 0 deletions src/AXSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ix_integration_plc", "sanbo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ax_blazor_example", "AXSharp.blazor\tests\sandbox\ax-blazor-example\ix\ax_blazor_example.csproj", "{6605983C-F5BF-4DD5-8F06-640505C0D6B0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AXSharp.LocalizablesToResx", "AXSharp.tools\src\AXSharp.LocalizablesToResx\AXSharp.LocalizablesToResx.csproj", "{CC79093E-00B6-42A6-9548-E3A88494DC27}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AXSharp.LocalizablesToResx.Tests", "AXSharp.tools\tests\AXSharp.LocalizablesToResx.Tests\AXSharp.LocalizablesToResx.Tests.csproj", "{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -530,6 +534,30 @@ Global
{6605983C-F5BF-4DD5-8F06-640505C0D6B0}.Release|x64.Build.0 = Release|Any CPU
{6605983C-F5BF-4DD5-8F06-640505C0D6B0}.Release|x86.ActiveCfg = Release|Any CPU
{6605983C-F5BF-4DD5-8F06-640505C0D6B0}.Release|x86.Build.0 = Release|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Debug|x64.ActiveCfg = Debug|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Debug|x64.Build.0 = Debug|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Debug|x86.ActiveCfg = Debug|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Debug|x86.Build.0 = Debug|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Release|Any CPU.Build.0 = Release|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Release|x64.ActiveCfg = Release|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Release|x64.Build.0 = Release|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Release|x86.ActiveCfg = Release|Any CPU
{CC79093E-00B6-42A6-9548-E3A88494DC27}.Release|x86.Build.0 = Release|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Debug|x64.ActiveCfg = Debug|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Debug|x64.Build.0 = Debug|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Debug|x86.ActiveCfg = Debug|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Debug|x86.Build.0 = Debug|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Release|Any CPU.Build.0 = Release|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Release|x64.ActiveCfg = Release|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Release|x64.Build.0 = Release|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Release|x86.ActiveCfg = Release|Any CPU
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -586,6 +614,8 @@ Global
{22F540F6-16FC-4C4A-9360-3FAB409807C2} = {02989C66-B1D1-4E5C-A350-6C3D18D0A6BD}
{60AEE1CA-8623-4950-BE53-196E00920888} = {F30D5DD0-F259-49E0-AB1B-84DD8766A37A}
{6605983C-F5BF-4DD5-8F06-640505C0D6B0} = {E7FC977B-1114-4D27-8FC8-DAB3F1323D24}
{CC79093E-00B6-42A6-9548-E3A88494DC27} = {FC332118-F8B8-48DC-A7EA-AC7559CD4A98}
{4C18C927-8CD6-4ED5-80F1-91DE60D2DD07} = {FE787422-9AB3-4065-A6D9-97511EC6141C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {99D50E81-8A37-4BB9-A435-C2C98430D600}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>


<!--NuGet Specific part-->
<Description>Creates Resx files from localizables in a .NET project.</Description>
<PackAsTool>True</PackAsTool>
<ToolCommandName>ltr</ToolCommandName>

<!-- NuGet Common part-->
<PackageProjectUrl>https://github.com/ix-ax/</PackageProjectUrl>
<RepositoryUrl>https://github.com/ix-ax/axsharp</RepositoryUrl>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<Authors>ix-ax</Authors>
<Copyright>(c) Peter Kurhajec and Contributors</Copyright>
<PackageTags>simatix-ax, PLC, industrial automation, SCADA, HMI</PackageTags>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Title>AX# compiler CLI</Title>
<PackageIcon>icon_128_128.png</PackageIcon>
<RepositoryType>git</RepositoryType>
<IncludeSymbols>True</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReleaseNotes>
Release notes are published here:
https://github.com/ix-ax/axsharp/releases
</PackageReleaseNotes>
<PackageReadmeFile>NUGET-README.md</PackageReadmeFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ResXResourceReader.NetStandard" Version="1.1.0" />
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="GitVersion.MsBuild" Version="5.10.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\..\assets\icons\icon_128_128.png" Link="icon_128_128.png">
<PackagePath>\</PackagePath>
<Pack>True</Pack>
</None>
<None Include="..\..\..\NUGET-README.md" Link="NUGET-README.md">
<PackagePath>\</PackagePath>
<Pack>True</Pack>
</None>
</ItemGroup>
<ItemGroup>
<None Update="tests\SimpleTests.razor">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
20 changes: 20 additions & 0 deletions src/AXSharp.tools/src/AXSharp.LocalizablesToResx/Options.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using CommandLine;

namespace AXSharp.LocalizablesToResx
{
public class Options
{
[Option('f', "file", Required = false, HelpText = "Source file, from which resx will be generated.")]
public string? SourceFile { get; set; }

[Option('d', "directory", Required = false, HelpText = "Source director, which contains files for resx gen.")]
public string? SourceDirectory { get; set; }

[Option('i', "identifier", Required = false, HelpText = "Localizable identifier, from which regex for searching is created. If empty, default value \"Localizer\" is used.")]
public string? Identifier { get; set; }

[Option('o', "output", Required = true, HelpText = "Required output resx file.")]
public string? OutputResx { get; set; }

}
}
161 changes: 161 additions & 0 deletions src/AXSharp.tools/src/AXSharp.LocalizablesToResx/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// See https://aka.ms/new-console-template for more information
using AXSharp.LocalizablesToResx;
using CommandLine;
using CommandLine.Text;
using System.Resources.NetStandard;
using System.Text.RegularExpressions;


Parser.Default.ParseArguments<Options>(args)
.WithParsed(o =>
{

Main(o);

});



void Main(Options o)
{
Console.WriteLine("** ltr (LocalizablesToResx) **");
Console.WriteLine("Generator of resx file from source code based on localizable identifier.");
Console.WriteLine("Generating...");
// Create a Regex
ResXGen.CreateRegex(o.Identifier);

// Create in memory dictionary with unique localizable values
ResXGen.CreateResxDictionary(o);

// Write dictionary into resx file
ResXGen.WriteToResx(o.OutputResx);

Console.WriteLine($"Returned {ResXGen.count} records.");
Console.WriteLine($"Location: {o.OutputResx}");
Console.WriteLine("Done.");


}

/// <summary>
/// Main static class containing logic of acquiring localized strings and generating resx file.
/// </summary>
public static class ResXGen
{
public static uint count;
public static Regex LocalizableRegex;
public static Dictionary<string, string> ResxDictionary = new Dictionary<string, string>();


/// <summary>
/// Create regex based on -i argument. If argument is empty, default regex "Localizer\[.*?\]" is used.
/// </summary>
/// <param name="identifier">Identifier used in regex</param>
public static void CreateRegex(string identifier)
{
string pattern;
if (identifier == null)
{
//use default identifier for regex
pattern = @"Localizer\[.*?\]";
}
else
{
pattern = $@"{identifier}\[.*?\]";
}

LocalizableRegex = new Regex(pattern);
}

/// <summary>
/// Creates dictionary of values acquired from input files.
/// </summary>
/// <param name="o"></param>
public static void CreateResxDictionary(Options o)
{
if (o.SourceFile != null)
{
if (!File.Exists(o.SourceFile))
{
Console.WriteLine("Source file does not exist!");
return;
}
else
{
AddLocalizablesToDictionary(o.SourceFile);
}
}

if (o.SourceDirectory != null)
{
if (!Directory.Exists(o.SourceDirectory))
{
Console.WriteLine("Director does not exist!");
return;
}
else
{
CreateResxDictionaryRecursive(o.SourceDirectory);
}
}

}

/// <summary>
/// Writes created dictionary of localizable values into resx file.
/// </summary>
/// <param name="outputPath">Output path of resx file</param>
public static void WriteToResx(string outputPath)
{
using (ResXResourceWriter resx = new ResXResourceWriter(outputPath))
{
foreach (var item in ResxDictionary)
{
resx.AddResource(item.Value, item.Value);
}
}
}

private static void CreateResxDictionaryRecursive(string sourceDir)
{
foreach (string d in Directory.GetDirectories(sourceDir))
{
foreach (string f in Directory.GetFiles(d, "*.razor"))
{
AddLocalizablesToDictionary(f);
}

CreateResxDictionaryRecursive(d);
}
}

private static void AddLocalizablesToDictionary(string filePath)
{
string ln;
using (StreamReader file = new StreamReader(filePath))
{
while ((ln = file.ReadLine()) != null)
{
MatchCollection matches = LocalizableRegex.Matches(ln);

foreach (Match match in matches)
{
var value = match.Value;

string[] sp = value.Split('\"');
// get text inside [""]
if (sp.Length > 1 && ResxDictionary.TryAdd(sp[1], sp[1]))
{
count++;
}
}

}
file.Close();
}
}


}


Loading