diff --git a/README.md b/README.md
index ffaa4e8..7f1d4fc 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
Ready-made templates for the [phpBB Modders wiki extension](https://github.com/phpbbmodders/phpbb-ext-wiki), adapted from Wikipedia's and other Wikimedia wikis' for what the wiki can do, so a board can start with a useful set instead of writing every template from nothing.
-So far [`templates/`](templates/) holds the hatnotes `{{Main}}`, `{{See also}}`, `{{Further}}` and `{{About}}`; the message boxes `{{Ambox}}`, `{{Update}}`, `{{Unreferenced}}`, `{{More citations needed}}` and `{{Under construction}}`; the stub boxes `{{Asbox}}` and `{{Stub}}`; and `{{Nowrap}}`. The plan for this repository is in the wiki extension's [`docs/TODO/todo-wiki-templates-repo.md`](https://github.com/phpbbmodders/phpbb-ext-wiki/blob/main/docs/TODO/todo-wiki-templates-repo.md).
+So far [`templates/`](templates/) holds the hatnotes `{{Main}}`, `{{See also}}`, `{{Further}}` and `{{About}}`; the message boxes `{{Ambox}}`, `{{Update}}`, `{{Unreferenced}}`, `{{More citations needed}}` and `{{Under construction}}`; the stub boxes `{{Asbox}}` and `{{Stub}}`; and the inline helpers `{{Nowrap}}`, `{{Small}}` and `{{Large}}`. The plan for this repository is in the wiki extension's [`docs/TODO/todo-wiki-templates-repo.md`](https://github.com/phpbbmodders/phpbb-ext-wiki/blob/main/docs/TODO/todo-wiki-templates-repo.md).
## Why a separate repository
diff --git a/data/templates.json b/data/templates.json
index 0952f65..f9295b4 100644
--- a/data/templates.json
+++ b/data/templates.json
@@ -6,6 +6,13 @@
"status": "adapted",
"title": "Template:Stub"
},
+ "enwiki:828359": {
+ "name": "Center",
+ "reason": "needs a
to centre its text, and phpBB has no centring BBCode out of the box",
+ "revid": 1282577637,
+ "status": "not adaptable",
+ "title": "Template:Center"
+ },
"enwiki:1208356": {
"name": "Main",
"reason": "",
@@ -48,6 +55,13 @@
"status": "adapted",
"title": "Template:Update"
},
+ "enwiki:2385304": {
+ "name": "Small",
+ "reason": "",
+ "revid": 1313016425,
+ "status": "adapted",
+ "title": "Template:Small"
+ },
"enwiki:2425121": {
"name": "Under construction",
"reason": "",
@@ -62,6 +76,13 @@
"status": "adapted",
"title": "Template:About"
},
+ "enwiki:8183126": {
+ "name": "Large",
+ "reason": "",
+ "revid": 1133894340,
+ "status": "adapted",
+ "title": "Template:Large"
+ },
"enwiki:10160967": {
"name": "More citations needed",
"reason": "",
diff --git a/templates/Large.wiki b/templates/Large.wiki
new file mode 100644
index 0000000..46482b0
--- /dev/null
+++ b/templates/Large.wiki
@@ -0,0 +1,9 @@
+
+Source: https://en.wikipedia.org/wiki/Template:Large
+History: https://en.wikipedia.org/w/index.php?title=Template:Large&action=history
+Revision: https://en.wikipedia.org/w/index.php?title=Template:Large&oldid=1133894340 (01/16/2023 1:12 AM UTC)
+Adapted by phpBB Modders.
+Changes: rewritten with phpBB's [size=120] BBCode instead of the the wiki does not allow, which gives the same size; removed the source's documentation and categories.
+Example: {{Large|This is large text.}}
+Licence: CC BY-SA 4.0, https://creativecommons.org/licenses/by-sa/4.0/
+[size=120]{{{1}}}[/size]
diff --git a/templates/Small.wiki b/templates/Small.wiki
new file mode 100644
index 0000000..da026a4
--- /dev/null
+++ b/templates/Small.wiki
@@ -0,0 +1,9 @@
+
+Source: https://en.wikipedia.org/wiki/Template:Small
+History: https://en.wikipedia.org/w/index.php?title=Template:Small&action=history
+Revision: https://en.wikipedia.org/w/index.php?title=Template:Small&oldid=1313016425 (09/23/2025 9:17 PM UTC)
+Adapted by phpBB Modders.
+Changes: rewritten with phpBB's [size=85] BBCode instead of the the wiki does not allow, which gives the same size; no check for unknown parameters (Lua) or tracking category; removed the source's documentation and categories.
+Example: {{Small|This is small text.}}
+Licence: CC BY-SA 4.0, https://creativecommons.org/licenses/by-sa/4.0/
+[size=85]{{{1}}}[/size]
diff --git a/tests/test_tools.py b/tests/test_tools.py
index c592b53..39675ce 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -100,7 +100,13 @@ def test_translate_markup_is_flagged(self):
def test_plain_template_needs_nothing(self):
self.assertEqual(fetch_template.needs(
- '
{{{1}}}'), [])
+ "
"), [])
+
+ def test_html_other_than_tables_is_flagged(self):
+ self.assertEqual(
+ fetch_template.needs('
{{{1}}}'
+ '
'),
+ ["HTML the wiki shows as text:
,
, "])
def test_called_templates_skip_magic_words_and_parameters(self):
text = ("{{Hatnote|x}} {{ ambox }} {{{1|{{Main}}}}} {{PAGENAME}} "
@@ -368,7 +374,7 @@ def setUp(self):
def fake_fetch(site, names, content=True):
if content:
self.fetched.extend(names)
- return {name: (dict(self.INFO, text="{{{1}}}",
+ return {name: (dict(self.INFO, text="[b]{{{1}}}[/b]",
timestamp="2025-05-30T12:00:00Z")
if name == "See also" else None)
for name in names}
@@ -402,13 +408,24 @@ def test_fetch_records_the_page_id_and_skips_a_known_revision(self):
self.assertEqual(self.fetched, ["See also"])
self.assertFalse((self.dir / "See also.wiki").exists())
+ def test_a_redirect_is_not_fetched_under_its_own_name(self):
+ redirect = dict(self.INFO, title="Template:Small")
+ with mock.patch.object(fetch_template, "fetch",
+ return_value={"Smaller": redirect}):
+ self.assertEqual(self.run_main("Smaller"), 1)
+ self.assertEqual(self.printed.call_args.args[0],
+ "REDIRECT Smaller: redirects to Template:Small; "
+ "use 'Small'")
+ self.assertFalse((self.dir / "Smaller.wiki").exists())
+ self.assertEqual(self.saved(), {})
+
def test_existing_file_is_not_replaced_without_force(self):
target = self.dir / "See also.wiki"
target.write_text("edited", encoding="utf-8")
self.assertEqual(self.run_main("See also"), 1)
self.assertEqual(target.read_text(encoding="utf-8"), "edited")
self.assertEqual(self.run_main("--force", "See also"), 0)
- self.assertIn("{{{1}}}",
+ self.assertIn("[b]{{{1}}}[/b]",
target.read_text(encoding="utf-8"))
def test_missing_template_fails_and_dry_run_writes_nothing(self):
diff --git a/tools/fetch_template.py b/tools/fetch_template.py
index 0891c24..fcb77bb 100755
--- a/tools/fetch_template.py
+++ b/tools/fetch_template.py
@@ -17,8 +17,8 @@
outside , or inside ) was removed, since the header
takes its place;
* "Needs adapting:", when the text uses what the phpBB Modders wiki cannot run:
- Lua ({{#invoke:}}), TemplateStyles, the Translate extension's markup, or
- parser functions and magic words it does not have;
+ Lua ({{#invoke:}}), TemplateStyles, the Translate extension's markup, HTML
+ other than tables, or parser functions and magic words it does not have;
* the licence notice.
Once adapted and passing check_headers.py, --mark-adapted records it as such.
@@ -104,6 +104,16 @@
r"|SERVER(?:NAME)?|SCRIPTPATH|DISPLAYTITLE|DEFAULTSORT|PAGESIZE"
r"|PROTECTIONLEVEL)$")
+# Tags the phpBB Modders wiki allows in articles and templates: its HTML table
+# elements, and the template tags it understands itself
+ALLOWED_TAGS = {
+ "table", "caption", "thead", "tbody", "tfoot", "tr", "th", "td",
+ "noinclude", "includeonly", "onlyinclude",
+}
+
+# Tags reported under their own names above, not again as HTML
+REPORTED_TAGS = {"templatestyles", "translate", "languages"}
+
# Names that cannot be a file in templates/: subpages and path characters.
INVALID_NAME = re.compile(r'[/\\<>:"|?*\x00-\x1f]|^\.|^\s|\s$')
@@ -313,6 +323,13 @@ def needs(text: str) -> list:
if re.search(r"<(?:translate|languages)\b|", text,
re.IGNORECASE):
problems.append("Translate markup (, )")
+ # The wiki allows HTML tables and nothing else; other tags show as text
+ tags = {tag.lower() for tag in re.findall(r"?([a-zA-Z][a-zA-Z0-9]*)",
+ text)}
+ html = sorted(tags - ALLOWED_TAGS - REPORTED_TAGS)
+ if html:
+ problems.append("HTML the wiki shows as text: <"
+ + ">, <".join(html) + ">")
unsupported = set()
for match in re.finditer(r"\{\{\s*(#?[A-Za-z][\w ]*?)\s*:", text):
word = match.group(1).strip().lower()
@@ -464,6 +481,20 @@ def check_updates(record: dict) -> int:
return 0
+def redirected(name: str, page: dict) -> bool:
+ """
+ Whether a name is only a redirect to another template on the wiki, such as
+ Smaller to Small; prints where it points. A template is kept under its own
+ name, so the redirect's target should be fetched instead.
+ """
+ if page["title"] == PREFIX + name:
+ return False
+ target = page["title"][len(PREFIX):] if page["title"].startswith(
+ PREFIX) else page["title"]
+ print(f"REDIRECT {name}: redirects to {page['title']}; use {target!r}")
+ return True
+
+
def mark_unadaptable(site_id: str, names: list, reason: str,
record: dict) -> int:
"""Record templates as not adaptable; return the exit status."""
@@ -476,6 +507,9 @@ def mark_unadaptable(site_id: str, names: list, reason: str,
print(f"MISSING {name}: no such template on {site['label']}")
failed += 1
continue
+ if redirected(name, page):
+ failed += 1
+ continue
record[record_key(site_id, page["pageid"])] = record_entry(
page, name, "not adaptable", reason)
print(f"RECORDED {name} (page {page['pageid']}, revision "
@@ -530,6 +564,9 @@ def fetch_templates(names: list, args: argparse.Namespace,
print(f"MISSING {name}: no such template on {site['label']}")
failed += 1
continue
+ if redirected(name, page):
+ failed += 1
+ continue
entry = record.get(record_key(site_id, page["pageid"]))
if entry and entry["revid"] == page["revid"] and not args.force:
print(f"KNOWN {name}: recorded at revision {page['revid']} "