Merge branch 'trunk'

This commit is contained in:
Vincent BRIDIER 2024-10-15 15:42:04 +02:00
commit ed301a4f1f
No known key found for this signature in database
GPG key ID: 8571BFA20420D512
175 changed files with 2506 additions and 1460 deletions

View file

@ -36,6 +36,9 @@ MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
MAIL_LIST_CONTACT=
MAIL_LIST_PASSERELLE=
MAIL_LIST_NL=
# Sentry
SENTRY_LARAVEL_DSN=

View file

@ -12,10 +12,6 @@ convert -colors 256 -depth 8 +dither bg-footer-ori.png bg-footer-test.png
apt install trimage
### TODO
FIXME: supprimer le dossier resources/assets/images/tmp
# Copy paste from the admin secure readme.md
Put every min in PROD :
php artisan schedule:run

View file

@ -18,7 +18,7 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule): void
{
$schedule->job(FetchDigitalRecruiterOffers::class)->daily();
$schedule->job(FetchDigitalRecruiterOffers::class)->everyFourHours(15);
$schedule->job(DeleteOldMessages::class)->dailyAt('14:15');
$schedule->job(FetchMesBr::class)->daily();
}

View file

@ -21,12 +21,12 @@ enum ContactFormType: int
* @phpstan-ignore-next-line
*/
private const LABELS = [
self::none->name => 'Aucun',
self::complain->name => 'Une réclamation',
self::club->name => 'Le Club des Gaulois',
self::games->name => 'Jeux Concours',
self::others->name => 'Autres',
self::nl->name => 'Formulaire en NL',
self::none->name => 'enums.contact-form-type.none.label',
self::complain->name => 'enums.contact-form-type.complain.label',
self::club->name => 'enums.contact-form-type.club.label',
self::games->name => 'enums.contact-form-type.games.label',
self::others->name => 'enums.contact-form-type.others.label',
self::nl->name => 'enums.contact-form-type.nl.label',
];
/**
@ -37,15 +37,12 @@ enum ContactFormType: int
public function description(): string
{
return match ($this) {
self::none => 'Aucun objet',
self::complain => 'Je souhaite obtenir de l\'aide car je désire envoyer une réclamation sur un produit',
self::club => 'Je rencontre des problèmes au sujet des magnets départ\'aimants ou des bons de
réductions Le Gaulois.',
self::games => 'Je souhaite faire une réclamation sur un jeu Le Gaulois ou je rencontre un problème
sur le site.',
self::others => 'Je souhaite faire une réclamation sur un jeu Le Gaulois ou je rencontre un problème
sur le site.',
self::nl => '',
self::none => trans('enums.contact-form-type.none.description'),
self::complain => trans('enums.contact-form-type.complain.description'),
self::club => trans('enums.contact-form-type.club.description'),
self::games => trans('enums.contact-form-type.games.description'),
self::others => trans('enums.contact-form-type.others.description'),
default => '',
};
}
@ -59,13 +56,13 @@ enum ContactFormType: int
return match ($this) {
self::complain => [
'src' => 'resources/assets/images/contact/exclamation.svg',
'alt' => 'Point d\'exclamation'
'alt' => 'enums.contact-form-type.misc.picto-exclamation-alt'
],
self::club,
self::games,
self::others => [
'src' => 'resources/assets/images/contact/question-mark.svg',
'alt' => 'Point d\'interrogation'
'alt' => 'enums.contact-form-type.misc.picto-question-mark-alt'
],
default => [
'src' => '',
@ -81,6 +78,13 @@ enum ContactFormType: int
*/
public static function getContactTypes(): array
{
if (request()->routeIs('fo.*.export')) {
return [
self::complain,
self::others,
];
}
return [
self::complain,
self::club,
@ -88,4 +92,31 @@ enum ContactFormType: int
self::others,
];
}
/**
* Get all 'locales' contact types.
*
* @return array
*/
public static function getLocalesContactType(): array
{
return [
self::nl,
];
}
/**
* Check if the current subject has a file input.
*
* @return array
*/
public function hasFileInput(): bool
{
return match ($this) {
self::complain,
self::club,
self::games => true,
default => false,
};
}
}

View file

@ -11,10 +11,10 @@ enum SettingsType: int
{
use BaseEnum;
case mainMenu = 1;
case hotNews = 2;
case offersCount = 3;
case breederMapComponent = 4;
case mainMenu = 1;
case hotNews = 2;
case offersCount = 3;
case breederMap = 4;
/**
* Optionnal labels definition.
@ -22,9 +22,9 @@ enum SettingsType: int
* @phpstan-ignore-next-line
*/
private const LABELS = [
self::mainMenu->name => 'Menu principal',
self::hotNews->name => 'Infos chaudes',
self::offersCount->name => 'Total des offres de la marque',
self::breederMapComponent->name => 'Composant \'Carte des éleveurs\'',
self::mainMenu->name => 'Menu principal',
self::hotNews->name => 'Infos chaudes',
self::offersCount->name => 'Total des offres de la marque',
self::breederMap->name => 'Carte des éleveurs',
];
}

View file

@ -5,6 +5,7 @@ namespace App\Http\Controllers\Bo;
use App\Enums\Settings\SettingsType;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\GeneralSettings\UpdateGeneralSettingRequest;
use App\Lib\Definitions\MenuNode;
use App\Lib\Helpers\FileStorageHelper;
use App\Models\GeneralSetting;
use Illuminate\Support\Facades\DB;
@ -28,7 +29,13 @@ class GeneralSettingController extends Controller
*/
public function edit(GeneralSetting $general_setting): \Illuminate\Contracts\View\View
{
return view('bo.pages.general_settings.edit', ['generalSettingModel' => $general_setting]);
$menuNodes = collect($general_setting->value)->map(function (MenuNode $node) {
return collect($node)->toArray();
})->toArray();
return view('bo.pages.general_settings.edit', [
'generalSettingModel' => $general_setting,
'menuNodes' => $menuNodes
]);
}
/**
@ -44,8 +51,8 @@ class GeneralSettingController extends Controller
): \Illuminate\Http\RedirectResponse {
return DB::transaction(function () use ($request, $general_setting) {
match ($general_setting->type) {
SettingsType::hotNews => self::updateHotNews($request, $general_setting),
SettingsType::breederMapComponent => self::updateBreederMapComponent($request, $general_setting),
SettingsType::hotNews => self::updateHotNews($request, $general_setting),
SettingsType::breederMap => self::updateBreederMap($request, $general_setting),
default => $general_setting->fill($request->only('value'))
};
@ -90,7 +97,7 @@ class GeneralSettingController extends Controller
*
* @return void
*/
private static function updateBreederMapComponent(
private static function updateBreederMap(
UpdateGeneralSettingRequest $request,
GeneralSetting $general_setting
): void {

View file

@ -94,12 +94,12 @@ class NewsClubController extends Controller
if ($newsClub->saveOrFail()) {
return redirect()->route('bo.news_clubs.edit', $newsClub)
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.news_club'))
'model' => Str::ucfirst(trans('models.classes.news_club'))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.news_club'))
'model' => Str::ucfirst(trans('models.classes.news_club'))
]));
});
}
@ -130,12 +130,12 @@ class NewsClubController extends Controller
if ($newsClub->saveOrFail()) {
return redirect()->route('bo.news_clubs.edit', $newsClub)
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.news_club'))
'model' => Str::ucfirst(trans('models.classes.news_club'))
]));
}
return redirect()->route('bo.news_clubs.edit', $newsClub)
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.news_club'))
'model' => Str::ucfirst(trans('models.classes.news_club'))
]));
});
}
@ -154,12 +154,12 @@ class NewsClubController extends Controller
if ($newsClub->deleteOrFail()) {
return redirect()->route('bo.news_clubs.index', $previousQueries)
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.news_club'))
'model' => Str::ucfirst(trans('models.classes.news_club'))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.news_club'))
'model' => Str::ucfirst(trans('models.classes.news_club'))
]));
}

View file

@ -101,8 +101,6 @@ class BreederController extends Controller
*/
public function getManageableTextComponent(): array
{
return GeneralSetting::query()
->where('type', SettingsType::breederMapComponent)
->first()->value;
return GeneralSetting::query()->where('type', SettingsType::breederMap)->first()->value;
}
}

View file

@ -8,9 +8,11 @@ use App\Exceptions\AbortContactMailer;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\ContactFormRequest;
use App\Jobs\Mails\SendArcadiaMail;
use App\Jobs\Mails\SendNLMail;
use App\Jobs\Mails\SendPasserelleMail;
use App\Models\MailContactData;
use App\Models\StaticPage;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
@ -39,34 +41,57 @@ class ContactController extends Controller
{
return DB::transaction(function () use ($request) {
try {
$data = new MailContactData($request->safe()->except(['g-recaptcha-response', 'joinFile']));
$data = new MailContactData(
$request->safe()->except(['g-recaptcha-response', 'joinFile', 'locale'])
);
$locale = $request->input('locale');
// Send to Passerelle if it is a compalin about a product.
if ($request->type == ContactFormType::complain->value) {
$joinFilePath = null;
$joinFile = '';
$uniqIdDirectory = \uniqid();
if ($request->file('joinFile')) {
$joinFile = Storage::disk('local')->put(
sprintf('public/tmp/%s', $uniqIdDirectory),
$request->file('joinFile')
);
$joinFilePath = storage_path('app/' . $joinFile);
}
$joinFilePath = ContactFormType::make($request->type)->hasFileInput()
? $this->storeFile($request->file('joinFile'))
: null;
// Send to Passerelle if it is a complain about a product.
if (isset($locale) && ContactFormType::make($request->input('locale'))->equals(ContactFormType::nl)) {
app()->setLocale('nl');
\dispatch(new SendNLMail($data, $joinFilePath));
} elseif (ContactFormType::make($request->type)->equals(ContactFormType::complain)) {
\dispatch(new SendPasserelleMail($data, $joinFilePath));
} else {
\dispatch(new SendArcadiaMail($data));
\dispatch(new SendArcadiaMail($data, $joinFilePath));
}
return back()->with('success', __('Votre message a été envoyé avec succès'));
return back()->with('success', trans('contact.message_contact_send'));
} catch (AbortContactMailer $e) {
Log::error('Fail to build mail from complain page ', ['exception' => $e]);
} //end try
return back()->withInput()->with(
'error',
'Une erreur est survenue durant l\'envoi de votre message. Veuillez réessayer ultérieurement.'
trans('contact.message_contact_failed')
);
});
}
/**
* Store the file sent in the request if it exists.
*
* @param \Illuminate\Http\UploadedFile|null $file
*
* @return string|null
*/
private function storeFile(\Illuminate\Http\UploadedFile|null $file): string|null
{
$joinFilePath = null;
$joinFile = '';
if ($file) {
$uniqIdDirectory = \uniqid();
$joinFile = Storage::disk('local')->put(
sprintf('public/tmp/%s', $uniqIdDirectory),
$file
);
$joinFilePath = storage_path('app/' . $joinFile);
}
return $joinFilePath;
}
}

View file

