AtelierCMS: multilingual routing without a framework
The client has content in German, French, and Italian. The requirement: /de/ausstellungen, /fr/expositions, /it/mostre all resolve to the same template with the right language loaded. Clean URLs, no query strings.
Solution: a single lang.php router sitting behind an .htaccess rewrite rule.
RewriteRule ^(de|fr|it)/(.*)$ /lang.php?lang=$1&path=$2 [QSA,L]
// lang.php
$lang = in_array($_GET['lang'] ?? '', ['de', 'fr', 'it']) ? $_GET['lang'] : 'de';
$path = preg_replace('/[^a-z0-9\-\/]/', '', $_GET['path'] ?? '');
define('LANG', $lang);
define('CONTENT_PATH', __DIR__ . "/content/{$lang}/{$path}");
require __DIR__ . '/routes.php';
The content files are just JSON per language: content/de/ausstellungen.json, content/fr/expositions.json. The template is language-agnostic — it receives an array and renders it.
What I did not do: automatic redirect based on browser Accept-Language. Clients asked for it; I said no. That way leads to users being silently rerouted to a language they didn’t pick, and support tickets.
The slug-translation table (ausstellungen → expositions → mostre) lives in one file. When a new page is added, one entry in the table is enough.