hammer-editor/docs
Adam Brown 1b312bc3b2
Allow a project to set the language it's written in (#838)
* Add per-project language setting (#754)

An optional BCP-47 language on ProjectData, picked from a searchable
list of all platform locales in project settings. New projects default
to the device locale; the Alice example project is en-US.

Spell check is gated per project: when the project language does not
leniently match the dictionary locale, the dictionary is withheld
(ProjectSpellCheckRepository) and project settings explain why.

The public story page emits <html lang> and JSON-LD inLanguage from the
declared language, and EPUB export prefers it over the device locale.
The hasher contributes zero bytes when unset so existing sync hashes
stay stable.

* Fix review findings in the project-language feature

createProject now only seeds the default language for genuinely new
projects (seedDefaultLanguage), so account sync materializes server
projects with the never-synced baseline intact, and the seed is
language-only so it cannot gate spell check against a same-language
dictionary. The hasher's language block gets a -1 marker plus length
prefix so it can never collide with a tags block, and the initial
write goes through the shared saveStoredProjectData path.

The Locale type now retains the script subtag, keeping zh-Hans/zh-Hant
style locales distinct in the picker. The picker's clear row is pinned
above the list so it survives an empty search, watchSpellCheckAllowed
delivers on the main dispatcher, and the public story page hashes the
stored project-data hash into its validator instead of parsing the
blob per request, applying the language override after withDefaults so
chrome links keep the viewer's locale.

* Enforce single-owner persisted formats

The tags write in PromoteIdeaUseCase rewrote project_data.toml from
scratch, erasing the language seed createProject had just written: the
exact hazard of a second inline writer. It now read-modify-writes
through the datasource's scope-less helpers, and ProjectsListComponent's
hand-rolled reader delegates to a new blocking readStoredProjectData.

The rule is written down (ARCHITECTURE.md hard constraint 7, CLAUDE.md)
and enforced by PersistedFormatOwnershipTest, which fails the build when
raw TOML I/O appears outside a Datasource file. Migrators are exempt by
role; the two remaining legacy offenders are allowlisted as a burn-down
that can only shrink.

* Burn down the last raw TOML I/O outside datasources

ProjectStatisticsCacheReader now delegates to a scope-less
readProjectStatistics helper in StatisticsDatasource, and the example
project's fabricated activity log goes through writeDeviceLog in
WritingActivityDatasource, which also becomes the single owner of the
.activity path convention.

With no offenders left, PersistedFormatOwnershipTest drops its
burn-down allowlist entirely: only Datasource files and migrators may
touch persisted TOML formats from here on.

* Pass seedDefaultLanguage in the Android instrumented-test harness

* Pass seedDefaultLanguage in the round-trip sync HeadlessClient
2026-08-03 22:22:00 -07:00
..
ARCHITECTURE.md Allow a project to set the language it's written in (#838) 2026-08-03 22:22:00 -07:00
ASSET-GENERATION.md Add manifest-driven asset generation pipeline 2026-05-22 19:26:49 -07:00
DESIGN-PATTERNS.md Rename file to match pattern 2026-06-23 00:09:49 -07:00
HOW-TO-RELEASE.md Add "Server only" publish scope to prepareForRelease 2026-06-23 00:38:08 -07:00
HOW-TO-RUN-A-SERVER-DOCKER.md Tell self-hosters when the server is not serving HTTPS (#800) 2026-07-30 22:16:41 -07:00
HOW-TO-RUN-A-SERVER.md Self-service account deletion (#815) 2026-08-01 02:59:30 -07:00
ROADMAP.md Update ROADMAP.md to reflect completed tasks 2026-06-16 01:22:00 -07:00
SERVER-SECRET-STORAGE.md Update SERVER-SECRET-STORAGE.md for clarity on upgrades 2026-06-23 16:44:06 -07:00
SYNCING-PROTOCOL.md Story Ideas: account-level idea capture with sync (#720) 2026-07-05 01:49:04 -07:00
WEB-DESIGN-SYSTEM.md Show error toasts on htmx error responses (#818) 2026-08-01 15:43:48 -07:00