Changelog

View Source

All 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/1 returned the raw English msgid/msgid_plural for every locale, so ngettext rendered 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 .po files. This is not avoidable via Gettext's runtime API: lngettext/7 does Map.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 via Intl.PluralRules, so Polish, Russian, Arabic and friends work correctly. Falls back to the English rule when Intl.PluralRules is unavailable.

  • Multi-line comments shifted .pot line 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.24 was advertised, but use Gettext.Backend and the lgettext/5 and lngettext/7 callbacks 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: true needed.

  • translation_payload/1 on 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 to all_translations/1 for modules compiled against 0.1.x.

    The metadata is nested rather than wrapping the translations (%{"locale" => ..., "translations" => ...}) specifically so older clients keep working: they do translations = {...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() and getLocale() 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 .pot reference behaviour - the library's core promise - was previously only tested by hand.

Changed

  • Jason is now optional. On OTP 27+ the built-in :json module is used, matching LiveSvelte 0.17's move away from a hard Jason dependency. Override with config :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.build and mix hex.publish now build the JavaScript bundle and verify that mix.exs and assets/package.json agree on the version. The npm package had drifted to 0.1.1 while Hex was at 0.1.3, and assets/dist is 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

0.1.2 - 2025-10-16

Fixed

  • Fixed compilation error when installed as a dependency

    • Changed igniter from only: :dev to optional: true to 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: :dev option meant Igniter was only available when developing the library itself, not when used as a dependency
    • The optional: true configuration 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
  • Fixed installer crash caused by unnecessary Gettext backend modification step

    • Removed the step that attempted to add use LiveSvelteGettext to Gettext backend
    • This step was causing the Igniter installer to crash on clean installations
    • The use LiveSvelteGettext should 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

Changed

  • Simplified installation process
    • Reduced installation steps from 7 to 6 by removing manual Gettext backend modification
    • Users now have more control over how LiveSvelteGettext is 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.Backend modules, not consumers (Issue #7)
    • Fixed module naming to create proper submodule MyApp.Gettext.SvelteStrings (Issue #4)
    • Fixed missing use LiveSvelteGettext in Gettext backend (previously undiscovered issue)
    • Fixed component import to be added to both :html and :live_view functions (Issue #3)
    • Eliminated all compile warnings about undefined functions (Issue #5)
  • Fixed translation initialization race condition
    • Phoenix hook mounted() callback sometimes doesn't fire before Svelte components call gettext()
    • Implemented lazy initialization - translations now auto-initialize on first use
    • Completely removed Phoenix hook requirement for simpler setup

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.setup wizard
    • 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() or ngettext() 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.js location 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.)
  • Automated use LiveSvelteGettext injection
    • Installer now adds use LiveSvelteGettext to your Gettext backend module
    • Properly configured with backend reference and Svelte path
    • Idempotent operation (safe to run multiple times)
  • Improved Elixir component import
    • Now adds import LiveSvelteGettext.Components to both :html and :live_view functions
    • Ensures svelte_translations/1 is available in LiveView contexts
    • Idempotent operation
  • 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
    • LiveSvelteGettextInit hook 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/1 function
    • add_hook_to_livesocket/1 function
    • add_hook_to_existing_hooks_object/1 function
    • find_matching_closing_brace/2 function
    • 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):

  1. The JavaScript modifications may have errors - manually verify assets/js/app.js
  2. Run mix live_svelte_gettext.setup to get correct setup instructions
  3. 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 .svelte files for gettext() and ngettext() calls
    • Supports both single and double quotes
    • Handles escaped characters properly
    • Extracts file and line number references for debugging
    • Deduplicates strings across multiple files
  • Compile-time code generation (LiveSvelteGettext.Compiler)

    • Generates Elixir gettext() and ngettext() calls for extraction
    • Creates runtime all_translations/1 function
    • Sets up @external_resource for automatic recompilation
    • Provides __lsg_metadata__/0 debug function
    • Validates configuration options at compile time
  • NPM package (live-svelte-gettext)

    • gettext() - Simple translations with interpolation
    • ngettext() - Plural form handling
    • initTranslations() - Initialize with server data (called automatically)
    • isInitialized() - Check initialization status
    • resetTranslations() - Reset state (for testing)
    • LiveSvelteGettextInit - Phoenix LiveView hook for auto-initialization
    • Full TypeScript type safety with .d.ts definitions
    • 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 SvelteStrings module 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.extract and mix gettext.merge workflows
  • 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_resource for 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