Add multilanguage support

Add german
This commit is contained in:
dadav 2019-09-29 14:17:02 +02:00
parent 000e11869f
commit 2935d9ccaf
9 changed files with 872 additions and 125 deletions
README.md
scripts
sdcard/rootfs/root/pwnagotchi
config.yml
scripts
main.py
pwnagotchi

@ -91,6 +91,34 @@ The UI is available either via display if installed, or via http://pwnagotchi.lo
* **PWND**: Number of handshakes captured in this session and number of unique networks we own at least one handshake of, from the beginning. * **PWND**: Number of handshakes captured in this session and number of unique networks we own at least one handshake of, from the beginning.
* **AUTO**: This indicates that the algorithm is running with AI disabled (or still loading), it disappears once the AI dependencies have been bootrapped and the neural network loaded. * **AUTO**: This indicates that the algorithm is running with AI disabled (or still loading), it disappears once the AI dependencies have been bootrapped and the neural network loaded.
#### Languages
Pwnagotchi is able to speak multiple languages!! Currently supported is:
* **english** (default)
* german
If you want to add a language use the `language.sh` script.
If you want to add for example the language **italian** you would type:
```shell
./scripts/language.sh add it
# Now make your changes to the file
# sdcard/scripts/rootfs/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.po
./scripts/language.sh compile it
# DONE
```
If you changed the `voice.py`- File, the translations need an update. Do it like this:
```shell
./scripts/language.sh update it
# Now make your changes to the file (changed lines are marked with "fuzzy")
# sdcard/scripts/rootfs/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.po
./scripts/language.sh compile it
# DONE
```
### Random Info ### Random Info
- `hostname` sets the unit name. - `hostname` sets the unit name.

71
scripts/language.sh Executable file

@ -0,0 +1,71 @@
#!/bin/bash
set -eu
DEPENDENCIES=( 'xgettext' 'msgfmt' 'msgmerge' )
COMMANDS=( 'add' 'update' 'delete' 'compile' )
REPO_DIR="$(dirname "$(dirname "$(realpath "$0")")")"
LOCALE_DIR="${REPO_DIR}/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale"
VOICE_FILE="${REPO_DIR}/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/voice.py"
function usage() {
cat <<EOF
usage: $0 <command> [options]
Commands:
add <language> # Adds a new language
delete <language> # Deletes a language
compile <language> # Compiles a language
update # Update
EOF
}
for REQ in "${DEPENDENCIES[@]}"; do
if ! type "$REQ" >/dev/null 2>&1; then
echo "Dependency check failed for ${REQ}"
exit 1
fi
done
if [[ ! "${COMMANDS[*]}" =~ $1 ]]; then
usage
fi
function add_lang() {
mkdir -p "$LOCALE_DIR/$1/LC_MESSAGES"
cp -n "$LOCALE_DIR/voice.pot" "$LOCALE_DIR/$1/LC_MESSAGES/voice.po"
}
function del_lang() {
# set -eu is present; so not dangerous
rm -rf "$LOCALE_DIR/$1"
}
function comp_lang() {
msgfmt -o "$LOCALE_DIR/$1/LC_MESSAGES/voice.mo" "$LOCALE_DIR/$1/LC_MESSAGES/voice.po"
}
function update_lang() {
xgettext -d voice -o "$LOCALE_DIR/voice.pot" "$VOICE_FILE"
msgmerge --update "$LOCALE_DIR/$1/LC_MESSAGES/voice.po" "$LOCALE_DIR/voice.pot"
}
case "$1" in
add)
add_lang "$2"
;;
delete)
del_lang "$2"
;;
compile)
comp_lang "$2"
;;
update)
update_lang "$2"
;;
esac

@ -1,5 +1,7 @@
# main algorithm configuration # main algorithm configuration
main: main:
# currently implemented: en (default), de
lang: en
# monitor interface to use # monitor interface to use
iface: mon0 iface: mon0
# command to run to bring the mon interface up in case it's not up already # command to run to bring the mon interface up in case it's not up already

