Repository navigation
v2.7.0 — Data-safe writes & fast DB updates
Highlights
Writes no longer destroy what they don't own. JSON locale files and the CSV are shared with keys of other groups, plain sentence keys and columns of other locales. Until now every set / sync / import / export rewrote them with the filtered collection and silently deleted everything outside fileNames / locales (e.g. with --file-names=auth). Both handlers now replace only the managed entries and carry the rest over.
Single-key database writes are constant in query count. Changing one translation against 2000 keys × 2 locales:
| Before | After | |
|---|---|---|
| Queries | ~2000 (one UPDATE per kept key) |
4 |
| Time (test suite, SQLite) | ~21 s | ~0.15 s |
set() scopes reads and writes to the groups and locales present in the input; the DB handler loads keys and values once per group and soft-deletes with a single UPDATE; Translation drops the per-instance Validator; collection merges are linear. A regression test guards the query budget.
Fixed
- Invalid UTF-8 no longer wipes a JSON locale file: the writer throws before touching the file (
JSON_THROW_ON_ERROR). - Writes outside the configured locales / file names are rejected with an explicit error (surfaced by the MCP tools) instead of being dropped silently with
written: 0. keyDelimiterother than.works again: group filters always used the default.separator, soget()returned nothing.- A key used both as a value and as a parent (
auth.a+auth.a.b) is refused up front with a message naming both keys, instead of crashing the nested PHP/JSON writers or overwriting data depending on order. null,int,floatandboolvalues in PHP/JSON lang files andNULLDB values no longer throw a TypeError; the CSV reader skips locales whose column is missing.csvDelimiteris actually validated againstkeyDelimiter(thedifferent:rule was given a value instead of a field name).- Commands (
sync/import/export) restore the shared service options after the run, so a narrowed--file-names/--localesno longer leaks into later calls in long-running processes (Octane, queue workers, Boost MCP server). - PHP 8.4 deprecation on
fgetcsv/fputcsvwithout an explicit$escape.
Changed
- The database handler only manages the configured locales, like the file handlers: values of other locales are never soft-deleted, and a key is only retired when no active value of another locale still depends on it. Previously a key whose only values were in an unconfigured locale was soft-deleted on every write to its group.
- JSON files are written with
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES(èinstead ofè). Existing files are rewritten in the new form on their next change. Translation::__construct()accepts a nullable value, matching its property and validation rule.DatabaseHandler::handleUpdate()/handleSoftDelete()accept an optional pre-loaded$dbValues; new publicgetCurrentValues(). Existing calls keep working.
No configuration changes are required. Verified against brunoscode/twill-translation-handler v2.3.0 (tests and PHPStan green).
Full Changelog: v2.6.1...v2.7.0