Changeset 5e61b17 in Klonkt for src/routes


Ignore:
Timestamp:
06/21/2026 03:16:51 PM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
11b3ba5
Parents:
4885eab
Message:

feat(i18n): admin-configurable language — personal + default for visitors

  • users.lang column: personal interface language per account (follows across devices/sessions). Switcher (/lang/:code) and Account select both write it.
  • app_setting default_lang: admin picks the default language for visitors in Admin → Settings (overrides env/browser; empty = automatic).
  • resolveLang priority: session choice → users.lang → default_lang (DB) → env KLONKT_DEFAULT_LANG → browser → nl.
  • Account: language select; admin-settings: default language select. NL/EN/DE keys.

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

Location:
src/routes
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/routes/account.js

    r4885eab r5e61b17  
    2626import { googleConfigured } from '../config/google.js';
    2727import { toWebp } from '../services/ImageWebpService.js';
     28import { SUPPORTED } from '../services/i18n.js';
    2829
    2930const __dirname = path.dirname(fileURLToPath(import.meta.url));
     
    6061router.get('/', requireAuth, (req, res) => {
    6162  const account = db.prepare(`
    62     SELECT id, username, email, role, bio, avatar_url, created_at, password_hash, google_sub
     63    SELECT id, username, email, role, bio, avatar_url, created_at, password_hash, google_sub, lang
    6364    FROM users WHERE id = ?
    6465  `).get(req.session.user.id);
     
    8081});
    8182
     83// ==================== PERSOONLIJKE INTERFACE-TAAL ====================
     84// Slaat de taalkeuze op het account op (reist mee over apparaten/sessies) én
     85// zet 'm meteen in de sessie zodat 't direct effect heeft.
     86router.post('/lang', requireAuth, (req, res) => {
     87  const code = SUPPORTED.includes(req.body.lang) ? req.body.lang : null;
     88  if (code) {
     89    db.prepare('UPDATE users SET lang = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(code, req.session.user.id);
     90    req.session.user.lang = code;
     91    req.session.lang = code;
     92  }
     93  res.redirect('/account?success=' + encodeURIComponent('Taal opgeslagen'));
     94});
     95
    8296// De site die deze gebruiker mag bewerken vanuit z'n account: z'n eigen site
    8397// (owner_id), of voor een god de primaire site. Null als er niets is.
  • src/routes/admin-settings.js

    r4885eab r5e61b17  
    2222import { requireGod } from '../middleware/auth.js';
    2323import { getTenancy, setTenancy, getSetting, setSetting } from '../services/SettingsService.js';
     24import { SUPPORTED } from '../services/i18n.js';
    2425import { mailerStatus, sendMail } from '../config/mailer.js';
    2526import { entitlementStatus, premiumUnlocked } from '../services/PatreonService.js';
     
    7879    hubHeroImage: getSetting('hub_hero_image') || '',
    7980    hubHeroOverlay: clampOverlay(getSetting('hub_hero_overlay')),
     81    defaultLang: getSetting('default_lang') || '',
    8082    premium: entitlementStatus(),
    8183    google: {
     
    108110      }
    109111      setTenancy(req.body.tenancy); // valideert naar solo | hub | circle
     112    }
     113    if (typeof req.body.default_lang !== 'undefined') {
     114      // Standaardtaal voor bezoekers (leeg = volg env/browser). Valideert tegen NL/EN/DE.
     115      const dl = (req.body.default_lang || '').toString().toLowerCase();
     116      setSetting('default_lang', SUPPORTED.includes(dl) ? dl : '');
    110117    }
    111118    if (typeof req.body.hub_title !== 'undefined') {
  • src/routes/lang.js

    r4885eab r5e61b17  
    33import express from 'express';
    44import { SUPPORTED } from '../services/i18n.js';
     5import db from '../config/database.js';
    56
    67const router = express.Router();
     
    910  const code = SUPPORTED.includes(req.params.code) ? req.params.code : 'nl';
    1011  if (req.session) req.session.lang = code;
     12  // Ingelogd? Bewaar de keuze ook op het account zodat 'ie meereist over
     13  // apparaten/sessies (niet alleen deze sessie-cookie).
     14  if (req.session && req.session.user && req.session.user.id) {
     15    try {
     16      db.prepare('UPDATE users SET lang = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(code, req.session.user.id);
     17      req.session.user.lang = code;
     18    } catch { /* lang-kolom ontbreekt op een oude DB → sessie-only, geen breuk */ }
     19  }
    1120  // Veilige terug-URL: alleen een intern pad (geen open redirect).
    1221  let back = (typeof req.query.r === 'string') ? req.query.r : '';
Note: See TracChangeset for help on using the changeset viewer.