;;; babel.el --- interface to web translation services such as Babelfish ;;; ;;; Author: Eric Marsden ;;; Keywords: translation, web ;;; Copyright: (C) 1999-2001 Eric Marsden ;; ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 2 of ;; the License, or (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public ;; License along with this program; if not, write to the Free ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. ;; ;; Please send suggestions and bug reports to . ;; The latest version of this package should be available at ;; ;; ;; joakim@verona.se added support for the swedish lexin service. ;;; Commentary: ;;; Overview ========================================================== ;; ;; This module provides an Emacs interface to different translation ;; services available on the Internet. You give it a word or paragraph ;; to translate and select the source and destination languages, and ;; it connects to the translation server, retrieves the data, and ;; presents it in a special *babel* buffer. Currently the following ;; backends are available: ;; ;; * the Babelfish service at babelfish.altavista.com (now uses UTF-8 ;; encoding, which w3 doesn't know how to handle, so you'll see ;; strange characters). ;; * the SysTran motor at onlinetrans.com ;; * the InterTrans server at tranexp.com ;; * the Transparent Language motor at FreeTranslation.com ;; * the Leo Dictionary at dict.leo.org (thanks to Klaus Berndl) ;; * the e-PROMPT motor at www.translate.ru (thanks to Ferenc Wagner) ;; ;; Entry points: either 'M-x babel', which prompts for a phrase, a ;; language pair and a backend, or 'M-x babel-region', which prompts ;; for a language pair and backend, then translates the currently ;; selected region, and 'M-x babel-buffer' to translate the current ;; buffer. ;; ;; The InterTrans server can translate to and from any of 25 languages. ;; Babelfish and Systran (which use the same translation engine) ;; can translate between a smaller number of languages, typically with ;; less poor results. If you ask for a language combination which ;; several backends could translate, babel.el will allow you to choose ;; which backend to use. Since most servers have limits on the ;; quantity of text translated, babel.el will split long requests into ;; translatable chunks and submit them sequentially. ;; ;; Please note that the washing process (which takes the raw HTML ;; returned by a translation server and attempts to extract the useful ;; information) is fragile, and can easily be broken by a change in ;; the server's output format. In that case, check whether a new ;; version is available (and if not, warn me; I don't translate into ;; Welsh very often). ;; ;; Also note that by accessing an online translation service you are ;; bound by its Terms and Conditions; in particular ;; FreeTranslation.com is for "personal, non-commercial use only". ;; ;; ;; Installation ======================================================== ;; ;; Place this file in a directory in your load-path (to see a list of ;; appropriate directories, type 'C-h v load-path RET'). Optionally ;; byte-compile the file (for example using the 'B' key when the ;; cursor is on the filename in a dired buffer). Then add the ;; following lines to your ~/.emacs.el initialization file: ;; ;; (autoload 'babel "babel" ;; "Use a web translation service to translate the message MSG." t) ;; (autoload 'babel-region "babel" ;; "Use a web translation service to translate the current region." t) ;; (autoload 'babel-as-string "babel" ;; "Use a web translation service to translate MSG, returning a string." t) ;; (autoload 'babel-buffer "babel" ;; "Use a web translation service to translate the current buffer." t) ;; ;; babel.el requires w3, the EmacsOS web browser to be installed. w3 ;; comes preinstalled with XEmacs before v21, and as a package for ;; 21.x; Emacs users can download it from ;; . It is also ;; available as a package called `w3-el' for Debian GNU/Linux; see ;; . ;; ;; ;; Backend information ================================================= ;; ;; A babel backend named must provide three functions: ;; ;; (babel--translation from to) ;; ;; where FROM and TO are three-letter language abbreviations from ;; the alist `babel-languages'. This should return non-nil if the ;; backend is capable of translating between these two languages. ;; ;; (babel--fetch msg from to) ;; ;; where FROM and TO are as above, and MSG is the text to ;; translate. Connect to the appropriate server and fetch the raw ;; HTML corresponding to the request. ;; ;; (babel--wash) ;; ;; When called on a buffer containing the raw HTML provided by the ;; server, remove all the uninteresting text and HTML markup. ;; ;; I would be glad to incorporate backends for new translation servers ;; which are accessible to the general public. List of translation ;; engines and multilingual dictionaries at ;; . ;; ;; ;; ;; ;; babel.el was inspired by a posting to the ding list by Steinar Bang ;; . Morten Eriksen provided several ;; patches to improve InterTrans washing. Thanks to Per Abrahamsen and ;; Thomas Lofgren for pointing out a bug in the keymap code. Matt ;; Hodges suggested ignoring case ;; on completion. Colin Marquardt suggested ;; `babel-preferred-to-language'. David Masterson suggested adding a ;; menu item. ;; ;; User quotes: Dieses ist die größte Sache seit geschnittenem Brot. ;; -- Stainless Steel Rat ;;; Code: (require 'cl) (require 'easymenu) (defconst babel-version 0.20 "The version number of babel.el.") (defconst babel-languages '(("English" . "eng") ("Brazilian Portuguese" . "pob") ("German" . "ger") ("Dutch" . "dut") ("Latin American Spanish" . "spl") ("Spanish" . "spa") ("European Spanish" . "spe") ("French" . "fre") ("Japanese (Shift JIS)" . "jpn") ("Danish" . "dan") ("Icelandic" . "ice") ("Finnish" . "fin") ("Italian" . "ita") ("Norwegian" . "nor") ("Swedish" . "swe") ("Portuguese" . "poe") ("Russian (CP 1251)" . "rus") ("Croatian (CP 1250)" . "cro") ("Hungarian (CP 1250)" . "hun") ("Polish (CP 1250)" . "pol") ("Czech (CP 1250)" . "che") ("Serbian (Latin)" . "sel") ("Slovenian (CP 1250)" . "slo") ("Greek" . "grk") ("Welsh" . "wel") ("Esperanto" . "esp") ("Lojban" . "loj"))) (defvar babel-preferred-to-language "French" "*Default target translation language. This must be the long name of one of the languages in the alist `babel-languages'.") (defvar babel-to-history (list babel-preferred-to-language)) (defvar babel-from-history (list)) (defvar babel-backend-history (list)) (defvar babel-mode-hook nil) (defvar babel-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "q") #'bury-buffer) (define-key map (kbd "SPC") #'scroll-up) (define-key map (kbd "DEL") #'scroll-down) (define-key map (kbd "<") #'beginning-of-buffer) (define-key map (kbd ">") #'end-of-buffer) (define-key map (kbd "s") #'isearch-forward) (define-key map (kbd "r") #'isearch-backward) (define-key map (kbd "h") #'describe-mode) map) "Keymap used in Babel mode.") (defvar babel-backends '( ;; ("Babelfish at Altavista" . fish) ("SysTran" . systran) ("InterTrans" . intertrans) ("FreeTranslation" . free) ("WorldBlaze" . blaze) ("Leo Dictionary" . leo) ("e-PROMPT" . prompt) ("Lojban Glossary" . lojban) ("Lexin" . lexin) ) "List of backends for babel translations.") ;;;###autoload (defun babel (msg &optional no-display) "Use a web translation service to translate the message MSG. Display the result in a buffer *babel* unless the optional argument NO-DISPLAY is nil." (interactive "sTranslate phrase: ") (let* ((completion-ignore-case t) (from-suggest (or (first babel-from-history) (caar babel-languages))) (from-long (completing-read "Translate from: " babel-languages nil t (cons from-suggest 0) 'babel-from-history)) (to-avail (remove* from-long babel-languages :test #'(lambda (a b) (string= a (car b))))) (to-suggest (or (first babel-to-history) (caar to-avail))) (to-long (completing-read "Translate to: " to-avail nil t (cons to-suggest 0) 'babel-to-history)) (from (cdr (assoc from-long babel-languages))) (to (cdr (assoc to-long babel-languages))) (backends (babel-get-backends from to)) (backend-str (completing-read "Using translation service: " backends nil t (cons (or (first babel-backend-history) (caar backends)) 0) 'babel-backend-history)) (backend (symbol-name (cdr (assoc backend-str babel-backends)))) (fetcher (intern (concat "babel-" backend "-fetch"))) (washer (intern (concat "babel-" backend "-wash"))) (chunks (babel-chunkify msg 700)) (translated-chunks '()) (view-read-only nil)) (loop for chunk in chunks do (push (babel-work chunk from to) translated-chunks)) (if no-display (apply #'concat (nreverse translated-chunks)) (with-output-to-temp-buffer "*babel*" (message "Translating...") (loop for tc in (nreverse translated-chunks) do (princ tc)) (save-excursion (set-buffer "*babel*") (babel-mode)) (message "Translating...done"))))) ;;;###autoload (defun babel-region (start end) "Use a web translation service to translate the current region." (interactive "r") (babel (buffer-substring-no-properties start end))) ;;;###autoload (defun babel-as-string (msg) "Use a web translation service to translate MSG, returning a string." (interactive "sTranslate phrase: ") (babel msg t)) ;; suggested by Djalil Chafai ;; ;;;###autoload (defun babel-buffer () "Use a web translation service to translate the current buffer. Default is to present the translated text in a *babel* buffer. With a prefix argument, replace the current buffer contents by the translated text." (interactive) (let (pos) (cond (prefix-arg (setq pos (point-max)) (goto-char pos) (insert (babel-as-string (buffer-substring-no-properties (point-min) (point-max)))) (delete-region (point-min) pos)) (t (babel-region (point-min) (point-max)))))) (defun babel-work (msg from to) (save-excursion (save-window-excursion (set-buffer (get-buffer-create " *babelurl*")) (erase-buffer) (funcall fetcher (babel-preprocess msg) from to) (setq buffer-file-name nil) ; don't know why w3 sets this (funcall washer) (babel-postprocess) ;;JAVE (babel-display) (buffer-substring-no-properties (point-min) (point-max))))) (defun babel-get-backends (from to) "Return a list of those backends which are capable of translating language FROM into language TO." (loop for b in babel-backends for name = (symbol-name (cdr b)) for translator = (intern (concat "babel-" name "-translation")) for translatable = (funcall translator from to) if translatable collect b)) (defun babel-display () (require 'w3m) (save-excursion (w3m-region (point-min) (point-max)))) ;JAVE replaced w3-region with w3m-region (defun babel-mode () (interactive) (use-local-map babel-mode-map) (setq major-mode 'babel-mode mode-name "Babel") (run-hooks 'babel-mode-hook)) (cond ((fboundp 'string-make-unibyte) (fset 'babel-make-unibyte #'string-make-unibyte)) ((fboundp 'string-as-unibyte) (fset 'babel-make-unibyte #'string-as-unibyte)) (t (fset 'babel-make-unibyte #'identity))) ;; from nnweb.el, with added `string-make-unibyte'. (defun babel-form-encode (pairs) "Return PAIRS encoded for forms." ; (require 'w3-forms) (mapconcat (lambda (data) (concat (babel-w3-form-encode-xwfu (babel-make-unibyte (car data))) "=" (babel-w3-form-encode-xwfu (babel-make-unibyte (cdr data))))) pairs "&")) ;JAVE I ripped this out of w3-forms.el (defun babel-w3-form-encode-xwfu (chunk) "Escape characters in a string for application/x-www-form-urlencoded. Blasphemous crap because someone didn't think %20 was good enough for encoding spaces. Die Die Die." ;; This will get rid of the 'attributes' specified by the file type, ;; which are useless for an application/x-www-form-urlencoded form. (if (consp chunk) (setq chunk (cdr chunk))) (mapconcat (function (lambda (char) (cond ((= char ? ) "+") ((memq char url-unreserved-chars) (char-to-string char)) (t (upcase (format "%%%02x" char)))))) (mule-encode-string chunk) "")) ;JAVE mule-encode-string resides mule-sysdp.el from w3, which seems standalone ;; We mark paragraph endings with a special token, so that we can ;; recover a little information on the original message's format after ;; translation and washing and rendering. Should really be using ;; `paragraph-start' and `paragraph-separate' here, but we no longer ;; have any information on the major-mode of the buffer that STR was ;; ripped from. ;; ;; This kludge depends on the fact that all the translation motors ;; seem to leave words they don't know how to translate alone, passing ;; them through untouched. (defun babel-preprocess (str) (while (string-match "\n\n\\|^\\s-+$" str) (setq str (replace-match " FLOBSiCLE " nil t str))) str) ;; decode paragraph endings in current buffer (defun babel-postprocess () (goto-char (point-min)) (while (search-forward "FLOBSiCLE" nil t) (replace-match "\n

" nil t))) ;; split STR into chunks of around LENGTH characters, trying to ;; maintain sentence structure (this is used to send big requests in ;; several batches, because otherwise the motors cut off the ;; translation). (defun babel-chunkify (str chunksize) (let ((start 0) (pos 0) (chunks '())) (while (setq pos (string-match (sentence-end) str pos)) (incf pos) (when (> (- pos start) chunksize) (push (substring str start pos) chunks) (setq start pos))) (when (/= start (length str)) (push (substring str start) chunks)) (nreverse chunks))) ;;;###autoload (defun babel-version (&optional here) "Show the version number of babel in the minibuffer. If optional argument HERE is non-nil, insert version number at point." (interactive "P") (let ((version-string (format "Babel version %s" babel-version))) (if here (insert version-string) (if (interactive-p) (message "%s" version-string) version-string)))) ;; Babelfish-specific functions ================================================ ;; ;; Babelfish (which uses the SysTran engine) is only able to translate ;; between a limited number of languages. ;; translation from 3-letter names to Babelfish 2-letter names (defconst babel-fish-languages '(("eng" . "en") ("ger" . "de") ("ita" . "it") ("poe" . "pt") ("spe" . "es") ("fre" . "fr"))) ;; those inter-language translations that Babelfish is capable of (defconst babel-fish-translations '("en_fr" "en_de" "en_it" "en_pt" "en_es" "fr_en" "de_en" "it_en" "es_en" "pt_en")) ;; if Babelfish is able to translate from language FROM to language ;; TO, then return the corresponding string, otherwise return nil (defun babel-fish-translation (from to) (let* ((fromb (cdr (assoc from babel-fish-languages))) (tob (cdr (assoc to babel-fish-languages))) (comb (and fromb tob (concat fromb "_" tob)))) (find comb babel-fish-translations :test #'string=))) (defun babel-fish-fetch (msg from to) "Connect to the Babelfish server and request the translation." (require 'url) ;; Babelfish now outputs UTF-8. If our emacs has UTF support (from ;; the Mule-UCS package for instance), treat the contents of the ;; buffer as UTF8. Otherwise we will have garbled output for 8-bit ;; characters. (let ((coding-system 'no-conversion)) (when (fboundp 'set-buffer-multibyte) (set-buffer-multibyte t)) (when (member 'utf-8 (coding-system-list t)) (setq coding-system 'utf-8)) (let ((translation (babel-fish-translation from to))) (unless translation (error "Babelfish can't translate from %s to %s" from to)) (let* ((pairs `(("urltext" . ,msg) ("lp" . ,translation) ("doit" . "done") ("bblType" . "urltext"))) (url-request-data (babel-form-encode pairs)) (url-request-method "POST") (url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded"))) (network-coding-system-alist '((80 . ,coding-system)))) (url-insert-file-contents "http://babelfish.altavista.com/translate.dyn"))))) (defun babel-fish-wash () "Extract the useful information from the HTML returned by Babelfish." (goto-char (point-min)) (cond ((search-forward "http://altavista.com/cgi-bin/query\" method=get>" nil t) ;; short response format (delete-region (point-min) (match-end 0)) (when (re-search-forward "^\\s-*$" nil t) (delete-region (match-beginning 0) (point-max)))) ((prog2 (goto-char (point-min)) (re-search-forward "^" nil t)) ;; long response format (delete-region (point-min) (match-end 0)) (when (search-forward "" nil t) (delete-region (point-max) (match-beginning 0)))) (t (error "Babelfish HTML has changed; please look for a new version of babel.el"))) (goto-char (point-min)) (while (re-search-forward "<[^>]+>" nil t) (replace-match "" t))) ;; SysTrans-specific functions =========================================== (defalias 'babel-systran-translation 'babel-fish-translation) (defun babel-systran-fetch (msg from to) "Connect to the SysTran server and request the translation." (require 'url) (let ((translation (babel-systran-translation from to))) (unless translation (error "Systran can't translate from %s to %s" from to)) (let* ((pairs `(("partner" . "demo-SystranSoft") ("urltext" . ,msg) ("lp" . ,translation))) (url-request-data (babel-form-encode pairs)) (url-request-method "POST") (url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded")))) (url-insert-file-contents "http://www.systranlinks.com/systran/cgi")))) (defun babel-systran-wash () "Extract the useful information from the HTML returned by SysTran." (goto-char (point-min)) (let ((case-fold-search t)) (when (re-search-forward "name=translated_text[^>]+>" nil t) (delete-region (point-min) (match-end 0))) (goto-char (point-max)) (when (re-search-backward "^
" nil t) (delete-region (point-max) (match-beginning 0))) (goto-char (point-min)) (while (re-search-forward "<[^>]+>" nil t) (replace-match "" t)))) ;; InterTrans-specific functions ========================================== ;; InterTrans can do all the possible language combinations, except ;; for Lojban (defun babel-intertrans-translation (to from) (and (not (string= to "loj")) (not (string= from "loj")))) (defun babel-intertrans-fetch (msg from to) "Connect to the InterTrans server and request the translation." (require 'url) (let* ((pairs `(("type" . "text") ("url" . "http://") ("text" . ,msg) ("from" . ,from) ("to" . ,to))) (url-request-data (babel-form-encode pairs)) (url-request-method "POST") (url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded")))) (url-insert-file-contents "http://www.tranexp.com:2000/InterTran"))) ;; these functions by Morten Eriksen . InterTrans ;; returns different HTML depending on whether you request the ;; translation of a phrase or of a single word. If you ask for a ;; single word which it doesn't know how to translate it will attempt ;; to find the closest match. (defun babel-intertrans-wash () "Extract the useful information from the HTML returned by InterTrans." (goto-char (point-min)) (if (search-forward "Translated text:" nil t) (babel-intertrans-wash-expression) (if (search-forward "Closest match" nil t) (babel-intertrans-wash-closest-match) (babel-intertrans-wash-single-word)))) (defun babel-intertrans-wash-expression () "Wash the HTML page InterTrans returns when translating an expression." (goto-char (point-min)) (let ((case-fold-search t)) (when (search-forward "Translated text:" nil t) (delete-region (point-min) (match-end 0))) (goto-char (point-max)) (when (re-search-backward "]+>" nil t) (replace-match "" t)))) (defun babel-intertrans-wash-single-word () "Wash the HTML page InterTrans returns when translating a single word." (goto-char (point-min)) (when (search-forward ":\n

    " nil t) (delete-region (point-min) (match-end 0)) (when (search-forward "
    " nil t) (delete-region (match-beginning 0) (point-max))))) (defun babel-intertrans-wash-closest-match () "Wash the HTML page InterTrans returns when the word is not found." (goto-char (point-min)) (when (search-forward "Closest match" nil t) (delete-region (point-min) (match-beginning 0)) (when (search-forward "
    " nil t) (delete-region (match-beginning 0) (point-max))))) ;; FreeTranslation.com stuff =========================================== ;; translation from 3-letter names to FreeTranslation names (defconst babel-free-languages '(("eng" . "English") ("ger" . "German") ("ita" . "Italian") ("poe" . "Portuguese") ("spe" . "Spanish") ("fre" . "French"))) ;; those inter-language translations that FreeTranslation is capable of (defconst babel-free-translations '("Spanish/English" "French/English" "German/English" "English/Spanish" "English/French" "English/German" "English/Italian" "English/Portuguese")) (defun babel-free-translation (from to) (let* ((ffrom (cdr (assoc from babel-free-languages))) (fto (cdr (assoc to babel-free-languages))) (trans (concat ffrom "/" fto))) (find trans babel-free-translations :test #'string=))) (defun babel-free-fetch (msg from to) "Connect to the FreeTranslation server and request the translation." (require 'url) (let ((translation (babel-free-translation from to))) (unless translation (error "FreeTranslation can't translate from %s to %s" from to)) (let* ((pairs `(("Sequence" . "core") ("Mode" . "html") ("Template" . "TextResult2.htm") ("SrcText" . ,msg) ("Language" . ,translation))) (url-request-data (babel-form-encode pairs)) (url-request-method "POST") (url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded")))) (url-insert-file-contents "http://ets.freetranslation.com:5081/"))) ) (defun babel-free-wash () "Extract the useful information from the HTML returned by FreeTranslation." (goto-char (point-min)) (let ((case-fold-search t)) (when (search-forward "by SDL International --

    " nil t) (delete-region (point-min) (match-end 0))) (goto-char (point-max)) (when (search-backward "-----------" nil t) (delete-region (point-max) (match-beginning 0))) (goto-char (point-min)) (while (re-search-forward "<[^>]+>" nil t) (replace-match "" t)))) ;; WorldBlaze.com stuff =========================================== ;; translation from 3-letter names to WorldBlaze names (defconst babel-blaze-languages '(("eng" . "en") ("ger" . "de") ("ita" . "it") ("poe" . "pt") ("spe" . "es") ("fre" . "fr"))) ;; those inter-language translations that WorldBlaze is capable of (defconst babel-blaze-translations '("enes-LHS" "enfr-LHS" "ende-LHS" "enit-LHS" "enpt-LHS" "enja-ATL" "enru-PROMT" "jaen-ATL" "fren-LHS" "frde-LHS" "frit-LHS" "frru-PROMT" "esen-LHS" "esit-LHS" "deen-LHS" "defr-LHS" "deit-LHS" "deru-PROMT" "iten-LHS" "itde-LHS" "ites-LHS" "itfr-LHS" "itru-PROMT" "pten-LHS" "ruen-PROMT" "rude-PROMT" "rufr-PROMT")) (defun babel-blaze-translation (from to) (let* ((ffrom (cdr (assoc from babel-blaze-languages))) (fto (cdr (assoc to babel-blaze-languages))) (trans (concat ffrom fto "-"))) (find trans babel-blaze-translations :test #'string-match))) (defun babel-blaze-fetch (msg from to) "Connect to the WorldBlaze server and request the translation." (require 'url) (let ((translation (babel-blaze-translation from to))) (unless translation (error "WorldBlaze can't translate from %s to %s" from to)) (let* ((pairs `(("go" . "Translate") ("data" . ,msg) ("lp" . ,translation))) (data (babel-form-encode pairs))) (url-insert-file-contents (concat "http://www.worldblaze.com/scripts/frtpgdemo.cgi?" data))))) (defun babel-blaze-wash () "Extract the useful information from the HTML returned by BlazeTranslation." (goto-char (point-min)) (let ((case-fold-search t)) (when (search-forward "

    Translated Text:

    " nil t) (delete-region (point-min) (match-end 0))) (goto-char (point-max)) (when (search-backward "

    Original Text:

    " nil t) (delete-region (point-max) (match-beginning 0))) (goto-char (point-min)) (while (re-search-forward "<[^>]+>" nil t) (replace-match "" t)))) ;; Leo-specific functions ================================================ ;; ;; this code contributed by Klaus Berndl . This ;; backend is mainly word-oriented; if you submit a phrase it will ;; give translations for the words (or subphrases) in the phrase. (defconst babel-leo-languages '(("eng" . "en") ("ger" . "de"))) (defconst babel-leo-translations '("en_de" "de_en")) (defun babel-leo-translation (from to) (let* ((fromb (cdr (assoc from babel-leo-languages))) (tob (cdr (assoc to babel-leo-languages))) (comb (and fromb tob (concat fromb "_" tob)))) (find comb babel-leo-translations :test #'string=))) (defun babel-leo-fetch (msg from to) "Connect to the Leo server and request the translation." (require 'url) (let* ((translation (babel-leo-translation from to)) (pairs `(("search" . ,msg) ("lang" . "en"))) ; indicates in which language the ; leo-resultpage is displayed (url-request-data (babel-form-encode pairs)) (url-request-method "POST") (url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded")))) (unless translation (error "Leo Dictionary can't translate from %s to %s" from to)) (url-insert-file-contents "http://dict.leo.org"))) (defun babel-leo-wash () (goto-char (point-min)) (if (re-search-forward "" nil t) (let ((result-table (match-string 0))) (erase-buffer) (insert result-table)) (error "Leo Dictionary HTML has changed ; please look for a new version of babel.el"))) ;; PROMPT stuff =========================================== ;; ;; Contributed by Ferenc Wagner ;; translation from 3-letter names to e-PROMPT names (defconst babel-prompt-languages '(("eng" . 1) ("rus" . 2) ("ger" . 4) ("fre" . 8) ("ita" . 16) ("spe" . 32))) ;; those inter-language translations that e-PROMPT is capable of (defconst babel-prompt-translations '( 262145 ; English-German 65540 ; German-English 524289 ; English-French 65544 ; French-English 524292 ; German-French 262152 ; French-German 2097153 ; English-Spanish 65568 ; Spanish-English )) (defun babel-prompt-translation (from to) (let ((ffrom (cdr (assoc from babel-prompt-languages))) (fto (cdr (assoc to babel-prompt-languages)))) (and ffrom fto (find (+ ffrom (* 65536 fto)) babel-prompt-translations :test #'=)))) (defun babel-prompt-fetch (msg from to) "Connect to the e-PROMPT server and request the translation." (require 'url) (let ((translation (babel-prompt-translation from to))) (unless translation (error "PROMPT can't translate from %s to %s" from to)) (let* ((pairs `(("CharSet" . "windows-1252") ; iso-8859-2 ("CharSetTo" . "windows-1252") ; iso-8859-2 ("Language" . "English") ("status" . "translate") ("source" . ,msg) ("directions" . ,(number-to-string translation)) ("templates" . "Default"))) (url-request-data (babel-form-encode pairs)) (url-request-method "POST") (url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded")))) (url-insert-file-contents "http://www.translate.ru/eng/other.asp")))) (defun babel-prompt-wash () "Extract the useful information from the HTML returned by e-PROMPT." (goto-char (point-min)) (unless (re-search-forward "]+>\\([^<]*\\)" nil t) (error "e-PROMPT HTML has changed; please look for a new version of babel.el")) (delete-region (match-end 1) (point-max)) (delete-region (point-min) (match-beginning 1))) ;; Lojban Glossary =============================================== ;; ;; Contributed by Mario Lang . (defun babel-lojban-translation (from to) "Lojban Glossary can only translate to english." (and (string= from "loj") (string= to "eng"))) (defun babel-lojban-fetch (msg from to) "Connect to the Lojban Glossary server and request the translation." (require 'url) (let* ((translation (babel-lojban-translation from to)) (pairs `(("lojtext" . ,msg))) (url-request-data (babel-form-encode pairs)) (url-request-method "POST") (url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded")))) (unless translation (error "Lojban Glossary can't translate from %s to %s" from to)) (url-insert-file-contents "http://www.barsoom.net/lojban/hezekiah/glossary.cgi"))) (defun babel-lojban-wash () (goto-char (point-min)) (if (re-search-forward "
    " nil t) (progn (delete-region (point-min) (point)) (goto-char (point-max)) (if (re-search-backward "
    " nil t) (delete-region (point) (point-max)) (error "Lojban Glossary format has changed."))) (error "Lojban Glossary format has changed."))) ;; (defun babel-debug () ;; (let ((buf (get-buffer-create "*babel-debug*"))) ;; (set-buffer buf) ;; (babel-free-fetch "state mechanisms are too busy" "eng" "ger"))) (easy-menu-add-item nil '("tools") ["Babel Translation" babel t]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;JAVE lexin backend (defun babel-lexin-translation (from to) (or (and (string= "eng" from) (string= "swe" to)) (and (string= "swe" from) (string= "eng" to))) ) (defun babel-lexin-fetch (msg from to) "Connect to the Lexin server and request the translation." (require 'url) (let* ((translation (babel-lexin-translation from to)) (sprak (if (string= from "swe") "källspråk" "målspråk")) (pairs `(("uppslagsord" . ,msg)("sprak" . ,sprak))) (url-request-data (babel-form-encode pairs)) (url-request-method "POST") (url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded")))) (unless translation (error "Lexin can't translate from %s to %s" from to)) (url-insert-file-contents "http://lexikon.nada.kth.se/cgi-bin/sve-eng")) ) ;;;;the lexin input form looks like this: ;;
    ;; Svenska till engelska.
    ;; Engelska till svenska. ;; ;; ;; ;;
    ;;lexin only handles a single word, its a dictionary (defun babel-lexin-wash () ;do nothing to start with ;wash will be called on the raw html. ;could look for

    ; then (goto-char (point-min)) (if (re-search-forward "

    " nil t) (progn (delete-region (point-min) (point)) (goto-char (point-max)) (if (re-search-backward "