@ -6,6 +6,7 @@ use App\Enums\Settings\SettingsType;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\SingleOptinRequest;
use App\Http\Requests\Fo\UnsubscribeNewsletterRequest;
use App\Models\DemarcheSlide;
use App\Models\Discount;
use App\Models\MainSlide;
@ -17,10 +18,13 @@ use App\Models\Recipe;
use App\Models\StaticPage;
use App\Models\Video;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use LDC\LDCCRM\Enums\ApiError;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\CrmException;
use LDC\LDCCRM\Exceptions\ValidationException;
use LDC\LDCCRM\Models\SingleOptin;
use LDC\LDCCRM\Models\Customer;
class HomeController extends Controller
{
@ -81,6 +85,56 @@ class HomeController extends Controller
}
}
/**
* unsubscribeNewsletter method
*
* @param \App\Http\Requests\Fo\UnsubscribeNewsletterRequest $request
* @return \Illuminate\Contracts\View\View
*/
public function unsubscribeNewsletter(UnsubscribeNewsletterRequest $request): \Illuminate\Contracts\View\View
{
$error = null;
$hashcode = $request->hashcode;
try {
SingleOptin::unsetStatusWithHashcode($hashcode);
} catch (ApiErrorException $e) {
Log::debug($e->getMessage());
if ($e->getApiError()->equals(ApiError::modelNotFound)) {
if ($customer = Customer::find($hashcode)) {
$customer->opt_in = false;
// ! Les données peuvent être parsés en retour de la crm et inconsitantes (Héritage vielle crm).
try {
$customer->save();
} catch (ValidationException $e) {
$error = null;
}
} else {
abort(404);
}
} else {
if (app()->bound('sentry')) {
app('sentry')->captureException($e);
}
$error = true;
}
} catch (CrmException $e) {
Log::debug($e->getMessage());
$error = true;
if (app()->bound('sentry')) {
app('sentry')->captureException($e);
}
} //end try
if (!is_null($error)) {
return view('fo.pages.newsletter-unsubscribe')->with(
'error',
trans('Une erreur est survenue, merci de réessayer ultérieurement')
);
}
return view('fo.pages.newsletter-unsubscribe');
}
/**
* Display a listing of the resource.
*

View file

@ -38,8 +38,8 @@ class UpdateGeneralSettingRequest extends FormRequest
case SettingsType::hotNews:
$this->prepareHotNewsDatas();
break;
case SettingsType::breederMapComponent:
$this->prepareBreederMapComponentDatas();
case SettingsType::breederMap:
$this->prepareBreederMapDatas();
break;
case SettingsType::mainMenu:
$this->prepareMainMenuDatas();
@ -61,8 +61,8 @@ class UpdateGeneralSettingRequest extends FormRequest
case SettingsType::hotNews:
$rules = $this->getRulesHotNews();
break;
case SettingsType::breederMapComponent:
$rules = $this->getRulesBreederMapComponent();
case SettingsType::breederMap:
$rules = $this->getRulesBreederMap();
break;
case SettingsType::mainMenu:
$rules = $this->getRulesMainMenu();
@ -113,27 +113,27 @@ class UpdateGeneralSettingRequest extends FormRequest
}
/**
* Prepare validation for Hot News
* Prepare validation for Hot News.
*
* @return void
*/
private function prepareHotNewsDatas(): void
{
$this->mergePicture('picture');
$this->merge([
'value->text' => $this->input('text'),
'value->picture' => $this->file('picture'),
'value->picture_alt' => $this->input('picture_alt'),
'value->picture_title' => $this->input('picture_title'),
]);
$this->mergePicture('picture');
}
/**
* Prepare validation for Breeder Map Component
* Prepare validation for Breeder Map.
*
* @return void
*/
private function prepareBreederMapComponentDatas(): void
private function prepareBreederMapDatas(): void
{
$this->merge([
'value->title' => $this->input('title'),
@ -143,7 +143,7 @@ class UpdateGeneralSettingRequest extends FormRequest
}
/**
* Prepare validation for Breeder Map Component
* Prepare validation for Breeder Map.
*
* @return void
*/
@ -226,11 +226,11 @@ class UpdateGeneralSettingRequest extends FormRequest
}
/**
* Get tha array of rules for the Breeder Map Component.
* Get tha array of rules for the Breeder Map.
*
* @return array
*/
private function getRulesBreederMapComponent(): array
private function getRulesBreederMap(): array
{
return [
'title' => 'required|string|between:3,255',

View file

@ -143,7 +143,8 @@ class UpdateStaticPageRequest extends UpdateMiniCrudRequest
!$staticPageModel->type->equals(StaticPageType::recruitment) &&
!$staticPageModel->type->equals(StaticPageType::recipe) &&
!$staticPageModel->type->equals(StaticPageType::product) &&
!$staticPageModel->type->equals(StaticPageType::home)
!$staticPageModel->type->equals(StaticPageType::home) &&
!$staticPageModel->type->equals(StaticPageType::contact)
) {
$rules = \array_merge(
$rules,

View file

@ -6,6 +6,7 @@ use App\Enums\ContactFormCivility;
use App\Enums\ContactFormType;
use App\Lib\Helpers\ToolboxHelper;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Route;
use Illuminate\Validation\Rule;
class ContactFormRequest extends FormRequest
@ -27,9 +28,13 @@ class ContactFormRequest extends FormRequest
*/
public function rules()
{
ToolboxHelper::validateRecaptcha($this, \config('services.google.recaptcha.version'));
// ToolboxHelper::validateRecaptcha($this, \config('services.google.recaptcha.version'));
$rules = [
'locale' => [
'nullable',
Rule::enum(ContactFormType::class)->only(ContactFormType::getLocalesContactType())
],
'type' => [
'required',
Rule::enum(ContactFormType::class)->only(ContactFormType::getContactTypes())
@ -45,12 +50,10 @@ class ContactFormRequest extends FormRequest
// Max arcadia 10 chars.
'town' => 'required|min:3|max:90',
'phone' => 'required|phone:FR',
// FIXME: uncomment when form on export page is ready.
// 'onepagesubject' => 'sometimes|min:10|max:250',
'message' => 'required|min:20|max:1900'
];
if (ContactFormType::make($this->input('type')) === ContactFormType::complain) {
if (ContactFormType::make($this->input('type'))->equals(ContactFormType::complain)) {
$rules = array_merge(
$rules,
[
@ -59,12 +62,20 @@ class ContactFormRequest extends FormRequest
'buyPlace' => 'required|min:2|max:100',
'lotNumberName' => 'required|min:2|max:50',
'limitDateDay' => 'required|numeric|min:1|max:31',
'limitDateMonth' => 'required|numeric|min:1|max:31',
'limitDateMonth' => 'required|numeric|min:1|max:12',
'limitDateYear' => 'required|numeric|min:2010|max:2050',
'consumptionDateDay' => 'required|numeric|min:1|max:31',
'consumptionDateMonth' => 'required|numeric|min:1|max:31',
'consumptionDateMonth' => 'required|numeric|min:1|max:12',
'consumptionDateYear' => 'required|numeric|min:2010|max:2050',
'joinFile' => 'nullable|mimes:jpg,jpeg,png,pdf|max:2048'
],
);
}
if (ContactFormType::make($this->input('type'))->hasFileInput()) {
$rules = array_merge(
$rules,
[
'joinFile' => 'nullable|mimes:jpg,jpeg,png,pdf|max:5120'
],
);
}

View file

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Fo;
use Illuminate\Foundation\Http\FormRequest;
class UnsubscribeNewsletterRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'hashcode' => 'required|uuid'
];
}
}

View file

@ -7,6 +7,7 @@ use App\Models\MailContactData;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
@ -22,15 +23,24 @@ class SendArcadiaMail implements ShouldQueue
* */
private $data;
/**
* The path of a specific file.
*
* @var string|null
* */
private $file;
/**
* Create a new job instance.
*
* @param \App\Models\MailContactData $data
* @return void
*/
public function __construct(MailContactData $data)
public function __construct(MailContactData $data, string|null $file = null)
{
$this->data = $data;
$this->file = $file;
}
/**
@ -40,7 +50,10 @@ class SendArcadiaMail implements ShouldQueue
*/
public function handle()
{
Mail::to(config('mail.contactsList.contact'))->send(new ContactMail($this->data));
Mail::to(config('mail.contactsList.contact'))->send(new ContactMail($this->data, $this->file));
if (file_exists($this->file)) {
File::deleteDirectory(File::dirname($this->file));
}
Log::debug(sprintf('Sent %s to %s', ContactMail::class, implode(',', config('mail.contactsList.contact'))));
}
}

View file

@ -0,0 +1,58 @@
<?php
namespace App\Jobs\Mails;
use App\Mail\ContactMailNL;
use App\Models\MailContactData;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
class SendNLMail implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
/**
* To be serialized by jobs system
*
* @var MailContactData
* */
private $data;
/**
* The path of a specific file.
*
* @var string|null
* */
private $file;
/**
* Create a new job instance.
*
* @param \App\Models\MailContactData $data
* @return void
*/
public function __construct(MailContactData $data, string|null $file = null)
{
$this->data = $data;
$this->file = $file;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
Mail::to(config('mail.contactsList.contactNL'))->send(new ContactMailNL($this->data));
if (file_exists($this->file)) {
File::deleteDirectory(File::dirname($this->file));
}
Log::debug(sprintf('Sent %s to %s', ContactMailNL::class, implode(',', config('mail.contactsList.contactNL'))));
}
}

View file

@ -26,7 +26,7 @@ class SendPasserelleMail implements ShouldQueue
/**
* The path of a specific file.
*
* @var string
* @var string|null
* */
private $file;
@ -34,10 +34,10 @@ class SendPasserelleMail implements ShouldQueue
* Create a new job instance.
*
* @param \App\Models\MailContactData $data
* @param string $file
* @param string|null $file
* @return void
*/
public function __construct(MailContactData $data, string $file)
public function __construct(MailContactData $data, string|null $file = null)
{
$this->data = $data;
$this->file = $file;
@ -54,6 +54,6 @@ class SendPasserelleMail implements ShouldQueue
if (file_exists($this->file)) {
File::deleteDirectory(File::dirname($this->file));
}
Log::debug(sprintf('Sent %s to %s', ContactComplainMail::class, config('mail.contactsList.passerelle')));
Log::debug(sprintf('Sent %s to %s', ContactComplainMail::class, implode(',', config('mail.contactsList.passerelle'))));
}
}

View file

@ -452,8 +452,7 @@ class ToolboxHelper
$ret = (object)$input;
foreach ($ret as &$item) {
// Recursively process EACH element only if not scalar.
$item = (is_object($item) or is_array($item)) ?
self::arrayToObject($item) : $item;
$item = (is_object($item) or is_array($item)) ? self::arrayToObject($item) : $item;
}
return $ret;
}

View file

