Index: src/assets/js/mod/read.js
===================================================================
--- src/assets/js/mod/read.js	(revision b67edbdfb84f7d125475d92c470edf68a7886ccf)
+++ src/assets/js/mod/read.js	(revision 7421147352180120b7c1601b2ce47d67418c3446)
@@ -18,4 +18,10 @@
 const MARGE = '1px 0px 100% 0px';
 
+// De teksten die dit script plaatst. Ze staan in data-i18n op de stroom, want
+// een zin die hier staat, staat in één taal -- en dat is nooit de taal van de
+// lezer. Zelfde afspraak als de topnav (mod/chrome.js).
+let woorden = {};
+function woord(sleutel) { return woorden[sleutel] || ''; }
+
 const stroom = () => document.getElementById('read-stream');
 const geladen = new Set();      // slugs die al in de stroom staan
@@ -26,5 +32,5 @@
 
 function chrome(verbergen) {
-  document.body.classList.toggle('read-chrome-weg', !!verbergen);
+  document.body.classList.toggle('read-chrome-hidden', !!verbergen);
 }
 
@@ -72,5 +78,5 @@
   if (geladen.has(slug)) return;
   bezigOnder = true;
-  const wacht = melding(s, 'read-laden', '…');
+  const wacht = melding(s, 'read-loading', '…');
   try {
     const art = await haal(slug, laatste.dataset.base || '');
@@ -80,5 +86,5 @@
     kijk();
   } catch (e) {
-    wacht.textContent = 'Kon het volgende bericht niet laden.';
+    wacht.textContent = woord('load_error');
     console.warn('[read] onderaan:', e && e.message);
   } finally { bezigOnder = false; }
@@ -120,6 +126,6 @@
 
 function klaar(s) {
-  if (s.querySelector('.read-eind')) return;
-  melding(s, 'read-eind', 'Je bent bij het begin van het archief.');
+  if (s.querySelector('.read-end')) return;
+  melding(s, 'read-end', woord('end'));
 }
 
@@ -152,4 +158,5 @@
   const s = stroom();
   if (!s) return;
+  try { woorden = JSON.parse(s.getAttribute('data-i18n') || '{}'); } catch (e) { woorden = {}; }
   s.querySelectorAll('.read-post').forEach((p) => geladen.add(p.dataset.slug));
   laatsteY = window.scrollY || 0;
Index: src/services/i18n.js
===================================================================
--- src/services/i18n.js	(revision b67edbdfb84f7d125475d92c470edf68a7886ccf)
+++ src/services/i18n.js	(revision 7421147352180120b7c1601b2ce47d67418c3446)
@@ -891,5 +891,5 @@
     'fgate.title': 'Alleen voor vrienden',
     'fgate.sub': 'Dit is exclusief voor ingelogde vrienden. Log in om het te bekijken.',
-    'fgate.login': 'Inloggen / aanmelden', 'read.exit': 'Terug naar de site', 'read.exit_label': 'Uit het leesscherm',
+    'fgate.login': 'Inloggen / aanmelden', 'read.end': 'Je bent bij het begin van het archief.', 'read.load_error': 'Kon het volgende bericht niet laden.', 'read.exit': 'Terug naar de site', 'read.exit_label': 'Uit het leesscherm',
     'lbio.empty': 'Nog geen links ingesteld.',
     'lbio.back_to_site': 'naar de site',
@@ -1897,5 +1897,5 @@
     'fgate.title': 'Friends only',
     'fgate.sub': 'This is exclusive to logged-in friends. Log in to view it.',
-    'fgate.login': 'Log in / sign up', 'read.exit': 'Back to the site', 'read.exit_label': 'Leave reading view',
+    'fgate.login': 'Log in / sign up', 'read.end': 'You have reached the beginning of the archive.', 'read.load_error': 'Could not load the next post.', 'read.exit': 'Back to the site', 'read.exit_label': 'Leave reading view',
     'lbio.empty': 'No links set up yet.',
     'lbio.back_to_site': 'back to the site',
@@ -2903,5 +2903,5 @@
     'fgate.title': 'Nur für Freunde',
     'fgate.sub': 'Dies ist exklusiv für eingeloggte Freunde. Melde dich an, um es anzusehen.',
-    'fgate.login': 'Anmelden / Registrieren', 'read.exit': 'Zurück zur Seite', 'read.exit_label': 'Lesemodus verlassen',
+    'fgate.login': 'Anmelden / Registrieren', 'read.end': 'Du bist am Anfang des Archivs angekommen.', 'read.load_error': 'Der nächste Beitrag konnte nicht geladen werden.', 'read.exit': 'Zurück zur Seite', 'read.exit_label': 'Lesemodus verlassen',
     'lbio.empty': 'Noch keine Links eingerichtet.',
     'lbio.back_to_site': 'zurück zur Seite',
Index: src/views/pages/read.ejs
===================================================================
--- src/views/pages/read.ejs	(revision b67edbdfb84f7d125475d92c470edf68a7886ccf)
+++ src/views/pages/read.ejs	(revision 7421147352180120b7c1601b2ce47d67418c3446)
@@ -14,5 +14,9 @@
 %>
 
-<div class="read-stream" id="read-stream" data-base="<%= _b %>">
+<%# De teksten die het script zelf plaatst, komen van hier -- zoals de
+    zoekteksten van de topnav (zie mod/chrome.js). Een zin die in het
+    script staat, staat in één taal, en dat is nooit de taal van de lezer. %>
+<div class="read-stream" id="read-stream" data-base="<%= _b %>"
+     data-i18n="<%= JSON.stringify({ end: t('read.end'), load_error: t('read.load_error') }) %>">
   <%- include('../partials/read-article', {
         post: post, entry: entry, newerPost: newerPost, olderPost: olderPost,
@@ -44,6 +48,6 @@
   will-change: transform;
 }
-.on-read.read-chrome-weg #pcms-chrome { transform: translateY(-100%); opacity: 0; }
-.on-read.read-chrome-weg .bottom-tab  { transform: translateY(100%);  opacity: 0; }
+.on-read.read-chrome-hidden #pcms-chrome { transform: translateY(-100%); opacity: 0; }
+.on-read.read-chrome-hidden .bottom-tab  { transform: translateY(100%);  opacity: 0; }
 
 /* De vrije ruimte onder de laatste post moet weg: anders eindigt het document
@@ -73,6 +77,6 @@
 /* Bezig / mislukt: de lezer hoort te merken dat er iets gebeurt, en vooral dat
    er NIETS gebeurde als het misging. */
-.on-read .read-laden { text-align: center; padding: 1.2rem; opacity: .6; font-size: .9rem; }
-.on-read .read-eind  { text-align: center; padding: 2rem 1rem 3rem; opacity: .5; font-size: .9rem; }
+.on-read .read-loading { text-align: center; padding: 1.2rem; opacity: .6; font-size: .9rem; }
+.on-read .read-end  { text-align: center; padding: 2rem 1rem 3rem; opacity: .5; font-size: .9rem; }
 
 .on-read .read-exit { position: fixed; right: 1rem; bottom: 1rem; z-index: 60; }
