From de264e58a0181a7198446915b5915519b2ac8eae Mon Sep 17 00:00:00 2001
From: nsnail <taokeu@gmail.com>
Date: Thu, 1 Dec 2022 17:26:37 +0800
Subject: [PATCH] 1.1.0 (#2)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* <feat> 多语言支持
* <feat> text tool 只读模式
---
 .editorconfig                |  45 ++
 .gitignore                   | 816 ++++++++++++++++++++++++++++++++++-
 .tgitconfig                  |   6 +-
 README.md                    |   3 +-
 build.ps1                    |   6 +-
 code-format.cmd              |   6 +-
 dot.sln                      |  16 +
 dot.sln.DotSettings          |  19 +-
 global.json                  |  10 +
 src/DirOption.cs             |  15 +
 src/GlobalUsings.cs          |   3 +-
 src/Guid/Main.cs             |   2 +-
 src/Guid/Option.cs           |   4 +-
 src/Lang/Strings.Designer.cs | 251 +++++++++++
 src/Lang/Strings.en-US.resx  |  86 ++++
 src/Lang/Strings.resx        |  94 ++++
 src/Pwd/Main.cs              |  53 +++
 src/Pwd/Option.cs            |  21 +
 src/RmBlank/Main.cs          | 113 +++++
 src/RmBlank/Option.cs        |   4 +
 src/RmBom/Main.cs            | 103 +++++
 src/RmBom/Option.cs          |   4 +
 src/Text/Main.cs             |   4 +-
 src/Text/Option.cs           |   4 +-
 src/ToLf/Main.cs             | 127 ++++++
 src/ToLf/Option.cs           |   4 +
 src/Tool.cs                  |  23 +-
 src/ToolsFactory.cs          |  16 +-
 src/dot.csproj               |  19 +-
 29 files changed, 1818 insertions(+), 59 deletions(-)
 create mode 100644 .editorconfig
 create mode 100644 global.json
 create mode 100644 src/DirOption.cs
 create mode 100644 src/Lang/Strings.Designer.cs
 create mode 100644 src/Lang/Strings.en-US.resx
 create mode 100644 src/Lang/Strings.resx
 create mode 100644 src/Pwd/Main.cs
 create mode 100644 src/Pwd/Option.cs
 create mode 100644 src/RmBlank/Main.cs
 create mode 100644 src/RmBlank/Option.cs
 create mode 100644 src/RmBom/Main.cs
 create mode 100644 src/RmBom/Option.cs
 create mode 100644 src/ToLf/Main.cs
 create mode 100644 src/ToLf/Option.cs

diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..8c3845c
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,45 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+
+
+# ReSharper properties
+resharper_align_linq_query = true
+resharper_align_multiline_argument = true
+resharper_align_multiline_array_and_object_initializer = true
+resharper_align_multiline_binary_patterns = true
+resharper_align_multiline_calls_chain = true
+resharper_align_multiline_extends_list = true
+resharper_align_multiline_parameter = true
+resharper_align_multiline_property_pattern = true
+resharper_align_multiline_switch_expression = true
+resharper_align_multiple_declaration = true
+resharper_align_multline_type_parameter_constrains = true
+resharper_align_multline_type_parameter_list = true
+resharper_align_tuple_components = true
+resharper_allow_comment_after_lbrace = true
+resharper_csharp_empty_block_style = together_same_line
+resharper_csharp_outdent_commas = true
+resharper_csharp_stick_comment = false
+resharper_csharp_wrap_before_comma = true
+resharper_indent_nested_foreach_stmt = true
+resharper_indent_nested_for_stmt = true
+resharper_indent_nested_while_stmt = true
+resharper_indent_preprocessor_if = usual_indent
+resharper_indent_preprocessor_other = usual_indent
+resharper_int_align = true
+resharper_keep_existing_arrangement = false
+resharper_place_linq_into_on_new_line = false
+resharper_place_simple_switch_expression_on_single_line = true
+resharper_wrap_before_eq = true
+resharper_wrap_chained_method_calls = chop_if_long
+resharper_wrap_switch_expression = chop_if_long
+
+# Microsoft .NET properties
+csharp_indent_braces = false
+csharp_new_line_before_open_brace = local_functions, methods, types
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 03eec4a..3b36b84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,23 +1,805 @@
-build
-bin
-obj
-packages
-Migrations
-_gsdata_
-_ReSharper*
-TestResults
-app_data
-nuget.config
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
 *.suo
 *.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
 *.log
+*.tlog
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
 *.pubxml
-*.publish.xml
-.svn
-.vs
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
 *.dbmdl
+*.dbproj.schemaview
 *.jfm
-*.exe
-.idea
-node_modules
-dist
\ No newline at end of file
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio 6 auto-generated project file (contains which files were open etc.)
+*.vbp
+
+# Visual Studio 6 workspace and project file (working project files containing files to include in project)
+*.dsw
+*.dsp
+
+# Visual Studio 6 technical files
+*.ncb
+*.aps
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# Visual Studio History (VSHistory) files
+.vshistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+# VS Code files for those working on multiple tools
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# JetBrains Rider
+*.sln.iml
+.idea/
+
+# User define
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.tlog
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio 6 auto-generated project file (contains which files were open etc.)
+*.vbp
+
+# Visual Studio 6 workspace and project file (working project files containing files to include in project)
+*.dsw
+*.dsp
+
+# Visual Studio 6 technical files
+*.ncb
+*.aps
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# Visual Studio History (VSHistory) files
+.vshistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+# VS Code files for those working on multiple tools
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# JetBrains Rider
+*.sln.iml
+.idea/
+
+# User Define
+build/
+nuget.config
\ No newline at end of file
diff --git a/.tgitconfig b/.tgitconfig
index c98b9ad..380a28a 100644
--- a/.tgitconfig
+++ b/.tgitconfig
@@ -1,4 +1,4 @@
 [hook "startcommit"]
-	cmdline = code-format.cmd
-	wait = true
-	show = true
\ No newline at end of file
+    cmdline = code-format.cmd
+    wait = true
+    show = true
\ No newline at end of file
diff --git a/README.md b/README.md
index 0c85949..d83fc0a 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
 # dot
-功能全面的实用工具-程序员的瑞士军刀
\ No newline at end of file
+
+A full-featured utility - the programmer's swiss army knife
\ No newline at end of file
diff --git a/build.ps1 b/build.ps1
index 58318bd..339e42a 100644
--- a/build.ps1
+++ b/build.ps1
@@ -1,3 +1,3 @@
-dotnet build 
-dotnet publish -c Release -r win-x64 --sc -p:PublishSingleFile=true -o ./build/win-x64
-rm -r ./build/temp
\ No newline at end of file
+dotnet build
+dotnet publish -c Release -r win-x64 --sc -p:"PublishSingleFile=true" -o ./build/win-x64
+Remove-Item -r ./build/temp
\ No newline at end of file
diff --git a/code-format.cmd b/code-format.cmd
index 82c9512..253fbb5 100644
--- a/code-format.cmd
+++ b/code-format.cmd
@@ -1,3 +1,3 @@
-dot trim-utf8-bom
-dot remove-whitespace
-dot convert-lf
\ No newline at end of file
+dot rm-bom
+dot rm-blank
+dot tolf
\ No newline at end of file
diff --git a/dot.sln b/dot.sln
index d27bc7f..f1cf980 100644
--- a/dot.sln
+++ b/dot.sln
@@ -5,6 +5,22 @@ VisualStudioVersion = 17.0.31903.59
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dot", "src\dot.csproj", "{E7608D54-4A3B-4B4B-ADA0-7852987CA21F}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "root-files", "root-files", "{AD79881E-74D9-4EC7-AFE9-82D10CD32C3A}"
+	ProjectSection(SolutionItems) = preProject
+		.editorconfig = .editorconfig
+		.gitattributes = .gitattributes
+		.gitignore = .gitignore
+		.tgitconfig = .tgitconfig
+		build.ps1 = build.ps1
+		code-format.cmd = code-format.cmd
+		Directory.Build.props = Directory.Build.props
+		dot.sln.DotSettings = dot.sln.DotSettings
+		git-clean.ps1 = git-clean.ps1
+		LICENSE = LICENSE
+		README.md = README.md
+		global.json = global.json
+	EndProjectSection
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
diff --git a/dot.sln.DotSettings b/dot.sln.DotSettings
index f7cba85..5f67123 100644
--- a/dot.sln.DotSettings
+++ b/dot.sln.DotSettings
@@ -1,4 +1,7 @@
-<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+<wpf:ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                        xmlns:s="clr-namespace:System;assembly=mscorlib"
+                        xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                        xml:space="preserve">
     <s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;
 &lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;
     &lt;TypePattern&gt;
@@ -36,10 +39,12 @@
         &lt;/Entry&gt;
     &lt;/TypePattern&gt;
 &lt;/Patterns&gt;</s:String>
-	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
-	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;</s:String>
-	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
-	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
-	<s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">False</s:Boolean>
-    <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=TooWideLocalVariableScope/@EntryIndexedValue">HINT</s:String>
+    <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
+    <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;</s:String>
+    <s:String
+        x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
+    <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
+    <s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">False</s:Boolean>
+    <s:String
+        x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=TooWideLocalVariableScope/@EntryIndexedValue">HINT</s:String>
 </wpf:ResourceDictionary>
\ No newline at end of file
diff --git a/global.json b/global.json
new file mode 100644
index 0000000..0e46db0
--- /dev/null
+++ b/global.json
@@ -0,0 +1,10 @@
+{
+    "sdk": {
+        "version": "7.0.100",
+        "allowPrerelease": true,
+        "rollForward": "major"
+    },
+    "tools": {
+        "dotnet": "7.0.100"
+    }
+}
\ No newline at end of file
diff --git a/src/DirOption.cs b/src/DirOption.cs
new file mode 100644
index 0000000..a86564a
--- /dev/null
+++ b/src/DirOption.cs
@@ -0,0 +1,15 @@
+namespace Dot;
+
+public class DirOption : IOption
+{
+    [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; }
+}
\ No newline at end of file
diff --git a/src/GlobalUsings.cs b/src/GlobalUsings.cs
index a9e96a1..38b2f93 100644
--- a/src/GlobalUsings.cs
+++ b/src/GlobalUsings.cs
@@ -1,2 +1,3 @@
 global using ShellProgressBar;
-global using CommandLine;
\ No newline at end of file
+global using CommandLine;
+global using Dot.Lang;
\ No newline at end of file
diff --git a/src/Guid/Main.cs b/src/Guid/Main.cs
index 7537bc3..0b157ce 100644
--- a/src/Guid/Main.cs
+++ b/src/Guid/Main.cs
@@ -12,6 +12,6 @@ public sealed class Main : Tool<Option>
         var guid            = System.Guid.NewGuid().ToString();
         if (Opt.Upper) guid = guid.ToUpper();
         ClipboardService.SetText(guid);
-        Console.WriteLine($"已复制到剪贴板:{guid}");
+        Console.WriteLine(Strings.Copied, guid);
     }
 }
