diff --git a/docs/cs/Contribution/Index.md b/docs/cs/Contribution/Index.md index fd7f65d14e..ac1aaf00c1 100644 --- a/docs/cs/Contribution/Index.md +++ b/docs/cs/Contribution/Index.md @@ -41,7 +41,9 @@ Nový jazyk je publikován jakmile jsou minimálně tyto překlady dokončeny. ABP framework má flexibilní [lokalizační systém](../Localization.md). Můžete tak vytvořit lokalizované uživatelské prostředí pro svou vlastní aplikaci. -K tomu mají framework a vestavěné moduly již lokalizované texty. Například [lokalizační texty pro Volo.Abp.UI balík](https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json). Můžete vytvořit nový soubor ve [stejné složce](https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi) k přidání překladu. +K tomu mají framework a vestavěné moduly již lokalizované texty. Například [lokalizační texty pro Volo.Abp.UI balík](https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json). + +Můžete vytvořit nový soubor ve [stejné složce](https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi) k přidání překladu. * Naklonujte [ABP repozitář](https://github.com/abpframework/abp/) z Githubu. * Vytvořte nový soubor pro cílový jazyk pro lokalizační text v (json) souboru (u souboru en.json). @@ -49,6 +51,8 @@ K tomu mají framework a vestavěné moduly již lokalizované texty. Napříkla * Přeložte texty. * Zašlete pull request na Githubu. +K překladu lokalizovaných textů můžete také použít příkaz `abp translate` of [ABP CLI](CLI.md). + ABP je modulářní framework, proto je zde mnoho zdrojů lokalizačních textů, jeden pro každý modul. K najití všech .json souborů, vyhledejte po naklonování repozitáře soubory "en.json". Můžete se taky podívat na [tento seznam](Localization-Text-Files.md) souborů lokalizačních textů. ### Příspevky do blogu a návody diff --git a/docs/cs/Contribution/Localization-Text-Files.md b/docs/cs/Contribution/Localization-Text-Files.md deleted file mode 100644 index fc9567dbb1..0000000000 --- a/docs/cs/Contribution/Localization-Text-Files.md +++ /dev/null @@ -1,40 +0,0 @@ -## Textové soubory pro lokalizaci - -Toto je seznam lokalizačních textových souborů pro každého kdo chce přispět k překladu textů ve frameworku. Tento seznam budeme udržovat aktuální: - -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/en.json -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json -* https://github.com/abpframework/abp/tree/master/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/en.json -* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Web/Localization/Resources/Blogging/Web/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Web/Localization/Resources/Docs/Web/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/Localization/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Localization/Resources/FeatureManagement/en.json -* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Localization/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json -* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Localization/Resources/AbpPermissionManagement/en.json -* https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Localization/Resources/AbpSettingManagement/en.json -* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts/Volo/Abp/TenantManagement/Localization/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Localization/Resources/AbpTenantManagement/Web/en.json -* https://github.com/abpframework/abp-samples/tree/master/BookStore/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json -* https://github.com/abpframework/abp-samples/tree/master/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/en.json -* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/en.json -* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Application.Contracts/Localization/MyProjectName/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/DomainShared/en.json -* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Web/Localization/MyProjectName/Web/en.json -* https://github.com/abpframework/abp/tree/master/templates/mvc/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json diff --git a/docs/en/CLI.md b/docs/en/CLI.md index d9b6832dd5..3320581fcb 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -138,6 +138,29 @@ abp update [options] * `--solution-path` or `-sp`: Specify the solution path. Use the current directory by default * `--solution-name` or `-sn`: Specify the solution name. Search `*.sln` files in the directory by default. + +### translate + +This command will create a unified json file based on the reference culture. It will search all localized `json` files in the current directory. It will include the localized translations that are missing from the reference culture. You can complete the translation in this `json`(eg: `abp-translation.json`) file. + +Finally, use `abp translate --apply` to submit the changes.This command will synchronize your translated text to the localized `json` file in the project. You can view the changes of localized information through git. + +Usage: + +````bash +abp translate [options] +```` + +#### Options + +* `--culture` or `-c`: Target culture. eg: `zh-Hans` +* `--reference-culture` or `-r`: Default `en` +* `--output` or `-o`: Output file name. Default `abp-translation.json`. +* `--all-values` or `-all`: Include all keys. Default `false` +* `--apply` or `-a`: Creates or updates the file for the translated culture. +* `--file` or `-f`: Default: `abp-translation.json` + + ### switch-to-preview You can use this command to switch your project to latest preview version of the ABP framework packages. @@ -147,6 +170,7 @@ Usage: ````bash abp switch-to-preview [options] ```` + #### Options `--solution-directory` or `-sd`: Specifies the directory. The solution should be in that directory or in any of its sub directories. If not specified, default is the current directory. diff --git a/docs/en/Contribution/Index.md b/docs/en/Contribution/Index.md index ba755426de..d753dc6bc2 100644 --- a/docs/en/Contribution/Index.md +++ b/docs/en/Contribution/Index.md @@ -41,7 +41,9 @@ A new language is published after these minimum translations have been completed ABP framework has a flexible [localization system](../Localization.md). You can create localized user interfaces for your own application. -In addition to that, the framework and pre-build modules have already localized texts. As an example, see [the localization texts for the Volo.Abp.UI package](https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json). You can create a new file in the [same folder](https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi) to translate it. +In addition to that, the framework and pre-build modules have already localized texts. As an example, see [the localization texts for the Volo.Abp.UI package](https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json). + +You can create a new file in the [same folder](https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi) to translate it. * Clone the [ABP repository](https://github.com/abpframework/abp/) from Github. * Create a new file for the target language for a localization text (json) file (near to the en.json file). @@ -49,6 +51,8 @@ In addition to that, the framework and pre-build modules have already localized * Translate the texts. * Send pull request on Github. +You can also use the `abp translate` command of [ABP CLI](CLI.md) to translate localized texts. + ABP is a modular framework. So there are many localization text resource, one per module. To find all .json files, you can search for "en.json" after cloning the repository. You can also check [this list](Localization-Text-Files.md) for a list of localization text files. ### Blog Posts & Tutorials diff --git a/docs/en/Contribution/Localization-Text-Files.md b/docs/en/Contribution/Localization-Text-Files.md deleted file mode 100644 index fc4b116967..0000000000 --- a/docs/en/Contribution/Localization-Text-Files.md +++ /dev/null @@ -1,31 +0,0 @@ -## Localization Text Files - -Here, a list of localization text files for anyone wants to contribute to localization of the texts coming from the framework. We will keep this list up to date: - -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json -* https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json -* https://github.com/abpframework/abp/blob/master/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json -* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json -* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/en.json -* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json -* https://github.com/abpframework/abp-samples/tree/master/BookStore/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json -* https://github.com/abpframework/abp-samples/tree/master/DashboardDemo/src/DashboardDemo.Domain.Shared/Localization/DashboardDemo/en.json -* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/en.json -* https://github.com/abpframework/abp/tree/master/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json diff --git a/docs/zh-Hans/Contribution/Index.md b/docs/zh-Hans/Contribution/Index.md index 9b645c34c3..058f195b0a 100644 --- a/docs/zh-Hans/Contribution/Index.md +++ b/docs/zh-Hans/Contribution/Index.md @@ -41,7 +41,9 @@ ABP是[开源](https://github.com/abpframework)和社区驱动项目. 本指南 ABP框架具有灵活的[本地化系统](../Localization.md). 你可以为自己的应用程序创建本地化用户界面. -除此之外,框架和预构建模块已经本地化了文本.请参阅[Volo.Abp.UI包的本地化文本](https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json).你可以在[相同文件夹](https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi)中创建一个新文件进行翻译. +除此之外,框架和预构建模块已经本地化了文本.请参阅[Volo.Abp.UI包的本地化文本](https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json). + +你可以在[相同文件夹](https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi)中创建一个新文件进行翻译. * 从Github克隆[ABP存储库](https://github.com/abpframework/abp/). * 为本地化文本(json)文件(en.json文件同目录下)创建目标语言的新文件. @@ -49,6 +51,9 @@ ABP框架具有灵活的[本地化系统](../Localization.md). 你可以为自 * 翻译文本. * 在Github上发送拉取请求(Pull request). + +你还可以使用[ABP CLI](CLI.md)的`abp translation`命令来翻译本地化文本. + ABP是一个模块化框架. 所以有很多本地化文本资源, 每个模块都有一个. 要查找所有.json文件,可以在克隆存储库后搜索"en.json". 你还可以检查[此列表](Localization-Text-Files.md)以获取本地化文本文件列表. ### 博客文章和教程 diff --git a/docs/zh-Hans/Contribution/Localization-Text-Files.md b/docs/zh-Hans/Contribution/Localization-Text-Files.md deleted file mode 100644 index 93132f516a..0000000000 --- a/docs/zh-Hans/Contribution/Localization-Text-Files.md +++ /dev/null @@ -1,31 +0,0 @@ -## 本地化文本文件 - -这是一个来自框架的本地化文本文件列表, 任何人都可以做出贡献. 我们会将此列表保持最新: - -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json -* https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json -* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json -* https://github.com/abpframework/abp/blob/master/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json -* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json -* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/en.json -* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json -* https://github.com/abpframework/abp-samples/tree/master/BookStore/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json -* https://github.com/abpframework/abp-samples/tree/master/DashboardDemo/src/DashboardDemo.Domain.Shared/Localization/DashboardDemo/en.json -* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/en.json -* https://github.com/abpframework/abp/tree/master/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs index f5a5a44980..dbffa820c8 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs @@ -28,11 +28,12 @@ namespace Volo.Abp.Cli options.Commands["add-package"] = typeof(AddPackageCommand); options.Commands["add-module"] = typeof(AddModuleCommand); options.Commands["login"] = typeof(LoginCommand); - options.Commands["logout"] = typeof(LogoutCommand); - options.Commands["generate-proxy"] = typeof(GenerateProxyCommand); + options.Commands["logout"] = typeof(LogoutCommand); + options.Commands["generate-proxy"] = typeof(GenerateProxyCommand); options.Commands["suite"] = typeof(SuiteCommand); options.Commands["switch-to-preview"] = typeof(SwitchNightlyPreviewCommand); - options.Commands["switch-to-stable"] = typeof(SwitchStableCommand); + options.Commands["switch-to-stable"] = typeof(SwitchStableCommand); + options.Commands["translate"] = typeof(TranslateCommand); }); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/TranslateCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/TranslateCommand.cs new file mode 100644 index 0000000000..953323fe3a --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/TranslateCommand.cs @@ -0,0 +1,443 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Volo.Abp.Cli.Args; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.Commands +{ + public class TranslateCommand: IConsoleCommand, ITransientDependency + { + public ILogger Logger { get; set; } + + public Task ExecuteAsync(CommandLineArgs commandLineArgs) + { + var currentDirectory = Directory.GetCurrentDirectory(); + + var apply = commandLineArgs.Options.ContainsKey(Options.Apply.Short) || commandLineArgs.Options.ContainsKey(Options.Apply.Long); + if (apply) + { + var inputFile = Path.Combine(currentDirectory, + commandLineArgs.Options.GetOrNull(Options.File.Short, Options.File.Long) + ?? "abp-translation.json"); + + Logger.LogInformation("Abp translate apply..."); + Logger.LogInformation("Input file: " + inputFile); + + ApplyAbpTranslateInfo(currentDirectory, inputFile); + } + else + { + var targetCulture = commandLineArgs.Options.GetOrNull(Options.Culture.Short, Options.Culture.Long); + if (targetCulture == null) + { + throw new CliUsageException( + "Target culture is missing!" + + Environment.NewLine + Environment.NewLine + + GetUsageInfo() + ); + } + + var referenceCulture = commandLineArgs.Options.GetOrNull(Options.ReferenceCulture.Short, Options.ReferenceCulture.Long) + ?? "en"; + + var outputFile = Path.Combine(currentDirectory, + commandLineArgs.Options.GetOrNull(Options.Output.Short, Options.Output.Long) + ?? "abp-translation.json"); + + var allValues = commandLineArgs.Options.ContainsKey(Options.AllValues.Short) || + commandLineArgs.Options.ContainsKey(Options.AllValues.Long); + + Logger.LogInformation("Abp translate..."); + Logger.LogInformation("Target culture: " + targetCulture); + Logger.LogInformation("Reference culture: " + referenceCulture); + Logger.LogInformation("Output file: " + outputFile); + if (allValues) + { + Logger.LogInformation("Include all keys"); + } + + var translateInfo = GetAbpTranslateInfo(currentDirectory, targetCulture, referenceCulture, allValues); + + File.WriteAllText(outputFile, JsonConvert.SerializeObject(translateInfo, Formatting.Indented)); + + Logger.LogInformation($"The translation file has been created."); + } + + return Task.CompletedTask; + } + + private AbpTranslateInfo GetAbpTranslateInfo(string directory, string targetCultureName, string referenceCultureName, bool allValues) + { + var translateInfo = new AbpTranslateInfo + { + ReferenceCulture = referenceCultureName, + TargetCulture = targetCultureName, + Resources = new List() + }; + + var referenceCultureFiles = GetCultureJsonFiles(directory, referenceCultureName); + foreach (var filePath in referenceCultureFiles) + { + var directoryName = Path.GetDirectoryName(filePath) ?? string.Empty; + + var referenceLocalizationInfo = GetAbpLocalizationInfoOrNull(filePath); + if (referenceLocalizationInfo == null) // Not abp json file + { + continue; + } + + var resource = new AbpTranslateResource + { + ResourcePath = directoryName, + Texts = new List() + }; + + foreach (var text in referenceLocalizationInfo.Texts) + { + resource.Texts.Add(new AbpTranslateResourceText + { + LocalizationKey = text.Name, + Reference = text.Value, + Target = string.Empty + }); + } + + //Use target json file content to fill resource texts + var targetFile = Path.Combine(directoryName, $"{targetCultureName}.json"); + if (File.Exists(targetFile)) + { + var targetLocalizationInfo = GetAbpLocalizationInfoOrNull(targetFile); + foreach (var referenceResourceText in resource.Texts) + { + var text = targetLocalizationInfo.Texts.FirstOrDefault(x => x.Name == referenceResourceText.LocalizationKey); + referenceResourceText.Target = text?.Value ?? string.Empty; + } + } + + if (!allValues) + { + //Only include missing keys. + resource.Texts.RemoveAll(x => !x.Target.Equals(string.Empty)); + } + + if (resource.Texts.Any()) + { + translateInfo.Resources.Add(resource); + } + } + + return translateInfo; + } + + private void ApplyAbpTranslateInfo(string directory, string filename) + { + var translateJsonPath = Path.Combine(directory, filename); + if (!File.Exists(translateJsonPath)) + { + throw new CliUsageException( + $"{translateJsonPath} file does not exist.." + + Environment.NewLine + Environment.NewLine + + GetUsageInfo() + ); + } + + var translateInfo = GetAbpTranslateInfo(translateJsonPath); + foreach (var resource in translateInfo.Resources) + { + var targetFile = Path.Combine(resource.ResourcePath, translateInfo.TargetCulture + ".json"); + var targetLocalizationInfo = File.Exists(targetFile) + ? GetAbpLocalizationInfoOrNull(targetFile) + : new AbpLocalizationInfo() + { + Culture = translateInfo.TargetCulture, + Texts = new List() + }; + + if (targetLocalizationInfo == null) + { + throw new CliUsageException( + $"Failed to get localization information from {targetFile} file." + + Environment.NewLine + Environment.NewLine + + GetUsageInfo() + ); + } + + var referenceFile = Path.Combine(resource.ResourcePath, translateInfo.ReferenceCulture + ".json"); + if (!File.Exists(referenceFile)) + { + throw new CliUsageException( + $"{referenceFile} file does not exist.." + + Environment.NewLine + Environment.NewLine + + GetUsageInfo() + ); + } + var referenceLocalizationInfo = GetAbpLocalizationInfoOrNull(referenceFile); + if (referenceLocalizationInfo == null) + { + throw new CliUsageException( + $"Failed to get localization information from {referenceFile} file." + + Environment.NewLine + Environment.NewLine + + GetUsageInfo() + ); + } + + foreach (var text in resource.Texts) + { + var targetText = targetLocalizationInfo.Texts.FirstOrDefault(x => x.Name == text.LocalizationKey); + if (targetText != null) + { + Logger.LogInformation($"Update translation: {targetText.Name} => " + text.Target); + targetText.Value = text.Target; + } + else + { + Logger.LogInformation($"Create translation: {text.LocalizationKey} => " + text.Target); + targetLocalizationInfo.Texts.Add(new NameValue(text.LocalizationKey, text.Target)); + } + } + + Logger.LogInformation($"Write translation json to {targetFile}."); + + // sort keys + targetLocalizationInfo = SortLocalizedKeys(targetLocalizationInfo, referenceLocalizationInfo); + File.WriteAllText(targetFile, AbpLocalizationInfoToJsonFile(targetLocalizationInfo)); + + // remove translate json file(abp-translation.json) + File.Delete(translateJsonPath); + Logger.LogInformation($"Delete the {translateJsonPath} file, if you need to translate again, please re-run the [abp translate] command."); + } + } + + private static IEnumerable GetCultureJsonFiles(string path,string cultureName) + { + var excludeDirectory = new List() + { + "node_modules", + Path.Combine("bin", "debug"), + Path.Combine("obj", "debug") + }; + + var allCultureInfos = CultureInfo.GetCultures(CultureTypes.AllCultures); + + return Directory.GetFiles(path, "*.json", SearchOption.AllDirectories) + .Where(file => excludeDirectory.All(x => file.IndexOf(x, StringComparison.OrdinalIgnoreCase) == -1)) + .Where(jsonFile => allCultureInfos.Any(culture => jsonFile.EndsWith($"{cultureName}.json", StringComparison.OrdinalIgnoreCase))); + } + + private AbpLocalizationInfo GetAbpLocalizationInfoOrNull(string path) + { + if (!File.Exists(path)) + { + throw new CliUsageException( + $"File {path} does not exist!" + + Environment.NewLine + Environment.NewLine + + GetUsageInfo() + ); + } + + var json = File.ReadAllText(path); + JObject jObject; + try + { + jObject = JObject.Parse(json); + } + catch (Exception e) + { + return null; + } + + var culture = jObject.GetValue("culture"); + var texts = jObject.GetValue("texts"); + if (culture == null || texts == null) + { + return null; + } + + var localizationInfo = new AbpLocalizationInfo + { + Culture = culture.Value(), + Texts = new List() + }; + + foreach (var text in texts) + { + var property = (text as JProperty); + localizationInfo.Texts.Add(new NameValue(property?.Name, property?.Value.Value())); + } + + return localizationInfo; + } + + private static string AbpLocalizationInfoToJsonFile(AbpLocalizationInfo localizationInfo) + { + var jObject = new JObject {{"culture", localizationInfo.Culture}}; + var value = new JObject(); + foreach (var text in localizationInfo.Texts) + { + value.Add(text.Name, text.Value); + } + jObject.Add("texts", value); + return jObject.ToString(); + } + + private AbpTranslateInfo GetAbpTranslateInfo(string path) + { + if (!File.Exists(path)) + { + throw new CliUsageException( + $"File {path} does not exist!" + + Environment.NewLine + Environment.NewLine + + GetUsageInfo() + ); + } + + AbpTranslateInfo translateInfo; + try + { + translateInfo = JsonConvert.DeserializeObject(File.ReadAllText(path)); + } + catch (Exception e) + { + throw new CliUsageException( + e.Message + + Environment.NewLine + Environment.NewLine + + GetUsageInfo() + ); + } + + return translateInfo; + } + + private static AbpLocalizationInfo SortLocalizedKeys(AbpLocalizationInfo targetLocalizationInfo, AbpLocalizationInfo referenceLocalizationInfo) + { + var sortedLocalizationInfo = new AbpLocalizationInfo + { + Culture = targetLocalizationInfo.Culture, + Texts = new List() + }; + + foreach (var targetText in referenceLocalizationInfo.Texts.Select(text => + targetLocalizationInfo.Texts.FirstOrDefault(x => x.Name == text.Name)) + .Where(targetText => targetText != null)) + { + sortedLocalizationInfo.Texts.Add(targetText); + } + + return sortedLocalizationInfo; + } + + public string GetUsageInfo() + { + var sb = new StringBuilder(); + + sb.AppendLine(""); + sb.AppendLine("Usage:"); + sb.AppendLine(""); + sb.AppendLine(" abp translate [options]"); + sb.AppendLine(""); + sb.AppendLine("Options:"); + sb.AppendLine(""); + sb.AppendLine("--culture|-c Target culture. eg: zh-Hans"); + sb.AppendLine("--reference-culture|-r Default: en"); + sb.AppendLine("--output|-o Output file name, Default abp-translation.json"); + sb.AppendLine("--all-values|-all Include all keys. Default false"); + sb.AppendLine("--apply|-a Creates or updates the file for the translated culture."); + sb.AppendLine("--file|-f Default: abp-translation.json"); + sb.AppendLine(""); + sb.AppendLine("Examples:"); + sb.AppendLine(""); + sb.AppendLine(" abp translate -c zh-Hans"); + sb.AppendLine(" abp translate -c zh-Hans -r en -a"); + sb.AppendLine(" abp translate --apply"); + sb.AppendLine(" abp translate -a -f my-translation.json"); + sb.AppendLine(""); + sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); + + return sb.ToString(); + } + + public string GetShortDescription() + { + return "Mainly used to translate ABP's resources (JSON files) easier."; + } + + public static class Options + { + public static class Culture + { + public const string Short = "c"; + public const string Long = "culture"; + } + + public static class ReferenceCulture + { + public const string Short = "r"; + public const string Long = "reference-culture"; + } + + public static class Output + { + public const string Short = "o"; + public const string Long = "output"; + } + + public static class AllValues + { + public const string Short = "all"; + public const string Long = "all-values"; + } + + public static class Apply + { + public const string Short = "a"; + public const string Long = "apply"; + } + + public static class File + { + public const string Short = "f"; + public const string Long = "file"; + } + } + + public class AbpTranslateInfo + { + public string ReferenceCulture { get; set; } + + public string TargetCulture { get; set; } + + public List Resources { get; set; } + } + + public class AbpTranslateResource + { + public string ResourcePath { get; set; } + + public List Texts { get; set; } + } + + public class AbpTranslateResourceText + { + public string LocalizationKey { get; set; } + + public string Reference { get; set; } + + public string Target { get; set; } + } + + public class AbpLocalizationInfo + { + public string Culture { get; set; } + + public List Texts { get; set; } + } + } +} diff --git a/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs b/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs index 2ccf9bb9a1..c78d5f93f3 100644 --- a/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs +++ b/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; using Serilog; using Serilog.Events; using System.IO; @@ -10,6 +11,8 @@ namespace Volo.Abp.Cli { private static void Main(string[] args) { + Console.OutputEncoding = System.Text.Encoding.UTF8; + Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)