using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using UnityEngine.Localization;
using UnityEngine.Localization.Metadata;
using UnityEngine.Localization.Tables;
using static UnityEngine.Localization.Tables.SharedTableData;
namespace UnityEditor.Localization
{
///
/// Provides methods for managing multiple in the Editor.
///
public class StringTableCollection : LocalizationTableCollection
{
///
protected internal override Type TableType => typeof(StringTable);
///
protected internal override Type RequiredExtensionAttribute => typeof(StringTableCollectionExtensionAttribute);
///
protected internal override string DefaultGroupName => "String Table";
///
/// A helper property which is the contents of loaded and cast to .
///
public virtual ReadOnlyCollection StringTables => new ReadOnlyCollection(Tables.Select(t => t.asset as StringTable).ToList().AsReadOnly());
///
/// Returns a string that contains all the unique characters that are used for all localized values in the tables that belong to the supplied 's.
/// This will also include Smart String entries but will only consider the values,
/// it will not consider values.
///
/// The tables to be included.
/// All distinct characters or an empty string if no tables or entries..
public string GenerateCharacterSet(params LocaleIdentifier[] localeIdentifiers)
{
if (localeIdentifiers == null || localeIdentifiers.Length == 0)
throw new ArgumentException(nameof(localeIdentifiers), "Must provide at least 1 LocaleIdentifier");
var characters = ExtractLiteralCharacters(localeIdentifiers);
var distinct = characters.Distinct().OrderBy(c => c);
return string.Concat(distinct);
}
internal IEnumerable ExtractLiteralCharacters(params LocaleIdentifier[] localeIdentifiers)
{
IEnumerable e = "";
foreach (var id in localeIdentifiers)
{
// Create an enumerator for all the tables and entries.
var table = GetTable(id) as StringTable;
if (table != null)
e = e.Concat(table.CollectLiteralCharacters());
}
return e;
}
///
/// Updates the collection entries with a and optionally removes entries that are missing from the update.
/// Used by various importers such as and .
///
/// The entries that should not be removed if is .
/// The new sorted entries.
/// Optional log for reporting what entries were removed.
/// Should missing entries be removed? If they will be placed at the end after the sorted entries.
internal void MergeUpdatedEntries(HashSet entriesToKeep, List sortedEntries, StringBuilder removedEntriesLog, bool removeMissingEntries)
{
// We either remove missing entries or add them to the end.
var stringTables = StringTables;
removedEntriesLog.AppendLine("Removed missing entries:");
for (int i = 0; i < SharedData.Entries.Count; ++i)
{
var entry = SharedData.Entries[i];
if (entriesToKeep.Contains(entry.Id))
continue;
if (!removeMissingEntries)
{
// Missing entries that we want to keep go to the bottom of the list.
sortedEntries.Add(entry);
}
else if (entry.Metadata.HasMetadata())
{
// Add back the entry which has ExcludeEntryFromExport Metadata.
sortedEntries.Insert(i, entry);
}
else
{
removedEntriesLog.AppendLine($" {entry}");
// Remove from tables
foreach (var table in stringTables)
{
table.Remove(entry.Id);
}
}
}
// Now replace the old list with our new one that is in the correct order.
SharedData.Entries = sortedEntries;
}
///
/// Returns an enumerator that can be used to step through each key and its localized values, such as in a foreach loop.
/// Internally and 's are separate assets with their own internal list of values.
/// This means that when iterating through each key a lookup must be made in each table in order to retrieve the localized value,
/// this can become slow when dealing with a large number of tables and entries.
/// GetRowEnumerator improves this process by first sorting the multiple internal lists and then stepping through each conceptual row at a time.
/// It handles missing keys and table entries and provides a more efficient and faster way to iterate through the tables.
///
///
/// This example shows how a StringTableCollection could be exported as CSV.
///
///
///
public IEnumerable> GetRowEnumerator() => GetRowEnumerator(StringTables);
///
/// Returns an enumerator that can be used to step through each key and its localized values, such as in a foreach loop.
/// This version does not sort the items by the Key Id but instead returns them in the order of the .
/// If the order of the rows is not important then using will provide better performance.
///
///
public IEnumerable> GetRowEnumeratorUnsorted() => GetRowEnumeratorUnsorted(StringTables);
///
///
///
///
///
public static IEnumerable> GetRowEnumerator(params StringTable[] tables) => GetRowEnumerator(tables);
///
public override void RemoveEntry(TableEntryReference entryReference)
{
var entry = SharedData.GetEntryFromReference(entryReference);
if (entry == null)
return;
foreach (var table in StringTables)
table.RemoveEntry(entry.Id);
SharedData.RemoveKey(entry.Key);
LocalizationEditorSettings.EditorEvents.RaiseTableEntryRemoved(this, entry);
}
///
public override void ClearAllEntries()
{
foreach (var table in StringTables)
{
if (table == null)
continue;
table.Clear();
EditorUtility.SetDirty(table);
}
base.ClearAllEntries();
}
}
}