Chinese to English Input Translator

Automatically translates Chinese input to English in real-time

Size

8.2 KB

Version

1.0.1

Created

Nov 9, 2025

Updated

about 1 month ago

1// ==UserScript==
2// @name		Chinese to English Input Translator
3// @description		Automatically translates Chinese input to English in real-time
4// @version		1.0.1
5// @match		https://*.robomonkey.io/*
6// @icon		https://robomonkey.io/icon.png?adc3438f5fbb5315
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('Chinese to English Input Translator: Extension loaded');
12
13    // Debounce function to avoid excessive API calls
14    function debounce(func, wait) {
15        let timeout;
16        return function executedFunction(...args) {
17            const later = () => {
18                clearTimeout(timeout);
19                func(...args);
20            };
21            clearTimeout(timeout);
22            timeout = setTimeout(later, wait);
23        };
24    }
25
26    // Check if text contains Chinese characters
27    function containsChinese(text) {
28        return /[\u4e00-\u9fa5]/.test(text);
29    }
30
31    // Show loading indicator
32    function showLoadingIndicator(element) {
33        const existingIndicator = element.parentElement.querySelector('.translation-loading');
34        if (existingIndicator) return;
35
36        const indicator = document.createElement('div');
37        indicator.className = 'translation-loading';
38        indicator.textContent = '🔄 Translating...';
39        indicator.style.cssText = `
40            position: absolute;
41            background: #007bff;
42            color: white;
43            padding: 4px 8px;
44            border-radius: 4px;
45            font-size: 12px;
46            z-index: 10000;
47            pointer-events: none;
48            box-shadow: 0 2px 8px rgba(0,0,0,0.2);
49        `;
50        
51        const rect = element.getBoundingClientRect();
52        indicator.style.top = (rect.top + window.scrollY - 30) + 'px';
53        indicator.style.left = (rect.left + window.scrollX) + 'px';
54        
55        document.body.appendChild(indicator);
56    }
57
58    // Hide loading indicator
59    function hideLoadingIndicator() {
60        const indicators = document.querySelectorAll('.translation-loading');
61        indicators.forEach(indicator => indicator.remove());
62    }
63
64    // Show translation result
65    function showTranslationResult(element, originalText, translatedText) {
66        hideLoadingIndicator();
67        
68        const result = document.createElement('div');
69        result.className = 'translation-result';
70        result.innerHTML = `
71            <div style="margin-bottom: 4px;">
72                <strong>Original:</strong> ${originalText}
73            </div>
74            <div style="margin-bottom: 8px;">
75                <strong>Translation:</strong> ${translatedText}
76            </div>
77            <button class="use-translation-btn" style="
78                background: #28a745;
79                color: white;
80                border: none;
81                padding: 6px 12px;
82                border-radius: 4px;
83                cursor: pointer;
84                font-size: 12px;
85                margin-right: 8px;
86            ">Use Translation</button>
87            <button class="close-translation-btn" style="
88                background: #dc3545;
89                color: white;
90                border: none;
91                padding: 6px 12px;
92                border-radius: 4px;
93                cursor: pointer;
94                font-size: 12px;
95            ">Close</button>
96        `;
97        result.style.cssText = `
98            position: absolute;
99            background: white;
100            border: 2px solid #007bff;
101            padding: 12px;
102            border-radius: 8px;
103            font-size: 13px;
104            z-index: 10001;
105            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
106            max-width: 400px;
107            color: #333;
108        `;
109        
110        const rect = element.getBoundingClientRect();
111        result.style.top = (rect.bottom + window.scrollY + 5) + 'px';
112        result.style.left = (rect.left + window.scrollX) + 'px';
113        
114        document.body.appendChild(result);
115
116        // Use translation button
117        result.querySelector('.use-translation-btn').addEventListener('click', () => {
118            element.value = translatedText;
119            element.dispatchEvent(new Event('input', { bubbles: true }));
120            element.dispatchEvent(new Event('change', { bubbles: true }));
121            result.remove();
122            console.log('Translation applied:', translatedText);
123        });
124
125        // Close button
126        result.querySelector('.close-translation-btn').addEventListener('click', () => {
127            result.remove();
128        });
129
130        // Auto-close after 15 seconds
131        setTimeout(() => {
132            if (result.parentElement) {
133                result.remove();
134            }
135        }, 15000);
136    }
137
138    // Translate text using AI
139    async function translateText(text, element) {
140        try {
141            console.log('Translating Chinese text:', text);
142            showLoadingIndicator(element);
143
144            const translation = await RM.aiCall(
145                `Translate the following Chinese text to English. Only return the English translation, nothing else: "${text}"`,
146                {
147                    type: "json_schema",
148                    json_schema: {
149                        name: "translation",
150                        schema: {
151                            type: "object",
152                            properties: {
153                                translation: { type: "string" }
154                            },
155                            required: ["translation"]
156                        }
157                    }
158                }
159            );
160
161            console.log('Translation result:', translation);
162            showTranslationResult(element, text, translation.translation);
163
164        } catch (error) {
165            console.error('Translation failed:', error);
166            hideLoadingIndicator();
167            
168            // Show error message
169            const errorMsg = document.createElement('div');
170            errorMsg.textContent = '❌ Translation failed. Please try again.';
171            errorMsg.style.cssText = `
172                position: absolute;
173                background: #dc3545;
174                color: white;
175                padding: 8px 12px;
176                border-radius: 4px;
177                font-size: 12px;
178                z-index: 10000;
179            `;
180            const rect = element.getBoundingClientRect();
181            errorMsg.style.top = (rect.top + window.scrollY - 30) + 'px';
182            errorMsg.style.left = (rect.left + window.scrollX) + 'px';
183            document.body.appendChild(errorMsg);
184            setTimeout(() => errorMsg.remove(), 3000);
185        }
186    }
187
188    // Handle input events
189    const handleInput = debounce(async (event) => {
190        const element = event.target;
191        const text = element.value.trim();
192
193        // Remove any existing translation results
194        document.querySelectorAll('.translation-result').forEach(el => el.remove());
195
196        // Check if text contains Chinese and is not empty
197        if (text && containsChinese(text)) {
198            console.log('Chinese input detected:', text);
199            await translateText(text, element);
200        }
201    }, 1000); // Wait 1 second after user stops typing
202
203    // Attach listeners to all input fields
204    function attachListeners() {
205        const inputs = document.querySelectorAll('input[type="text"], input:not([type]), textarea');
206        
207        inputs.forEach(input => {
208            if (!input.dataset.translatorAttached) {
209                input.dataset.translatorAttached = 'true';
210                input.addEventListener('input', handleInput);
211                console.log('Attached translator to input field');
212            }
213        });
214    }
215
216    // Initialize
217    function init() {
218        console.log('Initializing Chinese to English Input Translator');
219        
220        // Attach to existing inputs
221        attachListeners();
222
223        // Watch for new input fields being added to the page
224        const observer = new MutationObserver(debounce(() => {
225            attachListeners();
226        }, 500));
227
228        observer.observe(document.body, {
229            childList: true,
230            subtree: true
231        });
232
233        console.log('Chinese to English Input Translator: Ready');
234    }
235
236    // Start when DOM is ready
237    if (document.readyState === 'loading') {
238        document.addEventListener('DOMContentLoaded', init);
239    } else {
240        init();
241    }
242})();
Chinese to English Input Translator | Robomonkey