Localisation avec AutoLISP

mardi 27 janvier 2026

Il peut parfois être nécessaire de traduire vos programmes AutoLISP en plusieurs langues.

Pour cela, on va d'abord avoir besoin d'une fonction qui permet de diviser une chaîne en une liste de sous-chaînes.

;;; Divise une chaîne en une liste de sous-chaînes
;;; string : la chaîne à diviser
;;; separator : le caractère séparateur
;;; ignore-empty : si vrai, ignore les sous-chaînes vides
(defun split-string (string separator ignore-empty / result current-word index character)
  (setq result '())
  (setq current-word "")
  (setq index 1)

  (while (<= index (strlen string))
    (setq character (substr string index 1))
    (if (= character separator)
      (progn
        (if (or (not ignore-empty) (/= current-word ""))
          (setq result (append result (list current-word)))
        )
        (setq current-word "")
      )
      (setq current-word (strcat current-word character))
    )
    (setq index (1+ index))
  )

  (if (or (not ignore-empty) (/= current-word ""))
    (setq result (append result (list current-word)))
    result
  )
)

Ensuite, on a besoin de connaitre la langue utilisée par AutoCAD pour savoir quelles traductions utiliser. Aussi étonnant que cela puisse paraître, AutoCAD ne fournit pas de variable système pour cela. Il y a une variable nommée LOCALE, mais elle renvoie un code correspondant à la langue du système d'exploitation. Pour avoir la langue utilisée par AutoCAD, il faut utilsier un moyen détouné :

;;; Retourne la culture actuelle d'AutoCAD en majuscules
;;; FRA pour français/France, ENU pour anglais/Etats-Unis, etc.
(defun get-acad-culture (/)
  ;; La variable système LOCALE retourne la langue du système d'exploitation, mais pas la culture d'AutoCAD.
  ;; La variable système LOCALROOTPREFIX contient un chemin qui se termine par le code de culture.
  ;; Exemple : C:\Users\<Nom d'utilisateur>\AppData\Local\Autodesk\AutoCAD 2026\R25.1\fra\
  (strcase (last (split-string (getvar "LOCALROOTPREFIX") "\\" T)))
)

La variable système LOCALROOTPREFIX contient un chemin qui se termine par le code de culture d'AutoCAD. Donc on peut utiliser la première fonction split-string pour extraire le code de culture.

Ensuite, pour les traductions, on va utiliser un fichier TSV (Tab-Separated Values). Ce type de fichier permet de stocker des données tabulaires et on peut les créer et les modifier facilement avec un tableur comme Microsoft Excel.

ID	ENU	FRA
hello	Hello	Bonjour
goodbye	Goodbye	Au revoir

Attention, il faut utiliser UTF-8 pour encoder le fichier TSV sinon les caractères spéciaux (é, è, etc.) ne seront pas correctement affichés.

La première colonne est un identifiant unique pour chaque traduction. Les colonnes suivantes contiennent les traductions en différentes langues.

On peut charger le fichier avec la fonction suivante :

;;; Retourne l'index (0-based) d'un élément dans une liste, ou nil si non trouvé
;;; element : l'élément à rechercher
;;; items : la liste dans laquelle chercher
(defun find-index (element items / index found)
  (setq index 0)
  (setq found nil)
  (while (and (not found) (nth index items))
    (if (= (nth index items) element)
      (setq found T)
      (setq index (1+ index))
    )
  )
  (if found index nil)
)

;;; Charge les traductions depuis un fichier TSV pour la culture courante
;;; Le fichier doit comporter un en-tête avec les codes de culture (ENU, FRA, etc.)
;;; La première colonne contient les identifiants
;;; filename : chemin du fichier TSV
;;; Résultat : définit la variable globale $strings (liste de paires pointées)
(defun load-strings (filename / file header-line headers culture-index line columns)
  (setq file (open filename "r"))
  (if (not file)
    (progn
      (princ (strcat "\nErreur : impossible d'ouvrir le fichier " filename))
      nil
    )
    (progn
      ;; Lire l'en-tête et trouver la colonne de la culture courante
      (setq header-line (read-line file))
      (setq headers (split-string header-line "\t" T))
      (setq culture-index (find-index (get-acad-culture) headers))

      ;; Si la culture courante n'est pas trouvée, utiliser ENU par défaut
      (if (not culture-index)
        (setq culture-index (find-index "ENU" headers))
      )

      (if (not culture-index)
        (progn
          (close file)
          (princ "\nErreur : aucune colonne de traduction trouvee.")
          nil
        )
        (progn
          ;; Lire chaque ligne et construire la liste d'associations
          (setq $strings '())
          (while (setq line (read-line file))
            (setq columns (split-string line "\t" nil))
            (if (and (car columns) (nth culture-index columns))
              (setq $strings (cons (cons (car columns) (nth culture-index columns)) $strings))
            )
          )
          (setq $strings (reverse $strings))
          (close file)
          $strings
        )
      )
    )
  )
)

Les traductions sont stockées dans la variable globale $strings (noter le $ qui indique une variable globale). Elle va contenir une liste de paires pointées similaire à ('("hello" "Hello") ("goodbye" "Goodbye")). C'est l'équivalent d'un dictionnaire en Python ou en .NET.

Une fois les traductions chargées, on peut utiliser assoc pour récupérer une traduction :

;;; Retourne la traduction associée à un identifiant
;;; identifier : l'identifiant de la chaîne à traduire
(defun get-string (identifier)
  (cdr (assoc identifier $strings))
)

Vous pouvez maintenant utiliser ce petit framework comme ceci :

(load-strings "traductions.tsv")
(princ (get-string "hello"))

Coup de pouce Besoin d'un développement AutoCAD (AutoLISP, ObjectARX, .NET, VBA) ? Contactez-moi pour un devis gratuit.