* Add note about requesting a room with tables
The course is built on the idea of using live-coding as much as possible. This means that it's important that there are desks in the classrooms — a traditional auditorium setup does not work well.
* Integrate GA4 code directly with `book.js`
The main advantage of this is that it simplifies the setup since we
can avoid the monkey-patching we did before.
A secondary advantage is that it should make things a little faster
since we avoid a request to the server on every page load.
* Remove unreachable return
* Watch all of `third_party`
It just occurred to me that we want to refresh the page in `mdbook serve` when anything changes in `third_party`.
We often see timeouts when running the course. Most of the time, the
code compiles on the second try, which indicates that we just need to
wait a little longer.
Fixes#406.
The slide is way too large to comfortable use in a classroom. Instead
of printing six lines of output, the instructor should carefully walk
through the different examples. That way we can take the course
participants with us through the explanations instead of simply
showing them the end result.
* Further simplify `Box` diagrams
I think we can improve the drawing by simplifying them and making them
more symbolic. Followup to #374.
* Apply suggestions from code review
The picker is a drop-down menu using the same design as the theme
picker in the top-left.
There doesn’t seem to be an easy way to pass in a list of languages
and descriptions, so for now we’ll have to expand the menu by hand as
we add new languages. A comment has been added to `publish.yml` to
remind us of this.
This makes `mdbook` output a simple redirect at the location of the
old pages. I’ll try to add such pages when we shuffle around our
pages to make sure external links stay valid.
The code is probably meant to illustrate the `vec!` macro, but it
feels out of place when teaching: there is already enough material
here to get through.
This changes the build workflow to first list all available `.po`
files, and then use this information to start parallel jobs which test
each translation.
When the source text is updated, existing translations become
outdated. The `msgmerge` program will attempt to find a similar source
text among the existing translations and will reuse the translation.
The translation is marked “fuzzy” to signal to the translator that it
needs to be proofread.
This replaces a bit of code with the equivalent HTML code.
We also load the script async, which means that the browser won’t
block rendering while waiting for the scripts.
This will allow us to customize the appearance more easily: we can
move the GA logic into the theme (to reduce load times and to simplify
the JS injection logic). We can also add new elements, which is what I
will do next.
The mdbook theme can be added incrementally: if we don’t add a file to
our theme folder, we will get the corresponding file from mdbook.
This publishes translations (currently only the Danish translation) to
subdirectories named after the ISO 639-1 language code: “da/” for
Danish, “ko/” for Korean, etc.
The list of translation is an explicit list to make it easy for us to
enable/disable translations without being tied to the files in po/.
This allows us to experiment with a translation without publishing it
immediately.
I propose that we eventually move the English pages to an “en/”
directory for symmetry with the other locales. However, for now, the
pages remain at the room of our site (which works fine since we don’t
have a subdirectory named “en/” in the course).
This fixes the 404 page on GitHub Pages: the default is `/`, but we’re
hosting the site from a subdirectory because of how the repository is
setup.
Fixes#178.
* Extract common build steps to composite actions
This allows us to repeat ourselves less across the different jobs.
I also tested using a “reusable workflow” to factor out the common
steps. However, this starts a separate job without a shared
filesystem, which in turn requires us to upload/download artifacts
when we want to use them in several jobs. The artifacts are downloaded
one-by-one and this adds delays and extra steps to all jobs.
* Move Rust cache setup to its own build step
This made it easy to consistently setup the caching of our nested
projects via the “workspacs” config key.
This implements a translation pipeline using the industry-standard
Gettext[1] system.
I picked Gettext for the reasons described in [2] and [3]:
* It’s widely used in open source software. This means that there are
graphical editors which will help you in editing the `.po` files. An
example is Poedit[4], which is available for all major platforms.
There are also many online systems for doing translations. An
example is Pontoon[5], which is used for the Rust website itself. We
can consider setting up such an instance ourselves.
* It is a light-weight yet structured format. This means that nothing
changes with regards to how you update the original English text. We
can still accept fixes and PRs like normal.
The structure means that translators can see exactly which part of
the course they need to update after a change. This is completely
lost if you simply copy over the original text and translate it
in-place in the Markdown files.
The code here only adds support for translations. They are not yet
tested, published or used for anything. Next steps will be:
* Add support for switching languages via a bit of JavaScript on each
page.
* Update the speaker notes feature to support translations (right now
“Speaker Notes” is hard-coded into the generated HTML). I think we
should turn it into a mdbook preprocessor instead.
* Add testing: We should test that the `.po` files are well-formed. We
should also run `mdbook test` on each language since the
translations can alter the embedded code.
Fixes#115.
[1]: https://www.gnu.org/software/gettext/manual/html_node/index.html
[2]: https://github.com/rust-lang/mdBook/pull/1864
[3]:
https://github.com/rust-lang/mdBook/issues/5#issuecomment-1144887806
[4]: https://poedit.net/
[5]: https://pontoon.rust-lang.org/
Before, we attempted to change state from “popup” to “inline-open”
when the speaker note window was closed.
We did this by listening to “pagehide” and change the state there. The
event fires every time you navigate away from the page, so we had a
complex setup where we would reset the state to “popup” when the next
page was loaded into the speaker note window.
The problem with this is that it’s racy: we could end up in a
situation where we set the state to “inline-open” right after the
speaker note window was updated. When that happened, we would mark the
window as “defunct”, meaning that it was supposed to be closed.
With this change, we no longer try to change the state from the
speaker note window. If the window is lost (closed), the user will
have to click the “Close speaker notes” button in the top-right to
reset the state. This should be much more reliable.
Long-term, a better solution would be to let the speaker notes fetch
the current URL using JavaScript instead of doing it via an actual
page navigation. That should allow us to react to “pagehide” events
again (since they won’t fire on every page transition).
I think we need a chapter “before the course” which gives people some
background information about how to run the course. This is the start
of this chapter, we might expand it in the future as we find more
things to communicate here.
The `/print.html` page is concatenates all pages in the book and can
be reached from the printer icon in the top-right corner.
On this page, we will have many speaker notes. Since the page is for
people who want all information in one place, I think it makes sense
to render all these notes in their expanded form.
I wrote the logic for this as a separate little function since it has
to be different: we don’t want to add an `id` attribute to the
generated headers (since there will be more than one of them) and we
don’t want to generate links to open the notes into a separate window.
This uses the same media query as the rest of the mdbook theme:
devices with a width less than 1080px (mobiles) will not see the link
to open speaker notes in a new window.
This implements a system for speaker notes via `details` elements and
some JavaScript. The general idea is
1. You add speaker notes to each page by wrapping some Markdown code
in `<details> … </details>`. This is a standard HTML element for,
well extra details. Browsers will render the element with a toggle
control for showing/hiding the content.
2. We inject JavaScript on every page which finds these speaker note
elements. They’re styled slightly and we keep their open/closed
state in a browser local storage. This ensures that you can keep
them open/closed across page loads.
3. We add a link to the speaker notes which will open in a new tab.
The URL is amended with `#speaker-notes-open`, which we detect in
the new tab: we hide the other content in this case.
Simultaneously, we hide the speaker notes in the original window.
4. When navigating to a new page, we signal this to the other window.
We then navigate to the same page. The logic above kicks in and
hides the right part of the content. This lets the users page
through the course using either the regular window or the speaker
notes — the result is the same and both windows stay in sync.
Tested in both Chrome and Firefox. When using a popup speaker note
window, the content loads more smoothly in Chrome, but it still works
fine in Firefox.
Fixes#53.
This removes a bunch of boiler-plate comments which were left from the
template I used originally.
It also simplifies the name to just “Publish” since I feel this fits
better for what we do here.