Repository: AlexanderWillner/deepl-alfred-workflow2
Branch: master
Commit: cf0cbcd907b2
Files: 11
Total size: 57.7 KB
Directory structure:
gitextract_q2yra2a5/
├── .gitignore
├── .mdlrc
├── Deepl-Translate.alfred5workflow
├── Deepl-Translate.alfredworkflow
├── Makefile
├── README.md
├── deepl-write.sh
├── deepl.bats
├── deepl.sh
├── info4.plist
└── info5.plist
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
info.plist
================================================
FILE: .mdlrc
================================================
rules "~MD013"
================================================
FILE: Makefile
================================================
SHELL=bash
help:
@echo "Some available commands:"
@echo " * workflow : create workflow"
@echo " * bats : run dynamic tests"
@echo " * test : test shell scripts"
@echo " * style : style shell scripts"
@echo " * harden : harden shell scripts"
@echo " * feedback : create a GitHub issue"
workflow: dyntest workflow4 workflow5
workflow4:
@rm -f Deepl-Translate.alfredworkflow
@cp info4.plist info.plist
@zip Deepl-Translate.alfredworkflow icon.png info.plist deepl.sh
@rm info.plist
workflow5:
@rm -f Deepl-Translate.alfred5workflow
@cp info5.plist info.plist
@zip Deepl-Translate.alfred5workflow icon.png info.plist deepl.sh
@rm info.plist
feedback:
@open https://github.com/alexanderwillner/deepl-alfred-workflow2/issues
bats:
@echo "Running dynamic tests..."
@type bats >/dev/null 2>&1 || (echo "Run 'brew install bats-core' first." >&2 ; exit 1)
@bats deepl.bats
dyntest:
@DEEPL_KEY= ./deepl.sh -l EN "Guten Morgen." 2>&1|grep "Good morning"
@./deepl.sh -l EN "Guten Morgen." 2>&1|grep "Good morning"
test:
@echo "Running first round of shell checks..."
@type shellcheck >/dev/null 2>&1 || (echo "Run 'brew install shellcheck' first." >&2 ; exit 1)
@shellcheck -x *.sh
@echo "Running second round of shell checks..."
@type shellharden >/dev/null 2>&1 || (echo "Run 'brew install shellharden' first." >&2 ; exit 1)
@shellharden --check deepl.sh
harden:
@shellharden --replace deepl.sh
style:
@type shfmt >/dev/null 2>&1 || (echo "Run 'brew install shfmt' first." >&2 ; exit 1)
@shfmt -i 2 -w -s *.sh
.PHONY: workflow feedback bats test harden style
================================================
FILE: README.md
================================================
# Alfred DeepL Translation Workflow
[](https://www.codacy.com/gh/AlexanderWillner/deepl-alfred-workflow2/dashboard?utm_source=github.com&utm_medium=referral&utm_content=AlexanderWillner/deepl-alfred-workflow2&utm_campaign=Badge_Grade) [](https://github.com/AlexanderWillner/deepl-alfred-workflow2/releases)
## Usage
To activate this workflow use the default keyword ```dl```, enter the passage you wanna get translated and end the input with ```.``` (not needed if you've an API key). The source language will be inferred automatically and the target language can be configured.

After 1-2 seconds you get the translation. This is just an example.

Press ```↩``` to copy the result or ```⌘ + ↩``` to show result as big screen overlay.
You can also translate any selected text within macOS by pressing ```⌃ + ⌥ + ⌘ + d```.
Other languages are supported as well:

To quickly change the target language, you can use the ```dll``` keyword:

## Caveats
Please note that the DeepL API is designed to translate up to 600 characters per minute and per customer only. This fact and generally some longer sentences might result in the message ```Error: Too many requests.``` (see #5).
However, you can also get a (free or paid) [```API key```](https://www.deepl.com/pro-api) and configure it in the settings (see screenshot below).
## Installing the Workflow
1. Simply download the [last release](https://github.com/AlexanderWillner/deepl-alfred-workflow2/releases)
2. Unzip the file on your computer
3. Install `Deepl-Translate.alfredworkflow` by double-clicking the workflow file and clicking on "Import".
You'll now see the workflow listed in the left sidebar of your Workflows preferences pane.
Once imported, you may want to take a quick look at the workflow settings and setup what keyword you want to use. Further, you can change the target language in the settings as shown in this screenshot:

## Command Line
```shell
$ # DEEPL_TARGET="FR"
$ ./deepl.sh -l DE "This is just an example."
{
"items": [
{
"uid": null,
"arg": "Dies ist nur ein Beispiel.",
"valid": "yes",
"autocomplete": "autocomplete",
"title": "Dies ist nur ein Beispiel."
},
{
"uid": null,
"arg": "Das ist nur ein Beispiel.",
"valid": "yes",
"autocomplete": "autocomplete",
"title": "Das ist nur ein Beispiel."
},
{
"uid": null,
"arg": "Dies ist nur ein Beispiel dafür.",
"valid": "yes",
"autocomplete": "autocomplete",
"title": "Dies ist nur ein Beispiel dafür."
},
{
"uid": null,
"arg": "Dies ist nur ein exemplarisches Beispiel.",
"valid": "yes",
"autocomplete": "autocomplete",
"title": "Dies ist nur ein exemplarisches Beispiel."
}
]
}
```
## Important configuration variables
* `DEEPL_KEY`: the DeepL API key
* `DEEPL_PRO`: in case you have a professional DeepL account
* `DEEPL_POSTFIX`: the character to the input should end with to mitigate #5
* `DEEPL_TARGET`: the target language of the default `dl` keyword
## Builing the workflow
To create a modified version of the workflow, edit the files and run ```make workflow``` to create an updated workflow.
## Disclaimer
DeepL is a product from DeepL GmbH. More info: [deepl.com/publisher.html](https://www.deepl.com/publisher.html)
This package has been heavily inspired by [m9dfukc's DeepL Alfred Workflow](https://github.com/m9dfukc/deepl-alfred-workflow).
================================================
FILE: deepl-write.sh
================================================
#!/bin/bash
# setup #######################################################################
#set -o errexit -o pipefail -o noclobber -o nounset
LANGUAGE="${DEEPL_TARGET:-EN}"
LANGUAGE_SOURCE="${DEEPL_SOURCE:-auto}"
LANGUAGE_PREFERRED="${DEEPL_PREFERRED:-[\"DE\",\"EN\"]}"
KEY="${DEEPL_KEY:-}"
PRO="${DEEPL_PRO:-}"
# see https://developers.deepl.com/docs/api-reference/translate/openapi-spec-for-text-translation
FORMALITY="${DEEPL_FORMALITY:-prefer_less}"
POSTFIX="${DEEPL_POSTFIX:-.}"
VERSION="2.1.0"
PATH="$PATH:/usr/local/bin/"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
###############################################################################
# helper functions ############################################################
function printJson() {
echo '{"items": [{"uid": null,"arg": "'"$1"'","valid": "yes","autocomplete": "autocomplete","title": "'"$1"'"}]}'
}
###############################################################################
# parameters ##################################################################
POSITIONAL=()
while [[ $# -gt 0 ]]; do
key="$1"
case "$key" in
-l | --lang)
LANGUAGE="$2"
shift # past argument
shift # past value
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]:-}" # restore positional parameters
###############################################################################
# help ########################################################################
if [ -z "$1" ]; then
echo "Home made DeepL CLI (${VERSION}; https://github.com/AlexanderWillner/deepl-alfred-workflow2)"
echo ""
echo "SYNTAX : $0 [-l language] <query>" >&2
echo "Example: $0 -l EN \"This is just an example.\""
echo ""
exit 1
fi
###############################################################################
# process query ###############################################################
query="$1"
# shellcheck disable=SC2001
query="$(echo "$query" | sed 's/\"/\\\"/g')"
# shellcheck disable=SC2001
query="$(echo "$query" | sed "s/'/\\\'/g")"
query="$(echo "$query" | iconv -f utf-8-mac -t utf-8 | xargs)"
if [[ $KEY = "" ]] && [[ $query != *"$POSTFIX" ]]; then
printJson "End query with $POSTFIX"
exit 2
fi
###############################################################################
# prepare query ###############################################################
# shellcheck disable=SC2001
query="$(echo "$query" | sed "s/\\$POSTFIX$//")"
if [ "$KEY" = "" ]; then
FORM_PARAM=''
else
FORM_PARAM='"formality": "'"$FORMALITY"'", '
fi
data='{"jsonrpc":"2.0","method": "LMT_handle_jobs","params":{"jobs":[{"kind":"default","sentences":[{"text":"'"$query"'","id":1,"prefix":""}],"raw_en_context_before":[],"raw_en_context_after":[],"preferred_num_beams":1,"write_variant_requests":["main","variants"],"style_variant":"business"}],"lang":{"target_lang":"'"${LANGUAGE:-EN}"'","preference":{"weight":{},"default":"default"},"source_lang_computed":"'"${LANGUAGE:-EN}"'"},"priority":1,"commonJobParams":{"quality":"normal","regionalVariant":"en-US","mode":"write","browserType":1,"textType":"plaintext","style_variant":"business"},"timestamp":1739745925254},"id":20270141}'
HEADER=(
--compressed
-H 'authority: write-free.www.deepl.com'
-H 'Origin: https://write-free.www.deepl.com'
-H 'Referer: https://www.deepl.com/'
-H 'Accept: */*'
-H 'Content-Type: application/json'
-H 'Accept-Language: en-us'
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Safari/605.1.15'
)
###############################################################################
# query #######################################################################
if [ -n "$KEY" ]; then
if [ "$PRO" = "1" ]; then
url="https://api.deepl.com/v2/translate"
else
url="https://api-free.deepl.com/v2/translate"
fi
if [ ! -z "$DEEPL_HOST" ]; then
url="$DEEPL_HOST/v2/translate"
fi
echo >&2 "curl -s -X POST '$url' -H 'Authorization: DeepL-Auth-Key $KEY' --data-urlencode 'text=$query' -d 'formality=$FORMALITY' -d 'target_lang=${LANGUAGE:-EN}'"
result=$(curl -s -X POST "$url" -H "Authorization: DeepL-Auth-Key $KEY" --data-urlencode "text=$query" -d "formality=$FORMALITY" -d "target_lang=${LANGUAGE:-EN}")
ret=$?
if [[ "x$ret" != "x0" ]] || [[ "$result" == "" ]]; then
echo >&2 "$ret: $result"
http_code=$(curl -s -X POST "$url" -H "Authorization: DeepL-Auth-Key $KEY" --data-urlencode "text=$query" -d "target_lang=${LANGUAGE:-EN}" -d "formality=$FORMALITY" -w %{http_code} -o /dev/null)
if [[ $http_code -eq 403 ]]; then
printJson "Error: Invalid API key"
exit 3
fi
if [[ $ret -eq 6 ]]; then
printJson "Error: DNS resolution failed - no Internet connection?"
exit 4
fi
printJson "Error Code $ret - HTTP Code $http_code"
exit 5
fi
osascript -l JavaScript -e 'function run(argv) {
const translations = JSON.parse(argv[0])["translations"].map(item => ({
title: item["text"],
arg: item["text"]
}))
return JSON.stringify({ items: translations }, null, 2)
}' "$result" || echo >&2 "ERROR w/ key: result '$result', query '$query'"
else
echo >&2 "curl -s 'https://write-free.www.deepl.com/jsonrpc' '${HEADER[@]}' --data-binary $'$data'"
result=$(curl -s 'https://write-free.www.deepl.com/jsonrpc' "${HEADER[@]}" --data-binary $"$data")
ret=$?
if [[ "x$ret" != "x0" ]] || [[ "$result" == "" ]]; then
echo >&2 "$ret: $result"
http_code=$(curl -s 'https://write-free.www.deepl.com/jsonrpc' "${HEADER[@]}" --data-binary $"$data" -w %{http_code} -o /dev/null)
if [[ $ret -eq 6 ]]; then
printJson "Error: DNS resolution failed - no Internet connection?"
exit 6
fi
printJson "Error Code $ret - HTTP Code $http_code"
exit 7
fi
if [[ $result == *'"error":{"code":'* ]]; then
message="$(osascript -l JavaScript -e 'function run(argv) { return JSON.parse(argv[0])["error"]["message"] }')"
printJson "Error: $message"
exit 8
else
osascript -l JavaScript -e 'function run(argv) {
const translations = JSON.parse(argv[0])["result"]["translations"][0]["beams"].map(item => ({
title: item["sentences"],
arg: item["sentences"]
}))
return JSON.stringify({ items: translations }, null, 2)
}' "$result" || echo >&2 "ERROR w/o key: result '$result', query '$query'"
fi
fi
###############################################################################
================================================
FILE: deepl.bats
================================================
#!/usr/bin/env bats
teardown() {
sleep 1
}
@test "No parameters" {
run ./deepl.sh
[[ "$status" -eq 1 ]]
}
@test "Missing dot" {
run ./deepl.sh "Vogel"
[[ "$status" -eq 0 ]]
[[ "$output" == *"End query with a dot"* ]]
}
@test "Single Word" {
run ./deepl.sh -l EN "Vogel."
[[ "$status" -eq 0 ]]
[[ "$output" == *"bird"* ]]
}
@test "Trailing spaces" {
run ./deepl.sh " Vogel. "
[[ "$status" -eq 0 ]]
[[ "$output" == *"bird"* ]]
}
@test "Sentence" {
run ./deepl.sh -l DE "Translate from any language."
[[ "$status" -eq 0 ]]
[[ "$output" == *"aus jeder Sprache"* ]]
}
@test "Umlaut source" {
run ./deepl.sh -l EN "Erdöl."
[[ "$status" -eq 0 ]]
[[ "$output" == *"oil"* ]]
}
@test "Umlaut destination" {
run ./deepl.sh -l DE "Oil."
[[ "$status" -eq 0 ]]
[[ "$output" == *"öl"* ]]
}
@test "Quote source" {
run ./deepl.sh -l DE "I'll."
[[ "$status" -eq 0 ]]
[[ "$output" == *"Ich werde"* ]]
}
@test "Quote destination" {
run ./deepl.sh -l EN "Ich werde."
[[ "$status" -eq 0 ]]
[[ "$output" == *"I'll be"* ]]
}
@test "Double quote source" {
run ./deepl.sh -l EN '"Apfel".'
[[ "$status" -eq 0 ]]
[[ "$output" == *'\"Apple\"'* ]]
}
#todo: fixme #6
#@test "Spanisch" {
# run ./deepl.sh -l EN "El tiempo es una ilusión."
# [[ "$status" -eq 0 ]]
# [[ "$output" == *'\"time\"'* ]]
#}
#todo: fixme #1
#@test "Long sentences" {
# run ./deepl.sh -l DE "He felt that his whole life was some kind of dream and he sometimes wondered whose it was and whether they were enjoying it."
# [[ "$status" -eq 0 ]]
# [[ "$output" == *'\"Leben\"'* ]]
#}
#todo: fixme #1
#@test "Multi sentences" {
# run ./deepl.sh -l DE "This planet has - or rather had - a problem, which was this: most of the people living on it were unhappy for pretty much of the time. Many solutions were suggested for this problem, but most of these were largely concerned with the movement of small green pieces of paper, which was odd because on the whole it wasn't the small green pieces of paper that were unhappy."
# [[ "$status" -eq 0 ]]
# [[ "$output" == *'\"unglücklich\"'* ]]
#}
================================================
FILE: deepl.sh
================================================
#!/bin/bash
# setup #######################################################################
#set -o errexit -o pipefail -o noclobber -o nounset
LANGUAGE="${DEEPL_TARGET:-EN}"
LANGUAGE_SOURCE="${DEEPL_SOURCE:-auto}"
LANGUAGE_PREFERRED="${DEEPL_PREFERRED:-[\"DE\",\"EN\"]}"
KEY="${DEEPL_KEY:-}"
PRO="${DEEPL_PRO:-}"
# see https://developers.deepl.com/docs/api-reference/translate/openapi-spec-for-text-translation
FORMALITY="${DEEPL_FORMALITY:-prefer_less}"
POSTFIX="${DEEPL_POSTFIX:-.}"
VERSION="2.1.0"
PATH="$PATH:/usr/local/bin/"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
###############################################################################
# helper functions ############################################################
function printJson() {
echo '{"items": [{"uid": null,"arg": "'"$1"'","valid": "yes","autocomplete": "autocomplete","title": "'"$1"'"}]}'
}
###############################################################################
# parameters ##################################################################
POSITIONAL=()
while [[ $# -gt 0 ]]; do
key="$1"
case "$key" in
-l | --lang)
LANGUAGE="$2"
shift # past argument
shift # past value
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]:-}" # restore positional parameters
###############################################################################
# help ########################################################################
if [ -z "$1" ]; then
echo "Home made DeepL CLI (${VERSION}; https://github.com/AlexanderWillner/deepl-alfred-workflow2)"
echo ""
echo "SYNTAX : $0 [-l language] <query>" >&2
echo "Example: $0 -l DE \"This is just an example.\""
echo ""
exit 1
fi
###############################################################################
# process query ###############################################################
query="$1"
# shellcheck disable=SC2001
query="$(echo "$query" | sed 's/\"/\\\"/g')"
# shellcheck disable=SC2001
query="$(echo "$query" | sed "s/'/\\\'/g")"
query="$(echo "$query" | iconv -f utf-8-mac -t utf-8 | xargs)"
if [[ $KEY = "" ]] && [[ $query != *"$POSTFIX" ]]; then
printJson "End query with $POSTFIX"
exit 2
fi
###############################################################################
# prepare query ###############################################################
# shellcheck disable=SC2001
query="$(echo "$query" | sed "s/\\$POSTFIX$//")"
if [ "$KEY" = "" ]; then
FORM_PARAM=''
else
FORM_PARAM='"formality": "'"$FORMALITY"'", '
fi
data='{"jsonrpc":"2.0","method": "LMT_handle_jobs","params":{"commonJobParams": {'$FORM_PARAM'"browserType": 1, "mode": "translate", "textType": "plaintext"}, "jobs":[{"kind":"default","raw_en_sentence":"'"$query"'","preferred_num_beams":4,"raw_en_context_before":[],"raw_en_context_after":[],"quality":"fast"}],"lang":{"user_preferred_langs":'"${LANGUAGE_PREFERRED}"',"source_lang_user_selected":"'"${LANGUAGE_SOURCE}"'","target_lang":"'"${LANGUAGE:-EN}"'"},"priority":1,"timestamp":1557063997314},"id":79120002}'
HEADER=(
--compressed
-H 'authority: www2.deepl.com'
-H 'Origin: https://www.deepl.com'
-H 'Referer: https://www.deepl.com/translator'
-H 'Accept: */*'
-H 'Content-Type: application/json'
-H 'Accept-Language: en-us'
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Safari/605.1.15'
)
###############################################################################
# query #######################################################################
if [ -n "$KEY" ]; then
if [ "$PRO" = "1" ]; then
url="https://api.deepl.com/v2/translate"
else
url="https://api-free.deepl.com/v2/translate"
fi
if [ ! -z "$DEEPL_HOST" ]; then
url="$DEEPL_HOST/v2/translate"
fi
echo >&2 "curl -s -X POST '$url' -H 'Authorization: DeepL-Auth-Key $KEY' --data-urlencode 'text=$query' -d 'formality=$FORMALITY' -d 'target_lang=${LANGUAGE:-EN}'"
result=$(curl -s -X POST "$url" -H "Authorization: DeepL-Auth-Key $KEY" --data-urlencode "text=$query" -d "formality=$FORMALITY" -d "target_lang=${LANGUAGE:-EN}")
ret=$?
if [[ "x$ret" != "x0" ]] || [[ "$result" == "" ]]; then
echo >&2 "$ret: $result"
http_code=$(curl -s -X POST "$url" -H "Authorization: DeepL-Auth-Key $KEY" --data-urlencode "text=$query" -d "target_lang=${LANGUAGE:-EN}" -d "formality=$FORMALITY" -w %{http_code} -o /dev/null)
if [[ $http_code -eq 403 ]]; then
printJson "Error: Invalid API key"
exit 3
fi
if [[ $ret -eq 6 ]]; then
printJson "Error: DNS resolution failed - no Internet connection?"
exit 4
fi
printJson "Error Code $ret - HTTP Code $http_code"
exit 5
fi
osascript -l JavaScript -e 'function run(argv) {
try {
const parsed = JSON.parse(argv[0]);
if (!parsed || !parsed.translations) {
throw new Error("Invalid response structure");
}
const translations = parsed.translations.map(item => ({
title: item["text"],
arg: item["text"]
}));
return JSON.stringify({ items: translations }, null, 2);
} catch(e) {
return JSON.stringify({
items: [{
title: "Error parsing response: " + e.message,
arg: "error",
valid: false
}]
}, null, 2);
}
}' "$result" || {
echo >&2 "ERROR w/ key: result '$result', query '$query'"
printJson "Error: Failed to parse translation response"
exit 10
}
else
echo >&2 "curl -s 'https://www2.deepl.com/jsonrpc' '${HEADER[@]}' --data-binary $'$data'"
result=$(curl -s 'https://www2.deepl.com/jsonrpc' "${HEADER[@]}" --data-binary $"$data")
ret=$?
echo >&2 "DEBUG: curl exit code: $ret"
echo >&2 "DEBUG: result length: ${#result}"
echo >&2 "DEBUG: result first 200 chars: ${result:0:200}"
if [[ "x$ret" != "x0" ]] || [[ "$result" == "" ]]; then
echo >&2 "$ret: $result"
http_code=$(curl -s 'https://www2.deepl.com/jsonrpc' "${HEADER[@]}" --data-binary $"$data" -w %{http_code} -o /dev/null)
if [[ $ret -eq 6 ]]; then
printJson "Error: DNS resolution failed - no Internet connection?"
exit 6
fi
printJson "Error Code $ret - HTTP Code $http_code"
exit 7
fi
# Validate JSON before parsing
if ! echo "$result" | python3 -m json.tool > /dev/null 2>&1; then
echo >&2 "ERROR: Invalid JSON response: $result"
printJson "Error: Invalid JSON response from DeepL"
exit 8
fi
if [[ $result == *'"error":{"code":'* ]]; then
message="$(osascript -l JavaScript -e 'function run(argv) {
try {
return JSON.parse(argv[0])["error"]["message"]
} catch(e) {
return "JSON parse error: " + e.message
}
}' "$result")"
printJson "Error: $message"
exit 8
else
osascript -l JavaScript -e 'function run(argv) {
try {
const parsed = JSON.parse(argv[0]);
if (!parsed || !parsed.result || !parsed.result.translations || !parsed.result.translations[0] || !parsed.result.translations[0].beams) {
throw new Error("Invalid response structure");
}
const translations = parsed.result.translations[0].beams.map(item => ({
title: item["postprocessed_sentence"],
arg: item["postprocessed_sentence"]
}));
return JSON.stringify({ items: translations }, null, 2);
} catch(e) {
return JSON.stringify({
items: [{
title: "Error parsing response: " + e.message,
arg: "error",
valid: false
}]
}, null, 2);
}
}' "$result" || {
echo >&2 "ERROR w/o key: result '$result', query '$query'"
printJson "Error: Failed to parse translation response"
exit 9
}
fi
fi
###############################################################################
================================================
FILE: info4.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>bundleid</key>
<string>ws.willner.alex.alfred.deepl</string>
<key>category</key>
<string>Productivity</string>
<key>connections</key>
<dict>
<key>5233F7C8-9221-45A4-BDE0-DE53175096E1</key>
<array>
<dict>
<key>destinationuid</key>
<string>A222FB0A-D703-4C45-9CB0-4EDEA3399BEF</string>
<key>modifiers</key>
<integer>1048576</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
<dict>
<key>destinationuid</key>
<string>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</key>
<array>
<dict>
<key>destinationuid</key>
<string>D7D47F17-02DB-4A30-8F14-C03CBD051929</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>84FE56AF-330C-4BB8-85E6-34859AAB73A7</key>
<array>
<dict>
<key>destinationuid</key>
<string>91D16594-908E-4665-A005-0B715D96E5C2</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>91D16594-908E-4665-A005-0B715D96E5C2</key>
<array>
<dict>
<key>destinationuid</key>
<string>A222FB0A-D703-4C45-9CB0-4EDEA3399BEF</string>
<key>modifiers</key>
<integer>1048576</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
<dict>
<key>destinationuid</key>
<string>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>AD7C89C1-0978-4469-B62F-245E595DE9BD</key>
<array>
<dict>
<key>destinationuid</key>
<string>91D16594-908E-4665-A005-0B715D96E5C2</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>CAA19D9E-04B6-4AD4-A8DC-0B683215DD14</key>
<array>
<dict>
<key>destinationuid</key>
<string>5233F7C8-9221-45A4-BDE0-DE53175096E1</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
</dict>
<key>createdby</key>
<string>Alexander Willner</string>
<key>description</key>
<string>Translation using deepl.com</string>
<key>disabled</key>
<false/>
<key>name</key>
<string>Deepl-Translate</string>
<key>objects</key>
<array>
<dict>
<key>config</key>
<dict>
<key>alignment</key>
<integer>0</integer>
<key>backgroundcolor</key>
<string></string>
<key>fadespeed</key>
<integer>0</integer>
<key>fillmode</key>
<integer>0</integer>
<key>font</key>
<string></string>
<key>ignoredynamicplaceholders</key>
<false/>
<key>largetypetext</key>
<string>{query}</string>
<key>textcolor</key>
<string></string>
<key>wrapat</key>
<integer>50</integer>
</dict>
<key>type</key>
<string>alfred.workflow.output.largetype</string>
<key>uid</key>
<string>A222FB0A-D703-4C45-9CB0-4EDEA3399BEF</string>
<key>version</key>
<integer>3</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>alfredfiltersresults</key>
<false/>
<key>alfredfiltersresultsmatchmode</key>
<integer>0</integer>
<key>argumenttreatemptyqueryasnil</key>
<false/>
<key>argumenttrimmode</key>
<integer>0</integer>
<key>argumenttype</key>
<integer>0</integer>
<key>escaping</key>
<integer>102</integer>
<key>keyword</key>
<string>dl-to-en</string>
<key>queuedelaycustom</key>
<integer>3</integer>
<key>queuedelayimmediatelyinitially</key>
<false/>
<key>queuedelaymode</key>
<integer>1</integer>
<key>queuemode</key>
<integer>1</integer>
<key>runningsubtext</key>
<string>Translating to language "EN" using DeepL ...</string>
<key>script</key>
<string>./deepl.sh -l "EN" "{query}"
</string>
<key>scriptargtype</key>
<integer>0</integer>
<key>scriptfile</key>
<string>deepl.sh</string>
<key>subtext</key>
<string>Translate to language "EN" using DeepL</string>
<key>title</key>
<string>DeepL Dictionary</string>
<key>type</key>
<integer>0</integer>
<key>withspace</key>
<true/>
</dict>
<key>type</key>
<string>alfred.workflow.input.scriptfilter</string>
<key>uid</key>
<string>5233F7C8-9221-45A4-BDE0-DE53175096E1</string>
<key>version</key>
<integer>3</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>action</key>
<integer>0</integer>
<key>argument</key>
<integer>1</integer>
<key>focusedappvariable</key>
<false/>
<key>focusedappvariablename</key>
<string></string>
<key>hotkey</key>
<integer>14</integer>
<key>hotmod</key>
<integer>1835008</integer>
<key>hotstring</key>
<string>E</string>
<key>leftcursor</key>
<false/>
<key>modsmode</key>
<integer>0</integer>
<key>relatedAppsMode</key>
<integer>0</integer>
</dict>
<key>type</key>
<string>alfred.workflow.trigger.hotkey</string>
<key>uid</key>
<string>CAA19D9E-04B6-4AD4-A8DC-0B683215DD14</string>
<key>version</key>
<integer>2</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>autopaste</key>
<false/>
<key>clipboardtext</key>
<string></string>
<key>ignoredynamicplaceholders</key>
<false/>
<key>transient</key>
<false/>
</dict>
<key>type</key>
<string>alfred.workflow.output.clipboard</string>
<key>uid</key>
<string>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</string>
<key>version</key>
<integer>3</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>lastpathcomponent</key>
<false/>
<key>onlyshowifquerypopulated</key>
<true/>
<key>removeextension</key>
<false/>
<key>text</key>
<string>{query}</string>
<key>title</key>
<string>Copied to clipboard:</string>
</dict>
<key>type</key>
<string>alfred.workflow.output.notification</string>
<key>uid</key>
<string>D7D47F17-02DB-4A30-8F14-C03CBD051929</string>
<key>version</key>
<integer>1</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>action</key>
<integer>0</integer>
<key>argument</key>
<integer>1</integer>
<key>focusedappvariable</key>
<false/>
<key>focusedappvariablename</key>
<string></string>
<key>hotkey</key>
<integer>2</integer>
<key>hotmod</key>
<integer>1835008</integer>
<key>hotstring</key>
<string>D</string>
<key>leftcursor</key>
<false/>
<key>modsmode</key>
<integer>0</integer>
<key>relatedAppsMode</key>
<integer>0</integer>
</dict>
<key>type</key>
<string>alfred.workflow.trigger.hotkey</string>
<key>uid</key>
<string>84FE56AF-330C-4BB8-85E6-34859AAB73A7</string>
<key>version</key>
<integer>2</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>alfredfiltersresults</key>
<false/>
<key>alfredfiltersresultsmatchmode</key>
<integer>0</integer>
<key>argumenttreatemptyqueryasnil</key>
<false/>
<key>argumenttrimmode</key>
<integer>0</integer>
<key>argumenttype</key>
<integer>0</integer>
<key>escaping</key>
<integer>102</integer>
<key>keyword</key>
<string>dl-to-de</string>
<key>queuedelaycustom</key>
<integer>3</integer>
<key>queuedelayimmediatelyinitially</key>
<false/>
<key>queuedelaymode</key>
<integer>1</integer>
<key>queuemode</key>
<integer>1</integer>
<key>runningsubtext</key>
<string>Translating to language "de" using DeepL ...</string>
<key>script</key>
<string>DEEPL_KEY="$DEEPL_KEY" ./deepl.sh -l "de" "{query}"</string>
<key>scriptargtype</key>
<integer>0</integer>
<key>scriptfile</key>
<string>deepl.sh</string>
<key>subtext</key>
<string>Translate to language "de" using DeepL</string>
<key>title</key>
<string>DeepL Dictionary</string>
<key>type</key>
<integer>0</integer>
<key>withspace</key>
<true/>
</dict>
<key>type</key>
<string>alfred.workflow.input.scriptfilter</string>
<key>uid</key>
<string>91D16594-908E-4665-A005-0B715D96E5C2</string>
<key>version</key>
<integer>3</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>concurrently</key>
<false/>
<key>escaping</key>
<integer>0</integer>
<key>script</key>
<string># THESE VARIABLES MUST BE SET. SEE THE ONEUPDATER README FOR AN EXPLANATION OF EACH.
readonly remote_info_plist='https://raw.githubusercontent.com/AlexanderWillner/deepl-alfred-workflow2/master/info.plist'
readonly workflow_url='https://github.com/AlexanderWillner/deepl-alfred-workflow2/releases/latest/download/Deepl-Translate.alfredworkflow'
readonly download_type='direct'
readonly frequency_check='4'
# FROM HERE ON, CODE SHOULD BE LEFT UNTOUCHED!
function abort {
echo "${1}" >&2
exit 1
}
function url_exists {
curl --silent --location --output /dev/null --fail --range 0-0 "${1}"
}
function notification {
local -r notificator="$(find . -type d -name 'Notificator.app')"
if [[ -n "${notificator}" ]]; then
"${notificator}/Contents/Resources/Scripts/notificator" --message "${1}" --title "${alfred_workflow_name}" --subtitle 'A new version is available'
return
fi
local -r terminal_notifier="$(find . -type f -name 'terminal-notifier')"
if [[ -n "${terminal_notifier}" ]]; then
"${terminal_notifier}" -title "${alfred_workflow_name}" -subtitle 'A new version is available' -message "${1}"
return
fi
osascript -e "display notification \"${1}\" with title \"${alfred_workflow_name}\" subtitle \"A new version is available\""
}
# Local sanity checks
readonly local_info_plist='info.plist'
readonly local_version="$(/usr/libexec/PlistBuddy -c 'print version' "${local_info_plist}")"
[[ -n "${local_version}" ]] || abort 'You need to set a workflow version in the configuration sheet.'
[[ "${download_type}" =~ ^(direct|page|github_release)$ ]] || abort "'download_type' (${download_type}) needs to be one of 'direct', 'page', or 'github_release'."
[[ "${frequency_check}" =~ ^[0-9]+$ ]] || abort "'frequency_check' (${frequency_check}) needs to be a number."
# Check for updates
if [[ $(find "${local_info_plist}" -mtime +"${frequency_check}"d) ]]; then
if ! url_exists "${remote_info_plist}"; then abort "'remote_info_plist' (${remote_info_plist}) appears to not be reachable."; fi # Remote sanity check
readonly tmp_file="$(mktemp)"
curl --silent --location --output "${tmp_file}" "${remote_info_plist}"
readonly remote_version="$(/usr/libexec/PlistBuddy -c 'print version' "${tmp_file}")"
if [[ "${local_version}" == "${remote_version}" ]]; then
touch "${local_info_plist}" # Reset timer by touching local file
exit 0
fi
if [[ "${download_type}" == 'page' ]]; then
notification 'Opening download page…'
open "${workflow_url}"
exit 0
fi
download_url="$([[ "${download_type}" == 'github_release' ]] && curl --silent "https://api.github.com/repos/${workflow_url}/releases/latest" | grep 'browser_download_url' | head -1 | sed -E 's/.*browser_download_url": "(.*)"/\1/' || echo "${workflow_url}")"
if url_exists "${download_url}"; then
notification 'Downloading and installing…'
curl --silent --location --output "${HOME}/Downloads/${alfred_workflow_name}.alfredworkflow" "${download_url}"
open "${HOME}/Downloads/${alfred_workflow_name}.alfredworkflow"
else
abort "'workflow_url' (${download_url}) appears to not be reachable."
fi
fi</string>
<key>scriptargtype</key>
<integer>1</integer>
<key>scriptfile</key>
<string></string>
<key>type</key>
<integer>0</integer>
</dict>
<key>type</key>
<string>alfred.workflow.action.script</string>
<key>uid</key>
<string>51AFB0E3-C777-4C5E-A677-3AF381488BCC</string>
<key>version</key>
<integer>2</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>alfredfiltersresults</key>
<false/>
<key>alfredfiltersresultsmatchmode</key>
<integer>0</integer>
<key>argumenttreatemptyqueryasnil</key>
<false/>
<key>argumenttrimmode</key>
<integer>0</integer>
<key>argumenttype</key>
<integer>0</integer>
<key>escaping</key>
<integer>102</integer>
<key>keyword</key>
<string>dl</string>
<key>queuedelaycustom</key>
<integer>3</integer>
<key>queuedelayimmediatelyinitially</key>
<false/>
<key>queuedelaymode</key>
<integer>1</integer>
<key>queuemode</key>
<integer>1</integer>
<key>runningsubtext</key>
<string>Translating to language "{var:DEEPL_TARGET}" using DeepL ...</string>
<key>script</key>
<string>DEEPL_KEY="$DEEPL_KEY" ./deepl.sh -l "$DEEPL_TARGET" "{query}"</string>
<key>scriptargtype</key>
<integer>0</integer>
<key>scriptfile</key>
<string>deepl.sh</string>
<key>subtext</key>
<string>Translate to language "{var:DEEPL_TARGET}" using DeepL</string>
<key>title</key>
<string>DeepL Dictionary</string>
<key>type</key>
<integer>0</integer>
<key>withspace</key>
<true/>
</dict>
<key>type</key>
<string>alfred.workflow.input.scriptfilter</string>
<key>uid</key>
<string>AD7C89C1-0978-4469-B62F-245E595DE9BD</string>
<key>version</key>
<integer>3</integer>
</dict>
</array>
<key>readme</key>
<string>Using the keyword 'dl' will translate a sentence using deepl.com. You can configure the target language in the workflow configuration.
To avoid the error message 'too many requests', please configure your free (or paid) DeepL API key.</string>
<key>uidata</key>
<dict>
<key>51AFB0E3-C777-4C5E-A677-3AF381488BCC</key>
<dict>
<key>colorindex</key>
<integer>12</integer>
<key>note</key>
<string>Automatically update workflow to latest version.</string>
<key>xpos</key>
<integer>400</integer>
<key>ypos</key>
<integer>460</integer>
</dict>
<key>5233F7C8-9221-45A4-BDE0-DE53175096E1</key>
<dict>
<key>note</key>
<string>Use this keyword to start the translation to an alternative hard coded language.</string>
<key>xpos</key>
<integer>210</integer>
<key>ypos</key>
<integer>30</integer>
</dict>
<key>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</key>
<dict>
<key>note</key>
<string>Copy translated text to the clipboard.</string>
<key>xpos</key>
<integer>490</integer>
<key>ypos</key>
<integer>270</integer>
</dict>
<key>84FE56AF-330C-4BB8-85E6-34859AAB73A7</key>
<dict>
<key>note</key>
<string>Send any selected text to the translator using this hotkey.</string>
<key>xpos</key>
<integer>40</integer>
<key>ypos</key>
<integer>300</integer>
</dict>
<key>91D16594-908E-4665-A005-0B715D96E5C2</key>
<dict>
<key>note</key>
<string>Use this keyword to start the translation to the configured language.</string>
<key>xpos</key>
<integer>220</integer>
<key>ypos</key>
<integer>300</integer>
</dict>
<key>A222FB0A-D703-4C45-9CB0-4EDEA3399BEF</key>
<dict>
<key>note</key>
<string>Show translation as large text.</string>
<key>xpos</key>
<integer>480</integer>
<key>ypos</key>
<integer>30</integer>
</dict>
<key>AD7C89C1-0978-4469-B62F-245E595DE9BD</key>
<dict>
<key>note</key>
<string>Use this keyword to start the translation to the configured language.</string>
<key>xpos</key>
<integer>40</integer>
<key>ypos</key>
<integer>490</integer>
</dict>
<key>CAA19D9E-04B6-4AD4-A8DC-0B683215DD14</key>
<dict>
<key>note</key>
<string>Send any selected text to the translator using this hotkey.</string>
<key>xpos</key>
<integer>30</integer>
<key>ypos</key>
<integer>40</integer>
</dict>
<key>D7D47F17-02DB-4A30-8F14-C03CBD051929</key>
<dict>
<key>note</key>
<string>Show a notifciation when text was copied to the clipboard.</string>
<key>xpos</key>
<integer>680</integer>
<key>ypos</key>
<integer>270</integer>
</dict>
</dict>
<key>variables</key>
<dict>
<key>DEEPL_KEY</key>
<string></string>
<key>DEEPL_POSTFIX</key>
<string>.</string>
<key>DEEPL_PREFERRED</key>
<string>["DE", "EN"]</string>
<key>DEEPL_PRO</key>
<string>0</string>
<key>DEEPL_SOURCE</key>
<string>auto</string>
<key>DEEPL_TARGET</key>
<string>en</string>
</dict>
<key>version</key>
<string>1.11</string>
<key>webaddress</key>
<string>https://github.com/AlexanderWillner/deepl-alfred-workflow2</string>
</dict>
</plist>
================================================
FILE: info5.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>bundleid</key>
<string>ws.willner.alex.alfred.deepl</string>
<key>category</key>
<string>Productivity</string>
<key>connections</key>
<dict>
<key>5233F7C8-9221-45A4-BDE0-DE53175096E1</key>
<array>
<dict>
<key>destinationuid</key>
<string>A222FB0A-D703-4C45-9CB0-4EDEA3399BEF</string>
<key>modifiers</key>
<integer>1048576</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
<dict>
<key>destinationuid</key>
<string>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</key>
<array>
<dict>
<key>destinationuid</key>
<string>D7D47F17-02DB-4A30-8F14-C03CBD051929</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>84FE56AF-330C-4BB8-85E6-34859AAB73A7</key>
<array>
<dict>
<key>destinationuid</key>
<string>91D16594-908E-4665-A005-0B715D96E5C2</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>91D16594-908E-4665-A005-0B715D96E5C2</key>
<array>
<dict>
<key>destinationuid</key>
<string>A222FB0A-D703-4C45-9CB0-4EDEA3399BEF</string>
<key>modifiers</key>
<integer>1048576</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
<dict>
<key>destinationuid</key>
<string>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>AD7C89C1-0978-4469-B62F-245E595DE9BD</key>
<array>
<dict>
<key>destinationuid</key>
<string>A222FB0A-D703-4C45-9CB0-4EDEA3399BEF</string>
<key>modifiers</key>
<integer>1048576</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
<dict>
<key>destinationuid</key>
<string>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>B8B726E5-529C-4F1A-902E-A66B1589922D</key>
<array>
<dict>
<key>destinationuid</key>
<string>DA3683E7-31BA-4DE1-9796-2EAB971CA593</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>CAA19D9E-04B6-4AD4-A8DC-0B683215DD14</key>
<array>
<dict>
<key>destinationuid</key>
<string>5233F7C8-9221-45A4-BDE0-DE53175096E1</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
<key>DA3683E7-31BA-4DE1-9796-2EAB971CA593</key>
<array>
<dict>
<key>destinationuid</key>
<string>AD7C89C1-0978-4469-B62F-245E595DE9BD</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
<key>vitoclose</key>
<false/>
</dict>
</array>
</dict>
<key>createdby</key>
<string>Alexander Willner</string>
<key>description</key>
<string>Translation using deepl.com</string>
<key>disabled</key>
<false/>
<key>name</key>
<string>Deepl-Translate</string>
<key>objects</key>
<array>
<dict>
<key>config</key>
<dict>
<key>alignment</key>
<integer>0</integer>
<key>backgroundcolor</key>
<string></string>
<key>fadespeed</key>
<integer>0</integer>
<key>fillmode</key>
<integer>0</integer>
<key>font</key>
<string></string>
<key>ignoredynamicplaceholders</key>
<false/>
<key>largetypetext</key>
<string>{query}</string>
<key>textcolor</key>
<string></string>
<key>wrapat</key>
<integer>50</integer>
</dict>
<key>type</key>
<string>alfred.workflow.output.largetype</string>
<key>uid</key>
<string>A222FB0A-D703-4C45-9CB0-4EDEA3399BEF</string>
<key>version</key>
<integer>3</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>alfredfiltersresults</key>
<false/>
<key>alfredfiltersresultsmatchmode</key>
<integer>0</integer>
<key>argumenttreatemptyqueryasnil</key>
<false/>
<key>argumenttrimmode</key>
<integer>0</integer>
<key>argumenttype</key>
<integer>0</integer>
<key>escaping</key>
<integer>102</integer>
<key>keyword</key>
<string>dl-to-en</string>
<key>queuedelaycustom</key>
<integer>3</integer>
<key>queuedelayimmediatelyinitially</key>
<false/>
<key>queuedelaymode</key>
<integer>1</integer>
<key>queuemode</key>
<integer>1</integer>
<key>runningsubtext</key>
<string>Translating to language "EN" using DeepL ...</string>
<key>script</key>
<string>./deepl.sh -l "EN" "{query}"
</string>
<key>scriptargtype</key>
<integer>0</integer>
<key>scriptfile</key>
<string>deepl.sh</string>
<key>subtext</key>
<string>Translate to language "EN" using DeepL</string>
<key>title</key>
<string>DeepL Dictionary</string>
<key>type</key>
<integer>0</integer>
<key>withspace</key>
<true/>
</dict>
<key>type</key>
<string>alfred.workflow.input.scriptfilter</string>
<key>uid</key>
<string>5233F7C8-9221-45A4-BDE0-DE53175096E1</string>
<key>version</key>
<integer>3</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>action</key>
<integer>0</integer>
<key>argument</key>
<integer>1</integer>
<key>focusedappvariable</key>
<false/>
<key>focusedappvariablename</key>
<string></string>
<key>hotkey</key>
<integer>0</integer>
<key>hotmod</key>
<integer>0</integer>
<key>leftcursor</key>
<false/>
<key>modsmode</key>
<integer>0</integer>
<key>relatedAppsMode</key>
<integer>0</integer>
</dict>
<key>type</key>
<string>alfred.workflow.trigger.hotkey</string>
<key>uid</key>
<string>CAA19D9E-04B6-4AD4-A8DC-0B683215DD14</string>
<key>version</key>
<integer>2</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>autopaste</key>
<false/>
<key>clipboardtext</key>
<string></string>
<key>ignoredynamicplaceholders</key>
<false/>
<key>transient</key>
<false/>
</dict>
<key>type</key>
<string>alfred.workflow.output.clipboard</string>
<key>uid</key>
<string>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</string>
<key>version</key>
<integer>3</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>lastpathcomponent</key>
<false/>
<key>onlyshowifquerypopulated</key>
<true/>
<key>removeextension</key>
<false/>
<key>text</key>
<string>{query}</string>
<key>title</key>
<string>Copied to clipboard:</string>
</dict>
<key>type</key>
<string>alfred.workflow.output.notification</string>
<key>uid</key>
<string>D7D47F17-02DB-4A30-8F14-C03CBD051929</string>
<key>version</key>
<integer>1</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>action</key>
<integer>0</integer>
<key>argument</key>
<integer>1</integer>
<key>focusedappvariable</key>
<false/>
<key>focusedappvariablename</key>
<string></string>
<key>hotkey</key>
<integer>0</integer>
<key>hotmod</key>
<integer>0</integer>
<key>leftcursor</key>
<false/>
<key>modsmode</key>
<integer>0</integer>
<key>relatedAppsMode</key>
<integer>0</integer>
</dict>
<key>type</key>
<string>alfred.workflow.trigger.hotkey</string>
<key>uid</key>
<string>84FE56AF-330C-4BB8-85E6-34859AAB73A7</string>
<key>version</key>
<integer>2</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>alfredfiltersresults</key>
<false/>
<key>alfredfiltersresultsmatchmode</key>
<integer>0</integer>
<key>argumenttreatemptyqueryasnil</key>
<false/>
<key>argumenttrimmode</key>
<integer>0</integer>
<key>argumenttype</key>
<integer>0</integer>
<key>escaping</key>
<integer>102</integer>
<key>keyword</key>
<string>dl-to-de</string>
<key>queuedelaycustom</key>
<integer>3</integer>
<key>queuedelayimmediatelyinitially</key>
<false/>
<key>queuedelaymode</key>
<integer>1</integer>
<key>queuemode</key>
<integer>1</integer>
<key>runningsubtext</key>
<string>Translating to language "de" using DeepL ...</string>
<key>script</key>
<string>DEEPL_KEY="$DEEPL_KEY" ./deepl.sh -l "de" "{query}"</string>
<key>scriptargtype</key>
<integer>0</integer>
<key>scriptfile</key>
<string>deepl.sh</string>
<key>subtext</key>
<string>Translate to language "de" using DeepL</string>
<key>title</key>
<string>DeepL Dictionary</string>
<key>type</key>
<integer>0</integer>
<key>withspace</key>
<true/>
</dict>
<key>type</key>
<string>alfred.workflow.input.scriptfilter</string>
<key>uid</key>
<string>91D16594-908E-4665-A005-0B715D96E5C2</string>
<key>version</key>
<integer>3</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>alfredfiltersresults</key>
<true/>
<key>alfredfiltersresultsmatchmode</key>
<integer>2</integer>
<key>argumenttreatemptyqueryasnil</key>
<true/>
<key>argumenttrimmode</key>
<integer>0</integer>
<key>argumenttype</key>
<integer>1</integer>
<key>escaping</key>
<integer>102</integer>
<key>keyword</key>
<string>dll</string>
<key>queuedelaycustom</key>
<integer>3</integer>
<key>queuedelayimmediatelyinitially</key>
<true/>
<key>queuedelaymode</key>
<integer>0</integer>
<key>queuemode</key>
<integer>1</integer>
<key>runningsubtext</key>
<string></string>
<key>script</key>
<string>langs=(${(s/,/)${DEEPL_PREFERRED//[\[\]\" ]/}})
out=''
for file in $langs; do
out="${out:+$out,}{\"title\":\"$file\",\"arg\":\"$file\"}"
done
echo "{\"items\":[$out]}"</string>
<key>scriptargtype</key>
<integer>0</integer>
<key>scriptfile</key>
<string></string>
<key>subtext</key>
<string></string>
<key>title</key>
<string>Select Language</string>
<key>type</key>
<integer>11</integer>
<key>withspace</key>
<false/>
</dict>
<key>type</key>
<string>alfred.workflow.input.scriptfilter</string>
<key>uid</key>
<string>B8B726E5-529C-4F1A-902E-A66B1589922D</string>
<key>version</key>
<integer>3</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>alfredfiltersresults</key>
<false/>
<key>alfredfiltersresultsmatchmode</key>
<integer>0</integer>
<key>argumenttreatemptyqueryasnil</key>
<false/>
<key>argumenttrimmode</key>
<integer>0</integer>
<key>argumenttype</key>
<integer>0</integer>
<key>escaping</key>
<integer>102</integer>
<key>keyword</key>
<string>dl</string>
<key>queuedelaycustom</key>
<integer>3</integer>
<key>queuedelayimmediatelyinitially</key>
<false/>
<key>queuedelaymode</key>
<integer>1</integer>
<key>queuemode</key>
<integer>1</integer>
<key>runningsubtext</key>
<string>Translating to language "{var:DEEPL_TARGET}" using DeepL ...</string>
<key>script</key>
<string>DEEPL_KEY="$DEEPL_KEY" ./deepl.sh -l "$DEEPL_TARGET" "{query}"</string>
<key>scriptargtype</key>
<integer>0</integer>
<key>scriptfile</key>
<string>deepl.sh</string>
<key>subtext</key>
<string>Translate to language "{var:DEEPL_TARGET}" using DeepL</string>
<key>title</key>
<string>DeepL Dictionary</string>
<key>type</key>
<integer>0</integer>
<key>withspace</key>
<true/>
</dict>
<key>type</key>
<string>alfred.workflow.input.scriptfilter</string>
<key>uid</key>
<string>AD7C89C1-0978-4469-B62F-245E595DE9BD</string>
<key>version</key>
<integer>3</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>argument</key>
<string></string>
<key>passthroughargument</key>
<false/>
<key>variables</key>
<dict>
<key>DEEPL_TARGET</key>
<string>{query}</string>
</dict>
</dict>
<key>type</key>
<string>alfred.workflow.utility.argument</string>
<key>uid</key>
<string>DA3683E7-31BA-4DE1-9796-2EAB971CA593</string>
<key>version</key>
<integer>1</integer>
</dict>
</array>
<key>readme</key>
<string>Using the keyword 'dl' will translate a sentence using deepl.com. You can configure the target language in the workflow configuration.
To avoid the error message 'too many requests', please configure your free (or paid) DeepL API key.</string>
<key>uidata</key>
<dict>
<key>5233F7C8-9221-45A4-BDE0-DE53175096E1</key>
<dict>
<key>note</key>
<string>Use this keyword to start the translation to an alternative hard coded language.</string>
<key>xpos</key>
<real>300</real>
<key>ypos</key>
<real>30</real>
</dict>
<key>61BF4F8C-DC18-4BB4-8DDD-A87C45C0F79E</key>
<dict>
<key>note</key>
<string>Copy translated text to the clipboard.</string>
<key>xpos</key>
<real>580</real>
<key>ypos</key>
<real>270</real>
</dict>
<key>84FE56AF-330C-4BB8-85E6-34859AAB73A7</key>
<dict>
<key>note</key>
<string>Send any selected text to the translator using this hotkey.</string>
<key>xpos</key>
<real>130</real>
<key>ypos</key>
<real>300</real>
</dict>
<key>91D16594-908E-4665-A005-0B715D96E5C2</key>
<dict>
<key>note</key>
<string>Use this keyword to start the translation to the configured language.</string>
<key>xpos</key>
<real>310</real>
<key>ypos</key>
<real>300</real>
</dict>
<key>A222FB0A-D703-4C45-9CB0-4EDEA3399BEF</key>
<dict>
<key>note</key>
<string>Show translation as large text.</string>
<key>xpos</key>
<real>570</real>
<key>ypos</key>
<real>30</real>
</dict>
<key>AD7C89C1-0978-4469-B62F-245E595DE9BD</key>
<dict>
<key>note</key>
<string>Use this keyword to start the translation to the configured language.</string>
<key>xpos</key>
<real>310</real>
<key>ypos</key>
<real>500</real>
</dict>
<key>B8B726E5-529C-4F1A-902E-A66B1589922D</key>
<dict>
<key>xpos</key>
<real>30</real>
<key>ypos</key>
<real>500</real>
</dict>
<key>CAA19D9E-04B6-4AD4-A8DC-0B683215DD14</key>
<dict>
<key>note</key>
<string>Send any selected text to the translator using this hotkey.</string>
<key>xpos</key>
<real>120</real>
<key>ypos</key>
<real>40</real>
</dict>
<key>D7D47F17-02DB-4A30-8F14-C03CBD051929</key>
<dict>
<key>note</key>
<string>Show a notifciation when text was copied to the clipboard.</string>
<key>xpos</key>
<real>770</real>
<key>ypos</key>
<real>270</real>
</dict>
<key>DA3683E7-31BA-4DE1-9796-2EAB971CA593</key>
<dict>
<key>xpos</key>
<real>205</real>
<key>ypos</key>
<real>530</real>
</dict>
</dict>
<key>userconfigurationconfig</key>
<array>
<dict>
<key>config</key>
<dict>
<key>default</key>
<string></string>
<key>placeholder</key>
<string></string>
<key>required</key>
<false/>
<key>trim</key>
<true/>
</dict>
<key>description</key>
<string>Get one at https://www.deepl.com/pro-api for higher limits.</string>
<key>label</key>
<string>API Key</string>
<key>type</key>
<string>textfield</string>
<key>variable</key>
<string>DEEPL_KEY</string>
</dict>
<dict>
<key>config</key>
<dict>
<key>default</key>
<false/>
<key>required</key>
<false/>
<key>text</key>
<string>You have a professional DeepL account</string>
</dict>
<key>description</key>
<string></string>
<key>label</key>
<string>DeepL Pro</string>
<key>type</key>
<string>checkbox</string>
<key>variable</key>
<string>DEEPL_PRO</string>
</dict>
<dict>
<key>config</key>
<dict>
<key>default</key>
<string></string>
<key>placeholder</key>
<string></string>
<key>required</key>
<false/>
<key>trim</key>
<true/>
</dict>
<key>description</key>
<string>E.g., http://localhost:1188.</string>
<key>label</key>
<string>DeepLX Host</string>
<key>type</key>
<string>textfield</string>
<key>variable</key>
<string>DEEPL_HOST</string>
</dict>
<dict>
<key>config</key>
<dict>
<key>default</key>
<string>default</string>
<key>pairs</key>
<array>
<array>
<string>More Formal</string>
<string>prefer_more</string>
</array>
<array>
<string>Less Formal</string>
<string>prefer_less</string>
</array>
<array>
<string>Default</string>
<string>default</string>
</array>
</array>
</dict>
<key>description</key>
<string>Sets whether the translated text should lean towards formal or informal language.</string>
<key>label</key>
<string>Formality</string>
<key>type</key>
<string>popupbutton</string>
<key>variable</key>
<string>DEEPL_FORMALITY</string>
</dict>
<dict>
<key>config</key>
<dict>
<key>default</key>
<string>["DE", "EN"]</string>
<key>placeholder</key>
<string></string>
<key>required</key>
<false/>
<key>trim</key>
<true/>
</dict>
<key>description</key>
<string></string>
<key>label</key>
<string>Preferred Languages</string>
<key>type</key>
<string>textfield</string>
<key>variable</key>
<string>DEEPL_PREFERRED</string>
</dict>
<dict>
<key>config</key>
<dict>
<key>default</key>
<string>auto</string>
<key>placeholder</key>
<string></string>
<key>required</key>
<false/>
<key>trim</key>
<true/>
</dict>
<key>description</key>
<string></string>
<key>label</key>
<string>Source Language</string>
<key>type</key>
<string>textfield</string>
<key>variable</key>
<string>DEEPL_SOURCE</string>
</dict>
<dict>
<key>config</key>
<dict>
<key>default</key>
<string>en</string>
<key>placeholder</key>
<string></string>
<key>required</key>
<false/>
<key>trim</key>
<true/>
</dict>
<key>description</key>
<string></string>
<key>label</key>
<string>Target Language</string>
<key>type</key>
<string>textfield</string>
<key>variable</key>
<string>DEEPL_TARGET</string>
</dict>
<dict>
<key>config</key>
<dict>
<key>default</key>
<string>.</string>
<key>placeholder</key>
<string></string>
<key>required</key>
<false/>
<key>trim</key>
<true/>
</dict>
<key>description</key>
<string>Add this to the end of your query if you have not set an API key.</string>
<key>label</key>
<string>Query Postfix</string>
<key>type</key>
<string>textfield</string>
<key>variable</key>
<string>DEEPL_POSTFIX</string>
</dict>
</array>
<key>variablesdontexport</key>
<array/>
<key>version</key>
<string>2.2.2</string>
<key>webaddress</key>
<string>https://github.com/AlexanderWillner/deepl-alfred-workflow2</string>
</dict>
</plist>
gitextract_q2yra2a5/ ├── .gitignore ├── .mdlrc ├── Deepl-Translate.alfred5workflow ├── Deepl-Translate.alfredworkflow ├── Makefile ├── README.md ├── deepl-write.sh ├── deepl.bats ├── deepl.sh ├── info4.plist └── info5.plist
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (67K chars).
[
{
"path": ".gitignore",
"chars": 22,
"preview": ".DS_Store\ninfo.plist\n\n"
},
{
"path": ".mdlrc",
"chars": 15,
"preview": "rules \"~MD013\"\n"
},
{
"path": "Makefile",
"chars": 1602,
"preview": "SHELL=bash\n\nhelp:\n\t@echo \"Some available commands:\"\n\t@echo \" * workflow : create workflow\"\n\t@echo \" * bats : run dyn"
},
{
"path": "README.md",
"chars": 3825,
"preview": "# Alfred DeepL Translation Workflow\n\n[ {\n\tsleep 1\n}\n\n@test \"No parameters\" {\n run ./deepl.sh\n [[ \"$status\" -eq 1 ]]\n}\n\n@test "
},
{
"path": "deepl.sh",
"chars": 7994,
"preview": "#!/bin/bash\n\n# setup #######################################################################\n#set -o errexit -o pipefail"
},
{
"path": "info4.plist",
"chars": 17194,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "info5.plist",
"chars": 19722,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the AlexanderWillner/deepl-alfred-workflow2 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (57.7 KB), approximately 20.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.