public void RemoveLineFromSharedTable() { StringTableCollection collection = LocalizationEditorSettings.GetStringTableCollection("Questline Dialogue"); if (collection != null) { int index = 0; LocalizedString _dialogueLine = null; do { index++; string key = "L" + index + "-" + this.name; if (collection.SharedData.Contains(key)) { collection.SharedData.RemoveKey(key); } else { _dialogueLine = null; } } while (_dialogueLine != null); } }
void RemoveMissingEntries(HashSet <uint> entriesToKeep, StringTableCollection collection, StringBuilder removedEntriesLog) { var stringTables = collection.StringTables; removedEntriesLog.AppendLine("Removed missing entries:"); for (int i = 0; i < collection.SharedData.Entries.Count; ++i) { var entry = collection.SharedData.Entries[i]; if (entriesToKeep.Contains(entry.Id)) { continue; } removedEntriesLog.AppendLine($"\t{entry.Key}({entry.Id})"); // Remove the entry collection.SharedData.RemoveKey(entry.Id); i--; // Remove from tables foreach (var table in stringTables) { table.Remove(entry.Id); } } }
void SetDialogueLines() { _dialogueLines.Clear(); StringTableCollection collection = LocalizationEditorSettings.GetStringTableCollection("Questline Dialogue"); if (collection != null) { int index = 0; LocalizedString _dialogueLine = null; do { index++; string key = "L" + index + "-" + this.name; if (collection.SharedData.Contains(key)) { _dialogueLine = new LocalizedString() { TableReference = "Questline Dialogue", TableEntryReference = key }; _dialogueLines.Add(_dialogueLine); } else { _dialogueLine = null; } } while (_dialogueLine != null); } }
void VerifyPushPullArguments(int sheetId, StringTableCollection collection, IList <SheetColumn> columnMapping, Type requiredKeyType) { if (string.IsNullOrEmpty(SpreadSheetId)) { throw new Exception($"{nameof(SpreadSheetId)} is required."); } if (collection == null) { throw new ArgumentNullException(nameof(collection)); } if (columnMapping == null) { throw new ArgumentNullException(nameof(columnMapping)); } if (columnMapping.Count == 0) { throw new ArgumentException("Must include at least 1 column.", nameof(columnMapping)); } if (columnMapping.Count(c => requiredKeyType.IsAssignableFrom(c.GetType())) != 1) { throw new ArgumentException($"Must include 1 {requiredKeyType.Name}.", nameof(columnMapping)); } ThrowIfDuplicateColumnIds(columnMapping); }
static void ImportGroupIntoCollection(StringTableCollection collection, IGroup group, INoteCollection extraNotes, LocaleIdentifier source, LocaleIdentifier target, ImportOptions importOptions) { if (collection == null) { throw new ArgumentNullException(nameof(collection)); } var sourceTable = collection.GetTable(source) ?? collection.AddNewTable(source); var targetTable = collection.GetTable(target) ?? collection.AddNewTable(target); // Extract file comments? var generalNotes = AddMetadataCommentsFromNotes(group, collection.SharedData.Metadata, NoteType.General, importOptions.ImportNotes); var sourceNotes = AddMetadataCommentsFromNotes(group, sourceTable, NoteType.Source, importOptions.ImportNotes); int targetNotes = sourceTable != targetTable?AddMetadataCommentsFromNotes(group, targetTable, NoteType.Target, importOptions.ImportNotes) : 0; // If we are importing a group and the file contains notes that were not used then we can include them as extras here. if (extraNotes != null) { // If we imported some notes from the group then we need to switch to merge or we will lose those notes. var overrideBehavior = generalNotes > 0 ? ImportNotesBehavior.Merge : importOptions.ImportNotes; AddMetadataCommentsFromNotes(extraNotes, collection.SharedData.Metadata, NoteType.General, overrideBehavior); overrideBehavior = sourceNotes > 0 ? ImportNotesBehavior.Merge : importOptions.ImportNotes; AddMetadataCommentsFromNotes(extraNotes, sourceTable, NoteType.Source, overrideBehavior); overrideBehavior = targetNotes > 0 ? ImportNotesBehavior.Merge : importOptions.ImportNotes; if (sourceTable != targetTable) { AddMetadataCommentsFromNotes(extraNotes, targetTable, NoteType.Target, overrideBehavior); } } ImportIntoTables(group, sourceTable as StringTable, targetTable as StringTable, importOptions); LocalizationEditorSettings.EditorEvents.RaiseCollectionModified(null, collection); }
static void Export(string path, StringTableCollection collection, IList <CsvColumns> columns) { using (var stream = new StreamWriter(path, false, Encoding.UTF8)) { var reporter = TaskReporter.CreateDefaultReporter(); reporter.Start("Exporting " + path, string.Empty); Csv.Export(stream, collection, columns, reporter); } }
static void Import(string path, StringTableCollection collection, IList <CsvColumns> columns) { using (var stream = new StreamReader(path)) { var reporter = TaskReporter.CreateDefaultReporter(); reporter.Start("Importing " + path, string.Empty); Csv.ImportInto(stream, collection, columns, true, reporter); } }
public override void ReadBegin(StringTableCollection collection, CsvReader reader) { m_ImportTable = collection.GetTable(m_LocaleIdentifier) as StringTable; if (m_ImportTable != null) { m_SomeValueIndex = reader.GetFieldIndex(SomeValueFieldName, isTryGet: true); m_SomeOtherValueIndex = reader.GetFieldIndex(SomeOtherValueFieldName, isTryGet: true); } }
private static List <LocaleIdentifier> GetCulturesInfo(StringTableCollection collection) { List <LocaleIdentifier> cultures = new List <LocaleIdentifier>(); foreach (StringTable table in collection.StringTables) { cultures.Add(table.LocaleIdentifier); } return(cultures); }
/// <summary> /// Pulls data from the Spreadsheet with id <see cref="SpreadSheetId"/> and uses <paramref name="columnMapping"/> /// to populate the <paramref name="collection"/>. /// </summary> /// <param name="sheetId">The sheet(Spreadsheet tab) to pull the data from.</param> /// <param name="collection">The collection to insert the data into.</param> /// <param name="columnMapping">The column mappings control what data will be extracted for each column of the sheet. The list must contain 1 <see cref="IPullKeyColumn"/>.</param> /// <param name="removeMissingEntries">After a pull has completed any keys that exist in the <paramref name="collection"/> but did not exist in the sheet are considered missing, /// this may be because they have been deleted from the sheet. A value of true will remove these missing entries where false will preserve them.</param> /// <param name="reporter">Optional reporter to display the progress and status of the task.</param> /// <param name="createUndo">Should an Undo be recorded so any changes can be reverted?</param> public void PullIntoStringTableCollection(int sheetId, StringTableCollection collection, IList <SheetColumn> columnMapping, bool removeMissingEntries = false, ITaskReporter reporter = null, bool createUndo = false) { VerifyPushPullArguments(sheetId, collection, columnMapping, typeof(IPullKeyColumn)); try { var modifiedAssets = collection.StringTables.Select(t => t as Object).ToList(); modifiedAssets.Add(collection.SharedData); if (createUndo) { Undo.RecordObjects(modifiedAssets.ToArray(), $"Pull `{collection.TableCollectionName}` from Google sheets"); } reporter?.Start($"Pull `{collection.TableCollectionName}` from Google sheets", "Preparing columns"); // The response columns will be in the same order we request them, we need the key // before we can process any values so ensure the first column is the key column. var sortedColumns = columnMapping.OrderBy(c => c is IPullKeyColumn).ToList(); reporter?.ReportProgress("Generating request", 0.1f); var pullReq = GeneratePullRequest(sheetId, columnMapping); reporter?.ReportProgress("Sending request", 0.2f); var response = ExecuteRequest <Spreadsheet, GetByDataFilterRequest>(pullReq); reporter?.ReportProgress("Validating response", 0.5f); if (response.Sheets == null || response.Sheets.Count == 0) { throw new Exception($"No sheet data available for {sheetId} in Spreadsheet {SpreadSheetId}."); } var sheet = response.Sheets[0]; if (sheet.Data.Count != columnMapping.Count) { throw new Exception($"Column mismatch. Expected a response with {columnMapping.Count} columns but only got {sheet.Data.Count}"); } MergePull(sheet, collection, columnMapping, removeMissingEntries, reporter); if (!createUndo) { modifiedAssets.ForEach(EditorUtility.SetDirty); } LocalizationEditorSettings.EditorEvents.RaiseCollectionModified(this, collection); } catch (Exception e) { reporter?.Fail(e.Message); throw; } }
/// <summary> /// Exports a <see cref="StringTableCollection"/> using <paramref name="columnMappings"/> to control the contents of each exported column. /// <see cref="ColumnMapping.CreateDefaultMapping(bool)"/>. /// </summary> /// <param name="writer">The target that will be populated with CSV data.</param> /// <param name="collection">The collection to export to CSV.</param> /// <param name="cellMappings">Controls what will be exported. /// The <seealso cref="KeyIdColumns"/> can be used to export the Key, Id and shared comments whilst <seealso cref="LocaleColumns"/> can be /// used to export the values and comments for a specific <see cref="UnityEngine.Localization.Locale"/></param>. /// <seealso cref="ColumnMapping.CreateDefaultMapping(bool)"/> can be used to generate the default columns for the project. /// <param name="reporter">An optional reporter that can be used to provide feedback during export.</param> public static void Export(TextWriter writer, StringTableCollection collection, IList <CsvColumns> columnMappings, ITaskReporter reporter = null) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (collection == null) { throw new ArgumentNullException(nameof(collection)); } VerifyColumnMappings(columnMappings); using (var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture)) { try { reporter?.Start("Exporting CSV", string.Empty); reporter?.ReportProgress("Writing Headers", 0); foreach (var cell in columnMappings) { cell.WriteBegin(collection, csvWriter); } reporter?.ReportProgress("Writing Contents", 0.1f); foreach (var row in collection.GetRowEnumerator()) { if (row.TableEntries[0] != null && row.TableEntries[0].SharedEntry.Metadata.HasMetadata <ExcludeEntryFromExport>()) { continue; } csvWriter.NextRecord(); foreach (var cell in columnMappings) { cell.WriteRow(row.KeyEntry, row.TableEntries, csvWriter); } } foreach (var cell in columnMappings) { cell.WriteEnd(collection); } reporter?.Completed("Finished Exporting"); } catch (Exception e) { reporter?.Fail("Failed Exporting.\n" + e.Message); throw; } } }
void GeneratePushRequests(int sheetId, StringTableCollection collection, IList <SheetColumn> columnMapping, List <Request> requestsToSend, ITaskReporter reporter) { // Prepare the column requests. // We use a request per column as its possible that some columns in the sheet will be preserved and we don't want to write over them. reporter?.ReportProgress("Generating column headers", 0); var columnSheetRequests = new List <PushColumnSheetRequest>(columnMapping.Count); foreach (var col in columnMapping) { var colRequest = new PushColumnSheetRequest(sheetId, col); columnSheetRequests.Add(colRequest); colRequest.Column.PushBegin(collection); colRequest.Column.PushHeader(collection, out var header, out var note); colRequest.AddHeader(header, note); } var stringTables = collection.StringTables; var tableEntries = new StringTableEntry[stringTables.Count]; reporter?.ReportProgress("Generating push data", 0.1f); foreach (var keyEntry in collection.SharedData.Entries) { // Collect the table entry data. for (int i = 0; i < stringTables.Count; ++i) { tableEntries[i] = stringTables[i].GetEntry(keyEntry.Id); } // Now process each sheet column so they can update their requests. foreach (var colReq in columnSheetRequests) { if (tableEntries[0].SharedEntry.Metadata.HasMetadata <ExcludeEntryFromExport>()) { continue; } colReq.Column.PushCellData(keyEntry, tableEntries, out var value, out var note); colReq.AddRow(value, note); } } foreach (var col in columnSheetRequests) { col.Column.PushEnd(); requestsToSend.AddRange(col.Requests); } }
static void Export(IList <CsvColumns> cellMappings, StringTableCollection collection) { var path = EditorUtility.SaveFilePanel($"Export {collection.TableCollectionName} to CSV", PreviousDirectory, collection.TableCollectionName, "csv"); if (string.IsNullOrEmpty(path)) { return; } EditorPrefs.SetString(kPrefFile, path); using (var stream = new StreamWriter(path, false, Encoding.UTF8)) { var reporter = TaskReporter.CreateDefaultReporter(); reporter.Start("Exporting " + path, string.Empty); Csv.Export(stream, collection, cellMappings, reporter); } }
public void CreateLine() { if (_dialogueLines == null) { _dialogueLines = new List <LocalizedString>(); } _dialogueLines.Clear(); StringTableCollection collection = LocalizationEditorSettings.GetStringTableCollection("Questline Dialogue"); if (collection != null) { string DefaultKey = "L" + 1 + "-" + this.name; if (!collection.SharedData.Contains(DefaultKey)) { collection.SharedData.AddKey(DefaultKey); } } SetDialogueLines(); }
/// <summary> /// Import the XLIFF file into the collection. /// </summary> /// <param name="collection">The collection to import all the XLIFF data into.</param> /// <param name="file">The XLIFF file path.</param> /// <param name="importOptions">Optional import options which can be used to configure the importing behavior.</param> /// <param name="reporter">Optional reporter which can report the current progress.</param> public static void ImportFileIntoCollection(StringTableCollection collection, string file, ImportOptions importOptions = null, ITaskReporter reporter = null) { if (collection == null) { throw new ArgumentNullException(nameof(collection)); } reporter?.Start("Importing XLIFF", $"Importing {file}"); try { if (!File.Exists(file)) { throw new FileNotFoundException($"Could not find file {file}"); } using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read)) { reporter?.ReportProgress("Parsing XLIFF", 0.1f); var document = XliffDocument.Parse(stream); float progress = 0.3f; reporter?.ReportProgress("Importing XLIFF into project", progress); float progressStep = document.FileCount / 1.0f * 0.7f; var options = importOptions ?? s_DefaultOptions; for (int i = 0; i < document.FileCount; ++i) { var f = document.GetFile(i); progress += progressStep; reporter?.ReportProgress($"Importing({i + 1}/{document.FileCount}) {f.Id}", progress); ImportFileIntoCollection(collection, f, document.SourceLanguage, document.TargetLanguage, options); } reporter?.Completed("Finished importing XLIFF"); } } catch (Exception e) { reporter?.Fail(e.Message); throw; } }
/// <summary> /// Asynchronous version of <see cref="PushStringTableCollection"/> /// <inheritdoc cref="PushStringTableCollection"/> /// </summary> /// <param name="sheetId">The sheet(Spreadsheet tab) to insert the data into.</param> /// <param name="collection">The collection to extract the data from.</param> /// <param name="columnMapping">The column mappings control what data will be extracted for each column of the sheet. The list must contain 1 <see cref="KeyColumn"/>.</param> /// <param name="reporter">Optional reporter to display the progress and status of the task.</param> public async Task PushStringTableCollectionAsync(int sheetId, StringTableCollection collection, IList <SheetColumn> columnMapping, ITaskReporter reporter = null) { VerifyPushPullArguments(sheetId, collection, columnMapping, typeof(KeyColumn)); // Nothing to push if (collection.StringTables.Count == 0) { return; } try { reporter?.Start($"Push `{collection.TableCollectionName}` to Google Sheets", "Checking if sheet needs resizing"); var requests = new List <Request>(); var rowCountTask = GetRowCountAsync(sheetId); await rowCountTask.ConfigureAwait(true); var rowCount = rowCountTask.Result; // Do we need to resize the sheet? var requiredRows = collection.SharedData.Entries.Count + 1; // + 1 for the header row if (collection.SharedData.Entries.Count > rowCount) { reporter?.ReportProgress("Generating sheet resize request", 0.15f); requests.Add(ResizeRow(sheetId, requiredRows)); } GeneratePushRequests(sheetId, collection, columnMapping, requests, reporter); reporter?.ReportProgress("Sending Request", 0.5f); var sendTask = SendBatchUpdateRequestAsync(SpreadSheetId, requests); await sendTask.ConfigureAwait(true); reporter?.Completed($"Pushed {requiredRows} rows and {requiredRows * columnMapping.Count} cells successfully."); } catch (Exception e) { reporter?.Fail(e.Message); throw; } }
public override void WriteBegin(StringTableCollection collection, CsvWriter writer) { // Does the collection contain a string table for our Locale Id? var tables = collection.StringTables; m_CollectionTableIndex = -1; for (int i = 0; i < tables.Count; ++i) { if (tables[i].LocaleIdentifier == m_LocaleIdentifier) { m_CollectionTableIndex = i; } } if (m_CollectionTableIndex != -1) { writer.WriteField(SomeValueFieldName); writer.WriteField(SomeOtherValueFieldName); } }
static void ImportFileIntoCollection(StringTableCollection collection, IFile file, LocaleIdentifier source, LocaleIdentifier target, ImportOptions importOptions) { if (collection == null) { throw new ArgumentNullException(nameof(collection)); } var sourceTable = collection.GetTable(source) ?? collection.AddNewTable(source); var targetTable = collection.GetTable(target) ?? collection.AddNewTable(target); // Extract file comments? AddMetadataCommentsFromNotes(file, collection.SharedData.Metadata, NoteType.General, importOptions.ImportNotes); AddMetadataCommentsFromNotes(file, sourceTable, NoteType.Source, importOptions.ImportNotes); if (sourceTable != targetTable) { AddMetadataCommentsFromNotes(file, targetTable, NoteType.Target, importOptions.ImportNotes); } ImportIntoTables(file, sourceTable as StringTable, targetTable as StringTable, importOptions); LocalizationEditorSettings.EditorEvents.RaiseCollectionModified(null, collection); }
public override void PushBegin(StringTableCollection collection) { }
/// <summary> /// Pulls data from the Spreadsheet with id <see cref="TableId"/> and uses <paramref name="fieldMapping"/> /// to populate the <paramref name="collection"/>. /// </summary> /// <param name="collection">The collection to insert the data into.</param> /// <param name="fieldMapping">The column mappings control what data will be extracted for each column of the sheet. The list must contain 1 <see cref="IPullKeyColumn"/>.</param> /// <param name="removeMissingEntries">After a pull has completed any keys that exist in the <paramref name="collection"/> but did not exist in the sheet are considered missing, /// this may be because they have been deleted from the sheet. A value of true will remove these missing entries where false will preserve them.</param> /// <param name="reporter">Optional reporter to display the progress and status of the task.</param> /// <param name="createUndo">Should an Undo be recorded so any changes can be reverted?</param> public void PullIntoStringTableCollection(StringTableCollection collection, IList <SheetColumn> fieldMapping, bool removeMissingEntries = false, ITaskReporter reporter = null, bool createUndo = false) { VerifyPushPullArguments(collection, fieldMapping, typeof(IPullKeyColumn)); try { var modifiedAssets = collection.StringTables.Select(t => t as Object).ToList(); modifiedAssets.Add(collection.SharedData); if (createUndo) { Undo.RecordObjects(modifiedAssets.ToArray(), $"Pull `{collection.TableCollectionName}` from JSON file"); } reporter?.Start($"Pull `{collection.TableCollectionName}` from JSON file", "Preparing fields"); // The response columns will be in the same order we request them, we need the key // before we can process any values so ensure the first column is the key column. // var sortedColumns = fieldMapping.OrderByDescending(c => c is IPullKeyColumn).ToList(); // We can only use public API. No data filters. // We use a data filter when possible as it allows us to remove a lot of unnecessary information, // such as unneeded sheets and columns, which reduces the size of the response. A Data filter can only be used with OAuth authentication. reporter?.ReportProgress("Generating request", 0.1f); // TODO we need to get the json data. // ClientServiceRequest<Spreadsheet> pullReq = UsingApiKey // ? GeneratePullRequest() // : GenerateFilteredPullRequest(sheetId, fieldMapping); reporter?.ReportProgress("Sending request", 0.2f); var table = TableDatabase.Get.GetTable(TableId); reporter?.ReportProgress("Validating response", 0.5f); // When using an API key we get all the sheets so we need to extract the one we are pulling from. if (table == null) { throw new Exception($"No table data available for {TableId}"); } // The data will be structured differently if we used a filter or not so we need to extract the parts we need. var pulledRows = new List <(uint valueIndex, TableRow rowData)>(); if (UsingApiKey) { // When getting the whole sheet all the columns are stored in a single Data. We need to extract the correct value index for each column. // foreach (var sortedCol in sortedColumns) // { // TableRow row = table.Rows[0]; // pulledRows.Add((row.Fields.Values, sortedCol.ColumnIndex)); // } } else { // TODO check the fieldmapping count and see if it is equal to the object children amount // When using a filter each Data represents a single column. pulledRows = table.Rows.Select(t => (t.Key, t.Value)).ToList(); } MergePull(pulledRows, collection, fieldMapping, removeMissingEntries, reporter); // There is a bug that causes Undo to not set assets dirty (case 1240528) so we always set the asset dirty. modifiedAssets.ForEach(EditorUtility.SetDirty); // if(LocalizationEditorSettings.EditorEvents.CollectionModified != null) LocalizationEditorSettings.EditorEvents.RaiseCollectionMod(this, collection); AssetDatabase.SaveAssets(); } catch (Exception e) { reporter?.Fail(e.Message); throw; } }
public override void PushHeader(StringTableCollection collection, out string header, out string headerNote) { header = $"{LocaleIdentifier.ToString()} Comments"; headerNote = null; }
/// <summary> /// Pulls data from the Spreadsheet with id <see cref="SpreadSheetId"/> and uses <paramref name="columnMapping"/> /// to populate the <paramref name="collection"/>. /// </summary> /// <param name="sheetId">The sheet(Spreadsheet tab) to pull the data from.</param> /// <param name="collection">The collection to insert the data into.</param> /// <param name="columnMapping">The column mappings control what data will be extracted for each column of the sheet. The list must contain 1 <see cref="IPullKeyColumn"/>.</param> /// <param name="removeMissingEntries">After a pull has completed any keys that exist in the <paramref name="collection"/> but did not exist in the sheet are considered missing, /// this may be because they have been deleted from the sheet. A value of true will remove these missing entries where false will preserve them.</param> /// <param name="reporter">Optional reporter to display the progress and status of the task.</param> /// <param name="createUndo">Should an Undo be recorded so any changes can be reverted?</param> public void PullIntoStringTableCollection(int sheetId, StringTableCollection collection, IList <SheetColumn> columnMapping, bool removeMissingEntries = false, ITaskReporter reporter = null, bool createUndo = false) { VerifyPushPullArguments(sheetId, collection, columnMapping, typeof(IPullKeyColumn)); try { var modifiedAssets = collection.StringTables.Select(t => t as Object).ToList(); modifiedAssets.Add(collection.SharedData); if (createUndo) { Undo.RecordObjects(modifiedAssets.ToArray(), $"Pull `{collection.TableCollectionName}` from Google sheets"); } reporter?.Start($"Pull `{collection.TableCollectionName}` from Google sheets", "Preparing columns"); // The response columns will be in the same order we request them, we need the key // before we can process any values so ensure the first column is the key column. var sortedColumns = columnMapping.OrderByDescending(c => c is IPullKeyColumn).ToList(); // We can only use public API. No data filters. // We use a data filter when possible as it allows us to remove a lot of unnecessary information, // such as unneeded sheets and columns, which reduces the size of the response. A Data filter can only be used with OAuth authentication. reporter?.ReportProgress("Generating request", 0.1f); ClientServiceRequest <Spreadsheet> pullReq = UsingApiKey ? GeneratePullRequest() : GenerateFilteredPullRequest(sheetId, columnMapping); reporter?.ReportProgress("Sending request", 0.2f); var response = ExecuteRequest <Spreadsheet, ClientServiceRequest <Spreadsheet> >(pullReq); reporter?.ReportProgress("Validating response", 0.5f); // When using an API key we get all the sheets so we need to extract the one we are pulling from. var sheet = UsingApiKey ? response.Sheets?.FirstOrDefault(s => s?.Properties?.SheetId == sheetId) : response.Sheets[0]; if (sheet == null) { throw new Exception($"No sheet data available for {sheetId} in Spreadsheet {SpreadSheetId}."); } // The data will be structured differently if we used a filter or not so we need to extract the parts we need. var pulledColumns = new List <(IList <RowData> rowData, int valueIndex)>(); if (UsingApiKey) { // When getting the whole sheet all the columns are stored in a single Data. We need to extract the correct value index for each column. foreach (var sortedCol in sortedColumns) { pulledColumns.Add((sheet.Data[0].RowData, sortedCol.ColumnIndex)); } } else { if (sheet.Data.Count != columnMapping.Count) { throw new Exception($"Column mismatch. Expected a response with {columnMapping.Count} columns but only got {sheet.Data.Count}"); } // When using a filter each Data represents a single column. foreach (var d in sheet.Data) { pulledColumns.Add((d.RowData, 0)); } } MergePull(pulledColumns, collection, columnMapping, removeMissingEntries, reporter); // There is a bug that causes Undo to not set assets dirty (case 1240528) so we always set the asset dirty. modifiedAssets.ForEach(EditorUtility.SetDirty); LocalizationEditorSettings.EditorEvents.RaiseCollectionModified(this, collection); } catch (Exception e) { reporter?.Fail(e.Message); throw; } }
/// <summary> /// Populate the document with the entries from <paramref name="target"/> using <paramref name="source"/> as the source reference. /// Note: The source and target tables must be part of the same collection, they must both use the same <see cref="SharedTableData"/>. /// </summary> /// <param name="document">The XLIFF document to add the entries to.</param> /// <param name="source"></param> /// <param name="target"></param> public static void AddTableToDocument(IXliffDocument document, StringTable source, StringTable target) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (source == null) { throw new ArgumentNullException(nameof(source)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } if (source.SharedData != target.SharedData) { throw new Exception("Source and Target StringTables must be part of the same collection and use the same SharedTableData."); } var file = document.AddNewFile(); var filePath = AssetDatabase.GetAssetPath(target); file.Original = filePath; file.Id = AssetDatabase.AssetPathToGUID(filePath); var group = file.AddNewGroup(); group.Id = TableReference.StringFromGuid(target.SharedData.TableCollectionNameGuid); group.Name = target.SharedData.TableCollectionName; AddNotesFromMetadata(group, target.SharedData.Metadata, NoteType.General); AddNotesFromMetadata(group, source, NoteType.Source); if (source != target) { AddNotesFromMetadata(group, target, NoteType.Target); } foreach (var row in StringTableCollection.GetRowEnumerator(source, target)) { var unit = group.AddNewTranslationUnit(); unit.Id = row.KeyEntry.Id.ToString(); unit.Name = row.KeyEntry.Key; unit.Source = row.TableEntries[0]?.Value; // Dont add a value if its empty. if (row.TableEntries[1] != null && !string.IsNullOrEmpty(row.TableEntries[1].Value)) { unit.Target = row.TableEntries[1].Value; } // Add notes AddNotesFromMetadata(unit, row.KeyEntry.Metadata, NoteType.General); AddNotesFromMetadata(unit, row.TableEntries[0], NoteType.Source); if (source != target) { AddNotesFromMetadata(unit, row.TableEntries[1], NoteType.Target); } } }
public override void PushHeader(StringTableCollection collection, out string header, out string headerNote) { // The title of the Google Sheet column header = "My Custom Data"; headerNote = null; }
void MergePull(Sheet sheet, StringTableCollection collection, IList <SheetColumn> columnMapping, bool removeMissingEntries, ITaskReporter reporter) { reporter?.ReportProgress("Preparing to merge", 0.55f); // Keep track of any issues for a single report instead of filling the console. var messages = new StringBuilder(); var keyColumn = columnMapping[0] as IPullKeyColumn; Debug.Assert(keyColumn != null, "Expected the first column to be a Key column"); var rowCount = sheet.Data[0].RowData.Count; // Send the start message foreach (var col in columnMapping) { col.PullBegin(collection); } reporter?.ReportProgress("Merging response into collection", 0.6f); var keysProcessed = new HashSet <uint>(); uint totalCellsProcessed = 0; for (int row = 0; row < rowCount; row++) { var keyColData = sheet.Data[0]; var keyRowData = keyColData.RowData[row].Values[0]; var keyValue = keyRowData.FormattedValue; var keyNote = keyRowData.Note; var rowKeyEntry = keyColumn.PullKey(keyValue, keyNote); if (rowKeyEntry == null) { messages.AppendLine($"No key data was found for row {row} with Value '{keyValue}' and Note '{keyNote}'."); continue; } // Record the id so we can check what key ids were missing later. keysProcessed.Add(rowKeyEntry.Id); totalCellsProcessed++; for (int col = 1; col < columnMapping.Count; ++col) { var colData = sheet.Data[col]; // Do we have data in this column for this row? if (colData.RowData?.Count > row && colData.RowData[row].Values?.Count > 0) { var cellData = colData.RowData[row].Values[0]; columnMapping[col].PullCellData(rowKeyEntry, cellData.FormattedValue, cellData.Note); totalCellsProcessed++; } } } if (removeMissingEntries) { reporter?.ReportProgress("Removing missing entries", 0.9f); RemoveMissingEntries(keysProcessed, collection, messages); } reporter?.Completed($"Completed merge of {rowCount} rows and {totalCellsProcessed} cells from {columnMapping.Count} columns successfully.\n{messages.ToString()}"); }
void GeneratePushRequests(int sheetId, StringTableCollection collection, IList <SheetColumn> columnMapping, List <Request> requestsToSend, ITaskReporter reporter) { // Prepare the tables - Sort the keys and table entries reporter?.ReportProgress("Sorting entries", 0.2f); var sortedKeyEntries = collection.SharedData.Entries.OrderBy(e => e.Id); var sortedTableEntries = new List <IOrderedEnumerable <StringTableEntry> >(); foreach (var table in collection.StringTables) { if (table != null) { var s = table.Values.OrderBy(e => e.KeyId); sortedTableEntries.Add(s); } } // Extract all the data so we can generate a request to send // We go through each Key, extract the table entries for that key if they exists and then pass this to each column. var currentTableRowIterator = sortedTableEntries.Select(o => { var itr = o.GetEnumerator(); itr.MoveNext(); return(itr); }).ToArray(); // Prepare the column requests. // We use a request per column as its possible that some columns in the sheet will be preserved and we don't want to write over them. reporter?.ReportProgress("Generating column headers", 0.25f); var columnSheetRequests = new List <PushColumnSheetRequest>(columnMapping.Count); foreach (var col in columnMapping) { var colRequest = new PushColumnSheetRequest(sheetId, col); columnSheetRequests.Add(colRequest); colRequest.Column.PushBegin(collection); colRequest.Column.PushHeader(collection, out var header, out var note); colRequest.AddHeader(header, note); } // Populate the requests from the string tables var currentTableRow = new StringTableEntry[sortedTableEntries.Count]; foreach (var keyRow in sortedKeyEntries) { // Extract the string table entries for this row for (int i = 0; i < currentTableRow.Length; ++i) { var tableRowItr = currentTableRowIterator[i]; if (tableRowItr.Current?.KeyId == keyRow.Id) { currentTableRow[i] = tableRowItr.Current; tableRowItr.MoveNext(); } else { currentTableRow[i] = null; } } // Now process each sheet column so they can update their requests. foreach (var colReq in columnSheetRequests) { colReq.Column.PushCellData(keyRow, currentTableRow, out var value, out var note); colReq.AddRow(value, note); } } foreach (var col in columnSheetRequests) { col.Column.PushEnd(); requestsToSend.AddRange(col.Requests); } }
public override void PullBegin(StringTableCollection collection) { m_SharedTableData = collection.SharedData; }
public override void PushHeader(StringTableCollection collection, out string header, out string headerNote) { header = ColumnHeader; headerNote = null; }
/// <summary> /// Exports all <see cref="UnityEngine.Localization.Tables.StringTable"/> in <paramref name="collection"/> using default column mappings generated through /// <see cref="ColumnMapping.CreateDefaultMapping(bool)"/>. /// </summary> /// <param name="writer">The target that will be populated with CSV data.</param> /// <param name="collection">The collection to export to CSV.</param> /// <param name="reporter">An optional reporter that can be used to provide feedback during export.</param> /// <example> /// This example shows how to export a <see cref="StringTableCollection"/> to a csv file. /// <code> /// using (var stream = new StreamWriter("my CSV file.csv", false, Encoding.UTF8)) /// { /// var stringTableCollection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); /// Export(stream, stringTableCollection); /// } /// </code> /// </example> public static void Export(TextWriter writer, StringTableCollection collection, ITaskReporter reporter = null) { Export(writer, collection, ColumnMapping.CreateDefaultMapping(), reporter); }
public override void PushBegin(StringTableCollection collection) { throw new NotImplementedException(); }