Example #1
0
        /// <summary>
        /// Imports a single XLIFF document into the project.
        /// Attempts to find matching <see cref="StringTableCollection"/>'s, if one could not be found then a new one is created.
        /// </summary>
        /// <param name="document">The root XLIFF document.</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 ImportDocument(IXliffDocument document, ImportOptions importOptions = null, ITaskReporter reporter = null)
        {
            if (document == null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            reporter?.Start("Importing XLIFF", "Importing document");

            try
            {
                float progress = reporter == null ? 0.1f : reporter.CurrentProgress + 0.1f;
                reporter?.ReportProgress("Importing XLIFF into project", progress);

                float progressStep = document.FileCount / (1.0f - progress);
                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);
                    ImportFileNode(f, document.SourceLanguage, document.TargetLanguage, options);
                }

                reporter?.Completed("Finished importing XLIFF");
            }
            catch (Exception e)
            {
                reporter?.Fail(e.Message);
                throw;
            }
        }
Example #2
0
        /// <summary>
        /// Imports all XLIFF files with the extensions xlf or xliff into existing <see cref="StringTableCollection"/> or new ones if a matching one could not be found.
        /// </summary>
        /// <param name="directory">The directory to search. Searches sub directories as well.</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 ImportDirectory(string directory, ImportOptions importOptions = null, ITaskReporter reporter = null)
        {
            try
            {
                reporter?.Start("Importing XLIFF files in directory", "Finding xlf and xliff files.");

                var files         = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
                var filteredFiles = files.Where(s => s.EndsWith(".xlf") || s.EndsWith(".xliff"));

                float taskStep = filteredFiles.Count() / 1.0f;
                float progress = taskStep;

                foreach (var f in filteredFiles)
                {
                    reporter?.ReportProgress($"Importing {f}", progress);
                    progress += taskStep;

                    // Don't pass the reporter in as it will be Completed after each file and we only want to do that at the end.
                    ImportFile(f, importOptions);
                }
                reporter?.Completed("Finished importing XLIFF files");
            }
            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;
                }
            }
        }
Example #4
0
        /// <summary>
        /// Creates a new Google Spreadsheet.
        /// </summary>
        /// <param name="spreadSheetTitle">The title of the Spreadsheet.</param>
        /// <param name="sheetTtitle">The title of the sheet(tab) that is part of the Spreadsheet.</param>
        /// <param name="newSheetProperties"></param>
        /// <param name="reporter">Optional reporter to display the progress and status of the task.</param>
        /// <returns>Returns the new Spreadsheet and sheet id.</returns>
        public (string spreadSheetId, int sheetId) CreateSpreadsheet(string spreadSheetTitle, string sheetTitle, NewSheetProperties newSheetProperties, ITaskReporter reporter = null)
        {
            if (newSheetProperties == null)
            {
                throw new ArgumentNullException(nameof(newSheetProperties));
            }

            try
            {
                reporter?.Start("Create Spreadsheet", "Preparing Request");

                var createRequest = SheetsService.Service.Spreadsheets.Create(new Spreadsheet
                {
                    Properties = new SpreadsheetProperties
                    {
                        Title = spreadSheetTitle
                    },
                    Sheets = new Sheet[]
                    {
                        new Sheet
                        {
                            Properties = new SheetProperties
                            {
                                Title = sheetTitle,
                            }
                        }
                    }
                });

                reporter?.ReportProgress("Sending create request", 0.2f);
                var createResponse = ExecuteRequest <Spreadsheet, CreateRequest>(createRequest);
                SpreadSheetId = createResponse.SpreadsheetId;
                var sheetId = createResponse.Sheets[0].Properties.SheetId.Value;

                reporter?.ReportProgress("Setting up new sheet", 0.5f);
                SetupSheet(SpreadSheetId, sheetId, newSheetProperties);

                reporter?.Completed(string.Empty);
                return(SpreadSheetId, sheetId);
            }
            catch (Exception e)
            {
                reporter?.Fail(e.Message);
                throw;
            }
        }
