сам скрипт:
#!/usr/bin/env bash
# описание: перевод выделенного текста и отображение его через терминал foot в sway
# зависимости: sway foot wl-clipboard curl jq ttf-jetbrains-mono
NAME="${0##*/}"
DIR="/tmp/$NAME" && mkdir -p "$DIR"
FileIn="$DIR/in.txt"
FileOut="$DIR/out.txt"
COLUMNSxLINES=33x17
POSITION="center" # or "X Y"
FONT="JetBrainsMono:size=15"
# ColorBackground="000000"
# ColorForeground="826b58"
# ColorIn="\e[1;34m"
# ColorOut="\e[1;37m"
ColorIn="\e[1;34;40m"
ColorOut="\e[1;30;44m"
ColorError="\e[1;37;41m"
ColorReset="\e[0m"
LangDetect=true
LangIn=eng
LangOut=rus
PrimaryClipboard=true
# shellcheck source=/dev/null
touch "$DIR/conf" && source "$DIR/conf"
tput civis # убрать курсор
tput bold # текст жирным
if [[ ! $z ]]; then
export z=1
# sway: правило для отображения окна по его app_id
swaymsg for_window [app_id="$NAME"] floating enable
swaymsg for_window [app_id="$NAME"] sticky enable
swaymsg for_window [app_id="$NAME"] move position "$POSITION"
# закрыть открытое окно при повторном запуске программы
WindowID=$(swaymsg -t get_tree | jq --arg name "$NAME" --raw-output '..|select(.app_id == $name)? | .pid')
[[ -n "$WindowID" ]] && kill "$WindowID" && exit
rm -rf "$FileIn.old"
[[ $PrimaryClipboard == true ]] && BUFFER_TYPE="--primary"
exec foot --hold \
-t foot-direct \
--app-id="$NAME" \
--font="$FONT" \
--window-size-chars="$COLUMNSxLINES" \
--override=pad="10x10 center" \
--override="mouse.hide-when-typing=true" \
--override="colors.alpha=1" \
-e wl-paste "$BUFFER_TYPE" --type "text/plain;charset=utf-8" --watch "$NAME"
# --override="colors.background=$ColorBackground" \
# --override="colors.foreground=$ColorForeground" \
fi
# читаем буфер и пишем в файл
cat - > "$FileIn"
TextIn=$(cat "$FileIn")
[[ "$TextIn" == "" ]] && exit
[[ "$TextIn" =~ [[:alpha:]] ]] || exit
# если выделенный текст идентичен предыдущему то не переводить
cmp --quiet "$FileIn" "$FileIn.old" && exit
cp "$FileIn" "$FileIn.old"
# фильтры для входящего текста
sed -i -e '/./,$!d' -e :a -e '/^\n*$/{$d;N;ba' -e '}' "$FileIn" # удалить начальные и конечные пустые строки
awk 'NF{c=1} (c++)<3' "$FileIn" | sponge "$FileIn" # удалить больше одной пустой строки
awk 'NF>0{printf "%s ",$0;next} {printf "\n\n"}' "$FileIn" | sponge "$FileIn"
tr -s ' ' < "$FileIn" | sponge "$FileIn" # удаляем больше одного пробела
JsonOut="$(
curl -s 'https://api.reverso.net/translate/v1/translation' \
--compressed \
-X POST \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3' \
-H 'Accept-Encoding: gzip, deflate, br, zstd' \
-H 'Content-Type: application/json' \
-H 'X-Reverso-Origin: translation.web' \
-H 'Origin: https://www.reverso.net' \
-H 'DNT: 1' \
-H 'Sec-GPC: 1' \
-H 'Connection: keep-alive' \
-H 'Referer: https://www.reverso.net/' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Site: same-site' \
-H 'TE: trailers' \
--data-raw "$(
jq --null-input \
--arg languageDetection "$LangDetect" \
--arg from "$LangIn" \
--arg to "$LangOut" \
--arg input "$TextIn" \
'{"format":"text","from":$from,"to":$to,"input":$input,"options":{"sentenceSplitter":true,"origin":"translation.web","contextResults":false,"languageDetection":$languageDetection}}')"
)"
printf "%s" "$JsonOut" | jq --raw-output0 '.translation[]' > "$FileOut"
error=$(printf "%s" "$JsonOut" | jq --raw-output '.error')
if [[ "$error" != "null" ]]; then
echo -en "$ColorError"
StatusBarError="-- [err]"
dashes=""
while ((--COLUMNS - 8)) ; do dashes="${dashes}-" ; done
echo -n "$StatusBarError $dashes"
echo "$error"
echo -e "$ColorReset"
exit
fi
LangIn2=$LangIn
LangOut2=$LangOut
LangIn2=$(printf "%s" "$JsonOut" | jq --raw-output '.languageDetection.detectedLanguage')
reversed=$(printf "%s" "$JsonOut" | jq --raw-output '.languageDetection.isDirectionChanged')
[[ $reversed == "true" ]] && LangOut2=$LangIn || LangOut2=$LangOut
# вывод статус бара
StatusBar="-- [$LangIn2:$LangOut2(reverso)]"
StatusBarChars=$(echo -n "$StatusBar" |wc -m)
dashes=""
while ((--COLUMNS - StatusBarChars)) ; do dashes="${dashes}-" ;done
echo "$StatusBar $dashes"
# вывод переводимого и переведённого текста
echo -en "$ColorIn"
cat "$FileIn"
echo -e "\n$ColorOut"
cat "$FileOut"
echo -e "\n$ColorReset"
# запоминаем(до перезагрузки) размер консоли
echo "COLUMNSxLINES=${COLUMNS}x${LINES}" > "$DIR/conf"
# запоминаем(до перезагрузки) положения окна в sway
SwayBarInfo=$(swaymsg -t get_bar_config "$(swaymsg -t get_bar_config | jq -r '.[]')")
BAR_MODE=$(echo "$SwayBarInfo" | jq -r '.mode')
BAR_POSITION=$(echo "$SwayBarInfo" | jq -r '.position')
BAR_HEIGHT=$(echo "$SwayBarInfo" | jq -r '.bar_height')
[[ "$BAR_MODE" == "dock" && "$BAR_POSITION" == "top" ]] || BAR_HEIGHT=0
echo "POSITION=$(swaymsg -t get_tree | jq --arg name "$NAME" --arg bar_height "$BAR_HEIGHT" '.. | select(.app_id == $name )? | .rect | "\(.x) \(.y - ($bar_height|tonumber))"')" >> "$DIR/conf"
exit
у сябя повесил на одну из боковых кнопок мыши
~/.config/sway/
bindsym --whole-window BTN_SIDE exec lalang.sh
что он уже может
- перевод с помощью онлайн сервиса reverso.net (будут и другие)
- выбор буфера для перевода, параметр PrimaryClipboard (true - первичный буффер, когда достаточно просто выделить текст; false - стандартный буффер, тот же Ctrl-C который отправляет в буфер)
- запоминает(до перезагрузки) где было расположенно окно(sway) и его(foot) размер; в принципе можно будет сделать его более универсальным(без привязки к WM), но пока так.
- запускаеться в слушающем(выбранный буффер) режиме, то есть переводит по мере поступления; закрываеться так же как и запускаеться
если будут конструктивные предложение то добро пожаловать