Skip to content

Commit 966f548

Browse files
konardclaude
andcommitted
Implement VK Bot translation word API feature
- Add translation patterns for Russian and English queries - Implement translate_word() method with language detection - Support queries like "Как перевести X на английский?" and "How to translate X?" - Use MyMemory free translation API with proper URL encoding - Respond in the same language as the query - Add comprehensive tests for pattern matching and API functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent bffb2d6 commit 966f548

File tree

7 files changed

+422
-2
lines changed

7 files changed

+422
-2
lines changed

examples/manual_test.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""Manual test for translation logic without external dependencies."""
4+
5+
import re
6+
7+
def test_russian_detection():
8+
"""Test Russian character detection logic."""
9+
test_cases = [
10+
("Как перевести hello на английский?", True),
11+
("How to translate красота?", False),
12+
("как переводится beautiful", True),
13+
("translate house", False),
14+
("перевод машина", True),
15+
]
16+
17+
print("Testing Russian character detection:")
18+
print("-" * 40)
19+
20+
for text, expected in test_cases:
21+
is_russian = bool(re.search(r'[а-яё]', text, re.IGNORECASE))
22+
result = "✓" if is_russian == expected else "✗"
23+
print(f"{result} '{text}' -> Russian: {is_russian} (expected: {expected})")
24+
25+
print()
26+
27+
def test_word_extraction():
28+
"""Test word extraction from various patterns."""
29+
patterns_and_tests = [
30+
# Pattern similar to TRANSLATE_TO_ENGLISH_RU
31+
(r'(как перевести|как переводится)\s+(.+?)\s+(на английский|на англ)',
32+
"Как перевести hello на английский?", "hello"),
33+
34+
# Pattern similar to TRANSLATE_TO_RUSSIAN_RU
35+
(r'(как переводится|как перевести)\s+(.+?)(\?|$)',
36+
"Как переводится beautiful?", "beautiful"),
37+
38+
# Pattern similar to TRANSLATE_TO_ENGLISH_EN
39+
(r'(how to translate|what is translation of)\s+(.+?)(\?|$)',
40+
"How to translate красота?", "красота"),
41+
42+
# Pattern similar to TRANSLATE_WORD
43+
(r'(translate|перевести|переводить|перевод)\s+(.+?)(\?|$)',
44+
"translate house", "house"),
45+
]
46+
47+
print("Testing word extraction patterns:")
48+
print("-" * 40)
49+
50+
for pattern, text, expected_word in patterns_and_tests:
51+
match = re.search(pattern, text, re.IGNORECASE)
52+
if match:
53+
extracted = match.group(2).strip()
54+
result = "✓" if extracted == expected_word else "✗"
55+
print(f"{result} '{text}' -> '{extracted}' (expected: '{expected_word}')")
56+
else:
57+
print(f"✗ '{text}' -> No match")
58+
59+
print()
60+
61+
def test_language_logic():
62+
"""Test the language detection and translation direction logic."""
63+
print("Testing translation direction logic (updated):")
64+
print("-" * 40)
65+
66+
test_cases = [
67+
("Как перевести hello на английский?", "hello", "en->ru"),
68+
("How to translate красота?", "красота", "ru->en"),
69+
("Как переводится beautiful?", "beautiful", "en->ru"),
70+
("translate house", "house", "en->ru"),
71+
("перевод машина", "машина", "ru->en"),
72+
]
73+
74+
for msg, word, expected_direction in test_cases:
75+
# Use updated logic: check message without the word
76+
message_without_word = msg.replace(word, '')
77+
is_russian_message = bool(re.search(r'[а-яё]', message_without_word, re.IGNORECASE))
78+
word_is_russian = bool(re.search(r'[а-яё]', word, re.IGNORECASE))
79+
80+
# Simplified logic: translate based on word language
81+
if word_is_russian:
82+
source_lang = 'ru'
83+
target_lang = 'en'
84+
else:
85+
source_lang = 'en'
86+
target_lang = 'ru'
87+
88+
actual_direction = f"{source_lang}->{target_lang}"
89+
90+
result = "✓" if expected_direction == actual_direction else "✗"
91+
print(f"{result} '{msg}' with word '{word}':")
92+
print(f" Expected: {expected_direction}")
93+
print(f" Actual: {actual_direction}")
94+
print()
95+
96+
if __name__ == '__main__':
97+
test_russian_detection()
98+
test_word_extraction()
99+
test_language_logic()

examples/test_api.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""Test the actual translation API."""
4+
5+
import json
6+
import urllib.request
7+
import urllib.parse
8+
9+
def test_translation_api():
10+
"""Test MyMemory translation API."""
11+
print("Testing MyMemory Translation API:")
12+
print("=" * 40)
13+
14+
test_cases = [
15+
('hello', 'en', 'ru'),
16+
('beautiful', 'en', 'ru'),
17+
('красота', 'ru', 'en'),
18+
('дом', 'ru', 'en'),
19+
('house', 'en', 'ru'),
20+
]
21+
22+
for word, source, target in test_cases:
23+
try:
24+
# URL encode the word to handle special characters
25+
encoded_word = urllib.parse.quote(word)
26+
url = f"https://api.mymemory.translated.net/get?q={encoded_word}&langpair={source}|{target}"
27+
28+
print(f"\nTranslating '{word}' from {source} to {target}...")
29+
print(f"URL: {url}")
30+
31+
with urllib.request.urlopen(url, timeout=10) as response:
32+
data = json.loads(response.read().decode())
33+
34+
if data.get('responseStatus') == 200:
35+
translation = data.get('responseData', {}).get('translatedText', '')
36+
print(f"✓ Result: '{word}' -> '{translation}'")
37+
else:
38+
print(f"✗ API Error: {data.get('responseStatus')} - {data.get('responseDetails', 'Unknown error')}")
39+
40+
except Exception as e:
41+
print(f"✗ Network Error: {e}")
42+
43+
if __name__ == '__main__':
44+
test_translation_api()