@ -8,7 +8,7 @@ import core
import pwnagotchi import pwnagotchi
from pwnagotchi.log import SessionParser from pwnagotchi.log import SessionParser
import pwnagotchi.voice as voice from pwnagotchi.voice import Voice
from pwnagotchi.agent import Agent from pwnagotchi.agent import Agent
from pwnagotchi.ui.display import Display from pwnagotchi.ui.display import Display
@ -74,7 +74,7 @@ if args.do_manual:
auth.set_access_token(config['twitter']['access_token_key'], config['twitter']['access_token_secret']) auth.set_access_token(config['twitter']['access_token_key'], config['twitter']['access_token_secret'])
api = tweepy.API(auth) api = tweepy.API(auth)
tweet = voice.on_log_tweet(log) tweet = Voice(lang=config['main']['lang']).on_log_tweet(log)
api.update_with_media(filename=picture, status=tweet) api.update_with_media(filename=picture, status=tweet)
log.save_session_id() log.save_session_id()

@ -0,0 +1,344 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-29 13:34+0200\n"
"PO-Revision-Date: 2019-09-29 14:00+0200\n"
"Last-Translator: dadav <33197631+dadav@users.noreply.github.com>\n"
"Language-Team: DE <33197631+dadav@users.noreply.github.com>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: voice.py:16
msgid "ZzzzZZzzzzZzzz"
msgstr ""
#: voice.py:21
msgid ""
"Hi, I'm Pwnagotchi!\n"
"Starting ..."
msgstr ""
"Hi, ich bin\n"
"ein Pwnagotchi!\n"
"Starte ..."
#: voice.py:22
msgid ""
"New day, new hunt,\n"
"new pwns!"
msgstr ""
"Neuer Tag, neue Jagd,\n"
"neue Pwns!"
#: voice.py:23
msgid "Hack the Planet!"
msgstr "Hack den Planet!"
#: voice.py:28
msgid "AI ready."
msgstr "KI bereit."
#: voice.py:29
msgid ""
"The neural network\n"
"is ready."
msgstr ""
"Das neurale Netz\n"
"ist bereit."
#: voice.py:39
#, python-brace-format
msgid ""
"Hey, channel {channel} is\n"
"free! Your AP will\n"
"say thanks."
msgstr ""
"Hey, Channel {channel} ist\n"
"frei! Dein AP wird\n"
"es dir danken."
#: voice.py:44
msgid "I'm bored ..."
msgstr "Mir ist langweilig..."
#: voice.py:45
msgid "Let's go for a walk!"
msgstr "Lass uns laufen gehen!"
#: voice.py:49
msgid ""
"This is the best\n"
"day of my life!"
msgstr ""
"Das ist der beste\n"
"Tag meines Lebens."
#: voice.py:53
msgid "Shitty day :/"
msgstr "Scheis Tag :/"
#: voice.py:58
msgid "I'm extremely bored ..."
msgstr "Mir ist sau langweilig..."
#: voice.py:59
msgid "I'm very sad ..."
msgstr "Ich bin sehr traurig..."
#: voice.py:60
msgid "I'm sad"
msgstr "Ich bin traurig"
#: voice.py:66
msgid "I'm living the life!"
msgstr "Ich lebe das Leben!"
#: voice.py:67
msgid "I pwn therefore I am."
msgstr "Ich pwne, also bin ich."
#: voice.py:68
msgid "So many networks!!!"
msgstr "So viele Netwerke!!!"
#: voice.py:69
msgid ""
"I'm having so much\n"
"fun!"
msgstr ""
"Ich habe sooo viel\n"
"Spaß!"
#: voice.py:70
msgid ""
"My crime is that of\n"
"curiosity ..."
msgstr ""
"Mein Verbrechen ist\n"
"das der Neugier ..."
#: voice.py:75
#, python-brace-format
msgid ""
"Hello\n"
"{name}!\n"
"Nice to meet you. {name}"
msgstr ""
"Hallo {name},\n"
"Nett Dich\n"
"kennenzulernen."
#: voice.py:76
#, python-brace-format
msgid ""
"Unit\n"
"{name}\n"
"is nearby! {name}"
msgstr ""
"Gerät {name}\n"
"ist in der\n"
"nähe!!"
#: voice.py:81
#, python-brace-format
msgid ""
"Uhm ...\n"
"goodbye\n"
"{name}"
msgstr ""
"Uhm ...\n"
"tschüß\n"
"{name}"
#: voice.py:82
#, python-brace-format
msgid ""
"{name}\n"
"is gone ..."
msgstr ""
"{name}\n"
"ist weg ..."
#: voice.py:87
#, python-brace-format
msgid ""
"Whoops ...\n"
"{name}\n"
"is gone."
msgstr ""
"Whoops ...\n"
"{name}\n"
"ist weg."
#: voice.py:88
#, python-brace-format
msgid ""
"{name}\n"
"missed!"
msgstr ""
"{name}\n"
"verpasst!"
#: voice.py:89
msgid "Missed!"
msgstr "Verpasst!"
#: voice.py:94
msgid ""
"Nobody wants to\n"
"play with me ..."
msgstr ""
"Niemand will mit\n"
"mir spielen ..."
#: voice.py:95
msgid "I feel so alone ..."
msgstr ""
"Ich fühl mich\n"
"so alleine ..."
#: voice.py:96
msgid "Where's everybody?!"
msgstr "Wo sind denn alle?"
#: voice.py:101
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Schlafe für {secs}s"
#: voice.py:102
msgid "Zzzzz"
msgstr ""
#: voice.py:103
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
#: voice.py:112
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Warte für {secs}s ..."
#: voice.py:114
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Schaue mich um ({secs}s)"
#: voice.py:121
#, python-brace-format
msgid ""
"Hey\n"
"{what}\n"
"let's be friends!"
msgstr ""
"Hey\n"
"{what}\n"
"lass uns Freunde sein!"
#: voice.py:122
#, python-brace-format
msgid ""
"Associating to\n"
"{what}"
msgstr ""
"Verbinde mit\n"
"{what}"
#: voice.py:123
#, python-brace-format
msgid ""
"Yo\n"
"{what}!"
msgstr ""
#: voice.py:128
#, python-brace-format
msgid ""
"Just decided that\n"
"{mac}\n"
"needs no WiFi!"
msgstr ""
"Habe gerade entschieden,\n"
"dass {mac}\n"
"kein WiFi brauch!"
#: voice.py:129
#, python-brace-format
msgid ""
"Deauthenticating\n"
"{mac}"
msgstr ""
"Deauthentifiziere\n"
"{mac}"
#: voice.py:130
#, python-brace-format
msgid ""
"Kickbanning\n"
"{mac}!"
msgstr ""
"Kicke\n"
"{mac}!"
#: voice.py:135
#, python-brace-format
msgid ""
"Cool, we got {num}\n"
"new handshake{plural}!"
msgstr ""
"Cool, wir haben {num}\n"
"neue Handshake{plural}!"
#: voice.py:139
msgid ""
"Ops, something\n"
"went wrong ...\n"
"Rebooting ..."
msgstr ""
"Ops, da ist etwas\n"
"schief gelaufen ...\n"
"Starte neu ..."
#: voice.py:143
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "{num} Stationen gekicked\n"
#: voice.py:144
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "{num} Freunde gefunden\n"
#: voice.py:145
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "{num} Handshakes aufgez.\n"
#: voice.py:147
msgid "Met 1 peer"
msgstr "1 Peer getroffen."
#: voice.py:149
#, python-brace-format
msgid "Met {num} peers"
msgstr "{num} Peers getroffen"
#: voice.py:154
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""
"Ich war {duration} am Pwnen und habe {deauthed} Clients gekickt! Außerdem habe ich "
"{associated} neue Freunde getroffen und {handshakes} Handshakes gefressen! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"

