13 Commits

Author SHA1 Message Date
9904bf508a fix: scope admin bar offcanvas padding to mobile viewports (v1.0.12)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 1m8s
Create Release Package / Build Release (push) Successful in 1m44s
Wrap the offcanvas padding-top rule in a max-width: 991.98px media query
so it only applies when the offcanvas is active, not on wide screens
where the navbar renders inline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:43:34 +01:00
77778860ab feat: offcanvas mobile navigation with user avatar and admin bar fix (v1.0.11)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 1m13s
Create Release Package / Build Release (push) Successful in 1m56s
Switch mobile nav from collapse to offcanvas, add logged-in user avatar
and My Account link to offcanvas header, move dark mode toggle to
offcanvas footer. Fix admin bar overlapping offcanvas via inline CSS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:38:42 +01:00
0902c5e1a5 fix: decode WordPress title entities before Twig to prevent double-encoding (v1.0.10)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 1m10s
Create Release Package / Build Release (push) Successful in 1m50s
WordPress's get_the_title() pre-encodes & as &#038;. Twig autoescape
re-encoded the & in &#038; to &amp;#038;, rendering as literal &#038;
in the browser. Wrapped all 6 get_the_title() calls in ContextBuilder
with wp_specialchars_decode() so Twig can properly re-encode once.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:20:19 +01:00
1a0a1fa63a i18n: add full translations for 13 locales (v1.0.10)
- Regenerated wp-bootstrap.pot with updated extractable strings
- Translated 13 locales: de_CH, de_CH_informal, de_DE, de_DE_informal,
  en_GB, es_ES, fr_CH, fr_FR, it_CH, it_IT, nl_NL, pl_PL, pt_PT
- German variants: Swiss (ss) vs Standard (ß), formal (Sie) vs informal (du)
- All 359 translatable strings covered per locale
- Documented fast translation workflow in CLAUDE.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 12:26:36 +01:00
576922160e perf: color variation CSS transient caching and Twig auto_reload fix (v1.0.9)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 2m3s
Create Release Package / Build Release (push) Successful in 2m5s
- functions.php: cache wp_bootstrap_variation_colors() output in a 24-hour
  transient keyed by md5(get_stylesheet()); invalidate on switch_theme and
  save_post_wp_global_styles so Design Editor changes apply immediately
- TwigService.php: change auto_reload from hardcoded true to WP_DEBUG so
  Twig stops stat()-ing compiled template files on every production request

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 18:26:40 +01:00
89afa00678 security: OWASP audit and hardening (v1.0.8)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 1m8s
Create Release Package / Build Release (push) Successful in 1m53s
- Archive XSS: wrap get_the_archive_title/description with wp_kses_post()
  in ContextBuilder to sanitize Editor-editable term content rendered via |raw
- Comment fields: esc_html() on comment_author, esc_url() on comment_author_url
  at data source; template updated to output pre-escaped URL via |raw
- dark-mode.js: whitelist localStorage value against ['dark','light'] to
  prevent attribute injection from third-party script tampering
- TwigService: add is_safe=>html to esc_html/esc_attr/esc_url Twig functions
  to prevent double-encoding if autoescape is ever enabled
- Add .markdownlint.json (disable MD024 duplicate headings, MD013 line length)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 13:23:33 +01:00
876be4a041 feat: register do_shortcode() as Twig function (v1.0.7)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 1m4s
Create Release Package / Build Release (push) Successful in 1m51s
Adds do_shortcode to TwigService::registerWordPressFunctions() so child
themes and partials can render WordPress shortcodes directly inside Twig
templates via {{ do_shortcode('[shortcode]') }}.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 15:06:15 +01:00
59b79d23df use the twig footer instead of FSE editor 2026-02-15 18:50:34 +01:00
e7decbe96b fix: populate sidebar context for pages using Page with Sidebar template, use block_template_part for footer (v1.0.6)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 57s
Create Release Package / Build Release (push) Successful in 1m29s
- ContextBuilder now calls getSidebarData() when page template slug is
  'page-sidebar', fixing empty sidebar on pages with that template
- Added block_template_part() Twig function to TwigService for FSE
  Template Editor compatibility
- Changed footer rendering from include to block_template_part() so
  footer edits in the Template Editor take effect

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 21:44:45 +01:00
815f6fa19e fix: standardize translation file names and add 11 new locales (v1.0.5)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 58s
Create Release Package / Build Release (push) Successful in 1m26s
- Rename all .po files to use wp-bootstrap- prefix (WordPress convention)
- Add 11 new locale translations (de_CH_informal, de_DE, de_DE_informal,
  en_GB, es_ES, fr_CH, it_CH, it_IT, nl_NL, pl_PL, pt_PT)
- Total: 13 locales + en_US base = 14 supported languages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 17:51:18 +01:00
b285d75878 feat: add wp_bootstrap_should_render_template filter for plugin decoupling (v1.0.4)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 1m29s
Create Release Package / Build Release (push) Successful in 1m40s
Allows plugins and child themes to prevent the theme's TemplateController
from rendering specific requests, enabling clean separation of concerns.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-11 11:48:08 +01:00
e3e9b9f2be fix: make page title <h1> conditional to prevent double headings (v1.0.3)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 1m3s
Create Release Package / Build Release (push) Successful in 1m41s
When plugins inject content via TwigService with empty post.title,
the theme's <h1> is now skipped. Prevents duplicate headings on
plugin-rendered pages that provide their own titles.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-11 09:54:16 +01:00
702c0c35f4 fix: add title-tag theme support for proper <title> output (v1.0.2)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 1m14s
Create Release Package / Build Release (push) Successful in 1m42s
Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-10 16:00:10 +01:00
32 changed files with 27015 additions and 2575 deletions

3
.gitignore vendored
View File

@@ -22,6 +22,9 @@ npm-debug.log
*.bak
*.po~
# Compiled translations (built by CI/CD release workflow)
*.mo
# Claude local settings
.claude/settings.local.json

4
.markdownlint.json Normal file
View File

@@ -0,0 +1,4 @@
{
"MD024": false,
"MD013": false
}

View File

@@ -2,6 +2,95 @@
All notable changes to this project will be documented in this file.
## [1.0.12] - 2026-02-28
### Fixed
- **Admin bar offcanvas padding on desktop** (`functions.php`): Scoped the admin bar offcanvas padding fix to mobile viewports only (`max-width: 991.98px`) so the extra padding does not appear on wide screens where the offcanvas renders inline as a regular navbar.
## [1.0.11] - 2026-02-28
### Changed
- **Offcanvas mobile navigation**: Default header now uses `header-offcanvas.html.twig` instead of `header.html.twig`. Mobile navigation slides in as an offcanvas panel from the right instead of collapsing downward.
- **User avatar in offcanvas header**: When logged in, the offcanvas header displays the user's Gravatar and display name linking to the WooCommerce My Account page (or WP admin profile as fallback). Falls back to the site name when logged out.
- **Dark mode toggle repositioned**: Moved from the offcanvas body to the offcanvas footer on mobile. Desktop toggle remains in the navbar.
### Added
- **User context data** (`inc/Template/ContextBuilder.php`): New `getUserData()` method exposing `user.logged_in`, `user.display_name`, `user.avatar`, and `user.account_url` to all Twig templates.
### Fixed
- **Admin bar overlapping offcanvas** (`functions.php`): Inline CSS via `wp_add_inline_style()` adds `padding-top` matching the admin bar height to `.offcanvas` when the admin bar is visible, preventing content overlap.
## [1.0.10] - 2026-02-25
### Fixed
- **Title double-encoding in Twig templates** (`inc/Template/ContextBuilder.php`): WordPress's `get_the_title()` pre-encodes `&` as `&#038;`. When passed to Twig with autoescape enabled, the `&` in `&#038;` was escaped again to `&amp;#038;`, rendering as literal `&#038;` in the browser (e.g. "Bewerbungen &#038; Nachrichten" instead of "Bewerbungen & Nachrichten"). Fixed by wrapping all 6 `get_the_title()` calls with `wp_specialchars_decode()` to decode WordPress entities before Twig. Twig autoescape then properly re-encodes `&``&amp;`. This is XSS-safe because Twig still escapes all output.
## [1.0.9] - 2026-02-19
### Performance
- **Color variation CSS transient caching** (`functions.php`): `wp_bootstrap_variation_colors()` now caches the generated inline CSS in a 24-hour WordPress transient keyed by `wp_bootstrap_variation_css_` + an MD5 of the active stylesheet slug. Previously the palette iteration and CSS string building ran on every frontend page load. The transient is immediately invalidated on `switch_theme` and `save_post_wp_global_styles`, so changes made via the Design Editor are reflected instantly.
- **Twig template recompilation gated behind `WP_DEBUG`** (`inc/Twig/TwigService.php`): `auto_reload` in the Twig `Environment` constructor was hardcoded to `true`, causing Twig to stat every compiled template file on every request to check for source changes. Changed to `WP_DEBUG` so template recompilation only occurs during development. In production (`WP_DEBUG = false`) compiled Twig templates are served from cache without filesystem mtime checks.
## [1.0.8] - 2026-02-19
### Security
- **Archive XSS hardening**: `ContextBuilder::getArchiveData()` now wraps `get_the_archive_title()` and `get_the_archive_description()` with `wp_kses_post()`. Term descriptions are user-editable by Editors and above; without sanitization an injected `<script>` tag would execute via the `|raw` filter in `archive.html.twig`
- **Comment author XSS hardening**: `ContextBuilder::buildCommentTree()` now applies `esc_html()` to `comment_author` and `esc_url()` to `comment_author_url` at the data source, preventing injection via user-supplied comment fields
- **Dark mode localStorage whitelist**: `getPreferredTheme()` in `dark-mode.js` now validates the stored theme value against `['dark', 'light']` before use, preventing attribute injection from a tampered localStorage value written by a third-party script
- **Twig escaping functions marked safe**: `esc_html()`, `esc_attr()`, and `esc_url()` registered in `TwigService` are now declared with `['is_safe' => ['html']]`, preventing double-encoding if Twig autoescape is ever enabled
### Changed
- `views/partials/comment-item.html.twig`: Comment author URL now output via `{{ comment.author_url|raw }}` (escaped in PHP) instead of calling `esc_url()` from the template, keeping escaping logic in one place
## [1.0.7] - 2026-02-18
### Added
- `do_shortcode()` registered as a Twig function in `TwigService`, allowing shortcodes to be rendered directly from Twig templates via `{{ do_shortcode('[shortcode]') }}`
## [1.0.6] - 2026-02-14
### Fixed
- Sidebar widgets not rendered on pages using the "Page with Sidebar" template — `ContextBuilder::build()` only populated `sidebar` context for `is_home()`, so `page-sidebar.html.twig` received no widget data
## [1.0.5] - 2026-02-11
### Added
- 11 new translation files: de_CH_informal, de_DE, de_DE_informal, en_GB, es_ES, fr_CH, it_CH, it_IT, nl_NL, pl_PL, pt_PT (total: 13 locales + en_US base)
- Compiled .mo files for all 13 translations
### Changed
- Standardized all .po file names to use `wp-bootstrap-` prefix (WordPress convention: `{text-domain}-{locale}.po`)
## [1.0.4] - 2026-02-11
### Added
- `wp_bootstrap_should_render_template` filter in `TemplateController::render()` — allows plugins and child themes to prevent the theme from rendering a specific request, enabling clean separation of concerns when plugins handle their own page rendering
## [1.0.3] - 2026-02-11
### Fixed
- Double `<h1>` headings on pages where plugins provide their own titles — `page.html.twig` now wraps `<h1>` in `{% if post.title is not empty %}` guard so plugins can suppress it by passing empty `post.title`
## [1.0.2] - 2026-02-10
### Fixed
- Missing HTML `<title>` tag on all pages — theme never declared `add_theme_support('title-tag')`, so WordPress's `_wp_render_title_tag()` hook was inactive during `wp_head()` output in Twig templates
## [1.0.1] - 2026-02-09
### Added

224
CLAUDE.md
View File

