feat(02-registration-dictionary-phrases): dictionary-backed registration text

Phase 2 complete:

- Seed registration dictionary phrases

- Update public and admin registration templates to use translations

- Document PAUL plan, apply, summary, and changelog
This commit is contained in:
2026-04-24 21:35:17 +02:00
parent 2cf4715914
commit 6ef8b0029d
13 changed files with 1033 additions and 189 deletions

View File

@@ -0,0 +1,226 @@
-- Dictionary phrase seed for XXXV Konferencja registration labels.
-- Safe to run more than once: each INSERT checks for an existing Polish key.
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_yes', 'pl', 'Tak'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_yes' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_no', 'pl', 'Nie'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_no' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_missing', 'pl', 'brak'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_missing' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_invoice_data', 'pl', 'Dane do wystawienia faktury'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_invoice_data' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_participant_data', 'pl', 'Dane uczestnika'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_participant_data' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_institution_data', 'pl', 'Dane instytucji'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_institution_data' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_presentation_data', 'pl', 'Dane wystąpienia'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_presentation_data' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_submit_talk', 'pl', 'Zgłaszam referat'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_submit_talk' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_submit_poster', 'pl', 'Zgłaszam poster'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_submit_poster' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_topic', 'pl', 'Temat'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_topic' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_abstract', 'pl', 'Streszczenie'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_abstract' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_author', 'pl', 'Autor'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_author' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_amount_information', 'pl', 'Informacja o kwocie do zapłaty'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_amount_information' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_selected_options', 'pl', 'Wybrane opcje'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_selected_options' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_fee_discount_2026', 'pl', 'Opłata obniżona (płatność do 03.10.2026)'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_fee_discount_2026' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_fee_normal_2026', 'pl', 'Opłata zwykła (płatność po 03.10.2026)'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_fee_normal_2026' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_net_price', 'pl', 'Cena netto'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_net_price' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_net_price_no_vat', 'pl', 'Cena netto (bez VAT)'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_net_price_no_vat' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_gross_price', 'pl', 'Cena brutto'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_gross_price' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_gross_price_vat', 'pl', 'Cena brutto (z VAT)'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_gross_price_vat' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_total_to_pay', 'pl', 'Razem do zapłaty'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_total_to_pay' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_full_conference_label', 'pl', 'Cała konferencja'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_full_conference_label' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_participation_full_cta', 'pl', 'Biorę udział w całej konferencji'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_participation_full_cta' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_participation_one_day_lodging_cta', 'pl', 'Biorę udział w jednym dniu konferencji (z noclegiem)'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_participation_one_day_lodging_cta' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_participation_one_day_no_lodging_cta', 'pl', 'Biorę udział w jednym dniu konferencji (bez noclegu)'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_participation_one_day_no_lodging_cta' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_participation_full', 'pl', 'cała konferencja'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_participation_full' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_participation_one_day_lodging', 'pl', 'jeden dzień konferencji (z noclegiem)'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_participation_one_day_lodging' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_participation_one_day_no_lodging', 'pl', 'jeden dzień konferencji (bez noclegu)'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_participation_one_day_no_lodging' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_select_day', 'pl', 'Proszę zaznaczyć dzień'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_select_day' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_selected_presence_days', 'pl', 'Wskazane dni obecności'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_selected_presence_days' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_full_conference_presence', 'pl', 'Obecność podczas całej konferencji.'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_full_conference_presence' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_single_room_surcharge', 'pl', 'Dopłata do pokoju 1-osobowego'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_single_room_surcharge' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_accompanying_driver_fee', 'pl', 'Opłata za pobyt osoby towarzyszącej lub kierowcy w pokoju dwuosobowym'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_accompanying_driver_fee' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_accompanying_driver', 'pl', 'Osoba towarzysząca/kierowca'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_accompanying_driver' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_participation_preferences', 'pl', 'Udział i preferencje'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_participation_preferences' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_diet_preferences', 'pl', 'Preferencje żywieniowe'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_diet_preferences' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_diet_standard', 'pl', 'dieta standardowa'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_diet_standard' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_diet_special', 'pl', 'dieta specjalna'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_diet_special' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_diet_standard_short', 'pl', 'standardowa'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_diet_standard_short' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_diet_special_short', 'pl', 'specjalna'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_diet_special_short' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_diet_which', 'pl', 'Jaka?'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_diet_which' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_conference_price', 'pl', 'Cena za konferencję'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_conference_price' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_consents_expressed', 'pl', 'Wyrażono zgody'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_consents_expressed' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_consent_data', 'pl', 'Zgoda na przetwarzanie danych'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_consent_data' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_consent_image', 'pl', 'Zgoda na przetwarzanie wizerunku'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_consent_image' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_selected_participation_option', 'pl', 'Wybrana opcja udziału'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_selected_participation_option' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_participation_type', 'pl', 'Typ udziału'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_participation_type' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_days', 'pl', 'Dni'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_days' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_diet', 'pl', 'Dieta'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_diet' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_payment_status', 'pl', 'Status opłaty'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_payment_status' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_paid', 'pl', 'opłacone'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_paid' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_unpaid', 'pl', 'nie opłacone'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_unpaid' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_edit', 'pl', 'edytuj'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_edit' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_delete', 'pl', 'usuń'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_delete' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_cancel', 'pl', 'Anuluj'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_cancel' AND lang = 'pl');
INSERT INTO mf_dictionary (keyword, lang, replacement)
SELECT 'registration_save', 'pl', 'Zapisz'
WHERE NOT EXISTS (SELECT 1 FROM mf_dictionary WHERE keyword = 'registration_save' AND lang = 'pl');

