diff --git a/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs b/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs index 8b6ffd2cdf..25d42e3ac2 100644 --- a/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs +++ b/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs @@ -18,7 +18,7 @@ namespace VoloDocs.Web.Pages _projectAppService = projectAppService; } - public async Task OnGet() + public async Task OnGetAsync() { Projects = (await _projectAppService.GetListAsync()).Items; @@ -28,6 +28,7 @@ namespace VoloDocs.Web.Pages { projectName = Projects[0].ShortName, version = DocsAppConsts.Latest, + languageCode = await _projectAppService.GetDefaultLanguageCode(Projects[0].ShortName), documentName = Projects[0].DefaultDocumentName }); } diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/ContentWithDetailsDto.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/ContentWithDetailsDto.cs index 44b2ef6861..43fab40c0c 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/ContentWithDetailsDto.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/ContentWithDetailsDto.cs @@ -25,6 +25,8 @@ namespace Volo.Docs.Documents public string FileName { get; set; } + public string CurrentLanguageCode { get; set; } + public ProjectDto Project { get; set; } public List Contributors { get; set; } diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDefaultDocumentInput.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDefaultDocumentInput.cs index 770f43b13e..c606c3be5d 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDefaultDocumentInput.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDefaultDocumentInput.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel.DataAnnotations; +using Volo.Docs.Language; using Volo.Docs.Projects; namespace Volo.Docs.Documents @@ -10,5 +11,8 @@ namespace Volo.Docs.Documents [StringLength(ProjectConsts.MaxVersionNameLength)] public string Version { get; set; } + + [StringLength(LanguageConsts.MaxLanguageCodeLength)] + public string LanguageCode { get; set; } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDocumentInput.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDocumentInput.cs index 2c887fb829..e28237c352 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDocumentInput.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDocumentInput.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel.DataAnnotations; +using Volo.Docs.Language; using Volo.Docs.Projects; namespace Volo.Docs.Documents @@ -14,5 +15,8 @@ namespace Volo.Docs.Documents [StringLength(ProjectConsts.MaxVersionNameLength)] public string Version { get; set; } + + [StringLength(LanguageConsts.MaxLanguageCodeLength)] + public string LanguageCode { get; set; } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDocumentResourceInput.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDocumentResourceInput.cs index e34dfa5512..1fff5a1e12 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDocumentResourceInput.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetDocumentResourceInput.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel.DataAnnotations; +using Volo.Docs.Language; using Volo.Docs.Projects; namespace Volo.Docs.Documents @@ -14,5 +15,8 @@ namespace Volo.Docs.Documents [StringLength(ProjectConsts.MaxVersionNameLength)] public string Version { get; set; } + + [StringLength(LanguageConsts.MaxLanguageCodeLength)] + public string LanguageCode { get; set; } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetNavigationDocumentInput.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetNavigationDocumentInput.cs index c9ea504272..c2a614ce58 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetNavigationDocumentInput.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/GetNavigationDocumentInput.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel.DataAnnotations; +using Volo.Docs.Language; using Volo.Docs.Projects; namespace Volo.Docs.Documents @@ -10,5 +11,8 @@ namespace Volo.Docs.Documents [StringLength(ProjectConsts.MaxVersionNameLength)] public string Version { get; set; } + + [StringLength(LanguageConsts.MaxLanguageCodeLength)] + public string LanguageCode { get; set; } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/IProjectAppService.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/IProjectAppService.cs index 5bfc221e4d..d7fdb6759d 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/IProjectAppService.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/IProjectAppService.cs @@ -9,6 +9,8 @@ namespace Volo.Docs.Projects Task> GetListAsync(); Task GetAsync(string shortName); + + Task GetDefaultLanguageCode(string shortName); Task> GetVersionsAsync(string shortName); } diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/ProjectDto.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/ProjectDto.cs index 91f5c63a22..a9ec815a6c 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/ProjectDto.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/ProjectDto.cs @@ -26,5 +26,7 @@ namespace Volo.Docs.Projects public string DocumentStoreType { get; set; } public Dictionary ExtraProperties { get; set; } + + public Dictionary Languages { get; set; } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs index d29828ad05..2f029f3a39 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs @@ -9,10 +9,10 @@ namespace Volo.Docs { public DocsApplicationAutoMapperProfile() { - CreateMap(); + CreateMap().Ignore(x=>x.Languages); CreateMap(); CreateMap() - .Ignore(x => x.Project).Ignore(x => x.Contributors); + .Ignore(x => x.Project).Ignore(x => x.Contributors).Ignore(x => x.CurrentLanguageCode); CreateMap(); CreateMap(); } diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs index 3a4474e877..013bcefe84 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Logging; @@ -15,17 +16,20 @@ namespace Volo.Docs.Documents private readonly IProjectRepository _projectRepository; private readonly IDocumentStoreFactory _documentStoreFactory; protected IDistributedCache DocumentCache { get; } + protected IDistributedCache LanguageCache { get; } protected IDistributedCache ResourceCache { get; } public DocumentAppService( IProjectRepository projectRepository, IDocumentStoreFactory documentStoreFactory, IDistributedCache documentCache, + IDistributedCache languageCache, IDistributedCache resourceCache) { _projectRepository = projectRepository; _documentStoreFactory = documentStoreFactory; DocumentCache = documentCache; + LanguageCache = languageCache; ResourceCache = resourceCache; } @@ -33,9 +37,10 @@ namespace Volo.Docs.Documents { var project = await _projectRepository.GetAsync(input.ProjectId); - return await GetDocumentWithDetailsDto( + return await GetDocument( project, input.Name, + input.LanguageCode, input.Version ); } @@ -44,9 +49,10 @@ namespace Volo.Docs.Documents { var project = await _projectRepository.GetAsync(input.ProjectId); - return await GetDocumentWithDetailsDto( + return await GetDocument( project, project.DefaultDocumentName, + input.LanguageCode, input.Version ); } @@ -55,9 +61,10 @@ namespace Volo.Docs.Documents { var project = await _projectRepository.GetAsync(input.ProjectId); - return await GetDocumentWithDetailsDto( + return await GetDocument( project, project.NavigationDocumentName, + input.LanguageCode, input.Version ); } @@ -65,12 +72,12 @@ namespace Volo.Docs.Documents public async Task GetResourceAsync(GetDocumentResourceInput input) { var project = await _projectRepository.GetAsync(input.ProjectId); - var cacheKey = $"Resource@{project.ShortName}#{input.Name}#{input.Version}"; + var cacheKey = $"Resource@{project.ShortName}#{input.LanguageCode}#{input.Name}#{input.Version}"; async Task GetResourceAsync() { var store = _documentStoreFactory.Create(project.DocumentStoreType); - var documentResource = await store.GetResource(project, input.Name, input.Version); + var documentResource = await store.GetResource(project, input.Name, input.LanguageCode, input.Version); return ObjectMapper.Map(documentResource); } @@ -92,20 +99,23 @@ namespace Volo.Docs.Documents ); } - protected virtual async Task GetDocumentWithDetailsDto( + protected virtual async Task GetDocument( Project project, string documentName, + string languageCode, string version) { - var cacheKey = $"Document@{project.ShortName}#{documentName}#{version}"; + var cacheKey = $"Document@{project.ShortName}#{languageCode}#{documentName}#{version}"; async Task GetDocumentAsync() { Logger.LogInformation($"Not found in the cache. Requesting {documentName} from the store..."); var store = _documentStoreFactory.Create(project.DocumentStoreType); - var document = await store.GetDocumentAsync(project, documentName, version); + var languages = await GetLanguageListAsync(store, project, version); + var language = GetLanguageByCode(languages, languageCode); + var document = await store.GetDocumentAsync(project, documentName, language.Code, version); Logger.LogInformation($"Document retrieved: {documentName}"); - return CreateDocumentWithDetailsDto(project, document); + return CreateDocumentWithDetailsDto(project, document, languages, language.Code); } if (Debugger.IsAttached) @@ -125,11 +135,43 @@ namespace Volo.Docs.Documents ); } - protected virtual DocumentWithDetailsDto CreateDocumentWithDetailsDto(Project project, Document document) + protected virtual LanguageConfigElement GetLanguageByCode(LanguageConfig languageCodes, string languageCode) + { + var language = languageCodes.Languages.FirstOrDefault(l => l.Code == languageCode); + + return language ?? languageCodes.Languages.Single(l => l.IsDefault); + } + + protected virtual async Task GetLanguageListAsync(IDocumentStore store, Project project, string version) + { + async Task GetLanguagesAsync() + { + return await store.GetLanguageListAsync(project, version); + } + + return await LanguageCache.GetOrAddAsync( + project.ShortName, + GetLanguagesAsync, + () => new DistributedCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(24) + } + ); + } + + protected virtual DocumentWithDetailsDto CreateDocumentWithDetailsDto(Project project, Document document, LanguageConfig languages, string languageCode) { var documentDto = ObjectMapper.Map(document); documentDto.Project = ObjectMapper.Map(project); documentDto.Contributors = ObjectMapper.Map, List>(document.Contributors); + + documentDto.Project.Languages = new Dictionary(); + foreach (var language in languages.Languages) + { + documentDto.Project.Languages.Add(language.Code, language.DisplayName); + } + + documentDto.CurrentLanguageCode = languageCode; return documentDto; } } diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Projects/ProjectAppService.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Projects/ProjectAppService.cs index 02ffac9ee9..19c4e66b7b 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Projects/ProjectAppService.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Projects/ProjectAppService.cs @@ -16,17 +16,15 @@ namespace Volo.Docs.Projects private readonly IProjectRepository _projectRepository; private readonly IDistributedCache> _versionCache; private readonly IDocumentStoreFactory _documentStoreFactory; - private readonly IGuidGenerator _guidGenerator; public ProjectAppService( IProjectRepository projectRepository, IDistributedCache> versionCache, - IDocumentStoreFactory documentStoreFactory, IGuidGenerator guidGenerator) + IDocumentStoreFactory documentStoreFactory) { _projectRepository = projectRepository; _versionCache = versionCache; _documentStoreFactory = documentStoreFactory; - _guidGenerator = guidGenerator; } public async Task> GetListAsync() @@ -45,6 +43,15 @@ namespace Volo.Docs.Projects return ObjectMapper.Map(project); } + public async Task GetDefaultLanguageCode(string shortName) + { + var project = await _projectRepository.GetByShortNameAsync(shortName); + var store = _documentStoreFactory.Create(project.DocumentStoreType); + var languageList = await store.GetLanguageListAsync(project, project.LatestVersionBranchName); + + return languageList.Languages.Single(l=>l.IsDefault).Code; + } + public async Task> GetVersionsAsync(string shortName) { var project = await _projectRepository.GetByShortNameAsync(shortName); diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Language/LanguageConsts.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Language/LanguageConsts.cs new file mode 100644 index 0000000000..867cc2dd4e --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Language/LanguageConsts.cs @@ -0,0 +1,8 @@ + +namespace Volo.Docs.Language +{ + public static class LanguageConsts + { + public const int MaxLanguageCodeLength = 10; + } +} diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentStore.cs index 1b001303b5..3cbf2c40f2 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentStore.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentStore.cs @@ -1,16 +1,19 @@ using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Domain.Services; +using Volo.Docs.GitHub.Documents; using Volo.Docs.Projects; namespace Volo.Docs.Documents { public interface IDocumentStore : IDomainService { - Task GetDocumentAsync(Project project, string documentName, string version); + Task GetDocumentAsync(Project project, string documentName, string languageCode, string version); Task> GetVersionsAsync(Project project); - Task GetResource(Project project, string resourceName, string version); + Task GetResource(Project project, string resourceName, string languageCode, string version); + + Task GetLanguageListAsync(Project project, string version); } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/LanguageConfig.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/LanguageConfig.cs new file mode 100644 index 0000000000..038ec00cee --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/LanguageConfig.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Volo.Docs.Documents +{ + public class LanguageConfig + { + public List Languages { get; set; } + } +} diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/LanguageConfigElement.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/LanguageConfigElement.cs new file mode 100644 index 0000000000..25525394ca --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/LanguageConfigElement.cs @@ -0,0 +1,11 @@ +namespace Volo.Docs.Documents +{ + public class LanguageConfigElement + { + public string DisplayName { get; set; } + + public string Code { get; set; } + + public bool IsDefault { get; set; } + } +} diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentStore.cs index 87a74d1702..74e2e8469e 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentStore.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentStore.cs @@ -1,7 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Security; using System.Threading.Tasks; +using Newtonsoft.Json; using Volo.Abp.Domain.Services; using Volo.Abp.IO; using Volo.Docs.Documents; @@ -14,10 +16,10 @@ namespace Volo.Docs.FileSystem.Documents { public const string Type = "FileSystem"; - public async Task GetDocumentAsync(Project project, string documentName, string version) + public async Task GetDocumentAsync(Project project, string documentName, string languageCode, string version) { var projectFolder = project.GetFileSystemPath(); - var path = Path.Combine(projectFolder, documentName); + var path = Path.Combine(projectFolder, languageCode, documentName); CheckDirectorySecurity(projectFolder, path); @@ -46,10 +48,18 @@ namespace Volo.Docs.FileSystem.Documents return Task.FromResult(new List()); } - public async Task GetResource(Project project, string resourceName, string version) + public async Task GetLanguageListAsync(Project project, string version) + { + var path = Path.Combine(project.GetFileSystemPath(), "languageConfig.json"); + var configAsJson = await FileHelper.ReadAllTextAsync(path); + + return JsonConvert.DeserializeObject(configAsJson); + } + + public async Task GetResource(Project project, string resourceName, string languageCode, string version) { var projectFolder = project.GetFileSystemPath(); - var path = Path.Combine(projectFolder, resourceName); + var path = Path.Combine(projectFolder, languageCode, resourceName); if (!DirectoryHelper.IsSubDirectoryOf(projectFolder, path)) { diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentStore.cs index 2d65a17c68..91c03379ab 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentStore.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentStore.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; using Volo.Abp.Domain.Services; using Volo.Docs.Documents; using Volo.Docs.GitHub.Projects; @@ -27,14 +28,14 @@ namespace Volo.Docs.GitHub.Documents _githubRepositoryManager = githubRepositoryManager; } - public virtual async Task GetDocumentAsync(Project project, string documentName, string version) + public virtual async Task GetDocumentAsync(Project project, string documentName, string languageCode, string version) { var token = project.GetGitHubAccessTokenOrNull(); var rootUrl = project.GetGitHubUrl(version); - var rawRootUrl = CalculateRawRootUrl(rootUrl); + var userAgent = project.GetGithubUserAgentOrNull(); + var rawRootUrl = CalculateRawRootUrlWithLanguageCode(rootUrl, languageCode); var rawDocumentUrl = rawRootUrl + documentName; var commitHistoryUrl = project.GetGitHubUrlForCommitHistory() + documentName; - var userAgent = project.GetGithubUserAgentOrNull(); var isNavigationDocument = documentName == project.NavigationDocumentName; var editLink = rootUrl.ReplaceFirst("/tree/", "/blob/") + documentName; var localDirectory = ""; @@ -90,9 +91,9 @@ namespace Volo.Docs.GitHub.Documents return versions; } - public async Task GetResource(Project project, string resourceName, string version) + public async Task GetResource(Project project, string resourceName, string languageCode, string version) { - var rawRootUrl = CalculateRawRootUrl(project.GetGitHubUrl(version)); + var rawRootUrl = CalculateRawRootUrlWithLanguageCode(project.GetGitHubUrl(version), languageCode); var content = await DownloadWebContentAsByteArrayAsync( rawRootUrl + resourceName, project.GetGitHubAccessTokenOrNull(), @@ -102,6 +103,19 @@ namespace Volo.Docs.GitHub.Documents return new DocumentResource(content); } + public async Task GetLanguageListAsync(Project project, string version) + { + var token = project.GetGitHubAccessTokenOrNull(); + var rootUrl = project.GetGitHubUrl(version); + var userAgent = project.GetGithubUserAgentOrNull(); + + var url = CalculateRawRootUrl(rootUrl) + "languageConfig.json"; + + var configAsJson = await DownloadWebContentAsStringAsync(url, token, userAgent); + + return JsonConvert.DeserializeObject(configAsJson); + } + private async Task> GetReleasesAsync(Project project) { var url = project.GetGitHubUrl(); @@ -202,6 +216,16 @@ namespace Volo.Docs.GitHub.Documents return contributors; } + private static string CalculateRawRootUrlWithLanguageCode(string rootUrl, string languageCode) + { + return (rootUrl + .Replace("github.com", "raw.githubusercontent.com") + .ReplaceFirst("/tree/", "/") + .EnsureEndsWith('/') + + languageCode + ).EnsureEndsWith('/'); + } + private static string CalculateRawRootUrl(string rootUrl) { return rootUrl diff --git a/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs b/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs index e22df620f9..9b9df7b481 100644 --- a/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs +++ b/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs @@ -34,6 +34,13 @@ namespace Volo.Docs.Projects return ProjectAppService.GetAsync(shortName); } + [HttpGet] + [Route("{shortName}/defaultLanguage")] + public Task GetDefaultLanguageCode(string shortName) + { + return ProjectAppService.GetDefaultLanguageCode(shortName); + } + [HttpGet] [Route("{shortName}/versions")] public virtual Task> GetVersionsAsync(string shortName) diff --git a/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs b/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs index 38e95a6e93..2e8ec8bde0 100644 --- a/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs +++ b/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs @@ -35,6 +35,9 @@ namespace Volo.Docs.Areas.Documents.TagHelpers [HtmlAttributeName("project-format")] public string ProjectFormat { get; set; } + [HtmlAttributeName("language")] + public string LanguageCode { get; set; } + public override void Process(TagHelperContext context, TagHelperOutput output) { var content = new StringBuilder(); @@ -107,7 +110,7 @@ namespace Volo.Docs.Areas.Documents.TagHelpers } else { - listInnerItem = string.Format(ListItemAnchor, NormalizePath(node.Path, node.HasChildItems), textCss, node.Text.IsNullOrEmpty() ? "?" : node.Text); + listInnerItem = string.Format(ListItemAnchor, NormalizePath(node.Path), textCss, node.Text.IsNullOrEmpty() ? "?" : node.Text); } return string.Format(LiItemTemplateWithLink, @@ -117,7 +120,7 @@ namespace Volo.Docs.Areas.Documents.TagHelpers content); } - private string NormalizePath(string path, bool hasChildItems) + private string NormalizePath(string path) { if (UrlHelper.IsExternalLink(path)) { @@ -131,7 +134,7 @@ namespace Volo.Docs.Areas.Documents.TagHelpers return "javascript:;"; } - return "/documents/" + ProjectName + "/" + Version + "/" + pathWithoutFileExtension; + return "/documents/" + LanguageCode + "/" + ProjectName + "/" + Version + "/" + pathWithoutFileExtension; } private string RemoveFileExtensionFromPath(string path) diff --git a/modules/docs/src/Volo.Docs.Web/DocsWebModule.cs b/modules/docs/src/Volo.Docs.Web/DocsWebModule.cs index 89301265ea..e92a8d21a6 100644 --- a/modules/docs/src/Volo.Docs.Web/DocsWebModule.cs +++ b/modules/docs/src/Volo.Docs.Web/DocsWebModule.cs @@ -39,8 +39,8 @@ namespace Volo.Docs { //TODO: Make configurable! options.Conventions.AddPageRoute("/Documents/Project/Index", "documents/{projectName}"); - - options.Conventions.AddPageRoute("/Documents/Project/Index", "documents/{projectName}/{version}/{*documentName}"); + options.Conventions.AddPageRoute("/Documents/Project/Index", "documents/{languageCode}/{projectName}"); + options.Conventions.AddPageRoute("/Documents/Project/Index", "documents/{languageCode}/{projectName}/{version}/{*documentName}"); }); Configure(options => diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs index 552aa0c21d..436b0fe8e3 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs @@ -17,7 +17,7 @@ namespace Volo.Docs.Pages.Documents _projectAppService = projectAppService; } - public async Task OnGet() + public async Task OnGetAsync() { var listResult = await _projectAppService.GetListAsync(); @@ -27,6 +27,7 @@ namespace Volo.Docs.Pages.Documents { projectName = listResult.Items[0].ShortName, version = DocsAppConsts.Latest, + languageCode = await _projectAppService.GetDefaultLanguageCode(listResult.Items[0].ShortName), documentName = listResult.Items[0].DefaultDocumentName }); } diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml index 9b98ebe4b4..e6991812b9 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml @@ -107,7 +107,7 @@ } -
+
@@ -116,7 +116,7 @@
-
+
@if (Model.Navigation == null || Model.Navigation.Content.IsNullOrEmpty()) @@ -132,6 +132,7 @@ project-name="@Model.ProjectName" project-format="@Model.Project.Format" selected-document-name="@Model.DocumentNameWithExtension" + language="@Model.LanguageCode" id="sidebar-scroll" class="nav nav-list"> } @@ -158,10 +159,17 @@
- @if (!string.IsNullOrEmpty(Model.Document.EditLink)) - { - @L["Edit"] - } +
+ @if (Model.LanguageSelectListItems.Count > 1) + { + + } + + @if (!string.IsNullOrEmpty(Model.Document.EditLink)) + { + @L["Edit"] + } +
diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index 378903d121..a50340294b 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Localization; using Volo.Docs.Documents; using Volo.Docs.HtmlConverting; using Volo.Docs.Models; @@ -23,8 +24,13 @@ namespace Volo.Docs.Pages.Documents.Project [BindProperty(SupportsGet = true)] public string DocumentName { get; set; } + [BindProperty(SupportsGet = true)] + public string LanguageCode { get; set; } + public ProjectDto Project { get; set; } + public List LanguageSelectListItems { get; set; } + public string DocumentNameWithExtension { get; private set; } public DocumentWithDetailsDto Document { get; private set; } @@ -58,6 +64,8 @@ namespace Volo.Docs.Pages.Documents.Project await SetVersionAsync(); await SetDocumentAsync(); await SetNavigationAsync(); + SetLanguageSelectListItems(); + AddLanguageCodePrefixToLinks(); } private async Task SetProjectAsync() @@ -72,7 +80,7 @@ namespace Volo.Docs.Pages.Documents.Project ProjectSelectItems = projects.Items.Select(p => new SelectListItem { Text = p.Name, - Value = p.Id != Project.Id ? "/documents/" + p.ShortName + "/" + DocsAppConsts.Latest : null, + Value = p.Id != Project.Id ? "/documents/" + LanguageCode + "/" + p.ShortName + "/" + DocsAppConsts.Latest : null, Selected = p.Id == Project.Id }).ToList(); } @@ -133,6 +141,7 @@ namespace Volo.Docs.Pages.Documents.Project new GetNavigationDocumentInput { ProjectId = Project.Id, + LanguageCode = LanguageCode, Version = Version } ); @@ -144,6 +153,8 @@ namespace Volo.Docs.Pages.Documents.Project return; } + LanguageCode = Document.CurrentLanguageCode; + Navigation.ConvertItems(); } @@ -154,7 +165,7 @@ namespace Volo.Docs.Pages.Documents.Project version = DocsAppConsts.Latest; } - var link = "/documents/" + ProjectName + "/" + version; + var link = "/documents/" + LanguageCode + "/" + ProjectName + "/" + version; if (documentName != null) { @@ -193,6 +204,7 @@ namespace Volo.Docs.Pages.Documents.Project new GetDefaultDocumentInput { ProjectId = Project.Id, + LanguageCode = LanguageCode, Version = Version } ); @@ -204,20 +216,46 @@ namespace Volo.Docs.Pages.Documents.Project { ProjectId = Project.Id, Name = DocumentNameWithExtension, + LanguageCode = LanguageCode, Version = Version } ); } + } catch (DocumentNotFoundException) { - //TODO: Handle it! - throw; + Document = await _documentAppService.GetDefaultAsync( + new GetDefaultDocumentInput + { + ProjectId = Project.Id, + LanguageCode = LanguageCode, + Version = Version + } + ); } + LanguageCode = Document.CurrentLanguageCode; + ConvertDocumentContentToHtml(); } + private void SetLanguageSelectListItems() + { + LanguageSelectListItems = new List(); + + foreach (var language in Document.Project.Languages) + { + LanguageSelectListItems.Add( + new SelectListItem( + language.Value, + "/documents/" + language.Key + "/" + Project.ShortName + "/" + Version + "/" + DocumentName, + language.Key == LanguageCode + ) + ); + } + } + private void ConvertDocumentContentToHtml() { var converter = _documentToHtmlConverterFactory.Create(Document.Format ?? Project.Format); @@ -238,5 +276,10 @@ namespace Volo.Docs.Pages.Documents.Project Document.Content = content; } + + private void AddLanguageCodePrefixToLinks() + { + Document.Content = Document.Content.Replace("href=\"/documents", "href=\"/documents/" + LanguageCode); + } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js index 32ce1933a7..8eb2083749 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js @@ -1,11 +1,11 @@ (function ($) { $(function () { - var initNavigationFilter = function (navigationContainerId) { var $navigation = $("#" + navigationContainerId); + var getShownDocumentLinks = function () { return $navigation.find(".mCSB_container > li a:visible").not(".tree-toggle"); }; diff --git a/modules/docs/test/Volo.Docs.Domain.Tests/Volo/Docs/GithubDocumentStore_Tests.cs b/modules/docs/test/Volo.Docs.Domain.Tests/Volo/Docs/GithubDocumentStore_Tests.cs index 1f8bfeca77..76d1f9f68f 100644 --- a/modules/docs/test/Volo.Docs.Domain.Tests/Volo/Docs/GithubDocumentStore_Tests.cs +++ b/modules/docs/test/Volo.Docs.Domain.Tests/Volo/Docs/GithubDocumentStore_Tests.cs @@ -28,7 +28,7 @@ namespace Volo.Docs var project = await _projectRepository.FindAsync(_testData.PorjectId); project.ShouldNotBeNull(); - var document = await store.GetDocumentAsync(project, "index2", "0.123.0"); + var document = await store.GetDocumentAsync(project, "index2", "en", "0.123.0"); document.ShouldNotBeNull(); document.Title.ShouldBe("index2"); @@ -60,7 +60,7 @@ namespace Volo.Docs var project = await _projectRepository.FindAsync(_testData.PorjectId); project.ShouldNotBeNull(); - var documentResource = await store.GetResource(project, "index.md", "0.123.0"); + var documentResource = await store.GetResource(project, "index.md", "en", "0.123.0"); documentResource.ShouldNotBeNull(); documentResource.Content.ShouldBe(new byte[]