@ -60,7 +60,7 @@ class Link implements Jsonable, Arrayable, Stringable
*/
public function getUrl(): string
{
return $this->url ?? route($this->routeName);
return $this->url ?? !is_null($this->routeName) ? route($this->routeName) : '#';
}
/**

View file

@ -10,36 +10,6 @@ use Illuminate\Support\Facades\File;
class ContactComplainMail extends ContactMail
{
use Queueable;
use SerializesModels;
/**
* The order instance.
*
* @var \App\Models\MailContactData
*/
protected $data;
/**
* The path of a specific file.
*
* @var string
*/
protected $file;
/**
* Create a new message instance.
*
* @param \App\Models\MailContactData $data
* @param string|null $file
* @return void
*/
public function __construct(MailContactData $data, string|null $file)
{
$this->data = $data;
$this->file = $file;
}
/**
* Build the message.
*
@ -47,17 +17,9 @@ class ContactComplainMail extends ContactMail
*/
public function build()
{
if ($this->file) {
$this->joinedFileName = sprintf(
'LEGAULOIS_PASS_MESSAGE-PJ-%s.%s',
date("YmdHis"),
File::extension($this->file)
);
}
return $this->view('emails.contact')
return $this->view('emails.contact-passerelle')
->subject(sprintf('Nouveau message consommateur Le Gaulois (%s)', $this->data->type->label()))
->text('emails.contact-plain')
->text('emails.contact-passerelle-plain')
->with('data', $this->data)
->attachData(
view('emails.passerelle-xml', ['data' => $this->data->exportToPasserelleDataArray()])->render(),
@ -65,23 +27,4 @@ class ContactComplainMail extends ContactMail
['mime' => 'application/xml']
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Attachment>
*/
public function attachments(): array
{
if (!$this->file) {
return [];
}
return [
Attachment::fromPath($this->file)->as(sprintf(
'LEGAULOIS_PASS_MESSAGE-PJ-%s.%s',
date("YmdHis"),
File::extension($this->file)
)),
];
}
}

View file

@ -4,8 +4,10 @@ namespace App\Mail;
use App\Models\MailContactData;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Attachment;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\File;
use League\Csv\Bom;
use League\Csv\Writer;
use SplTempFileObject;
@ -23,11 +25,11 @@ class ContactMail extends Mailable
protected $data;
/**
* The joined file name
* The path of a specific file.
*
* @var string
* @var string|null
*/
protected $joinedFileName;
protected $file;
/**
* Create a new message instance.
@ -35,9 +37,10 @@ class ContactMail extends Mailable
* @param \App\Models\MailContactData $data
* @return void
*/
public function __construct(MailContactData $data)
public function __construct(MailContactData $data, string|null $file = null)
{
$this->data = $data;
$this->file = $file;
}
/**
@ -59,6 +62,25 @@ class ContactMail extends Mailable
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Attachment>
*/
public function attachments(): array
{
if (!$this->file) {
return [];
}
return [
Attachment::fromPath($this->file)->as(sprintf(
'LEGAULOIS_PASS_MESSAGE-PJ-%s.%s',
date("YmdHis"),
File::extension($this->file)
)),
];
}
/**
* @return string
*/

View file

@ -0,0 +1,20 @@
<?php
namespace App\Mail;
class ContactMailNL extends ContactMail
{
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this
->subject(sprintf('Nouveau message consommateur Le Gaulois (%s)', $this->data->type->label()))
->view('emails.contactNL')
->text('emails.contactNL-plain')
->with('data', $this->data);
}
}

View file

