Initial commit. Script and Readme.

master
l3n 2019-12-28 16:42:24 +01:00
commit c3d275a714
2 changed files with 299 additions and 0 deletions

64
README.org 100644
View File

@ -0,0 +1,64 @@
#+TITLE: Ponsapi-cli
#+DATE: Sat Dec 28 12:48:54 CET 2019
#+AUTHOR: Lio Novelli
#+LICENSE: GPLv3.0
#+VERSION: 0.9
* Introduction
There was no nice command line tool for translations to be found so I've
written my own. I was frustrated by opening a new tab in browser whenever I
wasn't able to remember a translation of a word. I use terminal a lot and
ponsapi-cli is one of the micro optimisations that at the end of the day
sum up (I hope).
I gave a lot of attention to pretty printing results, but
not so much care was spent to make the translation script fast. It is
something that will be addressed in the future versions but until then
all you get is "pretty printing".
* Usage
~trans [flags] <word>~
To get help use flag ~-h~.
* Dependencies
This script uses following tools:
- curl
- jq
- recode
- sed
* Installation
First you have to register at pons.com [[https://login.pons.com/login?return_to=https%253A%252F%252Fen.pons.com%252Fopen_dict%252Fpublic_api][api registration form]].
Once you get your API secret key, create a file named ponsapi.config in one
of these paths: ~$HOME, $HOME/.config or $HOME/.config/ponsapi-cli~.
Besides ~PONS_SECRET="<your-pons-secret>"~ line in your config file, you can
specify other default parameters there as well (~PONS_DICT~ for dictionary -
you can see a list of those by calling trans script with flag ~-o~ and
~PONS_LANG~ to specify in which language is the word you are looking
translation for).
Make your script executable and crate a symlink to it in your execution
path.
* How it works
Script creates a curl request to pons api and parses json response with jq.
Json response can have 2 different structures depending on a results found in
their dictionary. This complicates parsing a little bit but script has
two functions written for parsing each of those two different structures
and creates a unified json which is then used for pretty printing results.
You can see raw results with ~-r~ flag.
* Development
- [[https://en.pons.com/p/files/uploads/API/API_Documentation.pdf][Pons api documentation]]
I will rewrite this application in haskell once I found more time. Even before
that I'll implement some error handling.

235
trans.sh 100755
View File

@ -0,0 +1,235 @@
#!/bin/bash
## Pons api request wrapper for commandline
##
## 0. Read api secreet from configuration file.
## You can store default options in your config file.
## 1. Create curl request with parameters (word to translate, languages,
## fuzzy matching, number of results, language of results, return type)
## 2. Parse results with jq!
## 3. Pretty print results.
##
# PONS_LANG='sl' # # jq
PONS_URI="https://api.pons.com/v1/"
PONS_DICT='ensl' # curl
PONS_FUZZY=0 # curl
# PONS_LIMIT=1000
PONS_RAW=0 # bash
PONS_HELP=0 # bash
PONS_CONFIG='ponsapi.config' #name of the config file
PONS_HITS=0 #true if type of hit is translation and not entry
PONS_COUNT=0
# Check if arguments hold.
pons_error() {
echo "Error check!"
}
# Build a request query.
pons_request() {
PONS_QUERY="dictionary?l=$PONS_DICT&q=$PONS_WORD"
if [ "$PONS_FUZZY" == "1" ] ; then
PONS_QUERY="$PONS_QUERY&fm=$PONS_FUZZY"
fi
if [ ! -z "$PONS_LANG" ] ; then
PONS_QUERY="$PONS_QUERY&in=$PONS_LANG"
fi
if [ ! -z "$PONS_REF" ] ; then
PONS_QUERY="$PONS_QUERY&ref=true"
fi
#echo "$PONS_QUERY"
PONS_JSON=$( curl -s --header "X-Secret: $PONS_SECRET" $PONS_URI$PONS_QUERY )
# check if type of hit is translation
pons_hits
}
pons_hits() {
PONS_HITS=$( jq '.[] | .hits[] | .type' <<< $PONS_JSON | grep -c "translation" )
}
# Build a jq filter
pons_filter() {
PONS_FILTER=".[]"
# if [ ! -z $PONS_LANG ] ; then
# PONS_FILTER="$PONS_FILTER | select( .lang == \"$PONS_LANG\")"
# fi
if [ ! -z $PONS_RAW -a "$PONS_RAW" == "1" ] ; then
# echo "Raw json output."
PONS_FILTER="[$PONS_FILTER ]"
else
if [ $PONS_HITS -gt 0 ] ; then
PONS_FILTER="[$PONS_FILTER | {\"language_p\": .lang, \"hits_p\": [.hits[] | {\"headword_p\": \"\", \"wordclass_p\": \"\", \"arabs_p\": [ {\"header_p\": \"\", \"translations_p\": [ {\"source_p\": .source, \"target_p\": .target }] } ] }] }]"
else
PONS_FILTER="[$PONS_FILTER | {\"language_p\": .lang, \"hits_p\": [.hits[] | .roms | .[] | {\"headword_p\": .headword, \"wordclass_p\": .wordclass, \"arabs_p\": [ .arabs | .[] | {\"header_p\": .header, \"translations_p\": [.translations[] | {\"source_p\": .source, \"target_p\": .target }] } ] }] }]"
fi
fi
#echo $PONS_FILTER
}
pons_tags() {
source_t="$1"
#echo "$source_t\n"
source_t=$( recode html..latin1 <<< $source_t )
old_color="$2"
spn_color="$3"
source_t=$( sed -e "s/<span[^>]*>/$(tput setaf ${spn_color})/g" -e "s/<strong[^>]*>/$(tput bold)/g" -e "s/<acronym[^>]*>/$(tput dim)/g" -re "s/(<\/acronym>|<\/strong>|<\/span>)+/$(tput sgr0)$(tput setaf ${old_color})/g" <<< $source_t )
printf " $(tput setaf ${old_color})%b$(tput sgr0)" "$source_t"
}
# 1. get language as variable and loop through it
# 2. get headword, wordclass and loop through arabs
pons_parse() {
COLS=$(( $(tput cols) / 2 - 4 ))
PONS_COUNT=0
for lang_key in $(jq -r '.| keys | .[]' <<< $PONS_JSON); do
cur_lang=$(echo $PONS_JSON | jq ".[$lang_key] | .language_p" | sed -e 's/^"//' -e 's/"$//')
sub_lang=$(echo $PONS_JSON | jq ".[$lang_key]");
if [ ! -z $PONS_LIMIT ] && [ "$PONS_COUNT" -gt "$PONS_LIMIT" ] ; then
break
fi
for hit_key in $(jq ".hits_p | keys | .[]" <<< $sub_lang); do
if [ ! -z $PONS_LIMIT ] && [ "$PONS_COUNT" -gt "$PONS_LIMIT" ] ; then
break
fi
sub_hit=$(jq -r ".hits_p | .[$hit_key]" <<< $sub_lang);
hw=$(jq -r '"\(.headword_p)"' <<< $sub_hit ) #| sed -e 's/^"//' -e 's/"$//')
cw=$(jq -r '"\(.wordclass_p)"' <<< $sub_hit)
echo -e "\033[1;36m$hw\033[0m\t$cur_lang\t\033[0;34m$cw\033[0m"
PONS_COUNT=$((PONS_COUNT + 1))
for ara_key in $(jq ".arabs_p | keys | .[]" <<< $sub_hit); do
sub_ara=$(jq ".arabs_p | .[$ara_key]" <<< $sub_hit)
hd=$(jq -r " .header_p" <<< $sub_ara | sed 's/<span.*>\(.*\)<\/span>/\\033\[0;34m\1\\033\[0;32m/g' | sed 's/<strong.*>\(.*\)<\/strong>/\\033\[1;32m\1\\033\[0;32m/g')
if [ ! -z "$hd" ] ; then
echo -e " $hd"
fi
for tra_key in $(jq -c ".translations_p | keys | .[] " <<< $sub_ara); do
sub_tra=$(jq ".translations_p | .[$tra_key] " <<< $sub_ara)
source_p=$(jq -r ".source_p " <<< $sub_tra)
target_p=$(jq -r ".target_p " <<< $sub_tra)
source_p=$( pons_tags "$source_p" '2' '3' )
target_p=$( pons_tags "$target_p" '5' '6' )
printf "$(tput sc) %b$(tput rc)$(tput cuf $COLS) %b\n" "$source_p" "$target_p"
done
done
done
done
}
# Pons api has this insufficiency that it can return json in different form
# Type of hit is translation.
pons_parse_translate() {
COLS=$(( $(tput cols) / 2 - 4 ))
for lang_key in $(jq -r '.| keys | .[]' <<< $PONS_JSON); do
cur_lang=$(echo $PONS_JSON | jq ".[$lang_key] | .language_p" | sed -e 's/^"//' -e 's/"$//')
sub_lang=$(echo $PONS_JSON | jq ".[$lang_key]");
if [ ! -z $PONS_LIMIT ] && [ "$PONS_COUNT" -gt "$PONS_LIMIT" ] ; then
break
fi
for hit_key in $(jq ".hits_p | keys | .[]" <<< $sub_lang); do
sub_hit=$(jq -r ".hits_p | .[$hit_key]" <<< $sub_lang);
hw=$(jq -r '"\(.headword_p)"' <<< $sub_hit ) #| sed -e 's/^"//' -e 's/"$//')
PONS_COUNT=$((PONS_COUNT + 1))
for ara_key in $(jq ".arabs_p | keys | .[]" <<< $sub_hit); do
sub_ara=$(jq ".arabs_p | .[$ara_key]" <<< $sub_hit)
for tra_key in $(jq -c ".translations_p | keys | .[] " <<< $sub_ara); do
if [ ! -z $PONS_LIMIT ] && [ "$PONS_COUNT" -gt "$PONS_LIMIT" ] ; then
break
fi
sub_tra=$(jq ".translations_p | .[$tra_key] " <<< $sub_ara)
source_p=$(jq -r ".source_p " <<< $sub_tra)
target_p=$(jq -r ".target_p " <<< $sub_tra)
source_p=$( pons_tags "$source_p" '2' '3' )
target_p=$( pons_tags "$target_p" '5' '6' )
printf "$(tput sc)%s %b$(tput rc)$(tput cuf $COLS) %b\n" "$cur_lang" "$source_p" "$target_p"
done
done
done
done
}
pons_config() {
#echo "Check if file exists: .ponsapi.config in home dir and ponsapi.config in home/.config dir."
if [ -f "$HOME/.$PONS_CONFIG" ] ; then
source $HOME/.$PONS_CONFIG
elif [ -f "$HOME/.config/$PONS_CONFIG" ] ; then
source $HOME/.config/$PONS_CONFIG
elif [ -f "$HOME/.config/ponsapi-cli/$PONS_CONFIG" ] ; then
source $HOME/.config/ponsapi-cli/$PONS_CONFIG
else
echo "ERROR: Config file not found!"
fi
}
pons_help () {
echo "This is a pons api wrapper for command line."
echo -e "Basic usage:\n\tpons -[ldfnrthoc] word."
echo -e "\nOptions:"
echo -e "\t-h :: Help; This help."
echo -e "\t-o :: Options; List of language options."
echo -e "\t-l [lang] :: Language; Specify language of the word (sl, en, de, hu). Results will be of another language."
echo -e "\t-d [dict] :: Dictonary; Select language pair to translate in (ensl, desl, husl ...). For full list call with [-o] flag."
echo -e "\t-f :: Fuzzy matching; Enable fuzzy matching results."
echo -e "\t-e :: Enable REference ; Not quite sure what this does yet."
echo -e "\t-n [num] :: Number; Limits the number of results."
echo -e "\t-r :: Raw; Return raw result from pons."
# echo -e "\t-t [type] :: Type; Return results in this type, txt by default (json, csv)." # long term plan
echo -e "\t-c :: Count; Count number of results."
}
pons_options () {
echo -e "Supported languages are: de, el, en, es, fr, it, pl, pt, ru, sl, th, zh;\n"
if [ ! -z $PONS_LANG ] ; then
PONS_QUERY="dictionaries?language=$PONS_LANG"
else
PONS_QUERY="dictionaries?language=sl"
fi
echo "List of dicitionaries:"
curl -s -k $PONS_URI$PONS_QUERY | jq 'map({(.key): .simple_label}) | add'
}
# FLAGS SETUP
while getopts "fl:d:n:t:rhoec" option
do
case "${option}"
in
l) PONS_LANG=${OPTARG};;
d) PONS_DICT=${OPTARG};;
f) PONS_FUZZY=1;;
n) PONS_LIMIT=${OPTARG};;
t) PONS_TYPE=${OPTARG};;
r) PONS_RAW=1;;
h) PONS_HELP=1;;
o) PONS_HELP=2;;
c) PONS_COUNT=1;;
e) PONS_REF=1;;
esac
done
shift $((OPTIND -1))
PONS_WORD=$1
if [ "$PONS_HELP" == "1" ] ; then
pons_help
#return 0;
elif [ "$PONS_HELP" == "2" ] ; then
pons_options
elif [ "$PONS_RAW" == "1" ] ; then
pons_config
pons_request
pons_filter
PONS_JSON=$(echo $PONS_JSON | jq "$PONS_FILTER")
echo -e $PONS_JSON | jq .
else
pons_config
pons_request
pons_filter
PONS_JSON=$(echo $PONS_JSON | jq "$PONS_FILTER")
#echo -e $PONS_JSON | jq .
# pons_parse
if [ "$PONS_HITS" -gt 0 ] ; then
pons_parse_translate
else
pons_parse
fi
fi