translationKeys method
Every distinct text style on screen, most-used first.
An aggregate, because "what is the type ramp" is a table and not a list of nodes. Asking it as a search returned 63 hits, cost 2451 tokens and was still truncated; this is the whole answer in about 185 — which makes it the cheapest question in the drill-down and the one that settles most design arguments (two greys that should be one, a ramp with 11.5 and 12.5 in it).
Buckets on InspectNode.textStyle, and that is a correction. It used
to read InspectNode.properties, which for a Text is the style its
author wrote — so every text that took its size and colour from the theme
had neither key and fell out of the ramp entirely. In a themed app that is
most of the screen, and the answer was a table of the exceptions
presented as a table of the whole. A ramp that cannot see the body text
cannot settle "are these two greys the same grey", which is the question
it exists for.
The fallback to properties is for stored readings, not for live ones:
scenario artifacts and comparison caches written before the resolved
Every translation key on this screen, with where it is.
Flattened out of the tree so a reader — the export, the panel — does not have to walk 120KB of nodes to answer "which keys are here". The node id and box ride along, because the next question is always where to crop.
A key appearing twice on a screen appears twice here: two occurrences are two places to photograph, and collapsing them would throw away the choice between them.
Implementation
List<TranslationOccurrence> translationKeys() {
var found = <TranslationOccurrence>[];
void visit(InspectNode node) {
for (var key in node.keys) {
found.add(
TranslationOccurrence(
key: key,
node: node.id,
layout: node.layout,
offstage: node.offstage,
overflowed: node.textOverflowed,
),
);
}
for (var child in node.children) {
visit(child);
}
}
if (root case var root?) visit(root);
return found;
}