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.
[1.0.0] - 2026-07-31
Renamed from localize_ecto to localize_sql — the package is about SQL databases (collations, serialization, migrations), not Ecto in general, which can be used without a database. The Localize.Ecto.* module namespace and the mix localize.ecto.audit task are unchanged; the app, config key (:localize_sql), env var (LOCALIZE_SQL_SQLITE_ICU) and priv/localize_sql/ path are renamed.
localize_sql grows from locale-aware collation into the SQL home for every Localize type — serializing the full set of Localize and Elixir data types and generating the tagged-decimal aggregate machinery ex_money_sql builds on.
Added
Localize.Ecto.TaggedDecimaland itsDDLgenerate a PostgreSQL composite type with tag-guardedsum/avg/min/maxaggregates and+/-operators for any tag-plus-decimal value; a mismatched tag (euros plus yen) raises in the database.ex_money_sqlnow buildsmoney_with_currencyon this rather than its own SQL.Unit serialization, folded in from
localize_units_sql:Localize.Unit.Ecto.{Composite,Map}.Typeand theLocalize.UnitWithUsagevariants,Localize.Unit.DDL(nowsum/min/max/avgforcldr_unitandcldr_unit_with_usage), andmix localize.unit.gen.migration.Ecto types for the remaining data types:
Localize.Currency.Ecto.Type,Localize.LanguageTag.Ecto.Type,Localize.Territory.Ecto.TypeandLocalize.Script.Ecto.Type(text);Localize.Ecto.Type.IntegerRangeand.DateRange(int8range/daterange);Localize.Duration.Ecto.TypeandLocalize.Ecto.Type.Duration(interval).Localize.Ecto.Rangeprovides query macros for PostgreSQL range columns — containment, overlap, adjacency, the bound accessors and the range aggregates — andLocalize.Ecto.Range.Migrationcreates a time range type, thebtree_gistextension and theno_overlap/3exclusion constraint that forbids overlapping bookings.Localize.Ecto.Migration.Generatorrenders and writes migrations for the SQL-generating mix tasks.
Fixed
Localize.UnitWithUsage.Ecto.Composite.Type.cast/1now accepts a string-keyed map with no"usage"key, casting it as a unit without a usage. Only the atom-keyed form tolerated the key's absence, so an HTML form — which submits string keys — could not cast a unit unless it also submitted a usage.
Changed
Requires
localize ~> 1.0.postgrexis an optional dependency; the range, duration and tagged-decimal composite types compile only when it is present, so a SQLite-only or collation-only consumer carries nothing extra.The
localize_units_sqlpackage is superseded — its unit serialization is folded in here, and itssum-only aggregates are replaced bysum,min,maxandavgfor bothcldr_unitandcldr_unit_with_usage.
[1.0.0-rc.0] - 2026-07-28
The 1.0 release candidate. localize_ecto now supports SQLite as well as PostgreSQL, with the same locale resolving to the same collation on both.
Added
SQLite support via
localize_icu, a bundled SQLite loadable extension that registers ICU collations under the same names PostgreSQL uses. The same locale sorts identically on both databases.Localize.Ecto.SQLite3providescollate/1,2,lower/1,2,upper/1,2andinitcap/1,2for SQLite. BCP 47 tailorings such as-u-co-phonebkneed no migration; collations are registered on demand.Localize.Ecto.SQLite3.Extensionlocates the compiled extension for the:load_extensionsoption of Exqlite andEcto.Adapters.SQLite3.Localize.Ecto.Postgresnames the PostgreSQL macros explicitly, alongside the new SQLite module.
Notes
- SQLite compares canonically equivalent strings (the NFC and NFD forms of
café) as equal where PostgreSQL, using deterministic collations, compares them as unequal. Ordering agrees on both; normalizing on write removes the difference.
Changed
The SQLite extension is an opt-in build (
config :localize_ecto, :sqlite_icu, true, orLOCALIZE_ECTO_SQLITE_ICU=true). Without it the package stays pure Elixir and PostgreSQL users are unaffected.Query macros emit Ecto's
identifier/1rather than the deprecatedliteral/1. The generated SQL is unchanged.
[0.3.0] - 2026-07-23
Added
Collation resolution carries all collation-affecting BCP 47
-u-keywords (kn,ks,kc,kf,ka,kb,kr,kv) into the collation name, socollate(f.name, "en-u-kn-true")finds a natural-sort collation created in a migration.create_collation/2accepts tailoring options (:strength,:numeric,:case_level,:case_first,:alternate,:backwards) using theLocalize.Collation.Optionsvocabulary. Primary and secondary strengths default to a nondeterministic collation, enabling case/accent-insensitive equality and unique indexes.mix localize.ecto.auditandLocalize.Ecto.Auditreport collation version drift with per-index remediation SQL, database default collation drift, server-versus-application Unicode/ICU/CLDR versions, and time zone inventory differences.Localize.Ecto.Type.TimeZoneis an Ecto type for IANA time zone identifiers, canonicalizing aliases and BCP 47 short zone ids against the CLDR inventory;at_time_zone/2applies a validatedAT TIME ZONE.Localize.Ecto.TextSearch.config_for/2resolves a locale to the best PostgreSQL text search configuration, andts_match/2,3builds a locale-awareto_tsvector … @@ websearch_to_tsquerymatch.lower/1,2,upper/1,2andinitcap/1,2apply locale-aware case mapping via the locale's collation ("INDIGO" lowercases to "ındıgo" under"tr").
Changed
- Requires Localize
~> 1.0-rc.1for the CLDR time zone inventory.
[0.2.0] - 2026-07-23
Changes
- Requires Localize
~> 1.0-rc
[0.1.0] - 2026-07-17
Initial release.
Highlights
Localize.Ecto.collate/1,2query macros applying PostgreSQL ICUCOLLATEclauses to query expressions and comparisons, resolved from a locale or the currentLocalizelocale.Locale-to-collation resolution via CLDR language matching, including BCP 47
-u-co-collation types and direct collation names.Localize.Ecto.Migration.create_collation/2anddrop_collation/2for creating ICU collations reversibly in migrations, andcollated/2for building collated indexes withEcto.Migration.index/3.
See the README for full documentation.