|
2 | 2 | // @name Next.js i18n Tampermonkey Script
|
3 | 3 | // @namespace https://github.com/xiaoyu2er/nextjs-i18n-docs
|
4 | 4 | // @website https://github.com/xiaoyu2er/nextjs-i18n-docs
|
5 |
| -// @version 0.0.1 |
| 5 | +// @version 0.0.2 |
6 | 6 | // @updateURL https://raw.githubusercontent.com/xiaoyu2er/nextjs-i18n-docs/refs/heads/dev/apps/tampermonkey/dist/script.iife.js
|
7 | 7 | // @downloadURL https://raw.githubusercontent.com/xiaoyu2er/nextjs-i18n-docs/refs/heads/dev/apps/tampermonkey/dist/script.iife.js
|
8 | 8 | // @description Adds a translation button to nextjs.org with links to community-maintained translated documentation
|
|
115 | 115 | );
|
116 | 116 | function devLog(...args) {
|
117 | 117 | }
|
118 |
| - function devWarn(...args) { |
119 |
| - } |
120 |
| - function devError(...args) { |
121 |
| - } |
122 |
| - function waitForLearnButton(callback, maxAttempts = 30) { |
| 118 | + function waitForTargetButton(callback, maxAttempts = 30) { |
123 | 119 | let attempts = 0;
|
124 | 120 | const check = () => {
|
125 | 121 | try {
|
126 | 122 | const learnButton = document.querySelector('a[href="/learn"]');
|
127 |
| - if (learnButton) { |
| 123 | + const searchButton = document.querySelector('button[aria-label="Search documentation"]'); |
| 124 | + if (learnButton || searchButton) { |
128 | 125 | callback();
|
129 |
| - } else if (attempts < maxAttempts) { |
| 126 | + return; |
| 127 | + } |
| 128 | + if (attempts < maxAttempts) { |
130 | 129 | attempts++;
|
131 | 130 | setTimeout(check, 200);
|
132 | 131 | } else {
|
133 |
| - devLog("⚠️ Learn button not found after maximum attempts"); |
| 132 | + devLog("⚠️ Neither Learn button nor Search button found after maximum attempts"); |
134 | 133 | }
|
135 | 134 | } catch (error) {
|
136 | 135 | }
|
|
298 | 297 | return container;
|
299 | 298 | }
|
300 | 299 | function addTranslationButton() {
|
| 300 | + var _a, _b; |
| 301 | + let addedCount = 0; |
301 | 302 | const learnButtonSelectors = [
|
302 | 303 | 'a[href="/learn"]',
|
303 | 304 | 'a[href*="/learn"]',
|
|
311 | 312 | break;
|
312 | 313 | }
|
313 | 314 | }
|
314 |
| - if (!learnButton) { |
315 |
| - return; |
316 |
| - } |
317 |
| - try { |
318 |
| - const existingButton = document.querySelector( |
319 |
| - ".next-i18n-translate-container" |
320 |
| - ); |
321 |
| - if (existingButton) { |
322 |
| - devLog("✅ Translation button already exists"); |
323 |
| - return; |
| 315 | + if (learnButton) { |
| 316 | + const existingLearnButton = (_a = learnButton.parentNode) == null ? void 0 : _a.querySelector(".next-i18n-translate-container"); |
| 317 | + if (!existingLearnButton) { |
| 318 | + try { |
| 319 | + const translationDropdown = createTranslationDropdown(); |
| 320 | + translationDropdown.setAttribute("data-placement", "learn-button"); |
| 321 | + const parentNode = learnButton.parentNode; |
| 322 | + if (parentNode) { |
| 323 | + if (learnButton.nextSibling) { |
| 324 | + parentNode.insertBefore(translationDropdown, learnButton.nextSibling); |
| 325 | + } else { |
| 326 | + parentNode.appendChild(translationDropdown); |
| 327 | + } |
| 328 | + devLog("✅ Translation button added next to Learn button"); |
| 329 | + addedCount++; |
| 330 | + } |
| 331 | + } catch (error) { |
| 332 | + } |
324 | 333 | }
|
325 |
| - const translationDropdown = createTranslationDropdown(); |
326 |
| - const parentNode = learnButton.parentNode; |
327 |
| - if (!parentNode) { |
328 |
| - devError("❌ Learn button has no parent node"); |
329 |
| - return; |
| 334 | + } |
| 335 | + const searchButtonSelectors = [ |
| 336 | + 'button[aria-label="Search documentation"]', |
| 337 | + "button.navbar_search__dZT2b", |
| 338 | + 'button[data-variant="small"]' |
| 339 | + ]; |
| 340 | + let searchButton = null; |
| 341 | + for (const selector of searchButtonSelectors) { |
| 342 | + try { |
| 343 | + searchButton = document.querySelector(selector); |
| 344 | + if (searchButton) { |
| 345 | + devLog(`🔍 Found Search button with selector: ${selector}`); |
| 346 | + break; |
| 347 | + } |
| 348 | + } catch (error) { |
330 | 349 | }
|
331 |
| - if (learnButton.nextSibling) { |
332 |
| - parentNode.insertBefore(translationDropdown, learnButton.nextSibling); |
333 |
| - } else { |
334 |
| - parentNode.appendChild(translationDropdown); |
| 350 | + } |
| 351 | + if (searchButton) { |
| 352 | + const existingSearchButton = (_b = searchButton.parentNode) == null ? void 0 : _b.querySelector(".next-i18n-translate-container"); |
| 353 | + if (!existingSearchButton) { |
| 354 | + try { |
| 355 | + const translationDropdown = createTranslationDropdown(); |
| 356 | + translationDropdown.setAttribute("data-placement", "search-button"); |
| 357 | + const parentNode = searchButton.parentNode; |
| 358 | + if (parentNode) { |
| 359 | + if (searchButton.nextSibling) { |
| 360 | + parentNode.insertBefore(translationDropdown, searchButton.nextSibling); |
| 361 | + } else { |
| 362 | + parentNode.appendChild(translationDropdown); |
| 363 | + } |
| 364 | + devLog("✅ Translation button added next to Search button"); |
| 365 | + addedCount++; |
| 366 | + } |
| 367 | + } catch (error) { |
| 368 | + } |
335 | 369 | }
|
336 |
| - devLog("✅ Translation button added successfully"); |
| 370 | + } |
| 371 | + if (addedCount === 0 && !learnButton && !searchButton) { |
| 372 | + return false; |
| 373 | + } |
| 374 | + if (addedCount > 0) { |
337 | 375 | setTimeout(() => {
|
338 |
| - const verifyButton = document.querySelector( |
| 376 | + const verifyButtons = document.querySelectorAll( |
339 | 377 | ".next-i18n-translate-container"
|
340 | 378 | );
|
341 |
| - if (!verifyButton) { |
342 |
| - devWarn( |
343 |
| - "⚠️ Translation button was removed shortly after adding, React might be re-rendering" |
344 |
| - ); |
| 379 | + if (verifyButtons.length === 0) { |
345 | 380 | setTimeout(() => {
|
346 |
| - devLog( |
347 |
| - "🔄 Attempting to re-add translation button after React stabilization" |
348 |
| - ); |
349 | 381 | addTranslationButton();
|
350 | 382 | }, 1e3);
|
351 | 383 | } else {
|
352 |
| - devLog("🎉 Translation button is stable and working!"); |
| 384 | + devLog(`🎉 ${verifyButtons.length} translation button(s) are stable and working!`); |
353 | 385 | }
|
354 | 386 | }, 500);
|
355 |
| - } catch (error) { |
356 | 387 | }
|
| 388 | + return addedCount > 0; |
357 | 389 | }
|
358 | 390 | function initializeScript() {
|
359 | 391 | setTimeout(() => {
|
360 | 392 | addTranslationButton();
|
361 | 393 | setTimeout(() => {
|
362 |
| - if (!document.querySelector(".next-i18n-translate-container")) { |
363 |
| - waitForLearnButton(() => { |
364 |
| - devLog("🎯 Learn button found, attempting to add translation button"); |
| 394 | + const existingButtons = document.querySelectorAll(".next-i18n-translate-container"); |
| 395 | + if (existingButtons.length === 0) { |
| 396 | + waitForTargetButton(() => { |
| 397 | + devLog("🎯 Target button found, attempting to add translation button"); |
365 | 398 | addTranslationButton();
|
366 | 399 | });
|
367 | 400 | }
|
|
0 commit comments