Changeset 834bcc3 in Klonkt for src/config


Ignore:
Timestamp:
06/23/2026 06:14:27 PM (3 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
d774679
Parents:
bb42dfb
Message:

i18n: translate Dutch code comments to English across src/

Comments in routes/services/views/config/middleware/assets translated to
English for the public repo. A few dev-facing throw/console message strings
were Englished too. No user-facing UI strings or i18n dictionary values changed
(src/services/i18n.js untouched). Logic unchanged.

Co-Authored-By: Claude <noreply@…>

Location:
src/config
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • src/config/database.js

    rbb42dfb r834bcc3  
    3939  ensureColumn('users', 'reset_token', 'TEXT');
    4040  ensureColumn('users', 'reset_token_expires', 'DATETIME');
    41   // Google OAuth: koppel een Google-account aan een user (login via Google).
     41  // Google OAuth: link a Google account to a user (login via Google).
    4242  ensureColumn('users', 'google_sub', 'TEXT');
    43   // Read-only/kijk-account: kan alles bekijken maar geen wijzigingen doen.
     43  // Read-only/viewer account: can view everything but make no changes.
    4444  ensureColumn('users', 'readonly', 'INTEGER DEFAULT 0');
    45   // Persoonlijke interface-taal (nl|en|de). Null = volg de standaard (site/env/browser).
     45  // Personal interface language (nl|en|de). Null = follow the default (site/env/browser).
    4646  ensureColumn('users', 'lang', 'TEXT');
    4747  // Site-level moderation toggle. 'trust' = auto-approve, 'moderate' = pending until reviewed.
    4848  ensureColumn('sites', 'comments_moderation_mode', "TEXT DEFAULT 'moderate'");
    49   // Cirkels: mag deze site in cirkels van anderen verschijnen (surfacing opt-out).
     49  // Circles: whether this site may appear in other sites' circles (surfacing opt-out).
    5050  ensureColumn('sites', 'allow_circle', 'INTEGER DEFAULT 1');
    5151
    52   // Eén EXPLICIETE primaire/hoofd-site (= de bedrijfs-/labelsite in hub-modus,
    53   // de enige site in solo) i.p.v. de fragiele "oudste = hoofd"-conventie die op
    54   // 4 plekken gedupliceerd stond. Backfill: markeer de oudste als er nog geen
    55   // primaire site is, zodat bestaand gedrag exact behouden blijft.
     52  // One EXPLICIT primary/main site (= the company/label site in hub mode,
     53  // the only site in solo) instead of the fragile "oldest = main" convention
     54  // that was duplicated in 4 places. Backfill: mark the oldest if no primary
     55  // site exists yet, so existing behaviour is preserved exactly.
    5656  ensureColumn('sites', 'is_primary', 'INTEGER DEFAULT 0');
    5757  try {
     
    6161      if (oldest) db.prepare('UPDATE sites SET is_primary = 1 WHERE id = ?').run(oldest.id);
    6262    }
    63   } catch (e) { /* sites-tabel nog leeg/afwezig bij verse init — ensurePrimarySite regelt 't */ }
     63  } catch (e) { /* sites table still empty/absent on fresh init — ensurePrimarySite handles it */ }
    6464
    6565  // v9 audit additions —————————————————————————————————————————
     
    8282  // Per-post noindex + type
    8383  ensureColumn('posts', 'noindex', 'INTEGER DEFAULT 0');
    84   ensureColumn('posts', 'publish_at', 'DATETIME');         // release-planning (premium #3): geplande go-live
     84  ensureColumn('posts', 'publish_at', 'DATETIME');         // release planning (premium #3): scheduled go-live
    8585  ensureColumn('posts', 'fan_only', 'INTEGER DEFAULT 0');  // fan-only preview (premium #3)
    8686  ensureColumn('posts', 'type',    "TEXT DEFAULT 'post'");  // post | foto | video | audio
    8787
    88   // Statistieken (premium-module) — kale tellers, cookievrij.
    89   ensureColumn('posts', 'view_count', 'INTEGER DEFAULT 0');         // weergaven per post
     88  // Statistics (premium module) — bare counters, cookie-free.
     89  ensureColumn('posts', 'view_count', 'INTEGER DEFAULT 0');         // views per post
    9090  ensureColumn('audio_tracks', 'play_count', 'INTEGER DEFAULT 0');  // plays per track
    91   ensureColumn('audio_tracks', 'downloadable', 'INTEGER DEFAULT 0'); // download-voor-email (premium #2)
    92   ensureColumn('audio_tracks', 'credit', 'TEXT');   // eigenaar/credit (copyright-houder)
    93   ensureColumn('audio_tracks', 'license', 'TEXT');  // licentie (bv. "CC BY 4.0", "Alle rechten voorbehouden")
    94   ensureColumn('audio_tracks', 'link_spotify',    'TEXT');  // "open in"-links per track
     91  ensureColumn('audio_tracks', 'downloadable', 'INTEGER DEFAULT 0'); // download-for-email (premium #2)
     92  ensureColumn('audio_tracks', 'credit', 'TEXT');   // owner/credit (copyright holder)
     93  ensureColumn('audio_tracks', 'license', 'TEXT');  // license (e.g. "CC BY 4.0", "All rights reserved")
     94  ensureColumn('audio_tracks', 'link_spotify',    'TEXT');  // "open in" links per track
    9595  ensureColumn('audio_tracks', 'link_youtube',    'TEXT');
    9696  ensureColumn('audio_tracks', 'link_soundcloud', 'TEXT');
     
    123123  `);
    124124
    125   // Globale app-instellingen (key/value singleton). O.a. de tenancy-modus
    126   // (solo = één site, hub = bedrijfssite + /user/). Default = solo.
     125  // Global app settings (key/value singleton). Includes the tenancy mode
     126  // (solo = one site, hub = company site + /user/). Default = solo.
    127127  db.exec(`
    128128    CREATE TABLE IF NOT EXISTS app_settings (
     
    134134  db.prepare("INSERT OR IGNORE INTO app_settings (key, value) VALUES ('tenancy', 'solo')").run();
    135135
    136   // ── Statistieken (premium) — cookievrij ─────────────────────
    137   // stat_daily: per dag per site het aantal pageviews (kale teller).
    138   // stat_visitor_day: per dag per site een rij per UNIEKE bezoeker-hash
    139   //   (sha256 van IP+UA+dag-salt; de salt roteert dagelijks en wordt nooit
    140   //   bewaard → geen persistente identifier, geen cookie, geen toestemming nodig).
     136  // ── Statistics (premium) — cookie-free ──────────────────────
     137  // stat_daily: pageview count per day per site (bare counter).
     138  // stat_visitor_day: one row per UNIQUE visitor hash per day per site
     139  //   (sha256 of IP+UA+day-salt; the salt rotates daily and is never stored
     140  //   → no persistent identifier, no cookie, no consent required).
    141141  db.exec(`
    142142    CREATE TABLE IF NOT EXISTS stat_daily (
     
    161161  `);
    162162
    163   // ── Cirkels (federatie) ─────────────────────────────────────
    164   // Decentrale, asymmetrische verbindingen tussen solo-instances.
     163  // ── Circles (federation) ────────────────────────────────────
     164  // Decentralised, asymmetric connections between solo instances.
    165165  db.exec(`
    166166    CREATE TABLE IF NOT EXISTS circle_links (
     
    200200  `);
    201201
    202   // Tags van de originele post — getoond in de cirkel (comma-separated string).
     202  // Tags from the original post — shown in the circle feed (comma-separated string).
    203203  ensureColumn('remote_posts', 'tags', 'TEXT');
    204204
    205   // Nieuwsbrief / mailinglijst (premium). Abonnees per site; double opt-in als SMTP
    206   // er is (status 'pending' tot bevestigd), anders single opt-in ('confirmed').
    207   // 'unsub' = uitgeschreven. token = confirm/unsubscribe-sleutel (in de e-maillinks).
     205  // Newsletter / mailing list (premium). Subscribers per site; double opt-in when SMTP
     206  // is configured (status 'pending' until confirmed), otherwise single opt-in ('confirmed').
     207  // 'unsub' = unsubscribed. token = confirm/unsubscribe key (used in email links).
    208208  db.exec(`
    209209    CREATE TABLE IF NOT EXISTS subscribers (
     
    221221  `);
    222222
    223   // Verstuurde nieuwsbrieven (historie + aantallen).
     223  // Sent newsletters (history + counts).
    224224  db.exec(`
    225225    CREATE TABLE IF NOT EXISTS newsletters (
     
    233233  `);
    234234
    235   // Show-agenda (premium #8): tourdata/optredens per site.
     235  // Show agenda (premium #8): tour dates / gigs per site.
    236236  db.exec(`
    237237    CREATE TABLE IF NOT EXISTS shows (
     
    250250  `);
    251251
    252   // Meldingen: iemand reageert op je reactie / post, of liket je post. Snapshots
    253   // van naam/titel zodat de lijst goedkoop te tonen is zonder joins.
    254   // NB: bewust 'user_notifications' — sommige oudere DBs hebben nog een stale,
    255   // ongebruikte 'notifications'-tabel met een ander schema (geen read-kolom).
     252  // Notifications: someone replies to your comment / post, or likes your post. Snapshots
     253  // of name/title so the list can be shown cheaply without joins.
     254  // NB: deliberately named 'user_notifications' — some older DBs still have a stale,
     255  // unused 'notifications' table with a different schema (no read column).
    256256  db.exec(`
    257257    CREATE TABLE IF NOT EXISTS user_notifications (
     
    270270  `);
    271271
    272   // Link-in-bio klikstatistiek (premium #6). Per (site, url) een teller; de
    273   // link-in-bio-pagina linkt via /links/go/:i dat de klik telt en doorstuurt.
     272  // Link-in-bio click statistics (premium #6). One counter per (site, url); the
     273  // link-in-bio page links via /links/go/:i which counts the click and redirects.
    274274  db.exec(`
    275275    CREATE TABLE IF NOT EXISTS link_clicks (
     
    282282  `);
    283283
    284   // Likes / favorieten: een ingelogde gebruiker kan een post liken. De set van
    285   // posts die een gebruiker likte = z'n favorieten (/favorieten-pagina). Eén rij
    286   // per (post, user); uniek zodat liken idempotent is.
     284  // Likes / favourites: a logged-in user can like a post. The set of
     285  // posts a user liked = their favourites (/favorieten page). One row
     286  // per (post, user); unique so that liking is idempotent.
    287287  db.exec(`
    288288    CREATE TABLE IF NOT EXISTS post_likes (
  • src/config/features.js

    rbb42dfb r834bcc3  
    1 // Feature-flags (boot-tijd, via env).
     1// Feature flags (boot-time, via env).
    22//
    3 // Lite-modus: zet KLONKT_AUDIO=off in .env om de HELE audio-feature uit te
    4 // schakelen — geen audio-/playlist-/download-/embed-routes, geen ffmpeg-aanroep,
    5 // geen speler en geen [[track]]/[[playlist]]-shortcodes. Zo draait Klonkt als
    6 // lichte blog/foto/EPK-site op een omgeving zónder ffmpeg/exec. Hub én Cirkels
    7 // blijven gewoon werken (die hangen niet van audio af).
     3// Lite mode: set KLONKT_AUDIO=off in .env to disable the ENTIRE audio feature —
     4// no audio/playlist/download/embed routes, no ffmpeg calls, no player, and no
     5// [[track]]/[[playlist]] shortcodes. This lets Klonkt run as a lightweight
     6// blog/photo/EPK site on environments without ffmpeg/exec. Hub and Circles
     7// keep working (they have no audio dependency).
    88//
    9 // Default = aan (volledige versie). Alleen de letterlijke waarde 'off' schakelt uit.
     9// Default = on (full version). Only the literal value 'off' disables it.
    1010export function audioEnabled() {
    1111  return String(process.env.KLONKT_AUDIO ?? 'on').toLowerCase() !== 'off';
  • src/config/google.js

    rbb42dfb r834bcc3  
    1 // Google OAuth2 voor LUISTERAARS (reageren). Per-instance: de self-hoster zet
    2 // z'n EIGEN Google-client. Zo hangt elke site aan z'n eigen Google Cloud project
    3 // — geen centrale afhankelijkheid, geen gedeelde aansprakelijkheid.
     1// Google OAuth2 for LISTENERS (commenting). Per-instance: each self-hoster sets
     2// their OWN Google client. This way every site is tied to its own Google Cloud
     3// project — no central dependency, no shared liability.
    44//
    5 // Config-bron (in deze volgorde): app_settings (ingesteld via Beheer → Instellingen),
    6 // anders de env-vars. Niet ingesteld → geen "Login met Google"-knop; de rest van
    7 // de site werkt door. Google-login geeft NOOIT beheerrechten.
     5// Config source (in this order): app_settings (set via Admin → Settings),
     6// otherwise env vars. Not configured → no "Login with Google" button; the rest
     7// of the site keeps working. Google login NEVER grants admin rights.
    88//
    9 // De redirect-URI wordt afgeleid van PUBLIC_BASE_URL (<base>/auth/google/callback),
    10 // of expliciet via GOOGLE_REDIRECT_URI. Die exacte URL moet in Google Cloud staan.
     9// The redirect URI is derived from PUBLIC_BASE_URL (<base>/auth/google/callback),
     10// or explicitly via GOOGLE_REDIRECT_URI. That exact URL must be listed in Google Cloud.
    1111
    1212import { getSetting } from '../services/SettingsService.js';
     
    1616const USERINFO_URL = 'https://openidconnect.googleapis.com/v1/userinfo';
    1717
    18 // Dynamisch lezen (UI-wijziging werkt zonder herstart). app_settings wint, env = fallback.
     18// Read dynamically (UI changes take effect without a restart). app_settings wins, env = fallback.
    1919function clientId() {
    2020  return getSetting('google_client_id', '') || process.env.GOOGLE_CLIENT_ID || '';
     
    2929}
    3030
    31 export function currentClientId() { return clientId(); } // niet-geheim, voor het formulier
     31export function currentClientId() { return clientId(); } // not secret, used for the settings form
    3232export function clientSecretSet() { return !!clientSecret(); }
    3333export function googleConfigured() {
     
    6161    body,
    6262  });
    63   if (!r.ok) throw new Error(`Google token-exchange faalde: ${r.status}`);
     63  if (!r.ok) throw new Error(`Google token exchange failed: ${r.status}`);
    6464  return r.json(); // { access_token, id_token, ... }
    6565}
     
    6868export async function fetchUserinfo(accessToken) {
    6969  const r = await fetch(USERINFO_URL, { headers: { Authorization: `Bearer ${accessToken}` } });
    70   if (!r.ok) throw new Error(`Google userinfo faalde: ${r.status}`);
     70  if (!r.ok) throw new Error(`Google userinfo failed: ${r.status}`);
    7171  return r.json();
    7272}
  • src/config/mailer.js

    rbb42dfb r834bcc3  
    1 // E-mail versturen (wachtwoord-reset, nieuwsbrief, notify). Optioneel: alleen actief
    2 // als SMTP is ingesteld — via Beheer → Instellingen (app_settings) OF env-vars.
     1// Send email (password reset, newsletter, notify). Optional: only active
     2// when SMTP is configured — via Admin → Settings (app_settings) OR env vars.
    33//
    4 // Config-bron (in deze volgorde): app_settings (ingesteld in de UI), anders env:
     4// Config source (in this order): app_settings (set via the UI), otherwise env:
    55//   SMTP_HOST, SMTP_PORT (default 587), SMTP_USER, SMTP_PASS, SMTP_FROM (default = USER)
    6 // Niet ingesteld → versturen valt terug op CLI (reset-admin) / wordt overgeslagen.
     6// Not configured → sending falls back to CLI (reset-admin) / is skipped.
    77
    88import nodemailer from 'nodemailer';
     
    2323}
    2424
    25 // Status voor de UI (zonder het wachtwoord te lekken).
     25// Status for the UI (without leaking the password).
    2626export function mailerStatus() {
    2727  const c = cfg();
     
    3333    from: c.from,
    3434    passSet: !!c.pass,
    35     // bron: handig om te tonen dat env nog actief is
     35    // source: useful to show that env vars are still active
    3636    fromEnv: !getSetting('smtp_host', '') && !!process.env.SMTP_HOST,
    3737  };
    3838}
    3939
    40 // Transport cachen, maar herbouwen zodra de config wijzigt (UI-edit zonder herstart).
     40// Cache the transport, but rebuild it whenever the config changes (UI edit without restart).
    4141let _transport = null, _key = null;
    4242function transport() {
     
    4747      host: c.host,
    4848      port: c.port,
    49       secure: c.port === 465, // 465 = impliciete TLS; 587 = STARTTLS
     49      secure: c.port === 465, // 465 = implicit TLS; 587 = STARTTLS
    5050      auth: { user: c.user, pass: c.pass },
    5151    });
     
    5656
    5757export async function sendMail({ to, subject, text, html }) {
    58   if (!mailerConfigured()) throw new Error('SMTP niet geconfigureerd');
     58  if (!mailerConfigured()) throw new Error('SMTP not configured');
    5959  const c = cfg();
    6060  return transport().sendMail({ from: c.from, to, subject, text, html });
Note: See TracChangeset for help on using the changeset viewer.