word-meaning-plugin 1.0.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/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # 📚 Word Meaning Plugin
2
+
3
+ A lightweight JavaScript plugin that adds instant word meaning functionality to any website. Simply select any word and see its definition, translation, and example sentence in a beautiful popup.
4
+
5
+ ## ✨ Features
6
+
7
+ - **Instant Meanings**: Select any word to see its meaning immediately
8
+ - **Bilingual Support**: English definitions with Hindi translations
9
+ - **Context-Aware**: Provides meanings based on surrounding text context
10
+ - **Text-to-Speech**: Listen to pronunciations in English and Hindi
11
+ - **Beautiful Design**: Modern, responsive popup with smooth animations
12
+ - **Zero Configuration**: Works out of the box with no setup required
13
+ - **Mobile Friendly**: Fully responsive design for all devices
14
+ - **Lightweight**: Small file size with minimal impact on page load
15
+
16
+ ## 🚀 Quick Start
17
+
18
+ ### Method 1: Simple Installation (Recommended)
19
+
20
+ Just add these two lines to your HTML file:
21
+
22
+ ```html
23
+ <!-- Add this to your HTML head -->
24
+ <link rel="stylesheet" href="word-meaning-plugin.css">
25
+
26
+ <!-- Add this before the closing </body> tag -->
27
+ <script src="word-meaning-plugin.js"></script>
28
+ ```
29
+
30
+ ### Method 2: JavaScript Only
31
+
32
+ If you prefer, you can add only the JavaScript file and it will automatically load the CSS:
33
+
34
+ ```html
35
+ <script src="word-meaning-plugin.js"></script>
36
+ ```
37
+
38
+ ### Method 3: CDN Installation (Coming Soon)
39
+
40
+ ```html
41
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/word-meaning-plugin@1.0/word-meaning-plugin.css">
42
+ <script src="https://cdn.jsdelivr.net/npm/word-meaning-plugin@1.0/word-meaning-plugin.js"></script>
43
+ ```
44
+
45
+ ## 📖 Usage
46
+
47
+ Once installed, the plugin works automatically:
48
+
49
+ 1. **Select any word** on your website by double-clicking or dragging
50
+ 2. **See the popup** appear with English meaning, Hindi translation, and example
51
+ 3. **Click the speaker icons** to hear pronunciations
52
+ 4. **Click anywhere else** to close the popup
53
+
54
+ ## 🔧 Advanced Configuration
55
+
56
+ You can access the plugin's public API through `window.wordMeaningPlugin`:
57
+
58
+ ```javascript
59
+ // Update API key (if you want to use your own)
60
+ window.wordMeaningPlugin.config.apiKey = 'your-huggingface-api-key';
61
+
62
+ // Manually hide the popup
63
+ window.wordMeaningPlugin.hidePopup();
64
+
65
+ // Use text-to-speech programmatically
66
+ window.wordMeaningPlugin.speakText('Hello world', 'en'); // English
67
+ window.wordMeaningPlugin.speakText('नमस्ते दुनिया', 'hi'); // Hindi
68
+ ```
69
+
70
+ ## 🎨 Customization
71
+
72
+ The plugin uses separate CSS for easy styling. You can override these styles:
73
+
74
+ ```css
75
+ /* Custom popup colors */
76
+ #word-meaning-popup {
77
+ background: your-custom-gradient;
78
+ border: your-custom-border;
79
+ }
80
+
81
+ /* Custom button styles */
82
+ #word-meaning-popup button {
83
+ background: your-button-color;
84
+ border-radius: your-border-radius;
85
+ }
86
+
87
+ /* Custom typography */
88
+ #word-meaning-popup strong {
89
+ color: your-accent-color;
90
+ font-size: your-font-size;
91
+ }
92
+ ```
93
+
94
+ ### CSS Features
95
+
96
+ - **Responsive Design**: Mobile-optimized styles
97
+ - **Dark Theme**: Automatic dark mode support
98
+ - **Accessibility**: High contrast and reduced motion support
99
+ - **Performance**: CSS animations for smooth interactions
100
+
101
+ ## 🌐 Browser Support
102
+
103
+ - Chrome 60+
104
+ - Firefox 55+
105
+ - Safari 11+
106
+ - Edge 79+
107
+
108
+ ## 📋 Requirements
109
+
110
+ - Modern web browser with JavaScript enabled
111
+ - Internet connection for API calls
112
+ - (Optional) HuggingFace API key for custom configuration
113
+
114
+ ## 🔒 API Usage
115
+
116
+ The plugin uses HuggingFace's API for word meanings. The default API key has usage limits. For production use, get your free API key from [HuggingFace](https://huggingface.co/) and update it:
117
+
118
+ ```javascript
119
+ window.wordMeaningPlugin.config.apiKey = 'your-api-key-here';
120
+ ```
121
+
122
+ ## 📁 File Structure
123
+
124
+ ```
125
+ word-meaning-plugin/
126
+ ├── word-meaning-plugin.js # Main plugin file
127
+ ├── word-meaning-plugin.css # Plugin styles
128
+ ├── demo.html # Basic demo
129
+ ├── demo-with-css.html # CSS version demo
130
+ ├── cdn-example.html # CDN usage example
131
+ ├── README.md # Documentation
132
+ └── disnorty/ # Original project files
133
+ ├── index.html
134
+ ├── script.js
135
+ └── style.css
136
+ ```
137
+
138
+ ## 🎯 Demo
139
+
140
+ Check out the live demos:
141
+ - `demo.html` - Basic demo with auto-loaded CSS
142
+ - `demo-with-css.html` - Demo with manually loaded CSS
143
+ - `cdn-example.html` - CDN usage example (when CDN is available)
144
+
145
+ ## 🤝 Contributing
146
+
147
+ Contributions are welcome! Please feel free to submit a Pull Request.
148
+
149
+ ## 📄 License
150
+
151
+ This project is licensed under the MIT License - see the LICENSE file for details.
152
+
153
+ ## 🙏 Acknowledgments
154
+
155
+ - HuggingFace for providing the AI API
156
+ - All contributors and users of this plugin
157
+
158
+ ## 📞 Support
159
+
160
+ If you encounter any issues or have questions, please open an issue on the GitHub repository.
161
+
162
+ ---
163
+
164
+ **Made with ❤️ for making web content more accessible and educational**
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "word-meaning-plugin",
3
+ "version": "1.0.0",
4
+ "description": "A simple word meaning plugin",
5
+ "license": "ISC",
6
+ "author": "Adi",
7
+ "type": "commonjs",
8
+ "keywords": [
9
+ "dictionary",
10
+ "word meaning",
11
+ "plugin",
12
+ "tooltip"
13
+ ],
14
+ "main": "word-meaning-plugin.js",
15
+ "scripts": {
16
+ "test": "echo \"Error: no test specified\" && exit 1"
17
+ }
18
+ }
@@ -0,0 +1,211 @@
1
+ /*!
2
+ * Word Meaning Plugin CSS v1.0
3
+ * Styles for the word meaning dictionary popup
4
+ * Author: Your Name
5
+ * License: MIT
6
+ */
7
+
8
+ /* Main popup container */
9
+ #word-meaning-popup {
10
+ display: none;
11
+ position: absolute;
12
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
13
+ color: #fff;
14
+ padding: 16px 20px;
15
+ border-radius: 12px;
16
+ max-width: 320px;
17
+ font-size: 14px;
18
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2),
19
+ 0 5px 10px rgba(0, 0, 0, 0.15),
20
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
21
+ z-index: 10000;
22
+ border: 1px solid rgba(255, 255, 255, 0.1);
23
+ backdrop-filter: blur(10px);
24
+ transition: opacity 0.3s ease, transform 0.3s ease;
25
+ opacity: 0;
26
+ transform: translateY(10px);
27
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
28
+ line-height: 1.6;
29
+ }
30
+
31
+ /* Popup show state */
32
+ #word-meaning-popup.show {
33
+ opacity: 1;
34
+ transform: translateY(0);
35
+ }
36
+
37
+ /* Popup arrow */
38
+ #word-meaning-popup::after {
39
+ content: '';
40
+ position: absolute;
41
+ top: -8px;
42
+ left: 50%;
43
+ transform: translateX(-50%);
44
+ border-left: 8px solid transparent;
45
+ border-right: 8px solid transparent;
46
+ border-bottom: 8px solid #1a1a2e;
47
+ }
48
+
49
+ /* Word title */
50
+ #word-meaning-popup strong {
51
+ color: #4fc3f7;
52
+ font-size: 18px;
53
+ margin-bottom: 8px;
54
+ display: block;
55
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
56
+ padding-bottom: 6px;
57
+ }
58
+
59
+ /* Section containers */
60
+ #word-meaning-popup > div {
61
+ margin-top: 8px;
62
+ display: flex;
63
+ align-items: start;
64
+ gap: 10px;
65
+ }
66
+
67
+ /* Labels */
68
+ #word-meaning-popup b {
69
+ color: #fff;
70
+ font-weight: 600;
71
+ }
72
+
73
+ /* Content areas */
74
+ #word-meaning-popup > div > div:first-child {
75
+ flex: 1;
76
+ }
77
+
78
+ /* Example section */
79
+ #word-meaning-popup > div[style*="italic"] {
80
+ font-style: italic;
81
+ color: #ccc;
82
+ }
83
+
84
+ /* Speaker buttons */
85
+ #word-meaning-popup button {
86
+ background: none;
87
+ border: none;
88
+ cursor: pointer;
89
+ padding: 4px;
90
+ border-radius: 4px;
91
+ color: #fff;
92
+ font-size: 14px;
93
+ transition: background-color 0.2s ease;
94
+ }
95
+
96
+ #word-meaning-popup button:hover {
97
+ background: rgba(255, 255, 255, 0.1);
98
+ }
99
+
100
+ #word-meaning-popup button:active {
101
+ transform: scale(0.95);
102
+ }
103
+
104
+ /* Responsive design */
105
+ @media (max-width: 480px) {
106
+ #word-meaning-popup {
107
+ max-width: 280px;
108
+ font-size: 13px;
109
+ padding: 12px 16px;
110
+ }
111
+
112
+ #word-meaning-popup strong {
113
+ font-size: 16px;
114
+ }
115
+
116
+ #word-meaning-popup button {
117
+ font-size: 12px;
118
+ padding: 3px;
119
+ }
120
+ }
121
+
122
+ /* Dark theme support */
123
+ @media (prefers-color-scheme: dark) {
124
+ #word-meaning-popup {
125
+ background: linear-gradient(135deg, #0f0f23 0%, #1a1a2e 100%);
126
+ border: 1px solid rgba(255, 255, 255, 0.15);
127
+ }
128
+
129
+ #word-meaning-popup::after {
130
+ border-bottom-color: #0f0f23;
131
+ }
132
+ }
133
+
134
+ /* High contrast mode support */
135
+ @media (prefers-contrast: high) {
136
+ #word-meaning-popup {
137
+ border: 2px solid #fff;
138
+ background: #000;
139
+ }
140
+
141
+ #word-meaning-popup::after {
142
+ border-bottom-color: #000;
143
+ }
144
+
145
+ #word-meaning-popup strong {
146
+ color: #fff;
147
+ border-bottom-color: #fff;
148
+ }
149
+ }
150
+
151
+ /* Reduced motion support */
152
+ @media (prefers-reduced-motion: reduce) {
153
+ #word-meaning-popup {
154
+ transition: none;
155
+ }
156
+
157
+ #word-meaning-popup button {
158
+ transition: none;
159
+ }
160
+ }
161
+
162
+ /* Loading state */
163
+ #word-meaning-popup.loading {
164
+ pointer-events: none;
165
+ }
166
+
167
+ #word-meaning-popup.loading::after {
168
+ content: '';
169
+ position: absolute;
170
+ bottom: 8px;
171
+ right: 8px;
172
+ width: 16px;
173
+ height: 16px;
174
+ border: 2px solid rgba(255, 255, 255, 0.3);
175
+ border-top: 2px solid #4fc3f7;
176
+ border-radius: 50%;
177
+ animation: spin 1s linear infinite;
178
+ }
179
+
180
+ @keyframes spin {
181
+ 0% { transform: rotate(0deg); }
182
+ 100% { transform: rotate(360deg); }
183
+ }
184
+
185
+ /* Error state */
186
+ #word-meaning-popup.error {
187
+ background: linear-gradient(135deg, #c62828 0%, #b71c1c 100%);
188
+ }
189
+
190
+ #word-meaning-popup.error::after {
191
+ border-bottom-color: #c62828;
192
+ }
193
+
194
+ /* Custom scrollbar for popup content */
195
+ #word-meaning-popup::-webkit-scrollbar {
196
+ width: 6px;
197
+ }
198
+
199
+ #word-meaning-popup::-webkit-scrollbar-track {
200
+ background: rgba(255, 255, 255, 0.1);
201
+ border-radius: 3px;
202
+ }
203
+
204
+ #word-meaning-popup::-webkit-scrollbar-thumb {
205
+ background: rgba(255, 255, 255, 0.3);
206
+ border-radius: 3px;
207
+ }
208
+
209
+ #word-meaning-popup::-webkit-scrollbar-thumb:hover {
210
+ background: rgba(255, 255, 255, 0.5);
211
+ }
@@ -0,0 +1,319 @@
1
+ /*!
2
+ * Word Meaning Plugin v1.0
3
+ * Easy word meaning dictionary for any website
4
+ * Just add this script and select any word to see its meaning
5
+ * Author: Your Name
6
+ * License: MIT
7
+ */
8
+
9
+ (function() {
10
+ 'use strict';
11
+
12
+ // Plugin configuration
13
+ const config = {
14
+ apiKey: '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', // You can make this configurable
15
+ apiUrl: 'https://router.huggingface.co/v1/chat/completions',
16
+ model: 'moonshotai/Kimi-K2-Instruct-0905',
17
+ popupWidth: 320,
18
+ popupHeight: 150,
19
+ animationDuration: 300
20
+ };
21
+
22
+ // Create popup element
23
+ let popup = null;
24
+ let isLoading = false;
25
+ let cssLoaded = false;
26
+
27
+ // Initialize plugin
28
+ function init() {
29
+ loadCSS();
30
+ createPopup();
31
+ addEventListeners();
32
+ console.log('Word Meaning Plugin initialized');
33
+ }
34
+
35
+ // Load CSS file
36
+ function loadCSS() {
37
+ if (cssLoaded) return;
38
+
39
+ const link = document.createElement('link');
40
+ link.rel = 'stylesheet';
41
+ link.type = 'text/css';
42
+ link.href = getCSSPath();
43
+ document.head.appendChild(link);
44
+ cssLoaded = true;
45
+ }
46
+
47
+ // Get CSS file path
48
+ function getCSSPath() {
49
+ // Try to detect the plugin's script path and use same directory for CSS
50
+ const scripts = document.getElementsByTagName('script');
51
+ for (let i = scripts.length - 1; i >= 0; i--) {
52
+ const script = scripts[i];
53
+ if (script.src && script.src.includes('word-meaning-plugin.js')) {
54
+ return script.src.replace('word-meaning-plugin.js', 'word-meaning-plugin.css');
55
+ }
56
+ }
57
+ // Fallback to same directory
58
+ return 'word-meaning-plugin.css';
59
+ }
60
+
61
+ // Create popup element
62
+ function createPopup() {
63
+ popup = document.createElement('div');
64
+ popup.id = 'word-meaning-popup';
65
+ document.body.appendChild(popup);
66
+ }
67
+
68
+ // Add event listeners
69
+ function addEventListeners() {
70
+ // Handle text selection
71
+ document.addEventListener('mouseup', handleTextSelection);
72
+
73
+ // Close popup when clicking outside
74
+ document.addEventListener('mousedown', function(event) {
75
+ if (popup.style.display === 'block' && !popup.contains(event.target)) {
76
+ hidePopup();
77
+ }
78
+ });
79
+
80
+ // Handle window resize
81
+ window.addEventListener('resize', hidePopup);
82
+ }
83
+
84
+ // Handle text selection
85
+ function handleTextSelection(event) {
86
+ const selection = window.getSelection();
87
+ const word = selection.toString().trim();
88
+
89
+ // Don't show popup for empty selection or multiple words
90
+ if (word.length === 0 || word.includes(' ') || isLoading) return;
91
+
92
+ // Don't show if clicking on input fields or buttons
93
+ if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA' || event.target.tagName === 'BUTTON') return;
94
+
95
+ // Get context for better meaning
96
+ const range = selection.getRangeAt(0);
97
+ const container = range.startContainer;
98
+ const textContent = container.textContent || container.innerText;
99
+ const startOffset = range.startOffset;
100
+ const endOffset = range.endOffset;
101
+
102
+ const contextStart = Math.max(0, startOffset - 50);
103
+ const contextEnd = Math.min(textContent.length, endOffset + 50);
104
+ const context = textContent.substring(contextStart, contextEnd).trim();
105
+
106
+ // Position popup
107
+ const position = calculatePopupPosition(event.pageX, event.pageY);
108
+
109
+ // Show loading state
110
+ showPopup(word, 'Loading definition...', '', '', position);
111
+
112
+ // Fetch meaning
113
+ fetchWordMeaning(word, context, position);
114
+ }
115
+
116
+ // Calculate popup position to keep it within viewport
117
+ function calculatePopupPosition(x, y) {
118
+ const viewportWidth = window.innerWidth;
119
+ const viewportHeight = window.innerHeight;
120
+
121
+ let finalX = x + 10;
122
+ let finalY = y + 10;
123
+
124
+ // Check if popup would go off screen horizontally
125
+ if (finalX + config.popupWidth > viewportWidth) {
126
+ finalX = viewportWidth - config.popupWidth - 20;
127
+ }
128
+
129
+ // Check if popup would go off screen vertically
130
+ if (finalY + config.popupHeight > viewportHeight) {
131
+ finalY = y - config.popupHeight - 20;
132
+ popup.style.transformOrigin = 'center bottom';
133
+ } else {
134
+ popup.style.transformOrigin = 'center top';
135
+ }
136
+
137
+ return { x: finalX, y: finalY };
138
+ }
139
+
140
+ // Fetch word meaning from API
141
+ function fetchWordMeaning(word, context, position) {
142
+ isLoading = true;
143
+
144
+ fetch(config.apiUrl, {
145
+ method: 'POST',
146
+ headers: {
147
+ 'Content-Type': 'application/json',
148
+ 'Authorization': `Bearer ${config.apiKey}`
149
+ },
150
+ body: JSON.stringify({
151
+ model: config.model,
152
+ messages: [
153
+ {
154
+ role: 'system',
155
+ content: `You are a context-aware dictionary. Given a word and its surrounding context, provide the most relevant meaning for that specific context.
156
+
157
+ Context: "${context}"
158
+ Word: "${word}"
159
+
160
+ Provide the response in this exact format:
161
+ English: [context-appropriate meaning]
162
+ Hindi: [Hindi translation]
163
+ Example: [example sentence using the word in this context]`
164
+ },
165
+ {
166
+ role: 'user',
167
+ content: `What is the meaning of "${word}" in the context: "${context}"?`
168
+ }
169
+ ],
170
+ max_tokens: 150,
171
+ temperature: 0.3
172
+ })
173
+ })
174
+ .then(response => response.json())
175
+ .then(data => {
176
+ if (!data.choices || !data.choices[0] || !data.choices[0].message) {
177
+ throw new Error('Invalid API response');
178
+ }
179
+
180
+ const response = data.choices[0].message.content.trim();
181
+ const parsed = parseResponse(response);
182
+
183
+ showPopup(word, parsed.enMeaning, parsed.hiMeaning, parsed.example, position);
184
+ })
185
+ .catch(error => {
186
+ console.error('Error fetching word meaning:', error);
187
+ showPopup(word, 'Meaning not found', 'मतलब नहीं मिला', 'No example available.', position);
188
+ })
189
+ .finally(() => {
190
+ isLoading = false;
191
+ });
192
+ }
193
+
194
+ // Parse API response
195
+ function parseResponse(response) {
196
+ const lines = response.split('\n');
197
+ let enMeaning = 'Meaning not found';
198
+ let hiMeaning = 'अनुवाद उपलब्ध नहीं';
199
+ let example = 'No example available';
200
+
201
+ lines.forEach(line => {
202
+ if (line.toLowerCase().includes('english') || line.toLowerCase().includes('meaning')) {
203
+ enMeaning = line.replace(/english:|meaning:/gi, '').trim();
204
+ } else if (line.toLowerCase().includes('hindi') || line.toLowerCase().includes('translation')) {
205
+ hiMeaning = line.replace(/hindi:|translation:/gi, '').trim();
206
+ } else if (line.toLowerCase().includes('example')) {
207
+ example = line.replace(/example:/gi, '').trim();
208
+ }
209
+ });
210
+
211
+ return { enMeaning, hiMeaning, example };
212
+ }
213
+
214
+ // Show popup with content
215
+ function showPopup(word, enMeaning, hiMeaning, example, position) {
216
+ popup.innerHTML = `
217
+ <strong style="color: #4fc3f7; font-size: 18px; margin-bottom: 8px; display: block; border-bottom: 1px solid rgba(255, 255, 255, 0.1); padding-bottom: 6px;">${word}</strong>
218
+
219
+ <div style="margin-top:8px; display: flex; align-items: start; gap: 10px;">
220
+ <div style="flex: 1;">
221
+ <b>English:</b><br>${enMeaning}
222
+ </div>
223
+ <button onclick="event.stopPropagation(); window.wordMeaningPlugin.speakText('${enMeaning.replace(/'/g, "\\'")}', 'en')"
224
+ style="background: none; border: none; cursor: pointer; padding: 4px; border-radius: 4px;"
225
+ title="Speak English">
226
+ 🔊
227
+ </button>
228
+ </div>
229
+
230
+ <div style="margin-top:8px; display: flex; align-items: start; gap: 10px;">
231
+ <div style="flex: 1;">
232
+ <b>Hindi:</b><br>${hiMeaning}
233
+ </div>
234
+ <button onclick="event.stopPropagation(); window.wordMeaningPlugin.speakText('${hiMeaning.replace(/'/g, "\\'")}', 'hi')"
235
+ style="background: none; border: none; cursor: pointer; padding: 4px; border-radius: 4px;"
236
+ title="Speak Hindi">
237
+ 🔊
238
+ </button>
239
+ </div>
240
+
241
+ <div style="margin-top:8px; font-style:italic; color:#ccc; display: flex; align-items: start; gap: 10px;">
242
+ <div style="flex: 1;">
243
+ <b>Example:</b><br>${example}
244
+ </div>
245
+ <button onclick="event.stopPropagation(); window.wordMeaningPlugin.speakText('${example.replace(/'/g, "\\'")}', 'en')"
246
+ style="background: none; border: none; cursor: pointer; padding: 4px; border-radius: 4px;"
247
+ title="Speak Example">
248
+ 🔊
249
+ </button>
250
+ </div>
251
+ `;
252
+
253
+ popup.style.left = position.x + 'px';
254
+ popup.style.top = position.y + 'px';
255
+ popup.style.display = 'block';
256
+
257
+ // Trigger animation
258
+ setTimeout(() => {
259
+ popup.style.opacity = '1';
260
+ popup.style.transform = 'translateY(0)';
261
+ }, 10);
262
+ }
263
+
264
+ // Hide popup
265
+ function hidePopup() {
266
+ popup.style.opacity = '0';
267
+ popup.style.transform = 'translateY(10px)';
268
+ setTimeout(() => {
269
+ popup.style.display = 'none';
270
+ }, config.animationDuration);
271
+ }
272
+
273
+ // Text-to-speech function
274
+ function speakText(text, lang) {
275
+ if (!window.speechSynthesis) return;
276
+
277
+ window.speechSynthesis.cancel();
278
+
279
+ const utterance = new SpeechSynthesisUtterance(text);
280
+ utterance.lang = lang;
281
+ utterance.rate = 0.9;
282
+ utterance.pitch = 1;
283
+ utterance.volume = 1;
284
+
285
+ const voices = window.speechSynthesis.getVoices();
286
+ if (lang === 'hi') {
287
+ const hindiVoice = voices.find(voice => voice.lang.includes('hi') || voice.lang.includes('hin'));
288
+ if (hindiVoice) utterance.voice = hindiVoice;
289
+ } else {
290
+ const englishVoice = voices.find(voice => voice.lang.includes('en') || voice.lang.includes('en-US'));
291
+ if (englishVoice) utterance.voice = englishVoice;
292
+ }
293
+
294
+ window.speechSynthesis.speak(utterance);
295
+ }
296
+
297
+ // Load voices when available
298
+ if (window.speechSynthesis) {
299
+ window.speechSynthesis.onvoiceschanged = function() {
300
+ window.speechSynthesis.getVoices();
301
+ };
302
+ }
303
+
304
+ // Public API
305
+ window.wordMeaningPlugin = {
306
+ init: init,
307
+ speakText: speakText,
308
+ hidePopup: hidePopup,
309
+ config: config
310
+ };
311
+
312
+ // Auto-initialize when DOM is ready
313
+ if (document.readyState === 'loading') {
314
+ document.addEventListener('DOMContentLoaded', init);
315
+ } else {
316
+ init();
317
+ }
318
+
319
+ })();