Writing a post in another language

Writing — part 2 of 7

Only on a site that publishes more than one -- site.locales in Getting started is what says so.

./blog.sh translate my-post --lang de

Or from the wizard, which is where the rest of the work happens: pick the post, and the crossroads that offers its text and its properties offers the languages too. With one other language it names it ([l] language: Deutsch); with several it opens a picker that says what is already written, what is only started, and what has nothing yet -- the same three states check --languages prints. The properties screen carries a languages row for the same reason. (As data the two say them in different words: props --json has written, started and none, check --languages --json has written, title_only and missing.)

The editor that opens holds a title and a body, and nothing else. That is the whole of what a translation may carry: the date, the tags, the series, the pin and the state belong to the POST and are true in every language at once, so they are changed with props or edit and never here. A translation cannot quietly disagree with the post it belongs to.

Save it and ./blog.sh rebuild builds every language the site publishes: the language in site.lang at the site root, the others under /de/, all in one tree with one copy of /assets/ between them.

The header also holds the address that language serves the post at. Left alone it is made from the translated title, once, and then stays put -- see Localization.

The post's own words come along as // lines the first time, so the text being translated is in front of you rather than in another window. The editor drops every // line on save, which is also why a translation left half-done cannot save the original as though it were this language's.

What a translation's text does not say is kept, as it is for the post's own: a block the new text left alone is saved as it was stored, with a paragraph's kind or a video's player still on it, and a block the text rewrote keeps them too. What the text cannot carry at all -- a link card, a player with no address to write -- is asked about before it goes; from a file it is refused (content_lost), and translate --json marks such a translation editable: false beforehand.

Publishing a post the site cannot show in every language it publishes is a decision, not an accident: the command line refuses it and names --allow-partial, and the wizard asks -- write the missing language now, or publish it as it stands. A site that has made that decision for every post says publishing.allow_partial: true in config/site.yml, and is neither refused nor asked (Localization).

Taking a language off a post is emptying the title and deleting the body. The post then looks exactly as it did before the translation existed -- which matters, because a half-empty translation would otherwise give that language a page with the wrong words on it. Two things of it are kept: the text as it was, as a version [v] restores, and the old addresses that text was owed, which go to the post's own list.

An address that belonged to a translation is kept with it. When two posts that were the same piece in two languages are made one -- the English post becomes the Czech post's translations.en -- the English post's address is still out on the web. Put into the post's own former_slugs it would lead to the post, which at the site's root is the Czech page. Written into the translation instead, it leads to the translated one:

"translations": { "en": { "title": "…", "slug": "the-old-slug", "content": [ … ],
                          "former_slugs": ["2019/the-old-slug"] } }

/posts/2019/the-old-slug/ then redirects to /en/posts/2019/the-old-slug/.

The merge has two more steps, and check between them speaks of neither. The English post is still in the archive, at the very address the list now names -- so check says the address is taken by a live post and offers to drop the entry or rename that post. Neither: the English post is what goes, ./blog.sh delete the-old-slug, and the entry is served from then on. Before it goes, copy any picture only it had into the media folder of the post that stays (media.nosync/<year>/<slug>/), under a name the translation's blocks then use: delete takes a post's media to the trash with it, and a translation shows files from the folder of the post it belongs to. Deleting a published post also takes its announcement down where the network allows it, as any delete does. The same list covers a translation whose slug: is changed -- in the header translate opens, or in a text an app sends -- on a post that is out: the address its page stood at is written into the list by that save, as a post's own old address is when it is renamed, and redirects to the new one in that language's tree. (A translated page has no year in its address and the list has no way to say one; there the old address is yours to keep, with redirect_from.) For the merge the list is written by hand, and nothing drops it: translate and an edit from an app carry it across, and taking the language off the post hands the list to the post itself, where each address then leads to the post.

Such an address is answered in two places and no others -- the site's root and that language's tree -- and only while the language is published: take the language out of site.locales and its old addresses answer nothing, which check says of each entry. check asks each tree about its own pages, as the build does. An old address another post's page stands at in one of them is reported with where it is taken and where it is still served; and one written into the lists of two languages leads, at the root, to the text of the language the file names first -- check names that too.

A post you have not translated is not hidden. It stays in the other language's listing and the link on it goes to the address the post really has, so the same words never stand at two addresses. The language switcher still offers every language; one with nothing of this post in it leads to that language's front page rather than to a 404. What is promised to a search engine (hreflang) is narrower on purpose: only the addresses that exist.

Pictures belong to the post, not to one of its languages, so they are added with edit and referred to from a translation. translate refuses an attachment rather than putting a file in one language's copy of a post whose media the other languages share.