@@ -34,7 +34,7 @@ This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase w
**Note for AI Assistants:** Clean this section after the specific features are done or new releases are made. Effective changes are tracked in `CHANGELOG.md`. Do not add completed versions here - document them in the Session History section at the end of this file.
Current version is **v1.0.1**. See `PLAN.md` for details.
Current version is **v1.0.11**. See `PLAN.md` for details.
## Technical Stack
@@ -77,8 +77,49 @@ Text domain: `wp-bootstrap`
- `en_US` - English (United States) [base language - .pot template]
- `de_CH` - German (Switzerland, formal)
- `de_CH_informal` - German (Switzerland, informal)
- `de_DE` - German (Germany, formal)
- `de_DE_informal` - German (Germany, informal)
- `en_GB` - English (United Kingdom)
- `es_ES` - Spanish (Spain)
- `fr_CH` - French (Switzerland)
- `fr_FR` - French (France)
- `it_CH` - Italian (Switzerland)
- `it_IT` - Italian (Italy)
- `nl_NL` - Dutch (Netherlands)
- `pl_PL` - Polish (Poland)
- `pt_PT` - Portuguese (Portugal)
There is no need to compile translation to *.mo locally as it will be done in the Gitea CD/CI pipeline
Translation file naming convention: `wp-bootstrap-{locale}.po` (e.g., `wp-bootstrap-de_CH.po`)
Compiled .mo files are built by the Gitea CI/CD pipeline during releases. For local development:
```bash
for po in languages/wp-bootstrap-*.po; do msgfmt -o "${po%.po}.mo" "$po"; done
```
#### Updating Translations
When new strings are added to PHP sources, use the fast JSON workflow documented in
`wp-jobroom-theme/CLAUDE.md → Updating Translations (Fast JSON Workflow)`. That
document contains the full step-by-step process including the `patch-po.py` patcher script
(located in `wp-jobroom-theme/languages/patch-po.py`) which patches **both** `wp-bootstrap`
and `wp-jobroom-theme` `.po` files in a single pass.
**Quick reference for wp-bootstrap POT regeneration:**
```bash
docker exec jobroom-wordpress wp i18n make-pot \
/var/www/html/wp-content/themes/wp-bootstrap \
/var/www/html/wp-content/themes/wp-bootstrap/languages/wp-bootstrap.pot \
--allow-root
# Then merge into all .po files:
for locale in de_CH de_CH_informal de_DE de_DE_informal en_GB es_ES fr_CH fr_FR it_CH it_IT nl_NL pl_PL pt_PT; do
msgmerge --update --backup=none --no-fuzzy-matching \
languages/wp-bootstrap-${locale}.po languages/wp-bootstrap.pot
done
```
### Create Releases
@@ -193,6 +234,185 @@ Build steps (in order):
## Session History
### Session 17 — v1.0.11 Offcanvas Navigation & User Context (2026-02-28)
**Completed:** Switched mobile navigation from Bootstrap collapse to offcanvas, added logged-in user context to the header, and fixed admin bar overlap.
**What was changed:**
- **Offcanvas navigation** (`views/base.html.twig`): Default header include switched from `partials/header.html.twig` (collapse) to `partials/header-offcanvas.html.twig` (offcanvas slide-in from right). The offcanvas variant already existed in the theme.
- **Offcanvas header with user avatar** (`views/partials/header-offcanvas.html.twig`): When logged in, the offcanvas header shows the user's Gravatar avatar and display name linking to the WooCommerce My Account page. Falls back to the site name when logged out.
- **Dark mode toggle repositioned**: Moved from the offcanvas body to the offcanvas footer (`d-lg-none`) on mobile. On desktop (≥lg), the toggle remains visible next to the navbar via a separate `d-none d-lg-block` wrapper.
- **User context in ContextBuilder** (`inc/Template/ContextBuilder.php`): New `getUserData()` method providing `user.logged_in`, `user.display_name`, `user.avatar` (rendered `<img>` with `rounded-circle` class), and `user.account_url` (WooCommerce My Account or WP admin profile fallback).
- **Admin bar offcanvas overlap fix** (`functions.php`): Inline CSS injected via `wp_add_inline_style()` when `is_admin_bar_showing()` is true. Adds `padding-top: var(--wp-admin--admin-bar--height, 32px)` to `.offcanvas` so the offcanvas content clears the admin bar.
**Files modified:**
- `views/base.html.twig` — header include changed to offcanvas variant
- `views/partials/header-offcanvas.html.twig` — user avatar header, dark mode toggle in footer
- `inc/Template/ContextBuilder.php``getUserData()` method, `user` key in context
- `functions.php` — admin bar offcanvas padding inline style
- `style.css` — version bump to 1.0.11
- `CHANGELOG.md` — v1.0.11 entry
**Key learnings:**
- Bootstrap offcanvas inside `navbar-expand-lg` uses `position: fixed; top: 0` which is covered by the WordPress admin bar (`z-index: 99999`). Since the offcanvas z-index (1045) is lower, adjusting `top` alone doesn't help visually — `padding-top` on the offcanvas content is the practical fix.
- `wp_add_inline_style()` bypasses file-level browser caching, making it more reliable for conditional CSS rules than editing the main stylesheet.
- WordPress's `--wp-admin--admin-bar--height` CSS custom property (set on `:root`) adjusts between 32px (desktop) and 46px (mobile ≤782px), making it the ideal value for admin bar offset calculations.
- `get_avatar()` accepts an `$args` array where CSS classes can be passed via the `class` key, avoiding post-processing of the HTML output.
### Session 16 — v1.0.10 Title Double-Encoding Fix (2026-02-25)
**Completed:** Fixed double-encoding of HTML entities in page titles rendered through Twig.
**Root cause:** WordPress's `get_the_title()` returns titles with HTML entities pre-encoded (e.g. `&``&#038;`). `ContextBuilder` passed these pre-encoded strings to Twig as template variables. Twig's autoescape then re-encoded the `&` in `&#038;` to `&amp;#038;`, which browsers rendered as the literal text `&#038;` instead of `&`. Affected all pages with `&` in their title (e.g. help pages "Bewerbungen & Nachrichten", "Konto & Sicherheit", "Abonnements & Abrechnung").
**Fix:** Wrapped all 6 `get_the_title()` calls in `ContextBuilder.php` with `wp_specialchars_decode()`. This decodes WordPress entities back to raw characters before Twig, allowing Twig autoescape to properly encode them once. XSS-safe because Twig still escapes all output.
**Files modified:**
- `inc/Template/ContextBuilder.php``wp_specialchars_decode()` on all 6 `get_the_title()` calls
- `style.css` — version bump to 1.0.10
- `CHANGELOG.md` — v1.0.10 entry
### Session 15 — v1.0.9 Performance Optimization (2026-02-19)
**Completed:** Two targeted performance fixes for production environments.
**Changes made:**
- **Color variation CSS transient caching** (`functions.php`): `wp_bootstrap_variation_colors()` now caches the generated Bootstrap CSS variable overrides in a 24-hour transient keyed by `wp_bootstrap_variation_css_` + `md5(get_stylesheet())`. Previously the palette loop and CSS string building executed on every frontend request. Transient is invalidated on `switch_theme` and `save_post_wp_global_styles` hooks so Design Editor changes apply immediately.
- **Twig `auto_reload` gated behind `WP_DEBUG`** (`inc/Twig/TwigService.php`): Hardcoded `auto_reload => true` caused Twig to `stat()` each compiled template file on every request to detect source file changes. Changed to `auto_reload => WP_DEBUG` so stat checks only occur during development. In production, compiled templates are served from cache unconditionally.
**Files modified:**
- `functions.php` — transient caching and invalidation for variation CSS
- `inc/Twig/TwigService.php``auto_reload => WP_DEBUG`
- `style.css` — version bump to 1.0.9
- `CHANGELOG.md` — v1.0.9 entry
### Session 14 — v1.0.8 Security Audit & Hardening (2026-02-19)
**Completed:** Comprehensive OWASP-aligned security audit. Two parallel background agents reviewed all PHP (functions.php, ContextBuilder, NavWalker, TemplateController, TwigService, all patterns) and JavaScript/Twig templates. Four targeted security fixes applied.
**Findings and fixes:**
- **Archive term description XSS (High)**: `get_the_archive_description()` returns raw term content editable by Editor-role users. Templates rendered it with `|raw`, creating a stored XSS path. Fixed: wrapped with `wp_kses_post()` in `ContextBuilder::getArchiveData()`. Same applied to `get_the_archive_title()`.
- **Comment author injection (Low, defense-in-depth)**: `comment_author` and `comment_author_url` were passed to Twig as raw database values. Fixed: `esc_html()` applied to author name, `esc_url()` applied to author URL in `ContextBuilder::buildCommentTree()`. Template updated to output pre-escaped URL via `|raw` rather than calling `esc_url()` in Twig.
- **Dark mode localStorage whitelist (Medium)**: `getPreferredTheme()` returned any stored value without validation, allowing attribute injection if a malicious script wrote to `localStorage`. Fixed: strict equality check against `['dark', 'light']` before trusting the stored value.
- **Twig escaping functions not marked safe (Medium)**: `esc_html()`, `esc_attr()`, `esc_url()` registered in `TwigService` lacked `['is_safe' => ['html']]`, meaning any future autoescape enablement would cause double-encoding. Fixed: all three now carry the `is_safe` declaration.
**Confirmed secure (no action needed):**
- All `|raw` filter usages for widget HTML, comment content, comment reply links, and comment forms are by-design (WordPress core output)
- Pattern files: no direct-access guards needed (loaded only via `register_block_pattern()`)
- No SQL injection vectors (`$wpdb` not used directly; all data via WordPress functions)
- `TemplateController` error handling: `\Throwable` caught, logged, and gated behind `WP_DEBUG`
- `do_shortcode()` and `wp_kses_post()` Twig functions correctly marked `is_safe`
- `wp_head()`, `wp_footer()`, `body_class()` Twig functions correctly use output buffering + `is_safe`
**Key learnings:**
- WordPress Twig themes should not enable `autoescape => 'html'` globally: `get_the_title()` applies `wptexturize()` which returns HTML entities (`&mdash;`, `&ldquo;`). Autoescape would double-encode these, corrupting post title rendering.
- `esc_url()` does more than HTML-encoding — it validates the URL scheme and strips dangerous protocols (`javascript:`, `data:`). Always use it for user-supplied URLs, even when autoescape is active.
- Registering WordPress escaping functions (`esc_url`, `esc_html`, `esc_attr`) as Twig functions without `is_safe => html` silently creates a double-encoding trap: calling `{{ esc_url(url) }}` with autoescape on would produce `&amp;amp;` instead of `&amp;`.
- Added `.markdownlint.json` disabling MD024 (duplicate headings, expected in changelogs) and MD013 (line length).
**Files modified:**
- `inc/Template/ContextBuilder.php` — archive data sanitization, comment field escaping
- `inc/Twig/TwigService.php``is_safe => html` on three escaping functions
- `views/partials/comment-item.html.twig` — use pre-escaped author URL
- `src/js/dark-mode.js` — localStorage whitelist
- `assets/js/dark-mode.js` — rebuilt compiled output
- `style.css` — version bump to 1.0.8
- `CHANGELOG.md` — v1.0.8 entry
- `.markdownlint.json` — created
### Session 13 — v1.0.5 Translation Files (2026-02-11)
**Completed:** Standardized translation file naming and added 11 new locale translations.
**What was done:**
- Renamed all .po files to use `wp-bootstrap-` prefix for WordPress text domain convention
- Previously: mixed naming (some with prefix like `wp-bootstrap-en_GB.po`, some without like `de_CH.po`)
- Now: all 13 files follow `wp-bootstrap-{locale}.po` pattern
- Compiled all 13 .po files to .mo for local development
- Added 11 new locales: de_CH_informal, de_DE, de_DE_informal, en_GB, es_ES, fr_CH, it_CH, it_IT, nl_NL, pl_PL, pt_PT
**Files renamed:**
- `de_CH.po``wp-bootstrap-de_CH.po`
- `de_CH_informal.po``wp-bootstrap-de_CH_informal.po`
- `de_DE.po``wp-bootstrap-de_DE.po`
- `de_DE_informal.po``wp-bootstrap-de_DE_informal.po`
- `es_ES.po``wp-bootstrap-es_ES.po`
- `fr_CH.po``wp-bootstrap-fr_CH.po`
- `fr_FR.po``wp-bootstrap-fr_FR.po`
- `it_CH.po``wp-bootstrap-it_CH.po`
- `it_IT.po``wp-bootstrap-it_IT.po`
- `pt_PT.po``wp-bootstrap-pt_PT.po`
**Key learnings:**
- WordPress expects translation files named `{text-domain}-{locale}.po` (e.g., `wp-bootstrap-de_CH.po`)
- `load_theme_textdomain()` loads files matching this pattern from the `languages/` directory
- Files without the text domain prefix would not be loaded by WordPress
### Session 12 — v1.0.4 Template Render Filter (2026-02-11)
**Completed:** Added `wp_bootstrap_should_render_template` filter to `TemplateController::render()` for clean plugin/theme separation.
**What was added:**
- New `wp_bootstrap_should_render_template` filter at the top of `TemplateController::render()` — returns `true` by default, but plugins can return `false` to prevent the theme from rendering a request
- Enables the wp-jobroom plugin to handle its own custom post types and routes without the theme's `TemplateController` racing to render first
- Theme remains 100% standalone — the filter is a no-op when no plugin hooks into it
**Key learnings:**
- WordPress `template_redirect` hook priority ordering is the primary mechanism for plugin/theme rendering coordination: plugin Router at priority 5, theme TemplateController at default priority 10
- Adding a simple filter check (`apply_filters('wp_bootstrap_should_render_template', true)`) is the cleanest decoupling mechanism — no cross-project class detection needed
### Session 11 — v1.0.3 Conditional Page Title (2026-02-11)
**Completed:** Made `<h1>` on page template conditional to prevent double headings when plugins provide their own titles.
**What was fixed:**
- `views/pages/page.html.twig` now wraps `<h1>{{ post.title }}</h1>` in `{% if post.title is not empty %}` guard
- When a plugin passes empty `post.title` via `render_via_theme_twig()`, the theme's `<h1>` is skipped
- Prevents duplicate headings on pages where plugin templates render their own `<h1>` with richer context (icons, badges, meta)
**Key learnings:**
- Plugins that delegate rendering to the parent theme via `TwigService` should be able to opt out of the theme's `<h1>` by passing empty `post.title`
- The `is not empty` Twig test correctly handles both `null` and empty string `''`
### Session 10 — v1.0.2 Title Tag Fix (2026-02-10)
**Completed:** Fixed missing HTML `<title>` tag on all pages rendered by the theme's Twig pipeline.
**What was fixed:**
- Added `add_theme_support('title-tag')` to `wp_bootstrap_setup()` in `functions.php`
**Root cause:**
- The theme's `base.html.twig` calls `{{ wp_head() }}` which fires the `wp_head` action
- WordPress hooks `_wp_render_title_tag()` to `wp_head` at priority 1, which outputs the `<title>` tag
- However, this hook only fires when the theme declares `add_theme_support('title-tag')`
- The theme never made this declaration, so `wp_head()` output included styles and scripts but no `<title>` element
- All pages rendered by `TemplateController` (via `base.html.twig`) were affected
**Key learnings:**
- `add_theme_support('title-tag')` is required even for themes that render `wp_head()` via Twig — WordPress does not output `<title>` without it
- The absence of a `<title>` tag is invisible in the rendered page but affects SEO, browser tab display, and bookmarking
- This support declaration has been standard since WordPress 4.1 and should always be included in `after_setup_theme`
### Session 9 — v1.0.1 Bootstrap Icons (2026-02-09)
**Completed:** Bootstrap Icons web font integration via SCSS build pipeline.

View File

@@ -17,7 +17,7 @@ A modern WordPress Block Theme built from scratch with Bootstrap 5. Features res
- **Widget Area** -- Sidebar widget area manageable via WordPress admin, with built-in fallback
- **Accessibility** -- Skip-to-content link, ARIA labels, `aria-current` on active items, screen reader announcements
- **RTL Support** -- Right-to-left language support with logical CSS properties
- **Translation Ready** -- Full i18n support with `en_US`, `de_CH`, and `fr_FR` translations
- **Translation Ready** -- Full i18n support with 14 locales (en_US, de_CH, de_CH_informal, de_DE, de_DE_informal, en_GB, es_ES, fr_CH, fr_FR, it_CH, it_IT, nl_NL, pl_PL, pt_PT)
- **Responsive** -- Mobile-first design with Bootstrap's responsive grid
## Requirements
@@ -84,7 +84,7 @@ The theme uses a dual-rendering approach:
- **Site Editor (admin):** FSE block templates in `templates/` and `parts/` for visual editing
- **Frontend (public):** Twig templates in `views/` render Bootstrap 5 HTML via the `template_redirect` hook
The `TemplateController` intercepts frontend requests and renders the appropriate Twig template with data gathered by `ContextBuilder`. FSE templates remain untouched for the WordPress admin editor.
The `TemplateController` intercepts frontend requests and renders the appropriate Twig template with data gathered by `ContextBuilder`. Plugins can hook into the `wp_bootstrap_should_render_template` filter to prevent rendering for specific requests (e.g., when a plugin handles its own custom post types). FSE templates remain untouched for the WordPress admin editor.
### Style Variation Bridge

View File

@@ -20,7 +20,9 @@
*/
function getPreferredTheme() {
var stored = localStorage.getItem(STORAGE_KEY);
if (stored) {
// Whitelist: only honour known-good values to prevent attribute injection
// from a tampered localStorage (e.g. XSS-written value by another script).
if (stored === 'dark' || stored === 'light') {
return stored;
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';

View File

@@ -23,6 +23,9 @@ if ( file_exists( get_template_directory() . '/vendor/autoload.php' ) ) {
*/
if ( ! function_exists( 'wp_bootstrap_setup' ) ) :
function wp_bootstrap_setup() {
// Add support for automatic document title tag.
add_theme_support( 'title-tag' );
// Add support for post formats.
add_theme_support( 'post-formats', array(
'aside', 'audio', 'chat', 'gallery', 'image',
@@ -80,6 +83,13 @@ if ( ! function_exists( 'wp_bootstrap_enqueue_scripts' ) ) :
$theme_version
);
// Push offcanvas below the WP admin bar when logged in.
if ( is_admin_bar_showing() ) {
wp_add_inline_style( 'wp-bootstrap-style',
'@media (max-width: 991.98px) { .offcanvas { padding-top: var(--wp-admin--admin-bar--height, 32px); } }'
);
}
// Enqueue Bootstrap JS bundle (includes Popper).
wp_enqueue_script(
'wp-bootstrap-js',
@@ -172,6 +182,17 @@ add_action( 'wp_enqueue_scripts', 'wp_bootstrap_rtl_styles', 20 );
*/
if ( ! function_exists( 'wp_bootstrap_variation_colors' ) ) :
function wp_bootstrap_variation_colors() {
$transient_key = 'wp_bootstrap_variation_css_' . md5( get_stylesheet() );
$cached_css = get_transient( $transient_key );
if ( false !== $cached_css ) {
// '' means default palette (no inline CSS needed); non-empty string is the computed CSS.
if ( '' !== $cached_css ) {
wp_add_inline_style( 'wp-bootstrap-style', $cached_css );
}
return;
}
// Read the theme origin palette — this contains the base theme.json
// colors merged with the active style variation (if any).
$theme_palette = wp_get_global_settings( array( 'color', 'palette', 'theme' ) );
@@ -202,10 +223,12 @@ if ( ! function_exists( 'wp_bootstrap_variation_colors' ) ) :
// No variation active — let Bootstrap's compiled CSS handle both modes.
if ( $is_default ) {
set_transient( $transient_key, '', DAY_IN_SECONDS );
return;
}
if ( empty( $colors['base'] ) || empty( $colors['contrast'] ) ) {
set_transient( $transient_key, '', DAY_IN_SECONDS );
return;
}
@@ -277,6 +300,9 @@ if ( ! function_exists( 'wp_bootstrap_variation_colors' ) ) :
. '[data-bs-theme=light]{' . $light_css . '}'
. '[data-bs-theme=dark]{' . $dark_css . '}';
// Cache for 24 hours; invalidated on theme switch or global-styles save.
set_transient( $transient_key, $css, DAY_IN_SECONDS );
// Attach after the compiled stylesheet so variation values override
// Bootstrap's hardcoded dark-mode defaults via source order.
wp_add_inline_style( 'wp-bootstrap-style', $css );
@@ -284,6 +310,16 @@ if ( ! function_exists( 'wp_bootstrap_variation_colors' ) ) :
endif;
add_action( 'wp_enqueue_scripts', 'wp_bootstrap_variation_colors', 30 );
/**
* Invalidate the color variation CSS transient when global styles or theme change.
*/
add_action( 'switch_theme', function () {
delete_transient( 'wp_bootstrap_variation_css_' . md5( get_stylesheet() ) );
} );
add_action( 'save_post_wp_global_styles', function () {
delete_transient( 'wp_bootstrap_variation_css_' . md5( get_stylesheet() ) );
} );
/**
* Build Bootstrap surface CSS variables for a given background/foreground pair.
*

View File

@@ -32,6 +32,7 @@ class ContextBuilder
'layout' => 'default',
'header_variant' => $this->getHeaderVariant(),
'footer_variant' => $this->getFooterVariant(),
'user' => $this->getUserData(),
];
if (is_singular()) {
@@ -69,6 +70,14 @@ class ContextBuilder
$context['sidebar'] = $this->getSidebarData();
}
// Sidebar data for pages/posts using the "Page with Sidebar" template.
if (is_page() || is_singular('post')) {
$slug = get_page_template_slug();
if ($slug === 'page-sidebar') {
$context['sidebar'] = $this->getSidebarData();
}
}
return $context;
}
@@ -85,6 +94,28 @@ class ContextBuilder
];
}
/**
* Get current user data for header/navigation.
*/
private function getUserData(): array
{
if (! is_user_logged_in()) {
return ['logged_in' => false];
}
$user = wp_get_current_user();
$account_url = function_exists('wc_get_page_permalink')
? wc_get_page_permalink('myaccount')
: admin_url('profile.php');
return [
'logged_in' => true,
'display_name' => $user->display_name,
'avatar' => get_avatar($user->ID, 32, '', '', ['class' => 'rounded-circle']),
'account_url' => $account_url,
];
}
/**
* Get navigation menu items for a location.
*/
@@ -145,7 +176,7 @@ class ContextBuilder
return [
'id' => $post->ID,
'title' => get_the_title(),
'title' => wp_specialchars_decode( get_the_title() ),
'url' => get_permalink(),
'content' => apply_filters('the_content', get_the_content()),
'excerpt' => get_the_excerpt(),
@@ -176,7 +207,7 @@ class ContextBuilder
$wp_query->the_post();
$posts[] = [
'id' => get_the_ID(),
'title' => get_the_title(),
'title' => wp_specialchars_decode( get_the_title() ),
'url' => get_permalink(),
'excerpt' => get_the_excerpt(),
'date' => get_the_date(),
@@ -237,8 +268,10 @@ class ContextBuilder
private function getArchiveData(): array
{
return [
'title' => get_the_archive_title(),
'description' => get_the_archive_description(),
// wp_kses_post() allows safe HTML (headings, links, spans) while stripping
// script/event-handler attributes that could be injected via term descriptions.
'title' => wp_kses_post(get_the_archive_title()),
'description' => wp_kses_post(get_the_archive_description()),
];
}
@@ -283,8 +316,10 @@ class ContextBuilder
$tree[] = [
'id' => (int) $comment->comment_ID,
'author' => $comment->comment_author,
'author_url' => $comment->comment_author_url,
// Escape at source — comment_author is user-supplied, store as safe text.
'author' => esc_html($comment->comment_author),
// esc_url() strips dangerous schemes (javascript:, data:) and encodes for HTML.
'author_url' => esc_url($comment->comment_author_url),
'avatar_url' => get_avatar_url($comment, ['size' => 40]),
'date' => get_comment_date('', $comment),
'date_iso' => get_comment_date('c', $comment),
@@ -337,14 +372,14 @@ class ContextBuilder
if ($prev) {
$navigation['previous'] = [
'title' => get_the_title($prev),
'title' => wp_specialchars_decode( get_the_title($prev) ),
'url' => get_permalink($prev),
];
}
if ($next) {
$navigation['next'] = [
'title' => get_the_title($next),
'title' => wp_specialchars_decode( get_the_title($next) ),
'url' => get_permalink($next),
];
}
@@ -372,7 +407,7 @@ class ContextBuilder
$query->the_post();
$posts[] = [
'id' => get_the_ID(),
'title' => get_the_title(),
'title' => wp_specialchars_decode( get_the_title() ),
'url' => get_permalink(),
'date' => get_the_date(),
'date_iso' => get_the_date('c'),
@@ -426,7 +461,7 @@ class ContextBuilder
while ($query->have_posts()) {
$query->the_post();
$posts[] = [
'title' => get_the_title(),
'title' => wp_specialchars_decode( get_the_title() ),
'url' => get_permalink(),
'date' => get_the_date(),
];

View File

@@ -37,6 +37,11 @@ class TemplateController
return;
}
// Allow plugins or child themes to prevent rendering for this request.
if (! apply_filters('wp_bootstrap_should_render_template', true)) {
return;
}
$template = $this->resolveTemplate();
if (! $template) {
return;

View File

@@ -25,9 +25,9 @@ class TwigService
$loader = new FilesystemLoader($viewsDir);
$this->twig = new Environment($loader, [
'cache' => WP_DEBUG ? false : $cacheDir,
'debug' => WP_DEBUG,
'auto_reload' => true,
'cache' => WP_DEBUG ? false : $cacheDir,
'debug' => WP_DEBUG,
'auto_reload' => WP_DEBUG,
]);
$this->registerWordPressFunctions();
@@ -73,10 +73,12 @@ class TwigService
return _n($single, $plural, $number, $domain);
}));
// Escaping functions.
$this->twig->addFunction(new TwigFunction('esc_html', 'esc_html'));
$this->twig->addFunction(new TwigFunction('esc_attr', 'esc_attr'));
$this->twig->addFunction(new TwigFunction('esc_url', 'esc_url'));
// Escaping functions — marked is_safe so Twig does not double-escape their output.
// These functions already return HTML-safe strings; without is_safe, enabling
// Twig autoescape would double-encode the result (e.g. &amp; → &amp;amp;).
$this->twig->addFunction(new TwigFunction('esc_html', 'esc_html', ['is_safe' => ['html']]));
$this->twig->addFunction(new TwigFunction('esc_attr', 'esc_attr', ['is_safe' => ['html']]));
$this->twig->addFunction(new TwigFunction('esc_url', 'esc_url', ['is_safe' => ['html']]));
// WordPress head/footer output (captured via output buffering).
$this->twig->addFunction(new TwigFunction('wp_head', function (): string {
@@ -132,10 +134,21 @@ class TwigService
return wp_kses_post($content);
}, ['is_safe' => ['html']]));
$this->twig->addFunction(new TwigFunction('do_shortcode', function (string $content): string {
return do_shortcode($content);
}, ['is_safe' => ['html']]));
// Formatting.
$this->twig->addFunction(new TwigFunction('number_format_i18n', function (float $number, int $decimals = 0): string {
return number_format_i18n($number, $decimals);
}));
// Block template parts (allows FSE Template Editor changes to take effect).
$this->twig->addFunction(new TwigFunction('block_template_part', function (string $part): string {
ob_start();
block_template_part($part);
return ob_get_clean();
}, ['is_safe' => ['html']]));
}
private function registerWordPressGlobals(): void

View File

@@ -1,919 +0,0 @@
# German (Switzerland) translation for WP Bootstrap.
# Copyright (C) 2026 Marco Graetsch
# This file is distributed under the same license as the WP Bootstrap theme.
#
msgid ""
msgstr ""
"Project-Id-Version: WP Bootstrap 0.3.0\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-bootstrap/issues\n"
"POT-Creation-Date: 2026-02-08 00:00+0000\n"
"PO-Revision-Date: 2026-02-08 00:00+0000\n"
"Last-Translator: Marco Graetsch <magdev3.0@gmail.com>\n"
"Language-Team: German (Switzerland)\n"
"Language: de_CH\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: wp-bootstrap\n"
#. Theme Name of the theme
#: patterns/footer.php
msgid "WP Bootstrap"
msgstr "WP Bootstrap"
#. Description of the theme
msgid "A modern WordPress Block Theme built from scratch with Bootstrap 5. Features responsive design, dark mode support, and full compatibility with the WordPress Site Editor."
msgstr "Ein modernes WordPress Block-Theme, erstellt mit Bootstrap 5. Mit responsivem Design, Darkmode-Unterstützung und voller Kompatibilität mit dem WordPress Site-Editor."
#: patterns/footer.php
#: patterns/footer-columns.php
msgid "Powered by %s"
msgstr "Betrieben mit %s"
#: patterns/footer.php
#: patterns/footer-columns.php
msgid "https://wordpress.org"
msgstr "https://de.wordpress.org"
#: patterns/hidden-404.php
msgid "Page not found"
msgstr "Seite nicht gefunden"
#: patterns/hidden-404.php
msgid "The page you are looking for does not exist, or it has been moved. Please try searching using the form below."
msgstr "Die gesuchte Seite existiert nicht oder wurde verschoben. Bitte verwenden Sie das untenstehende Suchformular."
#: patterns/hidden-search.php
#: patterns/hidden-sidebar.php
msgid "Search"
msgstr "Suchen"
#: patterns/hidden-search.php
#: patterns/hidden-sidebar.php
msgid "Search..."
msgstr "Suchen..."
#: patterns/hidden-blog-heading.php
msgid "Blog"
msgstr "Blog"
#: patterns/comments.php
msgid "Comments"
msgstr "Kommentare"
#: patterns/post-navigation.php
msgid "Previous"
msgstr "Zurück"
#: patterns/post-navigation.php
msgid "Next"
msgstr "Weiter"
#: patterns/more-posts.php
msgid "More posts"
msgstr "Weitere Beiträge"
#: patterns/template-query-loop.php
msgid "Read more"
msgstr "Weiterlesen"
#: patterns/template-query-loop.php
msgid "No posts were found."
msgstr "Es wurden keine Beiträge gefunden."
#: patterns/hero-cover.php
msgid "Build something amazing"
msgstr "Erstellen Sie etwas Grossartiges"
#: patterns/hero-cover.php
msgid "Create modern, responsive websites with the power of Bootstrap 5 and the WordPress Site Editor."
msgstr "Erstellen Sie moderne, responsive Websites mit der Leistung von Bootstrap 5 und dem WordPress Site-Editor."
#: patterns/hero-cover.php
#: patterns/hero-centered.php
#: patterns/pricing-3-col.php
#: patterns/page-services.php
msgid "Get Started"
msgstr "Jetzt starten"
#: patterns/hero-split.php
msgid "Modern design meets powerful features"
msgstr "Modernes Design trifft auf leistungsstarke Funktionen"
#: patterns/hero-split.php
msgid "A WordPress theme built from the ground up with Bootstrap 5 for a seamless editing and browsing experience."
msgstr "Ein WordPress-Theme, von Grund auf mit Bootstrap 5 erstellt, für ein nahtloses Bearbeitungs- und Browsing-Erlebnis."
#: patterns/hero-split.php
#: patterns/hero-centered.php
#: patterns/text-about.php
msgid "Learn More"
msgstr "Mehr erfahren"
#: patterns/hero-split.php
msgid "View Demo"
msgstr "Demo ansehen"
#: patterns/hero-split.php
msgid "Hero image"
msgstr "Heldenbild"
#: patterns/hero-centered.php
msgid "Welcome to your new website"
msgstr "Willkommen auf Ihrer neuen Website"
#: patterns/hero-centered.php
msgid "Start building beautiful, responsive pages with the full power of Bootstrap 5 and the WordPress block editor."
msgstr "Beginnen Sie mit dem Erstellen schöner, responsiver Seiten mit der vollen Leistung von Bootstrap 5 und dem WordPress Block-Editor."
#: patterns/features-3-col.php
#: functions.php
msgid "Features"
msgstr "Funktionen"
#: patterns/features-3-col.php
msgid "Everything you need to build a modern website."
msgstr "Alles, was Sie für eine moderne Website benötigen."
#: patterns/features-3-col.php
msgid "Responsive Design"
msgstr "Responsives Design"
#: patterns/features-3-col.php
msgid "Your website looks great on every device, from mobile phones to large desktop screens."
msgstr "Ihre Website sieht auf jedem Gerät grossartig aus, vom Mobiltelefon bis zum grossen Desktop-Bildschirm."
#: patterns/features-3-col.php
msgid "Easy Customization"
msgstr "Einfache Anpassung"
#: patterns/features-3-col.php
msgid "Customize colors, fonts, and layouts using the WordPress Site Editor with no code required."
msgstr "Passen Sie Farben, Schriftarten und Layouts mit dem WordPress Site-Editor an, ganz ohne Programmierung."
#: patterns/features-3-col.php
msgid "Performance First"
msgstr "Leistung zuerst"
#: patterns/features-3-col.php
msgid "Built with speed in mind. Optimized assets and clean code for lightning-fast page loads."
msgstr "Entwickelt mit Fokus auf Geschwindigkeit. Optimierte Ressourcen und sauberer Code für blitzschnelle Seitenladezeiten."
#: patterns/features-icon-list.php
msgid "Why choose us"
msgstr "Warum Sie uns wählen sollten"
#: patterns/features-icon-list.php
msgid "Bootstrap 5 Framework"
msgstr "Bootstrap 5 Framework"
#: patterns/features-icon-list.php
msgid "Built on the most popular CSS framework. Leverage a proven, well-documented design system."
msgstr "Basierend auf dem beliebtesten CSS-Framework. Nutzen Sie ein bewährtes, gut dokumentiertes Design-System."
#: patterns/features-icon-list.php
msgid "Full Site Editing"
msgstr "Vollständige Website-Bearbeitung"
#: patterns/features-icon-list.php
msgid "Edit every part of your site visually. Headers, footers, templates, and content are all customizable."
msgstr "Bearbeiten Sie jeden Teil Ihrer Website visuell. Kopfzeilen, Fusszeilen, Vorlagen und Inhalte sind vollständig anpassbar."
#: patterns/features-icon-list.php
msgid "Dark Mode Support"
msgstr "Darkmode-Unterstützung"
#: patterns/features-icon-list.php
msgid "Built-in dark mode toggle that respects user preferences and persists across visits."
msgstr "Integrierter Darkmode-Schalter, der Benutzereinstellungen respektiert und über Besuche hinweg beibehalten wird."
#: patterns/features-2-col-offset.php
msgid "Feature illustration"
msgstr "Funktionsillustration"
#: patterns/features-2-col-offset.php
msgid "Designed for modern workflows"
msgstr "Entwickelt für moderne Arbeitsabläufe"
#: patterns/features-2-col-offset.php
msgid "Streamline your development process with a theme that works the way you do."
msgstr "Optimieren Sie Ihren Entwicklungsprozess mit einem Theme, das so arbeitet wie Sie."
#: patterns/features-2-col-offset.php
msgid "Block Patterns"
msgstr "Block-Vorlagen"
#: patterns/features-2-col-offset.php
msgid "Pre-built patterns for common page sections. Drop them in and customize to fit your needs."
msgstr "Vorgefertigte Vorlagen für gängige Seitenabschnitte. Fügen Sie diese ein und passen Sie sie an Ihre Bedürfnisse an."
#: patterns/features-2-col-offset.php
msgid "Style Variations"
msgstr "Stilvariationen"
#: patterns/features-2-col-offset.php
msgid "Switch between color schemes with a single click. Choose from multiple professionally designed palettes."
msgstr "Wechseln Sie mit einem Klick zwischen Farbschemata. Wählen Sie aus mehreren professionell gestalteten Paletten."
#: patterns/cta-banner.php
msgid "Ready to get started?"
msgstr "Bereit loszulegen?"
#: patterns/cta-banner.php
msgid "Start building your website today with our powerful and flexible theme."
msgstr "Beginnen Sie noch heute mit dem Aufbau Ihrer Website mit unserem leistungsstarken und flexiblen Theme."
#: patterns/cta-banner.php
msgid "Start Now"
msgstr "Jetzt beginnen"
#: patterns/cta-newsletter.php
msgid "Stay in the loop"
msgstr "Bleiben Sie auf dem Laufenden"
#: patterns/cta-newsletter.php
msgid "Subscribe to our newsletter for updates, tips, and exclusive content."
msgstr "Abonnieren Sie unseren Newsletter für Aktualisierungen, Tipps und exklusive Inhalte."
#: patterns/cta-newsletter.php
msgid "Enter your email address"
msgstr "Geben Sie Ihre E-Mail-Adresse ein"
#: patterns/cta-newsletter.php
msgid "Subscribe"
msgstr "Abonnieren"
#: patterns/testimonials-2-col.php
msgid "What our clients say"
msgstr "Was unsere Kunden sagen"
#: patterns/testimonials-2-col.php
msgid "This theme completely transformed our website. The Bootstrap integration makes it incredibly easy to create professional-looking pages without any custom code."
msgstr "Dieses Theme hat unsere Website vollständig transformiert. Die Bootstrap-Integration macht es unglaublich einfach, professionell aussehende Seiten ohne individuellen Code zu erstellen."
#: patterns/testimonials-2-col.php
msgid "Jane Doe, Web Designer"
msgstr "Jane Doe, Webdesignerin"
#: patterns/testimonials-2-col.php
msgid "The dark mode support and style variations give us the flexibility we need. Our clients love being able to switch between color schemes effortlessly."
msgstr "Die Darkmode-Unterstützung und Stilvariationen geben uns die Flexibilität, die wir benötigen. Unsere Kunden schätzen es, mühelos zwischen Farbschemata wechseln zu können."
#: patterns/testimonials-2-col.php
msgid "John Smith, Developer"
msgstr "John Smith, Entwickler"
#: patterns/testimonials-centered.php
msgid "The best WordPress theme we have ever used. Clean code, beautiful design, and incredible flexibility."
msgstr "Das beste WordPress-Theme, das wir je verwendet haben. Sauberer Code, schönes Design und unglaubliche Flexibilität."
#: patterns/testimonials-centered.php
msgid "Alex Johnson, Creative Director"
msgstr "Alex Johnson, Kreativdirektor"
#: patterns/pricing-3-col.php
#: functions.php
msgid "Pricing"
msgstr "Preise"
#: patterns/pricing-3-col.php
msgid "Choose the plan that works best for you."
msgstr "Wählen Sie den Plan, der am besten zu Ihnen passt."
#: patterns/pricing-3-col.php
msgid "Basic"
msgstr "Basis"
#: patterns/pricing-3-col.php
msgid "Free"
msgstr "Kostenlos"
#: patterns/pricing-3-col.php
msgid "1 Website"
msgstr "1 Website"
#: patterns/pricing-3-col.php
msgid "Community Support"
msgstr "Community-Support"
#: patterns/pricing-3-col.php
msgid "Core Features"
msgstr "Kernfunktionen"
#: patterns/pricing-3-col.php
msgid "Professional"
msgstr "Professionell"
#: patterns/pricing-3-col.php
msgid "$49"
msgstr "49 $"
#: patterns/pricing-3-col.php
msgid "5 Websites"
msgstr "5 Websites"
#: patterns/pricing-3-col.php
msgid "Priority Support"
msgstr "Vorrangiger Support"
#: patterns/pricing-3-col.php
msgid "All Features"
msgstr "Alle Funktionen"
#: patterns/pricing-3-col.php
msgid "Enterprise"
msgstr "Unternehmen"
#: patterns/pricing-3-col.php
msgid "$199"
msgstr "199 $"
#: patterns/pricing-3-col.php
msgid "Unlimited Websites"
msgstr "Unbegrenzte Websites"
#: patterns/pricing-3-col.php
msgid "Dedicated Support"
msgstr "Persönlicher Support"
#: patterns/pricing-3-col.php
msgid "Custom Development"
msgstr "Individuelle Entwicklung"
#: patterns/pricing-3-col.php
#: patterns/page-services.php
#: patterns/page-contact.php
msgid "Contact Us"
msgstr "Kontaktieren Sie uns"
#: patterns/contact-info.php
msgid "Get in touch"
msgstr "Kontakt aufnehmen"
#: patterns/contact-info.php
msgid "We would love to hear from you. Reach out through any of the channels below."
msgstr "Wir freuen uns von Ihnen zu hören. Kontaktieren Sie uns über einen der folgenden Kanäle."
#: patterns/contact-info.php
#: patterns/page-contact.php
msgid "Address"
msgstr "Adresse"
#: patterns/contact-info.php
msgid "123 Example Street"
msgstr "Beispielstrasse 123"
#: patterns/contact-info.php
msgid "8000 Zurich, Switzerland"
msgstr "8000 Zürich, Schweiz"
#: patterns/contact-info.php
#: patterns/page-contact.php
msgid "Phone"
msgstr "Telefon"
#: patterns/contact-info.php
msgid "+41 44 123 45 67"
msgstr "+41 44 123 45 67"
#: patterns/contact-info.php
#: patterns/cta-newsletter.php
#: patterns/page-contact.php
msgid "Email"
msgstr "E-Mail"
#: patterns/contact-info.php
#: patterns/page-contact.php
msgid "info@example.com"
msgstr "info@example.com"
#: patterns/text-faq.php
msgid "Frequently Asked Questions"
msgstr "Häufig gestellte Fragen"
#: patterns/text-faq.php
msgid "How do I install the theme?"
msgstr "Wie installiere ich das Theme?"
#: patterns/text-faq.php
msgid "Download the ZIP file from the releases page, then upload it via WordPress Admin > Appearance > Themes > Add New > Upload Theme."
msgstr "Laden Sie die ZIP-Datei von der Release-Seite herunter und laden Sie sie über WordPress-Admin > Design > Themes > Neu hinzufügen > Theme hochladen hoch."
#: patterns/text-faq.php
msgid "Does it work with the Site Editor?"
msgstr "Funktioniert es mit dem Site-Editor?"
#: patterns/text-faq.php
msgid "Yes, this is a Full Site Editing block theme. You can customize templates, headers, footers, and all block patterns using the WordPress Site Editor."
msgstr "Ja, dies ist ein Full-Site-Editing-Block-Theme. Sie können Vorlagen, Kopfzeilen, Fusszeilen und alle Block-Vorlagen mit dem WordPress Site-Editor anpassen."
#: patterns/text-faq.php
msgid "Can I use my own fonts?"
msgstr "Kann ich eigene Schriftarten verwenden?"
#: patterns/text-faq.php
msgid "The theme comes with Inter, Lora, and system font stacks. You can add custom fonts through the Site Editor or by modifying theme.json."
msgstr "Das Theme wird mit Inter, Lora und System-Schriftarten geliefert. Sie können eigene Schriftarten über den Site-Editor oder durch Anpassung der theme.json hinzufügen."
#: patterns/text-faq.php
msgid "Is dark mode supported?"
msgstr "Wird der Darkmode unterstützt?"
#: patterns/text-faq.php
msgid "Yes, the theme includes a dark mode toggle that uses Bootstrap 5.3 built-in dark mode. It respects system preferences and remembers your choice."
msgstr "Ja, das Theme enthält einen Darkmode-Schalter, der den integrierten Darkmode von Bootstrap 5.3 verwendet. Er respektiert Systemeinstellungen und merkt sich Ihre Wahl."
#: patterns/text-about.php
msgid "About us"
msgstr "Über uns"
#: patterns/text-about.php
msgid "We are passionate about creating tools that empower people to build beautiful websites. Our theme combines the reliability of Bootstrap with the flexibility of WordPress."
msgstr "Wir sind leidenschaftlich daran interessiert, Werkzeuge zu schaffen, die Menschen befähigen, schöne Websites zu erstellen. Unser Theme vereint die Zuverlässigkeit von Bootstrap mit der Flexibilität von WordPress."
#: patterns/text-about.php
msgid "With years of experience in web development and design, we understand what it takes to create a theme that is both powerful and easy to use."
msgstr "Mit jahrelanger Erfahrung in Webentwicklung und Design verstehen wir, was nötig ist, um ein Theme zu erstellen, das sowohl leistungsstark als auch einfach zu bedienen ist."
#: patterns/text-about.php
#: patterns/page-about.php
msgid "About us image"
msgstr "Über-uns-Bild"
#: patterns/hidden-sidebar.php
msgid "Recent Posts"
msgstr "Neueste Beiträge"
#: patterns/hidden-sidebar.php
msgid "Tags"
msgstr "Schlagwörter"
#: patterns/dark-mode-toggle.php
msgid "Switch to dark mode"
msgstr "Zum Darkmode wechseln"
#: patterns/dark-mode-toggle.php
msgid "Switch to light mode"
msgstr "Zum hellen Modus wechseln"
#: functions.php
msgid "Primary Navigation"
msgstr "Primäre Navigation"
#: functions.php
msgid "Footer Navigation"
msgstr "Fusszeilen-Navigation"
#: functions.php
msgid "Pages"
msgstr "Seiten"
#: functions.php
msgid "A collection of full page layouts."
msgstr "Eine Sammlung von ganzseitigen Layouts."
#: functions.php
msgid "Hero Sections"
msgstr "Heldenabschnitte"
#: functions.php
msgid "Large hero and banner sections."
msgstr "Grosse Helden- und Banner-Abschnitte."
#: functions.php
msgid "Call to Action"
msgstr "Handlungsaufforderung"
#: functions.php
msgid "Call to action sections."
msgstr "Handlungsaufforderungs-Abschnitte."
#: functions.php
msgid "Feature and service showcase sections."
msgstr "Funktions- und Service-Präsentationsabschnitte."
#: functions.php
msgid "Testimonials"
msgstr "Referenzen"
#: functions.php
msgid "Testimonial and review sections."
msgstr "Referenz- und Bewertungsabschnitte."
#: functions.php
msgid "Pricing table sections."
msgstr "Preistabellen-Abschnitte."
#: functions.php
msgid "Contact"
msgstr "Kontakt"
#: functions.php
msgid "Contact information sections."
msgstr "Kontaktinformations-Abschnitte."
#: functions.php
msgid "Text & Content"
msgstr "Text & Inhalt"
#: functions.php
msgid "Text-focused content sections."
msgstr "Textorientierte Inhaltsabschnitte."
#: functions.php
msgid "Checkmark"
msgstr "Häkchen"
#: functions.php
msgid "Unstyled"
msgstr "Ohne Stil"
#: functions.php
msgid "Card"
msgstr "Karte"
#: functions.php
msgid "Card with Shadow"
msgstr "Karte mit Schatten"
#: functions.php
msgid "Alert - Info"
msgstr "Hinweis - Info"
#: functions.php
msgid "Alert - Success"
msgstr "Hinweis - Erfolg"
#: functions.php
msgid "Alert - Warning"
msgstr "Hinweis - Warnung"
#: functions.php
msgid "Alert - Danger"
msgstr "Hinweis - Gefahr"
#: functions.php
msgid "Striped Rows"
msgstr "Gestreifte Zeilen"
#: functions.php
msgid "Hover Rows"
msgstr "Hervorgehobene Zeilen"
#: functions.php
msgid "Bordered"
msgstr "Mit Rahmen"
#: functions.php
msgid "Accent Border"
msgstr "Akzentrahmen"
#: functions.php
msgid "Shadow"
msgstr "Schatten"
#: functions.php
msgid "Large Rounded"
msgstr "Gross abgerundet"
#: functions.php
msgid "Large"
msgstr "Gross"
#: functions.php
msgid "Small"
msgstr "Klein"
#: functions.php
msgid "Wide"
msgstr "Breit"
#: functions.php
msgid "Name"
msgstr "Name"
#: functions.php
msgid "Website"
msgstr "Website"
#: functions.php
msgid "Save my name, email, and website in this browser for the next time I comment."
msgstr "Meinen Namen, meine E-Mail-Adresse und meine Website in diesem Browser für meinen nächsten Kommentar speichern."
#: functions.php
msgid "Bootstrap Layout"
msgstr "Bootstrap-Layout"
#: functions.php
msgid "Bootstrap Components"
msgstr "Bootstrap-Komponenten"
#: functions.php
msgid "Bootstrap Navigation"
msgstr "Bootstrap-Navigation"
#: functions.php
msgid "Layout"
msgstr "Layout"
#: functions.php
msgid "Layout building blocks for page structure."
msgstr "Layout-Bausteine für die Seitenstruktur."
#: functions.php
msgid "Components"
msgstr "Komponenten"
#: functions.php
msgid "Reusable Bootstrap component patterns."
msgstr "Wiederverwendbare Bootstrap-Komponentenvorlagen."
#: functions.php
#: patterns/footer-columns.php
msgid "Navigation"
msgstr "Navigation"
#: functions.php
msgid "Navigation and header patterns."
msgstr "Navigations- und Kopfzeilenvorlagen."
#: patterns/layout-container.php
msgid "Heading goes here"
msgstr "Überschrift hier eingeben"
#: patterns/layout-container.php
msgid "This is a content container with constrained width and comfortable padding. Replace this text with your own content."
msgstr "Dies ist ein Inhaltscontainer mit begrenzter Breite und komfortablem Innenabstand. Ersetzen Sie diesen Text durch Ihren eigenen Inhalt."
#: patterns/layout-2-col.php
#: patterns/layout-3-col.php
msgid "Column One"
msgstr "Spalte Eins"
#: patterns/layout-2-col.php
msgid "Add your content here. This column takes up half the available width on larger screens and stacks on mobile devices."
msgstr "Fügen Sie hier Ihren Inhalt ein. Diese Spalte nimmt auf grösseren Bildschirmen die Hälfte der verfügbaren Breite ein und wird auf Mobilgeräten gestapelt."
#: patterns/layout-2-col.php
#: patterns/layout-3-col.php
msgid "Column Two"
msgstr "Spalte Zwei"
#: patterns/layout-3-col.php
msgid "Column Three"
msgstr "Spalte Drei"
#: patterns/layout-3-col.php
msgid "Add your content here. This column takes up one third of the available width on larger screens."
msgstr "Fügen Sie hier Ihren Inhalt ein. Diese Spalte nimmt auf grösseren Bildschirmen ein Drittel der verfügbaren Breite ein."
#: patterns/layout-full-width-section.php
msgid "Full Width Section Heading"
msgstr "Überschrift des Vollbreiten-Abschnitts"
#: patterns/layout-full-width-section.php
msgid "This full-width section stands out with a colored background. Use it to highlight important content, announcements, or calls to action."
msgstr "Dieser Vollbreiten-Abschnitt fällt durch einen farbigen Hintergrund auf. Verwenden Sie ihn, um wichtige Inhalte, Ankündigungen oder Handlungsaufforderungen hervorzuheben."
#: patterns/component-card-group.php
msgid "Card One"
msgstr "Karte Eins"
#: patterns/component-card-group.php
msgid "Card Two"
msgstr "Karte Zwei"
#: patterns/component-card-group.php
msgid "Card Three"
msgstr "Karte Drei"
#: patterns/component-card-group.php
msgid "Add a short description for this card. Cards are a great way to organize and present related content."
msgstr "Fügen Sie eine kurze Beschreibung für diese Karte hinzu. Karten sind eine hervorragende Möglichkeit, zusammengehörige Inhalte zu organisieren und zu präsentieren."
#: patterns/component-accordion.php
msgid "Accordion"
msgstr "Akkordeon"
#: patterns/component-accordion.php
msgid "Click on each item to expand and reveal its content."
msgstr "Klicken Sie auf jedes Element, um es aufzuklappen und den Inhalt anzuzeigen."
#: patterns/component-accordion.php
msgid "Accordion Item One"
msgstr "Akkordeon-Element Eins"
#: patterns/component-accordion.php
msgid "This is the content for the first accordion item. You can add any blocks inside this details element to create rich, expandable content sections."
msgstr "Dies ist der Inhalt des ersten Akkordeon-Elements. Sie können beliebige Blöcke in dieses Details-Element einfügen, um reichhaltige, aufklappbare Inhaltsabschnitte zu erstellen."
#: patterns/component-accordion.php
msgid "Accordion Item Two"
msgstr "Akkordeon-Element Zwei"
#: patterns/component-accordion.php
msgid "This is the content for the second accordion item. Details blocks are a native HTML element that provide toggle functionality without JavaScript."
msgstr "Dies ist der Inhalt des zweiten Akkordeon-Elements. Details-Blöcke sind native HTML-Elemente, die Aufklappfunktionalität ohne JavaScript bieten."
#: patterns/component-accordion.php
msgid "Accordion Item Three"
msgstr "Akkordeon-Element Drei"
#: patterns/component-accordion.php
msgid "This is the content for the third accordion item. Use accordions to organize frequently asked questions, feature lists, or any content that benefits from progressive disclosure."
msgstr "Dies ist der Inhalt des dritten Akkordeon-Elements. Verwenden Sie Akkordeons, um häufig gestellte Fragen, Funktionslisten oder andere Inhalte zu organisieren, die von schrittweiser Offenlegung profitieren."
#: patterns/page-about.php
msgid "About Us"
msgstr "Über uns"
#: patterns/page-about.php
msgid "Learn more about who we are, what we do, and the people behind our mission."
msgstr "Erfahren Sie mehr darüber, wer wir sind, was wir tun und wer hinter unserer Mission steht."
#: patterns/page-about.php
msgid "Our Story"
msgstr "Unsere Geschichte"
#: patterns/page-about.php
msgid "Founded with a passion for innovation and excellence, our journey began with a simple idea: to create meaningful solutions that make a real difference. Over the years, we have grown from a small team into a dedicated group of professionals committed to delivering outstanding results."
msgstr "Gegründet mit einer Leidenschaft für Innovation und Exzellenz, begann unsere Reise mit einer einfachen Idee: bedeutungsvolle Lösungen zu schaffen, die einen echten Unterschied machen. Im Laufe der Jahre sind wir von einem kleinen Team zu einer engagierten Gruppe von Fachleuten gewachsen, die sich der Erbringung herausragender Ergebnisse verschrieben haben."
#: patterns/page-about.php
msgid "Today, we continue to push boundaries and challenge conventions. Our approach combines creative thinking with proven methodologies, ensuring that every project we undertake meets the highest standards of quality and craftsmanship."
msgstr "Heute stossen wir weiterhin Grenzen und hinterfragen Konventionen. Unser Ansatz verbindet kreatives Denken mit bewährten Methoden und stellt sicher, dass jedes Projekt, das wir übernehmen, den höchsten Qualitäts- und Handwerksstandards entspricht."
#: patterns/page-about.php
msgid "Our Team"
msgstr "Unser Team"
#: patterns/page-about.php
msgid "Meet the people who make it all happen."
msgstr "Lernen Sie die Menschen kennen, die alles möglich machen."
#: patterns/page-about.php
msgid "Jane Doe"
msgstr "Jane Doe"
#: patterns/page-about.php
msgid "Founder & CEO"
msgstr "Gründerin & CEO"
#: patterns/page-about.php
msgid "John Smith"
msgstr "John Smith"
#: patterns/page-about.php
msgid "Lead Developer"
msgstr "Leitender Entwickler"
#: patterns/page-about.php
msgid "Emily Johnson"
msgstr "Emily Johnson"
#: patterns/page-about.php
msgid "Creative Director"
msgstr "Kreativdirektorin"
#: patterns/page-services.php
msgid "Our Services"
msgstr "Unsere Dienstleistungen"
#: patterns/page-services.php
msgid "Professional solutions tailored to your needs."
msgstr "Professionelle Lösungen, massgeschneidert auf Ihre Bedürfnisse."
#: patterns/page-services.php
msgid "What We Offer"
msgstr "Was wir anbieten"
#: patterns/page-services.php
msgid "We provide a wide range of services to help your business grow and succeed."
msgstr "Wir bieten ein breites Spektrum an Dienstleistungen, um Ihr Unternehmen beim Wachstum und Erfolg zu unterstützen."
#: patterns/page-services.php
msgid "Design"
msgstr "Design"
#: patterns/page-services.php
msgid "Beautiful, user-centered designs that capture your brand identity and engage your audience across all platforms and devices."
msgstr "Schöne, benutzerzentrierte Designs, die Ihre Markenidentität einfangen und Ihr Publikum auf allen Plattformen und Geräten ansprechen."
#: patterns/page-services.php
msgid "Development"
msgstr "Entwicklung"
#: patterns/page-services.php
msgid "Robust, scalable web applications built with modern technologies and best practices to ensure performance and reliability."
msgstr "Robuste, skalierbare Webanwendungen, erstellt mit modernen Technologien und bewährten Methoden, um Leistung und Zuverlässigkeit zu gewährleisten."
#: patterns/page-services.php
msgid "Strategy"
msgstr "Strategie"
#: patterns/page-services.php
msgid "Data-driven strategies and consulting to help you achieve your business goals and stay ahead of the competition."
msgstr "Datengetriebene Strategien und Beratung, um Ihnen zu helfen, Ihre Geschäftsziele zu erreichen und der Konkurrenz voraus zu sein."
#: patterns/page-services.php
msgid "Ready to take your project to the next level? Let us help you build something great."
msgstr "Bereit, Ihr Projekt auf die nächste Stufe zu heben? Lassen Sie uns Ihnen helfen, etwas Grossartiges zu bauen."
#: patterns/page-services.php
msgid "View Portfolio"
msgstr "Portfolio ansehen"
#: patterns/page-contact.php
msgid "We would love to hear from you. Reach out to us anytime."
msgstr "Wir freuen uns von Ihnen zu hören. Kontaktieren Sie uns jederzeit."
#: patterns/page-contact.php
msgid "Get in Touch"
msgstr "Kontakt aufnehmen"
#: patterns/page-contact.php
msgid "123 Main Street, Suite 100, Anytown, ST 12345"
msgstr "Hauptstrasse 123, Suite 100, 8000 Zürich"
#: patterns/page-contact.php
msgid "+1 (555) 123-4567"
msgstr "+41 44 123 45 67"
#: patterns/page-contact.php
msgid "Business Hours"
msgstr "Öffnungszeiten"
#: patterns/page-contact.php
msgid "Monday - Friday:"
msgstr "Montag - Freitag:"
#: patterns/page-contact.php
msgid "9:00 AM - 6:00 PM"
msgstr "09:00 - 18:00 Uhr"
#: patterns/page-contact.php
msgid "Saturday:"
msgstr "Samstag:"
#: patterns/page-contact.php
msgid "10:00 AM - 4:00 PM"
msgstr "10:00 - 16:00 Uhr"
#: patterns/page-contact.php
msgid "Sunday:"
msgstr "Sonntag:"
#: patterns/page-contact.php
msgid "Closed"
msgstr "Geschlossen"
#. translators: Copyright notice. %1$s: Year, %2$s: Site title.
#: patterns/footer-minimal.php
msgid "&copy; %1$s %2$s. All rights reserved."
msgstr "&copy; %1$s %2$s. Alle Rechte vorbehalten."
#: patterns/footer-columns.php
msgid "A modern WordPress theme built with Bootstrap 5."
msgstr "Ein modernes WordPress-Theme, erstellt mit Bootstrap 5."
#: patterns/footer-columns.php
msgid "About"
msgstr "Über"
#: patterns/footer-columns.php
msgid "This theme is proudly built with Bootstrap 5 and WordPress Full Site Editing."
msgstr "Dieses Theme wurde mit Stolz mit Bootstrap 5 und WordPress Full Site Editing erstellt."
#. translators: Copyright notice. %1$s: Year, %2$s: Site title.
#: patterns/footer-columns.php
msgid "&copy; %1$s %2$s"
msgstr "&copy; %1$s %2$s"
#: views/base.html.twig
msgid "Skip to main content"
msgstr "Zum Hauptinhalt springen"
#: views/partials/header.html.twig
#: views/partials/header-centered.html.twig
#: views/partials/header-transparent.html.twig
#: views/partials/header-offcanvas.html.twig
msgid "Primary navigation"
msgstr "Hauptnavigation"
#: views/partials/footer.html.twig
#: views/partials/footer-columns.html.twig
msgid "Footer navigation"
msgstr "Fussnavigation"
#: functions.php
msgid "Sidebar"
msgstr "Seitenleiste"
#: functions.php
msgid "Add widgets here to appear in the sidebar."
msgstr "Widgets hier hinzufuegen, um sie in der Seitenleiste anzuzeigen."
#: views/partials/sidebar.html.twig
msgid "Blog sidebar"
msgstr "Blog-Seitenleiste"

View File

@@ -1,917 +0,0 @@
# French translation for WP Bootstrap theme.
# Copyright (C) 2026 Marco Graetsch
# This file is distributed under the same license as the WP Bootstrap theme.
msgid ""
msgstr ""
"Project-Id-Version: WP Bootstrap 0.3.0\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-bootstrap/issues\n"
"POT-Creation-Date: 2026-02-08 00:00+0000\n"
"PO-Revision-Date: 2026-02-08 00:00+0000\n"
"Last-Translator: Claude AI <noreply@anthropic.com>\n"
"Language-Team: French\n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Domain: wp-bootstrap\n"
#. Theme Name of the theme
#: patterns/footer.php
msgid "WP Bootstrap"
msgstr "WP Bootstrap"
#. Description of the theme
msgid "A modern WordPress Block Theme built from scratch with Bootstrap 5. Features responsive design, dark mode support, and full compatibility with the WordPress Site Editor."
msgstr "Un theme WordPress Block moderne construit de zéro avec Bootstrap 5. Design réactif, prise en charge du mode sombre et compatibilité totale avec l'éditeur de site WordPress."
#: patterns/footer.php
#: patterns/footer-columns.php
msgid "Powered by %s"
msgstr "Propulsé par %s"
#: patterns/footer.php
#: patterns/footer-columns.php
msgid "https://wordpress.org"
msgstr "https://fr.wordpress.org"
#: patterns/hidden-404.php
msgid "Page not found"
msgstr "Page non trouvée"
#: patterns/hidden-404.php
msgid "The page you are looking for does not exist, or it has been moved. Please try searching using the form below."
msgstr "La page que vous recherchez n'existe pas ou a été déplacée. Veuillez essayer de rechercher en utilisant le formulaire ci-dessous."
#: patterns/hidden-search.php
#: patterns/hidden-sidebar.php
msgid "Search"
msgstr "Rechercher"
#: patterns/hidden-search.php
#: patterns/hidden-sidebar.php
msgid "Search..."
msgstr "Rechercher..."
#: patterns/hidden-blog-heading.php
msgid "Blog"
msgstr "Blog"
#: patterns/comments.php
msgid "Comments"
msgstr "Commentaires"
#: patterns/post-navigation.php
msgid "Previous"
msgstr "Précédent"
#: patterns/post-navigation.php
msgid "Next"
msgstr "Suivant"
#: patterns/more-posts.php
msgid "More posts"
msgstr "Plus d'articles"
#: patterns/template-query-loop.php
msgid "Read more"
msgstr "Lire la suite"
#: patterns/template-query-loop.php
msgid "No posts were found."
msgstr "Aucun article n'a été trouvé."
#: patterns/hero-cover.php
msgid "Build something amazing"
msgstr "Créez quelque chose d'incroyable"
#: patterns/hero-cover.php
msgid "Create modern, responsive websites with the power of Bootstrap 5 and the WordPress Site Editor."
msgstr "Créez des sites web modernes et réactifs grâce à la puissance de Bootstrap 5 et de l'éditeur de site WordPress."
#: patterns/hero-cover.php
#: patterns/hero-centered.php
#: patterns/pricing-3-col.php
#: patterns/page-services.php
msgid "Get Started"
msgstr "Commencer"
#: patterns/hero-split.php
msgid "Modern design meets powerful features"
msgstr "Un design moderne allié à des fonctionnalités puissantes"
#: patterns/hero-split.php
msgid "A WordPress theme built from the ground up with Bootstrap 5 for a seamless editing and browsing experience."
msgstr "Un thème WordPress construit de zéro avec Bootstrap 5 pour une expérience d'édition et de navigation fluide."
#: patterns/hero-split.php
#: patterns/hero-centered.php
#: patterns/text-about.php
msgid "Learn More"
msgstr "En savoir plus"
#: patterns/hero-split.php
msgid "View Demo"
msgstr "Voir la démo"
#: patterns/hero-split.php
msgid "Hero image"
msgstr "Image héros"
#: patterns/hero-centered.php
msgid "Welcome to your new website"
msgstr "Bienvenue sur votre nouveau site web"
#: patterns/hero-centered.php
msgid "Start building beautiful, responsive pages with the full power of Bootstrap 5 and the WordPress block editor."
msgstr "Commencez à créer de belles pages réactives avec toute la puissance de Bootstrap 5 et de l'éditeur de blocs WordPress."
#: patterns/features-3-col.php
#: functions.php
msgid "Features"
msgstr "Fonctionnalités"
#: patterns/features-3-col.php
msgid "Everything you need to build a modern website."
msgstr "Tout ce dont vous avez besoin pour créer un site web moderne."
#: patterns/features-3-col.php
msgid "Responsive Design"
msgstr "Design réactif"
#: patterns/features-3-col.php
msgid "Your website looks great on every device, from mobile phones to large desktop screens."
msgstr "Votre site web est superbe sur tous les appareils, des téléphones mobiles aux grands écrans de bureau."
#: patterns/features-3-col.php
msgid "Easy Customization"
msgstr "Personnalisation facile"
#: patterns/features-3-col.php
msgid "Customize colors, fonts, and layouts using the WordPress Site Editor with no code required."
msgstr "Personnalisez les couleurs, les polices et les mises en page avec l'éditeur de site WordPress, sans aucun code requis."
#: patterns/features-3-col.php
msgid "Performance First"
msgstr "La performance avant tout"
#: patterns/features-3-col.php
msgid "Built with speed in mind. Optimized assets and clean code for lightning-fast page loads."
msgstr "Conçu pour la vitesse. Ressources optimisées et code propre pour des chargements de pages ultra-rapides."
#: patterns/features-icon-list.php
msgid "Why choose us"
msgstr "Pourquoi nous choisir"
#: patterns/features-icon-list.php
msgid "Bootstrap 5 Framework"
msgstr "Framework Bootstrap 5"
#: patterns/features-icon-list.php
msgid "Built on the most popular CSS framework. Leverage a proven, well-documented design system."
msgstr "Construit sur le framework CSS le plus populaire. Tirez parti d'un système de design éprouvé et bien documenté."
#: patterns/features-icon-list.php
msgid "Full Site Editing"
msgstr "Édition complète du site"
#: patterns/features-icon-list.php
msgid "Edit every part of your site visually. Headers, footers, templates, and content are all customizable."
msgstr "Modifiez chaque partie de votre site visuellement. En-têtes, pieds de page, modèles et contenu sont tous personnalisables."
#: patterns/features-icon-list.php
msgid "Dark Mode Support"
msgstr "Prise en charge du mode sombre"
#: patterns/features-icon-list.php
msgid "Built-in dark mode toggle that respects user preferences and persists across visits."
msgstr "Bouton de mode sombre intégré qui respecte les préférences de l'utilisateur et persiste entre les visites."
#: patterns/features-2-col-offset.php
msgid "Feature illustration"
msgstr "Illustration de fonctionnalité"
#: patterns/features-2-col-offset.php
msgid "Designed for modern workflows"
msgstr "Conçu pour les flux de travail modernes"
#: patterns/features-2-col-offset.php
msgid "Streamline your development process with a theme that works the way you do."
msgstr "Optimisez votre processus de développement avec un thème qui fonctionne comme vous."
#: patterns/features-2-col-offset.php
msgid "Block Patterns"
msgstr "Modèles de blocs"
#: patterns/features-2-col-offset.php
msgid "Pre-built patterns for common page sections. Drop them in and customize to fit your needs."
msgstr "Modèles préconçus pour les sections de page courantes. Insérez-les et personnalisez-les selon vos besoins."
#: patterns/features-2-col-offset.php
msgid "Style Variations"
msgstr "Variations de style"
#: patterns/features-2-col-offset.php
msgid "Switch between color schemes with a single click. Choose from multiple professionally designed palettes."
msgstr "Basculez entre les palettes de couleurs en un seul clic. Choisissez parmi plusieurs palettes conçues professionnellement."
#: patterns/cta-banner.php
msgid "Ready to get started?"
msgstr "Prêt à commencer ?"
#: patterns/cta-banner.php
msgid "Start building your website today with our powerful and flexible theme."
msgstr "Commencez à créer votre site web dès aujourd'hui avec notre thème puissant et flexible."
#: patterns/cta-banner.php
msgid "Start Now"
msgstr "Commencer maintenant"
#: patterns/cta-newsletter.php
msgid "Stay in the loop"
msgstr "Restez informé"
#: patterns/cta-newsletter.php
msgid "Subscribe to our newsletter for updates, tips, and exclusive content."
msgstr "Abonnez-vous à notre newsletter pour des mises à jour, des conseils et du contenu exclusif."
#: patterns/cta-newsletter.php
msgid "Enter your email address"
msgstr "Entrez votre adresse courriel"
#: patterns/cta-newsletter.php
msgid "Subscribe"
msgstr "S'abonner"
#: patterns/testimonials-2-col.php
msgid "What our clients say"
msgstr "Ce que disent nos clients"
#: patterns/testimonials-2-col.php
msgid "This theme completely transformed our website. The Bootstrap integration makes it incredibly easy to create professional-looking pages without any custom code."
msgstr "Ce thème a complètement transformé notre site web. L'intégration de Bootstrap rend incroyablement facile la création de pages d'aspect professionnel sans aucun code personnalisé."
#: patterns/testimonials-2-col.php
msgid "Jane Doe, Web Designer"
msgstr "Jane Doe, Webdesigneuse"
#: patterns/testimonials-2-col.php
msgid "The dark mode support and style variations give us the flexibility we need. Our clients love being able to switch between color schemes effortlessly."
msgstr "La prise en charge du mode sombre et les variations de style nous donnent la flexibilité dont nous avons besoin. Nos clients adorent pouvoir basculer entre les palettes de couleurs sans effort."
#: patterns/testimonials-2-col.php
msgid "John Smith, Developer"
msgstr "John Smith, Développeur"
#: patterns/testimonials-centered.php
msgid "The best WordPress theme we have ever used. Clean code, beautiful design, and incredible flexibility."
msgstr "Le meilleur thème WordPress que nous ayons jamais utilisé. Code propre, beau design et flexibilité incroyable."
#: patterns/testimonials-centered.php
msgid "Alex Johnson, Creative Director"
msgstr "Alex Johnson, Directeur créatif"
#: patterns/pricing-3-col.php
#: functions.php
msgid "Pricing"
msgstr "Tarifs"
#: patterns/pricing-3-col.php
msgid "Choose the plan that works best for you."
msgstr "Choisissez le forfait qui vous convient le mieux."
#: patterns/pricing-3-col.php
msgid "Basic"
msgstr "Basique"
#: patterns/pricing-3-col.php
msgid "Free"
msgstr "Gratuit"
#: patterns/pricing-3-col.php
msgid "1 Website"
msgstr "1 site web"
#: patterns/pricing-3-col.php
msgid "Community Support"
msgstr "Support communautaire"
#: patterns/pricing-3-col.php
msgid "Core Features"
msgstr "Fonctionnalités de base"
#: patterns/pricing-3-col.php
msgid "Professional"
msgstr "Professionnel"
#: patterns/pricing-3-col.php
msgid "$49"
msgstr "49 $"
#: patterns/pricing-3-col.php
msgid "5 Websites"
msgstr "5 sites web"
#: patterns/pricing-3-col.php
msgid "Priority Support"
msgstr "Support prioritaire"
#: patterns/pricing-3-col.php
msgid "All Features"
msgstr "Toutes les fonctionnalités"
#: patterns/pricing-3-col.php
msgid "Enterprise"
msgstr "Entreprise"
#: patterns/pricing-3-col.php
msgid "$199"
msgstr "199 $"
#: patterns/pricing-3-col.php
msgid "Unlimited Websites"
msgstr "Sites web illimités"
#: patterns/pricing-3-col.php
msgid "Dedicated Support"
msgstr "Support dédié"
#: patterns/pricing-3-col.php
msgid "Custom Development"
msgstr "Développement sur mesure"
#: patterns/pricing-3-col.php
#: patterns/page-services.php
#: patterns/page-contact.php
msgid "Contact Us"
msgstr "Contactez-nous"
#: patterns/contact-info.php
msgid "Get in touch"
msgstr "Prenez contact"
#: patterns/contact-info.php
msgid "We would love to hear from you. Reach out through any of the channels below."
msgstr "Nous serions ravis d'avoir de vos nouvelles. Contactez-nous via l'un des canaux ci-dessous."
#: patterns/contact-info.php
#: patterns/page-contact.php
msgid "Address"
msgstr "Adresse"
#: patterns/contact-info.php
msgid "123 Example Street"
msgstr "123, rue de l'Exemple"
#: patterns/contact-info.php
msgid "8000 Zurich, Switzerland"
msgstr "8000 Zurich, Suisse"
#: patterns/contact-info.php
#: patterns/page-contact.php
msgid "Phone"
msgstr "Téléphone"
#: patterns/contact-info.php
msgid "+41 44 123 45 67"
msgstr "+41 44 123 45 67"
#: patterns/contact-info.php
#: patterns/cta-newsletter.php
#: patterns/page-contact.php
msgid "Email"
msgstr "Courriel"
#: patterns/contact-info.php
#: patterns/page-contact.php
msgid "info@example.com"
msgstr "info@example.com"
#: patterns/text-faq.php
msgid "Frequently Asked Questions"
msgstr "Foire aux questions"
#: patterns/text-faq.php
msgid "How do I install the theme?"
msgstr "Comment installer le thème ?"
#: patterns/text-faq.php
msgid "Download the ZIP file from the releases page, then upload it via WordPress Admin > Appearance > Themes > Add New > Upload Theme."
msgstr "Téléchargez le fichier ZIP depuis la page des versions, puis importez-le via Administration WordPress > Apparence > Thèmes > Ajouter > Téléverser un thème."
#: patterns/text-faq.php
msgid "Does it work with the Site Editor?"
msgstr "Fonctionne-t-il avec l'éditeur de site ?"
#: patterns/text-faq.php
msgid "Yes, this is a Full Site Editing block theme. You can customize templates, headers, footers, and all block patterns using the WordPress Site Editor."
msgstr "Oui, c'est un thème bloc d'édition complète du site. Vous pouvez personnaliser les modèles, en-têtes, pieds de page et tous les modèles de blocs avec l'éditeur de site WordPress."
#: patterns/text-faq.php
msgid "Can I use my own fonts?"
msgstr "Puis-je utiliser mes propres polices ?"
#: patterns/text-faq.php
msgid "The theme comes with Inter, Lora, and system font stacks. You can add custom fonts through the Site Editor or by modifying theme.json."
msgstr "Le thème est livré avec Inter, Lora et des polices système. Vous pouvez ajouter des polices personnalisées via l'éditeur de site ou en modifiant theme.json."
#: patterns/text-faq.php
msgid "Is dark mode supported?"
msgstr "Le mode sombre est-il pris en charge ?"
#: patterns/text-faq.php
msgid "Yes, the theme includes a dark mode toggle that uses Bootstrap 5.3 built-in dark mode. It respects system preferences and remembers your choice."
msgstr "Oui, le thème inclut un bouton de mode sombre qui utilise le mode sombre intégré de Bootstrap 5.3. Il respecte les préférences système et mémorise votre choix."
#: patterns/text-about.php
msgid "About us"
msgstr "À propos de nous"
#: patterns/text-about.php
msgid "We are passionate about creating tools that empower people to build beautiful websites. Our theme combines the reliability of Bootstrap with the flexibility of WordPress."
msgstr "Nous sommes passionnés par la création d'outils qui permettent aux gens de construire de beaux sites web. Notre thème combine la fiabilité de Bootstrap avec la flexibilité de WordPress."
#: patterns/text-about.php
msgid "With years of experience in web development and design, we understand what it takes to create a theme that is both powerful and easy to use."
msgstr "Avec des années d'expérience en développement web et en design, nous comprenons ce qu'il faut pour créer un thème à la fois puissant et facile à utiliser."
#: patterns/text-about.php
#: patterns/page-about.php
msgid "About us image"
msgstr "Image à propos de nous"
#: patterns/hidden-sidebar.php
msgid "Recent Posts"
msgstr "Articles récents"
#: patterns/hidden-sidebar.php
msgid "Tags"
msgstr "Étiquettes"
#: patterns/dark-mode-toggle.php
msgid "Switch to dark mode"
msgstr "Passer en mode sombre"
#: patterns/dark-mode-toggle.php
msgid "Switch to light mode"
msgstr "Passer en mode clair"
#: functions.php
msgid "Primary Navigation"
msgstr "Navigation principale"
#: functions.php
msgid "Footer Navigation"
msgstr "Navigation du pied de page"
#: functions.php
msgid "Pages"
msgstr "Pages"
#: functions.php
msgid "A collection of full page layouts."
msgstr "Une collection de mises en page pleine page."
#: functions.php
msgid "Hero Sections"
msgstr "Sections héros"
#: functions.php
msgid "Large hero and banner sections."
msgstr "Grandes sections héros et bannières."
#: functions.php
msgid "Call to Action"
msgstr "Appel à l'action"
#: functions.php
msgid "Call to action sections."
msgstr "Sections d'appel à l'action."
#: functions.php
msgid "Feature and service showcase sections."
msgstr "Sections de présentation des fonctionnalités et services."
#: functions.php
msgid "Testimonials"
msgstr "Témoignages"
#: functions.php
msgid "Testimonial and review sections."
msgstr "Sections de témoignages et d'avis."
#: functions.php
msgid "Pricing table sections."
msgstr "Sections de tableaux de tarifs."
#: functions.php
msgid "Contact"
msgstr "Contact"
#: functions.php
msgid "Contact information sections."
msgstr "Sections d'informations de contact."
#: functions.php
msgid "Text & Content"
msgstr "Texte et contenu"
#: functions.php
msgid "Text-focused content sections."
msgstr "Sections de contenu axées sur le texte."
#: functions.php
msgid "Checkmark"
msgstr "Coche"
#: functions.php
msgid "Unstyled"
msgstr "Sans style"
#: functions.php
msgid "Card"
msgstr "Carte"
#: functions.php
msgid "Card with Shadow"
msgstr "Carte avec ombre"
#: functions.php
msgid "Alert - Info"
msgstr "Alerte - Info"
#: functions.php
msgid "Alert - Success"
msgstr "Alerte - Succès"
#: functions.php
msgid "Alert - Warning"
msgstr "Alerte - Avertissement"
#: functions.php
msgid "Alert - Danger"
msgstr "Alerte - Danger"
#: functions.php
msgid "Striped Rows"
msgstr "Lignes rayées"
#: functions.php
msgid "Hover Rows"
msgstr "Lignes survolées"
#: functions.php
msgid "Bordered"
msgstr "Avec bordure"
#: functions.php
msgid "Accent Border"
msgstr "Bordure d'accent"
#: functions.php
msgid "Shadow"
msgstr "Ombre"
#: functions.php
msgid "Large Rounded"
msgstr "Grand arrondi"
#: functions.php
msgid "Large"
msgstr "Grand"
#: functions.php
msgid "Small"
msgstr "Petit"
#: functions.php
msgid "Wide"
msgstr "Large"
#: functions.php
msgid "Name"
msgstr "Nom"
#: functions.php
msgid "Website"
msgstr "Site web"
#: functions.php
msgid "Save my name, email, and website in this browser for the next time I comment."
msgstr "Enregistrer mon nom, mon courriel et mon site web dans ce navigateur pour la prochaine fois que je commenterai."
#: functions.php
msgid "Bootstrap Layout"
msgstr "Mise en page Bootstrap"
#: functions.php
msgid "Bootstrap Components"
msgstr "Composants Bootstrap"
#: functions.php
msgid "Bootstrap Navigation"
msgstr "Navigation Bootstrap"
#: functions.php
msgid "Layout"
msgstr "Mise en page"
#: functions.php
msgid "Layout building blocks for page structure."
msgstr "Blocs de construction de mise en page pour la structure des pages."
#: functions.php
msgid "Components"
msgstr "Composants"
#: functions.php
msgid "Reusable Bootstrap component patterns."
msgstr "Modèles de composants Bootstrap réutilisables."
#: functions.php
#: patterns/footer-columns.php
msgid "Navigation"
msgstr "Navigation"
#: functions.php
msgid "Navigation and header patterns."
msgstr "Modèles de navigation et d'en-tête."
#: patterns/layout-container.php
msgid "Heading goes here"
msgstr "Le titre va ici"
#: patterns/layout-container.php
msgid "This is a content container with constrained width and comfortable padding. Replace this text with your own content."
msgstr "Ceci est un conteneur de contenu avec une largeur limitée et un espacement confortable. Remplacez ce texte par votre propre contenu."
#: patterns/layout-2-col.php
#: patterns/layout-3-col.php
msgid "Column One"
msgstr "Colonne un"
#: patterns/layout-2-col.php
msgid "Add your content here. This column takes up half the available width on larger screens and stacks on mobile devices."
msgstr "Ajoutez votre contenu ici. Cette colonne occupe la moitié de la largeur disponible sur les grands écrans et s'empile sur les appareils mobiles."
#: patterns/layout-2-col.php
#: patterns/layout-3-col.php
msgid "Column Two"
msgstr "Colonne deux"
#: patterns/layout-3-col.php
msgid "Column Three"
msgstr "Colonne trois"
#: patterns/layout-3-col.php
msgid "Add your content here. This column takes up one third of the available width on larger screens."
msgstr "Ajoutez votre contenu ici. Cette colonne occupe un tiers de la largeur disponible sur les grands écrans."
#: patterns/layout-full-width-section.php
msgid "Full Width Section Heading"
msgstr "Titre de la section pleine largeur"
#: patterns/layout-full-width-section.php
msgid "This full-width section stands out with a colored background. Use it to highlight important content, announcements, or calls to action."
msgstr "Cette section pleine largeur se distingue par un arrière-plan coloré. Utilisez-la pour mettre en valeur du contenu important, des annonces ou des appels à l'action."
#: patterns/component-card-group.php
msgid "Card One"
msgstr "Carte un"
#: patterns/component-card-group.php
msgid "Card Two"
msgstr "Carte deux"
#: patterns/component-card-group.php
msgid "Card Three"
msgstr "Carte trois"
#: patterns/component-card-group.php
msgid "Add a short description for this card. Cards are a great way to organize and present related content."
msgstr "Ajoutez une courte description pour cette carte. Les cartes sont un excellent moyen d'organiser et de présenter du contenu connexe."
#: patterns/component-accordion.php
msgid "Accordion"
msgstr "Accordéon"
#: patterns/component-accordion.php
msgid "Click on each item to expand and reveal its content."
msgstr "Cliquez sur chaque élément pour le développer et révéler son contenu."
#: patterns/component-accordion.php
msgid "Accordion Item One"
msgstr "Élément d'accordéon un"
#: patterns/component-accordion.php
msgid "This is the content for the first accordion item. You can add any blocks inside this details element to create rich, expandable content sections."
msgstr "Ceci est le contenu du premier élément d'accordéon. Vous pouvez ajouter n'importe quels blocs à l'intérieur de cet élément details pour créer des sections de contenu riches et dépliables."
#: patterns/component-accordion.php
msgid "Accordion Item Two"
msgstr "Élément d'accordéon deux"
#: patterns/component-accordion.php
msgid "This is the content for the second accordion item. Details blocks are a native HTML element that provide toggle functionality without JavaScript."
msgstr "Ceci est le contenu du deuxième élément d'accordéon. Les blocs details sont un élément HTML natif qui offre une fonctionnalité de basculement sans JavaScript."
#: patterns/component-accordion.php
msgid "Accordion Item Three"
msgstr "Élément d'accordéon trois"
#: patterns/component-accordion.php
msgid "This is the content for the third accordion item. Use accordions to organize frequently asked questions, feature lists, or any content that benefits from progressive disclosure."
msgstr "Ceci est le contenu du troisième élément d'accordéon. Utilisez les accordéons pour organiser les questions fréquentes, les listes de fonctionnalités ou tout contenu qui bénéficie d'une divulgation progressive."
#: patterns/page-about.php
msgid "About Us"
msgstr "À propos"
#: patterns/page-about.php
msgid "Learn more about who we are, what we do, and the people behind our mission."
msgstr "Apprenez-en plus sur qui nous sommes, ce que nous faisons et les personnes derrière notre mission."
#: patterns/page-about.php
msgid "Our Story"
msgstr "Notre histoire"
#: patterns/page-about.php
msgid "Founded with a passion for innovation and excellence, our journey began with a simple idea: to create meaningful solutions that make a real difference. Over the years, we have grown from a small team into a dedicated group of professionals committed to delivering outstanding results."
msgstr "Fondée avec une passion pour l'innovation et l'excellence, notre aventure a commencé avec une idée simple : créer des solutions significatives qui font une vraie différence. Au fil des années, nous sommes passés d'une petite équipe à un groupe dédié de professionnels engagés à fournir des résultats exceptionnels."
#: patterns/page-about.php
msgid "Today, we continue to push boundaries and challenge conventions. Our approach combines creative thinking with proven methodologies, ensuring that every project we undertake meets the highest standards of quality and craftsmanship."
msgstr "Aujourd'hui, nous continuons à repousser les limites et à remettre en question les conventions. Notre approche combine la pensée créative avec des méthodologies éprouvées, garantissant que chaque projet que nous entreprenons répond aux plus hauts standards de qualité et de savoir-faire."
#: patterns/page-about.php
msgid "Our Team"
msgstr "Notre équipe"
#: patterns/page-about.php
msgid "Meet the people who make it all happen."
msgstr "Rencontrez les personnes qui rendent tout cela possible."
#: patterns/page-about.php
msgid "Jane Doe"
msgstr "Jane Doe"
#: patterns/page-about.php
msgid "Founder & CEO"
msgstr "Fondatrice et PDG"
#: patterns/page-about.php
msgid "John Smith"
msgstr "John Smith"
#: patterns/page-about.php
msgid "Lead Developer"
msgstr "Développeur principal"
#: patterns/page-about.php
msgid "Emily Johnson"
msgstr "Emily Johnson"
#: patterns/page-about.php
msgid "Creative Director"
msgstr "Directrice créative"
#: patterns/page-services.php
msgid "Our Services"
msgstr "Nos services"
#: patterns/page-services.php
msgid "Professional solutions tailored to your needs."
msgstr "Des solutions professionnelles adaptées à vos besoins."
#: patterns/page-services.php
msgid "What We Offer"
msgstr "Ce que nous offrons"
#: patterns/page-services.php
msgid "We provide a wide range of services to help your business grow and succeed."
msgstr "Nous fournissons une large gamme de services pour aider votre entreprise à croître et réussir."
#: patterns/page-services.php
msgid "Design"
msgstr "Design"
#: patterns/page-services.php
msgid "Beautiful, user-centered designs that capture your brand identity and engage your audience across all platforms and devices."
msgstr "De beaux designs centrés sur l'utilisateur qui capturent l'identité de votre marque et engagent votre public sur toutes les plateformes et appareils."
#: patterns/page-services.php
msgid "Development"
msgstr "Développement"
#: patterns/page-services.php
msgid "Robust, scalable web applications built with modern technologies and best practices to ensure performance and reliability."
msgstr "Des applications web robustes et évolutives construites avec des technologies modernes et les meilleures pratiques pour garantir performance et fiabilité."
#: patterns/page-services.php
msgid "Strategy"
msgstr "Stratégie"
#: patterns/page-services.php
msgid "Data-driven strategies and consulting to help you achieve your business goals and stay ahead of the competition."
msgstr "Des stratégies basées sur les données et du conseil pour vous aider à atteindre vos objectifs commerciaux et garder une longueur d'avance sur la concurrence."
#: patterns/page-services.php
msgid "Ready to take your project to the next level? Let us help you build something great."
msgstr "Prêt à faire passer votre projet au niveau supérieur ? Laissez-nous vous aider à construire quelque chose de formidable."
#: patterns/page-services.php
msgid "View Portfolio"
msgstr "Voir le portfolio"
#: patterns/page-contact.php
msgid "We would love to hear from you. Reach out to us anytime."
msgstr "Nous serions ravis d'avoir de vos nouvelles. Contactez-nous à tout moment."
#: patterns/page-contact.php
msgid "Get in Touch"
msgstr "Prenez contact"
#: patterns/page-contact.php
msgid "123 Main Street, Suite 100, Anytown, ST 12345"
msgstr "123, rue Principale, Bureau 100, 75001 Paris"
#: patterns/page-contact.php
msgid "+1 (555) 123-4567"
msgstr "+33 1 23 45 67 89"
#: patterns/page-contact.php
msgid "Business Hours"
msgstr "Heures d'ouverture"
#: patterns/page-contact.php
msgid "Monday - Friday:"
msgstr "Lundi - Vendredi :"
#: patterns/page-contact.php
msgid "9:00 AM - 6:00 PM"
msgstr "9h00 - 18h00"
#: patterns/page-contact.php
msgid "Saturday:"
msgstr "Samedi :"
#: patterns/page-contact.php
msgid "10:00 AM - 4:00 PM"
msgstr "10h00 - 16h00"
#: patterns/page-contact.php
msgid "Sunday:"
msgstr "Dimanche :"
#: patterns/page-contact.php
msgid "Closed"
msgstr "Fermé"
#. translators: Copyright notice. %1$s: Year, %2$s: Site title.
#: patterns/footer-minimal.php
msgid "&copy; %1$s %2$s. All rights reserved."
msgstr "&copy; %1$s %2$s. Tous droits réservés."
#: patterns/footer-columns.php
msgid "A modern WordPress theme built with Bootstrap 5."
msgstr "Un thème WordPress moderne construit avec Bootstrap 5."
#: patterns/footer-columns.php
msgid "About"
msgstr "À propos"
#: patterns/footer-columns.php
msgid "This theme is proudly built with Bootstrap 5 and WordPress Full Site Editing."
msgstr "Ce thème est fièrement construit avec Bootstrap 5 et l'éditeur de site complet WordPress."
#. translators: Copyright notice. %1$s: Year, %2$s: Site title.
#: patterns/footer-columns.php
msgid "&copy; %1$s %2$s"
msgstr "&copy; %1$s %2$s"
#: views/base.html.twig
msgid "Skip to main content"
msgstr "Aller au contenu principal"
#: views/partials/header.html.twig
#: views/partials/header-centered.html.twig
#: views/partials/header-transparent.html.twig
#: views/partials/header-offcanvas.html.twig
msgid "Primary navigation"
msgstr "Navigation principale"
#: views/partials/footer.html.twig
#: views/partials/footer-columns.html.twig
msgid "Footer navigation"
msgstr "Navigation du pied de page"
#: functions.php
msgid "Sidebar"
msgstr "Barre latérale"
#: functions.php
msgid "Add widgets here to appear in the sidebar."
msgstr "Ajoutez des widgets ici pour les afficher dans la barre latérale."
#: views/partials/sidebar.html.twig
msgid "Blog sidebar"
msgstr "Barre latérale du blog"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,9 @@
*/
function getPreferredTheme() {
var stored = localStorage.getItem(STORAGE_KEY);
if (stored) {
// Whitelist: only honour known-good values to prevent attribute injection
// from a tampered localStorage (e.g. XSS-written value by another script).
if (stored === 'dark' || stored === 'light') {
return stored;
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';

View File

@@ -7,7 +7,7 @@ Description: A modern WordPress Block Theme built from scratch with Bootstrap 5.
Requires at least: 6.7
Tested up to: 6.7
Requires PHP: 8.3
Version: 1.0.1
Version: 1.0.12
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: wp-bootstrap

View File

@@ -11,7 +11,7 @@
<a class="wp-bootstrap-skip-link" href="#main-content">{{ __('Skip to main content') }}</a>
{% block header %}
{% include 'partials/header.html.twig' %}
{% include 'partials/header-offcanvas.html.twig' %}
{% endblock %}
<main id="main-content" class="{% block main_class %}py-4{% endblock %}">
@@ -19,7 +19,8 @@
</main>
{% block footer %}
{% include 'partials/footer.html.twig' %}
{# block_template_part('footer') #}
{% include 'partials/footer-columns.html.twig' %}
{% endblock %}
{{ wp_footer() }}

View File

@@ -10,7 +10,9 @@
</figure>
{% endif %}
<h1>{{ post.title }}</h1>
{% if post.title is not empty %}
<h1>{{ post.title }}</h1>
{% endif %}
<div class="post-content">
{{ post.content|raw }}

View File

@@ -7,7 +7,8 @@
<div class="d-flex align-items-center gap-2 mb-1">
<strong class="small">
{% if comment.author_url %}
<a href="{{ esc_url(comment.author_url) }}" class="text-decoration-none text-body" rel="nofollow">
{# author_url is pre-escaped with esc_url() in ContextBuilder #}
<a href="{{ comment.author_url|raw }}" class="text-decoration-none text-body" rel="nofollow">
{{ comment.author }}
</a>
{% else %}

View File

@@ -15,7 +15,14 @@
<div class="offcanvas offcanvas-end" tabindex="-1" id="navbarOffcanvas"
aria-labelledby="navbarOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="navbarOffcanvasLabel">{{ site.name }}</h5>
{% if user.logged_in %}
<a href="{{ user.account_url }}" class="d-flex align-items-center text-decoration-none">
{{ user.avatar|raw }}
<span class="ms-2 fw-semibold">{{ user.display_name|esc_html }}</span>
</a>
{% else %}
<h5 class="offcanvas-title" id="navbarOffcanvasLabel">{{ site.name }}</h5>
{% endif %}
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"
aria-label="{{ __('Close') }}"></button>
</div>
@@ -54,12 +61,19 @@
{% endif %}
{% endfor %}
</ul>
{% if dark_mode %}
{% include 'partials/dark-mode-toggle.html.twig' %}
{% endif %}
</div>
{% if dark_mode %}
<div class="offcanvas-footer d-lg-none border-top p-3">
{% include 'partials/dark-mode-toggle.html.twig' %}
</div>
{% endif %}
</div>
{%- if dark_mode %}
<div class="d-none d-lg-block ms-2">
{% include 'partials/dark-mode-toggle.html.twig' %}
</div>
{% endif %}
</div>
</nav>
</header>