Sunday 12 April 2015

在 fedora 21 自制谷歌翻译




【代码更新】 2015-10-31
1. 不再 recompile lex.yy 防止 delay。
2. mpg123 加 client=t 以及 tk=1|0,用 curl 加 UA, 才能跑。

【代码更新】 ?? (有点忙, 得空才 fix)

1. bug:dash 号开头就没有 dialog pop up, 虽然声音有。

【代码更新】 2015 april 19
1. 支持连续的特别字符会比较容易辨识。显示非跨线的 dash(也要小心 ab-\nc-d bug)。
2. 用 text 来取代之前的 html, 要知道区分 <b> 是内容还是 tag 是不可能的任务(即使 compare 之前的 source, 但是如果是语言转换后就不准了)。开头结尾不再有多余的 ""
3. 解决 one way replace (上面错的, 下面对的):

4. notify-send 有时会 truncate, 所以必须让它正确地显示 \\ 和 \n 诸如之类的。
5. silent 掉 curl 和 kill
6. 先 detect 有没有用到的 commands, 没有就用 xmessage 显示信息(notify-send 可能没有, 所以用 x 的内置 xmessage)
7.  bug fixed, [ ]+ only works when dealt with -E, so choose 1 style, i.e. <SPACE><SPACE>* over -E []+ bcoz the former always works regardless of -E
8.  bug fixed, $pre_fold forgot to quotes before pass to fold, and * expand to list files and dir names

【代码更新】 2015 april 15
1. 能够显示/翻译特别字符。 并且规定特别字符至多只能连续一个字(太占位子了,比如说 a is ????? apple) 。(april 19 支持连续)

2. 支持 ecc。

3. bug fixed, dash 的跨 line bugs, 还有更好地优先处理 dash。 ab-\nc-d 只能保留 c-d
4. bug fixed, 中文去英文的 html tag 以及 中文去英文的 F3 speak english bugs。

制作步骤:

1. 把下面的代码 save as 文件, e.g. seltr (纠正: 不是 .sh, 如果你想换别的名(我这个名字 seltr 的含义是 selECTION trANSLATE), 记得把代码的名字, "/usr/bin/seltr" 以及 "Usage: seltr " 改掉。)
2. sudo chmod 777 那个文件, e.g. `sudo chmod 777 seltr`
3. sudo mv 去 /usr/bin/ directory 那里, e.g. `sudo mv seltr /usr/bin/`
4. `gnome-control-center keyboard` 打开, -> "Shortcuts" Tab -> "Custom Shortcuts"
5. 在那里制作三个 command 捷径, 分别是:
(a)
Name: translate english to chinese and speak english
Command: seltr --ece
Accelerator: F1

(b)
Name: translate chinese to english and speak chinese
Command: seltr --cec
Accelerator: F2

(c)
Name: translate chinese to english and speak english
Command: seltr --cee
Accelerator: F3

(d)
Name: translate english to chinese and speak chinese
Command: seltr --ecc
Accelerator: F4



6. 酱就完成了。现在只需要用滑鼠 highlight/选你要翻译的文字范围, 按F1 或 F2 或 F3 或 F4, 下方就会 pop up 翻译结果, 并且发出相对的声音 :)

FAQ:
Q. 做么不用 stardict ?
A: 我最近有点 beh than stardict 的发音。不是不准确就是 quality 不好。 有时 pop up 太过 sensitive 了。而且最新版本的也无法使用 Google Translate, 我用 strace 检测发现它没有 follow HTTP 301 redirection 是主要原因。

Q: Where's the notification dialogue goes after multiple dialogue overlay ?
A: Super+m key to trigger messages menu tray,click gear icon to "Clear Messages" 就能清除全部累积的翻译 dialogues。

Q: 电脑没有 /usr/share/icons/hicolor/scalable/apps/im-google-talk.svg 这个 icon
A: 改成别的路径。不过看不见 error, 所以不重要。

