DEV Community

Cover image for Autocomplétion d'adresse en Tunisie : arabe et arabizi
Tmaps Tunisia
Tmaps Tunisia

Posted on

Autocomplétion d'adresse en Tunisie : arabe et arabizi

Demandez à dix personnes à Tunis de taper la même adresse, et vous verrez passer trois alphabets :

  • en français : Rue de Marseille, Tunis
  • en arabe : نهج مرسيليا
  • en arabizi, c'est-à-dire le tunisien écrit en lettres latines avec des chiffres pour les sons que le français n'a pas : nahj marseille, zan9et el bacha, 9asr said

Un champ d'adresse qui ne comprend que la première façon d'écrire fait perdre des clients au moment de la commande. Dans cet article, on construit une autocomplétion avec l'API de géocodage TMaps qui gère les trois, et qui affiche correctement les résultats en arabe, de droite à gauche.

À tester en ligne : examples.tmaps.tn/04-geocoding-search. Passez la langue en arabe, ou tapez 9asr said.

Ou testez-la directement ici, et copiez-la sur CodePen (bouton Fork) pour modifier le code :

Recherche en arabe avec des adresses affichées de droite à gauche

L'arabizi en 30 secondes

L'arabizi remplace certaines lettres arabes par des chiffres qui leur ressemblent :

Chiffre Arabe Son Exemple Orthographe française habituelle
3 ع « aïn » 3in Ain
5 خ kh 5ayreddine Khayreddine
7 ح h aspiré 7ammamet Hammamet
9 ق q 9asr said Ksar Said

Ajoutez les mots du dialecte pour les types de voies, nahj (rue), zan9a (impasse), chare3 (avenue) et 7ay (cité), et vous avez la façon dont beaucoup de gens écrivent vraiment leur adresse.

Étape 1 : une autocomplétion de base solide

Au fond, l'autocomplétion appelle GET /geocoding/forward pendant que l'utilisateur tape. Trois détails font toute la différence :

let timer;
let controller;

input.addEventListener('input', () => {
  clearTimeout(timer);
  timer = setTimeout(search, 300); // on attend que l'utilisateur fasse une pause
});

async function geocode(q, signal) {
  const url = new URL('https://api.tmaps.tn/geocoding/forward');
  url.search = new URLSearchParams({
    q,
    country: 'TN',                 // Tunisie uniquement
    limit: 5,
    lang: languageSelect.value,    // fr, en ou ar
    proximity: '36.8065,10.1815',  // favorise les résultats proches de l'utilisateur
    api_key: API_KEY,
  });
  const res = await fetch(url, { signal });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(`${res.status}: ${data.error ?? res.statusText}`);
  return data.results;
}
Enter fullscreen mode Exit fullscreen mode
  1. Un délai de 300 ms avant d'envoyer, pour faire une requête quand l'utilisateur s'arrête de taper, et pas une par lettre.
  2. Un AbortController : quand une nouvelle recherche démarre, on annule la précédente. Sinon, une vieille réponse un peu lente peut arriver après une plus récente et l'écraser.
  3. Le paramètre proximity : il y a une Rue de Marseille dans beaucoup de villes tunisiennes, et favoriser la position de l'utilisateur (ou le centre de la carte) fait remonter la bonne.

Chaque résultat contient le point dans geometry.location (lat, lng), l'adresse complète dans formatted, un score confidence, et components avec la commune, la délégation et le gouvernorat.

Étape 2 : des résultats en arabe, de droite à gauche

Avec lang=ar, toute l'adresse revient en arabe :

{
  "formatted": "نهج مرسيليا, حبيب ثامر, باب بحر, تونس, تونس",
  "type": "street",
  "confidence": 0.8
}
Enter fullscreen mode Exit fullscreen mode

