Skip to content

Commit

Permalink
Merge pull request #1180 from abpframework/Docs-multi-language
Browse files Browse the repository at this point in the history
Docs multi language
  • Loading branch information
hikalkan committed May 30, 2019
2 parents a8d22b9 + d99efbc commit 60233fe
Show file tree
Hide file tree
Showing 25 changed files with 246 additions and 47 deletions.
3 changes: 2 additions & 1 deletion modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs
Expand Up @@ -18,7 +18,7 @@ public IndexModel(IProjectAppService projectAppService)
_projectAppService = projectAppService;
}

public async Task<IActionResult> OnGet()
public async Task<IActionResult> OnGetAsync()
{
Projects = (await _projectAppService.GetListAsync()).Items;

Expand All @@ -28,6 +28,7 @@ public async Task<IActionResult> OnGet()
{
projectName = Projects[0].ShortName,
version = DocsAppConsts.Latest,
languageCode = await _projectAppService.GetDefaultLanguageCode(Projects[0].ShortName),
documentName = Projects[0].DefaultDocumentName
});
}
Expand Down
Expand Up @@ -25,6 +25,8 @@ public class DocumentWithDetailsDto

public string FileName { get; set; }

public string CurrentLanguageCode { get; set; }

public ProjectDto Project { get; set; }

public List<DocumentContributorDto> Contributors { get; set; }
Expand Down
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel.DataAnnotations;
using Volo.Docs.Language;
using Volo.Docs.Projects;

namespace Volo.Docs.Documents
Expand All @@ -10,5 +11,8 @@ public class GetDefaultDocumentInput

[StringLength(ProjectConsts.MaxVersionNameLength)]
public string Version { get; set; }

[StringLength(LanguageConsts.MaxLanguageCodeLength)]
public string LanguageCode { get; set; }
}
}
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel.DataAnnotations;
using Volo.Docs.Language;
using Volo.Docs.Projects;

namespace Volo.Docs.Documents
Expand All @@ -14,5 +15,8 @@ public class GetDocumentInput

[StringLength(ProjectConsts.MaxVersionNameLength)]
public string Version { get; set; }

[StringLength(LanguageConsts.MaxLanguageCodeLength)]
public string LanguageCode { get; set; }
}
}
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel.DataAnnotations;
using Volo.Docs.Language;
using Volo.Docs.Projects;

namespace Volo.Docs.Documents
Expand All @@ -14,5 +15,8 @@ public class GetDocumentResourceInput

[StringLength(ProjectConsts.MaxVersionNameLength)]
public string Version { get; set; }

[StringLength(LanguageConsts.MaxLanguageCodeLength)]
public string LanguageCode { get; set; }
}
}
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel.DataAnnotations;
using Volo.Docs.Language;
using Volo.Docs.Projects;

namespace Volo.Docs.Documents
Expand All @@ -10,5 +11,8 @@ public class GetNavigationDocumentInput

[StringLength(ProjectConsts.MaxVersionNameLength)]
public string Version { get; set; }

[StringLength(LanguageConsts.MaxLanguageCodeLength)]
public string LanguageCode { get; set; }
}
}
Expand Up @@ -9,6 +9,8 @@ public interface IProjectAppService : IApplicationService
Task<ListResultDto<ProjectDto>> GetListAsync();

Task<ProjectDto> GetAsync(string shortName);

Task<string> GetDefaultLanguageCode(string shortName);

Task<ListResultDto<VersionInfoDto>> GetVersionsAsync(string shortName);
}
Expand Down
Expand Up @@ -26,5 +26,7 @@ public class ProjectDto : EntityDto<Guid>
public string DocumentStoreType { get; set; }

public Dictionary<string, object> ExtraProperties { get; set; }

