Changelog
View SourceAll notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.2.0 - 2026-07-28
A correctness release. Plural translations never actually worked, and the extractor could silently drop strings or report the wrong line. Both are fixed, and the library now tracks the current Gettext and LiveSvelte ecosystem.
Upgrading requires no code changes. If you use ngettext in Svelte components,
run mix gettext.extract && mix gettext.merge priv/gettext and fill in the
msgstr[n] entries - they were previously ignored.
Fixed
Plural translations were never applied.
all_translations/1returned the raw Englishmsgid/msgid_pluralfor every locale, songettextrendered untranslated text everywhere. Compounding it, the client looked plural forms up under keys the server never emitted, so even a hand-built map would not have worked.Plural forms are now read directly from your
.pofiles. This is not avoidable via Gettext's runtime API:lngettext/7doesMap.put(bindings, :count, n)internally, so it can never return a localized plural with the%{count}placeholder intact - and the placeholder is what must reach the browser, since interpolation happens client-side.Plural form selection ignored the locale. The client always used
count === 1 ? singular : plural, which is wrong for the many languages with more than two forms. Selection now follows the locale's own rules viaIntl.PluralRules, so Polish, Russian, Arabic and friends work correctly. Falls back to the English rule whenIntl.PluralRulesis unavailable.Multi-line comments shifted
.potline references. Comments were deleted before scanning, taking their newlines with them, so every reference after a multi-line<!-- ... -->pointed too far up the file. Comments are now blanked out with their line structure preserved.The extractor silently dropped valid calls. The pattern required the whole call to close with an optional object literal, so these were skipped without any warning:
{gettext("Hello %{name}", vars)} <!-- non-literal bindings --> {gettext("Hello", buildVars(user))} <!-- function call --> {gettext( "Prettier formatted", { name }, <!-- trailing comma --> )}Only the msgid is matched now; whatever follows is ignored, so an unusual bindings argument can no longer cause a string to vanish.
Declared Gettext requirement was unsatisfiable.
~> 0.24was advertised, butuse Gettext.Backendand thelgettext/5andlngettext/7callbacks were only introduced in Gettext 0.26 - installing with 0.24 or 0.25 failed to compile. The requirement is now~> 0.26 or ~> 1.0, and CI tests both ends of the range.
Added
Gettext 1.0 support. No
override: trueneeded.translation_payload/1on generated modules, returning the translation map with the locale and its plural rules under the reserved"__lsg__"key.<.svelte_translations />uses it automatically and falls back toall_translations/1for modules compiled against 0.1.x.The metadata is nested rather than wrapping the translations (
%{"locale" => ..., "translations" => ...}) specifically so older clients keep working: they dotranslations = {...payload}and look msgids up directly, so a wrapper would make every lookup miss and every string fall back to English with no error anywhere. Verified against the published npm 0.1.1 bundle - upgrading Hex before npm keeps singular translations working, and plurals stay exactly as they already were.Automatic reload on locale change. The client watches the translation script tag, so a LiveView locale switch updates Svelte components without a page reload.
refreshTranslations()andgetLocale()exported from the JavaScript client.JavaScript comments are ignored when extracting - whole-line
//comments and/* ... */blocks, alongside the existing<!-- ... -->handling.Real test coverage for
mix gettext.extract. The.potreference behaviour - the library's core promise - was previously only tested by hand.
Changed
- Jason is now optional. On OTP 27+ the built-in
:jsonmodule is used, matching LiveSvelte 0.17's move away from a hard Jason dependency. Override withconfig :live_svelte_gettext, json_library: MyEncoder. - Runtime lookup moved out of the generated code into
LiveSvelteGettext.Runtime, so lookup fixes ship as a library upgrade instead of requiring consumers to recompile. mix hex.buildandmix hex.publishnow build the JavaScript bundle and verify thatmix.exsandassets/package.jsonagree on the version. The npm package had drifted to 0.1.1 while Hex was at 0.1.3, andassets/distis gitignored, so a publish could ship a stale bundle.- CI now runs the TypeScript test suite (69 tests that had never run in CI), tests Elixir 1.18/OTP 27 and 1.20/OTP 28, and verifies both the floor and the ceiling of the declared dependency ranges.
Compatibility
Verified against Elixir 1.18 and 1.20, OTP 27 and 28, Gettext 0.26 and 1.0, and
Expo 0.5 and 1.1. LiveSvelte itself is not a dependency - the library reads
.svelte files and renders a <script> tag - so LiveSvelte 0.18's move to Vite
needs no changes here.
0.1.3 - 2025-10-19
Fixed
- Fixed extraction of multiline gettext calls
- Previously, the extractor would fail to find
gettext()calls split across multiple lines - Now correctly handles calls with line breaks between function name and arguments
- Ensures all translation strings are extracted regardless of formatting
- Previously, the extractor would fail to find
0.1.2 - 2025-10-16
Fixed
Fixed compilation error when installed as a dependency
- Changed
igniterfromonly: :devtooptional: trueto follow Igniter best practices - Updated to Igniter ~> 0.6 (from ~> 0.5)
- Refactored installer to use conditional compilation pattern (
if Code.ensure_loaded?(Igniter)) - Previously, the installer task would fail to compile because Igniter wasn't available in the dependency environment
- The
only: :devoption meant Igniter was only available when developing the library itself, not when used as a dependency - The
optional: trueconfiguration makes Igniter available during installation but doesn't include it in production builds - Installer now gracefully falls back to a helpful error message when Igniter is not available
- Installation now works reliably with
mix igniter.install live_svelte_gettext
- Changed
Fixed installer crash caused by unnecessary Gettext backend modification step
- Removed the step that attempted to add
use LiveSvelteGettextto Gettext backend - This step was causing the Igniter installer to crash on clean installations
- The
use LiveSvelteGettextshould be added manually by users in their SvelteStrings module, not injected into the Gettext backend - Removed 62 lines of problematic code from
lib/mix/tasks/live_svelte_gettext.install.ex
- Removed the step that attempted to add
Changed
- Simplified installation process
- Reduced installation steps from 7 to 6 by removing manual Gettext backend modification
- Users now have more control over how
LiveSvelteGettextis integrated into their backend
0.1.1 - 2025-10-14
Fixed
- Igniter installer critical bug fixes (7 issues resolved)
- Fixed backend detection to only find actual
Gettext.Backendmodules, not consumers (Issue #7) - Fixed module naming to create proper submodule
MyApp.Gettext.SvelteStrings(Issue #4) - Fixed missing
use LiveSvelteGettextin Gettext backend (previously undiscovered issue) - Fixed component import to be added to both
:htmland:live_viewfunctions (Issue #3) - Eliminated all compile warnings about undefined functions (Issue #5)
- Fixed backend detection to only find actual
- Fixed translation initialization race condition
- Phoenix hook
mounted()callback sometimes doesn't fire before Svelte components callgettext() - Implemented lazy initialization - translations now auto-initialize on first use
- Completely removed Phoenix hook requirement for simpler setup
- Phoenix hook
Changed
- Refactored JavaScript setup to manual process (Issues #1, #2, #6 resolution)
- Removed 300+ lines of fragile regex-based JavaScript modification code
- JavaScript setup now uses interactive
mix live_svelte_gettext.setupwizard - Users get clear, copy-pasteable code snippets based on their project structure
- More reliable across different JavaScript formatting styles and project setups
- Follows Elixir ecosystem best practices (explicit over implicit)
- Phoenix hook completely removed
- Zero JavaScript setup required - just install the NPM package
- Translations automatically initialize on first
gettext()orngettext()call - Simpler API with less cognitive overhead for users
- Updated all documentation to remove hook references
Added
- Interactive setup wizard (
mix live_svelte_gettext.setup)- Detects
app.jslocation automatically - Analyzes existing code structure and hooks
- Provides context-aware, copy-pasteable instructions
- Verifies setup status and completion
- Supports multiple project structures (empty hooks, existing hooks, nested objects, etc.)
- Detects
- Automated
use LiveSvelteGettextinjection- Installer now adds
use LiveSvelteGettextto your Gettext backend module - Properly configured with backend reference and Svelte path
- Idempotent operation (safe to run multiple times)
- Installer now adds
- Improved Elixir component import
- Now adds
import LiveSvelteGettext.Componentsto both:htmland:live_viewfunctions - Ensures
svelte_translations/1is available in LiveView contexts - Idempotent operation
- Now adds
- Lazy initialization for translations (
ensureInit())- Translations automatically initialize from DOM on first use
- Eliminates need for Phoenix hook registration entirely
- Works in all environments with zero configuration
- Added comprehensive test coverage for lazy initialization (6 new tests)
- Supports SSR and all edge cases
Removed
- Phoenix LiveView hook requirement
LiveSvelteGettextInithook no longer needed or exported- Removed hook element from
<.svelte_translations />component - No more hook registration setup step
- Automatic JavaScript modification code (replaced with simplified setup guide)
add_import_to_js/1functionadd_hook_to_livesocket/1functionadd_hook_to_existing_hooks_object/1functionfind_matching_closing_brace/2function- All JavaScript-related test fixtures and tests (12 tests removed, 10 Elixir tests remain)
- Interactive setup wizard functions (replaced with simple informational task)
Architecture
This release represents a significant architectural improvement:
Before v0.1.1:
- Attempted to automatically modify JavaScript using regex patterns
- Fragile across different formatting styles and project structures
- Hard to debug and maintain
- 7 critical bugs in JavaScript parsing logic
After v0.1.1:
- Clean separation: Igniter handles Elixir, setup wizard handles JavaScript
- Users have full visibility into changes being made
- More reliable and easier to maintain
- Follows patterns used by successful libraries like
live_svelte
Migration
If you installed an earlier version of v0.1.1 (released 2025-10-14 morning):
- The JavaScript modifications may have errors - manually verify
assets/js/app.js - Run
mix live_svelte_gettext.setupto get correct setup instructions - Your Elixir-side setup should be correct and requires no changes
For most users, simply run:
mix deps.update live_svelte_gettext
mix live_svelte_gettext.setup
0.1.0 - 2025-10-14
Added
Core compile-time extraction engine (
LiveSvelteGettext.Extractor)- Scans
.sveltefiles forgettext()andngettext()calls - Supports both single and double quotes
- Handles escaped characters properly
- Extracts file and line number references for debugging
- Deduplicates strings across multiple files
- Scans
Compile-time code generation (
LiveSvelteGettext.Compiler)- Generates Elixir
gettext()andngettext()calls for extraction - Creates runtime
all_translations/1function - Sets up
@external_resourcefor automatic recompilation - Provides
__lsg_metadata__/0debug function - Validates configuration options at compile time
- Generates Elixir
NPM package (
live-svelte-gettext)gettext()- Simple translations with interpolationngettext()- Plural form handlinginitTranslations()- Initialize with server data (called automatically)isInitialized()- Check initialization statusresetTranslations()- Reset state (for testing)LiveSvelteGettextInit- Phoenix LiveView hook for auto-initialization- Full TypeScript type safety with
.d.tsdefinitions - Variable interpolation with
%{name}syntax - Count-based pluralization
Phoenix component (
.svelte_translations)- Injects translations as JSON script tag
- Renders invisible div with
phx-hook="LiveSvelteGettextInit" - Auto-initializes translations via Phoenix LiveView hook
- Zero manual setup required in Svelte components
Igniter installer (
mix igniter.install live_svelte_gettext)- Automatic Gettext backend detection
- Automatic Svelte directory detection
- Creates
SvelteStringsmodule with correct configuration - Copies TypeScript library to assets directory
- Provides clear usage instructions
- Supports manual configuration via CLI flags
Comprehensive documentation
- Module documentation with examples
- Function documentation with type specs
- README with quick start guide
- Architecture diagrams
- Troubleshooting section
- Contributing guidelines
Testing infrastructure
- Unit tests for extraction engine
- Unit tests for compiler
- Unit tests for TypeScript library
- Test fixtures for realistic scenarios
- ExCoveralls integration for coverage reporting
Features
- Zero-maintenance workflow - no generated files to commit
- Automatic recompilation when Svelte files change
- Works with existing
mix gettext.extractandmix gettext.mergeworkflows - Full integration with Elixir's Gettext library
- Type-safe TypeScript client
- One-command installation
- Supports variable interpolation in translations
- Supports plural forms
Technical Details
- Elixir 1.18+ required
- Compatible with Gettext 0.24+
- Uses
@external_resourcefor automatic recompilation - Uses macro-generated AST (no runtime overhead)
- Client library has zero dependencies
- Follows Elixir and TypeScript best practices
[Unreleased]
Planned
- Context-aware translations (pgettext) and domains (dgettext)
- Translation extraction from TypeScript/JavaScript files
- Translation coverage reporting