16 KiB
16 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, delegation
| phase | plan | type | wave | depends_on | files_modified | autonomous | delegation | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 18-en-translation | 01 | execute | 1 |
|
|
false | off |
Purpose
Phase 16 dostarczyła infrastrukturę (__(), textdomain, .pot), Phase 17 dodała bilingual pakiety + mapowanie błędów Softra. Phase 18 to jedyna faza, która wizualnie przełączy cały plugin na EN. Do tej pory użytkownik EN widzi oryginalne polskie stringi — brak .mo = brak tłumaczeń, __('Wybierz segment pojazdu', ...) zwraca polski msgid.
Output
carei-reservation-en_US.po— 157 msgstr wypełnionych profesjonalnym angielskim tłumaczeniem branży wynajmu samochodówcarei-reservation-en_US.mo— binarny plik zgodny z formatem gettext (magic bytes0x950412de, big-endian byte order)carei-reservation-en_GB.po+.mo— identyczna kopia (lub drobne różnicerentalvshire,licensevslicence— opcjonalne)- Po załadowaniu przez
load_plugin_textdomain(już wpięte w Phase 16) — wszystkie__()/esc_html__()iwp_localize_script('careiI18n')zwracają EN w localeen_*
<acceptance_criteria>
AC-1: Plik .po kompletnie przetłumaczony
Given istnieje plik `languages/carei-reservation-en_US.po`
When policzymy niepuste msgstr (`grep -c '^msgstr "[^"]' plik.po`)
Then wszystkie 157 wpisów ma wypełnione msgstr (nie-puste)
And nagłówek zawiera Language: en_US, poprawne Plural-Forms (nplurals=2; plural=(n != 1))
And msgid zawierające placeholdery `%count%`, `%name%`, `%price%`, `%status%` itp. mają je **zachowane w msgstr** (nietknięte — te same tokeny)
And msgid zawierające tagi HTML (`<strong>...</strong>`) mają je zachowane
And tłumaczenie zachowuje branżowy ton: `doba` → `day`, `oddział` → `location`, `pakiet ochronny` → `protection package`, `rezerwacja` → `reservation`, `zł` → `PLN`, itp.
AC-2: Plik .mo poprawny binarnie
Given istnieje plik `languages/carei-reservation-en_US.mo`
When otworzymy go jako binary
Then pierwsze 4 bajty to magic number `0xde120495` (little-endian) LUB `0x950412de` (big-endian)
And zawiera wszystkie tłumaczenia z .po
And daje się poprawnie sparsować przez `gettext` (WordPress i18n czyta go bez błędu)
And jest < 50 KB (typowy rozmiar dla 157 wpisów)
AC-3: EN UI działa po uploadzie
Given administrator ustawił Polylang locale na en_US albo en_GB
When użytkownik otwiera stronę w EN
Then modal rezerwacji ma WSZYSTKIE etykiety po angielsku (segment, dates, location, protection packages, booking summary, success)
And hero search form po angielsku
And widgety (mapa, grid miast, grid oddziałów) po angielsku gdzie są stringi UI
And wp-admin → Rezerwacje (dla administratora z EN locale) po angielsku
And błędy z Softra API (dla znanych komunikatów) po angielsku
And pakiety ochronne pokazują wartości z pól `_en` (lub PL fallback gdy puste — z Phase 17)
</acceptance_criteria>
Task 1: Translate .pot → carei-reservation-en_US.po wp-content/plugins/carei-reservation/languages/carei-reservation-en_US.po 1. Przeczytaj `languages/carei-reservation.pot` (157 msgid, ~13.7 KB) 2. Dla każdego wpisu msgid wygeneruj angielskie tłumaczenie w msgstr: - **Ton:** profesjonalny, branża wynajmu samochodów (car rental) - **Kluczowe terminy:** - „doba" / „dób" / „doby" → `day` / `days` (bez skomplikowanej pluralizacji — EN ma tylko one/other) - „oddział" → `location` (nie `branch` — bardziej rental-naturalne) - „pakiet ochronny" → `protection package` - „rezerwacja" → `reservation` (nie `booking` — spójne z nazwą pluginu) - „Złóż zapytanie o rezerwację" → `Request a reservation` (skrócone, CTA-friendly) - „klient" → `customer` - „zł" → `PLN` - „Wyjazd zagraniczny" → `International travel` - „Zniesienie udziału" → `Deductible waiver` (jeśli gdzieś zostało) - „najemca" → `renter` - „segment pojazdu" → `vehicle segment` - „miejsce odbioru" / „miejsce zwrotu" → `pickup location` / `return location` - „politykę prywatności" → `privacy policy` - „Pakiet SOFT" → `SOFT Package` (nazwy własne bez zmian) - **Placeholdery:** tokeny typu `%name%`, `%count%`, `%price%`, `%status%`, `%days%`, `%total%`, `%unit%`, `%no%`, `%msg%`, `%perDay%`, `%min%`, `%max%`, `%label%` → **ZACHOWAJ DOKŁADNIE** jak w oryginale (nie tłumacz, nie zmieniaj kolejności placeholderów jeśli to zmieniałoby znaczenie; ale możesz zmienić kolejność słów wokół nich) - **HTML tagi:** `...` → ZACHOWAJ - **%s** (sprintf) → ZACHOWAJ 3. Zapisz jako `wp-content/plugins/carei-reservation/languages/carei-reservation-en_US.po` z nagłówkiem: ``` # English (US) translation for Carei Reservation # This file is distributed under the same license as the Carei Reservation plugin. msgid "" msgstr "" "Project-Id-Version: Carei Reservation 1.0.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-22 12:00+0000\n" "PO-Revision-Date: 2026-04-22 12:00+0000\n" "Last-Translator: Carei\n" "Language-Team: English\n" "Language: en_US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Domain: carei-reservation\n" ``` 4. Zachowaj komentarze `#:` z referencjami plik:linia (dla kontekstu tłumacza przy przyszłych zmianach) 5. Sanity check per wpis: - msgid niepuste → msgstr niepuste - `%TOKEN%` w msgid → `%TOKEN%` w msgstr (ten sam token) - `` w msgid → `` w msgstr (dokładnie ten sam tag)Unikaj:
- Dosłownego tłumaczenia słowo-w-słowo (kluczowe są frazy rental, nie słownikowe mapowania)
- Zachowywania polskich diakrytyków w EN (ąćęłńóśźż nie powinny być w msgstr)
- Tłumaczenia nazw własnych (`SOFT`, `PREMIUM`, `Carei`, `Softra`)
- Zmiany placeholderów (`%count%` → `%iloscDni%` = katastrofa w runtime)
1. Plik `carei-reservation-en_US.po` istnieje
2. `grep -c '^msgid "[^"]' plik.po` ≈ 158 (157 + header)
3. `grep -c '^msgstr "[^"]' plik.po` ≈ 158 (wszystkie wypełnione)
4. `grep -cP "[ąćęłńóśźż]" plik.po` → tylko w msgid (oryginalne PL), zero w msgstr
5. Spot-check 10 wpisów: ton angielski branżowy, placeholdery zachowane, HTML zachowany
AC-1 satysfakcjonowane.
Task 2: Kompilacja .po → .mo (+ kopia en_GB)
wp-content/plugins/carei-reservation/languages/carei-reservation-en_US.mo,
wp-content/plugins/carei-reservation/languages/carei-reservation-en_GB.po,
wp-content/plugins/carei-reservation/languages/carei-reservation-en_GB.mo
**Problem:** `msgfmt` (standardowy kompilator gettext) nie jest dostępny w systemie developera. Python `msgfmt.py` również nie dostępny.
**Rozwiązanie:** Wygeneruj plik `.mo` binarnie programistycznie. Możliwe ścieżki (wybierz dostępną):
1. **Preferowana:** Napisz tymczasowy skrypt Node.js w sandbox używający pakietu `gettext-parser` (dostępny przez npm):
```js
// Wymaga: npm i gettext-parser
const fs = require('fs');
const gp = require('gettext-parser');
const po = fs.readFileSync('carei-reservation-en_US.po');
const parsed = gp.po.parse(po);
const mo = gp.mo.compile(parsed);
fs.writeFileSync('carei-reservation-en_US.mo', mo);
```
2. **Alternatywa PHP:** Napisz własny skrypt PHP implementujący format `.mo` (magic 0x950412de, header 7×uint32, offset tables, string data). Format jest w dokumentacji gettext: https://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
- Parsuj `.po` ręcznie (rozpoznaj msgid/msgstr, unescape)
- Zbuduj binarny layout: header → offset/length tables for originals → offset/length tables for translations → string blobs (null-terminated)
- Zapisz jako binary file
3. **Loco Translate (wp-admin):** gdyby powyższe zawiodły — upload `.po` do wp-content/languages/plugins/ i niech Loco Translate w `wp-admin → Loco Translate → Plugins → Carei Reservation → en_US → Sync → Save` wygeneruje `.mo` w server-side.
**Preferuj opcję 1** (Node.js + gettext-parser) — działa deterministycznie w dev environment, bez potrzeby wp-admin.
**Po skompilowaniu en_US:**
- Skopiuj `.po` jako `carei-reservation-en_GB.po` (zmień `Language: en_US\n` → `Language: en_GB\n` w nagłówku)
- Opcjonalnie: drobne poprawki UK-english (license→licence, color→colour, itp.) — na tym etapie zostaw identyczne
- Skompiluj `.po` → `.mo` tym samym skryptem
**Weryfikacja binarnej poprawności `.mo`:**
```bash
# Pierwsze 4 bajty = magic number (little-endian 0x950412de)
xxd -l 4 carei-reservation-en_US.mo
# Powinno pokazać: 0000000: de12 0495 (le) lub 9504 12de (be)
```
1. Pliki istnieją: `en_US.po`, `en_US.mo`, `en_GB.po`, `en_GB.mo` w `languages/`
2. Rozmiar `.mo` między 5–50 KB
3. Magic number poprawny (xxd/hexdump pierwsze 4 bajty)
4. PHP sanity check (opcjonalny): `php -r "$mo=file_get_contents('path.mo'); echo bin2hex(substr($mo,0,4));"` → `de120495` lub `950412de`
AC-2 satysfakcjonowane.
- `carei-reservation-en_US.po` + `.mo` z 157 przetłumaczonymi wpisami
- `carei-reservation-en_GB.po` + `.mo` jako kopia en_US
- Po uploadzie wszystkie `__()`/`esc_html__()` + `careiI18n` w pluginie zwracają EN przy locale en_*
1. **Deploy:** wypchnij 4 nowe pliki (`carei-reservation-en_US.po`, `.mo`, `en_GB.po`, `.mo`) do `wp-content/plugins/carei-reservation/languages/` na serwer
2. **Cache:** wyczyść cache pluginu (jeśli masz WP Rocket / Autoptimize) + opcache PHP (zwykle wystarczy reboot fpm, albo `wp cache flush`)
3. **Admin panel pakietów:**
- Zaloguj się do wp-admin (jeśli twoja konto admina jest PL → zostawcie PL dla admina, albo zmień WP user locale na EN w Users → Profile → Language: English (United States))
- `Rezerwacje → Pakiety ochronne` — labele powinny być po EN (jeśli admin locale = EN)
- Uzupełnij pola EN dla SOFT i PREMIUM (np. `SOFT Protection` + `Basic damage coverage with 2000 PLN deductible`; `PREMIUM Protection` + `Full damage waiver, zero deductible`)
- Zapisz
4. **Frontend EN — modal rezerwacji:**
- Przełącz Polylang switcher na EN
- Otwórz stronę z przyciskiem → przycisk pokazuje `Request a reservation` (lub podobne)
- Modal otwiera się, WSZYSTKIE labele po angielsku: `Vehicle segment`, `From`, `To`, `Pickup location`, `Return location`, `Protection packages`, `Additional options`, `International travel`, `First name`, `Last name`, `Email`, `Phone`, `I agree to the privacy policy`, `Send request`
- Pakiety ochronne: `SOFT Protection` / `PREMIUM Protection` z angielskim opisem (z Phase 17)
- Komunikaty walidacji (spróbuj wysłać pusty form) po EN: `Enter first name`, `Enter a valid email`, itp.
- Podsumowanie → `Reservation summary`, `Subtotal`, `VAT`, `Total`, `Confirm reservation`
- Success: `Reservation confirmed`, `Order number: X`
5. **Hero search form:** `Vehicle segment`, `From`, `To`, `Pickup location`, `Check availability`
6. **Widgety:**
- Mapa Polski: tooltipy `Location: {city}`, `ul. {street}` → po EN
- Grid miast, grid oddziałów → po EN
7. **Błędy Softra:**
- Spróbuj zarezerwować niedostępny pojazd / nieprawidłową datę — komunikat po EN (z słownika Phase 17 via `__()`)
8. **DevTools sanity:**
- `window.careiI18n.selectSegment` → `"Select vehicle segment"` (lub podobne)
- `window.careiI18n.dayOne` → `"day"`, `dayOther` → `"days"` (jeśli dodałeś `dayOther` jako en-plural)
- Network: `/wp-json/carei/v1/protection-packages?lang=en` → response z EN treścią
9. **Powrót do PL:**
- Przełącz Polylang na PL
- Wszystko wraca do polskiego bez regresji (oryginał zachowany)
**Kryterium przejścia:** cała UI pluginu w EN (modal + hero + widgety + admin + error messages). Zero polskich literałów przy locale EN (poza treściami z DB które admin zostawił puste → fallback PL z Phase 17).
**Znane limitacje (NIE blokują approve):**
- Treści stron Elementora (nagłówki hero, sekcje marketingowe) — tłumaczone osobno przez Polylang addon (poza scope tej fazy)
- Menu, footer, inne treści WP — Polylang / Polylang Strings Translation (poza scope)
Napisz "approved" aby zamknąć Milestone v0.7, albo wskaż stringi które pozostały po polsku pomimo EN locale.
DO NOT CHANGE
- Żaden plik PHP/JS pluginu (Phase 16–17 już to załatwiły)
- Plik
.pot(baseline — nie nadpisujemy bazowego template) - Textdomain, mechanizm
load_plugin_textdomain(Phase 16) - Panel admina pakietów — tylko DANE w bazie mogą być wypełnione przez admina (to nie zmiana kodu)
carei-reservation.css— styling niezależny od językamu-plugins/fix-sprintf-global.php— dalej potrzebny dla Polylang addon
SCOPE LIMITS
- Nie tłumaczymy innych pluginów (tylko carei-reservation)
- Nie tłumaczymy Elementora ani treści stron (Polylang addon)
- Nie tłumaczymy nazw krajów w sekcji wyjazdu zagranicznego (dane biznesowe COUNTRY_FLAGS — pozostają po polsku bo backend tak zwraca)
- Nie tłumaczymy slugów URL, permalink structures
- Nie generujemy dodatkowych locale (fr, de, itp.) — tylko en_US + en_GB
- Nie zmieniamy generatora .pot ani pipeline-u i18n
<success_criteria>
- Task 1–2 ukończone
- Checkpoint zatwierdzony
- Milestone v0.7 — 100% complete
- Plugin carei-reservation pełnoprawnie dwujęzyczny (PL + EN) </success_criteria>