Emacs でテキスト翻訳をする
以前作った, エキサイト翻訳をするやつを更新した.
ほぼ全修正.
いやーいじったね.
エキサイトだけでなく, Google Translation も使えるようにした.
# ホントは, altavista, worldlingo も足したかったけど, 何度試しても上手くいかないからあきらめた.
まずは, Ruby スクリプト.
これを使って, 翻訳サイトへ繋いで, 翻訳をする.
以前作ったクラスが残ってないw
# 翻訳サイトを利用して, テキストを翻訳する Ruby プログラム. # 文字コードに注意 # ============================================================ # コマンドラインからの使用法 # ============================================================ # # このファイルの名前を translate.rb とし, ~/lib/ 以下に配置したとする. # # エキサイト翻訳 : # 英語 → 日本語 excite_enja # 日本語 → 英語 excite_jaen # Google Translation : # 英語 → 日本語 google_enja # 日本語 → 英語 google_jaen # # ------------------------------------------------------------ # $ ruby ~/lib/translate.rb excite_enja "Japanese" # ------------------------------------------------------------ # # excite_enja のところを, 別のもの, # google_enja 等に変更すれば, 他の翻訳サイトで翻訳をする. # 翻訳した文字は, utf-8 で返戻される. # # ============================================================ require "net/http" require "kconv" class TranslateByWeb attr_reader :sites def initialize () @sites = Hash.new # サイトの登録 @sites["excite_enja"] = register_site( "www.excite.co.jp", "/world/english/", "wb_lp=ENJA&before=%s", "<input type=\"hidden\" name=\"after\" value=\"([^\"]*)", "sjis" ) @sites["excite_jaen"] = register_site( "www.excite.co.jp", "/world/english/", "wb_lp=JAEN&before=%s", "<input type=\"hidden\" name=\"after\" value=\"([^\"]*)", "sjis" ) @sites["google_enja"] = register_site( "translate.google.com", "/translate_t", "langpair=en|ja&ie=utf-8&oe=utf-8&text=%s", "<div id=result_box dir=ltr>([^<]*)", "utf-8" ) @sites["google_jaen"] = register_site( "translate.google.com", "/translate_t", "langpair=ja|en&ie=utf-8&oe=utf-8&text=%s", "<div id=result_box dir=ltr>([^<]*)", "utf-8" ) end def register_site( site, path, header, regex, code ) name = SiteData.new name.site = site name.path = path name.header = header name.regex = regex name.code = code return name end def return_code ( code, word ) case code when "sjis" return word.to_s.tosjis when "utf-8" return word.to_s.toutf8 when "eucjp" return word.to_s.toeuc when "jis" return word.to_s.tojis else return word.to_s.toutf8 end end def translate( site, word ) site_data = @sites["excite_enja"] @sites.each do |key, val| if key == site site_data = val end end Net::HTTP.start( site_data.site, 80 ) do |http| response = http.post( site_data.path, # site_data.header + return_code( site_data.code, word ) ) site_data.header.sub( /%s/, return_code( site_data.code, word ) ) ) # html ソースがちゃんと取れているか確認用 # puts response.body regex = Regexp.new( site_data.regex ) if regex =~ response.body # puts $1.toutf8 html_to_text( $1.toutf8 ) end end end # 二重引用符や引用符, 不等号を示す特殊文字を変換する. def html_to_text ( string ) # 引用符を変換 string = string.gsub( "'", "'" ) # 二重引用符を変換 string = string.gsub( """, "\"" ) # アンドを変換 string = string.gsub( "&", "&" ) # 不等号を変換 string = string.gsub( "<", "<") string = string.gsub( ">", ">") puts string end end class SiteData attr_accessor :site, :path, :header, :regex, :code def initialize () @site = "" @path = "" @header = "" @regex = "" @code = "utf-8" end end # テスト用 #TranslateByWeb.new.translate( "excite_jaen", "やっと, エキサイト翻訳を使って, 英語から日本語へ翻訳できた. #やった. #疲れたよ, 本当." ) #TranslateByWeb.new.translate( "google_enja", "Japanese " ) # コマンドラインから使用するサイトとテキストを取得して, 翻訳する. tr = TranslateByWeb.new tr.sites.keys.each do |site| if site == ARGV[0] tr.translate( site.to_s, ARGV[1].to_s ) end end
コマンドライン上から使用する場合は, 次のような感じで.
$ ruby ~/lib/translate.rb "excite_enja", "翻訳したい文字列"
変数 @sites に翻訳形式を増やしてあげれば, 日本語から英語とその逆だけじゃなくて,
フランス語に翻訳とかもできると思う. 試してないけど(文字コードで問題がでるかな?).
ちなみに, 翻訳したテキストは, utf-8 で返戻するようにしてる.
それで, こっちが elisp コード.
こっちも関数名からして, 全修した. 挙動も変わってる.
関数 text-translate が翻訳をする関数.
挙動はこんな感じ.
- マークが active だった.
- 前置引数(C-u)あり.
選択した翻訳形式で, リージョンに入れた内容の翻訳を行う. - 前置引数(C-u)なし.
リージョンに入れた内容を excite の英語→日本語翻訳で翻訳する.
- 前置引数(C-u)あり.
- マークが active でなかった.
- 前置引数(C-u)あり.
選択した翻訳形式で, ミニバッファより入力したテキストの翻訳を行う. - 前置引数(C-u)なし.
ミニバッファより入力したテキストを excite の英語→日本語翻訳で翻訳する.
- 前置引数(C-u)あり.
(defun text-translate (arg) "Excite 翻訳や Google Translation を使って, テキスト翻訳をする関数. 1. mark が active だった. - 前置引数が与えられた : 1. 使用する翻訳サイトを選択する. 2. 選択した形式で翻訳する. - 前置引数が与えられなかった : excite_enja でリージョンに入れた範囲を翻訳する. 2. mark が deactive だった. - 前置引数が与えられた. 1. 使用する翻訳サイトを選択する. 2. 選択した形式でミニバッファから入力した値を翻訳する. - 前置引数が与えられなかった. excite_enja でミニバッファから入力した値を翻訳する." (interactive "P") (let* ((sites '(("excite_enja") ("excite_jaen") ("google_enja") ("google_jaen"))) (def (caar sites))) ;; 前置引数があったならば, 使用する翻訳形式を選択したものに変更. (when arg (setq def (completing-read (format "select translation type [default:%s] : " def) sites nil t nil nil def))) (if mark-active (progn (translate-by-website def (buffer-substring-no-properties (region-beginning) (region-end))) (setq mark-active nil)) (translate-by-website def (read-string (format "translate[%s] : " def)))))) (defun translate-by-website (type string) "Ruby スクリプト translate.rb を使用して, 翻訳をする関数." (let ((replace-list '(("`" "‘") ("\\$" "$") ("&" "&") (";" ";") ("%" "%")))) ;; 直接使用できない文字を全角に変換する. (mapc (lambda (x) (let ((num 0)) (while (setq num (string-match (car x) string num)) (setq string (replace-match (nth 1 x) nil nil string))))) replace-list) ;; 翻訳して, *translated* バッファへ表示. (display-buffer (get-buffer-create "*translated*")) (shell-command (concat "ruby ~/lib/translate.rb " type " " (prin1-to-string string)) "*translated*")))
まず, 当然だけど, 翻訳するためには, 先に記述した Ruby スクリプトが必要.
ここでは, ~/lib 以下に, translate.rb という名前で配置している.
これを変更したいならば, 上記コード, 最終行にある, 「~/lib/translate.rb」の部分を変更すれば大丈夫(なはず).
また, デフォの翻訳が excite_enja はイヤだって場合は, 以下の部分の順番を変更すれば変わる(と思う. なんせ試してないから(^^;))
(let* ((sites '(("excite_enja") ("excite_jaen") ("google_enja") ("google_jaen")))
例えば, デフォルトを google_jaen にするならば, 以下のようにする.
(let* ((sites '(("google_jaen") ("excite_enja") ("excite_jaen") ("google_enja")))
まあ, sites の第1引数がデフォになるってこと.
あ, あと, Ruby スクリプトに翻訳形式を足したならば, この sites 変数にも足した翻訳形式を足さないと駄目.
elisp の方で shell-command 使ってるから, ; とか & とかが翻訳したいテキストに含まれてたら, 上手くいかないという事態になってた.
バックスラッシュでクォートしようと頑張ってみたけど, 全然駄目だから,
強引に全角文字に変換することで対処した.
今じゃ, 意外と悪くないかもと思ったりしてる.