Internationalization & Language Routing
PLANOVI serves clean bilingual experiences tailored for Polish (pl) and English (en) speaking users. The translation framework is designed with lightweight PHP architecture, zero heavy runtime dependencies, and instant response times.
1. Internationalization Architecture (i18n.php)
The core translation engine is encapsulated in i18n.php.
flowchart TD
Req["Incoming HTTP Request"] --> CheckQuery{"?lang=pl or ?lang=en in URL?"}
CheckQuery -->|Yes| SetSession["Update $_SESSION['lang'] & Cookie"]
CheckQuery -->|No| CheckSession{"$_SESSION['lang'] exists?"}
CheckSession -->|Yes| UseSession["Use Session Language"]
CheckSession -->|No| CheckBrowser{"Inspect HTTP_ACCEPT_LANGUAGE"}
CheckBrowser -->|Starts with 'pl'| UsePL["Default to 'pl'"]
CheckBrowser -->|Other| UseEN["Default to 'en'"]
SetSession --> LoadDict["Load lang/{current_lang}.json"]
UseSession --> LoadDict
UsePL --> LoadDict
UseEN --> LoadDict
LoadDict --> Helper["Expose __($key) helper function"]
Helper --> Render["SSR Template Rendering (index.php, docs.php, etc.)"]
2. Language Detection Hierarchy
When a user visits the webpage, the language is resolved in the following priority order:
- Explicit URL Parameter:
?lang=plor?lang=enoverrides everything. When present, it updates$_SESSION['lang']to persist across page navigations. - Session Storage: If no parameter is passed, the active PHP session variable
$_SESSION['lang']is used. - Browser Accept-Language Header: On the first visit without a session,
$_SERVER['HTTP_ACCEPT_LANGUAGE']is parsed. If it begins withpl, Polish is selected; otherwise, English (en) is used. - Fallback: If all checks fail or an invalid code is supplied, the system defaults to Polish (
pl).
3. Translation Helper __()
Translations are stored in JSON dictionaries:
lang/pl.json(Polish strings)lang/en.json(English strings)
Function Signature:
function __($key, $default = '') { global $translations;
$keys = explode('.', $key); $val = $translations; foreach ($keys as $k) { if (isset($val[$k])) { $val = $val[$k]; } else { return !empty($default) ? $default : $key; } } return $val;}Key Resolution Example:
Given the key 'hero.title', __() traverses $translations['hero']['title']. If the key is missing in the active locale dictionary, it safely falls back to the requested key string itself.
4. Language Switcher UI Integration
The navigation bar (components/navbar.php) exposes an intuitive language toggle:
<div class="lang-switcher"> <a href="?lang=pl" class="<?= $current_lang === 'pl' ? 'active' : '' ?>">PL</a> <span>|</span> <a href="?lang=en" class="<?= $current_lang === 'en' ? 'active' : '' ?>">EN</a></div>The active language receives the .active CSS class with accent highlighting.
5. Adding New Translation Keys
When contributing new marketing features or landing page sections:
- Open
lang/pl.jsonand add the Polish copy:"new_feature": {"title": "Nowa Funkcjonalność","description": "Opis funkcji w języku polskim."} - Mirror the exact same key structure in
lang/en.json:"new_feature": {"title": "New Feature","description": "Description of the feature in English."} - Use in PHP templates:
<h2><?= __('new_feature.title') ?></h2><p><?= __('new_feature.description') ?></p>