Version stable, aprelic, connexion CFRS et autres corrections

This commit is contained in:
Oleg Barykin committed 2026-04-17 20:18:11 +02:00
1 parent 865de8a976
commit e9d0010451
62 files changed
+17483 -7256

No files matched your search

+31
View File
@@ -910,3 +910,34 @@ a {
border-color: #e03c3f;
transform: none;
}
.menu-item-form {
padding: 0 !important;
list-style: none;
}
.menu-logout-form {
margin: 0;
width: 100%;
}
.menu-logout-btn {
all: unset;
box-sizing: border-box;
display: block;
width: 100%;
padding: 12px 16px;
cursor: pointer;
font: inherit;
color: inherit;
text-align: left;
}
.menu-logout-btn:hover {
background: #f3f4f6;
}
.menu-logout-btn:focus-visible {
outline: 2px solid #94a3b8;
outline-offset: -2px;
}
+55
View File
@@ -0,0 +1,55 @@
<?php
// Évite la boucle quand router.php inclut la page
if (defined('ROUTED_PRETTY')) return;
// Mapping vilain -> joli
$UGLY_TO_PRETTY = [
//racine
'/index.php' => '/',
'/result_search.php' => '/recherche',
'/detail_public.php' => '/specialistes',
'/connexion.php' => '/login',
'/choix_inscr.php' => '/choix-inscription',
'/inscription_client.php' => '/inscription-client',
'/inscription_praticien.php' => '/inscription-praticien',
'/mdp_oublie.php' => '/mot-de-passe-oublie',
'/avis_public.php' => '/avis',
//dossier client
'/public/client/informations.php' => '/profil',
'/public/client/modifier.php' => '/modifier-profil',
'/public/client/compte.php' => '/mon-compte',
'/public/client/list_praticien.php' => '/trouver-specialistes',
'/public/client/mes_favori.php' => '/mes-preferences',
'/public/client/detail_praticien.php' => '/specialiste',
'/public/client/avis.php' => '/donner-avis',
'/public/client/reserver_rdv.php' => '/reservation',
'/public/client/mes_rendez_vous.php' => '/mes-rendez-vous',
//Dossier praticien
'/public/praticien/informations.php' => '/profil-pro',
'/public/praticien/modifier.php' => '/modifier-profil-pro',
'/public/praticien/compte.php' => '/mon-compte-pro',
'/public/praticien/disponibilites.php' => '/mes-creneaux',
'/public/praticien/disponibilites_date.php' => '/mes-creneaux-date',
'/public/praticien/rendez_vous.php' => '/mes-consultations',
'/public/praticien/rendez_vous_du_jour.php' => '/consultations-du-jour',
'/public/praticien/agenda.php' => '/agenda',
'/public/praticien/synchronisation.php' => '/connecter-agenda',
'/public/praticien/resiliation.php' => '/abonnement',
'/public/praticien/factures.php' => '/mes-factures',
//Dossier messages
];
// Debug : ajouter ?_noredir=1 pour désactiver la redirection
if (!empty($_GET['_noredir'])) return;
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ?? '/';
if (isset($UGLY_TO_PRETTY[$path])) {
$target = $UGLY_TO_PRETTY[$path];
$qs = $_SERVER['QUERY_STRING'] ? ('?' . $_SERVER['QUERY_STRING']) : '';
header('Location: ' . $target . $qs, true, 301);
exit;
}
+82 -22
View File
@@ -1,29 +1,30 @@
<?php
// Évite la boucle quand router.php inclut la page
if (defined('ROUTED_PRETTY')) return;
if (defined('ROUTED_PRETTY')) {
return;
}
// Mapping vilain -> joli
$UGLY_TO_PRETTY = [
//racine
'/index.php' => '/',
'/result_search.php' => '/recherche',
'/detail_public.php' => '/specialistes',
'/connexion.php' => '/login',
'/choix_inscr.php' => '/choix-inscription',
'/inscription_client.php' => '/inscription-client',
'/inscription_praticien.php' => '/inscription-praticien',
'/mdp_oublie.php' => '/mot-de-passe-oublie',
'/avis_public.php' => '/avis',
'/index.php' => '/',
'/detail_public.php' => '/specialistes',
'/connexion.php' => '/login',
'/choix_inscr.php' => '/choix-inscription',
'/inscription_client.php' => '/inscription-client',
'/inscription_praticien.php' => '/inscription-praticien',
'/mdp_oublie.php' => '/mot-de-passe-oublie',
'/avis_public.php' => '/avis',
//dossier client
'/public/client/informations.php' => '/profil',
'/public/client/modifier.php' => '/modifier-profil',
'/public/client/compte.php' => '/mon-compte',
'/public/client/list_praticien.php' => '/trouver-specialistes',
'/public/client/mes_favori.php' => '/mes-preferences',
'/public/client/detail_praticien.php' => '/specialiste',
'/public/client/avis.php' => '/donner-avis',
'/public/client/reserver_rdv.php' => '/reservation',
'/public/client/mes_rendez_vous.php' => '/mes-rendez-vous',
'/public/client/informations.php' => '/profil',
'/public/client/modifier.php' => '/modifier-profil',
'/public/client/compte.php' => '/mon-compte',
'/public/client/list_praticien.php' => '/trouver-specialistes',
'/public/client/mes_favori.php' => '/mes-preferences',
'/public/client/detail_praticien.php' => '/specialiste',
'/public/client/avis.php' => '/donner-avis',
'/public/client/reserver_rdv.php' => '/reservation',
'/public/client/mes_rendez_vous.php' => '/mes-rendez-vous',
//Dossier praticien
'/public/praticien/informations.php' => '/profil-pro',
@@ -37,15 +38,74 @@ $UGLY_TO_PRETTY = [
'/public/praticien/synchronisation.php' => '/connecter-agenda',
'/public/praticien/resiliation.php' => '/abonnement',
'/public/praticien/factures.php' => '/mes-factures',
//Dossier messages
];
// Debug : ajouter ?_noredir=1 pour désactiver la redirection
if (!empty($_GET['_noredir'])) return;
if (! empty($_GET['_noredir'])) {
return;
}
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ?? '/';
require_once __DIR__ . '/search_helpers.php';
// Redirection SEO pour result_search.php
if ($path === '/result_search.php' || $path === '/recherche') {
if (! empty($_GET['ajax'])) {
return;
}
$specialite = trim((string) ($_GET['specialite'] ?? ''));
$ville = trim((string) ($_GET['ville'] ?? ''));
if ($specialite !== '' || $ville !== '') {
$target = '/recherche';
$specSlug = '';
if ($specialite === '__OTHERS__') {
$specSlug = 'autres-specialistes';
} elseif ($specialite !== '') {
$specSlug = seo_spec_slug_from_input($specialite) ?? '';
}
if ($specSlug !== '') {
$target .= '/' . rawurlencode($specSlug);
}
$citySlug = '';
if ($ville !== '') {
$citySlug = seo_city_slug_from_input($ville);
}
if ($citySlug !== '') {
if ($specSlug === '') {
// si ville seule, on garde la query string pour éviter une structure bancale
$target = '/recherche/?' . http_build_query([
'specialite' => $specialite,
'ville' => $ville,
]);
header('Location: ' . $target, true, 301);
exit;
}
$target .= '/' . rawurlencode($citySlug);
}
$target .= '/';
$extra = $_GET;
unset($extra['specialite'], $extra['ville']);
if (! empty($extra)) {
$target .= '?' . http_build_query($extra);
}
header('Location: ' . $target, true, 301);
exit;
}
}
if (isset($UGLY_TO_PRETTY[$path])) {
$target = $UGLY_TO_PRETTY[$path];
+65
View File
@@ -0,0 +1,65 @@
<?php
function has_cyrillic(string $s): bool {
return (bool) preg_match('/\p{Cyrillic}/u', $s);
}
function norm_key(string $s): string {
$s = mb_strtolower(trim($s), 'UTF-8');
$s = str_replace(['ё'], ['е'], $s); // homogénéiser RU
$s = preg_replace('/[\'"’\-\s]+/u', '', $s); // enlève tirets, espaces, quotes
return $s;
}
// Translittération simple RU -> latin (fallback si intl n’est pas dispo)
function translit_ru_to_lat(string $s): string {
if (class_exists('Transliterator')) {
// "Russian-Latin/BGN" produit Parizh (Париж) -> "parizh"
$t = \Transliterator::create('Russian-Latin/BGN; Lower();');
if ($t) return $t->transliterate($s);
}
$map = [
'а'=>'a','б'=>'b','в'=>'v','г'=>'g','д'=>'d','е'=>'e','ё'=>'e','ж'=>'zh','з'=>'z','и'=>'i','й'=>'i','к'=>'k',
'л'=>'l','м'=>'m','н'=>'n','о'=>'o','п'=>'p','р'=>'r','с'=>'s','т'=>'t','у'=>'u','ф'=>'f','х'=>'kh','ц'=>'ts',
'ч'=>'ch','ш'=>'sh','щ'=>'shch','ъ'=>'','ы'=>'y','ь'=>'','э'=>'e','ю'=>'yu','я'=>'ya',
];
$s = mb_strtolower($s, 'UTF-8');
return strtr($s, $map);
}
// Retourne une liste de candidats latins (pour LIKE) à partir d’une saisie q
function city_query_candidates(string $q): array {
$q = trim($q);
if ($q === '') return [];
$cands = [];
$cands[] = mb_strtolower($q, 'UTF-8'); // saisie brute (si déjà latine)
// charger alias RU -> latin
$aliases = @include __DIR__ . '/city_aliases_ru.php';
if (!is_array($aliases)) $aliases = [];
if (has_cyrillic($q)) {
// 1) correspondance par préfixe dans les alias (ПАР → Paris)
$key = norm_key($q);
foreach ($aliases as $ru => $lat) {
if (strpos(norm_key($ru), $key) === 0) {
$cands[] = $lat;
}
}
// 2) translittération simple (Париж -> parizh)
$cands[] = translit_ru_to_lat($q);
}
// Normalisation légère des candidats (minuscules, accents retirés si possible)
$res = [];
foreach (array_unique($cands) as $c) {
$lc = mb_strtolower($c, 'UTF-8');
// enlever accents (si intl transliterator dispo)
if (class_exists('Transliterator')) {
$t = \Transliterator::create('Any-Latin; Latin-ASCII;');
if ($t) $lc = $t->transliterate($lc);
}
$res[] = $lc;
}
return array_values(array_unique($res));
}
+396 -56
View File
@@ -1,65 +1,405 @@
<?php
function has_cyrillic(string $s): bool {
return (bool) preg_match('/\p{Cyrillic}/u', $s);
function has_cyrillic(string $s): bool
{
return (bool) preg_match('/\p{Cyrillic}/u', $s);
}
function norm_key(string $s): string {
$s = mb_strtolower(trim($s), 'UTF-8');
$s = str_replace(['ё'], ['е'], $s); // homogénéiser RU
$s = preg_replace('/[\'"’\-\s]+/u', '', $s); // enlève tirets, espaces, quotes
return $s;
function norm_key(string $s): string
{
$s = mb_strtolower(trim($s), 'UTF-8');
$s = str_replace(['ё'], ['е'], $s);
$s = preg_replace('/[\'"’\-\s]+/u', '', $s);
return $s;
}
// Translittération simple RU -> latin (fallback si intl n’est pas dispo)
function translit_ru_to_lat(string $s): string {
if (class_exists('Transliterator')) {
// "Russian-Latin/BGN" produit Parizh (Париж) -> "parizh"
$t = \Transliterator::create('Russian-Latin/BGN; Lower();');
if ($t) return $t->transliterate($s);
}
$map = [
'а'=>'a','б'=>'b','в'=>'v','г'=>'g','д'=>'d','е'=>'e','ё'=>'e','ж'=>'zh','з'=>'z','и'=>'i','й'=>'i','к'=>'k',
'л'=>'l','м'=>'m','н'=>'n','о'=>'o','п'=>'p','р'=>'r','с'=>'s','т'=>'t','у'=>'u','ф'=>'f','х'=>'kh','ц'=>'ts',
'ч'=>'ch','ш'=>'sh','щ'=>'shch','ъ'=>'','ы'=>'y','ь'=>'','э'=>'e','ю'=>'yu','я'=>'ya',
];
$s = mb_strtolower($s, 'UTF-8');
return strtr($s, $map);
}
// Retourne une liste de candidats latins (pour LIKE) à partir d’une saisie q
function city_query_candidates(string $q): array {
$q = trim($q);
if ($q === '') return [];
$cands = [];
$cands[] = mb_strtolower($q, 'UTF-8'); // saisie brute (si déjà latine)
// charger alias RU -> latin
$aliases = @include __DIR__ . '/city_aliases_ru.php';
if (!is_array($aliases)) $aliases = [];
if (has_cyrillic($q)) {
// 1) correspondance par préfixe dans les alias (ПАР → Paris)
$key = norm_key($q);
foreach ($aliases as $ru => $lat) {
if (strpos(norm_key($ru), $key) === 0) {
$cands[] = $lat;
}
}
// 2) translittération simple (Париж -> parizh)
$cands[] = translit_ru_to_lat($q);
}
// Normalisation légère des candidats (minuscules, accents retirés si possible)
$res = [];
foreach (array_unique($cands) as $c) {
$lc = mb_strtolower($c, 'UTF-8');
// enlever accents (si intl transliterator dispo)
function translit_ru_to_lat(string $s): string
{
if (class_exists('Transliterator')) {
$t = \Transliterator::create('Any-Latin; Latin-ASCII;');
if ($t) $lc = $t->transliterate($lc);
$t = \Transliterator::create('Russian-Latin/BGN; Lower();');
if ($t) {
return $t->transliterate($s);
}
}
$res[] = $lc;
}
return array_values(array_unique($res));
$map = [
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
'й' => 'i', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
'у' => 'u', 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch',
'ш' => 'sh', 'щ' => 'shch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
'э' => 'e', 'ю' => 'yu', 'я' => 'ya',
];
$s = mb_strtolower($s, 'UTF-8');
return strtr($s, $map);
}
// Retourne une liste de candidats latins (pour LIKE) à partir d’une saisie ville
function city_query_candidates(string $q): array
{
$q = trim($q);
if ($q === '') {
return [];
}
$aliases = @include __DIR__ . '/city_aliases_ru.php';
if (! is_array($aliases)) {
$aliases = [];
}
$cands = [];
$qLower = mb_strtolower($q, 'UTF-8');
// Toujours garder la saisie brute
$cands[] = $qLower;
// Version ASCII/latin normalisée
$qAscii = $qLower;
if (class_exists('Transliterator')) {
$t = \Transliterator::create('Any-Latin; Latin-ASCII; Lower();');
if ($t) {
$qAscii = $t->transliterate($qAscii);
}
}
$cands[] = $qAscii;
// Si saisie en cyrillique : on ajoute les villes latines correspondantes
if (has_cyrillic($q)) {
$key = norm_key($q);
foreach ($aliases as $ru => $lat) {
if (strpos(norm_key($ru), $key) === 0) {
$cands[] = mb_strtolower($lat, 'UTF-8');
$cands[] = mb_strtolower($ru, 'UTF-8');
}
}
$cands[] = translit_ru_to_lat($q);
}
// Si saisie en latin : on cherche aussi les correspondances RU depuis les aliases
foreach ($aliases as $ru => $lat) {
$latLower = mb_strtolower($lat, 'UTF-8');
$latAscii = $latLower;
if (class_exists('Transliterator')) {
$t = \Transliterator::create('Any-Latin; Latin-ASCII; Lower();');
if ($t) {
$latAscii = $t->transliterate($latAscii);
}
}
if (
strpos($latLower, $qLower) === 0 ||
strpos($latAscii, $qAscii) === 0
) {
$cands[] = mb_strtolower($ru, 'UTF-8');
$cands[] = $latLower;
}
}
$res = [];
foreach (array_unique($cands) as $c) {
$res[] = mb_strtolower(trim($c), 'UTF-8');
}
return array_values(array_unique(array_filter($res)));
}
function seo_slug(string $s): string
{
$s = trim(mb_strtolower($s, 'UTF-8'));
if ($s === '') {
return '';
}
if (has_cyrillic($s)) {
$aliases = @include __DIR__ . '/city_aliases_ru.php';
if (is_array($aliases)) {
foreach ($aliases as $ru => $lat) {
if (norm_key($ru) === norm_key($s)) {
$s = $lat;
break;
}
}
}
if (has_cyrillic($s)) {
$s = translit_ru_to_lat($s);
}
}
if (class_exists('Transliterator')) {
$t = \Transliterator::create('Any-Latin; Latin-ASCII; Lower();');
if ($t) {
$s = $t->transliterate($s);
}
}
$s = str_replace(['œ', 'æ'], ['oe', 'ae'], $s);
$s = preg_replace('/[^\p{L}\p{N}]+/u', '-', $s);
$s = trim($s, '-');
$s = preg_replace('/-+/u', '-', $s);
return $s;
}
function seo_unslug(string $s): string
{
$s = trim(mb_strtolower($s, 'UTF-8'));
$s = str_replace('-', ' ', $s);
$s = preg_replace('/\s+/u', ' ', $s);
return trim($s);
}
function seo_spec_map(): array
{
return [
'psychologue' => [
'db' => 'психолог',
'search' => [
'ru' => 'психолог',
'fr' => 'psychologue',
'en' => 'psychologist',
],
'inputs' => ['psychologue', 'psychologues', 'психолог', 'психологи'],
],
'manager' => [
'db' => 'менеджер',
'search' => [
'ru' => 'менеджер',
'fr' => 'manager',
'en' => 'manager',
],
'inputs' => ['it manager', 'it-manager', 'manager it', 'responsable it', 'it-менеджер', 'ит менеджер'],
],
'construction' => [
'db' => 'строитель',
'search' => [
'ru' => 'строитель',
'fr' => 'construction',
'en' => 'construction',
],
'inputs' => [
'строительная компания',
'строительная фирма',
'строительство',
'construction',
'entreprise de construction',
'bâtiment',
'btp',
],
],
'pompes-funebres' => [
'db' => 'похоронное',
'search' => [
'ru' => 'похоронное',
'fr' => 'pompes funebres',
'en' => 'funeral services',
],
'inputs' => [
'похоронное агентство',
'похоронное бюро',
'ритуальные услуги',
'ритуальное агентство',
'pompes funebres',
'pompes-funebres',
'services funeraires',
'funerailles',
],
],
'avocat' => [
'db' => 'адвокат',
'search' => [
'ru' => 'адвокат',
'fr' => 'avocat',
'en' => 'lawyer',
],
'inputs' => ['avocat', 'avocats', 'адвокат', 'адвокаты'],
],
'medecin' => [
'db' => 'врач',
'search' => [
'ru' => 'врач',
'fr' => 'medecin',
'en' => 'doctor',
],
'inputs' => ['medecin', 'medecins', 'médecin', 'médecins', 'врач', 'врачи', 'Врач - стоматолог', 'врач-стоматолог'],
],
'consultant' => [
'db' => 'консультант',
'search' => [
'ru' => 'консультант',
'fr' => 'consultant',
'en' => 'consultant',
],
'inputs' => ['consultant', 'consultants', 'консультант', 'консультанты', 'Консультант'],
],
'professeur' => [
'db' => 'преподаватель',
'search' => [
'ru' => 'преподаватель',
'fr' => 'professeur',
'en' => 'teacher',
],
'inputs' => ['professeur', 'professeurs', 'pedagogue', 'pedagogues', 'преподаватель', 'преподаватели', 'педагог', 'педагоги'],
],
'comptable' => [
'db' => 'бухгалтер',
'search' => [
'ru' => 'бухгалтер',
'fr' => 'comptable',
'en' => 'accountant',
],
'inputs' => ['comptable', 'comptables', 'бухгалтер', 'бухгалтеры'],
],
'traducteur' => [
'db' => 'переводчик',
'search' => [
'ru' => 'переводчик',
'fr' => 'traducteur',
'en' => 'translator',
],
'inputs' => ['traducteur', 'traducteurs', 'переводчик', 'переводчики'],
],
'notaire' => [
'db' => 'нотариус',
'search' => [
'ru' => 'нотариус',
'fr' => 'notaire',
'en' => 'notary',
],
'inputs' => ['notaire', 'notaires', 'нотариус', 'нотариусы'],
],
'guide' => [
'db' => 'гид',
'search' => [
'ru' => 'гид',
'fr' => 'guide',
'en' => 'guide',
],
'inputs' => ['guide', 'guides', 'гид', 'гиды'],
],
'agent-immobilier' => [
'db' => 'риелтор',
'search' => [
'ru' => 'риелтор',
'fr' => 'agent immobilier',
'en' => 'real estate agent',
],
'inputs' => [
'Agent immobilier',
'agent immobilier',
'agent-immobilier',
'agents immobiliers',
'agents-immobiliers',
'риелтор',
'риелторы',
],
],
'autres-specialistes' => [
'db' => '__OTHERS__',
'inputs' => ['autres specialistes', 'autres-specialistes', 'другие', 'другие специалисты'],
],
];
}
function seo_spec_slug_from_input(string $input): ?string
{
$inputSlug = seo_slug($input);
foreach (seo_spec_map() as $slug => $cfg) {
foreach (($cfg['inputs'] ?? []) as $candidate) {
if ($inputSlug === seo_slug((string) $candidate)) {
return $slug;
}
}
}
return null;
}
function seo_spec_db_from_slug(string $slug): ?string
{
$slug = seo_slug($slug);
$map = seo_spec_map();
return $map[$slug]['db'] ?? null;
}
function seo_city_slug_from_input(string $input): string
{
$input = trim($input);
if ($input === '') {
return '';
}
$aliases = @include __DIR__ . '/city_aliases_ru.php';
if (! is_array($aliases)) {
$aliases = [];
}
$key = norm_key($input);
foreach ($aliases as $ru => $lat) {
if (norm_key($ru) === $key) {
return seo_slug((string) $lat);
}
}
return seo_slug($input);
}
function seo_spec_slug_from_key(string $key): ?string
{
$map = [
'avocats' => 'avocat',
'consultants' => 'consultant',
'vrachi' => 'medecin',
'psychologues' => 'psychologue',
'repetitori' => 'professeur',
'finance' => 'comptable',
'perevod' => 'traducteur',
'notarius' => 'notaire',
'gid' => 'guide',
'rieltori' => 'agent-immobilier',
'drugie' => 'autres-specialistes',
];
return $map[$key] ?? null;
}
function seo_spec_search_value_from_slug(string $slug, string $lang): ?string
{
$slug = seo_slug($slug);
$lang = mb_strtolower(trim($lang), 'UTF-8');
$map = seo_spec_map();
if (! isset($map[$slug])) {
return null;
}
$cfg = $map[$slug];
if (isset($cfg['search'][$lang]) && trim((string) $cfg['search'][$lang]) !== '') {
return trim((string) $cfg['search'][$lang]);
}
return $cfg['db'] ?? null;
}
+24 -25
View File
@@ -1,30 +1,29 @@
<?php
// Map des clés de traduction -> valeur canonique (singulier) pour la BDD
return [
'ru' => [
'avocats' => 'адвокат',
'consultants' => 'консультант',
'vrachi' => 'врач',
'psychologues' => 'психолог',
'repetitori' => 'преподаватель',
'finance' => 'бухгалтер', // ajuste si besoin
'perevod' => 'переводчик',
'notarius' => 'нотариус',
'gid' => 'гид',
'rieltori' => 'риелтор',
'ru' => [
'avocats' => 'адвокат',
'consultants' => 'консультант',
'vrachi' => 'врач',
'psychologues' => 'психолог',
'repetitori' => 'преподаватель',
'finance' => 'бухгалтер', // ajuste si besoin
'perevod' => 'переводчик',
'notarius' => 'нотариус',
'gid' => 'гид',
'rieltori' => 'риелтор',
],
'fr' => [
'avocats' => 'адвокат',
'consultants' => 'консультант',
'vrachi' => 'врач', // clé existante "vrachi" côté traductions
'psychologues' => 'психолог',
'repetitori' => 'преподаватель', // ou "Répetiteur" selon ta BDD
'finance' => 'бухгалтер', // ajuste si besoin
'perevod' => 'переводчик',
'notarius' => 'нотариус',
'gid' => 'гид',
'rieltori' => 'риелтор',
],
],
'fr' => [
'avocats' => 'адвокат',
'consultants' => 'консультант',
'vrachi' => 'врач', // clé existante "vrachi" côté traductions
'psychologues' => 'психолог',
'repetitori' => 'преподаватель', // ou "Répetiteur" selon ta BDD
'finance' => 'бухгалтер', // ajuste si besoin
'perevod' => 'переводчик',
'notarius' => 'нотариус',
'gid' => 'гид',
'rieltori' => 'риелтор',
],
];