View File

@@ -0,0 +1,200 @@
<?php
/**
* One-off dictionary phrase seed for XXXV Konferencja registration labels.
*
* Usage:
* - Browser: /_rejestracja/sql/apply-2026-04-24-registration-dictionary-phrases.php?run=20260424
* - CLI: php apply-2026-04-24-registration-dictionary-phrases.php --run
*
* Remove this file from the server after a successful production run.
*/
ini_set('display_errors', 1);
error_reporting(E_ALL);
$phrases = array(
'registration_yes' => 'Tak',
'registration_no' => 'Nie',
'registration_missing' => 'brak',
'registration_invoice_data' => 'Dane do wystawienia faktury',
'registration_participant_data' => 'Dane uczestnika',
'registration_institution_data' => 'Dane instytucji',
'registration_presentation_data' => 'Dane wystąpienia',
'registration_submit_talk' => 'Zgłaszam referat',
'registration_submit_poster' => 'Zgłaszam poster',
'registration_topic' => 'Temat',
'registration_abstract' => 'Streszczenie',
'registration_author' => 'Autor',
'registration_amount_information' => 'Informacja o kwocie do zapłaty',
'registration_selected_options' => 'Wybrane opcje',
'registration_fee_discount_2026' => 'Opłata obniżona (płatność do 03.10.2026)',
'registration_fee_normal_2026' => 'Opłata zwykła (płatność po 03.10.2026)',
'registration_net_price' => 'Cena netto',
'registration_net_price_no_vat' => 'Cena netto (bez VAT)',
'registration_gross_price' => 'Cena brutto',
'registration_gross_price_vat' => 'Cena brutto (z VAT)',
'registration_total_to_pay' => 'Razem do zapłaty',
'registration_full_conference_label' => 'Cała konferencja',
'registration_participation_full_cta' => 'Biorę udział w całej konferencji',
'registration_participation_one_day_lodging_cta' => 'Biorę udział w jednym dniu konferencji (z noclegiem)',
'registration_participation_one_day_no_lodging_cta' => 'Biorę udział w jednym dniu konferencji (bez noclegu)',
'registration_participation_full' => 'cała konferencja',
'registration_participation_one_day_lodging' => 'jeden dzień konferencji (z noclegiem)',
'registration_participation_one_day_no_lodging' => 'jeden dzień konferencji (bez noclegu)',
'registration_select_day' => 'Proszę zaznaczyć dzień',
'registration_selected_presence_days' => 'Wskazane dni obecności',
'registration_full_conference_presence' => 'Obecność podczas całej konferencji.',
'registration_single_room_surcharge' => 'Dopłata do pokoju 1-osobowego',
'registration_accompanying_driver_fee' => 'Opłata za pobyt osoby towarzyszącej lub kierowcy w pokoju dwuosobowym',
'registration_accompanying_driver' => 'Osoba towarzysząca/kierowca',
'registration_participation_preferences' => 'Udział i preferencje',
'registration_diet_preferences' => 'Preferencje żywieniowe',
'registration_diet_standard' => 'dieta standardowa',
'registration_diet_special' => 'dieta specjalna',
'registration_diet_standard_short' => 'standardowa',
'registration_diet_special_short' => 'specjalna',
'registration_diet_which' => 'Jaka?',
'registration_conference_price' => 'Cena za konferencję',
'registration_consents_expressed' => 'Wyrażono zgody',
'registration_consent_data' => 'Zgoda na przetwarzanie danych',
'registration_consent_image' => 'Zgoda na przetwarzanie wizerunku',
'registration_selected_participation_option' => 'Wybrana opcja udziału',
'registration_participation_type' => 'Typ udziału',
'registration_days' => 'Dni',
'registration_diet' => 'Dieta',
'registration_payment_status' => 'Status opłaty',
'registration_paid' => 'opłacone',
'registration_unpaid' => 'nie opłacone',
'registration_edit' => 'edytuj',
'registration_delete' => 'usuń',
'registration_cancel' => 'Anuluj',
'registration_save' => 'Zapisz',
);
$isCli = PHP_SAPI === 'cli';
$approved = $isCli
? in_array('--run', $argv, true)
: (isset($_GET['run']) && $_GET['run'] === '20260424');
header_safe('Content-Type: text/plain; charset=utf-8');
if (!$approved) {
echo "DRY RUN ONLY\n";
echo "To apply dictionary seed, run with ?run=20260424 in browser or --run in CLI.\n";
echo "No database changes were made.\n";
exit;
}
$configPath = __DIR__ . '/../core/config/Strona/db.config.ini';
if (!is_file($configPath)) {
fail("Config file not found: " . $configPath);
}
$config = parse_ini_file($configPath, true);
if (!isset($config['db'])) {
fail("Missing [db] section in config.");
}
$dbConfig = $config['db'];
foreach (array('prodHost', 'prodUser', 'prodPass', 'prodDb') as $key) {
if (!array_key_exists($key, $dbConfig)) {
fail("Missing db config key: " . $key);
}
}
$mysqli = new mysqli(
$dbConfig['prodHost'],
$dbConfig['prodUser'],
$dbConfig['prodPass'],
$dbConfig['prodDb']
);
if ($mysqli->connect_errno) {
fail("MySQL connection failed: " . $mysqli->connect_error);
}
$mysqli->set_charset('utf8');
$langs = get_dictionary_langs($mysqli);
echo "Applying dictionary phrase seed...\n";
echo "Languages: " . implode(', ', $langs) . "\n";
$inserted = 0;
$skipped = 0;
foreach ($phrases as $keyword => $replacementPl) {
foreach ($langs as $lang) {
if (dictionary_phrase_exists($mysqli, $keyword, $lang)) {
$skipped++;
continue;
}
$replacement = $lang === 'pl' ? $replacementPl : $lang . '_' . $keyword;
insert_dictionary_phrase($mysqli, $keyword, $lang, $replacement);
$inserted++;
}
}
echo "Dictionary seed complete.\n";
echo "Inserted: " . $inserted . "\n";
echo "Skipped: " . $skipped . "\n";
$mysqli->close();
function get_dictionary_langs(mysqli $mysqli) {
$langs = array('pl');
$result = $mysqli->query("SELECT DISTINCT lang FROM mf_dictionary WHERE lang <> ''");
if (!$result) {
fail("Could not load dictionary languages: " . $mysqli->error);
}
while ($row = $result->fetch_assoc()) {
if (!in_array($row['lang'], $langs, true)) {
$langs[] = $row['lang'];
}
}
return $langs;
}
function dictionary_phrase_exists(mysqli $mysqli, $keyword, $lang) {
$stmt = $mysqli->prepare("SELECT COUNT(*) AS cnt FROM mf_dictionary WHERE keyword = ? AND lang = ?");
if (!$stmt) {
fail("Prepare failed: " . $mysqli->error);
}
$stmt->bind_param('ss', $keyword, $lang);
if (!$stmt->execute()) {
fail("Dictionary check failed: " . $stmt->error);
}
$result = $stmt->get_result();
$row = $result->fetch_assoc();
$stmt->close();
return isset($row['cnt']) && (int)$row['cnt'] > 0;
}
function insert_dictionary_phrase(mysqli $mysqli, $keyword, $lang, $replacement) {
$stmt = $mysqli->prepare("INSERT INTO mf_dictionary (keyword, lang, replacement) VALUES (?, ?, ?)");
if (!$stmt) {
fail("Prepare failed: " . $mysqli->error);
}
$stmt->bind_param('sss', $keyword, $lang, $replacement);
if (!$stmt->execute()) {
fail("Insert failed for " . $keyword . " / " . $lang . ": " . $stmt->error);
}
$stmt->close();
}
function fail($message) {
echo "ERROR: " . $message . "\n";
exit(1);
}
function header_safe($header) {
if (!headers_sent() && PHP_SAPI !== 'cli') {
header($header);
}
}