示例#1
0
    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);
                }
            }
        }
示例#3
0
    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);
        }
    }
示例#4
0
        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);
        }
示例#5
0
        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);
     }
 }
示例#9
0
    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;
            }
        }
示例#11
0
        /// <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;
                }
            }
        }
示例#12
0
        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);
            }
        }
示例#13
0
        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);
            }
        }
示例#14
0
    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();
    }
示例#15
0
        /// <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;
            }
        }
示例#16
0
        /// <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);
            }
        }
示例#18
0
        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);
        }
示例#19
0
 public override void PushBegin(StringTableCollection collection)
 {
 }
示例#20
0
        /// <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;
            }
        }
示例#21
0
 public override void PushHeader(StringTableCollection collection, out string header, out string headerNote)
 {
     header     = $"{LocaleIdentifier.ToString()} Comments";
     headerNote = null;
 }
示例#22
0
        /// <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;
            }
        }
示例#23
0
        /// <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);
                }
            }
        }
示例#24
0
 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);
            }
        }
示例#27
0
 public override void PullBegin(StringTableCollection collection)
 {
     m_SharedTableData = collection.SharedData;
 }
示例#28
0
 public override void PushHeader(StringTableCollection collection, out string header, out string headerNote)
 {
     header     = ColumnHeader;
     headerNote = null;
 }
示例#29
0
 /// <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);
 }
示例#30
0
 public override void PushBegin(StringTableCollection collection)
 {
     throw new NotImplementedException();
 }