--- phase: 15-locale-detection-routing plan: 02 type: execute wave: 2 depends_on: ["15-01"] files_modified: - themes/quotify/partials/header.htm - themes/quotify/partials/language-switcher.htm - themes/quotify/layouts/default.htm - themes/quotify/layouts/dashboard.htm - themes/quotify/layouts/empty.htm - themes/quotify/assets/css/components/language-switcher.css - themes/quotify/assets/css/app.css autonomous: true must_haves: truths: - "Language switcher dropdown visible in header" - "Clicking language option switches locale and reloads page" - "Current language name shown in native form (Polski, Deutsch, English)" - "All pages have hreflang tags for SEO" artifacts: - path: "themes/quotify/partials/language-switcher.htm" provides: "Dropdown language switcher UI" contains: "data-request=\"localePicker::onSwitchLocale\"" - path: "themes/quotify/partials/header.htm" provides: "Header with language switcher" contains: "language-switcher" - path: "themes/quotify/layouts/default.htm" provides: "Layout with hreflang and LocalePicker" contains: "alternateHrefLangElements" key_links: - from: "themes/quotify/partials/language-switcher.htm" to: "localePicker::onSwitchLocale" via: "data-request attribute" pattern: "data-request.*localePicker::onSwitchLocale" - from: "themes/quotify/layouts/default.htm" to: "AlternateHrefLangElements component" via: "component registration" pattern: "\\[localePicker\\]|\\[alternateHrefLangElements\\]" --- Create language switcher UI in header and integrate hreflang tags for SEO across all layouts. Purpose: Enable users to switch languages via visible dropdown in header, with proper SEO markup for search engines. Output: Language switcher partial, updated header, hreflang integration in all layouts @/home/jin/.claude/get-shit-done/workflows/execute-plan.md @/home/jin/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/15-locale-detection-routing/15-CONTEXT.md @.planning/phases/15-locale-detection-routing/15-RESEARCH.md @themes/quotify/partials/header.htm @themes/quotify/layouts/default.htm @themes/quotify/layouts/dashboard.htm @themes/quotify/assets/css/app.css @plugins/golem15/translate/components/LocalePicker.php @plugins/golem15/translate/components/AlternateHrefLangElements.php Task 1: Create language switcher partial and CSS themes/quotify/partials/language-switcher.htm themes/quotify/assets/css/components/language-switcher.css themes/quotify/assets/css/app.css Create `themes/quotify/partials/language-switcher.htm`: ```twig {% set locales = localePicker.locales %} {% set activeLocale = localePicker.activeLocale %} {% set activeLocaleName = localePicker.activeLocaleName %}
``` Create `themes/quotify/assets/css/components/language-switcher.css`: ```css /* Language Switcher */ .language-switcher { position: relative; } .language-switcher-toggle { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); background: transparent; border: 1px solid var(--color-gray-200); border-radius: var(--radius-md); font-size: var(--text-sm); font-weight: 500; color: var(--color-gray-700); cursor: pointer; transition: all var(--transition-fast); } .language-switcher-toggle:hover { border-color: var(--color-gray-300); background: var(--color-gray-50); } .language-switcher-toggle:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; } .language-switcher-icon { width: 16px; height: 16px; transition: transform var(--transition-fast); } .language-switcher.open .language-switcher-icon { transform: rotate(180deg); } .language-switcher-list { position: absolute; top: 100%; right: 0; z-index: 50; min-width: 140px; margin-top: var(--space-1); padding: var(--space-1); background: var(--color-white); border: 1px solid var(--color-gray-200); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); list-style: none; opacity: 0; visibility: hidden; transform: translateY(-8px); transition: all var(--transition-fast); } .language-switcher.open .language-switcher-list { opacity: 1; visibility: visible; transform: translateY(0); } .language-switcher-option { display: block; padding: var(--space-2) var(--space-3); font-size: var(--text-sm); color: var(--color-gray-700); text-decoration: none; border-radius: var(--radius-sm); transition: all var(--transition-fast); } .language-switcher-option:hover { background: var(--color-gray-50); color: var(--color-gray-900); } .language-switcher-option.active { background: rgba(0, 102, 102, 0.08); color: var(--color-primary); font-weight: 500; } .language-switcher-option:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; } /* Mobile: Slightly larger touch targets */ @media (max-width: 768px) { .language-switcher-toggle { padding: var(--space-2); } .language-switcher-label { display: none; } .language-switcher-toggle::before { content: ''; width: 20px; height: 20px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129'/%3E%3C/svg%3E"); background-size: contain; background-repeat: no-repeat; } .language-switcher-option { padding: var(--space-3) var(--space-4); } } ``` Add import to `themes/quotify/assets/css/app.css` after other component imports: ```css @import 'components/language-switcher.css'; ``` Add JavaScript for dropdown toggle to the partial (inline script at bottom): ```html ```
Files exist and contain expected content: dropdown HTML, CSS styles, JS toggle logic Language switcher partial created with accessible dropdown, CSS styling, and toggle JavaScript
Task 2: Integrate language switcher into header themes/quotify/partials/header.htm Update `themes/quotify/partials/header.htm` to include the language switcher in the desktop navigation area, near the right side of the header. Add the language switcher partial between the nav and the mobile menu toggle: ```twig
{% partial 'language-switcher' %}
``` Add CSS for header-actions positioning (add to header.htm inline styles or ensure it exists in header CSS): The header-actions div should be positioned to the right, before the mobile menu toggle. If using flexbox on header-inner, it will naturally flow to the right. Style addition (can be inline or in existing header CSS): ```css .header-actions { display: flex; align-items: center; gap: var(--space-3); margin-left: auto; } @media (max-width: 768px) { .header-actions { order: 2; /* After logo, before menu toggle */ } } ```
Header partial includes language-switcher partial with header-actions wrapper Language switcher integrated into site header, visible on all pages
Task 3: Register components and add hreflang to all layouts themes/quotify/layouts/default.htm themes/quotify/layouts/dashboard.htm themes/quotify/layouts/empty.htm Update all three layouts to: 1. Register localePicker and alternateHrefLangElements components 2. Add hreflang output in head section For each layout, add component registration in the configuration section: ```ini [localePicker] [alternateHrefLangElements] ``` In the `` section, after the meta tags and before stylesheets, add: ```twig {% component 'alternateHrefLangElements' %} ``` This generates: ```html ``` For default.htm - add both components For dashboard.htm - add both components For empty.htm - check if it exists, add both components if present The localePicker component is needed so the language-switcher partial can access its properties (locales, activeLocale, etc.). All layouts register localePicker and alternateHrefLangElements components, and output hreflang in head All layouts have LocalePicker for switcher functionality and hreflang tags for SEO
1. Visual: Language switcher dropdown visible in header on all pages 2. Functional: Click switcher, dropdown opens with language options 3. Functional: Click a language option, page reloads in that language 4. Accessibility: Switcher focusable, Escape closes dropdown 5. SEO: View page source, confirm hreflang tags present for en, pl, de 6. Mobile: On mobile viewport, switcher shows icon only (label hidden) 7. Styling: Matches design palette (teal primary, proper spacing) - Language switcher partial exists with dropdown UI - Header displays language switcher near right side - Dropdown shows all enabled locales (English, Polski, Deutsch) - Clicking language triggers localePicker::onSwitchLocale - All layouts register localePicker and alternateHrefLangElements components - hreflang tags present in page source for all enabled locales - Responsive design: icon-only on mobile After completion, create `.planning/phases/15-locale-detection-routing/15-02-SUMMARY.md`