L'arabe doit s'afficher de droite à gauche. Comme une liste de suggestions mélange souvent les écritures (une adresse en arabe à côté d'un nom de commune en français, un numéro de route en chiffres latins…), ne fixez pas le sens d'écriture en dur. Laissez le navigateur décider pour chaque élément :

const li = document.createElement('li');
li.dir = 'auto'; // le premier caractère fort décide : arabe = droite à gauche, latin = gauche à droite
li.textContent = result.formatted;
Enter fullscreen mode Exit fullscreen mode
<input id="address" type="search" dir="auto">
Enter fullscreen mode Exit fullscreen mode

Mettre aussi dir="auto" sur le champ de saisie fait basculer le curseur et l'alignement dès qu'on commence à taper en arabe. Sans ça, la ponctuation et les chiffres se retrouvent du mauvais côté.

Étape 3 : ce que l'API comprend déjà

Nous avons testé de vraies requêtes tunisiennes sur l'API (lang=fr, country=TN). Voici le premier résultat pour chacune :

Requête Premier résultat
نهج مرسيليا ✅ Rue de Marseille
nahj marseille ✅ Rue de Marseille, Tunis
9asr said ✅ Ksar Said, Le Bardo
7ammamet ✅ Hammamet
5ayreddine ✅ Rue Khayreddine
3in zaghouan ❌ aucun résultat
zan9et el bacha ⚠️ Khaireddine Pacha (pas une impasse)

L'arabe, nahj et les chiffres 7, 9 et 5 fonctionnent donc déjà. Le chiffre 3 et certains mots du dialecte ont besoin d'un coup de pouce, qu'on peut donner directement dans le navigateur.

Étape 4 : normaliser l'arabizi côté navigateur

Une petite fonction réécrit les mots du dialecte et les chiffres de l'arabizi dans l'orthographe utilisée dans les adresses :

// Mots du dialecte tunisien et chiffres de l'arabizi, réécrits comme dans les adresses
const DIALECT = {
  nahj: 'rue', nhej: 'rue', zan9a: 'impasse', zan9et: 'impasse', zanket: 'impasse',
  chare3: 'avenue', chara3: 'avenue', hay: 'cité', '7ay': 'cité',
};
const ARABIZI = { 3: 'a', 5: 'kh', 7: 'h', 9: 'k' };

function normalizeTunisian(text) {
  return text.toLowerCase().split(/\s+/).map((word) => {
    if (DIALECT[word]) return DIALECT[word];
    // On ne touche ni aux nombres (4014) ni aux routes (rn9, c27)
    if (!/[a-z]/.test(word) || /^[a-z]{1,2}\d+$/.test(word)) return word;
    return word.replace(/3a/g, 'a').replace(/[3579]/g, (digit) => ARABIZI[digit]);
  }).join(' ');
}
Enter fullscreen mode Exit fullscreen mode
"3in zaghouan"     → "ain zaghouan"
"nahj 5ayreddine"  → "rue khayreddine"
"zan9et el bacha"  → "impasse el bacha"
"chare3 bourguiba" → "avenue bourguiba"
"Rue 4014"         → "rue 4014"     (inchangé)
"RN9"              → "rn9"          (inchangé)
"نهج مرسيليا"       → "نهج مرسيليا"  (inchangé)
Enter fullscreen mode Exit fullscreen mode

Ne sautez pas les deux protections. Les adresses tunisiennes sont pleines de numéros (Rue 4014) et de codes de routes (RN9, C27), et réécrire ces chiffres casserait des recherches qui marchaient très bien.

Étape 5 : chercher les deux versions en parallèle

La normalisation peut aussi faire moins bien : 9asr said fonctionne déjà tel quel. Plutôt que de remplacer ce que l'utilisateur a tapé, on cherche donc les deux versions et on fusionne les résultats :

async function search() {
  const q = input.value.trim();
  if (q.length < 3) return;

  controller?.abort();
  controller = new AbortController();

  const normalized = normalizeTunisian(q);
  const queries = normalized === q.toLowerCase() ? [q] : [q, normalized];

  const lists = await Promise.all(queries.map((text) => geocode(text, controller.signal)));

  // Résultats normalisés d'abord, puis ceux de la saisie brute, sans doublons
  const seen = new Set();
  const results = lists.reverse().flat()
    .filter((r) => !seen.has(r.formatted) && seen.add(r.formatted))
    .slice(0, 5);

  render(results);
}
Enter fullscreen mode Exit fullscreen mode

Un texte en français ou en arabe ressort de normalizeTunisian sans changement : il ne coûte donc qu'une seule requête. Seule une saisie en arabizi ou en dialecte déclenche la deuxième.

La différence se voit tout de suite : 3in zaghouan passe de zéro résultat à la Rue Ain Zaghouane et aux villages « Ain » autour de Zaghouan.

La requête arabizi « 3in zaghouan » renvoie des résultats

Et 9asr said tombe bien sur Ksar Said, au Bardo :

La requête arabizi « 9asr said » renvoie Ksar Said

Étape 6 : ne pas faire confiance à tous les résultats

Pour une adresse de livraison, une mauvaise adresse coûte plus cher que pas d'adresse du tout. Le score confidence aide à décider :

  • à partir de 0,85, enregistrez les coordonnées ;
  • en dessous, gardez la suggestion mais demandez au client de vérifier le pin sur la carte.

La démo du formulaire de commande montre tout le parcours : le client choisit une suggestion, la commune, la délégation et le gouvernorat se remplissent tout seuls, puis il peut déplacer le pin, et l'adresse est affinée par géocodage inverse.

Les limites actuelles

Pour être transparents sur ce que cette approche ne règle pas encore :

  • Certains noms de ville tapés en arabe peuvent renvoyer un autre lieu au nom proche. Si vos utilisateurs tapent les villes en arabe, gardez proximity et affichez la commune et le gouvernorat dans chaque suggestion, pour qu'ils puissent choisir le bon lieu.
  • Quand plusieurs lieux portent le même nom dans des régions différentes (il y a plus d'une El Aouina), le classement dépend beaucoup de proximity. Envoyez la vraie position de l'utilisateur dès que vous l'avez.

En résumé

  1. Un délai avant d'envoyer, l'annulation des requêtes dépassées, et proximity pour orienter les résultats.
  2. lang=ar pour des résultats en arabe, et dir="auto" partout où vous les affichez.
  3. Normaliser le dialecte et l'arabizi dans le navigateur, sans toucher aux numéros ni aux routes.
  4. Chercher en parallèle la saisie brute et la version normalisée, puis fusionner sans doublons.
  5. N'enregistrer les coordonnées que si confidence est suffisant.

Pour aller plus loin

Et vous, comment écrivez-vous vos adresses ? Partagez votre requête tunisienne la plus compliquée en commentaire, ou écrivez-nous à support@tmott13

Top comments (0)