@ -0,0 +1,288 @@
# pwnigotchi voice data
# Copyright (C) 2019
# This file is distributed under the same license as the pwnagotchi package.
# FIRST AUTHOR <33197631+dadav@users.noreply.github.com>, 2019.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-29 13:42+0200\n"
"PO-Revision-Date: 2019-09-29 14:00+0200\n"
"Last-Translator: dadav <33197631+dadav@users.noreply.github.com>\n"
"Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
"Language: english\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: voice.py:16
msgid "ZzzzZZzzzzZzzz"
msgstr ""
#: voice.py:21
msgid ""
"Hi, I'm Pwnagotchi!\n"
"Starting ..."
msgstr ""
#: voice.py:22
msgid ""
"New day, new hunt,\n"
"new pwns!"
msgstr ""
#: voice.py:23
msgid "Hack the Planet!"
msgstr ""
#: voice.py:28
msgid "AI ready."
msgstr ""
#: voice.py:29
msgid ""
"The neural network\n"
"is ready."
msgstr ""
#: voice.py:39
#, python-brace-format
msgid ""
"Hey, channel {channel} is\n"
"free! Your AP will\n"
"say thanks."
msgstr ""
#: voice.py:44
msgid "I'm bored ..."
msgstr ""
#: voice.py:45
msgid "Let's go for a walk!"
msgstr ""
#: voice.py:49
msgid ""
"This is the best\n"
"day of my life!"
msgstr ""
#: voice.py:53
msgid "Shitty day :/"
msgstr ""
#: voice.py:58
msgid "I'm extremely bored ..."
msgstr ""
#: voice.py:59
msgid "I'm very sad ..."
msgstr ""
#: voice.py:60
msgid "I'm sad"
msgstr ""
#: voice.py:66
msgid "I'm living the life!"
msgstr ""
#: voice.py:67
msgid "I pwn therefore I am."
msgstr ""
#: voice.py:68
msgid "So many networks!!!"
msgstr ""
#: voice.py:69
msgid ""
"I'm having so much\n"
"fun!"
msgstr ""
#: voice.py:70
msgid ""
"My crime is that of\n"
"curiosity ..."
msgstr ""
#: voice.py:75
#, python-brace-format
msgid ""
"Hello\n"
"{name}!\n"
"Nice to meet you. {name}"
msgstr ""
#: voice.py:76
#, python-brace-format
msgid ""
"Unit\n"
"{name}\n"
"is nearby! {name}"
msgstr ""
#: voice.py:81
#, python-brace-format
msgid ""
"Uhm ...\n"
"goodbye\n"
"{name}"
msgstr ""
#: voice.py:82
#, python-brace-format
msgid ""
"{name}\n"
"is gone ..."
msgstr ""
#: voice.py:87
#, python-brace-format
msgid ""
"Whoops ...\n"
"{name}\n"
"is gone."
msgstr ""
#: voice.py:88
#, python-brace-format
msgid ""
"{name}\n"
"missed!"
msgstr ""
#: voice.py:89
msgid "Missed!"
msgstr ""
#: voice.py:94
msgid ""
"Nobody wants to\n"
"play with me ..."
msgstr ""
#: voice.py:95
msgid "I feel so alone ..."
msgstr ""
#: voice.py:96
msgid "Where's everybody?!"
msgstr ""
#: voice.py:101
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr ""
#: voice.py:102
msgid "Zzzzz"
msgstr ""
#: voice.py:103
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
#: voice.py:112
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr ""
#: voice.py:114
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr ""
#: voice.py:121
#, python-brace-format
msgid ""
"Hey\n"
"{what}\n"
"let's be friends!"
msgstr ""
#: voice.py:122
#, python-brace-format
msgid ""
"Associating to\n"
"{what}"
msgstr ""
#: voice.py:123
#, python-brace-format
msgid ""
"Yo\n"
"{what}!"
msgstr ""
#: voice.py:128
#, python-brace-format
msgid ""
"Just decided that\n"
"{mac}\n"
"needs no WiFi!"
msgstr ""
#: voice.py:129
#, python-brace-format
msgid ""
"Deauthenticating\n"
"{mac}"
msgstr ""
#: voice.py:130
#, python-brace-format
msgid ""
"Kickbanning\n"
"{mac}!"
msgstr ""
#: voice.py:135
#, python-brace-format
msgid ""
"Cool, we got {num}\n"
"new handshake{plural}!"
msgstr ""
#: voice.py:139
msgid ""
"Ops, something\n"
"went wrong ...\n"
"Rebooting ..."
msgstr ""
#: voice.py:143
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr ""
#: voice.py:144
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr ""
#: voice.py:145
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr ""
#: voice.py:147
msgid "Met 1 peer"
msgstr ""
#: voice.py:149
#, python-brace-format
msgid "Met {num} peers"
msgstr ""
#: voice.py:154
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""