\ No newline at end of file
diff --git a/src/Guid/Option.cs b/src/Guid/Option.cs
index 0c1c419..44801e2 100644
--- a/src/Guid/Option.cs
+++ b/src/Guid/Option.cs
@@ -1,8 +1,8 @@
 namespace Dot.Guid;
 
-[Verb("guid", HelpText = "GUID工具")]
+[Verb("guid", HelpText = nameof(Strings.GuidTool), ResourceType = typeof(Strings))]
 public class Option : IOption
 {
-    [Option('u', "upper", HelpText = "大写", Default = false)]
+    [Option('u', "upper", HelpText = nameof(Strings.UseUppercase), Default = false, ResourceType = typeof(Strings))]
     public bool Upper { get; set; } //normal options here
 }
\ No newline at end of file
diff --git a/src/Lang/Strings.Designer.cs b/src/Lang/Strings.Designer.cs
new file mode 100644
index 0000000..b053a6d
--- /dev/null
+++ b/src/Lang/Strings.Designer.cs
@@ -0,0 +1,251 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Dot.Lang {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    public class Strings {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Strings() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        public static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Dot.Lang.Strings", typeof(Strings).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        public static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 转换换行符为LF.
+        /// </summary>
+        public static string ConvertEndOfLineToLF {
+            get {
+                return ResourceManager.GetString("ConvertEndOfLineToLF", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to {0}(已复制到剪贴板).
+        /// </summary>
+        public static string Copied {
+            get {
+                return ResourceManager.GetString("Copied", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 文件通配符.
+        /// </summary>
+        public static string FileSearchPattern {
+            get {
+                return ResourceManager.GetString("FileSearchPattern", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 要处理的目录路径.
+        /// </summary>
+        public static string FolderPath {
+            get {
+                return ResourceManager.GetString("FolderPath", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to GUID工具.
+        /// </summary>
+        public static string GuidTool {
+            get {
+                return ResourceManager.GetString("GuidTool", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 文本编码工具.
+        /// </summary>
+        public static string HelpForText {
+            get {
+                return ResourceManager.GetString("HelpForText", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 输入文本为空.
+        /// </summary>
+        public static string InputTextIsEmpty {
+            get {
+                return ResourceManager.GetString("InputTextIsEmpty", resourceCulture);
+            }
+        }
+        
+        /// <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>
+        public static string PathNotFound {
+            get {
+                return ResourceManager.GetString("PathNotFound", resourceCulture);
+            }
+        }
+        
+        /// <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>
+        public static string PwdGenerateTypes {
+            get {
+                return ResourceManager.GetString("PwdGenerateTypes", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 密码长度.
+        /// </summary>
+        public static string PwdLength {
+            get {
+                return ResourceManager.GetString("PwdLength", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 随机密码生成器.
+        /// </summary>
+        public static string RandomPasswordGenerator {
+            get {
+                return ResourceManager.GetString("RandomPasswordGenerator", resourceCulture);
+            }
+        }
+        
+        /// <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>
+        public static string RemoveTrailingWhiteSpaces {
+            get {
+                return ResourceManager.GetString("RemoveTrailingWhiteSpaces", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 查找文件....
+        /// </summary>
+        public static string SearchingFile {
+            get {
+                return ResourceManager.GetString("SearchingFile", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to {0} 个文件.
+        /// </summary>
+        public static string SearchingFileOK {
+            get {
+                return ResourceManager.GetString("SearchingFileOK", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 已读取:{0}/{1},处理:{2},跳过:{3}.
+        /// </summary>
+        public static string ShowMessageTemp {
+            get {
+                return ResourceManager.GetString("ShowMessageTemp", resourceCulture);
+            }
+        }
+        
+        /// <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>
+        public static string TrimUtf8Bom {
+            get {
+                return ResourceManager.GetString("TrimUtf8Bom", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 使用大写输出.
+        /// </summary>
+        public static string UseUppercase {
+            get {
+                return ResourceManager.GetString("UseUppercase", resourceCulture);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Lang/Strings.en-US.resx b/src/Lang/Strings.en-US.resx
new file mode 100644
index 0000000..d9d42b0
--- /dev/null
+++ b/src/Lang/Strings.en-US.resx
@@ -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>
\ No newline at end of file
diff --git a/src/Lang/Strings.resx b/src/Lang/Strings.resx
new file mode 100644
index 0000000..49467fb
--- /dev/null
+++ b/src/Lang/Strings.resx
@@ -0,0 +1,94 @@
+<?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>输入文本为空</value>
+    </data>
+    <data name="SearchingFile" xml:space="preserve">
+        <value>查找文件...</value>
+    </data>
+    <data name="PathNotFound" xml:space="preserve">
+        <value>指定的路径“{0}”不存在</value>
+    </data>
+    <data name="SearchingFileOK" xml:space="preserve">
+        <value>{0} 个文件</value>
+    </data>
+    <data name="ShowMessageTemp" xml:space="preserve">
+        <value>已读取:{0}/{1},处理:{2},跳过:{3}</value>
+    </data>
+    <data name="HelpForText" xml:space="preserve">
+        <value>文本编码工具</value>
+    </data>
+    <data name="TextTobeProcessed" xml:space="preserve">
+        <value>要处理的文本(默认取取剪贴板值)</value>
+    </data>
+    <data name="Copied" xml:space="preserve">
+        <value>{0}(已复制到剪贴板)</value>
+    </data>
+    <data name="FileSearchPattern" xml:space="preserve">
+        <value>文件通配符</value>
+    </data>
+    <data name="FolderPath" xml:space="preserve">
+        <value>要处理的目录路径</value>
+    </data>
+    <data name="ConvertEndOfLineToLF" xml:space="preserve">
+        <value>转换换行符为LF</value>
+    </data>
+    <data name="GuidTool" xml:space="preserve">
+        <value>GUID工具</value>
+    </data>
+    <data name="UseUppercase" xml:space="preserve">
+        <value>使用大写输出</value>
+    </data>
+    <data name="RandomPasswordGenerator" xml:space="preserve">
+        <value>随机密码生成器</value>
+    </data>
+
+    <data name="PwdLength" xml:space="preserve">
+        <value>密码长度</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>移除文件尾部换行和空格</value>
+    </data>
+    <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>
\ No newline at end of file
diff --git a/src/Pwd/Main.cs b/src/Pwd/Main.cs
new file mode 100644
index 0000000..7cdf363
--- /dev/null
+++ b/src/Pwd/Main.cs
@@ -0,0 +1,53 @@
+using NSExt.Extensions;
+using TextCopy;
+
+namespace Dot.Pwd;
+
+public sealed class Main : Tool<Option>
+{
+    private readonly char[][] _charTable = {
+                                               "0123456789".ToCharArray() //
+                                             , "abcdefghijklmnopqrstuvwxyz".ToCharArray()
+                                             , "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()
+                                             , "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".ToCharArray()
+                                           };
+
+
+    public Main(Option opt) : base(opt) { }
+
+    public override void Run()
+    {
+        unsafe {
+            var pSource   = stackalloc char[_charTable.Sum(x => x.Length)];
+            var pDest     = stackalloc char[Opt.Length];
+            var sourceLen = 0;
+
+            if (Opt.Type.HasFlag(Option.GenerateTypes.Number))
+                foreach (var c in _charTable[0])
+                    *(pSource + sourceLen++) = c;
+
+
+            if (Opt.Type.HasFlag(Option.GenerateTypes.LowerCaseLetter))
+                foreach (var c in _charTable[1])
+                    *(pSource + sourceLen++) = c;
+
+            if (Opt.Type.HasFlag(Option.GenerateTypes.UpperCaseLetter))
+                foreach (var c in _charTable[2])
+                    *(pSource + sourceLen++) = c;
+
+
+            if (Opt.Type.HasFlag(Option.GenerateTypes.SpecialCharacter))
+                foreach (var c in _charTable[3])
+                    *(pSource + sourceLen++) = c;
+
+
+            var randScope = new[] { 0, sourceLen };
+            for (var i = 0; i != Opt.Length; ++i) //
+                *(pDest + i) = *(pSource + randScope.Rand());
+
+            var result = new string(pDest, 0, Opt.Length);
+            ClipboardService.SetText(result);
+            Console.WriteLine(Strings.Copied, result);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Pwd/Option.cs b/src/Pwd/Option.cs
new file mode 100644
index 0000000..80f9558
--- /dev/null
+++ b/src/Pwd/Option.cs
@@ -0,0 +1,21 @@
+namespace Dot.Pwd;
+
+[Verb("pwd", HelpText = nameof(Strings.RandomPasswordGenerator), ResourceType = typeof(Strings))]
+public class Option : IOption
+{
+    [Flags]
+    public enum GenerateTypes
+    {
+        Number           = 1
+      , LowerCaseLetter  = 2
+      , UpperCaseLetter  = 4
+      , SpecialCharacter = 8
+    }
+
+    [Value(1, Required = true, HelpText = nameof(Strings.PwdLength), ResourceType = typeof(Strings))]
+    public int Length { get; set; }
+
+
+    [Value(0, Required = true, HelpText = nameof(Strings.PwdGenerateTypes), ResourceType = typeof(Strings))]
+    public GenerateTypes Type { get; set; }
+}
\ No newline at end of file
diff --git a/src/RmBlank/Main.cs b/src/RmBlank/Main.cs
new file mode 100644
index 0000000..d1af5bc
--- /dev/null
+++ b/src/RmBlank/Main.cs
@@ -0,0 +1,113 @@
+using System.Diagnostics.CodeAnalysis;
+using NSExt.Extensions;
+
+namespace Dot.RmBlank;
+
+public sealed class Main : Tool<Option>, IDisposable
+{
+    private                 int              _breakCnt;
+    private                 bool             _disposed;
+    private static readonly object           _lockObj = new();
+    private                 int              _procedCnt;
+    private                 int              _replaceCnt;
+    private                 ChildProgressBar _step2Bar;
+    private                 int              _totalCnt;
+    public Main(Option opt) : base(opt) { }
+
+
+    ~Main()
+    {
+        Dispose(false);
+    }
+
+    private void Dispose(bool disposing)
+    {
+        if (_disposed) return;
+        if (disposing) _step2Bar?.Dispose();
+        _disposed = true;
+    }
+
+    private void FileHandle(string file)
+    {
+        _step2Bar.Tick();
+        ShowMessage(1, 0, 0);
+        var spacesCnt = 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;
+        }
+
+        fsrw.Seek(0, SeekOrigin.Begin);
+        if (!fsrw.IsTextStream()) return;
+        ShowMessage(0, 1, 0);
+        fsrw.SetLength(fsrw.Length - spacesCnt);
+    }
+
+    private static int GetSpacesCnt(Stream fsr)
+    {
+        var trimLen = 0;
+        fsr.Seek(-1, SeekOrigin.End);
+        int data;
+        while ((data = fsr.ReadByte()) != -1)
+            if (new[] { 0x20, 0x0d, 0x0a }.Contains(data)) {
+                ++trimLen;
+                if (fsr.Position - 2 < 0) break;
+                fsr.Seek(-2, SeekOrigin.Current);
+            }
+            else {
+                break;
+            }
+
+        return trimLen;
+    }
+
+
+    private void ShowMessage(int procedCnt, int removeCnt, int breakCnt)
+    {
+        lock (_lockObj) {
+            _procedCnt        += procedCnt;
+            _replaceCnt       += removeCnt;
+            _breakCnt         += breakCnt;
+            _step2Bar.Message =  string.Format(Strings.ShowMessageTemp, _procedCnt, _totalCnt, _replaceCnt, _breakCnt);
+        }
+    }
+
+    public void Dispose()
+    {
+        Dispose(true);
+        GC.SuppressFinalize(this);
+    }
+
+    /// <inheritdoc />
+    [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
+    public override void Run()
+    {
+        if (!Directory.Exists(Opt.Path))
+            throw new ArgumentException(nameof(Opt.Path), string.Format(Strings.PathNotFound, Opt.Path));
+
+
+        using var step1Bar = new IndeterminateProgressBar(Strings.SearchingFile, DefaultProgressBarOptions);
+
+
+        var fileList = EnumerateFiles(Opt.Path, Opt.Filter);
+        _totalCnt = fileList.Count();
+
+        step1Bar.Message = string.Format(Strings.SearchingFileOK, _totalCnt);
+        step1Bar.Finished();
+        if (_totalCnt == 0) return;
+
+
+        _step2Bar = step1Bar.Spawn(_totalCnt, string.Empty, DefaultProgressBarOptions);
+
+        Parallel.ForEach(fileList, FileHandle);
+    }
+}
\ No newline at end of file
diff --git a/src/RmBlank/Option.cs b/src/RmBlank/Option.cs
new file mode 100644
index 0000000..e9523d9
--- /dev/null
+++ b/src/RmBlank/Option.cs
@@ -0,0 +1,4 @@
+namespace Dot.RmBlank;
+
+[Verb("rm-blank", HelpText = nameof(Strings.RemoveTrailingWhiteSpaces), ResourceType = typeof(Strings))]
+public class Option : DirOption { }
\ No newline at end of file
diff --git a/src/RmBom/Main.cs b/src/RmBom/Main.cs
new file mode 100644
index 0000000..c38a003
--- /dev/null
+++ b/src/RmBom/Main.cs
@@ -0,0 +1,103 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace Dot.RmBom;
+
+public sealed class Main : Tool<Option>, IDisposable
+{
+    private                 int              _breakCnt;
+    private                 bool             _disposed;
+    private static readonly object           _lockObj = new();
+    private                 int              _procedCnt;
+    private                 ChildProgressBar _step2Bar;
+    private                 int              _totalCnt;
+    private                 int              _trimCnt;
+    public Main(Option opt) : base(opt) { }
+
+
+    ~Main()
+    {
+        Dispose(false);
+    }
+
+    private void Dispose(bool disposing)
+    {
+        if (_disposed) return;
+        if (disposing) _step2Bar?.Dispose();
+        _disposed = true;
+    }
+
+
+    private void ShowMessage(int procedCnt, int replaceCnt, int breakCnt)
+    {
+        lock (_lockObj) {
+            _procedCnt        += procedCnt;
+            _trimCnt          += replaceCnt;
+            _breakCnt         += breakCnt;
+            _step2Bar.Message =  string.Format(Strings.ShowMessageTemp, _procedCnt, _totalCnt, _trimCnt, _breakCnt);
+        }
+    }
+
+    public void Dispose()
+    {
+        Dispose(true);
+        GC.SuppressFinalize(this);
+    }
+
+    [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
+    public override void Run()
+    {
+        if (!Directory.Exists(Opt.Path))
+            throw new ArgumentException(nameof(Opt.Path), string.Format(Strings.PathNotFound, Opt.Path));
+
+
+        var       utf8Bom  = new byte[] { 0xef, 0xbb, 0xbf };
+        using var step1Bar = new IndeterminateProgressBar(Strings.SearchingFile, DefaultProgressBarOptions);
+
+
+        var fileList = EnumerateFiles(Opt.Path, Opt.Filter);
+        _totalCnt = fileList.Count();
+
+        step1Bar.Message = string.Format(Strings.SearchingFileOK, _totalCnt);
+        step1Bar.Finished();
+        if (_totalCnt == 0) return;
+
+        _step2Bar = step1Bar.Spawn(_totalCnt, string.Empty, DefaultProgressBarOptions);
+
+        Parallel.ForEach(fileList, file => {
+            _step2Bar.Tick();
+            ShowMessage(1, 0, 0);
+
+            var tmpFile    = $"{file}.tmp";
+            var isReplaced = false;
+            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 = OpenFileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.Write);
+                    int       data;
+                    while ((data = fsr.ReadByte()) != -1) fsw.WriteByte((byte)data);
+                    isReplaced = true;
+                }
+            }
+
+            if (isReplaced) {
+                MoveFile(tmpFile, file);
+                ShowMessage(0, 1, 0);
+            }
+            else {
+                ShowMessage(0, 0, 1);
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/src/RmBom/Option.cs b/src/RmBom/Option.cs
new file mode 100644
index 0000000..579a772
--- /dev/null
+++ b/src/RmBom/Option.cs
@@ -0,0 +1,4 @@
+namespace Dot.RmBom;
+
+[Verb("rm-bom", HelpText = nameof(Strings.TrimUtf8Bom), ResourceType = typeof(Strings))]
+public class Option : DirOption { }
\ No newline at end of file
diff --git a/src/Text/Main.cs b/src/Text/Main.cs
index b84dd1a..f083935 100644
--- a/src/Text/Main.cs
+++ b/src/Text/Main.cs
@@ -28,7 +28,7 @@ public sealed class Main : Tool<Option>
     public Main(Option opt) : base(opt)
     {
         if (Opt.Text.NullOrEmpty()) Opt.Text = ClipboardService.GetText();
-        if (Opt.Text.NullOrEmpty()) throw new ArgumentException("输入文本为空");
+        if (Opt.Text.NullOrEmpty()) throw new ArgumentException(Strings.InputTextIsEmpty);
     }
 
     private static Output BuildOutput(string text, Encoding enc)
@@ -102,5 +102,7 @@ html-decode:       {o.HtmlDecode}
         PrintOutput(utf8);
         PrintOutput(unicodeLittleEndian);
         PrintOutput(unicodeBigEndian);
+        Console.Write(Strings.PressAnyKey);
+        Console.ReadKey();
     }
 }
\ No newline at end of file
diff --git a/src/Text/Option.cs b/src/Text/Option.cs
index 3ce844b..17af8ac 100644
--- a/src/Text/Option.cs
+++ b/src/Text/Option.cs
@@ -1,8 +1,8 @@
 namespace Dot.Text;
 
-[Verb("text", HelpText = "文本编码工具")]
+[Verb("text", HelpText = nameof(Strings.HelpForText), ResourceType = typeof(Strings))]
 public class Option : IOption
 {
-    [Value(0, MetaName = "文本", HelpText = "要处理的文本,不指定此参数:取剪贴板值")]
+    [Value(0, HelpText = nameof(Strings.TextTobeProcessed), ResourceType = typeof(Strings))]
     public string Text { get; set; }
 }
\ No newline at end of file
diff --git a/src/ToLf/Main.cs b/src/ToLf/Main.cs
new file mode 100644
index 0000000..e53741b
--- /dev/null
+++ b/src/ToLf/Main.cs
@@ -0,0 +1,127 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace Dot.ToLf;
+
+public sealed class Main : Tool<Option>, IDisposable
+{
+    private                 int              _breakCnt;
+    private                 bool             _disposed;
+    private static readonly object           _lockObj = new();
+    private                 int              _procedCnt;
+    private                 int              _replaceCnt;
+    private                 ChildProgressBar _step2Bar;
+    private                 int              _totalCnt;
+    public Main(Option opt) : base(opt) { }
+
+
+    ~Main()
+    {
+        Dispose(false);
+    }
+
+    private void Dispose(bool disposing)
+    {
+        if (_disposed) return;
+        if (disposing) _step2Bar?.Dispose();
+        _disposed = true;
+    }
+
+    private void FileHandle(string file)
+    {
+        _step2Bar.Tick();
+        ShowMessage(1, 0, 0);
+
+        var tmpFile    = $"{file}.tmp";
+        var isReplaced = false;
+        var isBin      = false;
+        int data;
+
+        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) {
+                    case 0x0d when fsr.ReadByte() == 0x0a: // crlf windows
+                        fsw.WriteByte(0x0a);
+                        isReplaced = true;
+                        continue;
+                    case 0x0d: //cr macos
+                        fsw.WriteByte(0x0a);
+                        fsr.Seek(-1, SeekOrigin.Current);
+                        isReplaced = true;
+                        continue;
+                    case 0x00 or 0xff: //非文本文件
+                        isBin = true;
+                        break;
+                    default:
+                        fsw.WriteByte((byte)data);
+                        continue;
+                }
+
+                break;
+            }
+        }
+
+
+        if (isReplaced && !isBin) {
+            MoveFile(tmpFile, file);
+
+            ShowMessage(0, 1, 0);
+        }
+        else {
+            File.Delete(tmpFile);
+            ShowMessage(0, 0, 1);
+        }
+    }
+
+
+    private void ShowMessage(int procedCnt, int replaceCnt, int breakCnt)
+    {
+        lock (_lockObj) {
+            _procedCnt        += procedCnt;
+            _replaceCnt       += replaceCnt;
+            _breakCnt         += breakCnt;
+            _step2Bar.Message =  string.Format(Strings.ShowMessageTemp, _procedCnt, _totalCnt, _replaceCnt, _breakCnt);
+        }
+    }
+
+    public void Dispose()
+    {
+        Dispose(true);
+        GC.SuppressFinalize(this);
+    }
+
+    [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
+    public override void Run()
+    {
+        if (!Directory.Exists(Opt.Path))
+            throw new ArgumentException(nameof(Opt.Path), string.Format(Strings.PathNotFound, Opt.Path));
+
+
+        using var step1Bar = new IndeterminateProgressBar(Strings.SearchingFile, DefaultProgressBarOptions);
+
+
+        var fileList = EnumerateFiles(Opt.Path, Opt.Filter);
+        _totalCnt = fileList.Count();
+
+        step1Bar.Message = string.Format(Strings.SearchingFileOK, _totalCnt);
+        step1Bar.Finished();
+        if (_totalCnt == 0) return;
+
+
+        _step2Bar = step1Bar.Spawn(_totalCnt, string.Empty, DefaultProgressBarOptions);
+
+        Parallel.ForEach(fileList, FileHandle);
+    }
+}
\ No newline at end of file
diff --git a/src/ToLf/Option.cs b/src/ToLf/Option.cs
new file mode 100644
index 0000000..e5637f2
--- /dev/null
+++ b/src/ToLf/Option.cs
@@ -0,0 +1,4 @@
+namespace Dot.ToLf;
+
+[Verb("tolf", HelpText = nameof(Strings.ConvertEndOfLineToLF), ResourceType = typeof(Strings))]
+public class Option : DirOption { }
\ No newline at end of file
diff --git a/src/Tool.cs b/src/Tool.cs
index ff4641c..1f06c3e 100644
--- a/src/Tool.cs
+++ b/src/Tool.cs
@@ -9,10 +9,11 @@ public abstract class Tool<TOption> : ITool
                                             , ForegroundColor     = ConsoleColor.Yellow
                                             , ForegroundColorDone = ConsoleColor.DarkGreen
                                             , BackgroundColor     = ConsoleColor.DarkGray
-                                            , BackgroundCharacter = '\u2593'
+                                            , BackgroundCharacter = '\u2500'
+                                            , ProgressCharacter   = '\u2500'
                                           };
 
-    protected virtual TOption Opt { get; set; }
+    protected TOption Opt { get; set; }
 
     protected Tool(TOption opt)
     {
@@ -43,17 +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;
     }
 
diff --git a/src/ToolsFactory.cs b/src/ToolsFactory.cs
index b02ca76..67d2f1f 100644
--- a/src/ToolsFactory.cs
+++ b/src/ToolsFactory.cs
@@ -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)
-                 , Random.Option o                   => new Random.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))
                };
     }
 }
\ No newline at end of file
diff --git a/src/dot.csproj b/src/dot.csproj
index b168f25..ec1a403 100644
--- a/src/dot.csproj
+++ b/src/dot.csproj
@@ -6,12 +6,12 @@
         <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>
         <RepositoryType>git</RepositoryType>
-        <AssemblyTitle>功能全面的实用工具-程序员的瑞士军刀</AssemblyTitle>
+        <AssemblyTitle>功能全面的实用工具 - 程序员的瑞士军刀</AssemblyTitle>
     </PropertyGroup>
 
     <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
@@ -29,4 +29,19 @@
         <PackageReference Include="TextCopy" Version="6.2.0"/>
     </ItemGroup>
 
+    <ItemGroup>
+        <EmbeddedResource Update="Lang\Strings.resx">
+            <Generator>PublicResXFileCodeGenerator</Generator>
+            <LastGenOutput>Strings.Designer.cs</LastGenOutput>
+        </EmbeddedResource>
+    </ItemGroup>
+
+    <ItemGroup>
+        <Compile Update="Lang\Strings.Designer.cs">
+            <DesignTime>True</DesignTime>
+            <AutoGen>True</AutoGen>
+            <DependentUpon>Strings.resx</DependentUpon>
+        </Compile>
+    </ItemGroup>
+
 </Project>
\ No newline at end of file