Q: 优点/缺点
A: 优点是声音比较好听,只需要 highlight 一次,那个字就会在 buffer 里头, 此时不需要再 highlight, 再按 F1/F2/F3/F4 就能重复翻译/发音。而且支持多 lines /跨 line 字眼。也会把冗长的 link 翻译成 URL。缺点是需要网络,新的 dialogue 无法直接 ganti 旧的 dialogue。要先关掉旧的 dialogue 才能看到新的。 而且我的代码没有 handle cache 来减少流量。

Q: 做么你的代码没有 comments?
A: 有, 而且夸张多, 所以就干脆弄干净放在 blog。而且有些 tricks 解释太多给 google 看到就见光死了。当然要留后路。

Q:  做么在编辑(vi/gedit)着的 seltr 有时会自动关掉  ?
A:  因为你按 F[1-4] 会启动代码里头 kill 掉其它的 seltr process

Q: 做么有时翻译到有空格,有时特别字符, 如 ! 又会不见掉。
A: 你问 google 拉,鬼懂它的 bug。

无论如何, 语言之间的转换,比如英文翻译到中文,有时不见或多了空格都是正常的。在这里提醒一下,web browser 会先翻译 suggestion, 所以要再选 "Translate instead from"。


Q: 网上有条水用 iconv, awk, html2text 代码
A: 如果只比较关键的 curl, 我不但要考虑把结果 pass 去 mpg123(所以不能依赖 curl 的 --data-urlencode), 而且我用的 url 也不同(我知道有5种不同的 api, 实际数目当然不止)。那条水的 response 是包括大量的 html/js/css tag, 真的是名副其实的 web scraping, 很容易 broken。 最后,真的只依赖 html2text 就收工过年 ? 看下面的例子,google 那里是 source, notify-send 是我的, terminal 是那条水的, 仔细看 terminal 的 &quot; 和 &amp; bug。



Tips:
1. highlight 英文就要使用 F1/F4,highlight 中文就 F2/F3

2. 请先检查电脑有 xmessage, curl, xsel, mpg123, sed, fold, notify-send, pkill 这些 commands。

3. 我的平台 Fedora 21 gnome 3, 没在 Ubuntu 其它 platforms 测试。

4. 如果想中途 stop 掉很长的发声, 只需要选其它的很短的字体来翻译, 就可以ganti 掉了。当然别忘了得空清理下 Super+m 的 messages。

5. 发音没有用 https, 所以别手痒翻译密码哟 :p

代码:


#!/usr/bin/env bash
#Author: <limkokhole@facebook.com>
notify_icon='/usr/share/icons/hicolor/scalable/apps/im-google-talk.svg'

<<update_2015_april_20
1. xmessage use LANG=POSIX instead of LC_ALL
2. check curl return code and show xmessage for relevant error
3. use || and == instead of && and != for more intuitive
4. todo: avoid kill vi/gedit /usr/bin/seltr
update_2015_april_20

if [[ "$@" == "--ece" ]]; then
 text_sl='en'
 text_tl='zh-CN'
 ao_tl='en'
elif [[ "$@" == "--cec" ]]; then
 text_sl='zh-CN'
 text_tl='en'
 ao_tl='zh-CN'
elif [[ "$@" == "--cee" ]]; then
 text_sl='zh-CN'
 text_tl='en'
 ao_tl='en'
elif [[ "$@" == "--ecc" ]]; then
 text_sl='en'
 text_tl='zh-CN'
 ao_tl='zh-CN'
else
        echo -e 'Usage: seltr --[ece|cec|cee|ecc]
\n In which:
 ece means translate english to chinese but speak english
 cec means translate chinese to english but speak chinese
 cee means translate chinese to english but speak english
 ecc means translate english to chinese but speak chinese
'
        exit 1
fi

for cmd in "xsel" "mktemp" "cc" "lex" "curl" "mpg123" "sed" "fold" "notify-send" "pkill" "kill" "pgrep" "grep"; do
    command -v $cmd >/dev/null 2>&1 || {  LANG=POSIX; xmessage "Require $cmd but it's not installed.  Aborting." >&2; exit 1; }; :;
