Expose mod.yaml content to localisation.
Mod metadata, load screens and mod content is all now sourced from ftl files, allowing these items to be translated. Translations are now initialized as part of ModData creation, as currently they are made available too late for the usage we need here. The "modcontent" mod learns a new parameter for "Content.TranslationFile" - this allows a mod to provide the path of a translation file to the mod which it can load. This allows mods such as ra, cnc, d2k, ts to own the translations for their ModContent, yet still make them accessible to the modcontent mod. CheckFluentReference learns to validate all these new fields to ensure translations have been set.
This commit is contained in:
@@ -48,7 +48,12 @@ namespace OpenRA.Mods.Common.FileSystem
|
||||
if (contentInstalled)
|
||||
return false;
|
||||
|
||||
Game.InitializeMod(content.ContentInstallerMod, new Arguments("Content.Mod=" + modData.Manifest.Id));
|
||||
string translationPath;
|
||||
using (var fs = (FileStream)modData.DefaultFileSystem.Open(content.Translation))
|
||||
translationPath = fs.Name;
|
||||
Game.InitializeMod(
|
||||
content.ContentInstallerMod,
|
||||
new Arguments(new[] { "Content.Mod=" + modData.Manifest.Id, "Content.TranslationFile=" + translationPath }));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,16 +43,17 @@ namespace OpenRA.Mods.Common.Lint
|
||||
|
||||
var mapTranslations = FieldLoader.GetValue<string[]>("value", map.TranslationDefinitions.Value);
|
||||
|
||||
foreach (var language in GetModLanguages(modData))
|
||||
var allModTranslations = modData.Manifest.Translations.Append(modData.Manifest.Get<ModContent>().Translation).ToArray();
|
||||
foreach (var language in GetModLanguages(allModTranslations))
|
||||
{
|
||||
// Check keys and variables are not missing across all language files.
|
||||
// But for maps we don't warn on unused keys. They might be unused on *this* map,
|
||||
// but the mod or another map may use them and we don't have sight of that.
|
||||
CheckKeys(
|
||||
modData.Manifest.Translations.Concat(mapTranslations), map.Open, usedKeys,
|
||||
allModTranslations.Concat(mapTranslations), map.Open, usedKeys,
|
||||
language, _ => false, emitError, emitWarning);
|
||||
|
||||
var modFluentBundle = new FluentBundle(language, modData.Manifest.Translations, modData.DefaultFileSystem, _ => { });
|
||||
var modFluentBundle = new FluentBundle(language, allModTranslations, modData.DefaultFileSystem, _ => { });
|
||||
var mapFluentBundle = new FluentBundle(language, mapTranslations, map, error => emitError(error.Message));
|
||||
|
||||
foreach (var group in usedKeys.KeysWithContext)
|
||||
@@ -78,14 +79,15 @@ namespace OpenRA.Mods.Common.Lint
|
||||
foreach (var context in usedKeys.EmptyKeyContexts)
|
||||
emitWarning($"Empty key in mod translation files required by {context}");
|
||||
|
||||
foreach (var language in GetModLanguages(modData))
|
||||
var allModTranslations = modData.Manifest.Translations.Append(modData.Manifest.Get<ModContent>().Translation).ToArray();
|
||||
foreach (var language in GetModLanguages(allModTranslations))
|
||||
{
|
||||
Console.WriteLine($"Testing language: {language}");
|
||||
CheckModWidgets(modData, usedKeys, testedFields);
|
||||
|
||||
// With the fully populated keys, check keys and variables are not missing and not unused across all language files.
|
||||
var keyWithAttrs = CheckKeys(
|
||||
modData.Manifest.Translations, modData.DefaultFileSystem.Open, usedKeys,
|
||||
allModTranslations, modData.DefaultFileSystem.Open, usedKeys,
|
||||
language,
|
||||
file =>
|
||||
!modData.Manifest.AllowUnusedTranslationsInExternalPackages ||
|
||||
@@ -113,9 +115,9 @@ namespace OpenRA.Mods.Common.Lint
|
||||
$"`{field.ReflectedType.Name}.{field.Name}` - previous warnings may be incorrect");
|
||||
}
|
||||
|
||||
static IEnumerable<string> GetModLanguages(ModData modData)
|
||||
static IEnumerable<string> GetModLanguages(IEnumerable<string> translations)
|
||||
{
|
||||
return modData.Manifest.Translations
|
||||
return translations
|
||||
.Select(filename => FilenameRegex.Match(filename).Groups["language"].Value)
|
||||
.Distinct()
|
||||
.OrderBy(l => l);
|
||||
@@ -249,51 +251,55 @@ namespace OpenRA.Mods.Common.Lint
|
||||
.Where(t => t.IsSubclassOf(typeof(TraitInfo)) || t.IsSubclassOf(typeof(Warhead)))
|
||||
.SelectMany(t => t.GetFields().Where(f => f.HasAttribute<FluentReferenceAttribute>())));
|
||||
|
||||
// HACK: Need to hardcode the custom loader for GameSpeeds.
|
||||
var gameSpeeds = modData.Manifest.Get<GameSpeeds>();
|
||||
var gameSpeedNameField = typeof(GameSpeed).GetField(nameof(GameSpeed.Name));
|
||||
var gameSpeedFluentReference = Utility.GetCustomAttributes<FluentReferenceAttribute>(gameSpeedNameField, true)[0];
|
||||
testedFields.Add(gameSpeedNameField);
|
||||
foreach (var speed in gameSpeeds.Speeds.Values)
|
||||
usedKeys.Add(speed.Name, gameSpeedFluentReference, $"`{nameof(GameSpeed)}.{nameof(GameSpeed.Name)}`");
|
||||
// TODO: linter does not work with LoadUsing
|
||||
GetUsedTranslationKeysFromFieldsWithTranslationReferenceAttribute(
|
||||
usedKeys, testedFields, Utility.GetFields(typeof(GameSpeed)), modData.Manifest.Get<GameSpeeds>().Speeds.Values);
|
||||
|
||||
// TODO: linter does not work with LoadUsing
|
||||
foreach (var actorInfo in modData.DefaultRules.Actors)
|
||||
GetUsedTranslationKeysFromFieldsWithTranslationReferenceAttribute(
|
||||
usedKeys, testedFields,
|
||||
Utility.GetFields(typeof(ResourceRendererInfo.ResourceTypeInfo)),
|
||||
modData.DefaultRules.Actors
|
||||
.SelectMany(actorInfo => actorInfo.Value.TraitInfos<ResourceRendererInfo>())
|
||||
.SelectMany(info => info.ResourceTypes.Values));
|
||||
|
||||
const BindingFlags Binding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
|
||||
var constFields = modData.ObjectCreator.GetTypes().SelectMany(modType => modType.GetFields(Binding)).Where(f => f.IsLiteral);
|
||||
GetUsedTranslationKeysFromFieldsWithTranslationReferenceAttribute(
|
||||
usedKeys, testedFields, constFields, new[] { (object)null });
|
||||
|
||||
var modMetadataFields = typeof(ModMetadata).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
GetUsedTranslationKeysFromFieldsWithTranslationReferenceAttribute(
|
||||
usedKeys, testedFields, modMetadataFields, new[] { modData.Manifest.Metadata });
|
||||
|
||||
var modContent = modData.Manifest.Get<ModContent>();
|
||||
GetUsedTranslationKeysFromFieldsWithTranslationReferenceAttribute(
|
||||
usedKeys, testedFields, Utility.GetFields(typeof(ModContent)), new[] { modContent });
|
||||
GetUsedTranslationKeysFromFieldsWithTranslationReferenceAttribute(
|
||||
usedKeys, testedFields, Utility.GetFields(typeof(ModContent.ModPackage)), modContent.Packages.Values);
|
||||
|
||||
return (usedKeys, testedFields);
|
||||
}
|
||||
|
||||
static void GetUsedTranslationKeysFromFieldsWithTranslationReferenceAttribute(
|
||||
Keys usedKeys, List<FieldInfo> testedFields,
|
||||
IEnumerable<FieldInfo> newFields, IEnumerable<object> objects)
|
||||
{
|
||||
var fieldsWithAttribute =
|
||||
newFields
|
||||
.Select(f => (Field: f, FluentReference: Utility.GetCustomAttributes<FluentReferenceAttribute>(f, true).SingleOrDefault()))
|
||||
.Where(x => x.FluentReference != null)
|
||||
.ToArray();
|
||||
testedFields.AddRange(fieldsWithAttribute.Select(x => x.Field));
|
||||
foreach (var obj in objects)
|
||||
{
|
||||
foreach (var info in actorInfo.Value.TraitInfos<ResourceRendererInfo>())
|
||||
foreach (var (field, fluentReference) in fieldsWithAttribute)
|
||||
{
|
||||
var resourceTypeNameField = typeof(ResourceRendererInfo.ResourceTypeInfo).GetField(nameof(ResourceRendererInfo.ResourceTypeInfo.Name));
|
||||
var resourceTypeFluentReference = Utility.GetCustomAttributes<FluentReferenceAttribute>(resourceTypeNameField, true)[0];
|
||||
testedFields.Add(resourceTypeNameField);
|
||||
foreach (var resourceTypes in info.ResourceTypes)
|
||||
usedKeys.Add(
|
||||
resourceTypes.Value.Name,
|
||||
resourceTypeFluentReference,
|
||||
$"`{nameof(ResourceRendererInfo.ResourceTypeInfo)}.{nameof(ResourceRendererInfo.ResourceTypeInfo.Name)}`");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var modType in modData.ObjectCreator.GetTypes())
|
||||
{
|
||||
const BindingFlags Binding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
|
||||
foreach (var field in modType.GetFields(Binding))
|
||||
{
|
||||
// Checking for constant string fields.
|
||||
if (!field.IsLiteral)
|
||||
continue;
|
||||
|
||||
var fluentReference = Utility.GetCustomAttributes<FluentReferenceAttribute>(field, true).SingleOrDefault();
|
||||
if (fluentReference == null)
|
||||
continue;
|
||||
|
||||
testedFields.Add(field);
|
||||
var keys = LintExts.GetFieldValues(null, field, fluentReference.DictionaryReference);
|
||||
var keys = LintExts.GetFieldValues(obj, field, fluentReference.DictionaryReference);
|
||||
foreach (var key in keys)
|
||||
usedKeys.Add(key, fluentReference, $"`{field.ReflectedType.Name}.{field.Name}`");
|
||||
}
|
||||
}
|
||||
|
||||
return (usedKeys, testedFields);
|
||||
}
|
||||
|
||||
static void CheckModWidgets(ModData modData, Keys usedKeys, List<FieldInfo> testedFields)
|
||||
|
||||
@@ -30,10 +30,11 @@ namespace OpenRA.Mods.Common.Lint
|
||||
|
||||
void ILintPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData)
|
||||
{
|
||||
Run(emitError, emitWarning, modData.DefaultFileSystem, modData.Manifest.Translations);
|
||||
var allModTranslations = modData.Manifest.Translations.Append(modData.Manifest.Get<ModContent>().Translation);
|
||||
Run(emitError, emitWarning, modData.DefaultFileSystem, allModTranslations);
|
||||
}
|
||||
|
||||
static void Run(Action<string> emitError, Action<string> emitWarning, IReadOnlyFileSystem fileSystem, string[] paths)
|
||||
static void Run(Action<string> emitError, Action<string> emitWarning, IReadOnlyFileSystem fileSystem, IEnumerable<string> paths)
|
||||
{
|
||||
foreach (var path in paths)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Widgets;
|
||||
using OpenRA.Primitives;
|
||||
@@ -18,6 +20,9 @@ namespace OpenRA.Mods.Common.LoadScreens
|
||||
{
|
||||
public sealed class LogoStripeLoadScreen : SheetLoadScreen
|
||||
{
|
||||
[FluentReference]
|
||||
const string Loading = "loadscreen-loading";
|
||||
|
||||
Rectangle stripeRect;
|
||||
float2 logoPos;
|
||||
Sprite stripe, logo;
|
||||
@@ -26,14 +31,13 @@ namespace OpenRA.Mods.Common.LoadScreens
|
||||
int lastDensity;
|
||||
Size lastResolution;
|
||||
|
||||
string[] messages = { "Loading..." };
|
||||
string[] messages = Array.Empty<string>();
|
||||
|
||||
public override void Init(ModData modData, Dictionary<string, string> info)
|
||||
{
|
||||
base.Init(modData, info);
|
||||
|
||||
if (info.TryGetValue("Text", out var text))
|
||||
messages = text.Split(',');
|
||||
messages = FluentProvider.GetString(Loading).Split(',').Select(x => x.Trim()).ToArray();
|
||||
}
|
||||
|
||||
public override void DisplayInner(Renderer r, Sheet s, int density)
|
||||
@@ -59,7 +63,7 @@ namespace OpenRA.Mods.Common.LoadScreens
|
||||
if (logo != null)
|
||||
r.RgbaSpriteRenderer.DrawSprite(logo, logoPos);
|
||||
|
||||
if (r.Fonts != null)
|
||||
if (r.Fonts != null && messages.Length > 0)
|
||||
{
|
||||
var text = messages.Random(Game.CosmeticRandom);
|
||||
var textSize = r.Fonts["Bold"].Measure(text);
|
||||
|
||||
@@ -52,6 +52,10 @@ namespace OpenRA.Mods.Common.LoadScreens
|
||||
if (modId == null || !Game.Mods.TryGetValue(modId, out var selectedMod))
|
||||
throw new InvalidOperationException("Invalid or missing Content.Mod argument.");
|
||||
|
||||
var translationFilePath = args.GetValue("Content.TranslationFile", null);
|
||||
if (translationFilePath == null || !File.Exists(translationFilePath))
|
||||
throw new InvalidOperationException("Invalid or missing Content.TranslationFile argument.");
|
||||
|
||||
var content = selectedMod.Get<ModContent>(Game.ModData.ObjectCreator);
|
||||
|
||||
Ui.LoadWidget("MODCONTENT_BACKGROUND", Ui.Root, new WidgetArgs());
|
||||
@@ -63,6 +67,7 @@ namespace OpenRA.Mods.Common.LoadScreens
|
||||
{ "continueLoading", () => Game.RunAfterTick(() => Game.InitializeMod(modId, new Arguments())) },
|
||||
{ "mod", selectedMod },
|
||||
{ "content", content },
|
||||
{ "translationFilePath", translationFilePath },
|
||||
};
|
||||
|
||||
Ui.OpenWindow("CONTENT_PROMPT_PANEL", widgetArgs);
|
||||
@@ -71,9 +76,10 @@ namespace OpenRA.Mods.Common.LoadScreens
|
||||
{
|
||||
var widgetArgs = new WidgetArgs
|
||||
{
|
||||
{ "onCancel", () => Game.RunAfterTick(() => Game.InitializeMod(modId, new Arguments())) },
|
||||
{ "mod", selectedMod },
|
||||
{ "content", content },
|
||||
{ "onCancel", () => Game.RunAfterTick(() => Game.InitializeMod(modId, new Arguments())) }
|
||||
{ "translationFilePath", translationFilePath },
|
||||
};
|
||||
|
||||
Ui.OpenWindow("CONTENT_PANEL", widgetArgs);
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace OpenRA
|
||||
{
|
||||
public class ModPackage
|
||||
{
|
||||
[FluentReference]
|
||||
public readonly string Title;
|
||||
public readonly string Identifier;
|
||||
public readonly string[] TestFiles = Array.Empty<string>();
|
||||
@@ -100,10 +101,13 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
[FluentReference]
|
||||
public readonly string InstallPromptMessage;
|
||||
public readonly string QuickDownload;
|
||||
[FluentReference]
|
||||
public readonly string HeaderMessage;
|
||||
public readonly string ContentInstallerMod = "modcontent";
|
||||
public readonly string Translation;
|
||||
|
||||
[FieldLoader.LoadUsing(nameof(LoadPackages))]
|
||||
public readonly Dictionary<string, ModPackage> Packages = new();
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
var maps = new List<(IReadWritePackage Package, string Map)>();
|
||||
if (args.Length < 2)
|
||||
{
|
||||
Console.WriteLine($"Testing mod: {modData.Manifest.Metadata.Title}");
|
||||
Console.WriteLine($"Testing mod: {modData.Manifest.Metadata.TitleTranslated}");
|
||||
|
||||
// Run all rule checks on the default mod rules.
|
||||
CheckRules(modData, modData.DefaultRules);
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var switchButton = panel.Get<ButtonWidget>("SWITCH_BUTTON");
|
||||
|
||||
var mod = CurrentServerSettings.ServerExternalMod;
|
||||
var modTitle = mod.Title;
|
||||
var modTitle = mod.Id;
|
||||
var modVersion = mod.Version;
|
||||
|
||||
switchButton.OnClick = () =>
|
||||
|
||||
@@ -87,6 +87,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
readonly ModData modData;
|
||||
readonly ModContent content;
|
||||
readonly Dictionary<string, ModContent.ModSource> sources;
|
||||
readonly FluentBundle externalFluentBundle;
|
||||
|
||||
readonly Widget panel;
|
||||
readonly LabelWidget titleLabel;
|
||||
@@ -116,11 +117,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
Mode visible = Mode.Progress;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public InstallFromSourceLogic(Widget widget, ModData modData, ModContent content, Dictionary<string, ModContent.ModSource> sources)
|
||||
public InstallFromSourceLogic(
|
||||
Widget widget, ModData modData, ModContent content, Dictionary<string, ModContent.ModSource> sources, FluentBundle externalFluentBundle)
|
||||
{
|
||||
this.modData = modData;
|
||||
this.content = content;
|
||||
this.sources = sources;
|
||||
this.externalFluentBundle = externalFluentBundle;
|
||||
|
||||
Log.AddChannel("install", "install.log");
|
||||
|
||||
@@ -339,7 +342,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
var containerWidget = (ContainerWidget)checkboxListTemplate.Clone();
|
||||
var checkboxWidget = containerWidget.Get<CheckboxWidget>("PACKAGE_CHECKBOX");
|
||||
checkboxWidget.GetText = () => package.Title;
|
||||
var title = externalFluentBundle.GetString(package.Title);
|
||||
checkboxWidget.GetText = () => title;
|
||||
checkboxWidget.IsDisabled = () => package.Required;
|
||||
checkboxWidget.IsChecked = () => selectedPackages[package.Identifier];
|
||||
checkboxWidget.OnClick = () => selectedPackages[package.Identifier] = !selectedPackages[package.Identifier];
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Widgets;
|
||||
@@ -30,10 +31,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
readonly Dictionary<string, ModContent.ModSource> sources = new();
|
||||
readonly Dictionary<string, ModContent.ModDownload> downloads = new();
|
||||
|
||||
readonly FluentBundle externalFluentBundle;
|
||||
|
||||
bool sourceAvailable;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public ModContentLogic(Widget widget, Manifest mod, ModContent content, Action onCancel)
|
||||
public ModContentLogic(Widget widget, Manifest mod, ModContent content, Action onCancel, string translationFilePath)
|
||||
{
|
||||
this.content = content;
|
||||
|
||||
@@ -58,20 +61,25 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
modFileSystem.UnmountAll();
|
||||
|
||||
externalFluentBundle = new FluentBundle(Game.Settings.Player.Language, File.ReadAllText(translationFilePath), _ => { });
|
||||
|
||||
scrollPanel = panel.Get<ScrollPanelWidget>("PACKAGES");
|
||||
template = scrollPanel.Get<ContainerWidget>("PACKAGE_TEMPLATE");
|
||||
|
||||
var headerTemplate = panel.Get<LabelWidget>("HEADER_TEMPLATE");
|
||||
var headerLines = !string.IsNullOrEmpty(content.HeaderMessage) ? content.HeaderMessage.Replace("\\n", "\n").Split('\n') : Array.Empty<string>();
|
||||
var headerLines =
|
||||
!string.IsNullOrEmpty(content.HeaderMessage)
|
||||
? externalFluentBundle.GetString(content.HeaderMessage)
|
||||
: null;
|
||||
var headerHeight = 0;
|
||||
foreach (var l in headerLines)
|
||||
if (headerLines != null)
|
||||
{
|
||||
var line = (LabelWidget)headerTemplate.Clone();
|
||||
line.GetText = () => l;
|
||||
line.Bounds.Y += headerHeight;
|
||||
panel.AddChild(line);
|
||||
var label = (LabelWidget)headerTemplate.Clone();
|
||||
label.GetText = () => headerLines;
|
||||
label.IncreaseHeightToFitCurrentText();
|
||||
panel.AddChild(label);
|
||||
|
||||
headerHeight += headerTemplate.Bounds.Height;
|
||||
headerHeight += label.Bounds.Height;
|
||||
}
|
||||
|
||||
panel.Bounds.Height += headerHeight;
|
||||
@@ -85,7 +93,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
sourceButton.OnClick = () => Ui.OpenWindow("SOURCE_INSTALL_PANEL", new WidgetArgs
|
||||
{
|
||||
{ "sources", sources },
|
||||
{ "content", content }
|
||||
{ "content", content },
|
||||
{ "externalFluentBundle", externalFluentBundle },
|
||||
});
|
||||
|
||||
var backButton = panel.Get<ButtonWidget>("BACK_BUTTON");
|
||||
@@ -109,7 +118,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
var container = template.Clone();
|
||||
var titleWidget = container.Get<LabelWidget>("TITLE");
|
||||
var title = p.Value.Title;
|
||||
var title = externalFluentBundle.GetString(p.Value.Title);
|
||||
titleWidget.GetText = () => title;
|
||||
|
||||
var requiredWidget = container.Get<LabelWidget>("REQUIRED");
|
||||
|
||||
@@ -27,14 +27,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
const string Quit = "button-quit";
|
||||
|
||||
readonly ModContent content;
|
||||
readonly FluentBundle externalFluentBundle;
|
||||
bool requiredContentInstalled;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public ModContentPromptLogic(ModData modData, Widget widget, Manifest mod, ModContent content, Action continueLoading)
|
||||
public ModContentPromptLogic(ModData modData, Widget widget, Manifest mod, ModContent content, Action continueLoading, string translationFilePath)
|
||||
{
|
||||
this.content = content;
|
||||
CheckRequiredContentInstalled();
|
||||
|
||||
externalFluentBundle = new FluentBundle(Game.Settings.Player.Language, File.ReadAllText(translationFilePath), _ => { });
|
||||
|
||||
var continueMessage = FluentProvider.GetString(Continue);
|
||||
var quitMessage = FluentProvider.GetString(Quit);
|
||||
|
||||
@@ -42,17 +45,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var headerTemplate = panel.Get<LabelWidget>("HEADER_TEMPLATE");
|
||||
var headerLines =
|
||||
!string.IsNullOrEmpty(content.InstallPromptMessage)
|
||||
? content.InstallPromptMessage.Replace("\\n", "\n").Split('\n')
|
||||
: Array.Empty<string>();
|
||||
? externalFluentBundle.GetString(content.InstallPromptMessage)
|
||||
: null;
|
||||
var headerHeight = 0;
|
||||
foreach (var l in headerLines)
|
||||
if (headerLines != null)
|
||||
{
|
||||
var line = (LabelWidget)headerTemplate.Clone();
|
||||
line.GetText = () => l;
|
||||
line.Bounds.Y += headerHeight;
|
||||
panel.AddChild(line);
|
||||
var label = (LabelWidget)headerTemplate.Clone();
|
||||
label.GetText = () => headerLines;
|
||||
label.IncreaseHeightToFitCurrentText();
|
||||
panel.AddChild(label);
|
||||
|
||||
headerHeight += headerTemplate.Bounds.Height;
|
||||
headerHeight += label.Bounds.Height;
|
||||
}
|
||||
|
||||
panel.Bounds.Height += headerHeight;
|
||||
@@ -64,9 +67,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
Ui.OpenWindow("CONTENT_PANEL", new WidgetArgs
|
||||
{
|
||||
{ "onCancel", CheckRequiredContentInstalled },
|
||||
{ "mod", mod },
|
||||
{ "content", content },
|
||||
{ "onCancel", CheckRequiredContentInstalled }
|
||||
{ "translationFilePath", translationFilePath },
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -93,7 +93,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
return;
|
||||
|
||||
var content = modData.Manifest.Get<ModContent>();
|
||||
Game.InitializeMod(content.ContentInstallerMod, new Arguments(new[] { "Content.Mod=" + modData.Manifest.Id }));
|
||||
string translationPath;
|
||||
using (var fs = (FileStream)modData.DefaultFileSystem.Open(content.Translation))
|
||||
translationPath = fs.Name;
|
||||
Game.InitializeMod(
|
||||
content.ContentInstallerMod,
|
||||
new Arguments(new[] { "Content.Mod=" + modData.Manifest.Id, "Content.TranslationFile=" + translationPath }));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user