@ -7,6 +7,7 @@ use App\Enums\Settings\SettingsType;
use App\Lib\Definitions\MenuNode;
use App\Lib\Helpers\FileStorageHelper;
use App\Lib\Link;
use App\Traits\Models\ActivityLog;
use App\Traits\Models\IsCachedAsCollection;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
@ -14,14 +15,14 @@ use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
/**
* @property-read \App\Enums\Settings\SettingsType $type Enum SettingsType.
* ! Note complete this with pipes when adding another SettingsType.
* phpcs:ignore Generic.Files.LineLength.TooLong
* @property array<\App\Lib\Definitions\MenuNode>|array<string,array<string|null>>|array<string,int> $value The actual setting value.
* @package App\Models
* @property-read \App\Enums\Settings\SettingsType $type
* Enum SettingsType.
* @property array<\App\Lib\Definitions\MenuNode>|array<string,array<string|null>>|array<string,int> $value
* The actual setting value.
*/
class GeneralSetting extends Model
{
use ActivityLog;
use IsCachedAsCollection;
/**
@ -132,8 +133,6 @@ class GeneralSetting extends Model
* Get the json layout for a setting type.
*
* @param \App\Enums\Settings\SettingsType $type
*
* ! Note complete this with pipes when adding another SettingsType.
* @return array<\App\Lib\Definitions\MenuNode>|array<string,array<string|null>>
* @throws \ErrorException If $type is unhandled.
*/
@ -160,7 +159,7 @@ class GeneralSetting extends Model
SettingsType::offersCount => [
'count' => 0,
],
SettingsType::breederMapComponent => [
SettingsType::breederMap => [
'title' => 'titre',
'main_text' => 'texte principal',
'picto_text' => 'texte du pictogramme',
@ -175,18 +174,17 @@ class GeneralSetting extends Model
*
* @param \App\Enums\Settings\SettingsType $type
* @param string $json
* ! Note complete this with pipes when adding another SettingsType.
* @return array<\App\Lib\Definitions\MenuNode>|array<string,array<string|null>>
* @throws \ErrorException If $type is unhandled.
*/
public static function valueFromJson(SettingsType $type, string $json): array
{
return match ($type) {
SettingsType::mainMenu => collect(json_decode($json, true))
SettingsType::mainMenu => collect(json_decode($json, true))
->map(fn(array $jsonLayout) => MenuNode::make(...$jsonLayout))->all(),
SettingsType::hotNews => json_decode($json, true),
SettingsType::offersCount => json_decode($json, true),
SettingsType::breederMapComponent => json_decode($json, true),
SettingsType::hotNews => json_decode($json, true),
SettingsType::offersCount => json_decode($json, true),
SettingsType::breederMap => json_decode($json, true),
// @phpstan-ignore-next-line
default => throw new \ErrorException("No instruction to unserialize setting type '{$type->label()}'")
};

View file

@ -19,7 +19,6 @@ use Illuminate\Support\Str;
* @property string $town Picto publish status.
* @property integer $phone Picto publish status.
* @property \App\Enums\ContactFormType $type Picto publish status.
* @property string $onepagesubject Picto publish status.
* @property string $message Picto publish status.
* @property string $joinFile Picto publish status.
* @property string $productName Picto publish status.
@ -59,7 +58,6 @@ class MailContactData extends Model
'town',
'phone',
'type',
'onepagesubject',
'message',
'joinFile',
'productName',
@ -119,7 +117,7 @@ class MailContactData extends Model
$this->postal,
$this->town,
$this->email,
$this->type->equals(ContactFormType::nl) ? $this->onepagesubject : $this->type->value,
$this->type->value,
$this->message,
'0',
'0',
@ -167,9 +165,7 @@ class MailContactData extends Model
$this->limitDateYear ?? '0000'
),
'EMETTEUR_NUM_LOT' => $this->lotNumberName,
'EMETTEUR_MESSAGE' => $this->type->equals(ContactFormType::nl) ?
sprintf('%s \n %s', $this->onepagesubject, $this->message) :
$this->message,
'EMETTEUR_MESSAGE' => $this->message,
'EMETTEUR_PJ' => $this->joinFile,
'DATE_CONSO' => sprintf(
'%s/%s/%s',

View file

@ -5,6 +5,7 @@ namespace App\Models;
use App\Casts\HtmlColor;
use App\Enums\Settings\MenuNodeType;
use App\Lib\Helpers\FileStorageHelper;
use App\Traits\Models\ActivityLog;
use App\Traits\Models\IsCachedAsCollection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -31,6 +32,7 @@ use Illuminate\Database\Eloquent\Model;
*/
class MenuNodeData extends Model
{
use ActivityLog;
use HasFactory;
use IsCachedAsCollection;

View file

@ -168,15 +168,15 @@ class Product extends Model implements SeoInterface
$rangeModel = !is_null($slug) ?
Range::query()->where([['slug', $slug], ['published', true]])->first() :
Range::query()->where('published', true)->orderBy('slug', 'ASC')->first();
return Product::query()->where('published', true)
return Product::query()
->whereHas('subrange', function (Builder $q) use ($rangeModel) {
$q->where('published', true)->whereHas('range', function (Builder $q) use ($rangeModel) {
$q->where('id', $rangeModel->getKey());
});
})
})->where('published', true)
->orWhereHas('range', function (Builder $q) use ($rangeModel) {
$q->where('id', $rangeModel->getKey());
})
})->where('published', true)
->inRandomOrder()
->limit(6)
->get()

View file

@ -88,7 +88,7 @@ class ViewServiceProvider extends ServiceProvider
collect([
['name' => 'mainMenuSettingModel', 'enum' => SettingsType::mainMenu],
['name' => 'hotNewsSettingModel', 'enum' => SettingsType::hotNews],
['name' => 'breederMapComponentSettingModel', 'enum' => SettingsType::breederMapComponent],
['name' => 'breederMapSettingModel', 'enum' => SettingsType::breederMap],
])->map(function ($array) {
View::share($array['name'], (function () use ($array) {
return GeneralSetting::getCachedGeneralSetting($array['enum']) ?: null;
@ -114,6 +114,7 @@ class ViewServiceProvider extends ServiceProvider
['name' => 'confidentialityStaticPageModel', 'value' => StaticPage::getCachedStaticPage(StaticPageType::confidentiality)],
['name' => 'sellingStaticPageModel', 'value' => StaticPage::getCachedStaticPage(StaticPageType::selling)],
['name' => 'accessibilityStaticPageModel', 'value' => StaticPage::getCachedStaticPage(StaticPageType::accessibility)],
['name' => 'contactStaticPageModel', 'value' => StaticPage::getCachedStaticPage(StaticPageType::contact)],
['name' => 'productStaticPageModel', 'value' => StaticPage::getCachedStaticPage(StaticPageType::product)],
['name' => 'breedingPoultryStaticPageModel', 'value' => StaticPage::getCachedStaticPage(StaticPageType::breedingPoultry)],
['name' => 'breedingJobStaticPageModel', 'value' => StaticPage::getCachedStaticPage(StaticPageType::breedingJob)],

View file

@ -65,9 +65,9 @@ trait HasPicture
bool $sometimes = false,
): array {
$dimensions = (object)[
'minWidth' => $minWidth ?? $this->minWidth,
'minWidth' => $minWidth ?? $this->minWidth,
'minHeight' => $minHeight ?? $this->minHeight,
'maxWidth' => $maxWidth ?? $this->maxWidth,
'maxWidth' => $maxWidth ?? $this->maxWidth,
'maxHeight' => $maxHeight ?? $this->maxHeight
];
return [
@ -153,7 +153,6 @@ trait HasPicture
$this->merge([
$name => $changedPicture
]);
// FIXME: patch because of component return.
} elseif (is_null($picturePath)) {
$this->merge([$name => null]);
return;

View file

@ -98,8 +98,9 @@ return [
// Contacts List.
'contactsList' => [
'contact' => [env('MAIL_LIST_CONTACT', 'contact.legaulois@ldc.fr')],
'passerelle' => env('MAIL_LIST_PASSERELLE', 'passerelle.ldc@ldc.fr'),
'contact' => explode(',', env('MAIL_LIST_CONTACT')),
'passerelle' => explode(',', env('MAIL_LIST_PASSERELLE')),
'contactNL' => explode(',', env('MAIL_LIST_NL')),
],
/*

View file

@ -14,8 +14,8 @@ return new class extends Migration
public function up(): void
{
GeneralSetting::query()->insert([
'type' => SettingsType::breederMapComponent,
'value' => json_encode(GeneralSetting::getJsonLayout(SettingsType::breederMapComponent)),
'type' => SettingsType::breederMap,
'value' => json_encode(GeneralSetting::getJsonLayout(SettingsType::breederMap)),
'created_at' => now(),
'updated_at' => now()
]);
@ -28,6 +28,6 @@ return new class extends Migration
*/
public function down(): void
{
GeneralSetting::query()->where('type', SettingsType::breederMapComponent)->firstOrFail()->deleteQuietly();
GeneralSetting::query()->where('type', SettingsType::breederMap)->firstOrFail()->deleteQuietly();
}
};

View file

@ -20,6 +20,9 @@ data:
MAIL_ENCRYPTION: "${APP_MAIL_ENCRYPTION}"
MAIL_FROM_ADDRESS: "${APP_MAIL_FROM_ADDRESS}"
MAIL_FROM_NAME: "${APP_NAME}"
MAIL_LIST_CONTACT: "${APP_MAIL_LIST_CONTACT}"
MAIL_LIST_PASSERELLE: "${APP_MAIL_LIST_PASSERELLE}"
MAIL_LIST_NL: "${APP_MAIL_LIST_NL}"
CRM_ENDPOINT: "${APP_CRM_ENDPOINT}"
CRM_TOKEN: "${APP_CRM_TOKEN}"
CRM_PASSWORD: "${APP_CRM_PASSWORD}"
@ -48,7 +51,7 @@ metadata:
spec:
storageClassName: "csi-cinder-classic"
accessModes:
- ReadWriteOnce
- ReadWriteOnce
resources:
requests:
storage: $APP_PVC_SIZE
@ -69,25 +72,25 @@ spec:
app: ${CI_PROJECT_PATH_SLUG}-app
spec:
containers:
- name: ${CI_PROJECT_PATH_SLUG}-container
image: $IMAGE_TAG
envFrom:
- configMapRef:
name: ${CI_PROJECT_PATH_SLUG}-config-map
volumeMounts:
- name: storage
mountPath: /app/srcs/storage
- name: ${CI_PROJECT_PATH_SLUG}-container
image: $IMAGE_TAG
envFrom:
- configMapRef:
name: ${CI_PROJECT_PATH_SLUG}-config-map
volumeMounts:
- name: storage
mountPath: /app/srcs/storage
imagePullSecrets:
- name: docker-registry-credentials
- name: docker-registry-credentials
securityContext:
runAsUser: 33
runAsGroup: 33
fsGroup: 33
fsGroupChangePolicy: "OnRootMismatch"
volumes:
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
---
apiVersion: v1
@ -98,8 +101,8 @@ spec:
selector:
app: ${CI_PROJECT_PATH_SLUG}-app
ports:
- port: 80
targetPort: 443
- port: 80
targetPort: 443
---
apiVersion: traefik.io/v1alpha1
@ -108,14 +111,14 @@ metadata:
name: ${CI_PROJECT_PATH_SLUG}-ingress-route
spec:
entryPoints:
- web
- websecure
- web
- websecure
routes:
- match: Host(`${APP_DOMAIN}`) || Host(`www.${APP_DOMAIN}`)
kind: Rule
services:
- name: ${CI_PROJECT_PATH_SLUG}-service
port: 80
- match: Host(`${APP_DOMAIN}`) || Host(`www.${APP_DOMAIN}`)
kind: Rule
services:
- name: ${CI_PROJECT_PATH_SLUG}-service
port: 80
tls:
secretName: ${CRT_TLS_NAME}
@ -133,35 +136,35 @@ spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- ${CI_PROJECT_PATH_SLUG}-app
topologyKey: "kubernetes.io/hostname"
namespaces: [$KUBE_NAMESPACE]
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- ${CI_PROJECT_PATH_SLUG}-app
topologyKey: "kubernetes.io/hostname"
namespaces: [$KUBE_NAMESPACE]
containers:
- name: ${CI_PROJECT_PATH_SLUG}-scheduled
image: $IMAGE_TAG
imagePullPolicy: IfNotPresent
command:
- "php"
args:
- "artisan"
- "schedule:run"
envFrom:
- configMapRef:
name: ${CI_PROJECT_PATH_SLUG}-config-map
volumeMounts:
- name: storage
mountPath: /app/srcs/storage
- name: ${CI_PROJECT_PATH_SLUG}-scheduled
image: $IMAGE_TAG
imagePullPolicy: IfNotPresent
command:
- "php"
args:
- "artisan"
- "schedule:run"
envFrom:
- configMapRef:
name: ${CI_PROJECT_PATH_SLUG}-config-map
volumeMounts:
- name: storage
mountPath: /app/srcs/storage
imagePullSecrets:
- name: docker-registry-credentials
- name: docker-registry-credentials
volumes:
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
securityContext:
runAsUser: 33
runAsGroup: 33

8
package-lock.json generated
View file

@ -14,7 +14,7 @@
"@fortawesome/free-regular-svg-icons": "^6.5.1",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/vue-fontawesome": "^3.0.5",
"@ldc-web/cookie-notice": "^6.0.3",
"@ldc-web/cookie-notice": "^6.1.0",
"@sipec/vue3-tags-input": "^3.0.4",
"@types/aos": "^3.0.7",
"@types/bootstrap": "^5.2.7",
@ -1101,9 +1101,9 @@
"dev": true
},
"node_modules/@ldc-web/cookie-notice": {
"version": "6.0.3",
"resolved": "https://lab.s-web.fr/api/v4/projects/50/packages/npm/@ldc-web/cookie-notice/-/@ldc-web/cookie-notice-6.0.3.tgz",
"integrity": "sha1-mW2DD+8ipWkmvKhZ3m9h5wemAHI=",
"version": "6.1.0",
"resolved": "https://lab.s-web.fr/api/v4/projects/50/packages/npm/@ldc-web/cookie-notice/-/@ldc-web/cookie-notice-6.1.0.tgz",
"integrity": "sha1-bzewvM6mGuWr3Ju8/HWkxXm60+A=",
"dev": true
},
"node_modules/@nodelib/fs.scandir": {

View file

@ -22,7 +22,7 @@
"@fortawesome/free-regular-svg-icons": "^6.5.1",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/vue-fontawesome": "^3.0.5",
"@ldc-web/cookie-notice": "^6.0.3",
"@ldc-web/cookie-notice": "^6.1.0",
"@sipec/vue3-tags-input": "^3.0.4",
"@types/aos": "^3.0.7",
"@types/bootstrap": "^5.2.7",

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 KiB

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View file

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

View file

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View file

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 MiB

After

Width:  |  Height:  |  Size: 977 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 775 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,007 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View file

@ -1,43 +1,43 @@
{
"homepage": "startseite",
"40years.more-gifts-to-win": "Noch mehr Geschenke zu gewinnen",
"40years.section1.more-gifts-to-win": "Noch mehr Geschenke zu gewinnen",
"40years.collect-points": "Sammeln Sie Punkte und wählen Sie Ihre Geschenke in unserem Shop aus!",
"40years.1euro-spent": "1€ ausgegeben",
"40years.1point-collected": "1 Punkt gesammelt",
"40years.2-levels": "2 Stufen",
"40years.many-gifts": "zahlreiche Geschenke",
"40years.discover-our-store": "Entdecken Sie unseren Shop",
"40years.find-the-golden-magnets": "Finden Sie die goldenen Magneten",
"40years.win-a-surprise": "und gewinnen Sie eine Überraschung!",
"40years.hide-golden-magnet": "Zu seinem 40-jährigen Jubiläum hat Le Gaulois 94 goldene Magneten",
"40years.in-his-panes-cases": "in seinen Schachteln von panierten Produkten versteckt!",
"40years.i-discover": "Ich entdecke",
"40years.a-golden-magnet": "einen goldenen Magnet",
"40years.i-win": "Ich gewinne",
"40years.a-collector-map": "eine Sammlerkarte von Frankreich, die von einem jungen französischen Künstler entworfen wurde, und eine komplette Sammlung goldener Magnete!",
"40years.happy-searching": "Viel Spaß beim Suchen!",
"40years.play-with-us": "Spielen Sie mit uns!",
"40years.more-gifts": "Noch mehr Geschenke!",
"40years.banner": "Seit 40 Jahren verpflichtet sich Le Gaulois, Produkte anzubieten, die zu <strong>100% aus Frankreich stammen</strong> mit <strong>Geflügel, das in unserem Land geboren, aufgezogen und verarbeitet wurde.</strong> <br><strong>40 Jahre Geselligkeit und Freude \"à la française\", die wir mit Ihnen teilen möchten!</strong><br> Entdecken Sie in diesem festlichen Jahr <strong>unsere Spiele und Überraschungen.</strong>",
"40years.game-title": "40 Jahre!",
"40years.game-subtitle": "Das Jubiläum aller Gaulois",
"40years.visit-your-store": "Finden Sie unsere Produkte in den Geschäften und haben Sie die Chance, tolle Geschenke zu gewinnen!",
"40years.dream-stays": "Traumaufenthalte",
"40years.dream-stays-subtitle": "im Wert von 4.000 €",
"40years.camera": "Kameras",
"40years.discount-title": "Tausende",
"40years.discount-subtitle": "von Rabattgutscheinen",
"40years.how-to": "Wie wird",
"40years.play": "gespielt?",
"40years.bearing-products-top": "Zahlreiche Produkte,",
"40years.bearing-products-bottom": "die Angebote tragen",
"40years.to-participate": "Um teilzunehmen, kaufen Sie eines unserer Produkte, das den Aufkleber trägt.",
"40years.see-you-in-store": "Wir sehen uns im Geschäft!",
"40years.i-participate": "Ich nehme am Spiel teil",
"40years.section4.2-levels": "2 Stufen",
"40years.section4.many-gifts": "zahlreiche Geschenke",
"40years.section4.discover-our-store": "Entdecken Sie unseren Shop",
"40years.section4.find-the-golden-magnets": "Finden Sie die goldenen Magneten",
"40years.section4.win-a-surprise": "und gewinnen Sie eine Überraschung!",
"40years.section4.hide-golden-magnet": "Zu seinem 40-jährigen Jubiläum hat Le Gaulois 94 goldene Magneten",
"40years.section4.in-his-panes-cases": "in seinen Schachteln von panierten Produkten versteckt!",
"40years.section4.i-discover": "Ich entdecke",
"40years.section4.a-golden-magnet": "einen goldenen Magnet",
"40years.section4.i-win": "Ich gewinne",
"40years.section4.a-collector-map": "eine Sammlerkarte von Frankreich, die von einem jungen französischen Künstler entworfen wurde, und eine komplette Sammlung goldener Magnete!",
"40years.section4.happy-searching": "Viel Spaß beim Suchen!",
"40years.section1.play-with-us": "Spielen Sie mit uns!",
"40years.section1.more-gifts": "Noch mehr Geschenke!",
"40years.section1.banner": "Seit 40 Jahren verpflichtet sich Le Gaulois, Produkte anzubieten, die zu <strong>100% aus Frankreich stammen</strong> mit <strong>Geflügel, das in unserem Land geboren, aufgezogen und verarbeitet wurde.</strong> <br><strong>40 Jahre Geselligkeit und Freude \"à la française\", die wir mit Ihnen teilen möchten!</strong><br> Entdecken Sie in diesem festlichen Jahr <strong>unsere Spiele und Überraschungen.</strong>",
"40years.section3.game-title": "40 Jahre!",
"40years.section3.game-subtitle": "Das Jubiläum aller Gaulois",
"40years.section3.visit-your-store": "Finden Sie unsere Produkte in den Geschäften und haben Sie die Chance, tolle Geschenke zu gewinnen!",
"40years.section3.dream-stays": "Traumaufenthalte",
"40years.section3.dream-stays-subtitle": "im Wert von 4.000 €",
"40years.section3.camera": "Kameras",
"40years.section3.discount-title": "Tausende",
"40years.section3.discount-subtitle": "von Rabattgutscheinen",
"40years.section3.how-to": "Wie wird",
"40years.section3.play": "gespielt?",
"40years.section3.bearing-products-top": "Zahlreiche Produkte,",
"40years.section3.bearing-products-bottom": "die Angebote tragen",
"40years.section3.to-participate": "Um teilzunehmen, kaufen Sie eines unserer Produkte, das den Aufkleber trägt.",
"40years.section3.see-you-in-store": "Wir sehen uns im Geschäft!",
"40years.section3.i-participate": "Ich nehme am Spiel teil",
"40years.breadcrumb": "40 Jahre! Das Jubiläum aller Gaulois",
"40years.animations": "Animationen in den Geschäften!",
"40years.highlight": "Highlights",
"40years.highlight-date": "vom 2. September bis zum 30. November",
"40years.section3.animations": "Animationen in den Geschäften!",
"40years.section3.highlight": "Highlights",
"40years.section3.highlight-date": "vom 2. September bis zum 30. November",
"40years.who-are-we.tagline.alt": "Logo Le Gaulois mit dem Slogan \"C'est bon d'être Gaulois\" (Es ist gut, Gallier zu sein) mit einem Holztisch und -stuhl im Hintergrund",
"40years.who-are-we.tagline.title": "Logo Le Gaulois mit dem Slogan \"C'est bon d'être Gaulois\"",
"40years.who-are-we.title": "Wer sind wir?",

View file

@ -52,44 +52,44 @@
"You are logged in!": "You are logged in!",
"You are receiving this email because we received a password reset request for your account.": "You are receiving this email because we received a password reset request for your account.",
"homepage": "homepage",
"40years.more-gifts-to-win": "Even more gifts to win",
"40years.section1.more-gifts-to-win": "Even more gifts to win",
"40years.collect-points": "Collect points and choose your gifts in our store!",
"40years.1euro-spent": "1€ spent",
"40years.1point-collected": "1 point collected",
"40years.2-levels": "2 levels",
"40years.many-gifts": "Many gifts",
"40years.discover-our-store": "Discover our store",
"40years.find-the-golden-magnets": "Find the golden magnets",
"40years.win-a-surprise": "and win a surprise!",
"40years.hide-golden-magnet": "For his 40th birthday, Le Gaulois hid 94 golden magnets",
"40years.in-his-panes-cases": "in his Panés cases",
"40years.i-discover": "I discovered",
"40years.a-golden-magnet": "a golden magnet",
"40years.i-win": "I won",
"40years.a-collector-map": "a 40th anniversary collector's card of France created by a young French artist and a complete collection of golden magnets!",
"40years.happy-searching": "Happy searching everyone!",
"40years.play-with-us": "Play with us!",
"40years.more-gifts": "Even more gifts!",
"40years.banner": "For 40 years, Le Gaulois has been committed to offering products <strong>100% of French origin</strong> with <strong>poultry born, raised and prepared</strong> in our territory. <br><strong>40 years of French conviviality to share with you!</strong><br> During this festive year, discover <strong>our games and our surprises.</strong>",
"40years.game-title": "40 years!",
"40years.game-subtitle": "The birthday of all our Gaulois",
"40years.visit-your-store": "Visit your local store for a chance to win exceptional gifts!",
"40years.dream-stays": "Dream stays",
"40years.dream-stays-subtitle": "worth €4,000",
"40years.camera": "Cameras",
"40years.discount-title": "Thousands",
"40years.discount-subtitle": "of discount vouchers",
"40years.how-to": "How to",
"40years.play": "play?",
"40years.bearing-products-top": "Many",
"40years.bearing-products-bottom": "bearing products",
"40years.to-participate": "To participate, purchase one of our products bearing the sticker.",
"40years.see-you-in-store": "See you in store!",
"40years.i-participate": "I participate",
"40years.section4.2-levels": "2 levels",
"40years.section4.many-gifts": "Many gifts",
"40years.section4.discover-our-store": "Discover our store",
"40years.section4.find-the-golden-magnets": "Find the golden magnets",
"40years.section4.win-a-surprise": "and win a surprise!",
"40years.section4.hide-golden-magnet": "For his 40th birthday, Le Gaulois hid 94 golden magnets",
"40years.section4.in-his-panes-cases": "in his Panés cases",
"40years.section4.i-discover": "I discovered",
"40years.section4.a-golden-magnet": "a golden magnet",
"40years.section4.i-win": "I won",
"40years.section4.a-collector-map": "a 40th anniversary collector's card of France created by a young French artist and a complete collection of golden magnets!",
"40years.section4.happy-searching": "Happy searching everyone!",
"40years.section1.play-with-us": "Play with us!",
"40years.section1.more-gifts": "Even more gifts!",
"40years.section1.banner": "For 40 years, Le Gaulois has been committed to offering products <strong>100% of French origin</strong> with <strong>poultry born, raised and prepared</strong> in our territory. <br><strong>40 years of French conviviality to share with you!</strong><br> During this festive year, discover <strong>our games and our surprises.</strong>",
"40years.section3.game-title": "40 years!",
"40years.section3.game-subtitle": "The birthday of all our Gaulois",
"40years.section3.visit-your-store": "Visit your local store for a chance to win exceptional gifts!",
"40years.section3.dream-stays": "Dream stays",
"40years.section3.dream-stays-subtitle": "worth €4,000",
"40years.section3.camera": "Cameras",
"40years.section3.discount-title": "Thousands",
"40years.section3.discount-subtitle": "of discount vouchers",
"40years.section3.how-to": "How to",
"40years.section3.play": "play?",
"40years.section3.bearing-products-top": "Many",
"40years.section3.bearing-products-bottom": "bearing products",
"40years.section3.to-participate": "To participate, purchase one of our products bearing the sticker.",
"40years.section3.see-you-in-store": "See you in store!",
"40years.section3.i-participate": "I participate",
"40years.breadcrumb": "40 years! The birthday of all our Gaulois",
"40years.animations": "In-store events!",
"40years.highlight": "Highlight",
"40years.highlight-date": "from September 2 to November 30",
"40years.section3.animations": "In-store events!",
"40years.section3.highlight": "Highlight",
"40years.section3.highlight-date": "from September 2 to November 30",
"40years.who-are-we.tagline.alt": "Le Gaulois logo with the slogan \"C'est bon d'être Gaulois\" with a wooden table and chair in the background",
"40years.who-are-we.tagline.title": "Le Gaulois logo with the slogan \"C'est bon d'être Gaulois\"",
"40years.who-are-we.title": "About us",

View file

@ -53,51 +53,134 @@
"You are receiving this email because we received a password reset request for your account.": "Vous recevez cet e-mail car nous avons reçu une demande de réinitialisation de mot de passe pour votre compte.",
"homepage": "accueil",
"switch-language": "Accéder à la page :lang",
"40years.more-gifts-to-win": "Encore + de cadeaux à gagner",
"40years.collect-points": "Collectez des points et choisissez vos cadeaux dans notre boutique !",
"40years.1euro-spent": "1€ dépensé",
"40years.1point-collected": "1 point collecté",
"40years.2-levels": "2 paliers",
"40years.many-gifts": "de nombreux cadeaux",
"40years.discover-our-store": "Découvrez notre boutique",
"40years.find-the-golden-magnets": "Trouvez les magnets dorés",
"40years.win-a-surprise": "et remportez une surprise !",
"40years.hide-golden-magnet": "Pour ses 40 ans, Le Gaulois a caché 94 magnets dorés",
"40years.in-his-panes-cases": "dans ses étuis de Panés",
"40years.i-discover": "Je découvre",
"40years.a-golden-magnet": "un Magnet doré",
"40years.i-win": "Je gagne",
"40years.a-collector-map": "une carte de France collector 40 ans créée par un jeune artiste français et une collection complète de magnets dorés !",
"40years.happy-searching": "Bonne recherche à tous !",
"40years.play-with-us": "Jouez avec nous !",
"40years.more-gifts": "Encore + de cadeaux !",
"40years.banner": "Depuis 40 ans, Le Gaulois s'engage à proposer des produits <strong>100 % origine France</strong> avec des <strong>volailles nées, élevées et préparées</strong> sur notre territoire. <br><strong>40 ans de convivialité et de plaisir à la française, à partager avec vous !</strong><br> Pendant cette année festive, découvrez <strong>nos jeux et nos surprises.</strong>",
"40years.game-title": "Le jeu des 40 ans",
"40years.game-subtitle": "100% gagnant",
"40years.visit-your-store": "Rendez-vous en magasin, et tentez de remporter des cadeaux exceptionnels !",
"40years.dream-stays": "Séjours de rêve",
"40years.dream-stays-subtitle": "d'une valeur de 4000€",
"40years.camera": "Appareils photos",
"40years.discount-title": "Des<br> milliers",
"40years.discount-subtitle": "de bons de réduction",
"40years.how-to": "Comment",
"40years.play": "jouer ?",
"40years.bearing-products-top": "De nombreux",
"40years.bearing-products-bottom": "produits porteurs",
"40years.to-participate": "Pour participer, achetez un de nos produits porteurs du sticker.",
"40years.see-you-in-store": "Rendez-vous en magasin !",
"40years.i-participate": "Je participe",
"40years.breadcrumb": "40 ans ! L'anniversaire de tous les Gaulois",
"40years.animations": "Des animations en magasin\u00A0!",
"40years.highlight": "Temps fort",
"40years.highlight-date": "du 2 septembre au 30 novembre",
"40years.section1.banner": "Depuis 40 ans, Le Gaulois s'engage à proposer des produits <strong>100 % origine France</strong> avec des <strong>volailles nées, élevées et préparées</strong> sur notre territoire. <br><strong>40 ans de convivialité et de plaisir à la française, à partager avec vous !</strong><br> Pendant cette année festive, découvrez <strong>nos jeux et nos surprises.</strong>",
"40years.section1.logo-40ans-alt": "40 ans Le Gaulois ",
"40years.section1.logo-birthday-alt": "L'anniversaire de tous les gaulois",
"40years.section1.more-gifts": "Encore + de cadeaux !",
"40years.section1.play-with-us": "Jouez avec nous !",
"40years.section2.birthday.happy-birthday": "Bon anniversaire à tous nos Gaulois !",
"40years.section2.birthday.text": "Pour notre <strong>40e anniversaire</strong>, nous célébrons avec nos <strong>68 millions de Gaulois</strong>, notre attachement pour des produits <strong>français et authentiques</strong>, qui reflètent nos <strong>valeurs de qualité, accessibilité et de transparence.</strong>",
"40years.section2.birthday.title-part-1": "L'anniversaire de",
"40years.section2.birthday.title-part-2": "68 millions",
"40years.section2.birthday.title-part-3": "de Gaulois !",
"40years.section3.animations": "Des animations en magasin\u00A0!",
"40years.section3.bearing-products-bottom": "produits porteurs",
"40years.section3.bearing-products-top": "De nombreux",
"40years.section3.camera-alt": "Appareils photos",
"40years.section3.camera-title": "Appareils photos",
"40years.section3.camera": "Appareils photos",
"40years.section3.discount-pic-alt": "Bons de réduction de 1€",
"40years.section3.discount-pic-title": "Bons de réduction de 1€",
"40years.section3.discount-subtitle": "de bons de réduction",
"40years.section3.discount-title": "Des<br> milliers",
"40years.section3.dream-stays-alt": "Séjours de rêve",
"40years.section3.dream-stays-subtitle": "d'une valeur de 4000€",
"40years.section3.dream-stays-title": "Séjours de rêve",
"40years.section3.dream-stays": "Séjours de rêve",
"40years.section3.game-subtitle": "100% gagnant",
"40years.section3.game-title": "Le jeu des 40 ans",
"40years.section3.highlight-date": "du 2 septembre au 30 novembre",
"40years.section3.highlight": "Temps fort",
"40years.section3.how-to": "Comment",
"40years.section3.i-participate": "Je participe",
"40years.section3.participate.sticker-alt": "Sticker du jeu 100% gagnant Le Gaulois",
"40years.section3.play": "jouer ?",
"40years.section3.product-1-alt": "Packaging des cuisses de poulet Oui c'est Bon Le Gaulois",
"40years.section3.product-1-title": "Packaging des cuisses de poulet Oui c'est Bon Le Gaulois",
"40years.section3.product-10-alt": "Packaging du poulet 'le bon fumé' Le Gaulois",
"40years.section3.product-10-title": "Packaging du poulet 'le bon fumé' Le Gaulois",
"40years.section3.product-11-alt": "Packaging des grignottes extra rôti Le Gaulois",
"40years.section3.product-11-title": "Packaging des grignottes extra rôti Le Gaulois",
"40years.section3.product-2-alt": "Packaging de l'escalope cordon bleu de poulet Le Gaulois",
"40years.section3.product-2-title": "Packaging de l'escalope cordon bleu de poulet Le Gaulois",
"40years.section3.product-3-alt": "Packaging des émincés de filet de poulet rôti Le Gaulois",
"40years.section3.product-3-title": "Packaging des émincés de filet de poulet rôti Le Gaulois",
"40years.section3.product-4-alt": "Packaging des milanaises natures Le Gaulois",
"40years.section3.product-4-title": "Packaging des milanaises natures Le Gaulois",
"40years.section3.product-5-alt": "Packaging des filets de canard Le Gaulois",
"40years.section3.product-5-title": "Packaging des filets de canard Le Gaulois",
"40years.section3.product-6-alt": "Packaging des croques végétal Le Gaulois",
"40years.section3.product-6-title": "Packaging des croques végétal Le Gaulois",
"40years.section3.product-7-alt": "Packaging des cuisses de lapins Le Gaulois",
"40years.section3.product-7-title": "Packaging des cuisses de lapins Le Gaulois",
"40years.section3.product-8-alt": "Packaging des escalopes de dinde extra tendre Le Gaulois",
"40years.section3.product-8-title": "Packaging des escalopes de dinde extra tendre Le Gaulois",
"40years.section3.product-9-alt": "Packaging des blancs de poulet Le Gaulois",
"40years.section3.product-9-title": "Packaging des blancs de poulet Le Gaulois",
"40years.section3.see-you-in-store": "Rendez-vous en magasin !",
"40years.section3.stand-alt": "Animation magasin 40 ans Le Gaulois",
"40years.section3.stand-title": "Animation magasin 40 ans Le Gaulois",
"40years.section3.to-participate": "Pour participer, achetez un de nos produits porteurs du sticker.",
"40years.section3.visit-your-store": "Rendez-vous en magasin, et tentez de remporter des cadeaux exceptionnels !",
"40years.section4.1euro-spent": "1€ dépensé",
"40years.section4.1point-collected": "1 point collecté",
"40years.section4.2-levels": "2 paliers",
"40years.section4.7-families-alt": "Jeu de 7 familles Le Gaulois",
"40years.section4.7-families-title": "Jeu de 7 familles Le Gaulois",
"40years.section4.a-collector-map": "une carte de France collector 40 ans créée par un jeune artiste français et une collection complète de magnets dorés !",
"40years.section4.a-golden-magnet": "un magnet doré",
"40years.section4.collect-points": "Collectez des points et choisissez vos cadeaux dans notre boutique !",
"40years.section4.discover-our-store": "Découvrez notre boutique",
"40years.section4.find-the-golden-magnets": "Trouvez les magnets dorés",
"40years.section4.golden-magnet-alt": "Magnet doré Le Gaulois Sarthe",
"40years.section4.golden-magnet-title": "Magnet doré Le Gaulois Sarthe",
"40years.section4.happy-searching": "Bonne recherche à tous !",
"40years.section4.hide-golden-magnet": "Pour ses 40 ans, Le Gaulois a caché 94 magnets dorés",
"40years.section4.i-discover": "Je découvre",
"40years.section4.i-win": "Je gagne",
"40years.section4.in-his-panes-cases": "dans ses étuis de Panés",
"40years.section4.many-gifts": "de nombreux cadeaux",
"40years.section4.more-gifts-to-win": "Encore + de cadeaux à gagner",
"40years.section4.plush-alt": "Peluche cocotte Le Gaulois",
"40years.section4.plush-title": "Peluche cocotte Le Gaulois",
"40years.section4.sticker-alt": "1€ dépensé = 1 point collecté",
"40years.section4.sticker-title": "1€ dépensé = 1 point collecté",
"40years.section4.win-a-surprise": "et remportez une surprise !",
"40years.who-are-we.content1": "<strong>En France, le repas c'est sacré !</strong> C'est le moment de convivialité qui compte le plus, qu'on soit en famille, en couple ou entre amis. A table, c'est l'occasion de parler, beaucoup parler, d'avoir de grands débats, pas toujours justifiés, mais tous animés!",
"40years.who-are-we.content2": "Nous, les français, sommes fiers de partager des valeurs, un savoir-vivre, une vraie culture culinaire, un bonheur de manger et de vivre unique au monde : <strong>“ Le bon vivre à la française ! ”</strong>",
"40years.who-are-we.content3": "Le Gaulois s'engage à offrir à ses consommateur un savoir-faire volailler d'excellence. Car votre plaisir est notre priorité, nous vous engageons une qualité pleine de gourmandise pour bien manger à la française.",
"40years.who-are-we.content4": "Le Gaulois propose des produits bons pour la santé pour une alimentation équilibrée. Avec une volaille née, élevée et préparée en France. Le Gaulois offre des produits 100% Français. Une marque qui redonne goût aux bonnes choses et à la convivialité.",
"40years.who-are-we.h3-title1": "Le Gaulois, une marque qui véhicule le bon vivre",
"40years.who-are-we.h3-title2": "Le Gaulois, une marque à la française",
"40years.who-are-we.tagline.alt": "Logo Le Gaulois avec le slogan \"C'est bon d'être Gaulois\" avec en fond une table et une chaise en bois",
"40years.who-are-we.tagline.title": "Logo Le Gaulois avec le slogan \"C'est bon d'être Gaulois\"",
"40years.who-are-we.title": "Qui sommes-nous ?",
"40years.who-are-we.content1": "<strong>En France, le repas c'est sacré !</strong> C'est le moment de convivialité qui compte le plus, qu'on soit en famille, en couple ou entre amis. A table, c'est l'occasion de parler, beaucoup parler, d'avoir de grands débats, pas toujours justifiés, mais tous animés!",
"40years.who-are-we.content2": "Nous, les français, sommes fiers de partager des valeurs, un savoir-vivre, une vraie culture culinaire, un bonheur de manger et de vivre unique au monde : <strong>“ Le bon vivre à la française ! ”</strong>",
"40years.who-are-we.h3-title1": "Le Gaulois, une marque qui véhicule le bon vivre",
"40years.who-are-we.content3": "Le Gaulois s'engage à offrir à ses consommateur un savoir-faire volailler d'excellence. Car votre plaisir est notre priorité, nous vous engageons une qualité pleine de gourmandise pour bien manger à la française.",
"40years.who-are-we.h3-title2": "Le Gaulois, une marque à la française",
"40years.who-are-we.content4": "Le Gaulois propose des produits bons pour la santé pour une alimentation équilibrée. Avec une volaille née, élevée et préparée en France. Le Gaulois offre des produits 100% Français. Une marque qui redonne goût aux bonnes choses et à la convivialité."
"contact.attachment.allowed-formats": "Formats acceptés : :formats",
"contact.attachment.max-size": "Taille max : :max",
"contact.batch-number-helper": "Vous pouvez également trouver le n° de lot sous la dénomination \"n° de traçabilité\" ou \"n° trac\" ou à côté de la date.",
"contact.complain": "Réclamation produit",
"contact.gdpr-text-1": "Les informations qui vous concernent sont destinées à un usage interne et ne seront en aucun cas transmises à des tiers. Vous disposez d'un droit d'accès, de modification, de rectification et de suppression des données qui vous concernent (art. 34 de la loi \"Informatique et Libertés\").",
"contact.gdpr-text-2-part-1-link-label": "cookies",
"contact.gdpr-text-2-part-1-link-title": "Gérer les cookies",
"contact.gdpr-text-2-part-1": "Pour envoyer votre formulaire, vous devez accepter les :link.",
"contact.gdpr-text-2-part-2": "Les informations recueillies à partir de ce formulaire sont traitées par le Responsable de Traitement pour donner suite à votre demande de contact.",
"contact.gdpr-text-2-part-3-link-label": "Charte de confidentialité",
"contact.gdpr-text-2-part-3-link-title": "Visiter la page: Charte de confidentialité",
"contact.gdpr-text-2-part-3": "Pour connaître vos droits, vous pouvez consulter la :link.",
"contact.message_contact_failed": "Une erreur est survenue durant l'envoi de votre message. Veuillez réessayer ultèrieurement.",
"contact.message_contact_send": "Votre message a été envoyé avec succès.",
"contact.personnal-infos": "Mes coordonnées",
"contact.placeholder.day": "jj",
"contact.placeholder.month": "mm",
"contact.placeholder.year": "aaaa",
"contact.required-fields": "Champs obligatoires",
"contact.send": "Envoyer",
"contact.subject": "Objet de votre demande",
"contact.want-to-write": "Je souhaite rédiger une réclamation",
"40years.section2.grandpa-share-alt": "Partage d'un blanc de dinde Le Gaulois entre un grand père et son petit-fils",
"40years.section2.grandpa-share-title": "Partage d'un blanc de dinde Le Gaulois à table",
"40years.section2.conviviality-alt": "Convivialité et partage au sein de l'équipe Le Gaulois",
"40years.section2.conviviality-title": "Convivialité et partage chez Le Gaulois",
"40years.section2.cutlet-alt": "Escalope de volaille française Le Gaulois",
"40years.section2.cutlet-title": "Escalope de volaille française Le Gaulois",
"40years.section2.birthday-alt": "Famille et amis souflent les bougie du gateau d'anniversaire Le Gaulois",
"40years.section2.birthday-title": "Fête d'anniversaire Le Gaulois entre la famille et amis",
"40years.section2.auguste-lambert-alt": "Photo de famille de Auguste Lambert en 1909 sur un marché sarthois",
"40years.section2.auguste-lambert-title": "Photo de famille de Auguste Lambert sur un marché sarthois",
"40years.section2.deco-firework-alt": "Feux d'artfice bleu blanc rouge",
"40years.section2.deco-blue-gift-alt": "Cadeaux bleu",
"40years.section2.deco-red-gift-alt": "Cadeaux rouge",
"40years.section2.deco-cotillions-alt": "Cotillons bleu blanc rouge",
"40years.section2.flag-alt": "Drapeau Français"
}

View file

@ -10,5 +10,35 @@ return [
"conceptor" => "concepteur",
"admin" => "administrateur",
"visitor" => "visiteur",
],
'contact-form-type' => [
'none' => [
'label' => 'Aucun',
'description' => 'Aucun objet',
],
'complain' => [
'label' => 'Une réclamation',
'description' => 'Je souhaite obtenir de l\'aide car je désire envoyer une réclamation sur un produit',
],
'club' => [
'label' => 'Le Club des Gaulois',
'description' => 'Je rencontre des problèmes au sujet des magnets départ\'aimants ou des bons de réductions Le Gaulois.',
],
'games' => [
'label' => 'Jeux Concours',
'description' => 'Je souhaite faire une réclamation sur un jeu Le Gaulois ou je rencontre un problème sur le site.',
],
'others' => [
'label' => 'Autres',
'description' => 'Je souhaite faire une réclamation sur un jeu Le Gaulois ou je rencontre un problème sur le site.',
],
'nl' => [
'label' => 'Formulaire en NL',
'description' => '',
],
'misc' => [
'picto-question-mark-alt' => 'Point d\'interrogation',
'picto-exclamation-alt' => 'Point d\'exclamation',
]
]
];

View file

@ -1,51 +1,230 @@
{
"A fresh verification link has been sent to your email address.": "Er is een nieuwe verificatielink naar je e-mailadres verstuurd.",
"A Timeout Occurred": "Time-out opgetreden",
"Accepted": "Aanvaard",
"Already Reported": "Al gemeld",
"Bad Gateway": "Slechte poort",
"Bad Request": "Foute aanvraag",
"Bandwidth Limit Exceeded": "Bandbreedte overschreden",
"Before proceeding, please check your email for a verification link.": "Om verder te gaan, check je e-mail voor een verificatielink.",
"click here to request another": "vraag hier een andere aan",
"Client Closed Request": "Klant Gesloten Verzoek",
"Confirm Password": "Bevestig wachtwoord",
"Conflict": "Conflict",
"Connection Closed Without Response": "Verbinding gesloten zonder reactie",
"Connection Timed Out": "Connectie duurt te lang",
"Continue": "Doorgaan",
"Created": "Gemaakt",
"Dashboard": "Dashboard",
"Email Address": "E-mailadres",
"Expectation Failed": "Niet voldaan aan verwachting",
"Failed Dependency": "Gefaalde afhankelijkheid",
"Forbidden": "Geen toegang",
"Forgot Your Password?": "Wachtwoord Vergeten?",
"Found": "Gevonden",
"Gateway Timeout": "Gateway-time-out",
"Gone": "Verdwenen",
"homepage": "startpagina",
"HTTP Version Not Supported": "HTTP-versie wordt niet ondersteund",
"I'm a teapot": "Ik ben een theepot",
"If you did not receive the email": "Als je de e-mail niet hebt ontvangen",
"IM Used": "Ik ben gebruikt",
"Insufficient Storage": "Onvoldoende opslag",
"Internal Server Error": "Interne serverfout",
"Invalid SSL Certificate": "Ongeldig SSL-certificaat",
"Length Required": "Lengte vereist",
"Locked": "Afgesloten",
"Login": "Inloggen",
"Logout": "Uitloggen",
"Loop Detected": "Loop gedetecteerd",
"Maintenance Mode": "Dienst niet beschikbaar",
"Method Not Allowed": "Methode niet toegestaan",
"Misdirected Request": "Verkeerd geadresseerd verzoek",
"Moved Permanently": "Definitief verplaatst",
"Multi-Status": "Meerdere statussen",
"Multiple Choices": "Meerkeuze",
"Name": "Naam",
"Network Authentication Required": "Netwerkauthenticatie vereist",
"Network Connect Timeout Error": "Fout bij time-out netwerkverbinding",
"Network Read Timeout Error": "Time-outfout netwerk lezen",
"No Content": "Geen inhoud",
"Non-Authoritative Information": "Niet-gemachtigde informatie",
"Not Acceptable": "Niet aanvaardbaar",
"Not Extended": "Niet verlengd",
"Not Found": "Niet gevonden",
"Not Implemented": "Niet geïmplementeerd",
"Not Modified": "Niet gewijzigd",
"OK": "Oké",
"Origin Is Unreachable": "Herkomst is onbereikbaar",
"Partial Content": "Gedeeltelijke inhoud",
"Password": "Wachtwoord",
"Payload Too Large": "Aanvraag te groot",
"Payment Required": "Betaling Vereist",
"Permanent Redirect": "Definitieve omleiding",
"Please confirm your password before continuing.": "Bevestig je wachtwoord om verder te gaan.",
"Precondition Failed": "Niet voldaan aan de vooraf gestelde voorwaarde",
"Precondition Required": "Voorwaarde nodig",
"Processing": "Verwerken",
"Proxy Authentication Required": "Authenticatie op de proxyserver verplicht",
"Railgun Error": "Railgun foutmelding",
"Range Not Satisfiable": "Bereik niet bevredigend",
"Register": "Registreren",
"Remember Me": "Onthoud mij",
"Request Header Fields Too Large": "Headers van de aanvraag te lang",
"Request Timeout": "Aanvraagtijd verstreken",
"Reset Content": "Inhoud opnieuw instellen",
"Reset Password": "Wachtwoord herstellen",
"Retry With": "Opnieuw proberen met",
"See Other": "Zie andere",
"Send Password Reset Link": "Verstuur link voor wachtwoordherstel",
"Session Has Expired": "Pagina verlopen",
"SSL Handshake Failed": "SSL-handshake mislukt",
"switch-language": "naar :lang pagina gaan",
"40years.more-gifts-to-win": "Nog meer geschenken te winnen",
"40years.collect-points": "Verzamel punten en kies uw geschenk in onze winkel!",
"40years.1euro-spent": "1€ besteed",
"40years.1point-collected": "1 verzameld punt",
"40years.2-levels": "2 niveaus",
"40years.many-gifts": "talloze geschenken",
"40years.discover-our-store": "Ontdek onze winkel",
"40years.find-the-golden-magnets": "Vind de gouden magneten",
"40years.win-a-surprise": "en win een verrassing!",
"40years.hide-golden-magnet": "Voor zijn 40e verjaardag verborg Le Gaulois 94 gouden magneten",
"40years.in-his-panes-cases": "in zijn verpakkingen met gepaneerde producten",
"40years.i-discover": "Ik ontdek",
"40years.a-golden-magnet": "een gouden magneet",
"40years.i-win": "Ik won",
"40years.a-collector-map": "een verzamelkaart van Frankrijk collectie 40-jaar, ontworpen door een jonge Franse kunstenaar, en een volledige verzameling gouden magneten!",
"40years.happy-searching": "Veel zoekplezier aan allen!",
"40years.play-with-us": "Speel met ons!",
"40years.more-gifts": "nog meer geschenken!",
"40years.banner": "Sinds 40 jaar zet Le Gaulois zich in om producten aan te bieden van <strong>100% Franse origine,</strong><strong>gevogelte geboren, gekweekt en bereidt</strong> op ons grondgebied. <br><strong>40 jaar Franse gezelligheid en gebruiksgemak, om met u te delen!</strong><br> Ontdek tijdens dit feestjaar <strong>onze spelen en verrassingen.</strong>",
"40years.game-title": "40 jaar!",
"40years.game-subtitle": "De verjaardag van alle Gaulois",
"40years.visit-your-store": "Bezoek de winkel en probeer uitzonderlijke geschenken te winnen!",
"40years.dream-stays": "Droomverblijven",
"40years.dream-stays-subtitle": "ter waarde van € 4.000",
"40years.camera": "Fototoestellen",
"40years.discount-title": "Duizenden",
"40years.discount-subtitle": "kortingsbonnen",
"40years.how-to": "Hoe te",
"40years.play": "spelen?",
"40years.bearing-products-top": "Veel",
"40years.bearing-products-bottom": "deelnemende producten",
"40years.to-participate": "Om deel te nemen, koopt u een van onze producten met de sticker.",
"40years.see-you-in-store": "Tot ziens in de winkel!",
"40years.i-participate": "Ik neem deel",
"Switching Protocols": "Protocolwissel",
"Temporary Redirect": "Tijdelijke omleiding",
"Toggle navigation": "Schakel navigatie",
"Too Early": "Te vroeg",
"Too Many Requests": "Te veel serververzoeken",
"Unauthorized": "Onbevoegd",
"Unavailable For Legal Reasons": "Toegang geweigerd om juridische redenen",
"Unknown Error": "Onbekende foutmelding",
"Unprocessable Entity": "Aanvraag kan niet worden verwerkt",
"Unsupported Media Type": "Media-type niet ondersteund",
"Upgrade Required": "Upgrade nodig",
"URI Too Long": "Aanvraag-URL te lang",
"Use Proxy": "Gebruik Proxy",
"Variant Also Negotiates": "Variant onderhandelt ook",
"Verify Your Email Address": "Verifieer je e-mailadres",
"Web Server is Down": "Webserver is onbereikbaar",
"You are logged in!": "Je bent ingelogd!",
"40years.breadcrumb": "40 jaar! De verjaardag van alle Gaulois",
"40years.animations": "Animaties in de winkel!",
"40years.highlight": "Hoogtepunt",
"40years.highlight-date": "van 2 september tot 30 november",
"40years.who-are-we.tagline.alt": "Le Gaulois logo met de slogan \"C'est bon d'être Gaulois\" met een houten tafel en stoel op de achtergrond",
"40years.who-are-we.tagline.title": "Le Gaulois-logo met de slogan \"C'est bon d'être Gaulois\"",
"40years.who-are-we.title": "Wie zijn we?",
"40years.section1.banner": "Sinds 40 jaar zet Le Gaulois zich in om producten aan te bieden van <strong>100% Franse origine,</strong><strong>gevogelte geboren, gekweekt en bereidt</strong> op ons grondgebied. <br><strong>40 jaar Franse gezelligheid en gebruiksgemak, om met u te delen!</strong><br> Ontdek tijdens dit feestjaar <strong>onze spelen en verrassingen.</strong>",
"40years.section1.logo-40ans-alt": "40 jaar le gaulois",
"40years.section1.logo-birthday-alt": "De verjaardag van le gaulois",
"40years.section1.more-gifts": "nog meer geschenken!",
"40years.section1.play-with-us": "Speel met ons!",
"40years.section2.birthday.happy-birthday": "Gelukkige verjaardag aan al onze Gaulois!",
"40years.section2.birthday.text": "Voor onze <strong>40e verjaardag</strong>, vieren we met <strong>alle Gaulois </strong>, onze gehechtheid aan <strong>authentieke Franse producten</strong>, die onze <strong>waarden van kwaliteit, toegankelijkheid en transparantie weerspiegelen.</strong>",
"40years.section2.birthday.title-part-1": "De verjaardag van le Gaulois",
"40years.section2.birthday.title-part-2": "",
"40years.section2.birthday.title-part-3": "",
"40years.section3.animations": "Animaties in de winkel!",
"40years.section3.bearing-products-bottom": "deelnemende producten",
"40years.section3.bearing-products-top": "Veel",
"40years.section3.camera-alt": "Camera's",
"40years.section3.camera-title": "Te winnen camera's",
"40years.section3.camera": "Fototoestellen",
"40years.section3.discount-pic-alt": "1 kortingsbonnen",
"40years.section3.discount-pic-title": "1 te winnen kortingsbonnen",
"40years.section3.discount-subtitle": "kortingsbonnen",
"40years.section3.discount-title": "Duizenden",
"40years.section3.dream-stays-alt": "Droom pauzes",
"40years.section3.dream-stays-subtitle": "ter waarde van € 4.000",
"40years.section3.dream-stays-title": "Droomvakantie ter waarde van €4.000 te winnen",
"40years.section3.dream-stays": "Droomverblijven",
"40years.section3.game-subtitle": "De verjaardag van alle Gaulois",
"40years.section3.game-title": "40 jaar!",
"40years.section3.highlight-date": "van 2 september tot 30 november",
"40years.section3.highlight": "Hoogtepunt",
"40years.section3.how-to": "Hoe te",
"40years.section3.i-participate": "Ik neem deel",
"40years.section3.participate.sticker-alt": "100% winnaar Le Gaulois sticker",
"40years.section3.play": "spelen?",
"40years.section3.product-1-alt": "Visueel pakje Oui c'est Bon kippenpoten Le Gaulois",
"40years.section3.product-1-title": "Verpakking kippenpoten",
"40years.section3.product-10-alt": "Visual van de haanverpakking met de Le Gaulois 100% winnende spelsticker",
"40years.section3.product-10-title": "Verpakking van jonge haantje geel braadklaar",
"40years.section3.product-11-alt": "Visueel pakje extra geroosterde knabbels met Le Gaulois 100% winnende wildsticker",
"40years.section3.product-11-title": "Verpakking van gebraden borrelhapjes",
"40years.section3.product-2-alt": "Visueel pakje extra geroosterde knabbels met Le Gaulois 100% winnende wildsticker",
"40years.section3.product-2-title": "Verpakking van gebraden borrelhapjes",
"40years.section3.product-3-alt": "Visueel pakje extra geroosterde knabbels met Le Gaulois 100% winnende wildsticker",
"40years.section3.product-3-title": "Verpakking van gebraden kipfilet lapjes",
"40years.section3.product-4-alt": "Visueel pakket van gewone milanaises met Le Gaulois 100% winnende spelsticker",
"40years.section3.product-4-title": "Verpakking van kalkoenschnitzel milanaise",
"40years.section3.product-5-alt": "Visueel verpakking van pané Normand met Le Gaulois 100% winnende spelsticker",
"40years.section3.product-5-title": "Verpakking van gepaneerd normandisch",
"40years.section3.product-6-alt": "Visueel verpakking van kalkoen escalopes met Le Gaulois 100% winnende wildsticker",
"40years.section3.product-6-title": "Verpakking van kalkoenschnitzel",
"40years.section3.product-7-alt": "Visueel pakje kipreepjes met Le Gaulois 100% winnende wildsticker",
"40years.section3.product-7-title": "Verpakking van maiskip haasjes",
"40years.section3.product-8-alt": "Visueel pakje extra malse kalkoen escalopes met Le Gaulois 100% winnend wildsticker",
"40years.section3.product-8-title": "Verpakking van kalkoenschnitzel extra mals",
"40years.section3.product-9-alt": "Visueel pakje gekonfijte kippenmaagjes met Le Gaulois 100% winnende wildsticker",
"40years.section3.product-9-title": "Verpakking van gevogeltelevers confijt",
"40years.section3.see-you-in-store": "Tot ziens in de winkel!",
"40years.section3.stand-alt": "40e verjaardag van Le Gaulois",
"40years.section3.stand-title": "40 jaar theater in de winkel van Le Gaulois",
"40years.section3.to-participate": "Om deel te nemen, koopt u een van onze producten met de sticker.",
"40years.section3.visit-your-store": "Bezoek de winkel en probeer uitzonderlijke geschenken te winnen!",
"40years.section4.1euro-spent": "1€ besteed",
"40years.section4.1point-collected": "1 verzameld punt",
"40years.section4.2-levels": "2 niveaus",
"40years.section4.7-families-alt": "7 families Spel Le Gaulois",
"40years.section4.7-families-title": "Win een Le Gaulois 7-familiespel",
"40years.section4.a-collector-map": "een verzamelkaart van Frankrijk collectie 40-jaar, ontworpen door een jonge Franse kunstenaar, en een volledige verzameling gouden magneten!",
"40years.section4.a-golden-magnet": "een gouden magneet",
"40years.section4.collect-points": "Verzamel punten en kies uw geschenk in onze winkel!",
"40years.section4.discover-our-store": "Ontdek onze winkel",
"40years.section4.find-the-golden-magnets": "Vind de gouden magneten",
"40years.section4.golden-magnet-alt": "Magneet doré Le Gaulois van het departement Sarthe, France",
"40years.section4.golden-magnet-title": "Gouden magneet Le Gaulois Sarthe, France",
"40years.section4.happy-searching": "Veel zoekplezier aan allen!",
"40years.section4.hide-golden-magnet": "Voor zijn 40e verjaardag verborg Le Gaulois 94 gouden magneten",
"40years.section4.i-discover": "Ik ontdek",
"40years.section4.i-win": "Ik won",
"40years.section4.in-his-panes-cases": "in zijn verpakkingen met gepaneerde producten",
"40years.section4.many-gifts": "talloze geschenken",
"40years.section4.more-gifts-to-win": "Nog meer geschenken te winnen",
"40years.section4.plush-alt": "Le Gaulois pluche kip",
"40years.section4.plush-title": "Le Gaulois kippenpluche te winnen",
"40years.section4.sticker-alt": "1 uitgegeven = 1 punt verzameld",
"40years.section4.sticker-title": "1 uitgegeven = 1 punt verzameld in de Le Gaulois winkel",
"40years.section4.win-a-surprise": "en win een verrassing!",
"40years.who-are-we.content1": "<strong>Voor ons is eten heilig!</strong> Het is het belangrijkste moment van gezelligheid, of je nu met familie, met z'n tweeën of met vrienden bent. Aan tafel kan je praten, veel praten, geweldige debatten voeren, niet altijd terecht, maar wel levendig!",
"40years.who-are-we.content2": "Hier delen we met trots onze waarden, onze savoir-vivre, onze eetcultuur en ons plezier om te eten en leven, dat uniek is in de wereld: <strong>“ Het goede Franse leven! ”</strong>",
"40years.who-are-we.h3-title1": "Le Gaulois, een merk dat het goede leven uitdraagt ",
"40years.who-are-we.content3": "Le Gaulois doet er alles aan om zijn klanten het allerbeste te bieden als het gaat om gevogelte. Omdat jouw genot onze prioriteit is, kunnen we je gastronomische kwaliteit garanderen, zodat je lekker op z'n Frans kunt eten.",
"40years.who-are-we.content4": "Le Gaulois biedt kwaliteitsproducten aan voor een evenwichtige voeding. Met gevogelte dat geboren, gekweekt en bereid is in Frankrijk, biedt Le Gaulois 100% Franse producten. Een merk dat je zin geeft in goede dingen en gezelligheid!",
"40years.who-are-we.h3-title1": "Le Gaulois, een merk dat het goede leven uitdraagt ",
"40years.who-are-we.h3-title2": "Le Gaulois, een Frans merk",
"40years.who-are-we.content4": "Le Gaulois biedt kwaliteitsproducten aan voor een evenwichtige voeding. Met gevogelte dat geboren, gekweekt en bereid is in Frankrijk, biedt Le Gaulois 100% Franse producten. Een merk dat je zin geeft in goede dingen en gezelligheid!"
"40years.who-are-we.tagline.alt": "Houten eettafel met het logo van Le Gaulois op de achtergrond",
"40years.who-are-we.tagline.title": "Le Gaulois logo met houten achtergrond",
"40years.who-are-we.title": "Wie zijn we?",
"contact.attachment.allowed-formats": "Toegestane bestandsformaten: :formats",
"contact.attachment.max-size": "Max. grootte : :max",
"contact.batch-number-helper": "Je kunt het lotnummer ook vinden onder de aanduiding 'traceernummer' of 'trac nummer' of naast de datum.",
"contact.complain": "Klacht over het product",
"contact.gdpr-text-1": "Uw persoonlijke gegevens zijn uitsluitend voor intern gebruik en worden onder geen beding doorgegeven aan derden. U hebt het recht om uw gegevens in te zien, te wijzigen, te rectificeren en te verwijderen (art. 34 van de Franse wet op gegevensbescherming).",
"contact.gdpr-text-2-part-1-link-label": "cookies",
"contact.gdpr-text-2-part-1-link-title": "Cookies beheren",
"contact.gdpr-text-2-part-1": "Om uw formulier te versturen, dient u de :link te aanvaarden.",
"contact.gdpr-text-2-part-2": "De informatie die via dit formulier wordt verzameld, wordt verwerkt door de Gegevensbeheerder om te kunnen reageren op uw contactverzoek.",
"contact.gdpr-text-2-part-3-link-label": "Vertrouwelijkheidshandvest",
"contact.gdpr-text-2-part-3-link-title": "Bezoek de pagina: Vertrouwelijkheidshandvest",
"contact.gdpr-text-2-part-3": "Raadpleeg het :link voor meer informatie over uw rechten.",
"contact.message_contact_failed": "Er is een fout opgetreden bij het verzenden van uw bericht. Probeer het later opnieuw.",
"contact.message_contact_send": "Uw bericht is succesvol verzonden.",
"contact.personnal-infos": "Mijn gegevens",
"contact.placeholder.day": "dd",
"contact.placeholder.month": "mm",
"contact.placeholder.year": "jjjj",
"contact.required-fields": "Verplichte velden",
"contact.send": "Verzenden",
"contact.subject": "Onderwerp van uw aanvraag",
"contact.want-to-write": "Ik wil een klacht indienen",
"40years.section2.grandpa-share-alt": "Opa en kleinzoon delen een Le Gaulois kalkoenborst",
"40years.section2.grandpa-share-title": "Een kalkoenborst delen Le Gaulois à table",
"40years.section2.conviviality-alt": "CHANGEME",
"40years.section2.conviviality-title": "Gezelligheid en delen bij Le Gaulois",
"40years.section2.cutlet-alt": "Le Gaulois Frans gevogelte escalope",
"40years.section2.cutlet-title": "Le Gaulois Frans gevogelte escalope",
"40years.section2.birthday-alt": "Familie en vrienden blazen de kaarsjes uit op de verjaardagstaart van Le Gaulois",
"40years.section2.birthday-title": "Le Gaulois verjaardagsfeest voor familie en vrienden",
"40years.section2.auguste-lambert-alt": "Familiefoto van Auguste Lambert in 1909 op een markt in Sarthe, France",
"40years.section2.auguste-lambert-title": "Familiefoto van Auguste Lambert op een markt in Sarthe, France",
"40years.section2.deco-firework-alt": "Blauw wit rode verkeerslichten",
"40years.section2.deco-blue-gift-alt": "Blauw geschenk",
"40years.section2.deco-red-gift-alt": "Rode geschenken",
"40years.section2.deco-cotillions-alt": "Rood, wit en blauwe feestartikelen",
"40years.section2.flag-alt": "Franse vlag"
}

Some files were not shown because too many files have changed in this diff Show more