;;; -*- lexical-binding: t -*- ;; ;; this file: ;; https://dataswamp.org/~incal/emacs-init/ispell-detect.el ;; ;; NOTE: ;; GNU ELPA has `guess-language'. Try that first! ;; ;; Installation on Debian: ;; ;; 1. For detection, install the /usr/share/dict files from ;; the 'w-' packages, for example 'wamerican-insane', ;; 'wfrench' and 'wswedish'. ;; ;; 2. For correction, install the ispell files from the 'i-' ;; packages, for example 'iamerican-insane', 'ifrench-gut' ;; and 'iswedish'. ;; ;; 3. Set `ispell-detect--langs' as below. ;; ;; Test detection: ;; ;; (ispell-detect (point) (pos-eol)) ; l'oiseau aimait le beau ;; (ispell-detect (point) (pos-eol)) ; detta är en mening på svenska ;; (ispell-detect (point) (pos-eol)) ; this isn't just another program ;; ;; Test multiple language spelling: ;; ;; https://dataswamp.org/~incal/test-spell/3lang.txt (require 'cl-lib) (require 'ispell) (defvar ispell-detect--langs '( ("/usr/share/dict/american-english-insane" "English") ("/usr/share/dict/french" "francais") ("/usr/share/dict/swedish" "svenska")) ) (defun ids--region () (if (use-region-p) (list (region-beginning) (region-end)) (list nil nil))) (defun ispell-detect-spell (&optional beg end probe-forward spell-forward) (interactive (ids--region)) (or beg (setq beg (point-min))) (or end (setq end (point-max))) (or probe-forward (setq probe-forward #'forward-sentence)) (or spell-forward (setq spell-forward #'forward-paragraph)) (goto-char beg) (cl-loop for beg = (point) for probe-end = (progn (funcall probe-forward) (point)) for spell-end = (progn (goto-char beg) (funcall spell-forward) (min (point) end)) while (< beg spell-end) for lang = (ispell-detect beg probe-end) do (unless (string= lang ispell-current-dictionary) (ispell-change-dictionary lang)) (ispell-region beg spell-end))) (defun ispell-detect (&optional beg end) "Detect the language used in the current buffer, from the alternatives in `ispell-detect--langs'. \nDetect on the region from BEG to END [paragraph]. \nMethod: `ispell-count'" (interactive (ids--region)) (save-mark-and-excursion (cl-loop with beg = (or beg (progn (start-of-paragraph-text) (point))) with end = (or end (progn (end-of-paragraph-text) (point))) for (wl d) in ispell-detect--langs collect (list d (ispell-count beg end wl)) into res finally return (caar (cl-sort res #'< :key #'cadr))))) (defun ispell-count (&optional beg end wordlist) "Spell the region from BEG to END [whole buffer] with WORDLIST, Return the ratio of incorrectly spelled words." (interactive (ids--region)) (or beg (setq beg (point-min))) (or end (setq end (point-max))) (save-mark-and-excursion (goto-char beg) (forward-word) (backward-word) (cl-loop with words = 0 with errors = 0 while (< (point) end) do (let ((word (thing-at-point 'word t))) (unless (ispell-lookup-words word wordlist) (cl-incf errors)) (cl-incf words) (forward-to-word)) finally return (/ errors words 1.0)))) (provide 'ispell-detect)