Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Feature Request Ability to get all entries within a Table

Discussion in 'Localization Tools' started by rowanwaring, Oct 6, 2020.

  1. rowanwaring

    rowanwaring

    Joined:
    Mar 6, 2018
    Posts:
    6
    Hello again!

    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.

    Thanks!
     
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,422
    Hey,

    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.

    Code (csharp):
    1.  
    2. var collection = LocalizationEditorSettings.GetStringTableCollection("My Strings");
    3.  
    4.  var table = collection.GetTable("en") as StringTable;
    5.  
    6.  foreach(var v in table.Values)
    7.  {
    8.    
    9.  
    10.  }
     
  3. rowanwaring

    rowanwaring

    Joined:
    Mar 6, 2018
    Posts:
    6
    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:

    Code (CSharp):
    1. foreach(var v in table.Values)
    2. {
    3.       string key = Collection.SharedData.GetKey(v.KeyId);
    4. }
     
  4. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,422
    Yes thats how it works.

    This is the code to generate an enumerator if you want to try and use it now

    Code (csharp):
    1.  
    2. public class Row<TEntry> where TEntry : TableEntry
    3.         {
    4.             /// <summary>
    5.             /// The <see cref="LocaleIdentifier"/> for each table value in <see cref="TableEntries"/>.
    6.             /// The order of the tables is guaranteed not to change.
    7.             /// </summary>
    8.             public LocaleIdentifier[] TableEntriesReference { get; internal set; }
    9.  
    10.             /// <summary>
    11.             /// The Key for the current row.
    12.             /// </summary>
    13.             public SharedTableData.SharedTableEntry KeyEntry { get; internal set; }
    14.  
    15.             /// <summary>
    16.             /// The entries taken from all the tables for the current <see cref="KeyEntry"/>.
    17.             /// The value may be null, such as when the table does not have a value for the current key.
    18.             /// </summary>
    19.             public TEntry[] TableEntries { get; internal set; }
    20.         }
    21.  
    22.  
    23. protected static IEnumerable<Row<TEntry>> GetRowEnumerator<TTable, TEntry>(IEnumerable<TTable> tables)
    24.             where TTable : DetailedLocalizationTable<TEntry>
    25.             where TEntry : TableEntry
    26.         {
    27.             if (tables == null)
    28.                 throw new ArgumentException();
    29.  
    30.             SharedTableData sharedTableData = null;
    31.  
    32.             // Prepare the tables - Sort the keys and table entries
    33.             var sortedTableEntries = new List<IOrderedEnumerable<TEntry>>();
    34.             foreach (var table in tables)
    35.             {
    36.                 if (sharedTableData == null)
    37.                 {
    38.                     sharedTableData = table.SharedData;
    39.                 }
    40.                 else if (sharedTableData != table.SharedData)
    41.                 {
    42.                     throw new Exception("All tables must share the same SharedData.");
    43.                 }
    44.  
    45.                 if (table != null)
    46.                 {
    47.                     var s = table.Values.OrderBy(e => e.KeyId);
    48.                     sortedTableEntries.Add(s);
    49.                 }
    50.             }
    51.  
    52.             var sortedKeyEntries = sharedTableData.Entries.OrderBy(e => e.Id);
    53.  
    54.             var currentTableRowIterator = sortedTableEntries.Select(o =>
    55.             {
    56.                 var itr = o.GetEnumerator();
    57.                 itr.MoveNext();
    58.                 return itr;
    59.             }).ToArray();
    60.  
    61.             var currentRow = new Row<TEntry>
    62.             {
    63.                 TableEntriesReference = tables.Select(t => t.LocaleIdentifier).ToArray(),
    64.                 TableEntries = new TEntry[sortedTableEntries.Count]
    65.             };
    66.  
    67.             using (StringBuilderPool.Get(out var warningMessage))
    68.             {
    69.                 // Extract the table row values for this key.
    70.                 // If the table has a key value then add it to currentTableRow otherwise use null.
    71.                 foreach (var keyRow in sortedKeyEntries)
    72.                 {
    73.                     currentRow.KeyEntry = keyRow;
    74.  
    75.                     // Extract the string table entries for this row
    76.                     for (int i = 0; i < currentRow.TableEntries.Length; ++i)
    77.                     {
    78.                         var tableRowItr = currentTableRowIterator[i];
    79.  
    80.                         // Skip any table entries that may not not exist in Shared Data
    81.                         while (tableRowItr != null && tableRowItr.Current?.KeyId < keyRow.Id)
    82.                         {
    83.                             warningMessage.AppendLine($"{tableRowItr.Current.Table.name} - {tableRowItr.Current.KeyId} - {tableRowItr.Current.Data.Localized}");
    84.                             if (!tableRowItr.MoveNext())
    85.                             {
    86.                                 currentTableRowIterator[i] = null;
    87.                                 break;
    88.                             }
    89.                         }
    90.  
    91.                         if (tableRowItr?.Current?.KeyId == keyRow.Id)
    92.                         {
    93.                             currentRow.TableEntries[i] = tableRowItr.Current;
    94.                             if (!tableRowItr.MoveNext())
    95.                             {
    96.                                 currentTableRowIterator[i] = null;
    97.                             }
    98.                         }
    99.                         else
    100.                         {
    101.                             currentRow.TableEntries[i] = null;
    102.                         }
    103.                     }
    104.  
    105.                     yield return currentRow;
    106.                 }
    107.  
    108.                 // Any warning messages?
    109.                 if (warningMessage.Length > 0)
    110.                 {
    111.                     warningMessage.Insert(0, "Found entries in Tables that were missing a Shared Table Data Entry. These entries were ignored:\n");
    112.                     Debug.LogWarning(warningMessage.ToString(), sharedTableData);
    113.                 }
    114.             }
    115.         }
    116.