Example #5
0
        /// <summary>
        /// Export the values in <paramref name="tables"/> using <paramref name="sourceLanguage"/> as the source language to one or more XLIFF files.
        /// </summary>
        /// <param name="sourceLanguage">This is the table that will be used as the source language for all generated XLIFF files.</param>
        /// <param name="directory">The directory where all generated XLIFF files will be saved to.</param>
        /// <param name="version">The XLIFF version to generate the files in.</param>
        /// <param name="tables">1 or more <see cref="StringTable"/> that will be used as the target language for each XLIFF file. 1 XLIFF file will be generated for each table.</param>
        /// <param name="reporter">Optional reporter which can report the current progress.</param>
        public static void Export(StringTable sourceLanguage, string directory, XliffVersion version, ICollection <StringTable> tables, ITaskReporter reporter = null)
        {
            if (sourceLanguage == null)
            {
                throw new ArgumentNullException(nameof(sourceLanguage));
            }
            if (tables == null)
            {
                throw new ArgumentNullException(nameof(tables));
            }

            try
            {
                // Used for reporting
                float taskStep = 1.0f / (tables.Count * 2.0f);
                float progress = 0;
                reporter?.Start($"Exporting {tables.Count} String Tables to XLIFF", string.Empty);

                // We need the key, source value and translated value.
                foreach (var stringTable in tables)
                {
                    reporter?.ReportProgress($"Exporting {stringTable.name}", progress);
                    progress += taskStep;

                    var doc = CreateDocument(sourceLanguage.LocaleIdentifier, stringTable.LocaleIdentifier, version);
                    AddTableToDocument(doc, sourceLanguage, stringTable);

                    var cleanName = CleanFileName(stringTable.name);
                    var fileName  = $"{cleanName}.xlf";
                    var filePath  = Path.Combine(directory, fileName);
                    using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                    {
                        doc.Serialize(stream);
                    }
                }
                reporter?.Completed($"Finished exporting");
            }
            catch (Exception e)
            {
                reporter?.Fail(e.Message);
                throw;
            }
        }
Example #6
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;
            }
        }
Example #7
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;
            }
        }
Example #8
0
        /// <summary>
        /// Import an XLIFF document into the target table, ignoring <see cref="IXliffDocument.TargetLanguage"/>.
        /// </summary>
        /// <param name="document">The XLIFF document to import.</param>
        /// <param name="target">The target table that will be populated with the translated values.</param>
        /// <param name="importNotesBehavior">How should the notes be imported?</param>
        /// <param name="reporter">Optional reporter which can report the current progress.</param>
        public static void ImportDocumentIntoTable(IXliffDocument document, StringTable target, ImportNotesBehavior importNotesBehavior = ImportNotesBehavior.Replace, ITaskReporter reporter = null)
        {
            if (document == null)
            {
                throw new ArgumentNullException(nameof(document));
            }
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            EditorUtility.SetDirty(target);

            float progress = reporter == null ? 0 : reporter.CurrentProgress + 0.1f;

            reporter?.ReportProgress("Importing XLIFF into table", progress);

            float progressStep = document.FileCount / (1.0f - progress);

            var options = new ImportOptions {
                UpdateSourceTable = false, ImportNotes = importNotesBehavior
            };

            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);
                ImportIntoTables(f, null, target, options);
            }

            var collection = LocalizationEditorSettings.GetCollectionFromTable(target);

            if (collection != null)
            {
                LocalizationEditorSettings.EditorEvents.RaiseCollectionModified(document, collection);
            }

            reporter?.Completed("Finished importing XLIFF");
        }
        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()}");
        }
