Initial commit. Script and Readme.
commit
c3d275a714
|
@ -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.
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue