[{"data":1,"prerenderedAt":87},["ShallowReactive",2],{"YBwVQjNS6N":3,"fAodXV4WwR":19},{"data":4},[5,12],{"id":6,"title":7,"slug":8,"slugs":9,"thumbnail":10,"thumbnail_small":11},3,"Laravel","laravel",{"en":8,"fr":8},"https://app.tomjamon.com/storage/12/conversions/01JER9785TAJYWQRE60EHP67C4-cover.webp","https://app.tomjamon.com/storage/12/conversions/01JER9785TAJYWQRE60EHP67C4-card.webp",{"id":13,"title":14,"slug":15,"slugs":16,"thumbnail":17,"thumbnail_small":18},6,"Nuxt JS","nuxt-js",{"en":15,"fr":15},"https://app.tomjamon.com/storage/10/conversions/01JER91M3YJXF7EHZR75J054MT-cover.webp","https://app.tomjamon.com/storage/10/conversions/01JER91M3YJXF7EHZR75J054MT-card.webp",{"data":20,"links":72,"meta":75},[21,35,52],{"id":6,"title":22,"slug":23,"slugs":24,"summary":26,"content":27,"categories":28,"thumbnail":31,"thumbnail_small":32,"created_at":33,"updated_at":34},"Laravel 11: Send Emails with the Brevo API Without SMTP","laravel-11-send-emails-with-brevo-api-without-smtp",{"en":23,"fr":25},"envoyer-emails-laravel-11-brevo-api-sans-smtp","Learn how to integrate the Brevo API into Laravel 11 to send transactional emails without SMTP while keeping full compatibility with Laravel Mailables and Notifications.","When working with Laravel, the most common way to send emails through Brevo is by configuring an SMTP server. However, Brevo also provides a transactional API that offers several advantages:\n\n- No SMTP configuration required\n- Improved reliability\n- Faster email delivery\n- Native support for Brevo templates\n- Event tracking (opens, clicks, bounces, etc.)\n\nIn this article, we'll see how to integrate Brevo as a mail transport in Laravel 11 using its API.\n\n## Installing the Required Packages\n\nStart by installing the Symfony Brevo mailer transport and the required HTTP client:\n\n```bash\ncomposer require symfony/brevo-mailer\ncomposer require symfony/http-client\n```\n\n## Creating a Brevo API Key\n\nFrom your Brevo dashboard:\n\n1. Navigate to **SMTP & API**\n2. Open the **API Keys** tab\n3. Create a new transactional API key\n\nYou should receive a key similar to:\n\n```text\nxkeysib-xxxxxxxxxxxxxxxxxxxxxxxx\n```\n\n## Laravel Configuration\n\nAdd your API key to your `.env` file:\n\n```env\nMAIL_MAILER=brevo\n\nBREVO_API_KEY=xkeysib-xxxxxxxxxxxxxxxxxxxxxxxx\n\nMAIL_FROM_ADDRESS=noreply@yourdomain.com\nMAIL_FROM_NAME=\"${APP_NAME}\"\n```\n\nThen update `config/services.php`:\n\n```php\nreturn [\n\n    // ...\n\n    'brevo' => [\n        'key' => env('BREVO_API_KEY'),\n    ],\n\n];\n```\n\n## Registering the Brevo Mail Transport\n\nAdd a new mailer to `config/mail.php`:\n\n```php\n'brevo' => [\n    'transport' => 'brevo',\n],\n```\n\nLaravel does not natively recognize the Brevo transport, so it must be registered manually.\n\nIn `AppServiceProvider.php`:\n\n```php\nuse Illuminate\\Support\\Facades\\Mail;\nuse Symfony\\Component\\Mailer\\Bridge\\Brevo\\Transport\\BrevoTransportFactory;\nuse Symfony\\Component\\Mailer\\Transport\\Dsn;\n\npublic function boot(): void\n{\n    Mail::extend('brevo', function () {\n        return (new BrevoTransportFactory())->create(\n            new Dsn(\n                'brevo+api',\n                'default',\n                config('services.brevo.key')\n            )\n        );\n    });\n}\n```\n\n## Clearing Laravel Cache\n\nAfter updating the configuration, clear Laravel's cache:\n\n```bash\nphp artisan optimize:clear\n```\n\n## Sending a Test Email\n\nYou can now send emails as usual:\n\n```php\nuse Illuminate\\Support\\Facades\\Mail;\n\nMail::raw('Brevo API test', function ($message) {\n    $message->to('contact@example.com')\n        ->subject('Brevo Test');\n});\n```\n\nOr with a Mailable:\n\n```php\nMail::to($user)->send(new WelcomeMail());\n```\n\nNo additional changes are required in your application code.\n\n## Common Errors\n\n### Unsupported mail transport [brevo]\n\nThe transport has not been registered correctly in `AppServiceProvider`, or the `symfony/brevo-mailer` package is missing.\n\n### User is not set\n\nThe `Dsn` constructor is misconfigured. The API key must be passed as the third argument.\n\n### You cannot use AbstractHttpTransport as the HttpClient component is not installed\n\nThe following package is missing:\n\n```bash\ncomposer require symfony/http-client\n```\n\n## Conclusion\n\nUsing Brevo through its API allows you to keep the full Laravel mail ecosystem while benefiting from the performance and features of Brevo's transactional email platform.\n\nOnce configured, your Mailables, Notifications, and queued emails continue to work exactly as they would with SMTP, without requiring any changes to your business logic.",[29],{"id":6,"title":7,"slug":8,"slugs":30,"thumbnail":10,"thumbnail_small":11},{"en":8,"fr":8},"https://app.tomjamon.com/storage/15/conversions/01KT6BXVWDYSYYM25N3QKAPH7C-cover.webp","https://app.tomjamon.com/storage/15/conversions/01KT6BXVWDYSYYM25N3QKAPH7C-card.webp","2026-06-03T09:02:47.000000Z","2026-06-03T09:27:15.000000Z",{"id":36,"title":37,"slug":38,"slugs":39,"summary":41,"content":42,"categories":43,"thumbnail":48,"thumbnail_small":49,"created_at":50,"updated_at":51},2,"Internationalization (i18n) with Nuxt 3: A Step-by-Step Guide","internationalization-i18n-with-nuxt-3-a-step-by-step-guide",{"en":38,"fr":40},"mise-en-place-de-internationalisation-i18n-dans-un-projet-nuxt-3","Learn how to easily implement internationalization (i18n) in your Nuxt 3 project using the @nuxtjs/i18n module. This guide covers setting up multiple languages, managing custom routes, and optimizing the multilingual user experience.","Internationalization (i18n) is essential for web applications targeting a multilingual audience. Nuxt 3, with its advanced features, makes integrating i18n simple and effective. This article guides you through setting up i18n in a Nuxt 3 project using specific configurations and route and language files.\n\n## Prerequisites\n\nInstall Nuxt 3 and the i18n module using npm:\n\n```bash\nnpm install nuxt@latest @nuxtjs/i18n\n```\n\n## Basic Configuration\n\nWe will configure our Nuxt 3 project to support multiple languages by editing the nuxt.config.ts file. Here’s how to set up the i18n module:\n\n### Step 1: Import Routes\n\nCreate a `routes.json` file at the root of your project. This file will define your routes for each language. Example:\n\n```json\n{\n    \"about\": {\n        \"en\": \"/about\",\n        \"fr\": \"/a-propos\",\n        \"es\": \"/acerca-de\"\n    },\n    \"contact\": {\n        \"en\": \"/contact\",\n        \"fr\": \"/contact\",\n        \"es\": \"/contacto\"\n    }\n}\n```\n\n### Step 2: Update nuxt.config.ts\n\nEdit your `nuxt.config.ts` file to include i18n configurations. Example:\n\n\n```tsx\nimport routes from './routes.json'\n\nexport default defineNuxtConfig({\n  modules: [\n    '@nuxtjs/i18n',\n  ],\n  i18n: {\n    locales: [\n      { code: 'en', label: 'English', iso: 'en-US', file: 'en.json' },\n      { code: 'fr', label: 'Français', iso: 'fr-FR', file: 'fr.json' },\n      { code: 'es', label: 'Español', iso: 'es-ES', file: 'es.json' },\n    ],\n    defaultLocale: 'fr',\n    strategy: 'prefix_except_default',\n    detectBrowserLanguage: {\n      useCookie: true,\n      cookieKey: 'i18n_redirected_' + process.env.NODE_ENV,\n      alwaysRedirect: true,\n      fallbackLocale: 'fr',\n    },\n    langDir: 'lang/',\n    lazy: true,\n    pages: routes,\n    customRoutes: 'config',\n  }\n})\n```\n\n### Configuration Explanation\n\n- `locales`: Defines the supported languages.\n- `defaultLocale`: Sets the default language.\n- `strategy`: Uses `prefix_except_default` to prefix routes with language codes, except for the default language.\n- `detectBrowserLanguage`: Detects the user’s browser language and uses cookies to store preferences.\n- `langDir`: Specifies the directory for language files.\n- `lazy`: Enables lazy loading of language files.\n- `pages`: Uses routes defined in `routes.json`.\n- `customRoutes`: Allows flexible custom route management.\n\n## Creating Language Files\n\nFor each language, create a JSON file in the `lang/` directory. Example for French (lang/fr.json):\n\n```json\n{\n  \"welcome\": \"Bienvenue\",\n  \"about\": \"À propos de nous\",\n  \"contact\": \"Contactez-nous\"\n}\n\n```\n\nRepeat for `en.json` and `es.json`, translating keys accordingly.\n\n## Using Translations in Components\n\nUse translations in components with the `\u003Cnuxt-link>` component and the `$t` method. Example:\n\n```html\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Ch1>{{ $t('welcome') }}\u003C/h1>\n    \u003CNuxtLinkLocale to=\"about\">{{ $t('about') }}r\u003C/NuxtLinkLocale>\n  \u003C/div>\n\u003C/template>\n```\n\n## Browser Language Detection\n\nThe `detectBrowserLanguage` configuration automatically detects the user’s browser language and redirects to the appropriate version of your site. It ensures a consistent user experience by storing language preferences in cookies.\n\n## Managing Custom Routes\n\nGrâce à la configuration `customRoutes`, vous pouvez définir des routes spécifiques pour chaque langue dans votre fichier `routes.json`. Cela permet une gestion plus flexible et granulaire des chemins de votre application.\nWith the customRoutes configuration, you can define language-specific routes in `routes.json`, allowing granular control of your application’s paths.\n\n\n## Conclusion\n\nInternationalization is a crucial step for making your application accessible to a global audience. Nuxt 3 and the `@nuxtjs/i18n` module simplify and streamline the i18n setup. By following this guide, you can configure your project to support multiple languages and deliver a seamless localized user experience.\n\nNuxt 3’s flexibility, combined with i18n’s robust features, makes it easy to manage translations, language detection, and redirections. Now you’re ready to make your Nuxt 3 app multilingual and reach a broader audience.\n\nFor more details and advanced configurations, consult the official Nuxt i18n documentation. Happy coding!",[44,46],{"id":13,"title":14,"slug":15,"slugs":45,"thumbnail":17,"thumbnail_small":18},{"en":15,"fr":15},{"id":6,"title":7,"slug":8,"slugs":47,"thumbnail":10,"thumbnail_small":11},{"en":8,"fr":8},"https://app.tomjamon.com/storage/6/conversions/01JENYFEHS5X3VQQ75A54QCS25-cover.webp","https://app.tomjamon.com/storage/6/conversions/01JENYFEHS5X3VQQ75A54QCS25-card.webp","2024-12-09T14:51:50.000000Z","2024-12-11T15:27:38.000000Z",{"id":53,"title":54,"slug":55,"slugs":56,"summary":58,"content":59,"categories":60,"thumbnail":68,"thumbnail_small":69,"created_at":70,"updated_at":71},1,"My Solar Installation: 8 Panels and 3000W on a Flat Roof","my-solar-installation-8-panels-and-3000w-on-a-flat-roof",{"en":55,"fr":57},"mon-installation-solaire-8-panneaux-et-3000w-sur-un-toit-plat","Discover my experience of installing solar panels on a flat roof, including the selection of a Plug&Play kit, suitable supports, and electrical optimizations. A practical guide to starting with an efficient and cost-effective installation for under €800.","Hello,\n\nI recently installed solar panels on my flat roof and wanted to share my experience for those considering taking the leap. If you have any tips for optimizing the setup, I’m all ears!\n\n**Solar Kit**\n\nI purchased the “1520W Plug&Play Solar Kit - 4 Honor 380W Solar Panels + 2 Hoymiles HMS800W 2T Micro-Inverters” from Dealabs: https://www.dealabs.com/bons-plans/kits-solaires-1520w-plugplay-2832592.\n\nBuying a complete kit seemed like a better choice for my first purchase. It provided a single point of contact for any issues (delivery defects, etc.), ensured compatibility between the panels and micro-inverters, and came at an attractive price.\n\nMy roof measures 7x4m, allowing space for 8 to 10 panels. Initially, I started with one kit.\n\n**Component Choices - Slabs**\n\nI wanted a low angle for the installation to remain discreet (or even invisible) from the street. Unfortunately, the parapet is less than 20 cm high on the street side, and with only 4 meters of width, the installation remains somewhat visible regardless of the layout.\n\nThe price of pre-made bases was high, and they concentrated weight at a single point. I had doubts about my roof’s capacity, as it wasn’t specifically designed for solar panels (though the beams are closer together than usual, as I had anticipated possibly installing panels one day).\n\nRails seemed like a solid option, but I didn’t want to drill into the roof to preserve its waterproofing.\n\nI opted for a solution distributing the weight across 4 points using a support system split into four parts with slabs, ensuring recommended weight limits were respected.\n\nFor one panel, at least 50-60 kg of ballast is needed. Simple slabs from Leroy Merlin, costing €2.50 each and weighing 13.2 kg, were ideal for this: https://www.leroymerlin.fr/produits/terrasse-jardin/terrasse-et-sol-exterieur/dalle-de-terrasse/dalle-de-terrasse-beton/dalle-beton-spring-au-m2-gris-l-40-x-l-40-cm-x-ep-32-a-35-mm-65965592.html.\n\nI used four slabs per panel for my 4-panel kit, totaling around €41, providing about 53 kg of ballast per panel.\n\n**Component Choices - Support**\n\nI wanted low-angle supports that could easily attach to the slabs. I chose this model: https://amzn.to/3BFgLMD, costing €57 for two panels or €114 for my kit.\n\nI secured them at the center of each slab.\n\nTo avoid damaging the roof, I added thick foam under the supports. I used these rubber mats: https://www.leroymerlin.fr/produits/revetement-sol-et-mur/sous-couche-sol/plaque-de-sol-caoutchouc-sol-anti-vibrations-noma-rub-l-0-6-m-x-l-0-6-m-x-ep-10-66129294.html, cutting them into four pieces to cover about 70% of each slab’s surface.\n\nThese mats act as an interface between the slabs and the roof (no direct slab-to-roof or screw-to-roof contact), protecting against wear over time.\n\n**Panel Installation**\n\nOnce the supports and slabs were in place, I installed the panels. I positioned the slabs, then placed the panels in pairs, with the micro-inverter underneath.\n\nThe process is simple, but it’s easier with two people—one to hold the panels while the other secures them. It’s also helpful for repositioning the panels if needed. My 4-point system is easier to handle than heavy bases (~60 kg), but it’s best to choose the placement carefully from the start.\n\n**Electrical Connection**\n\nI chose not to plug the system directly into a socket. Instead, I connected it to my existing electrical panel via an existing 16A circuit breaker. If needed, a circuit breaker costs about €12.\n\nI already had electrical conduit, but you can buy it for around €30, depending on your installation’s distance, to protect the electrical cable on the roof.\n\n**Mobile App**\n\nI use the S-Miles Home app to monitor energy production in real time. Here’s a preview of the interface:\n\nTotal Cost\n\nKit €570 + €40 slabs + €52 mats + €114 supports = €776.\n\nI already had screws and circuit breakers. The total cost would be around €800 for those starting from scratch.\n\n**Installation Optimizations**\n\nTwo weeks later, I decided to double the installation. I used the same components: kit, slabs, supports, and rubber mats.\n\nI also separated the electrical setup for the annex and the panels. I purchased a waterproof electrical box: https://amzn.to/3NqCYjS (€19), an RCD switch https://amzn.to/401Hzk4 (€47), and a surge protector https://amzn.to/3YldRFx (€70). I also added two 16A circuit breakers.\n\nThe surge protector is an extra precaution, and I also grounded the panels using 6mm² wire with these grounding clips: https://amzn.to/4dJbwsu (€22).\n\nEverything is connected to a secondary panel, which then links to the house’s main panel.\n\n**Optimization Cost**: €147 (excluding wiring).\n\nIn summary, this solar panel installation has been a great success, and I’m already seeing the first savings on my energy bill. If you have questions or suggestions for further optimizations, feel free to reach out!",[61],{"id":62,"title":63,"slug":64,"slugs":65,"thumbnail":66,"thumbnail_small":67},5,"DIY","do-it-yourself",{"en":64,"fr":64},"https://app.tomjamon.com/storage/11/conversions/01JER93D4J9XXKT9V55N9H7GJN-cover.webp","https://app.tomjamon.com/storage/11/conversions/01JER93D4J9XXKT9V55N9H7GJN-card.webp","https://app.tomjamon.com/storage/5/conversions/01JENY6EQA3P5JWXQQ1EMPEX56-cover.webp","https://app.tomjamon.com/storage/5/conversions/01JENY6EQA3P5JWXQQ1EMPEX56-card.webp","2024-12-09T14:39:46.000000Z","2024-12-09T14:46:43.000000Z",{"first":73,"last":73,"prev":74,"next":74},"https://app.tomjamon.com/api/posts?page=1",null,{"current_page":53,"from":53,"last_page":53,"links":76,"path":85,"per_page":86,"to":6,"total":6},[77,80,83],{"url":74,"label":78,"page":74,"active":79},"&laquo; Previous",false,{"url":73,"label":81,"page":53,"active":82},"1",true,{"url":74,"label":84,"page":74,"active":79},"Next &raquo;","https://app.tomjamon.com/api/posts",7,1792846766655]