What's New
Multi-language Support (#80)
- New language selector in Settings → Appearance
- Initial UI translations for English, Spanish, German, and Dutch covering all primary user surfaces (dashboard, subscriptions list, add/edit subscription form, settings notifications + data management, mobile menu)
- Lightweight, file-based translation catalog (
web/locales/*.json) — community-friendly for adding more languages - Per-user preferred language persisted in settings
- A small set of advanced surfaces (auth pages, SMTP/Pushover/Webhook configuration, categories/API keys management) remains English for v0.6.0 and is queued for v0.6.x as community contributors review and extend translations
🌍 Translations note: the non-English translations are an initial AI-assisted pass and have not been reviewed by native speakers. If you spot phrasing that sounds awkward, stilted, or wrong — please send a PR! Refinements are small, very welcome, and you don't have to fix everything at once. See
web/locales/README.mdfor how to contribute.
Tags (#110)
- Add multiple comma-separated tags to any subscription alongside its primary category
- Tags display as small chips under the subscription name
- Tags are created on the fly — just type new ones in the field
- Orphaned tags are cleaned up automatically when no subscription uses them
Duplicate Subscription (#109)
- One-click Duplicate button on each subscription row
- New copy keeps cost, category, schedule, URL, notes, label, and tags
- Reminder tracking is reset on the new copy so reminders fire fresh
Shared / Split Costs (#86)
- New "Shared with" field (people, including you) on each subscription
- Dashboard, analytics, and category stats automatically use your share of the cost (full cost divided by share count)
- Subscription list shows
split N ways · your share $X.XXunder the cost when shared
Multiple Notification Windows (#94)
- Configure multiple "days before" reminders via a comma-separated list (e.g.
7,3,0) in Settings - Each window fires once per renewal date — get a heads-up at 7 days, again at 3, and on the day-of
- Backward compatible: existing single-value
reminder_dayssetting still works as a fallback - Same feature available for cancellation reminders
Visual Distinction for Same-Service Subscriptions (#111)
- New optional Label field (e.g.
example.com,Mom's plan,work account) - Label appears as a secondary line under the subscription name
- Useful for multiple domain renewals at one registrar, family-shared streaming accounts, or any time you have two subscriptions to the same service
Technical Changes
- New
internal/i18npackage with a simple JSON catalog and English-fallback lookup; new template functiont .Lang "key" - New
Tagmodel with many-to-many join viasubscription_tags; newTagRepository/TagService - New fields on
Subscription:Label,ShareCount,LastReminderWindow,LastCancellationReminderWindow - New CSV-based settings
reminder_days_list/cancellation_reminder_days_listparsed byParseReminderWindows - Category stats SQL now respects
share_countso dashboard and analytics totals stay consistent - New routes:
POST /api/subscriptions/:id/duplicate,POST /api/settings/language,POST /api/settings/notifications/days_list,POST /api/settings/notifications/cancellation_days_list - Added Playwright specs for duplicate, label, tags, share count, and i18n (including a coverage spec that scans every primary page in every supported language for translation leaks)
- Added Go unit tests for
ParseReminderWindows, multi-window reminder logic, share-count math, tag service (parse + dedupe + replace + orphan cleanup), and i18n catalog lookup
Migration Notes
- Back up your database before upgrading. This release adds several new columns (
label,share_count,last_reminder_window,last_cancellation_reminder_window) and a newtagstable plus asubscription_tagsjoin table. Migrations run automatically on startup. - Existing subscriptions default to no label, no tags,
share_count = 1, and fresh reminder-window tracking — no behavior change. - The existing single-value
reminder_dayssetting still works; the newreminder_days_listCSV setting takes precedence when set.
Deferred to a future release
- Wallos import (#65): initial implementation targeted an incorrect format. Will ship in v0.6.1 once verified against a real Wallos backup (the actual Wallos formats are either a ZIP containing a SQLite DB, or a display-formatted JSON from
subscriptions/export.php).
Help us improve translations 🙏
If you read Spanish, German, or Dutch (or want SubTrackr in your own language), the translation files are at web/locales/*.json. Open a PR with any fixes — even one-key tweaks are welcome. See web/locales/README.md for the conventions.