@ -5,7 +5,7 @@ from PIL import Image, ImageDraw
import core import core
import pwnagotchi import pwnagotchi
from pwnagotchi import voice from pwnagotchi.voice import Voice
import pwnagotchi.ui.fonts as fonts import pwnagotchi.ui.fonts as fonts
import pwnagotchi.ui.faces as faces import pwnagotchi.ui.faces as faces
@ -49,6 +49,7 @@ class View(object):
self._config = config self._config = config
self._canvas = None self._canvas = None
self._lock = Lock() self._lock = Lock()
self._voice = Voice(lang=config['main']['lang'])
self._width, self._height, \ self._width, self._height, \
face_pos, name_pos, status_pos = setup_display_specifics(config) face_pos, name_pos, status_pos = setup_display_specifics(config)
@ -81,7 +82,7 @@ class View(object):
'name': Text(value='%s>' % 'pwnagotchi', position=name_pos, color=BLACK, font=fonts.Bold), 'name': Text(value='%s>' % 'pwnagotchi', position=name_pos, color=BLACK, font=fonts.Bold),
# 'face2': Bitmap( '/root/pwnagotchi/data/images/face_happy.bmp', (0, 20)), # 'face2': Bitmap( '/root/pwnagotchi/data/images/face_happy.bmp', (0, 20)),
'status': Text(value=voice.default(), position=status_pos, color=BLACK, font=fonts.Medium), 'status': Text(value=self._voice.default(), position=status_pos, color=BLACK, font=fonts.Medium),
'shakes': LabeledValue(label='PWND ', value='0 (00)', color=BLACK, 'shakes': LabeledValue(label='PWND ', value='0 (00)', color=BLACK,
position=(0, self._height - int(self._height * .12) + 1), label_font=fonts.Bold, position=(0, self._height - int(self._height * .12) + 1), label_font=fonts.Bold,
@ -116,19 +117,19 @@ class View(object):
self._state.set(key, value) self._state.set(key, value)
def on_starting(self): def on_starting(self):
self.set('status', voice.on_starting()) self.set('status', self._voice.on_starting())
self.set('face', faces.AWAKE) self.set('face', faces.AWAKE)
def on_ai_ready(self): def on_ai_ready(self):
self.set('mode', '') self.set('mode', '')
self.set('face', faces.HAPPY) self.set('face', faces.HAPPY)
self.set('status', voice.on_ai_ready()) self.set('status', self._voice.on_ai_ready())
self.update() self.update()
def on_manual_mode(self, log): def on_manual_mode(self, log):
self.set('mode', 'MANU') self.set('mode', 'MANU')
self.set('face', faces.SAD if log.handshakes == 0 else faces.HAPPY) self.set('face', faces.SAD if log.handshakes == 0 else faces.HAPPY)
self.set('status', voice.on_log(log)) self.set('status', self._voice.on_log(log))
self.set('epoch', "%04d" % log.epochs) self.set('epoch', "%04d" % log.epochs)
self.set('uptime', log.duration) self.set('uptime', log.duration)
self.set('channel', '-') self.set('channel', '-')
@ -152,7 +153,7 @@ class View(object):
def on_normal(self): def on_normal(self):
self.set('face', faces.AWAKE) self.set('face', faces.AWAKE)
self.set('status', voice.on_normal()) self.set('status', self._voice.on_normal())
self.update() self.update()
def set_closest_peer(self, peer): def set_closest_peer(self, peer):
@ -180,17 +181,17 @@ class View(object):
def on_new_peer(self, peer): def on_new_peer(self, peer):
self.set('face', faces.FRIEND) self.set('face', faces.FRIEND)
self.set('status', voice.on_new_peer(peer)) self.set('status', self._voice.on_new_peer(peer))
self.update() self.update()
def on_lost_peer(self, peer): def on_lost_peer(self, peer):
self.set('face', faces.LONELY) self.set('face', faces.LONELY)
self.set('status', voice.on_lost_peer(peer)) self.set('status', self._voice.on_lost_peer(peer))
self.update() self.update()
def on_free_channel(self, channel): def on_free_channel(self, channel):
self.set('face', faces.SMART) self.set('face', faces.SMART)
self.set('status', voice.on_free_channel(channel)) self.set('status', self._voice.on_free_channel(channel))
self.update() self.update()
def wait(self, secs, sleeping=True): def wait(self, secs, sleeping=True):
@ -206,12 +207,12 @@ class View(object):
if sleeping: if sleeping:
if secs > 1: if secs > 1:
self.set('face', faces.SLEEP) self.set('face', faces.SLEEP)
self.set('status', voice.on_napping(secs)) self.set('status', self._voice.on_napping(secs))
else: else:
self.set('face', faces.SLEEP2) self.set('face', faces.SLEEP2)
self.set('status', voice.on_awakening()) self.set('status', self._voice.on_awakening())
else: else:
self.set('status', voice.on_waiting(secs)) self.set('status', self._voice.on_waiting(secs))
if step % 2 == 0: if step % 2 == 0:
self.set('face', faces.LOOK_R) self.set('face', faces.LOOK_R)
else: else:
@ -224,57 +225,57 @@ class View(object):
def on_bored(self): def on_bored(self):
self.set('face', faces.BORED) self.set('face', faces.BORED)
self.set('status', voice.on_bored()) self.set('status', self._voice.on_bored())
self.update() self.update()
def on_sad(self): def on_sad(self):
self.set('face', faces.SAD) self.set('face', faces.SAD)
self.set('status', voice.on_sad()) self.set('status', self._voice.on_sad())
self.update() self.update()
def on_motivated(self, reward): def on_motivated(self, reward):
self.set('face', faces.MOTIVATED) self.set('face', faces.MOTIVATED)
self.set('status', voice.on_motivated(reward)) self.set('status', self._voice.on_motivated(reward))
self.update() self.update()
def on_demotivated(self, reward): def on_demotivated(self, reward):
self.set('face', faces.DEMOTIVATED) self.set('face', faces.DEMOTIVATED)
self.set('status', voice.on_demotivated(reward)) self.set('status', self._voice.on_demotivated(reward))
self.update() self.update()
def on_excited(self): def on_excited(self):
self.set('face', faces.EXCITED) self.set('face', faces.EXCITED)
self.set('status', voice.on_excited()) self.set('status', self._voice.on_excited())
self.update() self.update()
def on_assoc(self, ap): def on_assoc(self, ap):
self.set('face', faces.INTENSE) self.set('face', faces.INTENSE)
self.set('status', voice.on_assoc(ap)) self.set('status', self._voice.on_assoc(ap))
self.update() self.update()
def on_deauth(self, sta): def on_deauth(self, sta):
self.set('face', faces.COOL) self.set('face', faces.COOL)
self.set('status', voice.on_deauth(sta)) self.set('status', self._voice.on_deauth(sta))
self.update() self.update()
def on_miss(self, who): def on_miss(self, who):
self.set('face', faces.SAD) self.set('face', faces.SAD)
self.set('status', voice.on_miss(who)) self.set('status', self._voice.on_miss(who))
self.update() self.update()
def on_lonely(self): def on_lonely(self):
self.set('face', faces.LONELY) self.set('face', faces.LONELY)
self.set('status', voice.on_lonely()) self.set('status', self._voice.on_lonely())
self.update() self.update()
def on_handshakes(self, new_shakes): def on_handshakes(self, new_shakes):
self.set('face', faces.HAPPY) self.set('face', faces.HAPPY)
self.set('status', voice.on_handshakes(new_shakes)) self.set('status', self._voice.on_handshakes(new_shakes))
self.update() self.update()
def on_rebooting(self): def on_rebooting(self):
self.set('face', faces.BROKEN) self.set('face', faces.BROKEN)
self.set('status', voice.on_rebooting()) self.set('status', self._voice.on_rebooting())
self.update() self.update()
def update(self): def update(self):

@ -1,147 +1,160 @@
import random import random
import gettext
import os
def default(): class Voice:
return 'ZzzzZZzzzzZzzz' def __init__(self, lang):
localedir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'locale')
translation = gettext.translation(
'voice', localedir,
languages=[lang],
fallback=True,
)
translation.install()
self._ = translation.gettext
def default(self):
return self._('ZzzzZZzzzzZzzz')
def on_starting(): def on_starting(self):
return random.choice([ \ return random.choice([ \
'Hi, I\'m Pwnagotchi!\nStarting ...', self._('Hi, I\'m Pwnagotchi!\nStarting ...'),
'New day, new hunt,\nnew pwns!', self._('New day, new hunt,\nnew pwns!'),
'Hack the Planet!']) self._('Hack the Planet!')])
def on_ai_ready(): def on_ai_ready(self):
return random.choice([ return random.choice([
'AI ready.', self._('AI ready.'),
'The neural network\nis ready.']) self._('The neural network\nis ready.')])
def on_normal(): def on_normal(self):
return random.choice([ \ return random.choice([ \
'', '',
'...']) '...'])
def on_free_channel(channel): def on_free_channel(channel):
return 'Hey, channel %d is\nfree! Your AP will\nsay thanks.' % channel return self._('Hey, channel {channel} is\nfree! Your AP will\nsay thanks.').format(channel=channel)
def on_bored(): def on_bored():
return random.choice([ \ return random.choice([ \
'I\'m bored ...', self._('I\'m bored ...'),
'Let\'s go for a walk!']) self._('Let\'s go for a walk!')])
def on_motivated(reward): def on_motivated(self, reward):
return 'This is the best\nday of my life!' return self._('This is the best\nday of my life!')
def on_demotivated(reward): def on_demotivated(self, reward):
return 'Shitty day :/' return self._('Shitty day :/')
def on_sad(): def on_sad(self):
return random.choice([ \ return random.choice([ \
'I\'m extremely bored ...', self._('I\'m extremely bored ...'),
'I\'m very sad ...', self._('I\'m very sad ...'),
'I\'m sad', self._('I\'m sad'),
'...']) '...'])
def on_excited(): def on_excited(self):
return random.choice([ \ return random.choice([ \
'I\'m living the life!', self._('I\'m living the life!'),
'I pwn therefore I am.', self._('I pwn therefore I am.'),
'So many networks!!!', self._('So many networks!!!'),
'I\'m having so much\nfun!', self._('I\'m having so much\nfun!'),
'My crime is that of\ncuriosity ...']) self._('My crime is that of\ncuriosity ...')])
def on_new_peer(peer): def on_new_peer(self, peer):
return random.choice([ \ return random.choice([ \
'Hello\n%s!\nNice to meet you.' % peer.name(), self._('Hello\n{name}!\nNice to meet you. {name}').format(name=peer.name()),
'Unit\n%s\nis nearby!' % peer.name()]) self._('Unit\n{name}\nis nearby! {name}').format(name=peer.name())])
def on_lost_peer(peer): def on_lost_peer(self, peer):
return random.choice([ \ return random.choice([ \
'Uhm ...\ngoodbye\n%s' % peer.name(), self._('Uhm ...\ngoodbye\n{name}').format(name=peer.name()),
'%s\nis gone ...' % peer.name()]) self._('{name}\nis gone ...').format(name=peer.name())])
def on_miss(who): def on_miss(self, who):
return random.choice([ \ return random.choice([ \
'Whoops ...\n%s\nis gone.' % who, self._('Whoops ...\n{name}\nis gone.').format(name=who),
'%s\nmissed!' % who, self._('{name}\nmissed!').format(name=who),
'Missed!']) self._('Missed!')])
def on_lonely(): def on_lonely(self):
return random.choice([ \ return random.choice([ \
'Nobody wants to\nplay with me ...', self._('Nobody wants to\nplay with me ...'),
'I feel so alone ...', self._('I feel so alone ...'),
'Where\'s everybody?!']) self._('Where\'s everybody?!')])
def on_napping(secs): def on_napping(self,secs):
return random.choice([ \ return random.choice([ \
'Napping for %ds ...' % secs, self._('Napping for {secs}s ...').format(secs=secs),
'Zzzzz', self._('Zzzzz'),
'ZzzZzzz (%ds)' % secs]) self._('ZzzZzzz ({secs}s)').format(secs=secs)])
def on_awakening(): def on_awakening(self):
return random.choice(['...', '!']) return random.choice(['...', '!'])
def on_waiting(secs): def on_waiting(self,secs):
return random.choice([ \ return random.choice([ \
'Waiting for %ds ...' % secs, self._('Waiting for {secs}s ...').format(secs=secs),
'...', '...',
'Looking around (%ds)' % secs]) self._('Looking around ({secs}s)').format(secs=secs)])
def on_assoc(ap): def on_assoc(self,ap):
ssid, bssid = ap['hostname'], ap['mac'] ssid, bssid = ap['hostname'], ap['mac']
what = ssid if ssid != '' and ssid != '<hidden>' else bssid what = ssid if ssid != '' and ssid != '<hidden>' else bssid
return random.choice([ \ return random.choice([ \
'Hey\n%s\nlet\'s be friends!' % what, self._('Hey\n{what}\nlet\'s be friends!').format(what=what),
'Associating to\n%s' % what, self._('Associating to\n{what}').format(what=what),
'Yo\n%s!' % what]) self._('Yo\n{what}!').format(what=what)])
def on_deauth(sta): def on_deauth(self,sta):
return random.choice([ \ return random.choice([ \
'Just decided that\n%s\nneeds no WiFi!' % sta['mac'], self._('Just decided that\n{mac}\nneeds no WiFi!').format(mac=sta['mac']),
'Deauthenticating\n%s' % sta['mac'], self._('Deauthenticating\n{mac}').format(mac=sta['mac']),
'Kickbanning\n%s!' % sta['mac']]) self._('Kickbanning\n{mac}!').format(mac=sta['mac'])])
def on_handshakes(new_shakes): def on_handshakes(self,new_shakes):
s = 's' if new_shakes > 1 else '' s = 's' if new_shakes > 1 else ''
return 'Cool, we got %d\nnew handshake%s!' % (new_shakes, s) return self._('Cool, we got {num}\nnew handshake{plural}!').format(num=new_shakes, plural=s)
def on_rebooting(): def on_rebooting(self):
return "Ops, something\nwent wrong ...\nRebooting ..." return self._("Ops, something\nwent wrong ...\nRebooting ...")
def on_log(log): def on_log(self,log):
status = 'Kicked %d stations\n' % log.deauthed status = self._('Kicked {num} stations\n').format(num=log.deauthed)
status += 'Made %d new friends\n' % log.associated status += self._('Made {num} new friends\n').format(num=log.associated)
status += 'Got %d handshakes\n' % log.handshakes status += self._('Got {num} handshakes\n').format(num=log.handshakes)
if log.peers == 1: if log.peers == 1:
status += 'Met 1 peer' status += self._('Met 1 peer')
elif log.peers > 0: elif log.peers > 0:
status += 'Met %d peers' % log.peers status += self._('Met {num} peers').format(num=log.peers)
return status return status
def on_log_tweet(log): def on_log_tweet(self,log):
return 'I\'ve been pwning for %s and kicked %d clients! I\'ve also met %d new friends and ate %d handshakes! #pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet' % ( \ return self._('I\'ve been pwning for {duration} and kicked {deauthed} clients! I\'ve also met {associated} new friends and ate {handshakes} handshakes! #pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet').format(
log.duration_human, duration=log.duration_human,
log.deauthed, deauthed=log.deauthed,
log.associated, associated=log.associated,
log.handshakes) handshakes=log.handshakes)