agentvibes 2.13.8 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/agent-vibes/bmad.md +16 -14
- package/.claude/commands/agent-vibes/translate.md +68 -0
- package/.claude/hooks/learn-manager.sh +14 -3
- package/.claude/hooks/play-tts-elevenlabs.sh +3 -1
- package/.claude/hooks/play-tts.sh +131 -8
- package/.claude/hooks/provider-manager.sh +112 -23
- package/.claude/hooks/requirements.txt +6 -0
- package/.claude/hooks/translate-manager.sh +341 -0
- package/.claude/hooks/translator.py +237 -0
- package/README.md +9 -8
- package/RELEASE_NOTES.md +111 -515
- package/docs/language-learning-mode.md +47 -2
- package/mcp-server/install-deps.js +7 -6
- package/mcp-server/server.py +4 -2
- package/package.json +1 -1
- package/src/commands/bmad-voices.js +5 -16
- package/src/commands/install-mcp.js +15 -9
- package/src/installer.js +21 -23
- package/test/unit/provider-manager.bats +13 -9
- package/test/unit/translator.bats +246 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# File: .claude/hooks/translate-manager.sh
|
|
4
|
+
#
|
|
5
|
+
# AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
|
|
6
|
+
# Website: https://agentvibes.org
|
|
7
|
+
# Repository: https://github.com/paulpreibisch/AgentVibes
|
|
8
|
+
#
|
|
9
|
+
# Co-created by Paul Preibisch with Claude AI
|
|
10
|
+
# Copyright (c) 2025 Paul Preibisch
|
|
11
|
+
#
|
|
12
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
+
# you may not use this file except in compliance with the License.
|
|
14
|
+
# You may obtain a copy of the License at
|
|
15
|
+
#
|
|
16
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
+
#
|
|
18
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
19
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
+
# See the License for the specific language governing permissions and
|
|
22
|
+
# limitations under the License.
|
|
23
|
+
#
|
|
24
|
+
# DISCLAIMER: This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
25
|
+
# express or implied. Use at your own risk. See the Apache License for details.
|
|
26
|
+
#
|
|
27
|
+
# ---
|
|
28
|
+
#
|
|
29
|
+
# @fileoverview Translation Manager - Auto-translate TTS to user's preferred language
|
|
30
|
+
# @context Integrates with BMAD communication_language and provides manual override
|
|
31
|
+
# @architecture Manages translation settings, detects BMAD config, translates text via translator.py
|
|
32
|
+
# @dependencies translator.py, language-manager.sh, .bmad/core/config.yaml (optional)
|
|
33
|
+
# @entrypoints Called by /agent-vibes:translate commands and play-tts.sh
|
|
34
|
+
# @patterns Config cascade - manual override > BMAD config > default (no translation)
|
|
35
|
+
# @related translator.py, play-tts.sh, language-manager.sh, learn-manager.sh
|
|
36
|
+
|
|
37
|
+
# Only set strict mode when executed directly, not when sourced
|
|
38
|
+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
39
|
+
set -euo pipefail
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
43
|
+
|
|
44
|
+
# Use PWD for project dir when called from project context, fall back to script-relative
|
|
45
|
+
if [[ -d "$PWD/.claude" ]]; then
|
|
46
|
+
PROJECT_DIR="$PWD"
|
|
47
|
+
else
|
|
48
|
+
PROJECT_DIR="$SCRIPT_DIR/../.."
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Configuration files
|
|
52
|
+
TRANSLATE_FILE="$PROJECT_DIR/.claude/tts-translate-to.txt"
|
|
53
|
+
GLOBAL_TRANSLATE_FILE="$HOME/.claude/tts-translate-to.txt"
|
|
54
|
+
|
|
55
|
+
# Colors
|
|
56
|
+
GREEN='\033[0;32m'
|
|
57
|
+
YELLOW='\033[1;33m'
|
|
58
|
+
BLUE='\033[0;34m'
|
|
59
|
+
RED='\033[0;31m'
|
|
60
|
+
NC='\033[0m'
|
|
61
|
+
|
|
62
|
+
# Supported languages (matching language-manager.sh)
|
|
63
|
+
SUPPORTED_LANGUAGES="spanish french german italian portuguese chinese japanese korean russian polish dutch turkish arabic hindi swedish danish norwegian finnish czech romanian ukrainian greek bulgarian croatian slovak"
|
|
64
|
+
|
|
65
|
+
# @function get_bmad_language
|
|
66
|
+
# @intent Read communication_language from BMAD config
|
|
67
|
+
# @why BMAD users can set their preferred language in .bmad/core/config.yaml
|
|
68
|
+
# @returns Language name (lowercase) or empty if not set
|
|
69
|
+
get_bmad_language() {
|
|
70
|
+
local bmad_config=""
|
|
71
|
+
|
|
72
|
+
# Search for BMAD config in project or parents
|
|
73
|
+
local search_dir="$PWD"
|
|
74
|
+
while [[ "$search_dir" != "/" ]]; do
|
|
75
|
+
if [[ -f "$search_dir/.bmad/core/config.yaml" ]]; then
|
|
76
|
+
bmad_config="$search_dir/.bmad/core/config.yaml"
|
|
77
|
+
break
|
|
78
|
+
fi
|
|
79
|
+
search_dir=$(dirname "$search_dir")
|
|
80
|
+
done
|
|
81
|
+
|
|
82
|
+
if [[ -z "$bmad_config" ]] || [[ ! -f "$bmad_config" ]]; then
|
|
83
|
+
echo ""
|
|
84
|
+
return
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Security: Verify file ownership (should be owned by current user)
|
|
88
|
+
local owner
|
|
89
|
+
owner=$(stat -c '%u' "$bmad_config" 2>/dev/null || stat -f '%u' "$bmad_config" 2>/dev/null || echo "")
|
|
90
|
+
if [[ -n "$owner" ]] && [[ "$owner" != "$(id -u)" ]]; then
|
|
91
|
+
echo "Warning: BMAD config not owned by current user, skipping" >&2
|
|
92
|
+
echo ""
|
|
93
|
+
return
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Extract communication_language from YAML (simple grep approach)
|
|
97
|
+
local lang
|
|
98
|
+
lang=$(grep -E "^communication_language:" "$bmad_config" 2>/dev/null | head -1 | cut -d: -f2 | tr -d ' "'"'" | tr '[:upper:]' '[:lower:]')
|
|
99
|
+
|
|
100
|
+
echo "$lang"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# @function get_translate_to
|
|
104
|
+
# @intent Get the target language for translation
|
|
105
|
+
# @why Implements priority: manual override > BMAD config > no translation
|
|
106
|
+
# @returns Language name or empty if no translation
|
|
107
|
+
get_translate_to() {
|
|
108
|
+
# Priority 1: Manual override
|
|
109
|
+
if [[ -f "$TRANSLATE_FILE" ]]; then
|
|
110
|
+
local manual
|
|
111
|
+
manual=$(cat "$TRANSLATE_FILE")
|
|
112
|
+
if [[ "$manual" != "off" ]] && [[ "$manual" != "auto" ]]; then
|
|
113
|
+
echo "$manual"
|
|
114
|
+
return
|
|
115
|
+
elif [[ "$manual" == "off" ]]; then
|
|
116
|
+
echo ""
|
|
117
|
+
return
|
|
118
|
+
fi
|
|
119
|
+
# If "auto", fall through to BMAD detection
|
|
120
|
+
elif [[ -f "$GLOBAL_TRANSLATE_FILE" ]]; then
|
|
121
|
+
local manual
|
|
122
|
+
manual=$(cat "$GLOBAL_TRANSLATE_FILE")
|
|
123
|
+
if [[ "$manual" != "off" ]] && [[ "$manual" != "auto" ]]; then
|
|
124
|
+
echo "$manual"
|
|
125
|
+
return
|
|
126
|
+
elif [[ "$manual" == "off" ]]; then
|
|
127
|
+
echo ""
|
|
128
|
+
return
|
|
129
|
+
fi
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# Priority 2: BMAD config
|
|
133
|
+
local bmad_lang
|
|
134
|
+
bmad_lang=$(get_bmad_language)
|
|
135
|
+
if [[ -n "$bmad_lang" ]] && [[ "$bmad_lang" != "english" ]]; then
|
|
136
|
+
echo "$bmad_lang"
|
|
137
|
+
return
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
# Default: No translation
|
|
141
|
+
echo ""
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# @function is_translation_enabled
|
|
145
|
+
# @intent Check if translation should occur
|
|
146
|
+
# @why Quick check for play-tts.sh to decide whether to translate
|
|
147
|
+
# @returns 0 if enabled, 1 if disabled
|
|
148
|
+
is_translation_enabled() {
|
|
149
|
+
local translate_to
|
|
150
|
+
translate_to=$(get_translate_to)
|
|
151
|
+
[[ -n "$translate_to" ]] && [[ "$translate_to" != "english" ]]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
# @function translate_text
|
|
155
|
+
# @intent Translate text to target language using translator.py
|
|
156
|
+
# @why Central translation function for all TTS
|
|
157
|
+
# @param $1 text to translate
|
|
158
|
+
# @param $2 target language (optional, auto-detected if not provided)
|
|
159
|
+
# @returns Translated text (or original if translation fails/disabled)
|
|
160
|
+
translate_text() {
|
|
161
|
+
local text="$1"
|
|
162
|
+
local target="${2:-}"
|
|
163
|
+
|
|
164
|
+
if [[ -z "$target" ]]; then
|
|
165
|
+
target=$(get_translate_to)
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
# Skip if no translation target or target is English
|
|
169
|
+
if [[ -z "$target" ]] || [[ "$target" == "english" ]]; then
|
|
170
|
+
echo "$text"
|
|
171
|
+
return
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
# Call translator.py
|
|
175
|
+
local translated
|
|
176
|
+
translated=$(python3 "$SCRIPT_DIR/translator.py" "$text" "$target" 2>/dev/null) || translated="$text"
|
|
177
|
+
|
|
178
|
+
echo "$translated"
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
# @function set_translate
|
|
182
|
+
# @intent Set manual translation override
|
|
183
|
+
# @why Allows users to override BMAD config or force specific language
|
|
184
|
+
# @param $1 language name, "auto", or "off"
|
|
185
|
+
set_translate() {
|
|
186
|
+
local lang="$1"
|
|
187
|
+
|
|
188
|
+
if [[ -z "$lang" ]]; then
|
|
189
|
+
echo -e "${YELLOW}Usage: translate-manager.sh set <language|auto|off>${NC}"
|
|
190
|
+
exit 1
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
lang=$(echo "$lang" | tr '[:upper:]' '[:lower:]')
|
|
194
|
+
|
|
195
|
+
mkdir -p "$PROJECT_DIR/.claude"
|
|
196
|
+
|
|
197
|
+
if [[ "$lang" == "off" ]]; then
|
|
198
|
+
echo "off" > "$TRANSLATE_FILE"
|
|
199
|
+
echo -e "${GREEN}✓${NC} Translation: ${YELLOW}DISABLED${NC}"
|
|
200
|
+
echo " TTS will speak in English only"
|
|
201
|
+
return
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
if [[ "$lang" == "auto" ]]; then
|
|
205
|
+
echo "auto" > "$TRANSLATE_FILE"
|
|
206
|
+
echo -e "${GREEN}✓${NC} Translation: ${BLUE}AUTO${NC}"
|
|
207
|
+
echo " Will detect from BMAD config if available"
|
|
208
|
+
|
|
209
|
+
local bmad_lang
|
|
210
|
+
bmad_lang=$(get_bmad_language)
|
|
211
|
+
if [[ -n "$bmad_lang" ]]; then
|
|
212
|
+
echo -e " ${BLUE}ℹ${NC} BMAD config detected: $bmad_lang"
|
|
213
|
+
else
|
|
214
|
+
echo -e " ${YELLOW}⚠${NC} No BMAD config found, will speak English"
|
|
215
|
+
fi
|
|
216
|
+
return
|
|
217
|
+
fi
|
|
218
|
+
|
|
219
|
+
# Validate language
|
|
220
|
+
local valid=false
|
|
221
|
+
for supported in $SUPPORTED_LANGUAGES; do
|
|
222
|
+
if [[ "$lang" == "$supported" ]]; then
|
|
223
|
+
valid=true
|
|
224
|
+
break
|
|
225
|
+
fi
|
|
226
|
+
done
|
|
227
|
+
|
|
228
|
+
if [[ "$valid" != "true" ]]; then
|
|
229
|
+
echo -e "${RED}❌${NC} Language '$lang' not supported"
|
|
230
|
+
echo ""
|
|
231
|
+
echo "Supported languages:"
|
|
232
|
+
echo "$SUPPORTED_LANGUAGES" | tr ' ' '\n' | column
|
|
233
|
+
exit 1
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
echo "$lang" > "$TRANSLATE_FILE"
|
|
237
|
+
echo -e "${GREEN}✓${NC} Translation set to: ${BLUE}$lang${NC}"
|
|
238
|
+
echo " All TTS will be translated to $lang before speaking"
|
|
239
|
+
|
|
240
|
+
# Show voice recommendation
|
|
241
|
+
source "$SCRIPT_DIR/language-manager.sh" 2>/dev/null || true
|
|
242
|
+
if command -v get_voice_for_language &>/dev/null; then
|
|
243
|
+
local provider
|
|
244
|
+
provider=$(get_active_provider 2>/dev/null || echo "piper")
|
|
245
|
+
local voice
|
|
246
|
+
voice=$(get_voice_for_language "$lang" "$provider" 2>/dev/null || echo "")
|
|
247
|
+
if [[ -n "$voice" ]]; then
|
|
248
|
+
echo -e " ${BLUE}💡${NC} Recommended voice: ${YELLOW}$voice${NC}"
|
|
249
|
+
echo -e " Switch with: /agent-vibes:switch $voice"
|
|
250
|
+
fi
|
|
251
|
+
fi
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
# @function show_status
|
|
255
|
+
# @intent Display current translation settings
|
|
256
|
+
# @why Help users understand what's configured
|
|
257
|
+
show_status() {
|
|
258
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
259
|
+
echo -e "${BLUE} Translation Settings${NC}"
|
|
260
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
261
|
+
echo ""
|
|
262
|
+
|
|
263
|
+
# Check manual setting
|
|
264
|
+
local manual_setting=""
|
|
265
|
+
if [[ -f "$TRANSLATE_FILE" ]]; then
|
|
266
|
+
manual_setting=$(cat "$TRANSLATE_FILE")
|
|
267
|
+
elif [[ -f "$GLOBAL_TRANSLATE_FILE" ]]; then
|
|
268
|
+
manual_setting=$(cat "$GLOBAL_TRANSLATE_FILE")
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
# Check BMAD config
|
|
272
|
+
local bmad_lang
|
|
273
|
+
bmad_lang=$(get_bmad_language)
|
|
274
|
+
|
|
275
|
+
# Get effective translation
|
|
276
|
+
local effective
|
|
277
|
+
effective=$(get_translate_to)
|
|
278
|
+
|
|
279
|
+
echo -e " ${BLUE}Manual Setting:${NC} ${manual_setting:-"(not set)"}"
|
|
280
|
+
echo -e " ${BLUE}BMAD Language:${NC} ${bmad_lang:-"(not detected)"}"
|
|
281
|
+
echo -e " ${BLUE}Effective:${NC} $(if [[ -n "$effective" ]]; then echo -e "${GREEN}$effective${NC}"; else echo -e "${YELLOW}No translation${NC}"; fi)"
|
|
282
|
+
echo ""
|
|
283
|
+
|
|
284
|
+
if [[ -n "$effective" ]]; then
|
|
285
|
+
echo -e " ${GREEN}✓${NC} TTS will be translated to ${BLUE}$effective${NC}"
|
|
286
|
+
else
|
|
287
|
+
echo -e " ${YELLOW}ℹ${NC} TTS will speak in English"
|
|
288
|
+
fi
|
|
289
|
+
|
|
290
|
+
echo ""
|
|
291
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
292
|
+
echo ""
|
|
293
|
+
echo -e " ${BLUE}Commands:${NC}"
|
|
294
|
+
echo -e " /agent-vibes:translate set <lang> Set manual translation"
|
|
295
|
+
echo -e " /agent-vibes:translate auto Use BMAD config"
|
|
296
|
+
echo -e " /agent-vibes:translate off Disable translation"
|
|
297
|
+
echo ""
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
# Main command handler - only run if script is executed directly, not sourced
|
|
301
|
+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
302
|
+
case "${1:-}" in
|
|
303
|
+
get-bmad-language)
|
|
304
|
+
get_bmad_language
|
|
305
|
+
;;
|
|
306
|
+
get-translate-to)
|
|
307
|
+
get_translate_to
|
|
308
|
+
;;
|
|
309
|
+
is-enabled)
|
|
310
|
+
if is_translation_enabled; then
|
|
311
|
+
echo "ON"
|
|
312
|
+
exit 0
|
|
313
|
+
else
|
|
314
|
+
echo "OFF"
|
|
315
|
+
exit 1
|
|
316
|
+
fi
|
|
317
|
+
;;
|
|
318
|
+
translate)
|
|
319
|
+
if [[ -z "${2:-}" ]]; then
|
|
320
|
+
echo "Usage: translate-manager.sh translate <text> [target_lang]" >&2
|
|
321
|
+
exit 1
|
|
322
|
+
fi
|
|
323
|
+
translate_text "$2" "${3:-}"
|
|
324
|
+
;;
|
|
325
|
+
set)
|
|
326
|
+
set_translate "${2:-}"
|
|
327
|
+
;;
|
|
328
|
+
auto)
|
|
329
|
+
set_translate "auto"
|
|
330
|
+
;;
|
|
331
|
+
off)
|
|
332
|
+
set_translate "off"
|
|
333
|
+
;;
|
|
334
|
+
status)
|
|
335
|
+
show_status
|
|
336
|
+
;;
|
|
337
|
+
*)
|
|
338
|
+
show_status
|
|
339
|
+
;;
|
|
340
|
+
esac
|
|
341
|
+
fi
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# File: .claude/hooks/translator.py
|
|
4
|
+
#
|
|
5
|
+
# AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
|
|
6
|
+
# Website: https://agentvibes.org
|
|
7
|
+
# Repository: https://github.com/paulpreibisch/AgentVibes
|
|
8
|
+
#
|
|
9
|
+
# Co-created by Paul Preibisch with Claude AI
|
|
10
|
+
# Copyright (c) 2025 Paul Preibisch
|
|
11
|
+
#
|
|
12
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
+
# you may not use this file except in compliance with the License.
|
|
14
|
+
# You may obtain a copy of the License at
|
|
15
|
+
#
|
|
16
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
+
#
|
|
18
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
19
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
+
# See the License for the specific language governing permissions and
|
|
22
|
+
# limitations under the License.
|
|
23
|
+
#
|
|
24
|
+
# DISCLAIMER: This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
25
|
+
# express or implied. Use at your own risk. See the Apache License for details.
|
|
26
|
+
#
|
|
27
|
+
# ---
|
|
28
|
+
#
|
|
29
|
+
# @fileoverview Text translator for multi-language TTS and learning mode
|
|
30
|
+
# @context Provides automatic translation using Google Translate via deep-translator library
|
|
31
|
+
# @architecture Standalone CLI module callable from bash scripts, with library mode for Python imports
|
|
32
|
+
# @dependencies deep-translator, langdetect (pip install deep-translator langdetect)
|
|
33
|
+
# @entrypoints CLI: python3 translator.py <text> <target_lang>, Library: from translator import translate
|
|
34
|
+
# @patterns Command pattern - supports translate, detect, and batch operations
|
|
35
|
+
# @related play-tts.sh, learn-manager.sh, language-manager.sh
|
|
36
|
+
#
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
Text translation utilities for AgentVibes multi-language TTS.
|
|
40
|
+
|
|
41
|
+
Provides automatic translation of TTS text to the user's preferred language,
|
|
42
|
+
supporting both BMAD communication_language settings and learning mode.
|
|
43
|
+
|
|
44
|
+
Usage:
|
|
45
|
+
CLI: python3 translator.py <text> <target_language>
|
|
46
|
+
Library: from translator import translate, detect_language
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
import sys
|
|
50
|
+
import os
|
|
51
|
+
from typing import Optional, Tuple
|
|
52
|
+
|
|
53
|
+
# Language name to ISO code mapping
|
|
54
|
+
LANG_CODES = {
|
|
55
|
+
'spanish': 'es', 'español': 'es', 'es': 'es',
|
|
56
|
+
'french': 'fr', 'français': 'fr', 'fr': 'fr',
|
|
57
|
+
'german': 'de', 'deutsch': 'de', 'de': 'de',
|
|
58
|
+
'italian': 'it', 'italiano': 'it', 'it': 'it',
|
|
59
|
+
'portuguese': 'pt', 'português': 'pt', 'pt': 'pt',
|
|
60
|
+
'chinese': 'zh-CN', 'mandarin': 'zh-CN', 'zh': 'zh-CN', '中文': 'zh-CN',
|
|
61
|
+
'japanese': 'ja', '日本語': 'ja', 'ja': 'ja',
|
|
62
|
+
'korean': 'ko', '한국어': 'ko', 'ko': 'ko',
|
|
63
|
+
'russian': 'ru', 'русский': 'ru', 'ru': 'ru',
|
|
64
|
+
'polish': 'pl', 'polski': 'pl', 'pl': 'pl',
|
|
65
|
+
'dutch': 'nl', 'nederlands': 'nl', 'nl': 'nl',
|
|
66
|
+
'turkish': 'tr', 'türkçe': 'tr', 'tr': 'tr',
|
|
67
|
+
'arabic': 'ar', 'العربية': 'ar', 'ar': 'ar',
|
|
68
|
+
'hindi': 'hi', 'हिन्दी': 'hi', 'hi': 'hi',
|
|
69
|
+
'swedish': 'sv', 'svenska': 'sv', 'sv': 'sv',
|
|
70
|
+
'danish': 'da', 'dansk': 'da', 'da': 'da',
|
|
71
|
+
'norwegian': 'no', 'norsk': 'no', 'no': 'no',
|
|
72
|
+
'finnish': 'fi', 'suomi': 'fi', 'fi': 'fi',
|
|
73
|
+
'czech': 'cs', 'čeština': 'cs', 'cs': 'cs',
|
|
74
|
+
'romanian': 'ro', 'română': 'ro', 'ro': 'ro',
|
|
75
|
+
'ukrainian': 'uk', 'українська': 'uk', 'uk': 'uk',
|
|
76
|
+
'greek': 'el', 'ελληνικά': 'el', 'el': 'el',
|
|
77
|
+
'bulgarian': 'bg', 'български': 'bg', 'bg': 'bg',
|
|
78
|
+
'croatian': 'hr', 'hrvatski': 'hr', 'hr': 'hr',
|
|
79
|
+
'slovak': 'sk', 'slovenčina': 'sk', 'sk': 'sk',
|
|
80
|
+
'english': 'en', 'en': 'en',
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_lang_code(language: str) -> str:
|
|
85
|
+
"""
|
|
86
|
+
Convert language name to ISO code.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
language: Language name or code (e.g., 'spanish', 'es', 'español')
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
ISO language code (e.g., 'es')
|
|
93
|
+
"""
|
|
94
|
+
lang_lower = language.lower().strip()
|
|
95
|
+
return LANG_CODES.get(lang_lower, lang_lower)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def detect_language(text: str) -> Optional[str]:
|
|
99
|
+
"""
|
|
100
|
+
Detect the language of given text.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
text: Text to analyze
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Language code (e.g., 'es', 'fr', 'en') or None if detection fails
|
|
107
|
+
"""
|
|
108
|
+
if not text or len(text.strip()) < 3:
|
|
109
|
+
return None
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
from langdetect import detect, LangDetectException
|
|
113
|
+
return detect(text)
|
|
114
|
+
except ImportError:
|
|
115
|
+
print("Warning: langdetect not installed. Run: pip install langdetect", file=sys.stderr)
|
|
116
|
+
return None
|
|
117
|
+
except Exception:
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def translate(text: str, target_lang: str, source_lang: str = 'en') -> Tuple[str, bool]:
|
|
122
|
+
"""
|
|
123
|
+
Translate text to target language.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
text: Text to translate
|
|
127
|
+
target_lang: Target language (name or code)
|
|
128
|
+
source_lang: Source language (default: 'en')
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
Tuple of (translated_text, success)
|
|
132
|
+
"""
|
|
133
|
+
if not text or not text.strip():
|
|
134
|
+
return text, False
|
|
135
|
+
|
|
136
|
+
# Convert language names to codes
|
|
137
|
+
target_code = get_lang_code(target_lang)
|
|
138
|
+
source_code = get_lang_code(source_lang)
|
|
139
|
+
|
|
140
|
+
# Skip if source and target are the same
|
|
141
|
+
if target_code == source_code:
|
|
142
|
+
return text, False
|
|
143
|
+
|
|
144
|
+
# Skip if target is English and source is also English
|
|
145
|
+
if target_code == 'en' and source_code == 'en':
|
|
146
|
+
return text, False
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
from deep_translator import GoogleTranslator
|
|
150
|
+
|
|
151
|
+
translator = GoogleTranslator(source=source_code, target=target_code)
|
|
152
|
+
translated = translator.translate(text)
|
|
153
|
+
|
|
154
|
+
if translated:
|
|
155
|
+
return translated, True
|
|
156
|
+
return text, False
|
|
157
|
+
|
|
158
|
+
except ImportError:
|
|
159
|
+
print("Error: deep-translator not installed. Run: pip install deep-translator", file=sys.stderr)
|
|
160
|
+
return text, False
|
|
161
|
+
except Exception as e:
|
|
162
|
+
print(f"Translation error: {e}", file=sys.stderr)
|
|
163
|
+
return text, False
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def translate_auto(text: str, target_lang: str) -> Tuple[str, bool, Optional[str]]:
|
|
167
|
+
"""
|
|
168
|
+
Translate text to target language with auto-detection of source language.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
text: Text to translate
|
|
172
|
+
target_lang: Target language (name or code)
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Tuple of (translated_text, success, detected_source_lang)
|
|
176
|
+
"""
|
|
177
|
+
if not text or not text.strip():
|
|
178
|
+
return text, False, None
|
|
179
|
+
|
|
180
|
+
# Detect source language
|
|
181
|
+
detected = detect_language(text)
|
|
182
|
+
|
|
183
|
+
# Convert target to code
|
|
184
|
+
target_code = get_lang_code(target_lang)
|
|
185
|
+
|
|
186
|
+
# Skip if detected language matches target
|
|
187
|
+
if detected and detected == target_code:
|
|
188
|
+
return text, False, detected
|
|
189
|
+
|
|
190
|
+
# Translate
|
|
191
|
+
translated, success = translate(text, target_lang, source_lang=detected or 'en')
|
|
192
|
+
return translated, success, detected
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def main():
|
|
196
|
+
"""CLI entry point for translator."""
|
|
197
|
+
if len(sys.argv) < 3:
|
|
198
|
+
print("Usage: translator.py <text> <target_language> [source_language]", file=sys.stderr)
|
|
199
|
+
print(" translator.py detect <text>", file=sys.stderr)
|
|
200
|
+
print("", file=sys.stderr)
|
|
201
|
+
print("Examples:", file=sys.stderr)
|
|
202
|
+
print(" translator.py 'Hello world' spanish", file=sys.stderr)
|
|
203
|
+
print(" translator.py 'Hello world' es en", file=sys.stderr)
|
|
204
|
+
print(" translator.py detect 'Hola mundo'", file=sys.stderr)
|
|
205
|
+
sys.exit(1)
|
|
206
|
+
|
|
207
|
+
command = sys.argv[1]
|
|
208
|
+
|
|
209
|
+
# Detection mode
|
|
210
|
+
if command == 'detect':
|
|
211
|
+
if len(sys.argv) < 3:
|
|
212
|
+
print("Usage: translator.py detect <text>", file=sys.stderr)
|
|
213
|
+
sys.exit(1)
|
|
214
|
+
text = sys.argv[2]
|
|
215
|
+
detected = detect_language(text)
|
|
216
|
+
if detected:
|
|
217
|
+
print(detected)
|
|
218
|
+
else:
|
|
219
|
+
print("unknown")
|
|
220
|
+
sys.exit(0)
|
|
221
|
+
|
|
222
|
+
# Translation mode
|
|
223
|
+
text = sys.argv[1]
|
|
224
|
+
target_lang = sys.argv[2]
|
|
225
|
+
source_lang = sys.argv[3] if len(sys.argv) > 3 else 'en'
|
|
226
|
+
|
|
227
|
+
translated, success = translate(text, target_lang, source_lang)
|
|
228
|
+
|
|
229
|
+
# Output the result (for shell script consumption)
|
|
230
|
+
print(translated)
|
|
231
|
+
|
|
232
|
+
# Exit with appropriate code
|
|
233
|
+
sys.exit(0 if success else 1)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
if __name__ == '__main__':
|
|
237
|
+
main()
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
[](https://github.com/paulpreibisch/AgentVibes/actions/workflows/publish.yml)
|
|
12
12
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
13
13
|
|
|
14
|
-
**Author**: Paul Preibisch ([@997Fire](https://x.com/997Fire)) | **Version**: v2.
|
|
14
|
+
**Author**: Paul Preibisch ([@997Fire](https://x.com/997Fire)) | **Version**: v2.14.0
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
@@ -94,16 +94,17 @@ Whether you're coding in Claude Code, chatting in Claude Desktop, or using Warp
|
|
|
94
94
|
|
|
95
95
|
## 📰 Latest Release
|
|
96
96
|
|
|
97
|
-
**[v2.
|
|
97
|
+
**[v2.14.0 - Auto-Translation for BMAD & Learning Mode](https://github.com/paulpreibisch/AgentVibes/releases/tag/v2.14.0)** 🎉
|
|
98
98
|
|
|
99
|
-
AgentVibes v2.
|
|
99
|
+
AgentVibes v2.14.0 introduces automatic translation for TTS output (Issues #50 and #51). When AgentVibes speaks acknowledgments like "Starting the build" or completions like "All tests passed!", this text is normally in English. Now, BMAD users who set `communication_language: Spanish` in `.bmad/core/config.yaml` will hear these spoken messages automatically translated to Spanish - matching their project's communication preference. This version also updates our Language Learning Mode feature to utilize Google Deep Translate, reducing token usage (Claude no longer needs to do the translation! Google now does it for free!).
|
|
100
100
|
|
|
101
101
|
**Key Highlights:**
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
102
|
+
- 🌐 **BMAD Multi-Language TTS** - Auto-detect `communication_language` from BMAD config and translate TTS
|
|
103
|
+
- 🎓 **Learning Mode Auto-Translation** - Hear English + auto-translated target language (Google does it free!)
|
|
104
|
+
- 🔄 **Translation Manager** - New `/agent-vibes:translate` command for manual control
|
|
105
|
+
- 🐍 **translator.py** - Core translation engine using deep-translator (Google Translate)
|
|
106
|
+
- ✅ **140 Tests Passing** - 18 new translation tests + all existing tests
|
|
107
|
+
- 🔄 **Zero Breaking Changes** - Fully backward compatible with v2.13.9
|
|
107
108
|
|
|
108
109
|
💡 **Tip:** If `npx agentvibes` shows an older version or missing commands, clear your npm cache: `npm cache clean --force && npx agentvibes@latest --help`
|
|
109
110
|
|