done

one_way_replace() {
  if [ ! -f /tmp/lex.yy ]; then
  #local dir=$(mktemp -d)
  ( #cd "$dir"
    echo 1 >> /tmp/lala
    { printf %s\\n "%option 8bit noyywrap nounput" "%%"
      printf '"%s" {fputs("%s", yyout);}\n' "${@//\"/\\\"}"
      printf %s\\n "%%" "int main(int argc, char** argv) { return yylex(); }"
    } | lex && cc lex.yy.c -o /tmp/lex.yy
  ) && /tmp/lex.yy
  else
      /tmp/lex.yy
  fi
  #rm -fR "$dir"
}

pre_mysed="$(xsel -o | sed ':a;N;$!ba;s/\xe2\x80\x90 *\n//g;s/\x2d *\n//g' | sed -E "s/[^ ]*http[s]?\:\/\/[^ ]*|[^ ]*www\.[^ ]*/URL/g;s/[^ ]*\.com[^ ]*/URL/g;s/[^ ]*\.net[^ ]*/URL/g;" )"

enc() { sed -E "s/\%/%25/g;s/\"/%22/g;s/'/%27/g;s/\./%2e/g;s/\,/%2c/g;s/\?/%3F/g;s/[\x5b]/%5b/g;s/[\x5d]/%5d/g;s/\!/%21/g;s/\;/%3b/g;s/\(/%28/g;s/\)/%29/g;s/\{/%7b/g;s/\}/%7d/g;s/\\\$/%24/g;s/\@/%40/g;s/\#/%23/g;s/\+/%2b/g;s/=/%3d/g;s/</%3c/g;s/>/%3e/g;s|/|%2f|g;s|\\\|%5c|g;s/_/%5f/g;s/~/%7e/g;s/:/%3a/g;s/&/%26/g;s/\^/%5e/g;s/\`/%60/g;s/\*/%2a/g;s/  */%20/g"; }

mysed="$(echo "$pre_mysed" | enc)"

translated="$(curl -d "q=$mysed" --post301 --post302 -sLk -A 'Mozilla/5.0' 'https://translate.googleapis.com/translate_a/t?anno=2&client=te&format=text&key&v=1.0&scid=&logld=v26&sl='"$text_sl"'&tl='"$text_tl"'&tc=2&mode=1')"

status=$?
case $status in
    0):;;
    6)LANG=POSIX; xmessage "Couldn't resolve host." >&2; exit 1;;
    7)LANG=POSIX; xmessage "Failed to connect to host." >&2; exit 1;;
    *)LANG=POSIX; xmessage "Curl error $status, exiting." >&2; exit $status;
esac

translated="$(echo "${translated:1:-1}" | one_way_replace '\\\\' '\\' '\\u0026' '&' '\\u003c' '<' '\\u003e' '>' | sed 's/\\\x5c\x74\x20/ /g;s/  */ /g')"

notif_txt="$(echo "$translated" | sed -E 's|\\|\\\\|g;s|\\"|"|g;s|\\n|\n|g;')"; notify-send -i "$notify_icon" -u critical " " "$notif_txt"

kill $(pgrep -f "/usr/bin/seltr" | grep -v ^$$\$) 2>/dev/null
pkill mpg123

if [[ "$@" == "--cee" ]] || [[ "$@" == "--ecc" ]]; then
 pre_fold="$translated"
else
 pre_fold="$pre_mysed"
fi

echo "$pre_fold" |fold -s -100 | enc | 
 while read line; do
  curl -sLk -A 'Mozilla/5.0' "http://translate.google.com/translate_tts?ie=UTF-8&q=${line}&tl=${ao_tl}&client=t&tk=1|0" | mpg123 -
 done




截图:


网页上使用


terminal 上使用


在 pdf 上使用, 跨界也没问题


留意那些冗长的 link 都会转换去 URL 字眼


用 F2, 中文去英文, speak 中文

No comments:

Post a Comment