Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,41 @@ jobs:
exit 1
fi

# Every page the sidebar names gets a navigation row, and the two ends of the sequence get
# one link rather than two. The order lives in MediaWiki:Sidebar and Module:Sequence reads
# it (#455); before that it was restated in each call, and what went wrong twice was
# exactly this -- a page in the sidebar with no row, and the last page with none either.
missing=
while IFS= read -r page; do
file="dist/$(printf '%s' "$page" | tr ' ' '_').html"
# The link div, not the wrapper: prevnext always emits the wrapper, so matching that
# passes an empty row -- which is exactly what a broken module produces, and what the
# first draft of this check waved through.
if [ ! -s "$file" ] || ! grep -q 'class="wikven-prevnext-' "$file"; then
missing="$missing $page"
fi
done < <(sed -n 's@^\*\* *Special:MyLanguage/\([^|]*\).*@\1@p' 'docs/MediaWiki:Sidebar.wikitext')
if [ -n "$missing" ]; then
echo "::error::sidebar pages with no navigation row:$missing"
exit 1
fi

# The two ends of the sequence get one link rather than two, which the old shape could not
# spell: a lone argument was the next step, so the last page had no way to say it had none.
#
# Matched on the div rather than the class name. TemplateStyles inlines prevnext/styles.css
# into every page that has a row, so both class names appear in the page's own stylesheet
# whether or not either link was rendered -- which is what the first draft of this check
# tripped over.
if grep -q 'class="wikven-prevnext-prev"' dist/Why_wikitext.html; then
echo "::error::Why wikitext heads the sequence and should have no previous link"
exit 1
fi
if grep -q 'class="wikven-prevnext-next"' dist/Licenses.html; then
echo "::error::Licenses ends the sequence and should have no next link"
exit 1
fi

# A prevnext link is labelled with the target page's own title, so on a translated page it
# must carry the translated one. The label is not in the calling page's source: the call
# sits outside the translate tags and passes a page name, and the template reads the
Expand Down
2 changes: 1 addition & 1 deletion docs/Commands.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,4 @@ Runs <code>translate check</code> over a source tree and reports each finding as
|}
</translate>

