diff --git a/src/LocaleAtlasBuilder.cs b/src/LocaleAtlasBuilder.cs
index 385f28c..6561a66 100644
--- a/src/LocaleAtlasBuilder.cs
+++ b/src/LocaleAtlasBuilder.cs
@@ -26,12 +26,17 @@ namespace Cthangover.LocaleAtlas
/// - manifest — mod_<id>_name/_desc used by the mod manager
/// (optional: the manifest text is the fallback).
///
- /// Collection files (collections/*.json) are also checked for inline
- /// locale entries: a literal name/description is the
- /// en text, every other project language needs a locale entry.
+ /// Collection packages come as sources named
+ /// + id: their locale/ files are declarations like a mod's, and their
+ /// collection.json is checked for inline locale entries — a
+ /// literal name/description is the en text, every other
+ /// project language needs a locale entry.
///
public static class LocaleAtlasBuilder
{
+ /// Source id prefix of a collection package (collection:<id>), as opposed to a mod.
+ public const string CollectionSourcePrefix = "collection:";
+
/// Language of literal collection texts (fallback in ModCollection.GetLocalizedName).
public const string CollectionBaseLanguage = "en";
@@ -66,6 +71,8 @@ namespace Cthangover.LocaleAtlas
result.Mods.Add(modId);
ScanLocaleFiles(modId, provider, result);
ScanReferences(modId, provider, result, collections, documents);
+ if (modId.StartsWith(CollectionSourcePrefix, StringComparison.Ordinal))
+ continue;
result.References.Add(new LocaleReference { Key = $"mod_{modId}_name", ModId = modId, File = "manifest.json", Via = "manifest", Optional = true });
result.References.Add(new LocaleReference { Key = $"mod_{modId}_desc", ModId = modId, File = "manifest.json", Via = "manifest", Optional = true });
}
@@ -229,7 +236,7 @@ namespace Cthangover.LocaleAtlas
AddMatches(SceneText, text, file, modId, "scene", result);
break;
case ".json":
- var isCollection = file.StartsWith("collections/", StringComparison.Ordinal);
+ var isCollection = file == "collection.json" && modId.StartsWith(CollectionSourcePrefix, StringComparison.Ordinal);
if (!isCollection)
AddMatches(JsonTextField, text, file, modId, "json", result);
AddMatches(JsonAtKey, text, file, modId, isCollection ? "collection" : "json", result);
diff --git a/src/LocaleAtlasDriverNode.cs b/src/LocaleAtlasDriverNode.cs
index 54096f7..7b22399 100644
--- a/src/LocaleAtlasDriverNode.cs
+++ b/src/LocaleAtlasDriverNode.cs
@@ -91,6 +91,12 @@ namespace Cthangover.LocaleAtlas
result.Add((info.Id, info.FileProvider));
}
+ foreach (var collection in ModCollectionStore.LoadAll())
+ {
+ if (collection.Package != null)
+ result.Add((LocaleAtlasBuilder.CollectionSourcePrefix + collection.Id, collection.Package));
+ }
+
return result;
}
diff --git a/tests/LocaleAtlasTests.cs b/tests/LocaleAtlasTests.cs
index 18c1684..82eab15 100644
--- a/tests/LocaleAtlasTests.cs
+++ b/tests/LocaleAtlasTests.cs
@@ -170,13 +170,13 @@ namespace Cthangover.LocaleAtlas.Tests
[ModTest("map/collection_texts_need_every_language")]
static void CollectionTextsNeedEveryLanguage(ModTestContext ctx)
{
- var mod = new MemoryProvider("m")
+ var package = new MemoryProvider("c")
.Add("locale/en.properties", "x = X\n")
.Add("locale/ru.properties", "x = Икс\n")
- .Add("collections/c.json",
+ .Add("collection.json",
"{ \"id\": \"c\", \"name\": \"Game\", \"locale\": [ { \"lang\": \"ru\", \"name\": \"Игра\" } ],\n" +
" \"mechanics\": [ { \"id\": \"m1\", \"name\": \"Story\" }, { \"id\": \"m2\", \"name\": \"@x\" } ] }");
- var result = LocaleAtlasBuilder.Build(new[] { ("m", (IModFileProvider)mod) });
+ var result = LocaleAtlasBuilder.Build(new[] { (LocaleAtlasBuilder.CollectionSourcePrefix + "c", (IModFileProvider)package) });
var missing = result.Findings.Where(f => f.Code == "collection_text_missing").ToList();
ModAssert.Equal(1, missing.Count, "only the literal mechanic without ru: " + string.Join("; ", missing.Select(f => f.Message)));
ModAssert.Equal("m1", missing[0].Key, "mechanic id");