Add automated chrome string extractor.
This commit is contained in:
committed by
Matthias Mailänder
parent
1f0e73906e
commit
cbd6b67456
@@ -17,6 +17,7 @@ using System.Reflection;
|
||||
using Linguini.Syntax.Ast;
|
||||
using Linguini.Syntax.Parser;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Lint
|
||||
{
|
||||
@@ -135,6 +136,23 @@ namespace OpenRA.Mods.Common.Lint
|
||||
}
|
||||
}
|
||||
|
||||
var translatableFields = modData.ObjectCreator.GetTypes()
|
||||
.Where(t => t.Name.EndsWith("Widget", StringComparison.InvariantCulture) && t.IsSubclassOf(typeof(Widget)))
|
||||
.ToDictionary(
|
||||
t => t.Name[..^6],
|
||||
t => t.GetFields().Where(f => f.HasAttribute<TranslationReferenceAttribute>()).ToArray())
|
||||
.Where(t => t.Value.Length > 0)
|
||||
.ToDictionary(
|
||||
t => t.Key,
|
||||
t => t.Value.Select(f => (f.Name, f, Utility.GetCustomAttributes<TranslationReferenceAttribute>(f, true).First())).ToArray());
|
||||
|
||||
foreach (var filename in modData.Manifest.ChromeLayout)
|
||||
{
|
||||
var nodes = MiniYaml.FromStream(modData.DefaultFileSystem.Open(filename));
|
||||
foreach (var node in nodes)
|
||||
CheckChrome(node, translation, language, emitError, emitWarning, translatableFields);
|
||||
}
|
||||
|
||||
foreach (var file in modData.Manifest.Translations)
|
||||
{
|
||||
var stream = modData.DefaultFileSystem.Open(file);
|
||||
@@ -179,6 +197,47 @@ namespace OpenRA.Mods.Common.Lint
|
||||
}
|
||||
}
|
||||
|
||||
void CheckChrome(MiniYamlNode node, Translation translation, string language, Action<string> emitError, Action<string> emitWarning,
|
||||
Dictionary<string, (string Name, FieldInfo Field, TranslationReferenceAttribute Attribute)[]> translatables)
|
||||
{
|
||||
var nodeType = node.Key.Split('@')[0];
|
||||
foreach (var childNode in node.Value.Nodes)
|
||||
{
|
||||
if (translatables.ContainsKey(nodeType))
|
||||
{
|
||||
var childType = childNode.Key.Split('@')[0];
|
||||
var field = translatables[nodeType].FirstOrDefault(t => t.Name == childType);
|
||||
if (field.Name == null)
|
||||
continue;
|
||||
|
||||
var key = childNode.Value.Value;
|
||||
if (key == null)
|
||||
{
|
||||
if (!field.Attribute.Optional)
|
||||
emitError($"Widget `{node.Key}` in field `{childType}` has an empty translation reference.");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (referencedKeys.Contains(key))
|
||||
continue;
|
||||
|
||||
if (!key.Any(char.IsLetter))
|
||||
continue;
|
||||
|
||||
if (!translation.HasMessage(key))
|
||||
emitWarning($"`{key}` defined by `{node.Key}` is not present in `{language}` translation.");
|
||||
|
||||
referencedKeys.Add(key);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var childNode in node.Value.Nodes)
|
||||
if (childNode.Key == "Children")
|
||||
foreach (var n in childNode.Value.Nodes)
|
||||
CheckChrome(n, translation, language, emitError, emitWarning, translatables);
|
||||
}
|
||||
|
||||
void CheckUnusedKey(string key, string attribute, Action<string> emitWarning, string file)
|
||||
{
|
||||
var isAttribute = !string.IsNullOrEmpty(attribute);
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
public bool DisableKeyRepeat = false;
|
||||
public bool DisableKeySound = false;
|
||||
|
||||
[TranslationReference]
|
||||
public string Text = "";
|
||||
public TextAlign Align = TextAlign.Center;
|
||||
public int LeftMargin = 5;
|
||||
@@ -54,9 +55,11 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
protected Lazy<TooltipContainerWidget> tooltipContainer;
|
||||
|
||||
[TranslationReference]
|
||||
public string TooltipText;
|
||||
public Func<string> GetTooltipText;
|
||||
|
||||
[TranslationReference]
|
||||
public string TooltipDesc;
|
||||
public Func<string> GetTooltipDesc;
|
||||
|
||||
@@ -74,7 +77,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
ModRules = modData.DefaultRules;
|
||||
|
||||
GetText = () => Text;
|
||||
var tooltipCache = new CachedTransform<string, string>(s => !string.IsNullOrEmpty(s) ? TranslationProvider.GetString(s) : "");
|
||||
GetText = () => tooltipCache.Update(Text);
|
||||
GetColor = () => TextColor;
|
||||
GetColorDisabled = () => TextColorDisabled;
|
||||
GetContrastColorDark = () => ContrastColorDark;
|
||||
@@ -82,8 +86,10 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
OnMouseUp = _ => OnClick();
|
||||
OnKeyPress = _ => OnClick();
|
||||
IsHighlighted = () => Highlighted;
|
||||
GetTooltipText = () => TooltipText;
|
||||
GetTooltipDesc = () => TooltipDesc;
|
||||
var tooltipDescCache = new CachedTransform<string, string>(s => !string.IsNullOrEmpty(s) ? TranslationProvider.GetString(s) : "");
|
||||
GetTooltipText = () => tooltipDescCache.Update(TooltipText);
|
||||
var textCache = new CachedTransform<string, string>(s => !string.IsNullOrEmpty(s) ? TranslationProvider.GetString(s) : "");
|
||||
GetTooltipDesc = () => tooltipDescCache.Update(TooltipDesc);
|
||||
tooltipContainer = Exts.Lazy(() =>
|
||||
Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
public Func<string> GetImageCollection;
|
||||
public Func<Sprite> GetSprite;
|
||||
|
||||
[TranslationReference]
|
||||
public string TooltipText;
|
||||
|
||||
readonly Lazy<TooltipContainerWidget> tooltipContainer;
|
||||
@@ -39,7 +40,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
GetImageName = () => ImageName;
|
||||
GetImageCollection = () => ImageCollection;
|
||||
GetTooltipText = () => TooltipText;
|
||||
var tooltipCache = new CachedTransform<string, string>(s => !string.IsNullOrEmpty(s) ? TranslationProvider.GetString(s) : "");
|
||||
GetTooltipText = () => tooltipCache.Update(TooltipText);
|
||||
tooltipContainer = Exts.Lazy(() =>
|
||||
Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly CachedTransform<bool, Color> textColor;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public LabelForInputWidget()
|
||||
: base()
|
||||
public LabelForInputWidget(ModData modData)
|
||||
: base(modData)
|
||||
{
|
||||
inputWidget = Exts.Lazy(() => Parent.Get<InputWidget>(For));
|
||||
textColor = new CachedTransform<bool, Color>(disabled => disabled ? TextDisabledColor : TextColor);
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
public class LabelWidget : Widget
|
||||
{
|
||||
[TranslationReference]
|
||||
public string Text = null;
|
||||
public TextAlign Align = TextAlign.Left;
|
||||
public TextVAlign VAlign = TextVAlign.Middle;
|
||||
@@ -37,9 +38,11 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
public Func<Color> GetContrastColorDark;
|
||||
public Func<Color> GetContrastColorLight;
|
||||
|
||||
public LabelWidget()
|
||||
[ObjectCreator.UseCtor]
|
||||
public LabelWidget(ModData modData)
|
||||
{
|
||||
GetText = () => Text;
|
||||
var textCache = new CachedTransform<string, string>(s => !string.IsNullOrEmpty(s) ? TranslationProvider.GetString(s) : "");
|
||||
GetText = () => textCache.Update(Text);
|
||||
GetColor = () => TextColor;
|
||||
GetContrastColorDark = () => ContrastColorDark;
|
||||
GetContrastColorLight = () => ContrastColorLight;
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly CachedTransform<string, (string Text, bool Highlighted)[]> textComponents;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public LabelWithHighlightWidget()
|
||||
: base()
|
||||
public LabelWithHighlightWidget(ModData modData)
|
||||
: base(modData)
|
||||
{
|
||||
textComponents = new CachedTransform<string, (string, bool)[]>(MakeComponents);
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
public Func<string> GetTooltipText = () => "";
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public LabelWithTooltipWidget()
|
||||
: base()
|
||||
public LabelWithTooltipWidget(ModData modData)
|
||||
: base(modData)
|
||||
{
|
||||
tooltipContainer = Exts.Lazy(() =>
|
||||
Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var descFont = Game.Renderer.Fonts[descTemplate.Font];
|
||||
var descWidth = 0;
|
||||
var descOffset = descTemplate.Bounds.Y;
|
||||
foreach (var line in desc.Split(new[] { "\\n" }, StringSplitOptions.None))
|
||||
foreach (var line in desc.Split(new[] { "\n" }, StringSplitOptions.None))
|
||||
{
|
||||
descWidth = Math.Max(descWidth, descFont.Measure(line).X);
|
||||
var lineLabel = (LabelWidget)descTemplate.Clone();
|
||||
|
||||
@@ -75,9 +75,11 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
public readonly bool DrawTime = true;
|
||||
|
||||
public readonly string ReadyText = "";
|
||||
[TranslationReference]
|
||||
public string ReadyText = "";
|
||||
|
||||
public readonly string HoldText = "";
|
||||
[TranslationReference]
|
||||
public string HoldText = "";
|
||||
|
||||
public readonly string InfiniteSymbol = "\u221E";
|
||||
|
||||
@@ -176,7 +178,9 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
Game.Renderer.Fonts.TryGetValue(SymbolsFont, out symbolFont);
|
||||
|
||||
iconOffset = 0.5f * IconSize.ToFloat2() + IconSpriteOffset;
|
||||
HoldText = TranslationProvider.GetString(HoldText);
|
||||
holdOffset = iconOffset - overlayFont.Measure(HoldText) / 2;
|
||||
ReadyText = TranslationProvider.GetString(ReadyText);
|
||||
readyOffset = iconOffset - overlayFont.Measure(ReadyText) / 2;
|
||||
|
||||
if (ChromeMetrics.TryGet("InfiniteOffset", out infiniteOffset))
|
||||
|
||||
@@ -22,9 +22,11 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class SupportPowersWidget : Widget
|
||||
{
|
||||
public readonly string ReadyText = "";
|
||||
[TranslationReference]
|
||||
public string ReadyText = "";
|
||||
|
||||
public readonly string HoldText = "";
|
||||
[TranslationReference]
|
||||
public string HoldText = "";
|
||||
|
||||
public readonly string OverlayFont = "TinyBold";
|
||||
|
||||
@@ -109,7 +111,10 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
overlayFont = Game.Renderer.Fonts[OverlayFont];
|
||||
|
||||
iconOffset = 0.5f * IconSize.ToFloat2() + IconSpriteOffset;
|
||||
|
||||
HoldText = TranslationProvider.GetString(HoldText);
|
||||
holdOffset = iconOffset - overlayFont.Measure(HoldText) / 2;
|
||||
ReadyText = TranslationProvider.GetString(ReadyText);
|
||||
readyOffset = iconOffset - overlayFont.Measure(ReadyText) / 2;
|
||||
|
||||
clock = new Animation(worldRenderer.World, ClockAnimation);
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly World world;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public WorldLabelWithTooltipWidget(World world)
|
||||
: base()
|
||||
public WorldLabelWithTooltipWidget(ModData modData, World world)
|
||||
: base(modData)
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user