{{prevnext|Standalone binary|Development}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Configuration.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,4 @@ docker run --rm --entrypoint cat ghcr.io/chaotic-ground/wikven extensions/Wikven
It is also in the [https://github.com/chaotic-ground/wikven/blob/main/default.yml repository].
</translate>

{{prevnext|Troubleshooting|Standalone binary}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Deploying.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,4 @@ A <code>commit</code> that follows a branch is the same manifest with the source
This site is the working example. Its manifests are in [<tvar name="1">https://github.com/chaotic-ground/wikven/tree/main/updatecli/updatecli.d</tvar> <code>updatecli/updatecli.d/</code>] (one release tag per <code>reference</code> pin, one branch head per <code>commit</code> pin), and [<tvar name="2">https://github.com/chaotic-ground/wikven/blob/main/.github/workflows/updatecli.yml</tvar> a weekly workflow] applies them, opening one pull request per pipeline. [<tvar name="3">https://www.updatecli.io/docs/</tvar> Upstream's own documentation] covers everything a manifest can do beyond the two shapes above.
</translate>

{{prevnext|Translating|Troubleshooting}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Development.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,4 @@ The e2e run serves <code>dist/</code> under a <code>/wikven/</code> path prefix,
Versions follow [https://www.conventionalcommits.org/ Conventional Commits], which release-please uses to generate the changelog and bump the version.
</translate>

{{prevnext|Commands|Writing an extension}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Editing sidebar.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ Some default sidebar blocks need a live wiki, so {{SITENAME}} drops them from th
* [<tvar name="1">https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Interface/Sidebar</tvar> Manual:Interface/Sidebar]
</translate>

{{prevnext|Pages|Images}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Extensions.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,4 @@ Scribunto is one of those, and the one most wikis reach for: it has a page of it
An extension of your own can also be made to survive a build deliberately; [[<tvar name="1">Special:MyLanguage/Writing an extension</tvar>|Writing an extension]] is the contract for that.
</translate>

{{prevnext|Skins|Lua modules}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Getting Started.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,4 @@ echo '{{Note|Back up your wiki first.}}' >> src/index.wikitext
Build again: the home page now shows the note. See [[<tvar name="1">Special:MyLanguage/Pages#Templates</tvar>|Pages#Templates]] for parameters and more.
</translate>

{{prevnext|Installation|Pages}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Images.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ The thumbnailing backend is detected from the tools present at build time: [<tva
To give a file its own description page, add a wikitext file named after it in the <code>File:</code> namespace, the same way other namespaced pages are named. For <code>My photo.png</code>, that is <code>File:My photo.png.wikitext</code>.
</translate>

{{prevnext|Editing sidebar|Skins}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Installation.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@ This produces a local <code>wikven</code> image you run exactly like the publish
Once you have {{SITENAME}}, head to [[<tvar name="1">Special:MyLanguage/Getting Started</tvar>|Getting Started]] to build your first site.
</translate>

{{prevnext|Why wikitext|Getting Started}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/JavaScript.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ Only gadgets marked <code>default</code> are loaded: a static site has no logged
These docs ship one such gadget, <code>PersistTabber</code>, which remembers whether you pick the Docker or the binary tab in the install steps. Every other tabber on the page switches to the tab you picked, and the choice is still there when you move to another page.
</translate>

{{prevnext|Lua modules|Searching}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Licenses.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ __TOC__
The standalone binary is compiled with [https://frankenphp.dev/ FrankenPHP], which also links several Caddy modules; see the FrankenPHP project for their licenses. The Docker image keeps MediaWiki's own <code>COPYING</code>, and each component's full license text is available from its project.
</translate>

{{prevnext|prev=Writing an extension}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Lua modules.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,4 @@ A refused build says so in its exit status as well as in words, so a script that
This documentation site uses a module itself, and the page you are reading is baked with the image on every change, with the module's answer asserted to be in it. The binary is held to the same rule on a source tree of its own, x86-64 on every change and arm64 on every nightly, so each row of the table above is something a machine checks rather than something this page claims.
</translate>

{{prevnext|Extensions|JavaScript}}
{{prevnext}}
91 changes: 91 additions & 0 deletions docs/Module:Sequence.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
-- The order of the documentation, read from the one place it is written down.
--
-- MediaWiki:Sidebar lists the pages in order, and Template:prevnext used to list them again as its
-- arguments. Nothing checked that the two agreed, and twice they did not: a page was added to the
-- sidebar without a chain entry, and the chain's last page was left with no row at all (#455). Both
-- are the same failure -- adding a page meant editing three files and forgetting one was invisible.
--
-- The direction is forced. MediaWiki:Sidebar is read line by line by the skin rather than parsed as
-- wikitext, so it cannot call anything; but it is an ordinary page, so anything can read it.
--
-- What the sidebar contributes is order alone. The link labels stay where they were, in
-- Template:prevnext/label, which reads each target's own translated title.
--
-- Named with the .lua marker, which Special:MyLanguage/Lua modules describes without recommending:
-- the page is Module:Sequence.lua, and Template:prevnext spells the invoke that way.
local p = {}

-- Where the order lives, and the entry line to read out of it: "** Special:MyLanguage/Page|key".
local SIDEBAR = 'MediaWiki:Sidebar'
local ENTRY = '^%*%*%s*Special:MyLanguage/([^|\n]+)'

-- Both sidebar groups, in one sequence. The chain has always crossed from the docs group into the
-- references group, and a reader at the end of the first group is better sent on than stopped.
local function sequence()
local sidebar = mw.title.new(SIDEBAR)
local content = sidebar and sidebar:getContent()
local pages = {}
if content then
for line in mw.text.gsplit(content, '\n') do
local target = line:match(ENTRY)
if target then
pages[#pages + 1] = mw.text.trim(target)
end
end
end
return pages
end

-- Where this page sits in the sequence, or nil if the sidebar does not name it -- which is every
-- page that is not a step of the documentation. The main page is one of those: it is where a reader
-- arrives rather than a step they walk, and it names its own way on in its opening lines.
--
-- A translation counts as its source page: "Searching/ko" is the sidebar's "Searching" in another
-- language, and the sidebar names the page it was translated from. Matched as a prefix rather than
-- by asking the title for its root, because rootText only strips a subpage where the namespace has
-- them turned on, and this one does not -- there, "Searching/ko" is one whole title. Anchoring on
-- the names the sidebar gives keeps that out of it: no entry is another entry plus a slash.
local function positionOf(pages, here)
for i, page in ipairs(pages) do
if here == page or here:sub(1, #page + 1) == page .. '/' then
return i
end
end
return nil
end

-- The page on either side of this one, or nil at an end of the sequence.
local function neighbour(step)
local pages = sequence()
-- Loud rather than empty. A row that renders as nothing is the failure this module exists to
-- end, and it is the invisible kind: the wrapper div is still there and the page still looks
-- finished. If the sidebar stops being readable, that should stop a build, not reach a reader.
if #pages == 0 then
error(SIDEBAR .. ' has no "** Special:MyLanguage/Page" entries to read the order from', 0)
end
local here = positionOf(pages, mw.title.getCurrentTitle().text)
return here and pages[here + step] or nil
end

local function link(frame, page, before, after)
local label = frame:expandTemplate{ title = 'prevnext/label', args = { page } }
return before .. '[[Special:MyLanguage/' .. page .. '|' .. label .. ']]' .. after
end

-- The row: a previous link, a next link, or both. A page the sidebar does not name gets neither,
-- which is what every page outside the sequence -- a template, a category, a File: page -- should
-- get if it ever calls this.
function p.row(frame)
local out = {}
local previous = neighbour(-1)
if previous then
out[#out + 1] = '<div class="wikven-prevnext-prev">' .. link(frame, previous, '&larr;&nbsp;', '') .. '</div>'
end
local following = neighbour(1)
if following then
out[#out + 1] = '<div class="wikven-prevnext-next">' .. link(frame, following, '', '&nbsp;&rarr;') .. '</div>'
end
return table.concat(out)
end

return p
2 changes: 1 addition & 1 deletion docs/Pages.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,4 @@ saved as <code>Template:Note.wikitext</code> and used on a page as:
renders as "'''Note:''' Back up your wiki first." Templates take positional (<code><nowiki>{{{1}}}</nowiki></code>) and named parameters and run [<tvar name="1">https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Parser_functions</tvar> parser functions] exactly as in MediaWiki. The syntax itself is standard MediaWiki; see [<tvar name="2">https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Templates</tvar> Help:Templates].
</translate>

{{prevnext|Getting Started|Editing sidebar}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Searching.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,4 @@ containing…" action and its Enter key go to that page. This site uses a page
titled <code>Search</code>.
</translate>

{{prevnext|JavaScript|Translating}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Skins.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,4 @@ The other six the skin reads off the configuration itself, so they behave as doc
What the inert ones would have configured, {{SITENAME}} supplies its own way where it can: the colour theme is on the <code>Settings</code> page the build writes in place of <code>Special:MobileOptions</code>, and the site's own navigation is written into the main menu of every rendered page.
</translate>

{{prevnext|Images|Extensions}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Standalone binary.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,4 @@ The binary renders on its own, but uses these host programs when they are presen
{{note|Fetching over HTTPS, Wikimedia Commons images via InstantCommons and any [[<tvar name="1">Special:MyLanguage/Configuration#WikvenRepositories</tvar>|third-party extensions or skins]], relies on your system's CA certificates. On a minimal system without them, install your distribution's CA bundle (for example the <code>ca-certificates</code> package). A site with only local content and images needs no network access.}}
</translate>

{{prevnext|Configuration|Commands}}
{{prevnext}}
10 changes: 3 additions & 7 deletions docs/Template:prevnext.wikitext
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
<templatestyles src="prevnext/styles.css" /><div class="wikven-prevnext"><!--
The next page is the last positional argument, so one argument is a next and two are a previous
and a next. The last page of the chain has a previous and no next, which no positional form can
spell -- an empty second argument reads the same as an absent one -- so that one names prev=.
-->{{#if:{{{2|}}}{{{prev|}}}|
<div class="wikven-prevnext-prev">&larr;&nbsp;[[Special:MyLanguage/{{{prev|{{{1|}}}}}}|{{prevnext/label|{{{prev|{{{1|}}}}}}}}]]</div>
}}<!--
-->{{#if:{{{2|{{{1|}}}}}}|<div class="wikven-prevnext-next">[[Special:MyLanguage/{{{2|{{{1|}}}}}}|{{prevnext/label|{{{2|{{{1|}}}}}}}}]]&nbsp;&rarr;</div>}}<!--
Takes no arguments: the order comes from MediaWiki:Sidebar, which is where it is written down.
See Module:Sequence.lua.
-->{{#invoke:Sequence.lua|row}}<!--
--></div><noinclude>
{{prevnext/doc}}
</noinclude>
31 changes: 19 additions & 12 deletions docs/Template:prevnext/doc.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,31 @@ Bottom-of-page navigation between the steps of the documentation, as a row of on

== Usage ==

<nowiki>{{prevnext|next step}}
{{prevnext|previous step|next step}}
{{prevnext|prev=previous step}}</nowiki>
<nowiki>{{prevnext}}</nowiki>

Each argument is a page name, not a link label: it is the link target, and the link text is the
target's own title.
No arguments. The order of the documentation is [[MediaWiki:Sidebar]], and
<code>Module:Sequence.lua</code> reads it: the page before this one in the sidebar becomes the previous
link, the page after it the next. The first and last pages of the sequence get one link rather than
two, without having to say so, and a page the sidebar does not name gets no row at all.

The next page is the last positional argument, so one of them is a next and two are a previous and
a next. The last page of the chain is the one form that leaves out: it has a previous and no next,
and an empty second argument reads the same as an absent one, so there is no positional way to say
it. That page names <code>prev=</code> instead, which is otherwise the same previous link.
It used to take the page names, which meant the order was written down twice -- once as the
sidebar's and once across twenty-one calls -- with nothing checking that the two agreed. Twice they
did not: a page reached the sidebar without a call naming it, and the last page of the chain had no
row, because a lone argument read as the *next* step and there was no way to spell "nothing after
this". Adding a page meant three edits, and forgetting the third was invisible. Now it is two: the
sidebar, and a <code><nowiki>{{prevnext}}</nowiki></code> at the foot of the new page.

The main page has no row. It is not a sidebar entry -- every skin already points its logo at it --
and it is where a reader arrives rather than a step they walk, so it names its own way on in its
opening lines instead.

== Translated pages ==

A prevnext sits outside the <code>&lt;translate&gt;</code> tags, so it is copied whole into every
translation of the page it is on. That is why it takes page names alone: a label passed in would be
a second copy of the target's title in every page that links to it, and one nothing checks, so
renaming a page would leave the links to it quietly wrong in every language.
translation of the page it is on. That is why no label is written into the call, and was not when
the call still took page names: a label passed in would be a second copy of the target's title in
every page that links to it, and one nothing checks, so renaming a page would leave the links to it
quietly wrong in every language.

<code>Template:prevnext/label</code> reads that title instead, from the one place it is translated:
the target's <code>title</code> unit, which the build writes to Translate's "Page display title"
Expand Down
2 changes: 1 addition & 1 deletion docs/Translating.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,4 @@ $ docker run --rm -v "$PWD/src:/workspace/src" ghcr.io/chaotic-ground/wikven tra
The [https://github.com/chaotic-ground/wikven/tree/main/actions/check-translations check-translations action] runs the same check on pull requests, reporting each one as an annotation on the file it belongs to. It fails the build on a broken source page and never on a translation that is behind; pass <code>gate: false</code> to report even a broken page without failing. This documentation site is checked this way. To bring a translation back up to date, edit it to match the new source, then <code>translate stamp</code> it again.
</translate>

{{prevnext|Searching|Deploying}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Troubleshooting.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@ Every parse of a page embedding a Commons image asks Commons for its thumbnail.
On a site with several skins, each is rendered by its own process and the build reports each one that failed by name (<code>build failed for skin ...</code>). The output of each pass is printed under its own heading, so read the section for the named skin rather than the end of the log. If the machine is short of memory, <code>WIKVEN_BUILD_JOBS=1</code> runs the passes one at a time; see [[<tvar name="1">Special:MyLanguage/Commands</tvar>|Commands]].
</translate>

{{prevnext|Deploying|Configuration}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Why wikitext.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ __TOC__
That last cost, running MediaWiki, is the one {{SITENAME}} removes: it renders your wikitext through MediaWiki once, at build time, and ships plain static HTML. You get templates, parser functions and the rest with nothing to run in production. Reach for {{SITENAME}} when that trade is worth it, typically when your content is already wikitext, or when templates and transclusion would save real work.
</translate>

{{prevnext|Installation}}
{{prevnext}}
2 changes: 1 addition & 1 deletion docs/Writing an extension.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,4 @@ Worth checking specifically:
* [[<tvar name="3">Special:MyLanguage/JavaScript</tvar>|JavaScript]] — how scripts and gadgets are bundled for a static host.
</translate>

{{prevnext|Development|Licenses}}
{{prevnext}}
1 change: 0 additions & 1 deletion docs/index.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,4 @@ These need a live wiki, so they are not part of the static export:
What replaces some of them is written down: the reader's own display choices are on a [[<tvar name="1">Special:MyLanguage/Skins#Settings</tvar>|Settings page]] the build writes, and searching is [[<tvar name="2">Special:MyLanguage/Searching</tvar>|done in the browser]].
</translate>

{{prevnext|Why wikitext}}
{{DISPLAYTITLE:Wikven}}
Loading