"Express" is also TD Snap's page-set name in the same field. The standard's reference app is now called the AAC Reference App: READMEs, crate docs, tool docs and the page-set design notes (which now say it was renamed). Its default title, without AAC_APP_TITLE, and its manifest name are "AAC — reference app". Code identifiers are unchanged. Co-Authored-By: Claude Opus 5.5 <[email protected]>
31 KiB
Phrase page sets: what they share
Four page sets for aac.aurasense.ai/app (the AAC Reference App, built on the open AAC standard) and for any app that reads Open Board Format (OBF):
| Set | File | For | Design |
|---|---|---|---|
| Adult conversation | adult.obz |
adults whose talking has changed: aphasia, ALS/MND, primary progressive aphasia, brain injury, Parkinson's | DESIGN-adult.md |
| Intent first (12, 20, 40) | intent-12.obz, intent-20.obz, intent-40.obz |
anyone who starts from what they want to do; also a printed book a partner reads from | DESIGN-intent.md |
| Themed phrases | themes.obz |
quick everyday messages, one 6 × 3 page per theme | DESIGN-themes.md |
| First switches and messages | emergent.obz |
first communication and first switch use | DESIGN-emergent.md |
This page covers what the four have in common: how they are written and
built, the OBF they produce (and the ext_aurasense_* extensions they use or
propose), how their translations were checked, their licences, how the app
should offer them, and the decisions they need from the founder.
The design follows the gap analysis of 2026-10-04 (REPORT.md on the
model-library drive, Part 1 and §1.1, §2.2, §2.7, §2.10–2.12, §4 items 8, 10,
13, 14 and §5). Every word, layout and name here is ours. No proprietary
page set was copied, and none is named on any board: the generator refuses
a board that names one (see Guards below).
Sources and build
aac-rs/tools/pagesets/phrases/
sources/adult.yaml intent.yaml themes.yaml emergent.yaml the sets, by hand
build.py validate the sources; build the packages and catalogue
review.py the two-reader translation check, round by round
translations/<lang>.json every text's translation, status and evidence
translations/review/<lang>/round<N>/ each round's record (see Languages)
reports/sets.md symbols.md translation-status.md review aids, generated, committed
LICENSE.md CC BY-SA 4.0 for the sources and every package built from them
aac-rs/crates/aac-core/tests/pagesets_phrases.rs the import test
The packages are generated, not committed. The site build makes them:
cd aac-rs/tools/pagesets/phrases
python3 build.py --check # fail on bad sources, a non-reproducible build or stale reports
python3 build.py --out "$SITE/pagesets/phrases" --hash-names
--out DIR writes DIR/<set>.obz (English, with the pictures and every
agreed translation), DIR/<lang>/<set>.obz (one language; <set>.f.obz and
<set>.m.obz where the speaker's gender changes the words), DIR/index.json
(the catalogue: families, sets, sizes, descriptions, licence, each file with
its size, sha256 and how many of its cells are still in English, and each
language's status) and DIR/LICENSE.md. --hash-names names packages
<set>.<sha256-12>.obz for a cache that keeps files for hours.
--check [--out DIR] builds twice in memory and fails if the bytes differ,
if reports/ is stale, or (with --out) if DIR differs from a fresh build.
--reports rewrites reports/; --strings writes work/strings.json for
translators. The interface matches the core page sets' tools/pagesets/build.py
(--check, an output directory, deterministic output), so one catalogue can
list both; this generator's index.json is self-describing (version,
generator) for that.
Today a full build is 99 packages, 28 MB, of which the six English packages (with pictures) are 5 MB and each language package 100–450 KB.
Python 3.11 or later with PyYAML. The build reads only the app's own symbol
index (crates/aac-core/src/symbols/index.json) and sprites
(crates/aac-web/public/symbols/); it never touches the network, and the
same sources always give the same bytes (UUIDv5 ids, a fixed zip date,
sorted output).
The source format
A source file has set (name, description, version, licence, which symbol
sets it may draw from, the root board), a palette of named colours,
cells (named cells used as $name), optional frames (cells placed on
every board of the set), and boards (or, for the intent-first set,
sizes and sections). A board is laid out by rows, each a list of cells
from left to right, so the layout reads as it looks. A cell is:
| Written as | Means |
|---|---|
"I'm tired." |
a message: shown and said |
$yes |
the named cell yes |
~ |
an empty place, kept empty (SPEC §2: a blank keeps the grid) |
{label, say} |
shown label, said say |
{add: "I want to"} |
words added to the message without being said (a sentence starter) |
{label, go: board} |
a link; with say too, the words are added and then the board opens |
{label, do: backspace | clear | speak} |
a message-bar command |
symbol: concept |
the picture: a concept of the app's symbol index (it must exist) |
want_symbol: concept |
a picture we want but the index does not have (listed in reports/symbols.md) |
fill: {words, photo, recording, hint} |
a template for the person to complete |
seq: {lines, order, at_end, reset_after_minutes} |
each press says the next line |
effect: sparkle | bounce | confetti |
a short animation with the words |
src: universal-core |
where the words came from, if not written for this project |
note: |
context for translators (not written into the packages) |
A board may say popup: true (it closes after a choice), speak_only: true
(its cells speak and never build a message), parent: (where Back goes;
otherwise the first board that links to it) and description: (a note to
the partner). YAML 1.1's other booleans are switched off: yes, no, on
and off are words.
Guards
build.py refuses to build when:
- a cell is outside its grid, two cells share a place, or a link leads to a board that does not exist;
- a board cannot be reached from the root;
- a symbol concept is not in the app's index, or not in a set the page set may use (the adult set uses pictograms only: Mulberry, then OpenMoji, no Bliss);
- a sequence has fewer than two lines, names a cell that does not speak, or has an unknown order or ending;
- any text names a proprietary product (
PROPRIETARY_NAMES: PODD, TD Snap, Proloquo, LAMP, Unity, Minspeak, Gateway, WordPower, TouchChat, Lingraphica, Grid 3, BIGmack, Step-by-Step, PECS, Boardmaker, PCS, …); - any text reads as a medical claim (
CLAIM_WORDS: diagnose, treatment, therapy, cure, heal, rehabilitate, recover, clinically, prevents, …). The sets are for wellness, research and clinical-trial use; they are not a medical device.
The OBF the generator writes
Each package is a .obz: a zip, stored without compression (what the app's
own importer reads directly), of manifest.json, boards/<uuid>.obf and,
in the English package, images/<symbol>.svg. Ids are UUIDv5 of the set,
board and position, so a rebuilt board keeps its ids, and every language's
package has the same board and cell ids in the same places (the test checks
this: changing language never moves a word, SPEC §3).
Standard OBF fields: format, id, locale, name, description_html,
license, grid (rows, columns, order), buttons (id, label,
vocalization, label_locale, vocalization_locale, load_board,
action, image_id, background_color, border_color, translations),
images (id, content_type, width, height, path, symbol,
license) and sounds.
Extensions the app already reads or writes
| Field | Where | Meaning |
|---|---|---|
ext_aurasense_provenance |
board, button | where the words came from: source_label / source_vocalization (the stored words), words_locale (the words are in this language, kept exactly as written, never glossed: the app's own-words cell), translation ("agreed by two model readers; native review pending", or "pending: shown and said in English"), english (the English source), source (file, board and position in the sources), symbol_wanted, words_source |
ext_aurasense_locked |
board, button | false: the person may change everything |
ext_aurasense_text_color |
button | the text colour |
ext_aurasense_action: "buffer" |
button | add the words to the message without saying them (sentence starters) |
ext_aurasense_symbol |
button | the picture, as a concept of the symbol index (the app draws it in the person's chosen set and skin tone; Track B reads and writes it) |
images[].symbol + license |
image | the symbol set and file, with the set's licence, attribution and conditions |
Extensions these sets add
A client that does not know them still works: each falls back to plain OBF.
The App column is the state on aac/pagesets-phrases: acts on it
(aac_core::behaviours, aac-web sequences.rs, behaviours.rs,
actions.rs, scan.rs, switches.rs, pointing.rs), or kept (on the
cell or board, written back on export, and named once in the import's
warning: "These boards use features this version can't do yet: … They are
kept.").
| Field | Where | What the app does | Fallback | App |
|---|---|---|---|---|
ext_aurasense_sequence |
button | each press says the next line; full behaviour in DESIGN-emergent.md | vocalization is the first line |
acts on it |
ext_aurasense_effect |
button | a short visual effect with the words (DESIGN-emergent.md) | none | kept ("animations") |
ext_aurasense_behaviour.after_choice: "return" |
board | a popup: after a cell that says or adds words, go back to the board that opened this one | stays; a Back or Start cell is on the page | acts on it |
ext_aurasense_behaviour.message: "speak_only" |
board | its cells speak at once and are never added to the message | words are added too | acts on it |
ext_aurasense_link_says: "I want" |
button with load_board |
add these words to the message as a speaking cell would, then open the board (the words themselves, as well as in vocalization: a reader that makes the button a link keeps no vocalization, but keeps this field) |
the link opens; the words are not added | acts on it |
ext_aurasense_fill_in |
button | {words, photo, recording, hint}: a template cell; Edit mode marks it "to fill in" and lists every such cell after the set is added; the hint is shown in the cell editor; editing the cell drops the mark |
the cell says its words (… is a pause) |
kept ("cells to fill in") |
ext_aurasense_book.page |
board | page number in a printed book | printing numbers pages itself | kept quietly (the app prints books and numbers them itself) |
ext_aurasense_book_goto |
button with load_board |
the page it links to, printed as "→ 12" | none | kept quietly (same) |
ext_aurasense_speaker_forms |
button, in a language's f/m packages | {f: {label, vocalization, lines}, m: {…}} for a word that changes with who says it: the app puts the person's form there, or leaves the word out while they would rather not say |
the package's own form | acts on it |
translations.<lang>.ext_aurasense_speaker_forms |
button | {f: {label, vocalization}, m: {…}} where the speaker's gender changes the words |
that language's words are absent: English | |
translations.<lang>.ext_aurasense_sequence_lines |
button | a sequence's lines in that language | English lines | |
manifest.ext_aurasense_page_set |
manifest | key, name, version, locale, speaker_forms |
none |
The importer defect, fixed. aac_core::obf used to accept every
ext_aurasense_* field silently and keep none it did not know, so a
sequence or popup was lost without a word (SPEC §8 forbids it). It now
keeps every field it does not map — ext_aurasense_* or any other — on
Cell::extra / Board::extra, writes them back on export, and adds one
warning per import naming, in plain words, the features it keeps but does
not act on. A few fields with no meaning for the app (url, data_url,
description, description_html, default_layout, default_locale,
background, and the position fields top, left, width, height)
are kept without a warning. The test checks the warning, and that
sequences, links that say words and board behaviours survive an import.
SPEC text (draft, after 0.2.0)
Approved and now in aac/SPEC.md (§2.2, §2.3, §2.4, §5.9 and the §8
addition, with the summary under "Proposed (draft, after 0.2.0)"):
§2.2 Sequences (proposed). A cell MAY carry a sequence: an ordered list of two or more lines, an order (
in_orderorshuffle), what happens after the last line (start_againorstay), whether the lines are added to the message (default: not), and an optional idle time after which it starts again. Each activation of the cell says the next line. A line MAY name another cell of the same board, whose current words (and recording) it then says. Where the next line is kept is the person's state, not the board's: using a sequence MUST NOT change the board. A client that cannot play a sequence MUST say the cell's own words (its first line) and MUST keep the sequence when it saves the board. Undo after a line MUST step the sequence back. A press during a line MUST be honoured (the person sets the pace); the hold and release times of §5 still apply.§2.3 Board behaviours (proposed). A board MAY declare that it closes after a choice (a popup) or that it speaks without building a message. After a cell of a popup that says or adds words is chosen, a client MUST return to the board that opened it (a popup's continuation pages count as the popup). The person MUST be able to turn popups off for all boards; the choice travels with their settings. This is a property of the vocabulary's design and returns to the board that opened the popup, not home: it is not the "go home after each word" option of §5.6 item 6, which stays the person's alone and, where they have chosen it, wins over a popup's return.
§2.4 Links that say words (proposed). A cell that goes to another board MAY also carry words; a client MUST add them to the message as a speaking cell would, then open the board.
§5.9 One target (proposed). When a scan has a single target — a one-cell board, with the bar and the navigation not scanned (§5.5, §5.6 let the person choose that) — every press of a switch MUST select it at once, and a touch or dwell anywhere on the board MUST select it.
§8 addition (proposed). An extension field a reader does not act on MUST be kept with the board or cell (§2) and reported once as a warning, so that a sequence, popup or other behaviour is never lost without a word.
Symbols
Pictures are chosen by concept from the app's own symbol index (472
concepts on 2026-10-05: Mulberry, OpenMoji, Bliss, all CC BY-SA 4.0), never
by inventing ids. Each set says which sets it may draw from: all four use
Mulberry, then OpenMoji (pictograms); none uses Bliss, which is a semantic
symbol language rather than a picture, and which a person can still choose
in the app (the app draws ext_aurasense_symbol in the person's own set).
Many adult concepts have no symbol yet (throat, chest, suction, frustrated,
appointment, …): those cells show their words alone, and an adult may add a
photo instead. reports/symbols.md lists every concept wanted and where.
Adding them is a job for tools/symbols (a confident match only: a wrong
picture is worse than none), after which the sources name them with
symbol:.
The English packages carry the pictures (each symbol once, as
images/<id>.svg, cut from the app's sprite with its set's attribution);
the language packages name each symbol by concept only, which the app draws
from its own sprites. That keeps each language package small (100–450 KB);
a language package opened in another OBF app shows words without pictures. build.py can embed
pictures in every package if that is wanted (one condition in Package.button).
Languages
English is the source. A translation is used only where two independent readers agree:
- Draft. A drafter (reader 1) translates each text, seeing the English
and where and how it is used (
review.py prepare): what a native speaker would say, short and spoken; polite address in the adult set, familiar in the emergent set; a wording that does not mark the speaker's gender wherever one is natural, and otherwise both forms (f,m) — never slash forms. - Blind back-translation. A second reader, who never sees the English
(
review.py blindwrites only the translations, with each text's role), translates the drafter's words back into English and says how they read: grammar, register, and whose gender they mark. - Judge. The English, the translation and the back-translation are
compared (
review.py judge); "agree" only when the back-translation means what the English means, with nothing added or lost, in natural words. - Merge. Agreed texts become
"agreed"; the rest"disputed", with the reason (review.py merge). A disputed text goes to a second round: the drafter revises it with the reason, and a fresh blind reader checks again. What is still disputed stays in English.
The status of every text in every language is data:
translations/<lang>.json (status, round, text or forms,
back_translation, notes), summarised in
reports/translation-status.md and in each build's index.json. Each
round's record is kept under translations/review/<lang>/round<N>/:
draft-input.json (what the drafter saw), draft.json, blind-input.json
(what the blind reader saw: no English), back.json, verdict.json.
Every reader was an AI model, so every agreed text says
"agreed by two model readers; native review pending", in the
translation files and in the packages' provenance. A native speaker's review
is still wanted for every text.
Result (2026-10-05). 1,075 English texts; three rounds.
| es | fr | de | pt | it | zh | ja | ar | hi | ru | |
|---|---|---|---|---|---|---|---|---|---|---|
| Agreed | 1,075 | 1,075 | 1,075 | 1,075 | 1,075 | 1,075 | 1,074 | 1,074 | 1,075 | 1,075 |
| Disputed in round 1 | 10 | 17 | 9 | 9 | 6 | 15 | 29 | 21 | 11 | 6 |
| Texts with speaker forms | 29 | 20 | 0 | 30 | 24 | 0 | 0 | 0 | 14 | 15 |
Still in English after round 3: Japanese "OK" (a feelings word; every wording offered could be heard as "so-so" or a polite "no thanks") and Arabic "I did that for … years." (one cell of the adult set's work page). What round 1 caught, among others: Spanish "Eso me pone" for the starter "That makes me" (sexual slang in Spain), "Salir" for "Going out" (reads as "Exit"), "Está demasiado alto" for "It's too loud" ("too high"); Hindi कल for both "yesterday" and "tomorrow"; Japanese requests that could be heard as about the listener ("brush/wash my…"); Russian «Мне очень неудобно» for "I'm very uncomfortable" (usually "I'm embarrassed"); Arabic الحمام unvoweled (bathroom or pigeons). The readers also showed three English texts were unclear in every language, and they were changed: "Adult home" (a care home) became "Home"; "My own card" (an ID card) became "In my own words"; three theme starters that no word on their page completed were rewritten.
Two blind readers (Spanish, Arabic) were stopped part-way by the model provider's content filter; Spanish was rerun as it was, Arabic as four readers of one part each. Neither saw the English.
A cell is shown and said in one language: if any of its texts (label,
message, sequence lines) is not agreed, the whole cell stays in English
(an empty translation is allowed only for a link's spoken words that the
language does not need, such as the English "to"; a label is never blank),
marked label_locale: "en" / vocalization_locale: "en", and its board's
description_html carries a visible note, in the board's language: "Some
messages on this board are still in English: their translation has not yet
been agreed by two readers."
Done first: the ten largest app languages (es, fr, de, pt, it, zh, ja, ar,
hi, ru). Pending (English only, listed in index.json): nl, ko, he, ur,
fa, bn, ta, te, ml, mr, kn, gu, pa, th, vi, id, ms, tl, pl, uk, ro, cs, sv,
da, nb, fi, sw, am, ha, yo, zu, tr, el, hu. Adding one: add it to
LANGUAGES in build.py and LANGUAGE_NOTES in review.py, run the
four steps (review.py prepare/blind/judge/merge), and build.
What translation cannot fix. Sentence starters and words are combined in the order the person picks them ("I want" + "to eat" + "an apple"). In languages whose word order differs — Japanese and Hindi put the verb last, German often does — the combined message is telegraphic; each language's drafter shaped the fragments to survive it (DESIGN-intent.md lists how). Phrase cells (whole messages) do not have the problem. Where a language marks a referent's gender in a label ("Friend", "Doctor", "Nurse" on the People templates), the drafters used the usual default and noted it: those are templates the person fills in and may rename.
Licences
- The page sets (words, layouts, packages): CC BY-SA 4.0, author
"AuraSense Tech Corporation and the open-standards AAC contributors"
(
tools/pagesets/phrases/LICENSE.md, copied into every build). ShareAlike because the English packages embed CC BY-SA symbols, and so that improvements stay open. - Symbols: Mulberry Symbols, OpenMoji, CC BY-SA 4.0, each image carrying its set's licence, attribution and conditions (Mulberry's symbols must stay free of charge).
- Words: written for this project unless a cell says
src:. The only borrowed list is the Universal Core vocabulary (21 single words on the 40-cell intent-first start page; CC BY 4.0 per UNC CLDS, CC BY-SA 4.0 per Project Core: treated as BY-SA, words only, no vendor symbols). - Nothing from PCS, SymbolStix, Widgit, METACOM, ARASAAC or Sclera; no proprietary vocabulary's words, positions, wording or names (§5 of the report). The design notes name products only to say what was not copied.
How the app should offer them
What is built on this branch. The app acts on the sets' behaviours:
sequences (by touch, switch scanning with one or two switches, pointer and
gaze dwell; "2 of 4" shown; Undo on the message bar's Delete; Modeling
shows the next line without moving on; the partner menu's "Start the lines
again" and "Back one line"; each line can be recorded in the person's own
voice from the cell editor, through message banking), popups that close
after a choice, speak-only boards, links that say words, one-target pages
(§5.9), a large scan highlight, and the profile setting "Words about
myself" (AacProfile::speaker_form; Settings → Language, shown for es, fr,
pt, it, hi and ru only, never assumed). The place in each sequence is the
person's (localStorage aac_sequence_places, per profile), never in the
board. The English cells of a phrase package — the English package taken
for a language without its own, and the cells still in English inside a
language's package — are marked as English words written as they are
(lang "en", pagesets::prepare): shown in English, marked, said by an
English voice, never glossed word by word and never hidden. "Words about
myself" can be declined ("I'd rather not say"): each word that changes with
who says it is then left out, hidden in place and marked in Edit mode
"Write this your way", until a form is chosen in Settings, when those words
appear in it. A board's description (its note to the people around the
person: what it is for, that nothing is sent, that it does not replace
alarms or monitoring) is shown as a line above the board. Pictures: when a person exports boards for another app, the export
already embeds each cell's symbol as a data: URI from the chosen set's
sprite (Cell::symbol → symbols::symbol_for_cell →
ObfExportOptions::sprites), so nothing more was needed there.
In the shared chooser. The sets are offered by the core page-set
catalogue and chooser (tools/pagesets/catalog.py, aac_core::pagesets,
aac-web pagesets.rs and catalogue_sets.rs), beside Growing Core and
Fixed Paths, at setup ("Words to start with") and in Settings → Words and
boards. There is no second chooser.
- The generator.
build.py --out DIRwrites, beside the packages,DIR/families.jsonin the catalogue's generator contract: four families (phrases-adult,phrases-intent,phrases-themes,phrases-emergent,chooser: "phrases"), one package per set, language and speaker form (99), each withlang,gender("f"/"m"/ null),size("12","20","40"for intent first, else""),rows,cols,home,label,description,boards,cellsandcells_in_english;languages[code]isGlossOnlywith the share agreed (a translation of English phrases is a gloss, SPEC §4.1, however good).tools/pagesets/generators.jsonlists it, anddata/pagesets/index.json(the catalogue compiled into the app) lists all six families, 118 packages;catalog.py --checkfails a build whose packages differ. The site's build puts the packages in/app/models/pagesets/. - By language and speaker form. The chooser takes the package with
Family::for_person(size, variant, locale, speaker_form): the person's language (exact tag, then base), in their form where that language's packages differ by it, else the English one. Where a set's words in the person's language change with who says them (Family:: speaker_form_matters) andAacProfile::speaker_formis not set, setup shows "Words about myself" with the set and will not start until it is answered; Settings asks it when Add is pressed and adds the set once it is answered. Never assumed; the answer is kept on the profile and can be changed in Settings → Language, which shows the question only for a language where some set's words differ (phrase_sets:: speaker_form_matters, from the catalogue). - How far the language goes. Each family says what it is, its
sources and licence, and, for a language other than English, its
language_noteand, for the chosen size, "All of it is in Spanish." or "1 of its 366 cells is still in English, and says so." from the package'scells_in_english; a language with no package of its own gets the note alone (in English for now). - Adding.
pagesets::add/start_with→prepare→obf::import_obz,give_new_ids,editing::add_boards_as_page_set; the import's warning is shown with the result (each package keeps, and names, page numbers for a printed book; all but Themed phrases, cells to fill in; First switches, animations). Each board keeps its licence (CC BY-SA), so re-sharing keeps the attribution. - After adding. If the set has
ext_aurasense_fill_incells (adult: names, photos, scripts, own voice; emergent: own message, news, photo choices), open Edit mode's list of them: "Fill in your details". For the adult set, offer later "Make Simple page my home" (the staged plan in DESIGN-adult.md). - Setup. The setup wizard can offer the matching set by the path the person picks: an adult whose talking has changed → Adult conversation; a first switch user → First switches and messages; someone starting out → Intent first (12); a reader who wants quick phrases → Themed phrases.
- Behaviours. Built (see above), except fill-in badges and effects,
which are kept and named in the import's warning. In a client without
them the sets still work: sequences say their first line, popups stay
open (every page has Back or Start), speak-only boards also add to the
message, links that carry words only open the page. Track A's
per-person setting "After a word on another board, go back to Home"
(
AccessPrefs::return_home) wins over a popup's return to its opener; the person can also keep popups open (AccessPrefs::popups_close, Access settings → Going back).
Tests
crates/aac-core/tests/pagesets_phrases.rs runs build.py --out into
Cargo's per-test temporary directory (it needs Python 3.11+ with PyYAML;
AAC_PYTHON names the interpreter), then checks every package in the
catalogue, English and every language and speaker form:
- the catalogue lists all six sets in English and ten languages, its files match the directory, and its sizes are the files';
- every package validates with the independent
open_board_formatcrate (no errors), and imports with the app's ownobf::import_obzwith no warnings, every board present and the root first; - every cell sits inside its grid, one per place; every link lands on a board of the package; every board is reachable from the root;
- every
ext_aurasense_symbolis a concept of the app's symbol index; every picture names a symbol its set has, is in the package, and carries its CC BY-SA licence; - every language's package has the same boards with the same cell ids in the same places as the English one;
- every cell of a language package is either wholly in that language (and says it was agreed by two readers) or marked as English, and a board with English left on it says so;
- imported with the app's importer, a translated cell is the person's own
words in that language (
Cell::lang), an English cell is an English key, and every chosen symbol is kept (Cell::symbol); - sequences have two lines or more, valid order and ending, lines that name cells of the same board, and say their first line to a client without the extension; board behaviours are only the two defined;
- in the intent-first sets, each operational command (Oops, I'm finished, Back to the start, Go back, Turn the page) is in one place on every page.
build.py --check adds: the sources are valid (every guard above), two
builds are byte-identical, and reports/ is current.
Decisions for the founder
- Speaker gender. Decided: "Words about myself: feminine / masculine", shown only for es, fr, pt, it, hi, ru, asked when a set in one of them is added, no default, changeable in Settings. Built.
- Address. Adult set: polite address (usted, vous, Sie, Lei, Вы, です/ます); emergent set: familiar; intent and themes: familiar with family and helpers. An informal adult variant (to family) would double the adult set's translations; not proposed now.
- Pictures in language packages. Decided: language packages name symbols; the app embeds the pictures when a person exports boards for another app (it already does).
- The importer defect. Decided and fixed (above).
- The SPEC text. Approved as draft text after 0.2.0; in SPEC.md.
- Native review. Every translation is model-read only. Which languages get native reviewers first (the AAC site's largest audiences), and who.
- Name collision. Decided. TD Snap has an "Express" page set, and the app was previously called Express too; it is now the AAC Reference App. Our page set is called "Themed phrases", and nothing here uses the word.