by @ulds · python
#!/usr/bin/env python3
"""
Google Translate CLI - Interactive Translation Tool
"""
import sys
import requests
from urllib.parse import urlencode
from typing import Optional, Dict, Any
import json
import re
class Colors:
"""ANSI color codes for terminal output"""
HEADER = '\033[95m'
BLUE = '\033[94m'
CYAN = '\033[96m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
END = '\033[0m'
BOLD = '\033[1m'
class GoogleTranslator:
def _init_(self, host: str = 'translate.google.com'):
self.host = host
self.base_url = f'https://{host}/translate_a/single'
def translate(self, text: str, from_lang: str = 'auto', to_lang: str = 'en') -> Dict[str, Any]:
"""Translate text from source language to target language"""
url = self.base_url + '?client=at&dt=t&dt=rm&dj=1'
params = {
'sl': from_lang,
'tl': to_lang,
'q': text
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
'User-Agent': 'Mozilla/5.0'
}
try:
response = requests.post(
url,
data=urlencode(params),
headers=headers,
timeout=10
)
if response.status_code == 429:
error_info = self._extract_rate_limit_info(response.text)
raise Exception(f"Too Many Requests - {error_info}")
response.raise_for_status()
raw = response.json()
# Extract translated text
sentences = raw.get('sentences', [])
translated_text = ''.join(
s.get('trans', '') for s in sentences if 'trans' in s
)
return {
'text': translated_text,
'raw': raw,
'detected_lang': raw.get('src', 'unknown'),
'confidence': raw.get('confidence', 0)
}
except requests.exceptions.RequestException as e:
raise Exception(f"Translation failed: {str(e)}")
def _extract_rate_limit_info(self, html: str) -> str:
"""Extract rate limit information from error page"""
ip = re.search(r'IP address: (.+?)<br>', html)
time = re.search(r'Time: (.+?)<br>', html)
url = re.search(r'URL: (.+?)<br>', html)
info = []
if ip:
info.append(f"IP: {ip.group(1)}")
if time:
info.append(f"Time: {time.group(1)}")
if url:
info.append(f"URL: {url.group(1).replace('&', '&')}")
return ', '.join(info) if info else 'Rate limit exceeded'
class TranslateCLI:
def _init_(self):
self.translator = GoogleTranslator()
self.popular_languages = {
'en': 'English',
'id': 'Indonesian',
'es': 'Spanish',
'fr': 'French',
'de': 'German',
'it': 'Italian',
'pt': 'Portuguese',
'ru': 'Russian',
'ja': 'Japanese',
'ko': 'Korean',
'zh-CN': 'Chinese (Simplified)',
'zh-TW': 'Chinese (Traditional)',
'ar': 'Arabic',
'hi': 'Hindi',
'th': 'Thai',
'vi': 'Vietnamese',
'nl': 'Dutch',
'tr': 'Turkish',
'pl': 'Polish',
'sv': 'Swedish'
}
def print_header(self):
"""Print CLI header"""
print(f"\n{Colors.CYAN}{Colors.BOLD}{'='*60}")
print(f" Google Translate CLI - Interactive Mode")
print(f"{'='*60}{Colors.END}\n")
def print_languages(self):
"""Display popular languages"""
print(f"{Colors.YELLOW}Popular Languages:{Colors.END}")
for i, (code, name) in enumerate(self.popular_languages.items(), 1):
print(f" {code:8} - {name}", end='')
if i % 2 == 0:
print()
if len(self.popular_languages) % 2 != 0:
print()
print(f" {'auto':8} - Auto Detect")
print()
def get_input(self, prompt: str, default: str = '') -> str:
"""Get user input with default value"""
if default:
prompt = f"{prompt} [{default}]: "
else:
prompt = f"{prompt}: "
value = input(f"{Colors.BLUE}{prompt}{Colors.END}").strip()
return value if value else default
def translate_interactive(self):
"""Interactive translation mode"""
from_lang = self.get_input("Source language (or 'auto')", "auto")
to_lang = self.get_input("Target language", "en")
print(f"\n{Colors.GREEN}Ready to translate! Type 'quit' or 'exit' to stop.{Colors.END}")
print(f"{Colors.GREEN}Type 'change' to change languages.{Colors.END}\n")
while True:
text = input(f"{Colors.CYAN}Text to translate: {Colors.END}").strip()
if not text:
continue
if text.lower() in ['quit', 'exit', 'q']:
print(f"\n{Colors.YELLOW}Goodbye!{Colors.END}\n")
break
if text.lower() == 'change':
from_lang = self.get_input("Source language (or 'auto')", from_lang)
to_lang = self.get_input("Target language", to_lang)
print()
continue
try:
result = self.translator.translate(text, from_lang, to_lang)
print(f"\n{Colors.GREEN}Translation:{Colors.END}")
print(f" {Colors.BOLD}{result['text']}{Colors.END}")
if from_lang == 'auto' and result['detected_lang']:
lang_name = self.popular_languages.get(
result['detected_lang'],
result['detected_lang']
)
print(f"\n{Colors.YELLOW}Detected: {lang_name} ({result['detected_lang']}){Colors.END}")
if result['confidence'] > 0:
print(f"{Colors.YELLOW}Confidence: {result['confidence']:.2%}{Colors.END}")
print()
except Exception as e:
print(f"\n{Colors.RED}Error: {str(e)}{Colors.END}\n")
def translate_single(self, text: str, from_lang: str, to_lang: str):
"""Single translation mode"""
try:
result = self.translator.translate(text, from_lang, to_lang)
print(result['text'])
return 0
except Exception as e:
print(f"Error: {str(e)}", file=sys.stderr)
return 1
def run(self, args: list):
"""Main CLI entry point"""
if len(args) == 1:
# Interactive mode
self.print_header()
self.print_languages()
self.translate_interactive()
elif len(args) == 4:
# Single translation: python translate.py "text" from to
text, from_lang, to_lang = args[1], args[2], args[3]
return self.translate_single(text, from_lang, to_lang)
else:
print("Usage:")
print(f" Interactive mode: {args[0]}")
print(f" Single translation: {args[0]} \"text\" from_lang to_lang")
print(f"\nExample:")
print(f" {args[0]} \"Hello world\" en id")
return 1
def main():
try:
cli = TranslateCLI()
return cli.run(sys.argv)
except KeyboardInterrupt:
print(f"\n\n{Colors.YELLOW}Interrupted by user{Colors.END}\n")
return 0
except Exception as e:
print(f"\n{Colors.RED}Fatal error: {str(e)}{Colors.END}\n", file=sys.stderr)
return 1
if _name_ == '_main_':
sys.exit(main())