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 :
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;
}
- 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.
- 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. - 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
}
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;
<input id="address" type="search" dir="auto">
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(' ');
}
"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é)
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);
}
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.
Et 9asr said tombe bien sur Ksar Said, au Bardo :
É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
proximityet 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é
- Un délai avant d'envoyer, l'annulation des requêtes dépassées, et
proximitypour orienter les résultats. -
lang=arpour des résultats en arabe, etdir="auto"partout où vous les affichez. - Normaliser le dialecte et l'arabizi dans le navigateur, sans toucher aux numéros ni aux routes.
- Chercher en parallèle la saisie brute et la version normalisée, puis fusionner sans doublons.
- N'enregistrer les coordonnées que si
confidenceest suffisant.
Pour aller plus loin
- TMaps pour la livraison et l'e-commerce : www.tmaps.tn
- La démo en ligne : examples.tmaps.tn/04-geocoding-search
- La démo du formulaire de commande : examples.tmaps.tn/12-checkout-address-form
- Le code source, sous licence MIT : github.com/tmaps-tn/tmaps-snippets
- La collection Postman : postman.com/tmaps-tn/tmaps-api
- La documentation du géocodage : tmaps.tn/documentation
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)