[Wiki] loc fix 2 (#3484)

This commit is contained in:
Pok
2026-01-15 08:44:45 +02:00
committed by GitHub
parent d326420204
commit eff710e312

View File

@@ -29,19 +29,18 @@ public static class LocJsonGenerator
.Where(c => c.Filename.EndsWith(".ftl", StringComparison.InvariantCultureIgnoreCase))
.ToArray();
var keys = new Dictionary<string, HashSet<string>>();
var keysValues = new Dictionary<string, string>();
// Matches top-level message/term identifiers at start of line (no leading whitespace or comment).
var topEntryRegex = new Regex(@"(?m)^(?!\s|#)([^\s=]+)\s*=", RegexOptions.Compiled);
var topEntryRegex = new Regex(@"^(?!\s|#)([^\s=]+)\s*=", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.CultureInvariant);
// Matches attribute lines like " .attr-name ="
var attrRegex = new Regex(@"(?m)^\s*\.(?<name>[A-Za-z0-9_\-]+)\s*=", RegexOptions.Compiled);
var attrRegex = new Regex(@"^\s*\.(?<name>[A-Za-z0-9_\-]+)\s*=", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.CultureInvariant);
foreach (var path in files)
{
using var stream = res.ContentFileRead(path);
using var reader = new StreamReader(stream, Encoding.UTF8);
var contents = reader.ReadToEnd();
// Normalize line endings to simplify indexing.
contents = contents.Replace("\r\n", "\n");
var contents = reader.ReadToEnd().Replace("\r\n", "\n");
var matches = topEntryRegex.Matches(contents);
for (var mi = 0; mi < matches.Count; mi++)
@@ -57,13 +56,66 @@ public static class LocJsonGenerator
var start = m.Index;
var end = mi + 1 < matches.Count ? matches[mi + 1].Index : contents.Length;
var block = contents.Substring(start, end - start);
var attrMatches = attrRegex.Matches(block);
foreach (Match am in attrMatches)
var mainEqual = block.IndexOf('=');
if (mainEqual >= 0)
{
var mainValueStart = mainEqual + 1;
var mainValueEnd = attrMatches.Count > 0 ? attrMatches[0].Index : block.Length;
keysValues[id] = mainValueEnd > mainValueStart ? FluentValue(block.Substring(mainValueStart, mainValueEnd - mainValueStart)) : string.Empty;
}
else
{
keysValues[id] = string.Empty;
}
for (var ai = 0; ai < attrMatches.Count; ai++)
{
var am = attrMatches[ai];
var attrName = am.Groups["name"].Value;
if (!string.IsNullOrEmpty(attrName))
keys[id].Add(attrName);
if (string.IsNullOrEmpty(attrName))
continue;
keys[id].Add(attrName);
var attrEqual = block.IndexOf('=', am.Index);
var attrValueStart = attrEqual >= 0 ? attrEqual + 1 : am.Index + am.Length;
var nextAttrIndex = ai + 1 < attrMatches.Count ? attrMatches[ai + 1].Index : block.Length;
keysValues[$"{id}.{attrName}"] = nextAttrIndex > attrValueStart ? FluentValue(block.Substring(attrValueStart, nextAttrIndex - attrValueStart)) : string.Empty;
}
continue;
// Helper: remove leading newline and common indentation across non-empty lines.
string FluentValue(string val)
{
if (string.IsNullOrEmpty(val))
return string.Empty;
if (val.Length > 0 && val[0] == '\n')
val = val.Substring(1);
var lines = val.Split('\n');
lines = lines.Where(l => !(l.Length > 0 && l[0] == '#')).ToArray();
var nonEmptyLines = lines.Where(l => !string.IsNullOrWhiteSpace(l)).ToArray();
if (nonEmptyLines.Length == 0)
return string.Join("\n", lines).TrimEnd('\n');
var minIndent = nonEmptyLines.Min(l => l.TakeWhile(char.IsWhiteSpace).Count());
if (minIndent > 0)
{
for (var li = 0; li < lines.Length; li++)
{
var line = lines[li];
if (line.Length >= minIndent)
lines[li] = line.Substring(minIndent);
}
}
var result = string.Join("\n", lines);
if (result.EndsWith("\n"))
result = result.Substring(0, result.Length - 1);
return result;
}
}
}
@@ -74,18 +126,18 @@ public static class LocJsonGenerator
{
if (attrs.Count == 0)
{
output[id] = Loc.GetString(id);
output[id] = keysValues.TryGetValue(id, out var value) ? value : string.Empty;
}
else
{
// _value is the main value of the key.
var obj = new Dictionary<string, string?>
{
["_value"] = Loc.GetString(id),
["_value"] = keysValues.TryGetValue(id, out var valueMain) ? valueMain : string.Empty,
};
foreach (var attr in attrs.OrderBy(a => a))
{
obj[attr] = Loc.GetString($"{id}.{attr}");
obj[attr] = keysValues.TryGetValue($"{id}.{attr}", out var valueAttr) ? valueAttr : string.Empty;
}
output[id] = obj;
}