public Dictionary<string, string> Languages { get; set; }
}
}
Expand Up @@ -9,10 +9,10 @@ public class DocsApplicationAutoMapperProfile : Profile
{
public DocsApplicationAutoMapperProfile()
{
CreateMap<Project, ProjectDto>();
CreateMap<Project, ProjectDto>().Ignore(x=>x.Languages);
CreateMap<VersionInfo, VersionInfoDto>();
CreateMap<Document, DocumentWithDetailsDto>()
.Ignore(x => x.Project).Ignore(x => x.Contributors);
.Ignore(x => x.Project).Ignore(x => x.Contributors).Ignore(x => x.CurrentLanguageCode);
CreateMap<DocumentContributor, DocumentContributorDto>();
CreateMap<DocumentResource, DocumentResourceDto>();
}
Expand Down
@@ -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;
Expand All @@ -15,27 +16,31 @@ public class DocumentAppService : ApplicationService, IDocumentAppService
private readonly IProjectRepository _projectRepository;
private readonly IDocumentStoreFactory _documentStoreFactory;
protected IDistributedCache<DocumentWithDetailsDto> DocumentCache { get; }
protected IDistributedCache<LanguageConfig> LanguageCache { get; }
protected IDistributedCache<DocumentResourceDto> ResourceCache { get; }

public DocumentAppService(
IProjectRepository projectRepository,
IDocumentStoreFactory documentStoreFactory,
IDistributedCache<DocumentWithDetailsDto> documentCache,
IDistributedCache<LanguageConfig> languageCache,
IDistributedCache<DocumentResourceDto> resourceCache)
{
_projectRepository = projectRepository;
_documentStoreFactory = documentStoreFactory;
DocumentCache = documentCache;
LanguageCache = languageCache;
ResourceCache = resourceCache;
}

public virtual async Task<DocumentWithDetailsDto> GetAsync(GetDocumentInput input)
{
var project = await _projectRepository.GetAsync(input.ProjectId);

return await GetDocumentWithDetailsDto(
return await GetDocument(
project,
input.Name,
input.LanguageCode,
input.Version
);
}
Expand All @@ -44,9 +49,10 @@ public virtual async Task<DocumentWithDetailsDto> GetDefaultAsync(GetDefaultDocu
{
var project = await _projectRepository.GetAsync(input.ProjectId);

return await GetDocumentWithDetailsDto(
return await GetDocument(
project,
project.DefaultDocumentName,
input.LanguageCode,
input.Version
);
}
Expand All @@ -55,22 +61,23 @@ public virtual async Task<DocumentWithDetailsDto> GetNavigationAsync(GetNavigati
{
var project = await _projectRepository.GetAsync(input.ProjectId);

return await GetDocumentWithDetailsDto(
return await GetDocument(
project,
project.NavigationDocumentName,
input.LanguageCode,
input.Version
);
}

public async Task<DocumentResourceDto> 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<DocumentResourceDto> 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, DocumentResourceDto>(documentResource);
}
Expand All @@ -92,20 +99,23 @@ async Task<DocumentResourceDto> GetResourceAsync()
);
}

protected virtual async Task<DocumentWithDetailsDto> GetDocumentWithDetailsDto(
protected virtual async Task<DocumentWithDetailsDto> 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<DocumentWithDetailsDto> 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)
Expand All @@ -125,11 +135,43 @@ async Task<DocumentWithDetailsDto> GetDocumentAsync()
);
}

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<LanguageConfig> GetLanguageListAsync(IDocumentStore store, Project project, string version)
{
async Task<LanguageConfig> 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, DocumentWithDetailsDto>(document);
documentDto.Project = ObjectMapper.Map<Project, ProjectDto>(project);
documentDto.Contributors = ObjectMapper.Map<List<DocumentContributor>, List<DocumentContributorDto>>(document.Contributors);

documentDto.Project.Languages = new Dictionary<string, string>();
foreach (var language in languages.Languages)
{
documentDto.Project.Languages.Add(language.Code, language.DisplayName);
}

documentDto.CurrentLanguageCode = languageCode;
return documentDto;
}
}
Expand Down
Expand Up @@ -16,17 +16,15 @@ public class ProjectAppService : ApplicationService, IProjectAppService
private readonly IProjectRepository _projectRepository;
private readonly IDistributedCache<List<VersionInfo>> _versionCache;
private readonly IDocumentStoreFactory _documentStoreFactory;
private readonly IGuidGenerator _guidGenerator;

public ProjectAppService(
IProjectRepository projectRepository,
IDistributedCache<List<VersionInfo>> versionCache,
IDocumentStoreFactory documentStoreFactory, IGuidGenerator guidGenerator)
IDocumentStoreFactory documentStoreFactory)
{
_projectRepository = projectRepository;
_versionCache = versionCache;
_documentStoreFactory = documentStoreFactory;
_guidGenerator = guidGenerator;
}

public async Task<ListResultDto<ProjectDto>> GetListAsync()
Expand All @@ -45,6 +43,15 @@ public async Task<ProjectDto> GetAsync(string shortName)
return ObjectMapper.Map<Project, ProjectDto>(project);
}

public async Task<string> 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<ListResultDto<VersionInfoDto>> GetVersionsAsync(string shortName)
{
var project = await _projectRepository.GetByShortNameAsync(shortName);
Expand Down
@@ -0,0 +1,8 @@

namespace Volo.Docs.Language
{
public static class LanguageConsts
{
public const int MaxLanguageCodeLength = 10;
}
}
@@ -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<Document> GetDocumentAsync(Project project, string documentName, string version);
Task<Document> GetDocumentAsync(Project project, string documentName, string languageCode, string version);

Task<List<VersionInfo>> GetVersionsAsync(Project project);

Task<DocumentResource> GetResource(Project project, string resourceName, string version);
Task<DocumentResource> GetResource(Project project, string resourceName, string languageCode, string version);

Task<LanguageConfig> GetLanguageListAsync(Project project, string version);
}
}
@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace Volo.Docs.Documents
{
public class LanguageConfig
{
public List<LanguageConfigElement> Languages { get; set; }
}
}
@@ -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; }
}
}

0 comments on commit 60233fe

Please sign in to comment.