diff --git a/tests/Jellyfin.Plugin.Multilang.Tests/Jellyfin.Plugin.Multilang.Tests.csproj b/tests/Jellyfin.Plugin.Multilang.Tests/Jellyfin.Plugin.Multilang.Tests.csproj
index ef24ea9..f439f23 100644
--- a/tests/Jellyfin.Plugin.Multilang.Tests/Jellyfin.Plugin.Multilang.Tests.csproj
+++ b/tests/Jellyfin.Plugin.Multilang.Tests/Jellyfin.Plugin.Multilang.Tests.csproj
@@ -13,7 +13,8 @@
-
+
+
diff --git a/tests/Jellyfin.Plugin.Multilang.Tests/TranslationStoreImportTests.cs b/tests/Jellyfin.Plugin.Multilang.Tests/TranslationStoreImportTests.cs
new file mode 100644
index 0000000..6bb311e
--- /dev/null
+++ b/tests/Jellyfin.Plugin.Multilang.Tests/TranslationStoreImportTests.cs
@@ -0,0 +1,99 @@
+using Jellyfin.Plugin.Multilang.Data;
+using Jellyfin.Plugin.Multilang.Services.Providers;
+using Jellyfin.Plugin.Multilang.Services.Refresh;
+using MediaBrowser.Common.Configuration;
+
+namespace Jellyfin.Plugin.Multilang.Tests;
+
+public sealed class TranslationStoreImportTests
+{
+ [Fact]
+ public void ImportTranslationDatabaseKeepsOnlyLiveItemsAndAllowedLanguages()
+ {
+ var root = Path.Combine(Path.GetTempPath(), "multilang-test-" + Guid.NewGuid().ToString("N"));
+ try
+ {
+ var source = new TranslationStore(new TestApplicationPaths(Path.Combine(root, "source")));
+ var destination = new TranslationStore(new TestApplicationPaths(Path.Combine(root, "destination")));
+ var liveId = "11111111111111111111111111111111";
+ var staleId = "22222222222222222222222222222222";
+ SeedImportSource(source, liveId, staleId);
+
+ var exportPath = Path.Combine(root, "export.sqlite");
+ source.ExportTranslationDatabase(exportPath);
+
+ var result = destination.ImportTranslationDatabase(
+ exportPath,
+ new HashSet(StringComparer.OrdinalIgnoreCase) { liveId },
+ new HashSet(StringComparer.OrdinalIgnoreCase) { "en" });
+
+ Assert.Equal(new ImportDatabaseResult(Facts: 1, Translations: 1, Assets: 1, Genres: 2), result);
+ Assert.NotNull(destination.GetFacts(liveId));
+ Assert.Null(destination.GetFacts(staleId));
+ Assert.Equal("English title", Translation(destination, liveId, "en", "title"));
+ Assert.Null(Translation(destination, liveId, "fi", "title"));
+ Assert.Null(destination.GetAssetPath(liveId, "fi", "poster"));
+ Assert.Equal("https://asset/en.jpg", destination.GetAssetPath(liveId, "en", "poster"));
+ Assert.Equal(["en", "Original"], destination.GetGenres("movie").Select(g => g.Lang).OrderBy(v => v).ToArray());
+ }
+ finally
+ {
+ if (Directory.Exists(root))
+ Directory.Delete(root, recursive: true);
+ }
+ }
+
+ private static void SeedImportSource(TranslationStore store, string liveId, string staleId)
+ {
+ store.UpsertFacts(Item(liveId), Metadata("Live"), 1, 2);
+ store.UpsertFacts(Item(staleId), Metadata("Stale"), 1, 2);
+ store.UpsertTranslation(liveId, "en", "title", "English title");
+ store.UpsertTranslation(liveId, "fi", "title", "Finnish title");
+ store.UpsertTranslation(staleId, "en", "title", "Stale English title");
+ store.UpsertAsset(liveId, "en", "poster", "https://asset/en.jpg", 1);
+ store.UpsertAsset(liveId, "fi", "poster", "https://asset/fi.jpg", 1);
+ store.UpsertAsset(staleId, "en", "poster", "https://asset/stale.jpg", 1);
+ store.UpsertGenre(1, "movie", "en", "Action");
+ store.UpsertGenre(1, "movie", "fi", "Toiminta");
+ store.UpsertGenre(1, "movie", "Original", "Original action");
+ }
+
+ private static RefreshItemInfo Item(string itemId)
+ => new(itemId, "123", "movie", RefreshWorkClass.Movies, 0, 0, null, "Movie");
+
+ private static TmdbMetadata Metadata(string title)
+ => new(title, "Overview", "Tagline", title, "en", ["US"], ["US"], ["en"], [new TmdbGenre(1, "Action")]);
+
+ private static string? Translation(TranslationStore store, string itemId, string lang, string field)
+ => store.GetTranslations([itemId], [lang])
+ .GetValueOrDefault(itemId)?
+ .GetValueOrDefault(lang)?
+ .GetValueOrDefault(field);
+
+ private sealed class TestApplicationPaths(string root) : IApplicationPaths
+ {
+ public string ProgramDataPath { get; } = root;
+ public string WebPath { get; } = Path.Combine(root, "web");
+ public string ProgramSystemPath { get; } = Path.Combine(root, "system");
+ public string DataPath { get; } = Path.Combine(root, "data");
+ public string ImageCachePath { get; } = Path.Combine(root, "images");
+ public string PluginsPath { get; } = Path.Combine(root, "plugins");
+ public string PluginConfigurationsPath { get; } = Path.Combine(root, "plugin-configs");
+ public string LogDirectoryPath { get; } = Path.Combine(root, "logs");
+ public string ConfigurationDirectoryPath { get; } = Path.Combine(root, "config");
+ public string SystemConfigurationFilePath { get; } = Path.Combine(root, "config", "system.xml");
+ public string CachePath { get; } = Path.Combine(root, "cache");
+ public string TempDirectory { get; } = Path.Combine(root, "temp");
+ public string VirtualDataPath { get; } = "%AppDataPath%";
+ public string TrickplayPath { get; } = Path.Combine(root, "trickplay");
+ public string BackupPath { get; } = Path.Combine(root, "backups");
+
+ public void MakeSanityCheckOrThrow()
+ {
+ }
+
+ public void CreateAndCheckMarker(string path, string marker, bool isTemporary = false)
+ {
+ }
+ }
+}