diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/ItemLabel.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/ItemLabel.cs index 651858092..10eb66e95 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/ItemLabel.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/ItemLabel.cs @@ -28,7 +28,7 @@ namespace Barotrauma.Items.Components } private string text; - [Serialize("", true), Editable(100)] + [Serialize("", true, translationTextTag: "Label."), Editable(100)] public string Text { get { return text; } @@ -40,13 +40,20 @@ namespace Barotrauma.Items.Components { textBlock = null; } - + text = value; - TextBlock.Text = value; + DisplayText = TextManager.Get(text, returnNull: true) ?? value; + TextBlock.Text = DisplayText; SetScrollingText(); } } + public string DisplayText + { + get; + private set; + } + [Editable, Serialize("0.0,0.0,0.0,1.0", true)] public Color TextColor { @@ -115,7 +122,7 @@ namespace Barotrauma.Items.Components { if (!scrollable) return; - float totalWidth = textBlock.Font.MeasureString(text).X; + float totalWidth = textBlock.Font.MeasureString(DisplayText).X; float textAreaWidth = Math.Max(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z, 0); if (totalWidth >= textAreaWidth) { @@ -123,13 +130,13 @@ namespace Barotrauma.Items.Components //(so the text can scroll entirely out of view before we reset it back to start) needsScrolling = true; float spaceWidth = textBlock.Font.MeasureChar(' ').X; - scrollingText = new string(' ', (int)Math.Ceiling(textAreaWidth / spaceWidth)) + text; + scrollingText = new string(' ', (int)Math.Ceiling(textAreaWidth / spaceWidth)) + DisplayText; } else { //whole text can fit in the textblock, no need to scroll needsScrolling = false; - scrollingText = text; + scrollingText = DisplayText; scrollAmount = 0.0f; scrollIndex = 0; return; @@ -145,7 +152,7 @@ namespace Barotrauma.Items.Components charWidths[i] = charWidth; } - scrollIndex = MathHelper.Clamp(scrollIndex, 0, text.Length); + scrollIndex = MathHelper.Clamp(scrollIndex, 0, DisplayText.Length); } public override void Update(float deltaTime, Camera cam) diff --git a/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs b/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs index 0d756b322..2413a5895 100644 --- a/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs +++ b/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs @@ -493,12 +493,15 @@ namespace Barotrauma private GUIComponent CreateStringField(ISerializableEntity entity, SerializableProperty property, string value, string displayName, string toolTip) { - var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, elementHeight), layoutGroup.RectTransform), color: Color.Transparent); + var frame = new GUILayoutGroup(new RectTransform(new Point(Rect.Width, elementHeight), layoutGroup.RectTransform), isHorizontal: true) + { + Stretch = true + }; var label = new GUITextBlock(new RectTransform(new Vector2(0.4f, 1), frame.RectTransform), displayName, font: GUI.SmallFont, textAlignment: Alignment.Left) { ToolTip = toolTip }; - GUITextBox propertyBox = new GUITextBox(new RectTransform(new Vector2(0.6f, 1), frame.RectTransform, Anchor.TopRight)) + GUITextBox propertyBox = new GUITextBox(new RectTransform(new Vector2(0.6f, 1), frame.RectTransform)) { ToolTip = toolTip, Font = GUI.SmallFont, @@ -514,6 +517,31 @@ namespace Barotrauma return true; } }; + string translationTextTag = property.GetAttribute()?.translationTextTag; + if (translationTextTag != null) + { + new GUIButton(new RectTransform(new Vector2(0.1f, 1), frame.RectTransform, Anchor.TopRight), "...") + { + OnClicked = (bt, userData) => { CreateTextPicker(translationTextTag, entity, property, propertyBox); return true; } + }; + propertyBox.OnTextChanged += (tb, text) => + { + string translatedText = TextManager.Get(text, returnNull: true); + if (translatedText == null) + { + propertyBox.TextColor = Color.Gray; + propertyBox.ToolTip = TextManager.Get("StringPropertyCannotTranslate").Replace("[tag]", text ?? ""); + } + else + { + propertyBox.TextColor = Color.LightGreen; + propertyBox.ToolTip = TextManager.Get("StringPropertyTranslate").Replace("[translation]", translatedText); + } + return true; + }; + propertyBox.Text = value; + } + Fields.Add(property.Name, new GUIComponent[] { propertyBox }); return frame; } @@ -870,6 +898,40 @@ namespace Barotrauma Fields.Add(property.Name, fields); return frame; } + + private void CreateTextPicker(string textTag, ISerializableEntity entity, SerializableProperty property, GUITextBox textBox) + { + var msgBox = new GUIMessageBox("", "", new string[] { TextManager.Get("Cancel") }, width: 300, height: 400); + msgBox.Buttons[0].OnClicked = msgBox.Close; + + var textList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.8f), msgBox.Content.RectTransform, Anchor.TopCenter)) + { + OnSelected = (component, userData) => + { + string text = userData as string ?? ""; + + if (property.TrySetValue(entity, text)) + { + TrySendNetworkUpdate(entity, property); + textBox.Text = (string)property.GetValue(entity); + textBox.Deselect(); + } + return true; + } + }; + + textTag = textTag.ToLowerInvariant(); + var tagTextPairs = TextManager.GetAllTagTextPairs(); + foreach (KeyValuePair tagTextPair in tagTextPairs) + { + if (!tagTextPair.Key.StartsWith(textTag)) { continue; } + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), textList.Content.RectTransform) { MinSize = new Point(0, 20) }, + ToolBox.LimitString(tagTextPair.Value, GUI.Font, textList.Content.Rect.Width)) + { + UserData = tagTextPair.Key + }; + } + } private void TrySendNetworkUpdate(ISerializableEntity entity, SerializableProperty property) { diff --git a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs index 77a6c71c1..bc9a64bcb 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs @@ -109,6 +109,25 @@ namespace Barotrauma } } + public string DisplayName + { + get; + private set; + } + + private string roomName; + [Editable, Serialize("", true, translationTextTag: "RoomName.")] + public string RoomName + { + get { return roomName; } + set + { + if (roomName == value) { return; } + roomName = value; + DisplayName = TextManager.Get(roomName, returnNull: true) ?? roomName; + } + } + public override Rectangle Rect { get diff --git a/Barotrauma/BarotraumaShared/Source/Serialization/SerializableProperty.cs b/Barotrauma/BarotraumaShared/Source/Serialization/SerializableProperty.cs index b2dbc8a56..1ae108e35 100644 --- a/Barotrauma/BarotraumaShared/Source/Serialization/SerializableProperty.cs +++ b/Barotrauma/BarotraumaShared/Source/Serialization/SerializableProperty.cs @@ -55,11 +55,20 @@ namespace Barotrauma { public object defaultValue; public bool isSaveable; + public string translationTextTag; - public Serialize(object defaultValue, bool isSaveable) + /// + /// Makes the property serializable to/from XML + /// + /// The property is set to this value during deserialization if the value is not defined in XML. + /// Is the value saved to XML when serializing. + /// If set to anything else than null, SerializableEntityEditors will show what the text gets translated to or warn if the text is not found in the language files. + /// Setting the value to a non-empty string will let the user select the text from one whose tag starts with the given string (e.g. RoomName. would show all texts with a RoomName.* tag) + public Serialize(object defaultValue, bool isSaveable, string translationTextTag = null) { this.defaultValue = defaultValue; this.isSaveable = isSaveable; + this.translationTextTag = translationTextTag; } } diff --git a/Barotrauma/BarotraumaShared/Source/TextManager.cs b/Barotrauma/BarotraumaShared/Source/TextManager.cs index 1d5d074c8..52df9ac7b 100644 --- a/Barotrauma/BarotraumaShared/Source/TextManager.cs +++ b/Barotrauma/BarotraumaShared/Source/TextManager.cs @@ -252,6 +252,28 @@ namespace Barotrauma return null; } + public static List> GetAllTagTextPairs() + { + if (!textPacks.ContainsKey(Language)) + { + DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English..."); + Language = "English"; + if (!textPacks.ContainsKey(Language)) + { + throw new Exception("No text packs available in English!"); + } + } + + List> allText = new List>(); + + foreach (TextPack textPack in textPacks[Language]) + { + allText.AddRange(textPack.GetAllTagTextPairs()); + } + + return allText; + } + public static string ReplaceGenderPronouns(string text, Gender gender) { if (gender == Gender.Male) diff --git a/Barotrauma/BarotraumaShared/Source/TextPack.cs b/Barotrauma/BarotraumaShared/Source/TextPack.cs index 91366d043..e36bff60c 100644 --- a/Barotrauma/BarotraumaShared/Source/TextPack.cs +++ b/Barotrauma/BarotraumaShared/Source/TextPack.cs @@ -62,6 +62,20 @@ namespace Barotrauma return textList; } + public List> GetAllTagTextPairs() + { + var pairs = new List>(); + foreach (KeyValuePair> kvp in texts) + { + foreach (string line in kvp.Value) + { + pairs.Add(new KeyValuePair(kvp.Key, line)); + } + } + + return pairs; + } + #if DEBUG public void CheckForDuplicates(int index) {