Example #10
0
        internal static void ExportSelected(LocaleIdentifier source, string dir, string name, XliffVersion version, Dictionary <StringTableCollection, HashSet <int> > collectionsWithSelectedIndexes, ITaskReporter reporter = null)
        {
            var documents = DictionaryPool <LocaleIdentifier, IXliffDocument> .Get();

            try
            {
                // Used for reporting
                int   totalTasks = collectionsWithSelectedIndexes.Sum(c => c.Value.Count);
                float taskStep   = 1.0f / (totalTasks * 2.0f);
                float progress   = 0;
                reporter?.Start($"Exporting {totalTasks} String Tables to XLIFF", string.Empty);

                foreach (var kvp in collectionsWithSelectedIndexes)
                {
                    var stringTableCollection = kvp.Key;
                    var sourceTable           = stringTableCollection.GetTable(source) as StringTable;
                    if (sourceTable == null)
                    {
                        var message = $"Collection {stringTableCollection.TableCollectionName} does not contain a table for the source language {source}";
                        reporter?.Fail(message);
                        throw new Exception(message);
                    }

                    foreach (var stringTableIndex in kvp.Value)
                    {
                        var stringTable = stringTableCollection.StringTables[stringTableIndex];

                        reporter?.ReportProgress($"Generating document for {stringTable.name}", progress);
                        progress += taskStep;

                        if (!documents.TryGetValue(stringTable.LocaleIdentifier, out var targetDoc))
                        {
                            targetDoc = CreateDocument(source, stringTable.LocaleIdentifier, version);
                            documents[stringTable.LocaleIdentifier] = targetDoc;
                        }

                        AddTableToDocument(targetDoc, sourceTable, stringTable);
                    }
                }

                // Now write the files
                foreach (var doc in documents)
                {
                    var cleanName = CleanFileName(name);
                    var fileName  = $"{cleanName}_{doc.Key.Code}.xlf";
                    var filePath  = Path.Combine(dir, fileName);

                    reporter?.ReportProgress($"Writing {fileName}", progress);
                    progress += taskStep;
                    using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                    {
                        doc.Value.Serialize(stream);
                    }
                }

                reporter?.Completed($"Finished exporting");
            }
            catch (Exception e)
            {
                reporter?.Fail(e.Message);
                throw;
            }
            finally
            {
                DictionaryPool <LocaleIdentifier, IXliffDocument> .Release(documents);
            }
        }
        /// <summary>
        /// Import the CSV data into <paramref name="collection"/> using default column mappings generated using <see cref="ColumnMapping.CreateDefaultMapping(bool)"/>.
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="collection"></param>
        /// <param name="columnMappings"></param>
        /// <param name="createUndo"></param>
        /// <param name="reporter"></param>
        public static void ImportInto(TextReader reader, StringTableCollection collection, IList <CsvColumns> columnMappings, bool createUndo = false, ITaskReporter reporter = null)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }
            if (collection == null)
            {
                throw new ArgumentNullException(nameof(collection));
            }
            VerifyColumnMappings(columnMappings);

            var modifiedAssets = collection.StringTables.Select(t => t as UnityEngine.Object).ToList();

            modifiedAssets.Add(collection.SharedData);

            if (createUndo)
            {
                Undo.RegisterCompleteObjectUndo(modifiedAssets.ToArray(), "Import CSV");
            }

            try
            {
                using (var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture))
                {
                    csvReader.Read();
                    csvReader.ReadHeader();

                    reporter?.Start("Importing CSV", string.Empty);
                    reporter?.ReportProgress("Mapping Headers", 0);
                    foreach (var col in columnMappings)
                    {
                        col.ReadBegin(collection, csvReader);
                    }

                    var keyCell = columnMappings.First(o => o is IKeyColumn) as IKeyColumn;

                    reporter?.ReportProgress("Reading Contents", 0.1f);
                    while (csvReader.Read())
                    {
                        var keyEntry = keyCell.ReadKey(csvReader);
                        foreach (var cell in columnMappings)
                        {
                            cell.ReadRow(keyEntry, csvReader);
                        }
                    }

                    foreach (var cell in columnMappings)
                    {
                        cell.ReadEnd(collection);
                    }
                }

                modifiedAssets.ForEach(EditorUtility.SetDirty);
                LocalizationEditorSettings.EditorEvents.RaiseCollectionModified(null, collection);
                reporter?.Completed("Finished Importing");
            }
            catch (Exception e)
            {
                reporter?.Fail("Failed Importing.\n" + e.Message);
                throw;
            }
        }