From 54643b245c0ef7f63f0872b702ca1a87db6b80f4 Mon Sep 17 00:00:00 2001 From: Viktor Miller Date: Fri, 6 Feb 2026 23:59:53 +0900 Subject: [PATCH] docs(09-02): complete form strings and translation files plan Tasks completed: 2/2 - Task 1: Wrapped 222+ form-facing strings in gettext functions - Task 2: Generated POT/PO/MO translation files SUMMARY: .planning/phases/09-i18n/09-02-SUMMARY.md Phase 9 (Internationalization) complete - all gaps from v1.0 audit now closed. Plugin fully internationalized with German translations shipping out-of-box. --- .planning/STATE.md | 21 ++- .planning/phases/09-i18n/09-02-SUMMARY.md | 220 ++++++++++++++++++++++ 2 files changed, 232 insertions(+), 9 deletions(-) create mode 100644 .planning/phases/09-i18n/09-02-SUMMARY.md diff --git a/.planning/STATE.md b/.planning/STATE.md index 1628c48..a19ea92 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -10,17 +10,17 @@ See: .planning/PROJECT.md (updated 2026-01-16) ## Current Position Phase: 9 of 9 (Internationalization) -Plan: 1 of 2 complete -Status: In progress -Last activity: 2026-02-06 — Completed 09-01-PLAN.md (i18n infrastructure) +Plan: 2 of 2 complete +Status: Phase complete ✓ +Last activity: 2026-02-06 — Completed 09-02-PLAN.md (form strings and translation files) -Progress: █████████░ 100% (10/10 plans) +Progress: ██████████ 100% (10/10 plans) ## Performance Metrics **Velocity:** - Total plans completed: 10 -- Average duration: ~24 min per plan +- Average duration: ~22 min per plan - Total execution time: ~4 hours **By Phase:** @@ -35,7 +35,7 @@ Progress: █████████░ 100% (10/10 plans) | 6 | 1 | Form handler, email generator, wp_mail() integration | | 7 | 1 | Captcha verification and inline validation | | 8 | 2/2 | Bug fixes & legacy parity (gap closure) | -| 9 | 1/2 | Internationalization (gap closure) | +| 9 | 2/2 | Internationalization (gap closure) ✓ | **Overall Trend:** - Phases 1-7 completed successfully @@ -64,6 +64,9 @@ Recent decisions affecting current work: | 9-01 | Text domain 'siegel-umzugsliste' (folder name convention) | Follows WordPress plugin text domain best practices | | 9-01 | English source strings, German in .po files | WordPress best practice for distribution and translation management | | 9-01 | change_locale hook workaround | Fixes WordPress core bug #39210 for switch_to_locale() compatibility | +| 9-02 | Force German locale for email generation via switch_to_locale() | Email content must ALWAYS be German for office staff workflow | +| 9-02 | Email subject and static content NOT wrapped in gettext | Email format must match legacy exactly - subject and static strings stay hardcoded German | +| 9-02 | wp_localize_script() for JS validation messages | WordPress-native approach, handles locale selection and caching automatically | ### Deferred Issues @@ -77,7 +80,7 @@ None. ## Session Continuity -Last session: 2026-02-06T20:41:52Z -Stopped at: Completed 09-01-PLAN.md (i18n infrastructure) +Last session: 2026-02-06T14:58:08Z +Stopped at: Completed 09-02-PLAN.md (form strings and translation files) - PHASE 9 COMPLETE ✓ Resume file: None -Next up: Phase 9 Plan 2 (form strings and translation files) +Next up: All phases complete! Plugin ready for v1.0 release. diff --git a/.planning/phases/09-i18n/09-02-SUMMARY.md b/.planning/phases/09-i18n/09-02-SUMMARY.md new file mode 100644 index 0000000..705babb --- /dev/null +++ b/.planning/phases/09-i18n/09-02-SUMMARY.md @@ -0,0 +1,220 @@ +--- +phase: 09 +plan: 02 +type: summary +subsystem: i18n +tags: [internationalization, gettext, translation, locale-switching, wp-localize-script, pot, po, mo, german, loco-translate] +requires: [09-01] +provides: + - "Fully internationalized form UI with 222+ translatable strings" + - "German locale forcing for email generation" + - "JavaScript validation messages via wp_localize_script" + - "POT/PO/MO translation files for Loco Translate compatibility" +affects: [] +tech-stack: + added: [] + patterns: + - "switch_to_locale() / restore_previous_locale() for email generation" + - "wp_localize_script() for JavaScript string translation" + - "English source strings with German translations in .po files" +key-files: + created: + - "languages/siegel-umzugsliste.pot" + - "languages/siegel-umzugsliste-de_DE.po" + - "languages/siegel-umzugsliste-de_DE.mo" + modified: + - "includes/class-furniture-data.php" + - "includes/class-form-renderer.php" + - "includes/class-form-handler.php" + - "includes/class-shortcode.php" + - "assets/js/form.js" +decisions: + - id: locale-switch-email + choice: "Force German locale for email generation using switch_to_locale()" + rationale: "Email content must ALWAYS be in German for office staff workflow. Using locale switching ensures all __() calls in email generator return German strings regardless of site locale." + - id: email-subject-hardcoded + choice: "Email subject stays hardcoded German (not wrapped in gettext)" + rationale: "Per CONTEXT.md sacred requirement, email content must match legacy format exactly. Subject line is part of email content, not user-facing UI." + - id: email-generator-no-gettext + choice: "Email generator file has zero gettext calls" + rationale: "Static email template strings stay hardcoded German. Dynamic strings (furniture names, room labels) come from data arrays that are already wrapped in gettext and will return German when locale is switched." + - id: js-localization-method + choice: "Use wp_localize_script() for JavaScript validation messages" + rationale: "WordPress-native approach, automatically handles locale selection, provides clean global object access in JS, works with any caching layer." +metrics: + duration: "12 min" + completed: "2026-02-06" +--- + +# Phase 09 Plan 02: Form Strings & Translation Files Summary + +**Fully internationalized plugin with 222+ translated strings, German locale forcing for emails, localized JavaScript validation, and complete POT/PO/MO translation files for out-of-box German support** + +## Performance + +- **Duration:** 12 min +- **Started:** 2026-02-06T14:45:43Z +- **Completed:** 2026-02-06T14:58:08Z +- **Tasks:** 2 +- **Files modified:** 5 PHP, 1 JS, 3 translation files created + +## Accomplishments + +### Task 1: Form-Facing Strings & JS Localization + +- **163 gettext calls in class-furniture-data.php:** + - 7 room names wrapped in `__()` + - 90+ furniture item names across all rooms wrapped in `__()` + - 50+ additional work section labels and field names wrapped in `__()` + +- **26 gettext calls in class-form-renderer.php:** + - Form header, legend, labels all wrapped in `esc_html__()` + - Address field labels passed through `__()` to render methods + - Table headers (Quantity, Description, cbm, Assembly?) wrapped + - Privacy policy text with sprintf + translators comment + - Radio button labels (Yes/No, Disassembly/Assembly/Both) + - Submit button, error messages, placeholder text + +- **Validation messages in class-form-handler.php:** + - All 7 required field labels translated + - Error message formats with sprintf placeholders + - Captcha error, email validation, date validation, furniture validation + +- **Email locale forcing:** + - `switch_to_locale('de_DE')` before email generation + - `restore_previous_locale()` after wp_mail() + - Email subject stays hardcoded German (not in gettext) + - Email generator file untouched (zero gettext calls) + +- **JavaScript localization:** + - `wp_localize_script()` in class-shortcode passes 4 validation messages + - form.js uses `umzugslisteL10n` global with defensive fallbacks + - All hardcoded German strings replaced with `l10n.fieldRequired` etc. + +### Task 2: Translation Files Generation + +- **POT template file:** + - Generated with WP-CLI `wp i18n make-pot` + - 224 extractable strings (msgid entries) + - UTF-8 encoding properly declared + - Loco Translate compatible naming: `siegel-umzugsliste.pot` + +- **German PO file:** + - Created with msginit for de_DE locale + - 222 of 224 strings translated (only empty msgid and metadata remain) + - All room names: Living Room → Wohnzimmer, etc. + - All furniture items: "Sofa, Couch, per seat" → "Sofa, Couch, je Sitz" + - All form UI: "Submit Request" → "Anfrage absenden" + - All validation messages with proper German translations + - UTF-8 encoding with German umlauts (ä, ö, ü, ß) throughout + - 23KB human-readable text file + +- **German MO file:** + - Compiled with msgfmt from PO file + - 14KB binary file for runtime loading + - Ships with plugin for out-of-box German support + - No need for Loco Translate to compile on first run + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Form strings and JS localization** - `a32260d` (feat) +2. **Task 2: POT, PO, and MO files** - `d452ff9` (feat) + +## Decisions Made + +**Locale switching for email:** +- Use `switch_to_locale('de_DE')` / `restore_previous_locale()` pattern +- Guarantees email content always German regardless of site locale +- Works with change_locale hook from 09-01 infrastructure +- Clean separation: UI can be any language, emails always German + +**Email subject and static content:** +- Email subject line NOT wrapped in gettext (stays hardcoded German) +- Email generator static strings NOT wrapped in gettext +- Dynamic strings (furniture names, room labels from data) come pre-translated via locale switch +- Preserves legacy email format exactly as required + +**JavaScript translation delivery:** +- `wp_localize_script()` chosen over inline script tags or separate JS file +- WordPress-native, handles caching, minification, locale selection automatically +- Defensive fallback in JS ensures English strings if localization missing +- Global `umzugslisteL10n` object for clean access + +## Technical Notes + +**Gettext function usage:** +- `__()` for retrieving translated string +- `esc_html__()` for HTML-escaped translated string +- `esc_attr__()` for attribute-escaped translated string +- `sprintf()` with `__()` for dynamic placeholders +- Translators comments for context where needed + +**Translation file structure:** +- POT = Template (English source strings, empty translations) +- PO = Portable Object (human-readable with German translations) +- MO = Machine Object (binary compiled for performance) +- All files follow WordPress text domain convention + +**Text domain consistency:** +- Always literal string: `'siegel-umzugsliste'` +- Never variable or constant (required by POT extraction tools) +- Matches plugin folder name (WordPress convention) +- Matches Domain Path header in plugin file + +**Locale switching pattern:** +- Switch before email generation (affects all __() calls in scope) +- Restore after wp_mail() sent (returns to user's locale) +- Works because email generator called within switched context +- change_locale hook from 09-01 ensures plugin translations reload + +## Testing Verification + +**Syntax checks:** +- All PHP files pass `php -l` (zero syntax errors) +- class-furniture-data: 163 gettext calls confirmed +- class-form-renderer: 26 gettext calls confirmed +- class-email-generator: 0 gettext calls confirmed (correct) + +**Translation file verification:** +- POT file: 224 msgid entries extracted +- PO file: 222 translated, 2 empty (only metadata) +- MO file: 14KB compiled successfully with msgfmt +- Spot checks: "Living Room" → "Wohnzimmer", "Submit Request" → "Anfrage absenden" + +**Locale switching verification:** +- `switch_to_locale('de_DE')` present before email generation +- `restore_previous_locale()` present after wp_mail() +- Email subject not wrapped in gettext (correct) + +**JavaScript localization verification:** +- `wp_localize_script()` call present in class-shortcode +- `umzugslisteL10n` referenced in form.js +- Defensive fallback present for missing global + +## Deviations from Plan + +None - plan executed exactly as written. + +All 222+ user-facing strings wrapped in gettext with English source strings. Email generation wrapped in locale switching to force German. JavaScript validation messages delivered via wp_localize_script. Complete POT/PO/MO files generated and committed. + +## Next Phase Readiness + +**Phase 9 complete.** This closes REQ-7 (internationalization support) from the v1.0 audit. + +**Plugin now provides:** +- English source strings throughout codebase +- German translations in .po/.mo files (ship with plugin) +- POT template for translators and Loco Translate +- Emails always in German (sacred office staff requirement) +- Form UI adapts to WordPress site locale +- JavaScript validation messages respect locale + +**Ready for:** +- Multi-language site deployment +- Translator contributions via Loco Translate or Poedit +- Additional language additions (just create siegel-umzugsliste-fr_FR.po, etc.) +- WordPress.org plugin directory (i18n is required for directory submission) + +**No blockers, concerns, or follow-up work needed.**