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

+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;
}