Remove magic ftl file naming.
This commit is contained in:
@@ -13,7 +13,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Linguini.Bundle;
|
||||
using Linguini.Bundle.Builder;
|
||||
using Linguini.Shared.Types.Bundle;
|
||||
@@ -53,37 +52,30 @@ namespace OpenRA
|
||||
{
|
||||
readonly Linguini.Bundle.FluentBundle bundle;
|
||||
|
||||
public FluentBundle(string language, string[] paths, IReadOnlyFileSystem fileSystem)
|
||||
: this(language, paths, fileSystem, error => Log.Write("debug", error.Message)) { }
|
||||
public FluentBundle(string culture, string[] paths, IReadOnlyFileSystem fileSystem)
|
||||
: this(culture, paths, fileSystem, error => Log.Write("debug", error.Message)) { }
|
||||
|
||||
public FluentBundle(string language, string[] paths, IReadOnlyFileSystem fileSystem, string text)
|
||||
: this(language, paths, fileSystem, text, error => Log.Write("debug", error.Message)) { }
|
||||
public FluentBundle(string culture, string[] paths, IReadOnlyFileSystem fileSystem, string text)
|
||||
: this(culture, paths, fileSystem, text, error => Log.Write("debug", error.Message)) { }
|
||||
|
||||
public FluentBundle(string language, string[] paths, IReadOnlyFileSystem fileSystem, Action<ParseError> onError)
|
||||
: this(language, paths, fileSystem, null, onError) { }
|
||||
public FluentBundle(string culture, string[] paths, IReadOnlyFileSystem fileSystem, Action<ParseError> onError)
|
||||
: this(culture, paths, fileSystem, null, onError) { }
|
||||
|
||||
public FluentBundle(string language, string text, Action<ParseError> onError)
|
||||
: this(language, null, null, text, onError) { }
|
||||
public FluentBundle(string culture, string text, Action<ParseError> onError)
|
||||
: this(culture, null, null, text, onError) { }
|
||||
|
||||
public FluentBundle(string language, string[] paths, IReadOnlyFileSystem fileSystem, string text, Action<ParseError> onError)
|
||||
public FluentBundle(string culture, string[] paths, IReadOnlyFileSystem fileSystem, string text, Action<ParseError> onError)
|
||||
{
|
||||
bundle = LinguiniBuilder.Builder()
|
||||
.CultureInfo(new CultureInfo(language))
|
||||
.CultureInfo(new CultureInfo(culture))
|
||||
.SkipResources()
|
||||
.SetUseIsolating(false)
|
||||
.UseConcurrent()
|
||||
.UncheckedBuild();
|
||||
|
||||
if (paths != null && paths.Length > 0)
|
||||
if (paths != null)
|
||||
{
|
||||
// Always load english strings to provide a fallback for missing translations.
|
||||
// It is important to load the english files first so the chosen language's files can override them.
|
||||
var resolvedPaths = paths.Where(t => t.EndsWith("en.ftl", StringComparison.Ordinal)).ToList();
|
||||
foreach (var t in paths)
|
||||
if (t.EndsWith($"{language}.ftl", StringComparison.Ordinal))
|
||||
resolvedPaths.Add(t);
|
||||
|
||||
foreach (var path in resolvedPaths.Distinct())
|
||||
foreach (var path in paths)
|
||||
{
|
||||
var stream = fileSystem.Open(path);
|
||||
using (var reader = new StreamReader(stream))
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace OpenRA
|
||||
{
|
||||
lock (SyncObject)
|
||||
{
|
||||
modFluentBundle = new FluentBundle(Game.Settings.Player.Language, modData.Manifest.Translations, fileSystem);
|
||||
modFluentBundle = new FluentBundle(modData.Manifest.FluentCulture, modData.Manifest.Translations, fileSystem);
|
||||
if (fileSystem is Map map && map.FluentMessageDefinitions != null)
|
||||
{
|
||||
var files = Array.Empty<string>();
|
||||
@@ -44,7 +44,7 @@ namespace OpenRA
|
||||
text = builder.ToString();
|
||||
}
|
||||
|
||||
mapFluentBundle = new FluentBundle(Game.Settings.Player.Language, files, fileSystem, text);
|
||||
mapFluentBundle = new FluentBundle(modData.Manifest.FluentCulture, files, fileSystem, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,10 +83,13 @@ namespace OpenRA
|
||||
public readonly string[] SpriteFormats = Array.Empty<string>();
|
||||
public readonly string[] PackageFormats = Array.Empty<string>();
|
||||
public readonly string[] VideoFormats = Array.Empty<string>();
|
||||
public readonly bool AllowUnusedTranslationsInExternalPackages = true;
|
||||
public readonly int FontSheetSize = 512;
|
||||
public readonly int CursorSheetSize = 512;
|
||||
|
||||
// TODO: This should be controlled by a user-selected translation bundle!
|
||||
public readonly string FluentCulture = "en";
|
||||
public readonly bool AllowUnusedTranslationsInExternalPackages = true;
|
||||
|
||||
readonly string[] reservedModuleNames =
|
||||
{
|
||||
"Include", "Metadata", "FileSystem", "MapFolders", "Rules",
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace OpenRA
|
||||
text = builder.ToString();
|
||||
}
|
||||
|
||||
FluentBundle = new FluentBundle(Game.Settings.Player.Language, files, fileSystem, text);
|
||||
FluentBundle = new FluentBundle(modData.Manifest.FluentCulture, files, fileSystem, text);
|
||||
}
|
||||
else
|
||||
FluentBundle = null;
|
||||
|
||||
@@ -249,7 +249,6 @@ namespace OpenRA
|
||||
public Color Color = Color.FromArgb(200, 32, 32);
|
||||
public string LastServer = "localhost:1234";
|
||||
public Color[] CustomColors = Array.Empty<Color>();
|
||||
public string Language = "en";
|
||||
}
|
||||
|
||||
public class GameSettings
|
||||
|
||||
@@ -26,9 +26,6 @@ namespace OpenRA
|
||||
if (Game.EngineVersion != null)
|
||||
Log.Write("exception", $"OpenRA engine version {Game.EngineVersion}");
|
||||
|
||||
if (Game.Settings != null && Game.Settings.Player != null && Game.Settings.Player.Language != null)
|
||||
Log.Write("exception", $"OpenRA Language: {Game.Settings.Player.Language}");
|
||||
|
||||
if (Game.ModData != null)
|
||||
{
|
||||
var manifest = Game.ModData.Manifest;
|
||||
|
||||
@@ -30,8 +30,6 @@ namespace OpenRA.Mods.Common.Lint
|
||||
{
|
||||
sealed class CheckFluentReferences : ILintPass, ILintMapPass
|
||||
{
|
||||
static readonly Regex FilenameRegex = new(@"(?<language>[^\/\\]+)\.ftl$");
|
||||
|
||||
void ILintMapPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData, Map map)
|
||||
{
|
||||
if (map.FluentMessageDefinitions == null)
|
||||
@@ -43,32 +41,27 @@ namespace OpenRA.Mods.Common.Lint
|
||||
emitWarning($"Empty key in map ftl files required by {context}");
|
||||
|
||||
var mapTranslations = FieldLoader.GetValue<string[]>("value", map.FluentMessageDefinitions.Value);
|
||||
|
||||
var allModTranslations = modData.Manifest.Translations;
|
||||
foreach (var language in GetModLanguages(allModTranslations))
|
||||
|
||||
// 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(allModTranslations.Concat(mapTranslations), map.Open, usedKeys,
|
||||
_ => false, emitError, emitWarning);
|
||||
|
||||
var modFluentBundle = new FluentBundle(modData.Manifest.FluentCulture, allModTranslations, modData.DefaultFileSystem, _ => { });
|
||||
var mapFluentBundle = new FluentBundle(modData.Manifest.FluentCulture, mapTranslations, map, error => emitError(error.Message));
|
||||
|
||||
foreach (var group in usedKeys.KeysWithContext)
|
||||
{
|
||||
// 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(
|
||||
allModTranslations.Concat(mapTranslations), map.Open, usedKeys,
|
||||
language, _ => false, emitError, emitWarning);
|
||||
|
||||
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)
|
||||
if (modFluentBundle.HasMessage(group.Key))
|
||||
{
|
||||
if (modFluentBundle.HasMessage(group.Key))
|
||||
{
|
||||
if (mapFluentBundle.HasMessage(group.Key))
|
||||
emitWarning($"Key `{group.Key}` in `{language}` language in map ftl files already exists in mod translations and will not be used.");
|
||||
}
|
||||
else if (!mapFluentBundle.HasMessage(group.Key))
|
||||
{
|
||||
foreach (var context in group)
|
||||
emitWarning($"Missing key `{group.Key}` in `{language}` language in map ftl files required by {context}");
|
||||
}
|
||||
if (mapFluentBundle.HasMessage(group.Key))
|
||||
emitWarning($"Key `{group.Key}` in map ftl files already exists in mod translations and will not be used.");
|
||||
}
|
||||
else if (!mapFluentBundle.HasMessage(group.Key))
|
||||
{
|
||||
foreach (var context in group)
|
||||
emitWarning($"Missing key `{group.Key}` in map ftl files required by {context}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,34 +73,30 @@ namespace OpenRA.Mods.Common.Lint
|
||||
|
||||
void ILintPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData)
|
||||
{
|
||||
Console.WriteLine("Testing Fluent references");
|
||||
var (usedKeys, testedFields) = GetUsedFluentKeysInMod(modData);
|
||||
|
||||
foreach (var context in usedKeys.EmptyKeyContexts)
|
||||
emitWarning($"Empty key in mod translation files required by {context}");
|
||||
|
||||
var allModTranslations = modData.Manifest.Translations.ToArray();
|
||||
foreach (var language in GetModLanguages(allModTranslations))
|
||||
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(
|
||||
allModTranslations, modData.DefaultFileSystem.Open, usedKeys,
|
||||
file =>
|
||||
!modData.Manifest.AllowUnusedTranslationsInExternalPackages ||
|
||||
!modData.DefaultFileSystem.IsExternalFile(file),
|
||||
emitError, emitWarning);
|
||||
|
||||
foreach (var group in usedKeys.KeysWithContext)
|
||||
{
|
||||
Console.WriteLine($"Testing language: {language}");
|
||||
CheckModWidgets(modData, usedKeys, testedFields);
|
||||
if (keyWithAttrs.Contains(group.Key))
|
||||
continue;
|
||||
|
||||
// With the fully populated keys, check keys and variables are not missing and not unused across all language files.
|
||||
var keyWithAttrs = CheckKeys(
|
||||
allModTranslations, modData.DefaultFileSystem.Open, usedKeys,
|
||||
language,
|
||||
file =>
|
||||
!modData.Manifest.AllowUnusedTranslationsInExternalPackages ||
|
||||
!modData.DefaultFileSystem.IsExternalFile(file),
|
||||
emitError, emitWarning);
|
||||
|
||||
foreach (var group in usedKeys.KeysWithContext)
|
||||
{
|
||||
if (keyWithAttrs.Contains(group.Key))
|
||||
continue;
|
||||
|
||||
foreach (var context in group)
|
||||
emitWarning($"Missing key `{group.Key}` in `{language}` language in mod ftl files required by {context}");
|
||||
}
|
||||
foreach (var context in group)
|
||||
emitWarning($"Missing key `{group.Key}` in mod ftl files required by {context}");
|
||||
}
|
||||
|
||||
// Check if we couldn't test any fields.
|
||||
@@ -121,14 +110,6 @@ namespace OpenRA.Mods.Common.Lint
|
||||
$"`{field.ReflectedType.Name}.{field.Name}` - previous warnings may be incorrect");
|
||||
}
|
||||
|
||||
static IEnumerable<string> GetModLanguages(IEnumerable<string> translations)
|
||||
{
|
||||
return translations
|
||||
.Select(filename => FilenameRegex.Match(filename).Groups["language"].Value)
|
||||
.Distinct()
|
||||
.OrderBy(l => l);
|
||||
}
|
||||
|
||||
static Keys GetUsedFluentKeysInRuleset(Ruleset rules)
|
||||
{
|
||||
var usedKeys = new Keys();
|
||||
@@ -427,15 +408,11 @@ namespace OpenRA.Mods.Common.Lint
|
||||
|
||||
static HashSet<string> CheckKeys(
|
||||
IEnumerable<string> paths, Func<string, Stream> openFile, Keys usedKeys,
|
||||
string language, Func<string, bool> checkUnusedKeysForFile,
|
||||
Action<string> emitError, Action<string> emitWarning)
|
||||
Func<string, bool> checkUnusedKeysForFile, Action<string> emitError, Action<string> emitWarning)
|
||||
{
|
||||
var keyWithAttrs = new HashSet<string>();
|
||||
foreach (var path in paths)
|
||||
{
|
||||
if (!path.EndsWith($"{language}.ftl", StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
var stream = openFile(path);
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user