1 Commits

Author SHA1 Message Date
3aecbf566b feat: Add Software alternative titles and use them in IGDB matching
Software entries (especially games) often have regional, script, or
otherwise alternative titles — e.g. a Japanese Kanji/Romaji title
alongside the Western release name. There was previously no way to
record these.

Database layer:
- New SoftwareAlternativeTitle entity (SoftwareId FK, Title, nullable
  Comment), cascade-deleted with its Software.
- New SoftwareAlternativeTitleCommentTranslation, a string-pool
  translation table keyed by (CommentText, LanguageCode), mirroring
  the existing SoftwareCoverCaptionTranslation pattern. Comments are
  free text that repeats often ("Japanese title", "European title"),
  so pooling avoids duplicate translation work.
- Migration AddSoftwareAlternativeTitles.

Translation pipeline:
- SoftwareAlternativeTitleCommentTranslationProvider, registered with
  the background TranslationWorker, anti-join translates missing
  comments into es/fr/de/it/nl.

API:
- GET /software/{id}/alternative-titles (public, language-aware, with
  an English fast path that skips the translation sub-query).
- POST/PUT/DELETE /software/alternative-titles (admin-only CRUD) on a
  new SoftwareAlternativeTitlesController.
- Kiota client regenerated against the updated OpenAPI schema.

Blazor admin UI:
- New "Alternative Titles" tab in SoftwareDialog.razor, with the same
  create-mode buffering/flush-after-create pattern used by the
  existing Genres tab.
- SoftwareService.cs client methods for list/add/remove.
- Localized resx strings added for en/es/fr/de/it/nl.

IGDB matching:
- Mirrored IGDB's /alternative_names endpoint into a new
  IgdbAlternativeName table (GameIgdbId, Name, Comment), via
  IgdbAlternativeNameMirrorService and a new `mirror-alternative-names`
  CLI command, following the existing resumable id-paged mirror
  pattern (e.g. InvolvedCompanyMirrorService).
- GameMatcher now builds a full name-variant set per side (IGDB
  canonical name + its mirrored alternative names; local Software
  name + its SoftwareAlternativeTitle rows) and matches across the
  full cross-product, both for exact equality and the Jaro-Winkler
  fuzzy sweep. This lets an IGDB alternate name match a local
  alternate title directly, not just canonical-vs-canonical.
- Match results record whether the winning pair was canonical-vs-
  canonical or involved an alternate, via a "-alt" suffix on
  MatchType (exact-alt, exact-platform-disambiguated-alt,
  jw-platform-corroborated-alt), keeping the match audit trail
  informative.
2026-06-26 02:16:39 +01:00