this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Experiment using browser's built in translation API

Spec: https://webmachinelearning.github.io/translation-api/

API may change in the future

+395 -240
+7
src/components/compose.jsx
··· 28 28 import supportedLanguages from '../data/status-supported-languages'; 29 29 import urlRegex from '../data/url-regex'; 30 30 import { api } from '../utils/api'; 31 + import { langDetector } from '../utils/browser-translator'; 31 32 import db from '../utils/db'; 32 33 import emojifyText from '../utils/emojify-text'; 33 34 import i18nDuration from '../utils/i18n-duration'; ··· 1875 1876 }); 1876 1877 1877 1878 const detectLangs = async (text) => { 1879 + if (langDetector) { 1880 + const langs = await langDetector.detect(text); 1881 + if (langs?.length) { 1882 + return langs.slice(0, 2).map((lang) => lang.detectedLanguage); 1883 + } 1884 + } 1878 1885 const { detectAll } = await import('tinyld/light'); 1879 1886 const langs = detectAll(text); 1880 1887 if (langs?.length) {
+23 -1
src/components/status.jsx
··· 41 41 import NameText from '../components/name-text'; 42 42 import Poll from '../components/poll'; 43 43 import { api } from '../utils/api'; 44 + import { langDetector } from '../utils/browser-translator'; 44 45 import emojifyText from '../utils/emojify-text'; 45 46 import enhanceContent from '../utils/enhance-content'; 46 47 import FilterContext from '../utils/filter-context'; ··· 253 254 }; 254 255 255 256 const detectLang = pmem(async (text) => { 256 - const { detectAll } = await import('tinyld/light'); 257 257 text = text?.trim(); 258 258 259 259 // Ref: https://github.com/komodojp/tinyld/blob/develop/docs/benchmark.md ··· 261 261 if (text?.length > 500) { 262 262 return null; 263 263 } 264 + 265 + if (langDetector) { 266 + const langs = await langDetector.detect(text); 267 + console.groupCollapsed( 268 + '💬 DETECTLANG BROWSER', 269 + langs.slice(0, 3).map((l) => l.detectedLanguage), 270 + ); 271 + console.log(text, langs.slice(0, 3)); 272 + console.groupEnd(); 273 + const lang = langs[0]; 274 + if (lang?.detectedLanguage && lang?.confidence > 0.5) { 275 + return lang.detectedLanguage; 276 + } 277 + } 278 + 279 + const { detectAll } = await import('tinyld/light'); 264 280 const langs = detectAll(text); 281 + console.groupCollapsed( 282 + '💬 DETECTLANG TINYLD', 283 + langs.slice(0, 3).map((l) => l.lang), 284 + ); 285 + console.log(text, langs.slice(0, 3)); 286 + console.groupEnd(); 265 287 const lang = langs[0]; 266 288 if (lang?.lang && lang?.accuracy > 0.5) { 267 289 // If > 50% accurate, use it
+20 -1
src/components/translation-block.jsx
··· 6 6 import { useEffect, useRef, useState } from 'preact/hooks'; 7 7 8 8 import sourceLanguages from '../data/lingva-source-languages'; 9 + import { 10 + translate as browserTranslate, 11 + supportsBrowserTranslator, 12 + } from '../utils/browser-translator'; 9 13 import getTranslateTargetLanguage from '../utils/get-translate-target-language'; 10 14 import localeCode2Text from '../utils/localeCode2Text'; 11 15 import pmem from '../utils/pmem'; ··· 95 99 const apiSourceLang = useRef('auto'); 96 100 97 101 if (!onTranslate) { 98 - onTranslate = mini ? throttledLingvaTranslate : lingvaTranslate; 102 + // onTranslate = supportsBrowserTranslator 103 + // ? browserTranslate 104 + // : mini 105 + // ? throttledLingvaTranslate 106 + // : lingvaTranslate; 107 + onTranslate = async (...args) => { 108 + if (supportsBrowserTranslator) { 109 + const result = await browserTranslate(...args); 110 + if (result && !result.error) { 111 + return result; 112 + } 113 + } 114 + return mini 115 + ? await throttledLingvaTranslate(...args) 116 + : await lingvaTranslate(...args); 117 + }; 99 118 } 100 119 101 120 const translate = async () => {
+238 -238
src/locales/en.po
··· 34 34 35 35 #: src/components/account-block.jsx:169 36 36 #: src/components/account-info.jsx:664 37 - #: src/components/status.jsx:525 37 + #: src/components/status.jsx:547 38 38 msgid "Group" 39 39 msgstr "" 40 40 ··· 108 108 109 109 #: src/components/account-info.jsx:430 110 110 #: src/components/account-info.jsx:1143 111 - #: src/components/compose.jsx:2696 111 + #: src/components/compose.jsx:2703 112 112 #: src/components/media-alt-modal.jsx:46 113 113 #: src/components/media-modal.jsx:358 114 - #: src/components/status.jsx:1748 115 - #: src/components/status.jsx:1765 116 - #: src/components/status.jsx:1890 117 - #: src/components/status.jsx:2495 118 - #: src/components/status.jsx:2498 114 + #: src/components/status.jsx:1770 115 + #: src/components/status.jsx:1787 116 + #: src/components/status.jsx:1912 117 + #: src/components/status.jsx:2517 118 + #: src/components/status.jsx:2520 119 119 #: src/pages/account-statuses.jsx:523 120 120 #: src/pages/accounts.jsx:110 121 121 #: src/pages/hashtag.jsx:200 ··· 197 197 msgstr "" 198 198 199 199 #: src/components/account-info.jsx:887 200 - #: src/components/status.jsx:2281 200 + #: src/components/status.jsx:2303 201 201 #: src/pages/catchup.jsx:71 202 202 #: src/pages/catchup.jsx:1445 203 203 #: src/pages/catchup.jsx:2058 ··· 294 294 msgstr "" 295 295 296 296 #: src/components/account-info.jsx:1327 297 - #: src/components/status.jsx:1188 297 + #: src/components/status.jsx:1210 298 298 msgid "Link copied" 299 299 msgstr "" 300 300 301 301 #: src/components/account-info.jsx:1330 302 - #: src/components/status.jsx:1191 302 + #: src/components/status.jsx:1213 303 303 msgid "Unable to copy link" 304 304 msgstr "" 305 305 306 306 #: src/components/account-info.jsx:1336 307 307 #: src/components/shortcuts-settings.jsx:1059 308 - #: src/components/status.jsx:1197 309 - #: src/components/status.jsx:3274 308 + #: src/components/status.jsx:1219 309 + #: src/components/status.jsx:3296 310 310 msgid "Copy" 311 311 msgstr "" 312 312 313 313 #: src/components/account-info.jsx:1351 314 314 #: src/components/shortcuts-settings.jsx:1077 315 - #: src/components/status.jsx:1213 315 + #: src/components/status.jsx:1235 316 316 msgid "Sharing doesn't seem to work." 317 317 msgstr "" 318 318 319 319 #: src/components/account-info.jsx:1357 320 - #: src/components/status.jsx:1219 320 + #: src/components/status.jsx:1241 321 321 msgid "Share…" 322 322 msgstr "" 323 323 ··· 419 419 #: src/components/account-info.jsx:2020 420 420 #: src/components/account-info.jsx:2140 421 421 #: src/components/account-sheet.jsx:38 422 - #: src/components/compose.jsx:876 423 - #: src/components/compose.jsx:2652 424 - #: src/components/compose.jsx:3126 425 - #: src/components/compose.jsx:3335 426 - #: src/components/compose.jsx:3565 422 + #: src/components/compose.jsx:877 423 + #: src/components/compose.jsx:2659 424 + #: src/components/compose.jsx:3133 425 + #: src/components/compose.jsx:3342 426 + #: src/components/compose.jsx:3572 427 427 #: src/components/drafts.jsx:59 428 428 #: src/components/embed-modal.jsx:13 429 429 #: src/components/generic-accounts.jsx:143 ··· 436 436 #: src/components/shortcuts-settings.jsx:230 437 437 #: src/components/shortcuts-settings.jsx:583 438 438 #: src/components/shortcuts-settings.jsx:783 439 - #: src/components/status.jsx:2998 440 - #: src/components/status.jsx:3238 441 - #: src/components/status.jsx:3738 439 + #: src/components/status.jsx:3020 440 + #: src/components/status.jsx:3260 441 + #: src/components/status.jsx:3760 442 442 #: src/pages/accounts.jsx:37 443 443 #: src/pages/catchup.jsx:1581 444 444 #: src/pages/filters.jsx:224 ··· 570 570 msgid "Compose" 571 571 msgstr "" 572 572 573 - #: src/components/compose.jsx:210 573 + #: src/components/compose.jsx:211 574 574 msgid "Add media" 575 575 msgstr "Add media" 576 576 577 - #: src/components/compose.jsx:211 577 + #: src/components/compose.jsx:212 578 578 msgid "Add custom emoji" 579 579 msgstr "" 580 580 581 - #: src/components/compose.jsx:212 581 + #: src/components/compose.jsx:213 582 582 msgid "Add GIF" 583 583 msgstr "Add GIF" 584 584 585 - #: src/components/compose.jsx:213 585 + #: src/components/compose.jsx:214 586 586 msgid "Add poll" 587 587 msgstr "" 588 588 589 - #: src/components/compose.jsx:214 589 + #: src/components/compose.jsx:215 590 590 msgid "Schedule post" 591 591 msgstr "Schedule post" 592 592 593 - #: src/components/compose.jsx:410 593 + #: src/components/compose.jsx:411 594 594 msgid "You have unsaved changes. Discard this post?" 595 595 msgstr "You have unsaved changes. Discard this post?" 596 596 597 597 #. placeholder {0}: unsupportedFiles.length 598 598 #. placeholder {1}: unsupportedFiles[0].name 599 599 #. placeholder {2}: lf.format( unsupportedFiles.map((f) => f.name), ) 600 - #: src/components/compose.jsx:639 600 + #: src/components/compose.jsx:640 601 601 msgid "{0, plural, one {File {1} is not supported.} other {Files {2} are not supported.}}" 602 602 msgstr "{0, plural, one {File {1} is not supported.} other {Files {2} are not supported.}}" 603 603 604 - #: src/components/compose.jsx:649 605 - #: src/components/compose.jsx:667 606 - #: src/components/compose.jsx:1746 607 - #: src/components/compose.jsx:1832 604 + #: src/components/compose.jsx:650 605 + #: src/components/compose.jsx:668 606 + #: src/components/compose.jsx:1747 607 + #: src/components/compose.jsx:1833 608 608 msgid "{maxMediaAttachments, plural, one {You can only attach up to 1 file.} other {You can only attach up to # files.}}" 609 609 msgstr "" 610 610 611 - #: src/components/compose.jsx:857 611 + #: src/components/compose.jsx:858 612 612 msgid "Pop out" 613 613 msgstr "Pop out" 614 614 615 - #: src/components/compose.jsx:864 615 + #: src/components/compose.jsx:865 616 616 msgid "Minimize" 617 617 msgstr "Minimize" 618 618 619 - #: src/components/compose.jsx:900 619 + #: src/components/compose.jsx:901 620 620 msgid "Looks like you closed the parent window." 621 621 msgstr "Looks like you closed the parent window." 622 622 623 - #: src/components/compose.jsx:907 623 + #: src/components/compose.jsx:908 624 624 msgid "Looks like you already have a compose field open in the parent window and currently publishing. Please wait for it to be done and try again later." 625 625 msgstr "Looks like you already have a compose field open in the parent window and currently publishing. Please wait for it to be done and try again later." 626 626 627 - #: src/components/compose.jsx:912 627 + #: src/components/compose.jsx:913 628 628 msgid "Looks like you already have a compose field open in the parent window. Popping in this window will discard the changes you made in the parent window. Continue?" 629 629 msgstr "Looks like you already have a compose field open in the parent window. Popping in this window will discard the changes you made in the parent window. Continue?" 630 630 631 - #: src/components/compose.jsx:955 631 + #: src/components/compose.jsx:956 632 632 msgid "Pop in" 633 633 msgstr "Pop in" 634 634 635 635 #. placeholder {0}: replyToStatus.account.acct || replyToStatus.account.username 636 636 #. placeholder {1}: rtf.format(-replyToStatusMonthsAgo, 'month') 637 - #: src/components/compose.jsx:965 637 + #: src/components/compose.jsx:966 638 638 msgid "Replying to @{0}’s post (<0>{1}</0>)" 639 639 msgstr "" 640 640 641 641 #. placeholder {0}: replyToStatus.account.acct || replyToStatus.account.username 642 - #: src/components/compose.jsx:975 642 + #: src/components/compose.jsx:976 643 643 msgid "Replying to @{0}’s post" 644 644 msgstr "" 645 645 646 - #: src/components/compose.jsx:988 646 + #: src/components/compose.jsx:989 647 647 msgid "Editing source post" 648 648 msgstr "" 649 649 650 - #: src/components/compose.jsx:1041 650 + #: src/components/compose.jsx:1042 651 651 msgid "Poll must have at least 2 options" 652 652 msgstr "Poll must have at least 2 options" 653 653 654 - #: src/components/compose.jsx:1045 654 + #: src/components/compose.jsx:1046 655 655 msgid "Some poll choices are empty" 656 656 msgstr "Some poll choices are empty" 657 657 658 - #: src/components/compose.jsx:1058 658 + #: src/components/compose.jsx:1059 659 659 msgid "Some media have no descriptions. Continue?" 660 660 msgstr "Some media have no descriptions. Continue?" 661 661 662 - #: src/components/compose.jsx:1110 662 + #: src/components/compose.jsx:1111 663 663 msgid "Attachment #{i} failed" 664 664 msgstr "Attachment #{i} failed" 665 665 666 - #: src/components/compose.jsx:1206 667 - #: src/components/status.jsx:2076 666 + #: src/components/compose.jsx:1207 667 + #: src/components/status.jsx:2098 668 668 #: src/components/timeline.jsx:989 669 669 msgid "Content warning" 670 670 msgstr "" 671 671 672 - #: src/components/compose.jsx:1222 672 + #: src/components/compose.jsx:1223 673 673 msgid "Content warning or sensitive media" 674 674 msgstr "Content warning or sensitive media" 675 675 676 - #: src/components/compose.jsx:1258 677 - #: src/components/status.jsx:93 676 + #: src/components/compose.jsx:1259 677 + #: src/components/status.jsx:94 678 678 #: src/pages/settings.jsx:306 679 679 msgid "Public" 680 680 msgstr "" 681 681 682 - #: src/components/compose.jsx:1263 682 + #: src/components/compose.jsx:1264 683 683 #: src/components/nav-menu.jsx:344 684 684 #: src/components/shortcuts-settings.jsx:165 685 - #: src/components/status.jsx:94 685 + #: src/components/status.jsx:95 686 686 msgid "Local" 687 687 msgstr "" 688 688 689 - #: src/components/compose.jsx:1267 690 - #: src/components/status.jsx:95 689 + #: src/components/compose.jsx:1268 690 + #: src/components/status.jsx:96 691 691 #: src/pages/settings.jsx:309 692 692 msgid "Unlisted" 693 693 msgstr "" 694 694 695 - #: src/components/compose.jsx:1270 696 - #: src/components/status.jsx:96 695 + #: src/components/compose.jsx:1271 696 + #: src/components/status.jsx:97 697 697 #: src/pages/settings.jsx:312 698 698 msgid "Followers only" 699 699 msgstr "" 700 700 701 - #: src/components/compose.jsx:1273 702 - #: src/components/status.jsx:97 703 - #: src/components/status.jsx:1954 701 + #: src/components/compose.jsx:1274 702 + #: src/components/status.jsx:98 703 + #: src/components/status.jsx:1976 704 704 msgid "Private mention" 705 705 msgstr "" 706 706 707 - #: src/components/compose.jsx:1282 707 + #: src/components/compose.jsx:1283 708 708 msgid "Post your reply" 709 709 msgstr "Post your reply" 710 710 711 - #: src/components/compose.jsx:1284 711 + #: src/components/compose.jsx:1285 712 712 msgid "Edit your post" 713 713 msgstr "Edit your post" 714 714 715 - #: src/components/compose.jsx:1285 715 + #: src/components/compose.jsx:1286 716 716 msgid "What are you doing?" 717 717 msgstr "What are you doing?" 718 718 719 - #: src/components/compose.jsx:1363 719 + #: src/components/compose.jsx:1364 720 720 msgid "Mark media as sensitive" 721 721 msgstr "" 722 722 723 - #: src/components/compose.jsx:1400 723 + #: src/components/compose.jsx:1401 724 724 msgid "Posting on <0/>" 725 725 msgstr "Posting on <0/>" 726 726 727 - #: src/components/compose.jsx:1431 728 - #: src/components/compose.jsx:3184 727 + #: src/components/compose.jsx:1432 728 + #: src/components/compose.jsx:3191 729 729 #: src/components/shortcuts-settings.jsx:715 730 730 #: src/pages/list.jsx:362 731 731 msgid "Add" 732 732 msgstr "" 733 733 734 - #: src/components/compose.jsx:1625 734 + #: src/components/compose.jsx:1626 735 735 msgid "Schedule" 736 736 msgstr "Schedule" 737 737 738 - #: src/components/compose.jsx:1627 738 + #: src/components/compose.jsx:1628 739 739 #: src/components/keyboard-shortcuts-help.jsx:154 740 - #: src/components/status.jsx:962 741 - #: src/components/status.jsx:1728 742 - #: src/components/status.jsx:1729 743 - #: src/components/status.jsx:2399 740 + #: src/components/status.jsx:984 741 + #: src/components/status.jsx:1750 742 + #: src/components/status.jsx:1751 743 + #: src/components/status.jsx:2421 744 744 msgid "Reply" 745 745 msgstr "" 746 746 747 - #: src/components/compose.jsx:1629 747 + #: src/components/compose.jsx:1630 748 748 msgid "Update" 749 749 msgstr "Update" 750 750 751 - #: src/components/compose.jsx:1630 751 + #: src/components/compose.jsx:1631 752 752 msgctxt "Submit button in composer" 753 753 msgid "Post" 754 754 msgstr "Post" 755 755 756 - #: src/components/compose.jsx:1758 756 + #: src/components/compose.jsx:1759 757 757 msgid "Downloading GIF…" 758 758 msgstr "Downloading GIF…" 759 759 760 - #: src/components/compose.jsx:1786 760 + #: src/components/compose.jsx:1787 761 761 msgid "Failed to download GIF" 762 762 msgstr "Failed to download GIF" 763 763 764 - #: src/components/compose.jsx:1956 765 - #: src/components/compose.jsx:2033 764 + #: src/components/compose.jsx:1963 765 + #: src/components/compose.jsx:2040 766 766 #: src/components/nav-menu.jsx:239 767 767 msgid "More…" 768 768 msgstr "" 769 769 770 - #: src/components/compose.jsx:2465 770 + #: src/components/compose.jsx:2472 771 771 msgid "Uploaded" 772 772 msgstr "" 773 773 774 - #: src/components/compose.jsx:2478 774 + #: src/components/compose.jsx:2485 775 775 msgid "Image description" 776 776 msgstr "Image description" 777 777 778 - #: src/components/compose.jsx:2479 778 + #: src/components/compose.jsx:2486 779 779 msgid "Video description" 780 780 msgstr "Video description" 781 781 782 - #: src/components/compose.jsx:2480 782 + #: src/components/compose.jsx:2487 783 783 msgid "Audio description" 784 784 msgstr "Audio description" 785 785 786 786 #. placeholder {0}: prettyBytes( imageSize, ) 787 787 #. placeholder {1}: prettyBytes(imageSizeLimit) 788 - #: src/components/compose.jsx:2516 788 + #: src/components/compose.jsx:2523 789 789 msgid "File size too large. Uploading might encounter issues. Try reduce the file size from {0} to {1} or lower." 790 790 msgstr "File size too large. Uploading might encounter issues. Try reduce the file size from {0} to {1} or lower." 791 791 ··· 793 793 #. placeholder {3}: i18n.number(height) 794 794 #. placeholder {4}: i18n.number(newWidth) 795 795 #. placeholder {5}: i18n.number( newHeight, ) 796 - #: src/components/compose.jsx:2528 796 + #: src/components/compose.jsx:2535 797 797 msgid "Dimension too large. Uploading might encounter issues. Try reduce dimension from {2}×{3}px to {4}×{5}px." 798 798 msgstr "Dimension too large. Uploading might encounter issues. Try reduce dimension from {2}×{3}px to {4}×{5}px." 799 799 800 800 #. placeholder {6}: prettyBytes( videoSize, ) 801 801 #. placeholder {7}: prettyBytes(videoSizeLimit) 802 - #: src/components/compose.jsx:2536 802 + #: src/components/compose.jsx:2543 803 803 msgid "File size too large. Uploading might encounter issues. Try reduce the file size from {6} to {7} or lower." 804 804 msgstr "File size too large. Uploading might encounter issues. Try reduce the file size from {6} to {7} or lower." 805 805 ··· 807 807 #. placeholder {9}: i18n.number(height) 808 808 #. placeholder {10}: i18n.number(newWidth) 809 809 #. placeholder {11}: i18n.number( newHeight, ) 810 - #: src/components/compose.jsx:2548 810 + #: src/components/compose.jsx:2555 811 811 msgid "Dimension too large. Uploading might encounter issues. Try reduce dimension from {8}×{9}px to {10}×{11}px." 812 812 msgstr "Dimension too large. Uploading might encounter issues. Try reduce dimension from {8}×{9}px to {10}×{11}px." 813 813 814 - #: src/components/compose.jsx:2556 814 + #: src/components/compose.jsx:2563 815 815 msgid "Frame rate too high. Uploading might encounter issues." 816 816 msgstr "Frame rate too high. Uploading might encounter issues." 817 817 818 - #: src/components/compose.jsx:2616 819 - #: src/components/compose.jsx:2866 818 + #: src/components/compose.jsx:2623 819 + #: src/components/compose.jsx:2873 820 820 #: src/components/shortcuts-settings.jsx:726 821 821 #: src/pages/catchup.jsx:1074 822 822 #: src/pages/filters.jsx:412 823 823 msgid "Remove" 824 824 msgstr "" 825 825 826 - #: src/components/compose.jsx:2633 826 + #: src/components/compose.jsx:2640 827 827 #: src/compose.jsx:84 828 828 msgid "Error" 829 829 msgstr "" 830 830 831 - #: src/components/compose.jsx:2658 831 + #: src/components/compose.jsx:2665 832 832 msgid "Edit image description" 833 833 msgstr "Edit image description" 834 834 835 - #: src/components/compose.jsx:2659 835 + #: src/components/compose.jsx:2666 836 836 msgid "Edit video description" 837 837 msgstr "Edit video description" 838 838 839 - #: src/components/compose.jsx:2660 839 + #: src/components/compose.jsx:2667 840 840 msgid "Edit audio description" 841 841 msgstr "Edit audio description" 842 842 843 - #: src/components/compose.jsx:2705 844 - #: src/components/compose.jsx:2754 843 + #: src/components/compose.jsx:2712 844 + #: src/components/compose.jsx:2761 845 845 msgid "Generating description. Please wait…" 846 846 msgstr "Generating description. Please wait…" 847 847 848 848 #. placeholder {12}: e.message 849 - #: src/components/compose.jsx:2725 849 + #: src/components/compose.jsx:2732 850 850 msgid "Failed to generate description: {12}" 851 851 msgstr "Failed to generate description: {12}" 852 852 853 - #: src/components/compose.jsx:2726 853 + #: src/components/compose.jsx:2733 854 854 msgid "Failed to generate description" 855 855 msgstr "Failed to generate description" 856 856 857 - #: src/components/compose.jsx:2738 858 - #: src/components/compose.jsx:2744 859 - #: src/components/compose.jsx:2790 857 + #: src/components/compose.jsx:2745 858 + #: src/components/compose.jsx:2751 859 + #: src/components/compose.jsx:2797 860 860 msgid "Generate description…" 861 861 msgstr "" 862 862 863 863 #. placeholder {13}: e?.message ? `: ${e.message}` : '' 864 - #: src/components/compose.jsx:2777 864 + #: src/components/compose.jsx:2784 865 865 msgid "Failed to generate description{13}" 866 866 msgstr "Failed to generate description{13}" 867 867 868 868 #. placeholder {0}: localeCode2Text(lang) 869 - #: src/components/compose.jsx:2792 869 + #: src/components/compose.jsx:2799 870 870 msgid "({0}) <0>— experimental</0>" 871 871 msgstr "" 872 872 873 - #: src/components/compose.jsx:2811 873 + #: src/components/compose.jsx:2818 874 874 msgid "Done" 875 875 msgstr "" 876 876 877 877 #. placeholder {0}: i + 1 878 - #: src/components/compose.jsx:2847 878 + #: src/components/compose.jsx:2854 879 879 msgid "Choice {0}" 880 880 msgstr "Choice {0}" 881 881 882 - #: src/components/compose.jsx:2894 882 + #: src/components/compose.jsx:2901 883 883 msgid "Multiple choices" 884 884 msgstr "" 885 885 886 - #: src/components/compose.jsx:2897 886 + #: src/components/compose.jsx:2904 887 887 msgid "Duration" 888 888 msgstr "" 889 889 890 - #: src/components/compose.jsx:2928 890 + #: src/components/compose.jsx:2935 891 891 msgid "Remove poll" 892 892 msgstr "" 893 893 894 - #: src/components/compose.jsx:3143 894 + #: src/components/compose.jsx:3150 895 895 msgid "Search accounts" 896 896 msgstr "Search accounts" 897 897 898 - #: src/components/compose.jsx:3197 898 + #: src/components/compose.jsx:3204 899 899 #: src/components/generic-accounts.jsx:228 900 900 msgid "Error loading accounts" 901 901 msgstr "" 902 902 903 - #: src/components/compose.jsx:3341 903 + #: src/components/compose.jsx:3348 904 904 msgid "Custom emojis" 905 905 msgstr "" 906 906 907 - #: src/components/compose.jsx:3361 907 + #: src/components/compose.jsx:3368 908 908 msgid "Search emoji" 909 909 msgstr "Search emoji" 910 910 911 - #: src/components/compose.jsx:3392 911 + #: src/components/compose.jsx:3399 912 912 msgid "Error loading custom emojis" 913 913 msgstr "" 914 914 915 - #: src/components/compose.jsx:3403 915 + #: src/components/compose.jsx:3410 916 916 msgid "Recently used" 917 917 msgstr "Recently used" 918 918 919 - #: src/components/compose.jsx:3404 919 + #: src/components/compose.jsx:3411 920 920 msgid "Others" 921 921 msgstr "Others" 922 922 923 923 #. placeholder {0}: i18n.number(emojis.length - max) 924 - #: src/components/compose.jsx:3442 924 + #: src/components/compose.jsx:3449 925 925 msgid "{0} more…" 926 926 msgstr "" 927 927 928 - #: src/components/compose.jsx:3580 928 + #: src/components/compose.jsx:3587 929 929 msgid "Search GIFs" 930 930 msgstr "Search GIFs" 931 931 932 - #: src/components/compose.jsx:3595 932 + #: src/components/compose.jsx:3602 933 933 msgid "Powered by GIPHY" 934 934 msgstr "Powered by GIPHY" 935 935 936 - #: src/components/compose.jsx:3603 936 + #: src/components/compose.jsx:3610 937 937 msgid "Type to search GIFs" 938 938 msgstr "" 939 939 940 - #: src/components/compose.jsx:3701 940 + #: src/components/compose.jsx:3708 941 941 #: src/components/media-modal.jsx:464 942 942 #: src/components/timeline.jsx:893 943 943 msgid "Previous" 944 944 msgstr "" 945 945 946 - #: src/components/compose.jsx:3719 946 + #: src/components/compose.jsx:3726 947 947 #: src/components/media-modal.jsx:483 948 948 #: src/components/timeline.jsx:910 949 949 msgid "Next" 950 950 msgstr "" 951 951 952 - #: src/components/compose.jsx:3736 952 + #: src/components/compose.jsx:3743 953 953 msgid "Error loading GIFs" 954 954 msgstr "" 955 955 ··· 972 972 973 973 #: src/components/drafts.jsx:128 974 974 #: src/components/list-add-edit.jsx:186 975 - #: src/components/status.jsx:1363 975 + #: src/components/status.jsx:1385 976 976 #: src/pages/filters.jsx:587 977 977 #: src/pages/scheduled-posts.jsx:367 978 978 msgid "Delete…" ··· 1181 1181 msgstr "" 1182 1182 1183 1183 #: src/components/keyboard-shortcuts-help.jsx:175 1184 - #: src/components/status.jsx:970 1185 - #: src/components/status.jsx:2426 1186 - #: src/components/status.jsx:2449 1187 - #: src/components/status.jsx:2450 1184 + #: src/components/status.jsx:992 1185 + #: src/components/status.jsx:2448 1186 + #: src/components/status.jsx:2471 1187 + #: src/components/status.jsx:2472 1188 1188 msgid "Boost" 1189 1189 msgstr "" 1190 1190 ··· 1193 1193 msgstr "" 1194 1194 1195 1195 #: src/components/keyboard-shortcuts-help.jsx:183 1196 - #: src/components/status.jsx:1033 1197 - #: src/components/status.jsx:2474 1198 - #: src/components/status.jsx:2475 1196 + #: src/components/status.jsx:1055 1197 + #: src/components/status.jsx:2496 1198 + #: src/components/status.jsx:2497 1199 1199 msgid "Bookmark" 1200 1200 msgstr "" 1201 1201 ··· 1254 1254 msgstr "" 1255 1255 1256 1256 #: src/components/media-alt-modal.jsx:58 1257 - #: src/components/status.jsx:1077 1258 - #: src/components/status.jsx:1104 1259 - #: src/components/translation-block.jsx:196 1257 + #: src/components/status.jsx:1099 1258 + #: src/components/status.jsx:1126 1259 + #: src/components/translation-block.jsx:215 1260 1260 msgid "Translate" 1261 1261 msgstr "" 1262 1262 1263 1263 #: src/components/media-alt-modal.jsx:69 1264 - #: src/components/status.jsx:1091 1265 - #: src/components/status.jsx:1118 1264 + #: src/components/status.jsx:1113 1265 + #: src/components/status.jsx:1140 1266 1266 msgid "Speak" 1267 1267 msgstr "" 1268 1268 ··· 1299 1299 msgstr "" 1300 1300 1301 1301 #: src/components/media-post.jsx:134 1302 - #: src/components/status.jsx:3568 1303 - #: src/components/status.jsx:3664 1304 - #: src/components/status.jsx:3742 1302 + #: src/components/status.jsx:3590 1303 + #: src/components/status.jsx:3686 1304 + #: src/components/status.jsx:3764 1305 1305 #: src/components/timeline.jsx:978 1306 1306 #: src/pages/catchup.jsx:75 1307 1307 #: src/pages/catchup.jsx:1877 ··· 1619 1619 msgstr "" 1620 1620 1621 1621 #: src/components/notification.jsx:441 1622 - #: src/components/status.jsx:1047 1623 - #: src/components/status.jsx:1057 1622 + #: src/components/status.jsx:1069 1623 + #: src/components/status.jsx:1079 1624 1624 msgid "Boosted/Liked by…" 1625 1625 msgstr "" 1626 1626 ··· 1646 1646 msgstr "View #Wrapstodon" 1647 1647 1648 1648 #: src/components/notification.jsx:770 1649 - #: src/components/status.jsx:275 1649 + #: src/components/status.jsx:297 1650 1650 msgid "Read more →" 1651 1651 msgstr "" 1652 1652 ··· 1948 1948 msgstr "" 1949 1949 1950 1950 #: src/components/shortcuts-settings.jsx:379 1951 - #: src/components/status.jsx:1325 1951 + #: src/components/status.jsx:1347 1952 1952 #: src/pages/list.jsx:171 1953 1953 msgid "Edit" 1954 1954 msgstr "" ··· 2147 2147 msgid "Import/export settings from/to instance server (Very experimental)" 2148 2148 msgstr "" 2149 2149 2150 - #: src/components/status.jsx:549 2150 + #: src/components/status.jsx:571 2151 2151 msgid "<0/> <1>boosted</1>" 2152 2152 msgstr "" 2153 2153 2154 - #: src/components/status.jsx:648 2154 + #: src/components/status.jsx:670 2155 2155 msgid "Sorry, your current logged-in instance can't interact with this post from another instance." 2156 2156 msgstr "" 2157 2157 2158 2158 #. placeholder {0}: username || acct 2159 - #: src/components/status.jsx:801 2159 + #: src/components/status.jsx:823 2160 2160 msgid "Unliked @{0}'s post" 2161 2161 msgstr "" 2162 2162 2163 2163 #. placeholder {1}: username || acct 2164 - #: src/components/status.jsx:802 2164 + #: src/components/status.jsx:824 2165 2165 msgid "Liked @{1}'s post" 2166 2166 msgstr "Liked @{1}'s post" 2167 2167 2168 2168 #. placeholder {2}: username || acct 2169 - #: src/components/status.jsx:841 2169 + #: src/components/status.jsx:863 2170 2170 msgid "Unbookmarked @{2}'s post" 2171 2171 msgstr "Unbookmarked @{2}'s post" 2172 2172 2173 2173 #. placeholder {3}: username || acct 2174 - #: src/components/status.jsx:842 2174 + #: src/components/status.jsx:864 2175 2175 msgid "Bookmarked @{3}'s post" 2176 2176 msgstr "Bookmarked @{3}'s post" 2177 2177 2178 - #: src/components/status.jsx:939 2178 + #: src/components/status.jsx:961 2179 2179 msgid "Some media have no descriptions." 2180 2180 msgstr "" 2181 2181 2182 2182 #. placeholder {0}: rtf.format(-statusMonthsAgo, 'month') 2183 - #: src/components/status.jsx:946 2183 + #: src/components/status.jsx:968 2184 2184 msgid "Old post (<0>{0}</0>)" 2185 2185 msgstr "" 2186 2186 2187 - #: src/components/status.jsx:970 2188 - #: src/components/status.jsx:1010 2189 - #: src/components/status.jsx:2426 2190 - #: src/components/status.jsx:2449 2187 + #: src/components/status.jsx:992 2188 + #: src/components/status.jsx:1032 2189 + #: src/components/status.jsx:2448 2190 + #: src/components/status.jsx:2471 2191 2191 msgid "Unboost" 2192 2192 msgstr "" 2193 2193 2194 - #: src/components/status.jsx:986 2195 - #: src/components/status.jsx:2441 2194 + #: src/components/status.jsx:1008 2195 + #: src/components/status.jsx:2463 2196 2196 msgid "Quote" 2197 2197 msgstr "" 2198 2198 2199 2199 #. placeholder {4}: username || acct 2200 - #: src/components/status.jsx:998 2200 + #: src/components/status.jsx:1020 2201 2201 msgid "Unboosted @{4}'s post" 2202 2202 msgstr "Unboosted @{4}'s post" 2203 2203 2204 2204 #. placeholder {5}: username || acct 2205 - #: src/components/status.jsx:999 2205 + #: src/components/status.jsx:1021 2206 2206 msgid "Boosted @{5}'s post" 2207 2207 msgstr "Boosted @{5}'s post" 2208 2208 2209 - #: src/components/status.jsx:1011 2209 + #: src/components/status.jsx:1033 2210 2210 msgid "Boost…" 2211 2211 msgstr "" 2212 2212 2213 - #: src/components/status.jsx:1023 2214 - #: src/components/status.jsx:1738 2215 - #: src/components/status.jsx:2462 2213 + #: src/components/status.jsx:1045 2214 + #: src/components/status.jsx:1760 2215 + #: src/components/status.jsx:2484 2216 2216 msgid "Unlike" 2217 2217 msgstr "" 2218 2218 2219 - #: src/components/status.jsx:1024 2220 - #: src/components/status.jsx:1738 2221 - #: src/components/status.jsx:1739 2222 - #: src/components/status.jsx:2462 2223 - #: src/components/status.jsx:2463 2219 + #: src/components/status.jsx:1046 2220 + #: src/components/status.jsx:1760 2221 + #: src/components/status.jsx:1761 2222 + #: src/components/status.jsx:2484 2223 + #: src/components/status.jsx:2485 2224 2224 msgid "Like" 2225 2225 msgstr "" 2226 2226 2227 - #: src/components/status.jsx:1033 2228 - #: src/components/status.jsx:2474 2227 + #: src/components/status.jsx:1055 2228 + #: src/components/status.jsx:2496 2229 2229 msgid "Unbookmark" 2230 2230 msgstr "" 2231 2231 2232 2232 #. placeholder {0}: username || acct 2233 - #: src/components/status.jsx:1141 2233 + #: src/components/status.jsx:1163 2234 2234 msgid "View post by <0>@{0}</0>" 2235 2235 msgstr "" 2236 2236 2237 - #: src/components/status.jsx:1162 2237 + #: src/components/status.jsx:1184 2238 2238 msgid "Show Edit History" 2239 2239 msgstr "" 2240 2240 2241 - #: src/components/status.jsx:1165 2241 + #: src/components/status.jsx:1187 2242 2242 msgid "Edited: {editedDateText}" 2243 2243 msgstr "" 2244 2244 2245 - #: src/components/status.jsx:1232 2246 - #: src/components/status.jsx:3243 2245 + #: src/components/status.jsx:1254 2246 + #: src/components/status.jsx:3265 2247 2247 msgid "Embed post" 2248 2248 msgstr "" 2249 2249 2250 - #: src/components/status.jsx:1246 2250 + #: src/components/status.jsx:1268 2251 2251 msgid "Conversation unmuted" 2252 2252 msgstr "" 2253 2253 2254 - #: src/components/status.jsx:1246 2254 + #: src/components/status.jsx:1268 2255 2255 msgid "Conversation muted" 2256 2256 msgstr "" 2257 2257 2258 - #: src/components/status.jsx:1252 2258 + #: src/components/status.jsx:1274 2259 2259 msgid "Unable to unmute conversation" 2260 2260 msgstr "" 2261 2261 2262 - #: src/components/status.jsx:1253 2262 + #: src/components/status.jsx:1275 2263 2263 msgid "Unable to mute conversation" 2264 2264 msgstr "" 2265 2265 2266 - #: src/components/status.jsx:1262 2266 + #: src/components/status.jsx:1284 2267 2267 msgid "Unmute conversation" 2268 2268 msgstr "" 2269 2269 2270 - #: src/components/status.jsx:1269 2270 + #: src/components/status.jsx:1291 2271 2271 msgid "Mute conversation" 2272 2272 msgstr "" 2273 2273 2274 - #: src/components/status.jsx:1285 2274 + #: src/components/status.jsx:1307 2275 2275 msgid "Post unpinned from profile" 2276 2276 msgstr "" 2277 2277 2278 - #: src/components/status.jsx:1286 2278 + #: src/components/status.jsx:1308 2279 2279 msgid "Post pinned to profile" 2280 2280 msgstr "" 2281 2281 2282 - #: src/components/status.jsx:1291 2282 + #: src/components/status.jsx:1313 2283 2283 msgid "Unable to unpin post" 2284 2284 msgstr "" 2285 2285 2286 - #: src/components/status.jsx:1291 2286 + #: src/components/status.jsx:1313 2287 2287 msgid "Unable to pin post" 2288 2288 msgstr "" 2289 2289 2290 - #: src/components/status.jsx:1300 2290 + #: src/components/status.jsx:1322 2291 2291 msgid "Unpin from profile" 2292 2292 msgstr "" 2293 2293 2294 - #: src/components/status.jsx:1307 2294 + #: src/components/status.jsx:1329 2295 2295 msgid "Pin to profile" 2296 2296 msgstr "" 2297 2297 2298 - #: src/components/status.jsx:1336 2298 + #: src/components/status.jsx:1358 2299 2299 msgid "Delete this post?" 2300 2300 msgstr "" 2301 2301 2302 - #: src/components/status.jsx:1352 2302 + #: src/components/status.jsx:1374 2303 2303 msgid "Post deleted" 2304 2304 msgstr "" 2305 2305 2306 - #: src/components/status.jsx:1355 2306 + #: src/components/status.jsx:1377 2307 2307 msgid "Unable to delete post" 2308 2308 msgstr "" 2309 2309 2310 - #: src/components/status.jsx:1383 2310 + #: src/components/status.jsx:1405 2311 2311 msgid "Report post…" 2312 2312 msgstr "" 2313 2313 2314 2314 #. placeholder {6}: username || acct 2315 - #: src/components/status.jsx:1453 2315 + #: src/components/status.jsx:1475 2316 2316 msgid "Unboosted @{6}'s post" 2317 2317 msgstr "Unboosted @{6}'s post" 2318 2318 2319 2319 #. placeholder {7}: username || acct 2320 - #: src/components/status.jsx:1454 2320 + #: src/components/status.jsx:1476 2321 2321 msgid "Boosted @{7}'s post" 2322 2322 msgstr "Boosted @{7}'s post" 2323 2323 2324 - #: src/components/status.jsx:1739 2325 - #: src/components/status.jsx:1775 2326 - #: src/components/status.jsx:2463 2324 + #: src/components/status.jsx:1761 2325 + #: src/components/status.jsx:1797 2326 + #: src/components/status.jsx:2485 2327 2327 msgid "Liked" 2328 2328 msgstr "" 2329 2329 2330 - #: src/components/status.jsx:1772 2331 - #: src/components/status.jsx:2450 2330 + #: src/components/status.jsx:1794 2331 + #: src/components/status.jsx:2472 2332 2332 msgid "Boosted" 2333 2333 msgstr "" 2334 2334 2335 - #: src/components/status.jsx:1782 2336 - #: src/components/status.jsx:2475 2335 + #: src/components/status.jsx:1804 2336 + #: src/components/status.jsx:2497 2337 2337 msgid "Bookmarked" 2338 2338 msgstr "" 2339 2339 2340 - #: src/components/status.jsx:1786 2340 + #: src/components/status.jsx:1808 2341 2341 msgid "Pinned" 2342 2342 msgstr "" 2343 2343 2344 - #: src/components/status.jsx:1832 2345 - #: src/components/status.jsx:2289 2344 + #: src/components/status.jsx:1854 2345 + #: src/components/status.jsx:2311 2346 2346 msgid "Deleted" 2347 2347 msgstr "" 2348 2348 2349 - #: src/components/status.jsx:1873 2349 + #: src/components/status.jsx:1895 2350 2350 msgid "{repliesCount, plural, one {# reply} other {# replies}}" 2351 2351 msgstr "" 2352 2352 2353 2353 #. placeholder {0}: snapStates.statusThreadNumber[sKey] ? ` ${snapStates.statusThreadNumber[sKey]}/X` : '' 2354 - #: src/components/status.jsx:1963 2354 + #: src/components/status.jsx:1985 2355 2355 msgid "Thread{0}" 2356 2356 msgstr "" 2357 2357 2358 - #: src/components/status.jsx:2039 2359 - #: src/components/status.jsx:2101 2360 - #: src/components/status.jsx:2186 2358 + #: src/components/status.jsx:2061 2359 + #: src/components/status.jsx:2123 2360 + #: src/components/status.jsx:2208 2361 2361 msgid "Show less" 2362 2362 msgstr "" 2363 2363 2364 - #: src/components/status.jsx:2039 2365 - #: src/components/status.jsx:2101 2364 + #: src/components/status.jsx:2061 2365 + #: src/components/status.jsx:2123 2366 2366 msgid "Show content" 2367 2367 msgstr "" 2368 2368 2369 - #: src/components/status.jsx:2186 2369 + #: src/components/status.jsx:2208 2370 2370 msgid "Show media" 2371 2371 msgstr "" 2372 2372 2373 - #: src/components/status.jsx:2323 2373 + #: src/components/status.jsx:2345 2374 2374 msgid "Edited" 2375 2375 msgstr "" 2376 2376 2377 - #: src/components/status.jsx:2400 2377 + #: src/components/status.jsx:2422 2378 2378 msgid "Comments" 2379 2379 msgstr "" 2380 2380 2381 2381 #. More from [Author] 2382 - #: src/components/status.jsx:2701 2382 + #: src/components/status.jsx:2723 2383 2383 msgid "More from <0/>" 2384 2384 msgstr "More from <0/>" 2385 2385 2386 - #: src/components/status.jsx:3003 2386 + #: src/components/status.jsx:3025 2387 2387 msgid "Edit History" 2388 2388 msgstr "" 2389 2389 2390 - #: src/components/status.jsx:3007 2390 + #: src/components/status.jsx:3029 2391 2391 msgid "Failed to load history" 2392 2392 msgstr "" 2393 2393 2394 - #: src/components/status.jsx:3012 2394 + #: src/components/status.jsx:3034 2395 2395 #: src/pages/annual-report.jsx:45 2396 2396 msgid "Loading…" 2397 2397 msgstr "" 2398 2398 2399 - #: src/components/status.jsx:3248 2399 + #: src/components/status.jsx:3270 2400 2400 msgid "HTML Code" 2401 2401 msgstr "" 2402 2402 2403 - #: src/components/status.jsx:3265 2403 + #: src/components/status.jsx:3287 2404 2404 msgid "HTML code copied" 2405 2405 msgstr "" 2406 2406 2407 - #: src/components/status.jsx:3268 2407 + #: src/components/status.jsx:3290 2408 2408 msgid "Unable to copy HTML code" 2409 2409 msgstr "" 2410 2410 2411 - #: src/components/status.jsx:3280 2411 + #: src/components/status.jsx:3302 2412 2412 msgid "Media attachments:" 2413 2413 msgstr "" 2414 2414 2415 - #: src/components/status.jsx:3302 2415 + #: src/components/status.jsx:3324 2416 2416 msgid "Account Emojis:" 2417 2417 msgstr "" 2418 2418 2419 - #: src/components/status.jsx:3333 2420 - #: src/components/status.jsx:3378 2419 + #: src/components/status.jsx:3355 2420 + #: src/components/status.jsx:3400 2421 2421 msgid "static URL" 2422 2422 msgstr "" 2423 2423 2424 - #: src/components/status.jsx:3347 2424 + #: src/components/status.jsx:3369 2425 2425 msgid "Emojis:" 2426 2426 msgstr "" 2427 2427 2428 - #: src/components/status.jsx:3392 2428 + #: src/components/status.jsx:3414 2429 2429 msgid "Notes:" 2430 2430 msgstr "" 2431 2431 2432 - #: src/components/status.jsx:3396 2432 + #: src/components/status.jsx:3418 2433 2433 msgid "This is static, unstyled and scriptless. You may need to apply your own styles and edit as needed." 2434 2434 msgstr "" 2435 2435 2436 - #: src/components/status.jsx:3402 2436 + #: src/components/status.jsx:3424 2437 2437 msgid "Polls are not interactive, becomes a list with vote counts." 2438 2438 msgstr "" 2439 2439 2440 - #: src/components/status.jsx:3407 2440 + #: src/components/status.jsx:3429 2441 2441 msgid "Media attachments can be images, videos, audios or any file types." 2442 2442 msgstr "" 2443 2443 2444 - #: src/components/status.jsx:3413 2444 + #: src/components/status.jsx:3435 2445 2445 msgid "Post could be edited or deleted later." 2446 2446 msgstr "" 2447 2447 2448 - #: src/components/status.jsx:3419 2448 + #: src/components/status.jsx:3441 2449 2449 msgid "Preview" 2450 2450 msgstr "" 2451 2451 2452 - #: src/components/status.jsx:3428 2452 + #: src/components/status.jsx:3450 2453 2453 msgid "Note: This preview is lightly styled." 2454 2454 msgstr "" 2455 2455 2456 2456 #. [Name] [Visibility icon] boosted 2457 - #: src/components/status.jsx:3672 2457 + #: src/components/status.jsx:3694 2458 2458 msgid "<0/> <1/> boosted" 2459 2459 msgstr "" 2460 2460 ··· 2491 2491 msgid "<0>Filtered</0>: <1>{0}</1>" 2492 2492 msgstr "" 2493 2493 2494 - #: src/components/translation-block.jsx:153 2494 + #: src/components/translation-block.jsx:172 2495 2495 msgid "Auto-translated from {sourceLangText}" 2496 2496 msgstr "" 2497 2497 2498 - #: src/components/translation-block.jsx:191 2498 + #: src/components/translation-block.jsx:210 2499 2499 msgid "Translating…" 2500 2500 msgstr "" 2501 2501 2502 - #: src/components/translation-block.jsx:194 2502 + #: src/components/translation-block.jsx:213 2503 2503 msgid "Translate from {sourceLangText} (auto-detected)" 2504 2504 msgstr "" 2505 2505 2506 - #: src/components/translation-block.jsx:195 2506 + #: src/components/translation-block.jsx:214 2507 2507 msgid "Translate from {sourceLangText}" 2508 2508 msgstr "" 2509 2509 2510 2510 #. placeholder {0}: detectedLang ?? '…' 2511 - #: src/components/translation-block.jsx:223 2511 + #: src/components/translation-block.jsx:242 2512 2512 msgid "Auto ({0})" 2513 2513 msgstr "" 2514 2514 2515 - #: src/components/translation-block.jsx:236 2515 + #: src/components/translation-block.jsx:255 2516 2516 msgid "Failed to translate" 2517 2517 msgstr "" 2518 2518
+107
src/utils/browser-translator.js
··· 1 + export const supportsBrowserTranslator = 2 + 'ai' in self && 'translator' in self.ai; 3 + 4 + // https://developer.chrome.com/docs/ai/language-detection 5 + export let langDetector; 6 + if (supportsBrowserTranslator) { 7 + try { 8 + const languageDetectorCapabilities = 9 + await self.ai.languageDetector.capabilities(); 10 + const canDetect = languageDetectorCapabilities.capabilities; 11 + if (canDetect === 'no') { 12 + // The language detector isn't usable. 13 + // return; 14 + } 15 + if (canDetect === 'readily') { 16 + // The language detector can immediately be used. 17 + langDetector = await self.ai.languageDetector.create(); 18 + } else { 19 + // The language detector can be used after model download. 20 + langDetector = await self.ai.languageDetector.create({ 21 + monitor(m) { 22 + m.addEventListener('downloadprogress', (e) => { 23 + console.log( 24 + `Detector: Downloaded ${e.loaded} of ${e.total} bytes.`, 25 + ); 26 + }); 27 + }, 28 + }); 29 + await langDetector.ready; 30 + } 31 + } catch (e) { 32 + console.error(e); 33 + } 34 + } 35 + 36 + // https://developer.chrome.com/docs/ai/translator-api 37 + export const translate = async (text, source, target) => { 38 + let detectedSourceLanguage; 39 + const originalSource = source; 40 + if (source === 'auto') { 41 + try { 42 + const results = await langDetector.detect(text); 43 + source = results[0].detectedLanguage; 44 + detectedSourceLanguage = source; 45 + } catch (e) { 46 + console.error(e); 47 + return { 48 + error: e, 49 + }; 50 + } 51 + } 52 + console.groupCollapsed( 53 + '💬 BROWSER TRANSLATE', 54 + originalSource, 55 + detectedSourceLanguage, 56 + target, 57 + ); 58 + console.log(text); 59 + try { 60 + const translatorCapabilities = await self.ai.translator.capabilities(); 61 + const canTranslate = translatorCapabilities.languagePairAvailable( 62 + source, 63 + target, 64 + ); 65 + if (canTranslate === 'no') { 66 + console.groupEnd(); 67 + return { 68 + error: `Unsupported language pair: ${source} -> ${target}`, 69 + }; 70 + } 71 + let translator; 72 + if (canTranslate === 'readily') { 73 + translator = await self.ai.translator.create({ 74 + sourceLanguage: source, 75 + targetLanguage: target, 76 + }); 77 + } else { 78 + translator = await self.ai.translator.create({ 79 + sourceLanguage: source, 80 + targetLanguage: target, 81 + monitor(m) { 82 + m.addEventListener('downloadprogress', (e) => { 83 + console.log( 84 + `Translate ${source} -> ${target}: Downloaded ${e.loaded} of ${e.total} bytes.`, 85 + ); 86 + }); 87 + }, 88 + }); 89 + } 90 + 91 + const content = await translator.translate(text); 92 + console.log(content); 93 + console.groupEnd(); 94 + 95 + return { 96 + content, 97 + detectedSourceLanguage, 98 + provider: 'browser', 99 + }; 100 + } catch (e) { 101 + console.groupEnd(); 102 + console.error(e); 103 + return { 104 + error: e, 105 + }; 106 + } 107 + };