<feat> 多语言支持

This commit is contained in:
2022-12-01 15:55:14 +08:00
parent 8ad313ff53
commit 7168901bef
19 changed files with 231 additions and 59 deletions

View File

@ -1,3 +1,3 @@
dot trim-utf8-bom
dot remove-whitespace
dot convert-lf
dot rm-bom
dot rm-blank
dot tolf

View File

@ -1,4 +0,0 @@
namespace Dot.Convert2Lf;
[Verb("convert-lf", HelpText = nameof(Strings.ConvertEndOfLineToLF), ResourceType = typeof(Strings))]
public class Option : DirOption { }

View File

@ -2,10 +2,14 @@ namespace Dot;
public class DirOption : IOption
{
[Option('f', "filter", Required = false, HelpText = nameof(Strings.FileSearchPattern), Default = "*.*"
[Option('f', "filter", HelpText = nameof(Strings.FileSearchPattern), Default = "*.*"
, ResourceType = typeof(Strings))]
public string Filter { get; set; }
[Value(0, HelpText = nameof(Strings.FolderPath), Default = ".", ResourceType = typeof(Strings))]
public string Path { get; set; }
[Option('r', "readonly", HelpText = nameof(Strings.ReadOnly), Default = false, ResourceType = typeof(Strings))]
public bool ReadOnly { get; set; }
}

View File

@ -113,15 +113,6 @@ namespace Dot.Lang {
}
}
/// <summary>
/// Looks up a localized string similar to 要处理的文本(默认取取剪贴板值).
/// </summary>
public static string HelpForTextArg0 {
get {
return ResourceManager.GetString("HelpForTextArg0", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 输入文本为空.
/// </summary>
@ -131,6 +122,15 @@ namespace Dot.Lang {
}
}
/// <summary>
/// Looks up a localized string similar to 没有需要处理的文件.
/// </summary>
public static string NoFileToBeProcessed {
get {
return ResourceManager.GetString("NoFileToBeProcessed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 指定的路径“{0}”不存在.
/// </summary>
@ -140,6 +140,15 @@ namespace Dot.Lang {
}
}
/// <summary>
/// Looks up a localized string similar to 按下任意键继续....
/// </summary>
public static string PressAnyKey {
get {
return ResourceManager.GetString("PressAnyKey", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to BitSet 1[0-9]2[a-z]4[A-Z]8[ascii.0x21-0x2F].
/// </summary>
@ -167,6 +176,15 @@ namespace Dot.Lang {
}
}
/// <summary>
/// Looks up a localized string similar to 只读模式(仅做测试,不实际修改).
/// </summary>
public static string ReadOnly {
get {
return ResourceManager.GetString("ReadOnly", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 移除文件尾部换行和空格.
/// </summary>
@ -186,7 +204,7 @@ namespace Dot.Lang {
}
/// <summary>
/// Looks up a localized string similar to 查找文件...OK.
/// Looks up a localized string similar to {0} 个文件.
/// </summary>
public static string SearchingFileOK {
get {
@ -203,6 +221,15 @@ namespace Dot.Lang {
}
}
/// <summary>
/// Looks up a localized string similar to 要处理的文本(默认取取剪贴板值).
/// </summary>
public static string TextTobeProcessed {
get {
return ResourceManager.GetString("TextTobeProcessed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 移除文件的uf8 bom.
/// </summary>

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
id="root" xmlns="">
<xsd:element name="root" msdata:IsDataSet="true"></xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="InputTextIsEmpty" xml:space="preserve">
<value>The input text is empty</value>
</data>
<data name="SearchingFile" xml:space="preserve">
<value>Find files...</value>
</data>
<data name="PathNotFound" xml:space="preserve">
<value>The specified path "{0}" does not exist</value>
</data>
<data name="SearchingFileOK" xml:space="preserve">
<value>Find files...OK</value>
</data>
<data name="ShowMessageTemp" xml:space="preserve">
<value>Read: {0}/{1}, processed: {2}, skipped: {3}</value>
</data>
<data name="HelpForText" xml:space="preserve">
<value>Text encoding tool</value>
</data>
<data name="Copied" xml:space="preserve">
<value>{0}(copied to clipboard)</value>
</data>
<data name="FileSearchPattern" xml:space="preserve">
<value>File wildcards</value>
</data>
<data name="FolderPath" xml:space="preserve">
<value>Directory path to be processed</value>
</data>
<data name="ConvertEndOfLineToLF" xml:space="preserve">
<value>Convert newline characters to LF</value>
</data>
<data name="GuidTool" xml:space="preserve">
<value>GUID tool</value>
</data>
<data name="UseUppercase" xml:space="preserve">
<value>Use uppercase output</value>
</data>
<data name="RandomPasswordGenerator" xml:space="preserve">
<value>Random password generator</value>
</data>
<data name="PwdLength" xml:space="preserve">
<value>Password length</value>
</data>
<data name="PwdGenerateTypes" xml:space="preserve">
<value>BitSet 1[0-9]2[a-z]4[A-Z]8[ascii.0x21-0x2F]</value>
</data>
<data name="RemoveTrailingWhiteSpaces" xml:space="preserve">
<value>Remove line breaks and spaces at the end of the file</value>
</data>
<data name="TrimUtf8Bom" xml:space="preserve">
<value>Remove the uf8 bom of the file</value>
</data>
<data name="TextTobeProcessed" xml:space="preserve">
<value>Text to be processed (clipboard value is taken by default)</value>
</data>
<data name="PressAnyKey" xml:space="preserve">
<value>Press any key to continue...</value>
</data>
<data name="ReadOnly" xml:space="preserve">
<value>Read-only mode (only for testing, no actual modification)</value>
</data>
<data name="NoFileToBeProcessed" xml:space="preserve">
<value>No documents to be processed</value>
</data>
</root>

View File

@ -34,7 +34,7 @@
<value>指定的路径“{0}”不存在</value>
</data>
<data name="SearchingFileOK" xml:space="preserve">
<value>查找文件...OK</value>
<value>{0} 个文件</value>
</data>
<data name="ShowMessageTemp" xml:space="preserve">
<value>已读取:{0}/{1},处理:{2},跳过:{3}</value>
@ -42,7 +42,7 @@
<data name="HelpForText" xml:space="preserve">
<value>文本编码工具</value>
</data>
<data name="HelpForTextArg0" xml:space="preserve">
<data name="TextTobeProcessed" xml:space="preserve">
<value>要处理的文本(默认取取剪贴板值)</value>
</data>
<data name="Copied" xml:space="preserve">
@ -82,4 +82,13 @@
<data name="TrimUtf8Bom" xml:space="preserve">
<value>移除文件的uf8 bom</value>
</data>
<data name="PressAnyKey" xml:space="preserve">
<value>按下任意键继续...</value>
</data>
<data name="ReadOnly" xml:space="preserve">
<value>只读模式(仅做测试,不实际修改)</value>
</data>
<data name="NoFileToBeProcessed" xml:space="preserve">
<value>没有需要处理的文件</value>
</data>
</root>

View File

@ -1,4 +0,0 @@
namespace Dot.RemoveTrailingWhiteSpace;
[Verb("remove-whitespace", HelpText = nameof(Strings.RemoveTrailingWhiteSpaces), ResourceType = typeof(Strings))]
public class Option : DirOption { }

View File

@ -1,7 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using NSExt.Extensions;
namespace Dot.RemoveTrailingWhiteSpace;
namespace Dot.RmBlank;
public sealed class Main : Tool<Option>, IDisposable
{
@ -33,16 +33,23 @@ public sealed class Main : Tool<Option>, IDisposable
ShowMessage(1, 0, 0);
var spacesCnt = 0;
using var fsr = OpenFileToWrite(file);
if (fsr.Length == 0 || (spacesCnt = GetSpacesCnt(fsr)) == 0) {
using var fsrw = OpenFileStream(file, FileMode.Open, FileAccess.ReadWrite);
if (Opt.ReadOnly) { //测试,只读模式
ShowMessage(0, 1, 0);
return;
}
if (fsrw is null || fsrw.Length == 0 || (spacesCnt = GetSpacesCnt(fsrw)) == 0) {
ShowMessage(0, 0, 1);
return;
}
fsr.Seek(0, SeekOrigin.Begin);
if (!fsr.IsTextStream()) return;
fsrw.Seek(0, SeekOrigin.Begin);
if (!fsrw.IsTextStream()) return;
ShowMessage(0, 1, 0);
fsr.SetLength(fsr.Length - spacesCnt);
fsrw.SetLength(fsrw.Length - spacesCnt);
}
private static int GetSpacesCnt(Stream fsr)
@ -94,8 +101,10 @@ public sealed class Main : Tool<Option>, IDisposable
var fileList = EnumerateFiles(Opt.Path, Opt.Filter);
_totalCnt = fileList.Count();
step1Bar.Message = Strings.SearchingFileOK;
step1Bar.Message = string.Format(Strings.SearchingFileOK, _totalCnt);
step1Bar.Finished();
if (_totalCnt == 0) return;
_step2Bar = step1Bar.Spawn(_totalCnt, string.Empty, DefaultProgressBarOptions);

4
src/RmBlank/Option.cs Normal file
View File

@ -0,0 +1,4 @@
namespace Dot.RmBlank;
[Verb("rm-blank", HelpText = nameof(Strings.RemoveTrailingWhiteSpaces), ResourceType = typeof(Strings))]
public class Option : DirOption { }

View File

@ -1,6 +1,6 @@
using System.Diagnostics.CodeAnalysis;
namespace Dot.TrimUtf8Bom;
namespace Dot.RmBom;
public sealed class Main : Tool<Option>, IDisposable
{
@ -57,8 +57,9 @@ public sealed class Main : Tool<Option>, IDisposable
var fileList = EnumerateFiles(Opt.Path, Opt.Filter);
_totalCnt = fileList.Count();
step1Bar.Message = Strings.SearchingFileOK;
step1Bar.Message = string.Format(Strings.SearchingFileOK, _totalCnt);
step1Bar.Finished();
if (_totalCnt == 0) return;
_step2Bar = step1Bar.Spawn(_totalCnt, string.Empty, DefaultProgressBarOptions);
@ -68,11 +69,22 @@ public sealed class Main : Tool<Option>, IDisposable
var tmpFile = $"{file}.tmp";
var isReplaced = false;
using (var fsr = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
using (var fsr = OpenFileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
if (Opt.ReadOnly) { //测试,只读模式
ShowMessage(0, 1, 0);
return;
}
if (fsr is null) {
ShowMessage(0, 0, 1);
return;
}
Span<byte> buffer = stackalloc byte[utf8Bom.Length];
var readLen = fsr.Read(buffer);
if (readLen == utf8Bom.Length && buffer.SequenceEqual(utf8Bom)) {
using var fsw = new FileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.Write);
using var fsw = OpenFileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.Write);
int data;
while ((data = fsr.ReadByte()) != -1) fsw.WriteByte((byte)data);
isReplaced = true;

4
src/RmBom/Option.cs Normal file
View File

@ -0,0 +1,4 @@
namespace Dot.RmBom;
[Verb("rm-bom", HelpText = nameof(Strings.TrimUtf8Bom), ResourceType = typeof(Strings))]
public class Option : DirOption { }

View File

@ -102,5 +102,9 @@ html-decode: {o.HtmlDecode}
PrintOutput(utf8);
PrintOutput(unicodeLittleEndian);
PrintOutput(unicodeBigEndian);
Console.Write(Strings.PressAnyKey);
Console.ReadKey();
}
}

View File

@ -3,6 +3,6 @@ namespace Dot.Text;
[Verb("text", HelpText = nameof(Strings.HelpForText), ResourceType = typeof(Strings))]
public class Option : IOption
{
[Value(0, HelpText = nameof(Strings.HelpForTextArg0), ResourceType = typeof(Strings))]
[Value(0, HelpText = nameof(Strings.TextTobeProcessed), ResourceType = typeof(Strings))]
public string Text { get; set; }
}

View File

@ -1,6 +1,6 @@
using System.Diagnostics.CodeAnalysis;
namespace Dot.Convert2Lf;
namespace Dot.ToLf;
public sealed class Main : Tool<Option>, IDisposable
{
@ -36,8 +36,19 @@ public sealed class Main : Tool<Option>, IDisposable
var isBin = false;
int data;
using (var fsr = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
using var fsw = new FileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.Write);
using (var fsr = OpenFileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
if (Opt.ReadOnly) { //测试,只读模式
ShowMessage(0, 1, 0);
return;
}
if (fsr is null) {
ShowMessage(0, 0, 1);
return;
}
using var fsw = OpenFileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.Write);
while ((data = fsr.ReadByte()) != -1) {
switch (data) {
@ -104,8 +115,10 @@ public sealed class Main : Tool<Option>, IDisposable
var fileList = EnumerateFiles(Opt.Path, Opt.Filter);
_totalCnt = fileList.Count();
step1Bar.Message = Strings.SearchingFileOK;
step1Bar.Message = string.Format(Strings.SearchingFileOK, _totalCnt);
step1Bar.Finished();
if (_totalCnt == 0) return;
_step2Bar = step1Bar.Spawn(_totalCnt, string.Empty, DefaultProgressBarOptions);

4
src/ToLf/Option.cs Normal file
View File

@ -0,0 +1,4 @@
namespace Dot.ToLf;
[Verb("tolf", HelpText = nameof(Strings.ConvertEndOfLineToLF), ResourceType = typeof(Strings))]
public class Option : DirOption { }

View File

@ -9,7 +9,8 @@ public abstract class Tool<TOption> : ITool
, ForegroundColor = ConsoleColor.Yellow
, ForegroundColorDone = ConsoleColor.DarkGreen
, BackgroundColor = ConsoleColor.DarkGray
, BackgroundCharacter = '\u2593'
, BackgroundCharacter = '\u2500'
, ProgressCharacter = '\u2500'
};
protected TOption Opt { get; set; }
@ -43,16 +44,23 @@ public abstract class Tool<TOption> : ITool
}
}
protected static FileStream OpenFileToWrite(string file)
protected static FileStream OpenFileStream(string file, FileMode mode, FileAccess access
, FileShare share = FileShare.Read)
{
FileStream fsr;
FileStream fsr = null;
try {
fsr = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
fsr = new FileStream(file, mode, access, share);
}
catch (UnauthorizedAccessException) {
File.SetAttributes(file, new FileInfo(file).Attributes & ~FileAttributes.ReadOnly);
fsr = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
try {
File.SetAttributes(file, new FileInfo(file).Attributes & ~FileAttributes.ReadOnly);
fsr = new FileStream(file, mode, access, share);
}
catch (Exception) {
// ignored
}
}
catch (IOException) { }
return fsr;
}

View File

@ -1,4 +1,4 @@
using Dot.TrimUtf8Bom;
using Dot.RmBom;
namespace Dot;
@ -7,13 +7,13 @@ public static class ToolsFactory
public static ITool Create(IOption option)
{
return option switch {
Option o => new Main(o)
, Convert2Lf.Option o => new Convert2Lf.Main(o)
, RemoveTrailingWhiteSpace.Option o => new RemoveTrailingWhiteSpace.Main(o)
, Pwd.Option o => new Pwd.Main(o)
, Text.Option o => new Text.Main(o)
, Guid.Option o => new Guid.Main(o)
, _ => throw new ArgumentOutOfRangeException(nameof(option))
Option o => new Main(o)
, ToLf.Option o => new ToLf.Main(o)
, RmBlank.Option o => new RmBlank.Main(o)
, Pwd.Option o => new Pwd.Main(o)
, Text.Option o => new Text.Main(o)
, Guid.Option o => new Guid.Main(o)
, _ => throw new ArgumentOutOfRangeException(nameof(option))
};
}
}

View File

@ -1,4 +0,0 @@
namespace Dot.TrimUtf8Bom;
[Verb("trim-utf8-bom", HelpText = nameof(Strings.TrimUtf8Bom), ResourceType = typeof(Strings))]
public class Option : DirOption { }

View File

@ -6,7 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Dot</RootNamespace>
<AssemblyName>dot</AssemblyName>
<Version>1.0.1</Version>
<Version>1.1.0</Version>
<Authors>nsnail</Authors>
<Copyright>Copyright (c) 2022 nsnail</Copyright>
<RepositoryUrl>https://github.com/nsnail/dot.git</RepositoryUrl>