/// <summary> /// Gets the localized string from an already loaded table, taking into account whether we are in edit mode, play mode, or a build. /// </summary> /// <param name="localizedStringReference">The <see cref="LocalizedString"/>.</param> /// <returns>The localized string.</returns> public static string GetLocalizedStringImmediateSafe(this LocalizedString localizedStringReference) { // If we are in the editor in edit mode, we need to find a valid locale and get the localized string from it: #if UNITY_EDITOR if (EditorApplication.isPlaying) { return(string.Empty); } string text = null; if (!localizedStringReference.IsEmpty) { var tableCollection = LocalizationEditorSettings.GetStringTableCollection(localizedStringReference.TableReference); Locale locale = Editor_GetValidLocaleInEditMode(tableCollection); if (locale != null) { StringTable table = (StringTable)tableCollection.GetTable(locale.Identifier); if (table != null) { if (table.GetEntryFromReference(localizedStringReference.TableEntryReference) != null) { text = table.GetEntryFromReference(localizedStringReference.TableEntryReference).LocalizedValue; } } } } return(text); #else // At runtime (build or editor in play mode), we just get the localized string normally: return(localizedStringReference.GetLocalizedString()); #endif }
public void SetupTableOverrideInEditor() { // Get the 2 table collections. 1 for default and 1 for our chosen platform (PS4). var collection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); var collectionPs4 = LocalizationEditorSettings.GetStringTableCollection("My Strings PS4"); var englishTable = collection.GetTable("en") as StringTable; var englishTablePs4 = collectionPs4.GetTable("en") as StringTable; // Add the default entry var entry = englishTable.AddEntry("COPYRIGHT_NOTICE", "This is some copyright info for general platforms..."); // Add the entry we want to use on PS4 using the same entry name. englishTablePs4.AddEntry("COPYRIGHT_NOTICE", "This is some copyright info for PS4 platforms..."); // Set up the platform override so that COPYRIGHT_NOTICE redirects to a different table but uses the same key. var platformOverride = new PlatformOverride(); platformOverride.AddPlatformTableOverride(RuntimePlatform.PS4, "My Strings PS4"); entry.SharedEntry.Metadata.AddMetadata(platformOverride); // Mark the assets dirty so changes are saved EditorUtility.SetDirty(collection.SharedData); EditorUtility.SetDirty(englishTable); }
static void WriteLocalizedValue(string valueName, StreamWriter stream, Locale locale, LocalizedString localizedString, PlistDocument plistDocument) { if (localizedString.IsEmpty) { return; } var tableCollection = LocalizationEditorSettings.GetStringTableCollection(localizedString.TableReference); var table = tableCollection?.GetTable(locale.Identifier) as StringTable; var entry = table?.GetEntryFromReference(localizedString.TableEntryReference); if (entry == null || string.IsNullOrWhiteSpace(entry.LocalizedValue)) { // Use fallback? var fallBack = FallbackLocaleHelper.GetLocaleFallback(locale); if (fallBack != null) { WriteLocalizedValue(valueName, stream, fallBack, localizedString, plistDocument); return; } Debug.LogWarning($"{valueName}: Could not find a localized value for {locale} from {localizedString}"); return; } Debug.Assert(!entry.IsSmart, $"Localized App Values ({valueName}) do not support Smart Strings - {localizedString}"); stream.WriteLine($"\"{valueName}\" = \"{entry.LocalizedValue}\";"); plistDocument.root.SetString(valueName, string.Empty); }
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); } }
private void Initialize() { if (ID != UInt32.MaxValue && childId != UInt32.MaxValue) { // Only get the first dialogue. startDialogue = DialogueLine.ConvertRow(TableDatabase.Get.GetRow("dialogues", childId), overrideTable ? collection : LocalizationEditorSettings.GetStringTableCollection("Dialogues")); var field = TableDatabase.Get.GetField(Name, "data", ID); if (field != null) { StoryTable.ParseNodeData(this, (JObject)field.Data); } } if (characterID != UInt32.MaxValue) { TableDatabase database = TableDatabase.Get; Tuple <uint, TableRow> link = database.FindLink("characters", "name", characterID); if (link != null) { var field = database.GetField(link.Item2, "name"); if (field != null) { characterName = (string)field.Data; } Debug.Log(characterName); } } }
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); } }
public static void PullEnglish() { // Setup the connection to Google var sheetServiceProvider = GetServiceProvider(); var googleSheets = new GoogleSheets(sheetServiceProvider); googleSheets.SpreadSheetId = "My spread sheet id"; // We need to provide the Spreadsheet id. This can be found in the url. See docs for further info. // You should provide your String Table Collection name here var tableCollection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); // We need configure what each column contains in the sheet var columnMappings = new SheetColumn[] { // Column A contains the Key new KeyColumn { Column = "A" }, // Column B contains any shared comments. These are Comment Metadata in the Shared category. new KeyCommentColumn { Column = "B" }, // Column C contains the English Locale and any comments that are just for this Locale. new LocaleColumn { Column = "C", LocaleIdentifier = "en", IncludeComments = true }, }; int mySheetId = 123456; // This it the id of the sheet in the Google Spreadsheet. it will be in the url after `gid=`. googleSheets.PullIntoStringTableCollection(mySheetId, tableCollection, columnMappings); }
// Gets string table from collection name and locale code private static StringTable GetSourceStringTable(string source, string locale) { // Get source string table collection var sourceCollection = LocalizationEditorSettings.GetStringTableCollection(source); if (sourceCollection == null) { Debug.LogErrorFormat("GetSourceStringTable() could not find source string table collection '{0}'", source); return(null); } // Find table in source collection with locale code StringTable sourceTable = null; foreach (StringTable table in sourceCollection.StringTables) { if (table.LocaleIdentifier == locale) { sourceTable = table; break; } } // Handle table not found if (sourceTable == null) { Debug.LogErrorFormat("GetSourceStringTable() could not find source string table with locale code '{0}' in collection '{1}'", locale, source); return(null); } return(sourceTable); }
public LocalizedString GenerateLocalizedStringInEditor() { // The main advantage to using a table Guid and entry Id is that references will not be lost when changes are made to the Table name or Entry name. var collection = LocalizationEditorSettings.GetStringTableCollection("My String Table"); var entry = collection.SharedData.GetEntry("Start Game"); return(new LocalizedString(collection.SharedData.TableCollectionNameGuid, entry.Id)); }
/// <summary> /// This example show how to export a collection with default settings. /// </summary> public static void SimpleExport() { var collection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); using (var stream = new StreamWriter("My Strings CSV.csv", false, Encoding.UTF8)) { Csv.Export(stream, collection); } }
/// <summary> /// This example show how to import a collection with default settings. /// </summary> public static void SimpleImport() { var collection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); using (var stream = new StreamReader("My Strings CSV.csv")) { Csv.ImportInto(stream, collection); } }
public static void ImportCustomColumns() { var collection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); // Use custom column mappings to control what data gets imported. var columns = CreateCustomColumnMapping(); using (var stream = new StreamReader("My Strings CSV.csv")) { Csv.ImportInto(stream, collection, columns); } }
/// <summary> /// This example shows how to configure the data you wish to export in CSV. /// </summary> public static void ExportCustomColumns() { var collection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); // Use custom column mappings to control what data gets exported var columns = CreateCustomColumnMapping(); // Now export using (var stream = new StreamWriter("My Strings CSV.csv", false, Encoding.UTF8)) { Csv.Export(stream, collection, columns); } }
void DoTableAndEntryGUI(Rect rect, SerializedProperty property) { var tableRef = new SerializedTableReference(property.FindPropertyRelative("tableReference")); var entryRef = new SerializedTableEntryReference(property.FindPropertyRelative("tableEntryReference")); GUIContent valueLabel; if (tableRef.Reference.ReferenceType != TableReference.Type.Empty && entryRef.Reference.ReferenceType != TableEntryReference.Type.Empty) { LocalizationTableCollection collection = null; if (m_TableType == typeof(StringTable)) { collection = LocalizationEditorSettings.GetStringTableCollection(tableRef.Reference); } else { collection = LocalizationEditorSettings.GetAssetTableCollection(tableRef.Reference); } valueLabel = new GUIContent($"{GetTableLabel(tableRef.Reference)}/{GetEntryLabel(entryRef.Reference, collection?.SharedData)}"); } else { valueLabel = Styles.none; } var dropDownPosition = EditorGUI.PrefixLabel(rect, Styles.reference); if (EditorGUI.DropdownButton(dropDownPosition, valueLabel, FocusType.Passive)) { Type assetType; if (m_TableType == typeof(AssetTable)) { var assetTableCollection = m_Collection as AssetTableCollection; assetType = assetTableCollection.GetEntryAssetType(entryRef.Reference); } else { assetType = typeof(string); } var treeSelection = new TableEntryTreeView(assetType, (c, e) => { entryRef.Reference = e != null ? e.Id : SharedTableData.EmptyId; tableRef.Reference = c != null ? c.TableCollectionNameReference : default(TableReference); property.serializedObject.ApplyModifiedProperties(); }); PopupWindow.Show(dropDownPosition, new TreeViewPopupWindow(treeSelection) { Width = dropDownPosition.width }); } }
public static void PullWithExtension() { // You should provide your String Table Collection name here var tableCollection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); var googleExtension = tableCollection.Extensions.FirstOrDefault(e => e is GoogleSheetsExtension) as GoogleSheetsExtension; if (googleExtension == null) { Debug.LogError($"String Table Collection {tableCollection.TableCollectionName} Does not contain a Google Sheets Extension."); return; } PullExtension(googleExtension); }
public void ChangeKeyGenerator() { var stringTableCollection = LocalizationEditorSettings.GetStringTableCollection("My Game Text"); // Determine the highest Key Id so Unity can continue generating Ids that do not conflict with existing Ids. long maxKeyId = 0; if (stringTableCollection.SharedData.Entries.Count > 0) { maxKeyId = stringTableCollection.SharedData.Entries.Max(e => e.Id); } stringTableCollection.SharedData.KeyGenerator = new SequentialIDGenerator(maxKeyId + 1); // Mark the asset dirty so that Unity saves the changes EditorUtility.SetDirty(stringTableCollection.SharedData); }
static void GenerateLocalizedXmlFile(string valueName, string filePath, Locale locale, AppInfo appinfo) { var localizedString = appinfo.DisplayName; if (localizedString.IsEmpty) { return; } var tableCollection = LocalizationEditorSettings.GetStringTableCollection(localizedString.TableReference); var table = tableCollection?.GetTable(locale.Identifier) as StringTable; var entry = table?.GetEntryFromReference(localizedString.TableEntryReference); if (entry == null || string.IsNullOrWhiteSpace(entry.LocalizedValue)) { // Use fallback? var fallBack = FallbackLocaleHelper.GetLocaleFallback(locale); if (fallBack != null) { GenerateLocalizedXmlFile(valueName, filePath, fallBack, appinfo); return; } Debug.LogWarning($"{valueName}: Could not find a localized value for {locale} from {localizedString}"); return; } Debug.Assert(!entry.IsSmart, $"Localized App Values ({valueName}) do not support Smart Strings - {localizedString}"); Debug.Assert(!entry.LocalizedValue.Contains("'"), $"Localized App Value ({valueName}) does not support Single Quote. \nEntry contains invalid character: {localizedString}\n{entry.LocalizedValue}"); using (var stream = new StreamWriter(filePath, false, Encoding.UTF8)) { stream.WriteLine( $@"<?xml version=""1.0"" encoding=""utf-8""?>" + "<!--" + "\n" + $"\t{k_InfoFile}\n" + $"\tThis file was auto-generated by {LocalizationPackageInfo.name}\n" + $"\tVersion {LocalizationPackageInfo.version}\n" + $"\tChanges to this file may cause incorrect behavior and will be lost if the project is rebuilt.\n" + $"-->" + "\n" + $@"<resources> <string name=""app_name""> {entry.LocalizedValue} </string> </resources>"); } }
public static void PushProjectLocales() { // Setup the connection to Google var sheetServiceProvider = GetServiceProvider(); var googleSheets = new GoogleSheets(sheetServiceProvider); googleSheets.SpreadSheetId = "My spread sheet id"; // We need to provide the Spreadsheet id. This can be found in the url. See docs for further info. // Prepare the data we want to push. // You should provide your String Table Collection name here var tableCollection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); // CreateDefaultMapping will create a KeyColumn and a LocaleColumn for each Locale in the project. var columnMappings = ColumnMapping.CreateDefaultMapping(); int mySheetId = 123456; // This it the id of the sheet in the Google Spreadsheet. it will be in the url after `gid=`. // Now send the update. We can pass in an optional ProgressBarReporter so that we can see updates in the Editor. googleSheets.PushStringTableCollection(mySheetId, tableCollection, columnMappings, new ProgressBarReporter()); }
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(); }
static StringTableCollection FindProjectCollection(IGroup group) { // Is the Id the Shared table data GUID? if (!string.IsNullOrEmpty(group.Id)) { var path = AssetDatabase.GUIDToAssetPath(group.Id); if (!string.IsNullOrEmpty(path)) { var sharedTableData = AssetDatabase.LoadAssetAtPath <SharedTableData>(path); if (sharedTableData != null) { return(LocalizationEditorSettings.GetCollectionForSharedTableData(sharedTableData) as StringTableCollection); } } } // Try table name instead return(LocalizationEditorSettings.GetStringTableCollection(group.Id) ?? LocalizationEditorSettings.GetStringTableCollection(group.Name)); }
/// <summary> /// Clear a named StringTable collection. /// </summary> /// <param name="name">StringTable collection to clear.</param> public static void ClearStringTables(string name) { var collection = LocalizationEditorSettings.GetStringTableCollection(name); if (collection == null) { return; } // Clear tables in collection foreach (StringTable table in collection.StringTables) { table.Clear(); EditorUtility.SetDirty(table); } // Clear shared data entries collection.SharedData.Entries.Clear(); EditorUtility.SetDirty(collection.SharedData); }
public void SetupEntryOverrideInEditor() { var collection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); var englishTable = collection.GetTable("en") as StringTable; // Add the default entry var entry = englishTable.AddEntry("COPYRIGHT_NOTICE", "This is some copyright info for general platforms..."); // Add the entry we want to use on PS4 englishTable.AddEntry("COPYRIGHT_NOTICE_PS4", "This is some copyright info for PS4 platforms..."); // Set up the platform override so that COPYRIGHT_NOTICE redirects to COPYRIGHT_NOTICE_PS4 when running on PS4. var platformOverride = new PlatformOverride(); platformOverride.AddPlatformEntryOverride(RuntimePlatform.PS4, "COPYRIGHT_NOTICE_PS4"); entry.SharedEntry.Metadata.AddMetadata(platformOverride); // Mark the assets dirty so changes are saved EditorUtility.SetDirty(collection.SharedData); EditorUtility.SetDirty(englishTable); }
private void Initialize() { if (ID != UInt32.MaxValue) { var entryId = (ID + 1).ToString(); collection = overrideTable ? collection : LocalizationEditorSettings.GetStringTableCollection("Characters"); if (collection) { characterName = new LocalizedString { TableReference = collection.TableCollectionNameReference, TableEntryReference = entryId } } ; else { Debug.LogWarning("Collection not found. Did you create any localization tables"); } } }
public static void PullProjectLocales() { // Setup the connection to Google var sheetServiceProvider = GetServiceProvider(); var googleSheets = new GoogleSheets(sheetServiceProvider); googleSheets.SpreadSheetId = "My spread sheet id"; // We need to provide the Spreadsheet id. This can be found in the url. See docs for further info. // You should provide your String Table Collection name here var tableCollection = LocalizationEditorSettings.GetStringTableCollection("My Strings"); // CreateDefaultMapping will create a KeyColumn and a LocaleColumn for each Locale in the project. // This assumes that the table was created and pushed to using the same column mappings. var columnMappings = ColumnMapping.CreateDefaultMapping(); int mySheetId = 123456; // This it the id of the sheet in the Google Spreadsheet. it will be in the url after `gid=`. // Now pull. // removeMissingEntries will remove any Keys that we have in the String Table Collection that do not exist in the Pull update. // reporter is an optional reporter that can be used to povide feedback in the editor during the Pull. googleSheets.PullIntoStringTableCollection(mySheetId, tableCollection, columnMappings, removeMissingEntries: true, reporter: new ProgressBarReporter()); }
public Line(string _name) { StringTableCollection collection = LocalizationEditorSettings.GetStringTableCollection("Questline Dialogue"); _textList = null; if (collection != null) { int lineIndex = 0; LocalizedString _dialogueLine = null; do { lineIndex++; string key = "L" + lineIndex + "-" + _name; if (collection.SharedData.Contains(key)) { SetActor(collection.SharedData.GetEntry(key).Metadata.GetMetadata <Comment>()); _dialogueLine = new LocalizedString() { TableReference = "Questline Dialogue", TableEntryReference = key }; if (_textList == null) { _textList = new List <LocalizedString>(); } _textList.Add(_dialogueLine); } else { _dialogueLine = null; } } while (_dialogueLine != null); int choiceIndex = 0; Choice choice = null; do { choiceIndex++; string key = "C" + choiceIndex + "-" + _name; if (collection.SharedData.Contains(key)) { LocalizedString _choiceLine = new LocalizedString() { TableReference = "Questline Dialogue", TableEntryReference = key }; choice = new Choice(_choiceLine); choice.SetChoiceAction(collection.SharedData.GetEntry(key).Metadata.GetMetadata <Comment>()); if (_choices == null) { _choices = new List <Choice>(); } _choices.Add(choice); } else { choice = null; } } while (choice != null); } else { _textList = null; } }
/// <summary> /// Grab the next dialogue /// nextDialogue = ConvertRow(TableDatabase.Get.GetRow("dialogues", nextDialogueID)); /// Set the dialogue options associated to the dialogue. /// CheckDialogueOptions(nextDialogue); /// so input has a connection member that consists of three values /// node -> reference to the other node. /// output -> reference to the key that consist of the value /// so in order to grab the data go to the node /// fetch the data /// if it is an option take options[$`optionOut-key`] and then the value /// if it is a dialogue take data["dialogueId"] -> can be Number.MAX_SAFE_INTEGER /// so output has a connection member that consists of three values /// node -> reference to the other node. /// input -> reference to the key that consist of the value /// so in order to grab the data go to the node /// fetch the data /// if it is an option take options[$`optionOut-key`] and then the value /// if it is a dialogue take data["dialogueId"] -> can be Number.MAX_SAFE_INTEGER /// </summary> /// <param name="currentDialogue"></param> /// <param name="story"></param> /// <param name="node"></param> /// <param name="nodes"></param> private static void ParseNextNodeData(StorySO story, IDialogueLine currentDialogue, JObject node, JObject nodes) { if (node["data"] == null) { return; } var data = node["data"].ToObject <JObject>(); // check what is inside the node if (data != null) { // get the outputs var outputs = node["outputs"].ToObject <JObject>(); // loop through the outputs // Outputs can be // Dialogue to dialogue // option to dialogue foreach (var outputToken in outputs) { var output = outputToken.Value.ToObject <JObject>(); var connections = output["connections"].ToArray(); var emptyObj = new JObject(); string nodeId; JObject otherNode; JObject otherData; if (outputToken.Key.Contains("Exec") && connections.Length > 0) { foreach (var con in connections) { // grab the other node id. nodeId = con["node"]?.ToObject <int>().ToString() ?? String.Empty; // grab the other node object. otherNode = nodeId != String.Empty ? nodes[nodeId].Value <JObject>() : emptyObj; // grab the data from the other node. otherData = otherNode["data"]?.ToObject <JObject>() ?? emptyObj; if (currentDialogue != null) { // fetch the event name var eventId = otherData["eventId"]?.ToObject <uint>() ?? UInt32.MaxValue; var eventName = ""; if (eventId != UInt32.MaxValue) { var row = TableDatabase.Get.GetRow("events", eventId); // validate the data if (row.Fields.Count > 0) { var field = row.Find("name"); if (field != null) { eventName = (string)field.Data; } } // fetch the parameters // TODO mark event value as dynamic to support multiple parameters JObject events = otherData["events"]?.ToObject <JObject>() ?? emptyObj; foreach (var @event in events) { // int value = @event.Value["value"]["value"].ToObject<int>(); currentDialogue.DialogueEvent = new DialogueEventSO(eventName, story); } } } } } // see if we have a connection // if (connections.Length == 0) // continue; // See if we are dealing with an option bool containsOption = outputToken.Key.Contains("option"); var connection = connections.Length > 0 ? connections[0] : emptyObj; // grab the other node id. nodeId = connection["node"]?.ToObject <int>().ToString() ?? String.Empty; // grab the other node object. otherNode = nodeId != String.Empty ? nodes[nodeId].Value <JObject>() : emptyObj; // grab the data from the other node. otherData = otherNode["data"]?.ToObject <JObject>() ?? emptyObj; if (currentDialogue != null) { // Fetch the other dialogueId var nextId = otherData["dialogueId"]?.ToObject <uint>() ?? UInt32.MaxValue; // if this node does not consist of any choices // go this way if (!containsOption) { // validate the data currentDialogue.NextDialogue = nextId != UInt32.MaxValue ? DialogueLine.ConvertRow(TableDatabase.Get.GetRow("dialogues", nextId), story.overrideTable ? story.collection : LocalizationEditorSettings.GetStringTableCollection("Dialogues")) : null; // Debug.Log(" Next: " + currentDialogue.NextDialogue); // now we have the next id check if we have a node that comes after. ParseNextNodeData(story, currentDialogue.NextDialogue, otherNode, nodes); } else { // grab the choice id from the current node. var optionId = data["options"][outputToken.Key]["value"].ToObject <uint>(); // Grab the choice DialogueChoiceSO choice = DialogueChoiceSO.ConvertRow(TableDatabase.Get.GetRow("dialogueOptions", optionId), story.overrideDialogueOptionsTable ? story.dialogueOptionsCollection : LocalizationEditorSettings.GetStringTableCollection("DialogueOptions") ); // find the next dialogue of this choice. choice.NextDialogue = nextId != UInt32.MaxValue ? DialogueLine.ConvertRow(TableDatabase.Get.GetRow("dialogues", nextId), story.overrideTable ? story.collection : LocalizationEditorSettings.GetStringTableCollection("Dialogues")) : null; // Debug.Log(" Choice: " + choice); // add the choices to the currentDialogue currentDialogue.Choices.Add(choice); // Set the nextDialogue to null because we are dealing with a choice currentDialogue.NextDialogue = null; // Find the next dialogue for the choice ParseNextNodeData(story, choice.NextDialogue, otherNode, nodes); } } } } }
/// <summary> /// Helper to import TEXT.RSC from classic game data into specified StringTable. /// WARNING: Named StringTable collection will be cleared and replaced with data from game files. /// </summary> /// <param name="name">StringTable collection name to receive TEXT.RSC data.</param> public static void ImportTextRSCToStringTables(string name) { // Clear all tables ClearStringTables(name); // Load character mapping table Table charMappingTable = null; TextAsset mappingTableText = Resources.Load <TextAsset>(textMappingTableFilename); if (mappingTableText) { charMappingTable = new Table(mappingTableText.text); } // Load default TEXT.RSC file TextFile defaultRSC = new TextFile(DaggerfallUnity.Instance.Arena2Path, TextFile.Filename); if (defaultRSC == null || defaultRSC.IsLoaded == false) { throw new Exception("Could not load default TEXT.RSC"); } // Get string tables collection var collection = LocalizationEditorSettings.GetStringTableCollection(name); if (collection == null) { return; } // Add all text records to each table foreach (StringTable table in collection.StringTables) { bool en = table.LocaleIdentifier.Code == enLocaleCode; TextFile rsc = defaultRSC; TextFile localeRSC = LoadCustomLocaleTextRSC(table.LocaleIdentifier.Code); if (localeRSC != null) { rsc = localeRSC; } for (int i = 0; i < defaultRSC.RecordCount; i++) { // Extract this record to tokens byte[] buffer = rsc.GetBytesByIndex(i); TextFile.Token[] tokens = TextFile.ReadTokens(ref buffer, 0, TextFile.Formatting.EndOfRecord); // Get token key and text int id = rsc.IndexToId(i); if (id == -1) { continue; } string key = MakeTextRSCKey(id); string text = ConvertRSCTokensToString(tokens); // Remap characters when mapping table present if (charMappingTable != null) { text = RemapCharacters(table.LocaleIdentifier.Code, text, charMappingTable); } // Add text to table table.AddEntry(key, text); // Add shared keys only when reading en table // These keys match across entire collection if (en) { collection.SharedData.AddKey(key); } } // Set table dirty EditorUtility.SetDirty(table); Debug.LogFormat("Added {0} TEXT.RSC entries to table {1}", rsc.RecordCount, table.LocaleIdentifier.Code); } // Set shared data dirty EditorUtility.SetDirty(collection.SharedData); }
/// <summary> /// Copies default Internal_Strings EN to all string tables in target collection. /// </summary> /// <param name="target">Target string table collection name.</param> /// <param name="overwriteExistingKeys">When true will overwrite existing keys with source string. When false existing keys are left unchanged.</param> public static void CopyInternalStringTable(string target, bool overwriteExistingKeys) { // Use default Internal_Strings collection with EN locale code as source string sourceCollectionName = TextManager.defaultInternalStringsCollectionName; string sourceLocaleCode = enLocaleCode; // Do nothing if target not set if (string.IsNullOrEmpty(target)) { return; } // Target cannot be same as default if (string.Compare(target, sourceCollectionName, true) == 0) { Debug.LogError("CopyInternalStringTable() target cannot be same as default"); return; } // Get target string table collection var targetCollection = LocalizationEditorSettings.GetStringTableCollection(target); if (targetCollection == null) { Debug.LogErrorFormat("CopyInternalStringTable() could not find target string table collection '{0}'", target); return; } // Get source string table StringTable sourceTable = GetSourceStringTable(sourceCollectionName, sourceLocaleCode); if (!sourceTable) { Debug.LogErrorFormat("CopyInternalStringTable() could not find source table '{0}' with locale '{1}'", sourceCollectionName, sourceLocaleCode); return; } // Copy source strings to all tables in target collection int totalSourceEntries = sourceTable.SharedData.Entries.Count; int copiedNew = 0; int copiedOverwrite = 0; foreach (StringTable targetTable in targetCollection.StringTables) { // Iterate through all string table values found in source table foreach (var item in sourceTable.SharedData.Entries) { string key = item.Key; var sourceEntry = sourceTable.GetEntry(key); if (sourceEntry == null) { Debug.LogWarningFormat("CopyInternalStringTable() could not find source table entry for key '{0}'", key); continue; } var targetEntry = targetTable.GetEntry(key); if (targetEntry == null) { targetTable.AddEntry(key, sourceEntry.Value); copiedNew++; } else if (targetEntry != null && overwriteExistingKeys) { if (targetTable.RemoveEntry(key)) { targetTable.AddEntry(key, sourceEntry.Value); copiedOverwrite++; } else { Debug.LogErrorFormat("CopyInternalStringTable() could not remove key '{0}'. Overwrite failed.", key); } } } // Set table dirty EditorUtility.SetDirty(targetTable); } // Set target collection shared data dirty EditorUtility.SetDirty(targetCollection.SharedData); Debug.LogFormat("Source collection '{0}' has a total of {1} entries.\nTarget collection '{2}' received {3} new entries, {4} entries were overwritten.", sourceCollectionName, totalSourceEntries, target, copiedNew, copiedOverwrite); }
/// <summary> /// Imports TEXT.RSC strings from classic game data into specified StringTable. /// </summary> /// <param name="target">Target string table collection name.</param> /// <param name="overwriteExistingKeys">When true will overwrite existing keys with source string. When false existing keys are left unchanged.</param> public static void CopyTextRSCToStringTable(string target, bool overwriteExistingKeys) { // Use default Internal_RSC collection with EN locale code as source // Note: Internal_RSC is reserved for future use string sourceCollectionName = TextManager.defaultInternalRSCCollectionName; // Do nothing if target not set if (string.IsNullOrEmpty(target)) { return; } // Target cannot be same as default if (string.Compare(target, sourceCollectionName, true) == 0) { Debug.LogError("CopyTextRSCToStringTable() target cannot be same as default"); return; } // Load character mapping table Table charMappingTable = null; TextAsset mappingTableText = Resources.Load <TextAsset>(textMappingTableFilename); if (mappingTableText) { charMappingTable = new Table(mappingTableText.text); } // Load default TEXT.RSC file TextFile defaultRSC = new TextFile(DaggerfallUnity.Instance.Arena2Path, TextFile.Filename); if (defaultRSC == null || defaultRSC.IsLoaded == false) { Debug.LogError("CopyTextRSCToStringTable() could not find default TEXT.RSC file"); return; } // Get target string table collection var targetCollection = LocalizationEditorSettings.GetStringTableCollection(target); if (targetCollection == null) { Debug.LogErrorFormat("CopyTextRSCToStringTable() could not find target string table collection '{0}'", target); return; } // Copy source strings to all tables in target collection int totalSourceEntries = defaultRSC.RecordCount; int copiedNew = 0; int copiedOverwrite = 0; foreach (StringTable targetTable in targetCollection.StringTables) { TextFile rsc = defaultRSC; TextFile localeRSC = LoadCustomLocaleTextRSC(targetTable.LocaleIdentifier.Code); if (localeRSC != null) { rsc = localeRSC; } for (int i = 0; i < defaultRSC.RecordCount; i++) { // Extract this record to tokens byte[] buffer = rsc.GetBytesByIndex(i); TextFile.Token[] tokens = TextFile.ReadTokens(ref buffer, 0, TextFile.Formatting.EndOfRecord); // Get token key and text int id = rsc.IndexToId(i); if (id == -1) { continue; } string key = MakeTextRSCKey(id); string text = ConvertRSCTokensToString(id, tokens); // Remap characters when mapping table present if (charMappingTable != null) { text = RemapCharacters(targetTable.LocaleIdentifier.Code, text, charMappingTable); } // ID 9000 is diverted to multiple records after initial conversion // Otherwise this record is too long for string table editor // Multiple records also make questionnaire easier to maintain if (id == 9000) { SplitQuestionnaireRecord(text, key, targetTable, overwriteExistingKeys, ref copiedNew, ref copiedOverwrite); continue; } var targetEntry = targetTable.GetEntry(key); if (targetEntry == null) { targetTable.AddEntry(key, text); copiedNew++; } else if (targetEntry != null && overwriteExistingKeys) { if (targetTable.RemoveEntry(key)) { targetTable.AddEntry(key, text); copiedOverwrite++; } else { Debug.LogErrorFormat("CopyTextRSCToStringTable() could not remove key '{0}'. Overwrite failed.", key); } } } // Set table dirty EditorUtility.SetDirty(targetTable); } // Set target collection shared data dirty EditorUtility.SetDirty(targetCollection.SharedData); Debug.LogFormat("Source collection TEXT.RSC has a total of {0} entries.\nTarget collection '{1}' received {2} new entries, {3} entries were overwritten.", totalSourceEntries, target, copiedNew, copiedOverwrite); }
/// <summary> /// Imports FLATS.CFG EN strings from embedded classic game data into specified StringTable. /// </summary> /// <param name="target">Target string table collection name.</param> /// <param name="overwriteExistingKeys">When true will overwrite existing keys with source string. When false existing keys are left unchanged.</param> public static void CopyTextFlatsToStringTable(string target, bool overwriteExistingKeys) { // Use default Internal_Flat collection with EN locale code as source // Note: Internal_Flats is reserved for future use string sourceCollectionName = TextManager.defaultInternalFlatsCollectionName; // Do nothing if target not set if (string.IsNullOrEmpty(target)) { return; } // Target cannot be same as default if (string.Compare(target, sourceCollectionName, true) == 0) { Debug.LogError("CopyTextFlatsToStringTable() target cannot be same as default"); return; } // Load default FLATS.CFG file FlatsFile flatsFile = new FlatsFile(Path.Combine(DaggerfallUnity.Instance.Arena2Path, FlatsFile.Filename), DaggerfallConnect.FileUsage.UseMemory, true); if (flatsFile == null) { Debug.LogError("CopyTextFlatsToStringTable() could not find default FLATS.CFG file"); return; } // Get target string table collection var targetCollection = LocalizationEditorSettings.GetStringTableCollection(target); if (targetCollection == null) { Debug.LogErrorFormat("CopyTextFlatsToStringTable() could not find target string table collection '{0}'", target); return; } // Copy source strings to all tables in target collection int totalSourceEntries = flatsFile.FlatsDict.Count; int copiedNew = 0; int copiedOverwrite = 0; foreach (StringTable targetTable in targetCollection.StringTables) { foreach (var item in flatsFile.FlatsDict) { string key = item.Key.ToString(); string text = item.Value.caption; var targetEntry = targetTable.GetEntry(key); if (targetEntry == null) { targetTable.AddEntry(key, text); copiedNew++; } else if (targetEntry != null && overwriteExistingKeys) { if (targetTable.RemoveEntry(key)) { targetTable.AddEntry(key, text); copiedOverwrite++; } else { Debug.LogErrorFormat("CopyTextFlatsToStringTable() could not remove key '{0}'. Overwrite failed.", key); } } } // Set table dirty EditorUtility.SetDirty(targetTable); } // Set target collection shared data dirty EditorUtility.SetDirty(targetCollection.SharedData); Debug.LogFormat("Source collection FLATS.CFG has a total of {0} entries.\nTarget collection '{1}' received {2} new entries, {3} entries were overwritten.", totalSourceEntries, target, copiedNew, copiedOverwrite); }