diff --git a/styles/all/template/recent_topics_body_side.html b/styles/all/template/recent_topics_body_side.html
index 2afc964..104b27c 100644
--- a/styles/all/template/recent_topics_body_side.html
+++ b/styles/all/template/recent_topics_body_side.html
@@ -55,7 +55,7 @@
{% if S_POSTLOVE and recent_topics.TOPIC_LIKES %} {{ recent_topics.TOPIC_LIKES }}{% endif %}
- {{ VIEW_LATEST_POST }}
+ {{ lang('GOTO_LAST_POST') }}
diff --git a/styles/all/template/recent_topics_page.html b/styles/all/template/recent_topics_page.html
index 18c55f8..ecbb80c 100644
--- a/styles/all/template/recent_topics_page.html
+++ b/styles/all/template/recent_topics_page.html
@@ -100,7 +100,7 @@
{% if not S_IS_BOT %}
- {{ VIEW_LATEST_POST }}
+ {{ lang('GOTO_LAST_POST') }}
{% endif %}
{{ recent_topics.LAST_POST_TIME }}
diff --git a/styles/all/template/recent_topics_simple.html b/styles/all/template/recent_topics_simple.html
index a5fd601..49e1dfa 100644
--- a/styles/all/template/recent_topics_simple.html
+++ b/styles/all/template/recent_topics_simple.html
@@ -96,7 +96,7 @@
{% if not S_IS_BOT %}
- {{ VIEW_LATEST_POST }}
+ {{ lang('GOTO_LAST_POST') }}
{% endif %}
{{ recent_topics.LAST_POST_TIME }}
diff --git a/styles/pbtech/template/recent_topics_body_side.html b/styles/pbtech/template/recent_topics_body_side.html
index 05c841e..2cc6787 100644
--- a/styles/pbtech/template/recent_topics_body_side.html
+++ b/styles/pbtech/template/recent_topics_body_side.html
@@ -43,7 +43,7 @@
{{ lang('RECENT_TOPICS') }}
{% if S_POSTLOVE and recent_topics.TOPIC_LIKES %} {{ recent_topics.TOPIC_LIKES }}{% endif %}
- {{ VIEW_LATEST_POST }}
+ {{ lang('GOTO_LAST_POST') }}
diff --git a/styles/pbwow3/template/recent_topics_body_side.html b/styles/pbwow3/template/recent_topics_body_side.html
index eadf921..17dd0c2 100644
--- a/styles/pbwow3/template/recent_topics_body_side.html
+++ b/styles/pbwow3/template/recent_topics_body_side.html
@@ -44,7 +44,7 @@ {{ lang('RECENT_TOPICS') }}
{% if S_POSTLOVE and recent_topics.TOPIC_LIKES %} {{ recent_topics.TOPIC_LIKES }}{% endif %}
- {{ VIEW_LATEST_POST }}
+ {{ lang('GOTO_LAST_POST') }}
diff --git a/styles/pbwow3/template/recent_topics_body_topbottom.html b/styles/pbwow3/template/recent_topics_body_topbottom.html
index cffa44d..32588f8 100644
--- a/styles/pbwow3/template/recent_topics_body_topbottom.html
+++ b/styles/pbwow3/template/recent_topics_body_topbottom.html
@@ -100,7 +100,7 @@ {{ lang('RECENT_TOPICS') }}
{% if not S_IS_BOT %}
- {{ VIEW_LATEST_POST }}
+ {{ lang('GOTO_LAST_POST') }}
{% endif %}
{{ recent_topics.LAST_POST_TIME }}
diff --git a/styles/we_clearblue/template/recent_topics_body_topbottom.html b/styles/we_clearblue/template/recent_topics_body_topbottom.html
index 80710a2..2db26d2 100644
--- a/styles/we_clearblue/template/recent_topics_body_topbottom.html
+++ b/styles/we_clearblue/template/recent_topics_body_topbottom.html
@@ -103,7 +103,7 @@
{% if not S_IS_BOT %}
- {{ VIEW_LATEST_POST }}
+ {{ lang('GOTO_LAST_POST') }}
{% endif %}
{{ recent_topics.LAST_POST_TIME }}
diff --git a/tests/template/template_vars_test.php b/tests/template/template_vars_test.php
new file mode 100644
index 0000000..a79974e
--- /dev/null
+++ b/tests/template/template_vars_test.php
@@ -0,0 +1,47 @@
+getExtension() === 'html')
+ {
+ $data[substr($file->getPathname(), strlen($root) + 1)] = [$file->getPathname()];
+ }
+ }
+ ksort($data);
+
+ return $data;
+ }
+
+ /**
+ * VIEW_LATEST_POST is never assigned, so it rendered an empty screen-reader label on the
+ * last-post link. The link's text comes from lang('GOTO_LAST_POST'), matching its title (#215).
+ *
+ * @dataProvider template_data
+ */
+ public function test_no_unassigned_view_latest_post($file)
+ {
+ $this->assertStringNotContainsString('VIEW_LATEST_POST', file_get_contents($file));
+ }
+}
diff --git a/tests/tests.md b/tests/tests.md
index 309cae9..d5edf9a 100644
--- a/tests/tests.md
+++ b/tests/tests.md
@@ -51,6 +51,8 @@ tests/
│ └── recenttopics_events_test.php Public event API contract (contrib/events.md)
├── language/
│ └── viewonline_lang_test.php Who Is Online label in every language pack
+├── template/
+│ └── template_vars_test.php No unassigned template variables in shipped templates
└── functional/
└── recenttopics_test.php End-to-end browser tests
```
@@ -257,7 +259,21 @@ It runs `fill_template()` on one page of four topics in time order (normal, anno
---
-## 11. Functional tests (`functional/recenttopics_test.php`)
+## 11. Template variables (`template/template_vars_test.php`)
+
+**What this code does:**
+The topic-list templates in `styles/*/template/` render a hidden screen-reader label inside each last-post link.
+
+**What this test file does:**
+It reads every `.html` template the extension ships (one data-provider row per file) and checks it for variables the PHP never assigns.
+
+| Test | Scenario | What it verifies |
+|------|----------|-----------------|
+| `test_no_unassigned_view_latest_post` | Every template file | No `VIEW_LATEST_POST`. It was never assigned, so the last-post link's screen-reader label rendered empty; the templates now use `lang('GOTO_LAST_POST')`, matching the link's title (#215) |
+
+---
+
+## 12. Functional tests (`functional/recenttopics_test.php`)
**What this code does:**
These tests start a real phpBB installation (using the test framework's built-in install), enable the extension, and make HTTP requests using a real browser-like crawler (Symfony DomCrawler). They check the actual rendered HTML for specific elements.