I was wondering if it would be possible to have a sort of **List<StringTableEntry> GetAllEntries()** that returns all entries within a given table (for example with a StringTable), at least read only? There doesn’t seem to be a way to do something like that already - and the way tables are displayed leads me to believe the underlying pattern used might be able to support something like this.
If it were at least readonly, I could find a lot of use for it - in other posts, I’ve alluded to a use case of writing an editor window that interfaces between say, this Localization system and other systems a project might have (as means of another way of interfacing with the Localization system without going to it’s dedicated editor) - and being able to more or less display all existing entries within a table is something I find myself seeing value in.
I’d assume there’s probably more of a map or hashing solution under the hood to how a table stores Key/Value entries, but even then we should be able to iterate over that type of collection via KeyValuePair or something alike? I may be pretty ignorant here as I’m still trying to figure out how all the Localization data structures interplay, but, it still seems like a logical train of thought as it stands.
There’s a few options. I suspect what you want it an enumerator to go through all the key, id and table values?
In the next release we have:
Added GetRowEnumerator to AssetTableCollection and StringTableCollection. This can be used to step through each key and its localized values.
This sorts the table entries and provides an enumerator to let you step through the items as if they were one big spreadsheet of rows and columns.
However, tables also implement IDictionary<long, TEntry> so you can get the table entries from the Values property now.
var collection = LocalizationEditorSettings.GetStringTableCollection("My Strings");
var table = collection.GetTable("en") as StringTable;
foreach(var v in table.Values)
{
}
Ahhh, that GetRowEnumerator sounds close to what I’m looking for - as it gets the Keys as well.
It sounds like it will also return localized values for every supported locale that that Key has?
I suppose in the interim I could implement a workaround using some information you provided in another post of mine to find the keys for each table.Value as outline above with something like:
foreach(var v in table.Values)
{
string key = Collection.SharedData.GetKey(v.KeyId);
}
This is the code to generate an enumerator if you want to try and use it now
public class Row<TEntry> where TEntry : TableEntry
{
/// <summary>
/// The <see cref="LocaleIdentifier"/> for each table value in <see cref="TableEntries"/>.
/// The order of the tables is guaranteed not to change.
/// </summary>
public LocaleIdentifier[] TableEntriesReference { get; internal set; }
/// <summary>
/// The Key for the current row.
/// </summary>
public SharedTableData.SharedTableEntry KeyEntry { get; internal set; }
/// <summary>
/// The entries taken from all the tables for the current <see cref="KeyEntry"/>.
/// The value may be null, such as when the table does not have a value for the current key.
/// </summary>
public TEntry[] TableEntries { get; internal set; }
}
protected static IEnumerable<Row<TEntry>> GetRowEnumerator<TTable, TEntry>(IEnumerable<TTable> tables)
where TTable : DetailedLocalizationTable<TEntry>
where TEntry : TableEntry
{
if (tables == null)
throw new ArgumentException();
SharedTableData sharedTableData = null;
// Prepare the tables - Sort the keys and table entries
var sortedTableEntries = new List<IOrderedEnumerable<TEntry>>();
foreach (var table in tables)
{
if (sharedTableData == null)
{
sharedTableData = table.SharedData;
}
else if (sharedTableData != table.SharedData)
{
throw new Exception("All tables must share the same SharedData.");
}
if (table != null)
{
var s = table.Values.OrderBy(e => e.KeyId);
sortedTableEntries.Add(s);
}
}
var sortedKeyEntries = sharedTableData.Entries.OrderBy(e => e.Id);
var currentTableRowIterator = sortedTableEntries.Select(o =>
{
var itr = o.GetEnumerator();
itr.MoveNext();
return itr;
}).ToArray();
var currentRow = new Row<TEntry>
{
TableEntriesReference = tables.Select(t => t.LocaleIdentifier).ToArray(),
TableEntries = new TEntry[sortedTableEntries.Count]
};
using (StringBuilderPool.Get(out var warningMessage))
{
// Extract the table row values for this key.
// If the table has a key value then add it to currentTableRow otherwise use null.
foreach (var keyRow in sortedKeyEntries)
{
currentRow.KeyEntry = keyRow;
// Extract the string table entries for this row
for (int i = 0; i < currentRow.TableEntries.Length; ++i)
{
var tableRowItr = currentTableRowIterator[i];
// Skip any table entries that may not not exist in Shared Data
while (tableRowItr != null && tableRowItr.Current?.KeyId < keyRow.Id)
{
warningMessage.AppendLine($"{tableRowItr.Current.Table.name} - {tableRowItr.Current.KeyId} - {tableRowItr.Current.Data.Localized}");
if (!tableRowItr.MoveNext())
{
currentTableRowIterator[i] = null;
break;
}
}
if (tableRowItr?.Current?.KeyId == keyRow.Id)
{
currentRow.TableEntries[i] = tableRowItr.Current;
if (!tableRowItr.MoveNext())
{
currentTableRowIterator[i] = null;
}
}
else
{
currentRow.TableEntries[i] = null;
}
}
yield return currentRow;
}
// Any warning messages?
if (warningMessage.Length > 0)
{
warningMessage.Insert(0, "Found entries in Tables that were missing a Shared Table Data Entry. These entries were ignored:\n");
Debug.LogWarning(warningMessage.ToString(), sharedTableData);
}
}
}