A formula was written as a fenced code block, which is what a plain text
file allows and is not what Markdown has for mathematics. A code block is
code: the reader of the source sees a formula presented as code, and the
renderer had been taught to guess which blocks held equations, which is a
guess that is wrong whenever a block holds something else.
Every formula now stands between dollar signs, which is the notation every
Markdown mathematics renderer reads, and the guess is gone from the
renderer. A hundred and four blocks became two hundred and four formulas
in the two languages.
Three things that were in a code block were not formulas and are now what
they are. A paragraph of geometry was prose. A table of the exponent
notation is a table, because its two columns are a written form and what
it means. Two blocks are left as they were: the layer diagram, which is a
diagram, and a sample element set, which has to keep its column alignment.
The renderer learned what the notation needs and did not have: matrix
environments, with an ampersand between the columns of a row and a double
backslash between the rows; the floor and ceiling marks; the modulo
operator; a mark above an argument, as in the time derivative of Omega and
a barred coefficient; the text command, whose argument is words and was
being set one letter at a time; and the spacing commands.
The check on the formulas covered the concept documents and not the
interface documentation, so every formula there was unexamined. It covers
both now, and it treats a command name and an environment name as
notation, which is what they are: neither is drawn as the letters of its
own name.
`apsis-rs` now writes each doc comment in English and then in Chinese, in
the one comment beside the code. The extractor splits the two halves as it
reads them and writes both to the catalogue, so the interface
documentation carries both languages and no translation file is maintained
beside it.
This replaces `content/api.zh.json`, which held the Chinese keyed by item
name. That arrangement was unsound: a name is not unique. `new` is
defined by fifty-nine crates and does not mean the same thing in each, so
a translation filed under the bare name could be shown against the wrong
documentation. Splitting the comment removes the question, because the
translation is attached to the item rather than looked up by a name.
The coverage went from 434 of 1202 items to all of them, and the crate
summaries from 15 of 40 to all of them. A test now asserts that no item in
the committed catalogue is left without Chinese, so a crate that is not
translated fails the build rather than reading as English to a Chinese
reader.
Two defects surfaced while doing this.
The JSON codec decoded one string character by validating the whole
remaining buffer as UTF-8. That is correct and quadratic, and it repeated
for every character of the document: the catalogue took twenty-nine
seconds to parse once it grew, and the service could not start. It now
validates only the sequence at hand, which is six milliseconds.
The module documentation was joined into one line before it was split,
which destroyed both the paragraph structure and the boundary between the
languages, so the English half came out empty and the Chinese half held
the English text.
A translation was filed under the item name alone. The name is not
unique: `new` is used by fifty-nine crates and `kind` by fifteen, and
they do not all mean the same thing by it, so a name-only translation
could be shown against the wrong documentation. A translation is now
looked up by `crate::name` first, then by `Type::name` for two items
of one crate that share a name, and only then by the bare name.
The facade crate sits directly in `crates` and re-exports every layer.
It defines nothing of its own, so listing it repeated every item of the
layers under a second name. The generator skips it and the catalog
carries forty crates.
The first batch of Chinese translations is in, covering the foundation,
time, coordinate, geodesy, frames, Kepler, SGP4 and linear algebra
crates.
The documents write their formulas as plain text in a fenced block,
`delta_v = v_e * ln (m_0 / m_f)`, which was shown as source. They were
written before the dollar form existed. A plain block holding equations
is now read as a formula: identifiers with subscripts and powers, roots,
functions, quotients, a group raised to a power, and a note set beside
the equation. A block that is not an equation, such as a matrix or a
worked example in prose, stays as it was written.
The interface catalog named fifteen crates in the generator, which was
written when only the foundation, physics and orbit crates existed. The
workspace has since grown to forty-one, and every network, radio and
operations crate was missing from the documentation without anything
saying so. The crates now come from the workspace manifest, so a crate
cannot be left out by omission again. The count went from 424 items to
1202, and the index now shows all seven layers.
A crate with no layer is the facade, which re-exports every layer. It is
left without one rather than filed under the foundation, and it is left
out of the crate structure diagram, where it would belong to no layer.
The graph took over three seconds to draw. The force layout ran four
hundred and twenty steps of repulsion between every pair of nodes, which
is quadratic in the node count and was doing that work through a reactive
proxy inside an effect that read the state it wrote, so it rescheduled
itself on every run. The repulsion now runs on a grid over neighbouring
cells, and the effect no longer tracks its own writes.
The physics layer covered two unrelated subjects, so it is presented as
two. Formulas are written between dollar signs and translated to MathML,
which the browser sets itself, so no script has to run. The palette is
now two sets of the same variables with a toggle between them, and below
a thousand pixels the sidebar is a drawer over the page.