private async Task ImportFromDocument(IDocumentGenerator documentGenerator, string path, IReadOnlyCollection <string> selectedCultures, IReadOnlyCollection <Project> selectedProjects, IStatusProgress progress, CancellationToken cancellationToken) { IReadOnlyList <ResGroupModel <ResExcelModel> > data = await documentGenerator.ImportFromDocumentAsync <ResExcelModel>(path, progress, cancellationToken); progress.Report(StatusRes.GettingProjectsResources); SolutionResources resources = await GetSolutionResourcesAsync(selectedCultures, selectedProjects, progress, cancellationToken); progress.Report(StatusRes.MergingResources); var projectsJoin = resources.ProjectResources .Join(data, projRes => projRes.ProjectName, excelProjRes => excelProjRes.GroupTitle, (projRes, excelProjRes) => new { ProjRes = projRes, ExcelProjRes = excelProjRes }); foreach (var project in projectsJoin) { var resourceTablesJoin = project.ProjRes.Resources .Join(project.ExcelProjRes.Tables, resTable => resTable.Key, excelResTable => excelResTable.TableTitle, (resTable, excelResTable) => new { ResTable = resTable, ExcelResTable = excelResTable }); foreach (var resource in resourceTablesJoin) { int columnsCount = resource.ExcelResTable.Header.Columns.Count; int culturesCount = columnsCount - 2; List <string> cultureIds = resource.ExcelResTable.Header.Columns .Skip(1) .Select(col => col.Title == InvariantCultureDisplayName ? InvariantCultureId : CultureInfo.GetCultureInfo(col.Title).Name) .Take(culturesCount) .ToList(); List <string> resourceKeys = resource.ExcelResTable.Rows.Select(row => row.DataList[0].DataString).ToList(); List <string> comments = resource.ExcelResTable.Rows.Select(row => row.DataList[columnsCount - 1].DataString).ToList(); Dictionary <string, IReadOnlyCollection <ResourceEntryData> > excelResources = cultureIds .Select((cultureId, index) => new KeyValuePair <string, IReadOnlyCollection <ResourceEntryData> > ( cultureId, resourceKeys.Zip( resource.ExcelResTable.Rows.Select(row => row.DataList[index + 1].DataString), (key, value) => new { Key = key, Value = value }) .Zip(comments, (kvp, comment) => new ResourceEntryData(kvp.Key, kvp.Value, comment)) .ToList() )) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); var resourceFileTablesJoin = resource.ResTable.Value .Join(excelResources, resData => resData.Key, excelResData => excelResData.Key, (resData, excelResData) => new { ResData = resData.Value, ExcelResData = excelResData.Value }); foreach (var resFileTablesJoin in resourceFileTablesJoin) { try { UpdateResourceFile(resFileTablesJoin.ResData, resFileTablesJoin.ExcelResData); } catch (MissingManifestResourceException ex) { throw new MissingManifestResourceException(String.Format(ErrorsRes.MissingResourcesFormat, project.ProjRes.ProjectId, resFileTablesJoin.ResData.ResourceName, resFileTablesJoin.ResData.Culture.DisplayName), ex); } } } } }
public async Task <IReadOnlyList <ResGroupModel <TModel> > > ImportFromDocumentAsync <TModel>(string path, IStatusProgress progress, CancellationToken cancellationToken) where TModel : IRowModel, new() { progress.Report(StatusRes.GettingSpreadsheet); SpreadsheetFeed spreadSheets = await Service.GetFeedAsync(new SpreadsheetQuery(path), progress, cancellationToken); SpreadsheetEntry spreadsheet = (SpreadsheetEntry)spreadSheets.Entries.First(); progress.Report(StatusRes.GettingWorksheets); WorksheetFeed worksheetsFeed = await Service.GetFeedAsync(spreadsheet.GetWorkSheetQuery(), progress, cancellationToken); List <WorksheetEntry> worksheets = worksheetsFeed.Entries.Cast <WorksheetEntry>().ToList(); var progresses = progress.CreateParallelProgresses(worksheets.Select(ws => (double)ws.Cols * ws.Rows).ToList()); progress.Report(StatusRes.GettingWorksheetsData); SemaphoreSlim semaphore = new SemaphoreSlim(MaxPushRequestsCount); var groupTasks = worksheets.Zip(progresses, (entry, p) => GetGroupAsync <TModel>(entry, semaphore, p, cancellationToken)); return((await Task.WhenAll(groupTasks)).ToList()); }
public async Task ExportToDocumentAsync <TModel>(string path, IReadOnlyList <ResGroupModel <TModel> > groups, IStatusProgress progress, CancellationToken cancellationToken) where TModel : IRowModel { progress.Report(StatusRes.GettingSpreadsheet); SpreadsheetFeed spreadSheets = await Service.GetFeedAsync(new SpreadsheetQuery(path), progress, cancellationToken); SpreadsheetEntry spreadsheet = (SpreadsheetEntry)spreadSheets.Entries.First(); progress.Report(StatusRes.GettingWorksheets); WorksheetFeed worksheetsFeed = await Service.GetFeedAsync(spreadsheet.GetWorkSheetQuery(), progress, cancellationToken); int columsCount = groups.First().Tables.First().Rows.First().DataList.Count; List <KeyValuePair <string, WorksheetEntry> > newWorksheets = groups .Select(g => new KeyValuePair <string, WorksheetEntry>(g.GroupTitle, new WorksheetEntry((uint)(g.Tables.Sum(t => t.Rows.Count + 3) + /*Table name rows*/ g.Tables.Count - 1), (uint)columsCount, g.GroupTitle))) .ToList(); List <WorksheetEntry> worksheets2Rename = worksheetsFeed.Entries.Cast <WorksheetEntry>() .Where(ws => newWorksheets.Any(nws => String.Equals(nws.Key, ws.Title.Text, StringComparison.OrdinalIgnoreCase))) .ToList(); if (worksheets2Rename.Count != 0) { foreach (var worksheetEntry in worksheets2Rename) { worksheetEntry.Title.Text = Guid.NewGuid().ToString("N"); worksheetEntry.BatchData = new GDataBatchEntryData(GDataBatchOperationType.update); } progress.Report(StatusRes.RenamingOldWorksheets); var progresses = progress.CreateParallelProgresses(worksheets2Rename.Count); //Renaming worksheets with matching names. await Task.WhenAll(worksheets2Rename.Zip(progresses, (ws, p) => Service.UpdateItemAsync(ws, p, cancellationToken))); } progress.Report(StatusRes.InsertingNewWorksheets); //Creating new worksheets. var insertingProgresses = progress.CreateParallelProgresses(newWorksheets.Count); var createdWorksheets = await Task.WhenAll(newWorksheets.Zip(insertingProgresses, (kvp, p) => Service.InsertItemAsync(spreadsheet.GetWorkSheetLink(), kvp.Value, p, cancellationToken))); newWorksheets = createdWorksheets.Select(ws => new KeyValuePair <string, WorksheetEntry>(ws.Title.Text, ws)).ToList(); progress.Report(StatusRes.DeletingOldWorksheets); //Clearing of previous worksheets. var deletingProgresses = progress.CreateParallelProgresses(worksheetsFeed.Entries.Count); await Task.WhenAll(worksheetsFeed.Entries.Cast <WorksheetEntry>().Zip(deletingProgresses, (ws, p) => Service.DeleteItemAsync(ws, p, cancellationToken)).ToArray()); progress.Report(StatusRes.PushingCells); var groupWorksheetsJoin = newWorksheets.Join(groups, ws => ws.Key, g => g.GroupTitle, (kvp, group) => new { Group = group, Worksheet = kvp.Value }).ToList(); var groupProgresses = progress.CreateParallelProgresses(groupWorksheetsJoin.Select(j => (double)j.Worksheet.Cols * j.Worksheet.Rows).ToList()); SemaphoreSlim semaphore = new SemaphoreSlim(MaxPushRequestsCount); await Task.WhenAll(groupWorksheetsJoin.Zip(groupProgresses, (j, p) => PushCellsAsync(j.Worksheet, j.Group, semaphore, p, cancellationToken))); }
private void ExportToDocument <TModel>(string path, IReadOnlyList <ResGroupModel <TModel> > groups, IStatusProgress progress, CancellationToken cancellationToken) where TModel : IRowModel { if (groups.Count == 0) { throw new ArgumentException(ErrorsRes.TherIsNotFilesToExport, "groups"); } progress.Report(StatusRes.ExportingToExcel); using (ExcelPackage package = new ExcelPackage()) { /* Create the worksheet. */ var workbook = package.Workbook; double totalRows = groups.Sum(g => g.Tables.Sum(t => t.Rows.Count)); int rowIndexReport = 1; foreach (var group in groups) { var worksheet = workbook.Worksheets.Add(group.GroupTitle); ExcelStyle defaultStyle = worksheet.Cells[1, 1].Style; int rowIndex = 1; int columnsCount = groups.SelectMany(g => g.Tables.Select(t => t.Header.Columns.Count)).Max(); for (int i = 0; i < columnsCount; i++) { List <string> groupStrings = groups.SelectMany(g => g.Tables.Select(t => { string colTitle = t.Header.Columns[i].Title; int longestRowLength = t.Rows.Select(r => r.DataList[i].DataString).Max(str => str.Length); string longestRow = t.Rows.Select(r => r.DataList[i].DataString).First(str => str.Length == longestRowLength); return(colTitle.Length > longestRow.Length ? colTitle : longestRow); }) ) .ToList(); int longestStringLength = groupStrings.Max(s => s.Length); string longestString = groupStrings.Find(str => str.Length == longestStringLength); worksheet.Column(i + 1).Width = (int)GetDefaultFontWidth(defaultStyle, longestString); } //Setting Columns foreach (var resTableModel in group.Tables) { var headerCell = worksheet.Cells[rowIndex++, 1]; headerCell.Style.Font.Bold = true; headerCell.Style.Fill.PatternType = ExcelFillStyle.Solid; headerCell.Style.Fill.BackgroundColor.SetColor(Color.LightGray); headerCell.Value = resTableModel.TableTitle; rowIndex++; for (int columnIndex = 0; columnIndex < resTableModel.Header.Columns.Count; columnIndex++) { var languageHeader = worksheet.Cells[rowIndex, columnIndex + 1]; languageHeader.Style.Font.Bold = true; languageHeader.Style.Fill.PatternType = ExcelFillStyle.Solid; languageHeader.Style.Fill.BackgroundColor.SetColor(Color.LightGray); languageHeader.Value = resTableModel.Header.Columns[columnIndex].Title; } rowIndex++; foreach (var tableRow in resTableModel.Rows) { for (int columnIndex = 0; columnIndex < tableRow.DataList.Count; columnIndex++) { var cell = tableRow.DataList[columnIndex]; var valueCell = worksheet.Cells[rowIndex, columnIndex + 1]; valueCell.Value = cell.DataString; if (cell.Hilight) { valueCell.Style.Font.Color.SetColor(Color.Red); } } rowIndex++; rowIndexReport++; } progress.Report(100 * rowIndexReport / totalRows); cancellationToken.ThrowIfCancellationRequested(); rowIndex++; } } package.SaveAs(new FileInfo(path)); } }
public async Task ExportToDocumentAsync(IDocumentGenerator documentGenerator, string path, IReadOnlyCollection <string> selectedCultures, IReadOnlyCollection <Project> selectedProjects, IStatusProgress progress, CancellationToken cancellationToken) { progress.Report(StatusRes.GettingProjectsResources); SolutionResources solutionResources = await GetSolutionResourcesAsync(selectedCultures, selectedProjects, progress, cancellationToken); progress.Report(StatusRes.PreparingResourcesToExport); var cultures = selectedCultures.Select(CultureInfo.GetCultureInfo) .ToDictionary( cult => cult.Name, cult => cult.Name == InvariantCultureId ? InvariantCultureDisplayName : cult.Name.ToUpper() ); var culturesOrder = new List <string>(cultures.Count) { InvariantCultureId }; culturesOrder.AddRange(cultures.Where(cult => cult.Key != InvariantCultureId).OrderBy(cult => cult.Value).Select(cult => cult.Key)); var header = new HeaderModel { Columns = new List <ColumnModel>(1) { new ColumnModel { Title = ExcelRes.ResourceKey } } .Concat(culturesOrder.Select(cultureId => cultures[cultureId]).Select(headerName => new ColumnModel { Title = headerName })) .Concat(new List <ColumnModel>(1) { new ColumnModel { Title = ExcelRes.Comment } }) .ToList() }; IReadOnlyList <ResGroupModel <ResExcelModel> > groups = solutionResources .ProjectResources.Select(proj => new ResGroupModel <ResExcelModel> { GroupTitle = proj.ProjectName, Tables = proj.Resources.Select(res => { var neutralResources = res.Value[InvariantCultureId].StringResources; List <string> keysOrder = neutralResources.Keys.OrderBy(key => key).ToList(); List <RowModel <ResExcelModel> > rows = keysOrder.Select( resKey => new RowModel <ResExcelModel> { Model = new ResExcelModel(resKey, culturesOrder.Select(cultureId => res.Value[cultureId]).Select(resData => resData.StringResources[resKey].Value).ToList(), res.Value[InvariantCultureId].StringResources[resKey].Comment) }) .Where(r => r.Model.ResourceValues.Count != 0) .ToList(); var tableModel = new ResTableModel <ResExcelModel> { TableTitle = res.Key, Header = header, Rows = rows }; cancellationToken.ThrowIfCancellationRequested(); return(tableModel); }) .Where(table => table.Rows.Count != 0) .ToList() }) .Where(res => res.Tables.Count != 0) .ToList(); await documentGenerator.ExportToDocumentAsync(path, groups, progress, cancellationToken); }
public void UpdateResources(IReadOnlyCollection <string> selectedCultures, IReadOnlyCollection <Project> selectedProjects, IStatusProgress progress, CancellationToken cancellationToken, UpdateResourcesOptions options) { IReadOnlyDictionary <string, CultureInfo> selectedCultureInfos = selectedCultures.Select(CultureInfo.GetCultureInfo) .ToDictionary(cult => cult.Name, cult => cult); IReadOnlyDictionary <string, Project> projectsDictionary = selectedProjects.ToDictionary(proj => proj.UniqueName, proj => proj); progress.Report(StatusRes.GettingProjectsResources); SolutionResources solutionResources = GetSolutionResources(null, selectedProjects, progress, cancellationToken); progress.Report(StatusRes.GeneratingResx); cancellationToken.ThrowIfCancellationRequested(); int resourceFilesProcessed = 0; int resourceFilesCount = solutionResources.ProjectResources.Sum(pr => pr.Resources.Count); foreach (var projectResources in solutionResources.ProjectResources) { var project = projectsDictionary[projectResources.ProjectId]; foreach (Dictionary <string, ResourceData> resourceFileGroup in projectResources.Resources.Values) { //Removing culture files without neutral culture file. TODO: find if it is required. ResourceData neutralCulture; if (!resourceFileGroup.TryGetValue(InvariantCultureId, out neutralCulture)) { _logger.Log(String.Format(LoggerRes.MissingNeutralCulture, resourceFileGroup.Values.First().ResourcePath, String.Join("\r\n", resourceFileGroup.Values.Select(r => r.ResourcePath)))); foreach (var projectItem in resourceFileGroup.Values) { _logger.Log(String.Format(LoggerRes.RemovedFormat, projectItem.ProjectItem.FileNames[0])); projectItem.ProjectItem.Delete(); } resourceFileGroup.Clear(); project.Save(); continue; } var items2Remove = resourceFileGroup.Where(f => !selectedCultureInfos.ContainsKey(f.Key)).ToList(); List <KeyValuePair <string, ProjectItem> > projectItems2Remove; if (items2Remove.Count == 0) { projectItems2Remove = new List <KeyValuePair <string, ProjectItem> >(0); } else { projectItems2Remove = items2Remove.Select(d => new KeyValuePair <string, ProjectItem>(d.Key, d.Value.ProjectItem)).ToList(); } var cultures2Add = selectedCultureInfos.Where(cult => !resourceFileGroup.ContainsKey(cult.Key)).Select(cult => cult.Value).ToList(); if (options.RemoveNotSelectedCultures) { foreach (var projectItem in projectItems2Remove) { _logger.Log(String.Format(LoggerRes.RemovedFormat, projectItem.Value.FileNames[0])); projectItem.Value.Delete(); resourceFileGroup.Remove(projectItem.Key); } } foreach (var cultureInfo in cultures2Add) { string resourcePath = Path.Combine(Path.GetDirectoryName(neutralCulture.ResourcePath), Path.GetFileName(neutralCulture.ResourceName) + "." + cultureInfo.Name.ToUpper() + ".resx"); using (File.Create(resourcePath)) { } ProjectItem projectItem = project.ProjectItems.AddFromFile(resourcePath); var newFile = new ResourceData ( resourceName: neutralCulture.ResourceName, resourcePath: resourcePath, culture: cultureInfo, projectItem: projectItem, resources: new Dictionary <string, ResXDataNode>(0) ); resourceFileGroup.Add(cultureInfo.Name, newFile); _logger.Log(String.Format(LoggerRes.AddedNewResource, newFile.ResourcePath)); } List <ResourceData> otherCultureResources = resourceFileGroup.Where(resData => resData.Key != InvariantCultureId).Select(resData => resData.Value).ToList(); if (options.EmbeedSubCultures.HasValue) { if (options.EmbeedSubCultures.Value) { EmbeedResources(neutralCulture.ProjectItem, otherCultureResources); } } if (options.UseDefaultCustomTool.HasValue) { Property customToolProperty = neutralCulture.ProjectItem.Properties.Cast <Property>().First(p => p.Name == "CustomTool"); customToolProperty.Value = options.UseDefaultCustomTool.Value ? "PublicResXFileCodeGenerator" : ""; } if (options.UseDefaultContentType.HasValue) { foreach (var resProjectItem in resourceFileGroup.Values.Select(g => g.ProjectItem)) { Property itemTypeProperty = resProjectItem.Properties.Cast <Property>().First(p => p.Name == "ItemType"); itemTypeProperty.Value = options.UseDefaultContentType.Value ? "EmbeddedResource" : "None"; } } UpdateResourceFiles(neutralCulture, otherCultureResources); project.Save(); progress.Report((int)Math.Round((double)100 * (++resourceFilesProcessed) / resourceFilesCount)); cancellationToken.ThrowIfCancellationRequested(); } } }