examples/test_final_logic.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""Test the final translation logic according to issue requirements."""
4+
5+
import re
6+
7+
def test_translation_logic():
8+
"""Test complete translation logic according to issue requirements."""
9+
print("Testing Final Translation Logic:")
10+
print("=" * 50)
11+
12+
test_cases = [
13+
# Issue examples
14+
{
15+
'msg': 'Как перевести hello на английский?',
16+
'word': 'hello',
17+
'expected_source': 'en',
18+
'expected_target': 'en', # Explicitly asking for English
19+
'expected_response_lang': 'russian',
20+
'expected_format': '"hello" переводится как "привет"'
21+
},
22+
{
23+
'msg': 'Как переводится beautiful?',
24+
'word': 'beautiful',
25+
'expected_source': 'en',
26+
'expected_target': 'ru', # Inferred Russian target
27+
'expected_response_lang': 'russian',
28+
'expected_format': '"beautiful" переводится как "красивый"'
29+
},
30+
{
31+
'msg': 'How to translate красота?',
32+
'word': 'красота',
33+
'expected_source': 'ru',
34+
'expected_target': 'en', # Inferred English target
35+
'expected_response_lang': 'english',
36+
'expected_format': '"красота" translates to "beauty"'
37+
},
38+
{
39+
'msg': 'What is translation of дом?',
40+
'word': 'дом',
41+
'expected_source': 'ru',
42+
'expected_target': 'en', # Inferred English target
43+
'expected_response_lang': 'english',
44+
'expected_format': '"дом" translates to "house"'
45+
},
46+
# Additional test cases
47+
{
48+
'msg': 'translate house',
49+
'word': 'house',
50+
'expected_source': 'en',
51+
'expected_target': 'ru', # English word -> Russian
52+
'expected_response_lang': 'english',
53+
'expected_format': '"house" translates to "дом"'
54+
}
55+
]
56+
57+
for i, case in enumerate(test_cases, 1):
58+
print(f"\nTest {i}: {case['msg']}")
59+
print("-" * 40)
60+
61+
msg = case['msg']
62+
word = case['word']
63+
64+
# Apply the logic from the implementation
65+
message_without_word = msg.replace(word, '')
66+
is_russian_message = bool(re.search(r'[а-яё]', message_without_word, re.IGNORECASE))
67+
word_is_russian = bool(re.search(r'[а-яё]', word, re.IGNORECASE))
68+
69+
if re.search(r'на английский|на англ', msg, re.IGNORECASE):
70+
# Explicitly asking for English translation
71+
source_lang = 'ru' if word_is_russian else 'en'
72+
target_lang = 'en'
73+
response_in_russian = True
74+
elif is_russian_message:
75+
# Russian message without explicit target - infer target language
76+
if word_is_russian:
77+
source_lang = 'ru'
78+
target_lang = 'en'
79+
else:
80+
source_lang = 'en'
81+
target_lang = 'ru'
82+
response_in_russian = True
83+
else:
84+
# English message - infer target as English
85+
if word_is_russian:
86+
source_lang = 'ru'
87+
target_lang = 'en'
88+
else:
89+
# English word in English message - might want Russian translation
90+
source_lang = 'en'
91+
target_lang = 'ru'
92+
response_in_russian = False
93+
94+
# Check results
95+
source_ok = source_lang == case['expected_source']
96+
target_ok = target_lang == case['expected_target']
97+
response_lang_ok = (
98+
(response_in_russian and case['expected_response_lang'] == 'russian') or
99+
(not response_in_russian and case['expected_response_lang'] == 'english')
100+
)
101+
102+
print(f"Word: '{word}' ({'Russian' if word_is_russian else 'English'} detected)")
103+
print(f"Message language: {'Russian' if is_russian_message else 'English'}")
104+
print(f"Source language: {source_lang} {'✓' if source_ok else '✗ (expected ' + case['expected_source'] + ')'}")
105+
print(f"Target language: {target_lang} {'✓' if target_ok else '✗ (expected ' + case['expected_target'] + ')'}")
106+
print(f"Response language: {'Russian' if response_in_russian else 'English'} {'✓' if response_lang_ok else '✗ (expected ' + case['expected_response_lang'] + ')'}")
107+
108+
all_ok = source_ok and target_ok and response_lang_ok
109+
print(f"Overall result: {'✓ PASS' if all_ok else '✗ FAIL'}")
110+
111+
if __name__ == '__main__':
112+
test_translation_logic()

examples/test_translation.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""Test script for translation patterns."""
4+
5+
import sys
6+
import os
7+
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
8+
9+
from regex import match
10+
import patterns
11+
12+
def test_pattern(pattern, text, expected_word):
13+
"""Test if pattern matches text and extracts expected word."""
14+
matched = match(pattern, text)
15+
if matched:
16+
word = matched.group('word')
17+
print(f"✓ Pattern matched: '{text}' -> word: '{word}'")
18+
if word.strip() == expected_word:
19+
print(f" ✓ Extracted word matches expected: '{expected_word}'")
20+
return True
21+
else:
22+
print(f" ✗ Expected '{expected_word}', got '{word.strip()}'")
23+
return False
24+
else:
25+
print(f"✗ Pattern did NOT match: '{text}'")
26+
return False
27+
28+
def run_tests():
29+
"""Run all pattern tests."""
30+
print("Testing Translation Patterns")
31+
print("=" * 50)
32+
33+
test_cases = [
34+
# Russian patterns asking for English translation
35+
(patterns.TRANSLATE_TO_ENGLISH_RU, "Как перевести hello на английский?", "hello"),
36+
(patterns.TRANSLATE_TO_ENGLISH_RU, "как переводится world на англ", "world"),
37+
(patterns.TRANSLATE_TO_ENGLISH_RU, "Как перевести красивый на английский", "красивый"),
38+
39+
# Russian patterns asking for translation (inferred as Russian target)
40+
(patterns.TRANSLATE_TO_RUSSIAN_RU, "Как переводится beautiful?", "beautiful"),
41+
(patterns.TRANSLATE_TO_RUSSIAN_RU, "как перевести computer", "computer"),
42+
43+
# English patterns asking for translation
44+
(patterns.TRANSLATE_TO_ENGLISH_EN, "How to translate красота?", "красота"),
45+
(patterns.TRANSLATE_TO_ENGLISH_EN, "What is translation of дом", "дом"),
46+
47+
# Generic translate pattern
48+
(patterns.TRANSLATE_WORD, "translate house", "house"),
49+
(patterns.TRANSLATE_WORD, "перевести дом", "дом"),
50+
(patterns.TRANSLATE_WORD, "перевод машина", "машина"),
51+
]
52+
53+
passed = 0
54+
total = len(test_cases)
55+
56+
for i, (pattern, text, expected_word) in enumerate(test_cases, 1):
57+
print(f"\nTest {i}/{total}:")
58+
if test_pattern(pattern, text, expected_word):
59+
passed += 1
60+
61+
print(f"\n" + "=" * 50)
62+
print(f"Results: {passed}/{total} tests passed")
63+
64+
if passed == total:
65+
print("🎉 All tests passed!")
66+
return True
67+
else:
68+
print(f"❌ {total - passed} tests failed")
69+
return False
70+
71+
if __name__ == '__main__':
72+
success = run_tests()
73+
sys.exit(0 if success else 1)

python/__main__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ def __init__(
6363
(patterns.WHAT_IS, self.commands.what_is),
6464
(patterns.WHAT_MEAN, self.commands.what_is),
6565
(patterns.APPLY_KARMA, self.commands.apply_karma),
66-
(patterns.GITHUB_COPILOT, self.commands.github_copilot)
66+
(patterns.GITHUB_COPILOT, self.commands.github_copilot),
67+
(patterns.TRANSLATE_TO_ENGLISH_RU, self.commands.translate_word),
68+
(patterns.TRANSLATE_TO_RUSSIAN_RU, self.commands.translate_word),
69+
(patterns.TRANSLATE_TO_ENGLISH_EN, self.commands.translate_word),
70+
(patterns.TRANSLATE_WORD, self.commands.translate_word)
6771
)
6872

6973
def message_new(

0 commit comments

Comments
 (0)