diff --git a/i18n/resources.json b/i18n/resources.json
new file mode 100644
index 0000000..47210c8
--- /dev/null
+++ b/i18n/resources.json
@@ -0,0 +1,70 @@
+{
+ "en": {
+ "translation": {
+ "translatedFrom": "Translated from {language}",
+ "quotedFrom": "Quoting {name} (@{screen_name})",
+ "replyingTo": "Replying to @{screen_name}",
+ "threadPartHeader": "A part of @${screen_name}'s thread",
+
+ "ivAuthorActionReply": "Reply from {authorName} (@{authorScreenName}):",
+ "ivAuthorActionOriginal": "Original from {authorName} (@{authorScreenName}):",
+ "ivAuthorActionFollowUp": "Follow-up from {authorName} (@{authorScreenName}):",
+ "ivQuoteHeader": "Quoting {authorName} (@{authorHandle})",
+
+ "photoCount": "Photo {number} / {total}",
+ "videoCount": "Video {number} / {total}",
+ "mediaCount": "Media {number} / {total}",
+
+ "videoAltTextUnavailable": "{author}'s video. Alt text not available.",
+ "gifAltTextUnavailable": "{author}'s GIF. Alt text not available.",
+
+ "ivOriginalText": "Original text",
+ "ivViewOriginal": "View full thread",
+ "ivAboutAuthor": "About author",
+ "ivProfileFollowing": "{numFollowing, plural,\none {Following}\nother {Following}\n}",
+ "ivProfileFollowers": "{numFollowers, plural,\none {Follower}\nother {Followers}\n}",
+ "ivProfileStatuses": "{numStatuses, plural,\none {Post}\nother {Posts}\n}",
+ "ivProfilePictureAlt": "{author}'s profile picture",
+
+ "ivFallbackText": "If you can see this, your browser is doing something weird with your user agent.",
+ "ivInternetArchiveText": "{brandingName} archive",
+
+ "pollFinalResults": "Final results",
+ "pollVotes": "{voteCount, plural,\none {# vote}\nother {# votes}\n} ยท {timeLeft}",
+ "ivPollChoice": "{voteCount, plural,\none {# vote}\nother {# votes}\n}, {percentage}%",
+ "ivCommunityNoteHeader": "Readers added context they thought people might want to know",
+
+ "gifIndicator": "GIF - {brandingName}",
+
+ "language_af": "Afrikaans",
+ "language_ar": "Arabic",
+ "language_ca": "Catalan",
+ "language_cs": "Czech",
+ "language_da": "Danish",
+ "language_de": "German",
+ "language_en": "English",
+ "language_el": "Greek",
+ "language_es": "Spanish",
+ "language_fi": "Finnish",
+ "language_fr": "French",
+ "language_he": "Hebrew",
+ "language_hu": "Hungarian",
+ "language_it": "Italian",
+ "language_ja": "Japanese",
+ "language_ko": "Korean",
+ "language_nl": "Dutch",
+ "language_no": "Norwegian",
+ "language_pl": "Polish",
+ "language_pt": "Portuguese",
+ "language_ro": "Romanian",
+ "language_ru": "Russian",
+ "language_sr": "Serbian",
+ "language_sv": "Swedish",
+ "language_tr": "Turkish",
+ "language_uk": "Ukrainian",
+ "language_vi": "Vietnamese",
+ "language_zh-CN": "Chinese",
+ "language_zh-TW": "Chinese"
+ }
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index 7c5c765..50c7fe5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,8 @@
"license": "MIT",
"dependencies": {
"@hono/sentry": "^1.0.1",
+ "i18next": "^23.8.2",
+ "i18next-icu": "^2.3.0",
"hono": "^4.2.9"
},
"devDependencies": {
@@ -35,6 +37,15 @@
"wrangler": "^3.53.0"
}
},
+ "node_modules/@aashutoshrathi/word-wrap": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
+ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/@ampproject/remapping": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
@@ -49,43 +60,43 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.24.2",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
- "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==",
+ "version": "7.23.5",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
+ "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
"dev": true,
"dependencies": {
- "@babel/highlight": "^7.24.2",
- "picocolors": "^1.0.0"
+ "@babel/highlight": "^7.23.4",
+ "chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/compat-data": {
- "version": "7.24.4",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz",
- "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==",
+ "version": "7.23.5",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz",
+ "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz",
- "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz",
+ "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.24.2",
- "@babel/generator": "^7.24.5",
+ "@babel/code-frame": "^7.23.5",
+ "@babel/generator": "^7.23.6",
"@babel/helper-compilation-targets": "^7.23.6",
- "@babel/helper-module-transforms": "^7.24.5",
- "@babel/helpers": "^7.24.5",
- "@babel/parser": "^7.24.5",
+ "@babel/helper-module-transforms": "^7.23.3",
+ "@babel/helpers": "^7.24.0",
+ "@babel/parser": "^7.24.0",
"@babel/template": "^7.24.0",
- "@babel/traverse": "^7.24.5",
- "@babel/types": "^7.24.5",
+ "@babel/traverse": "^7.24.0",
+ "@babel/types": "^7.24.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -101,14 +112,14 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz",
- "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==",
+ "version": "7.23.6",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz",
+ "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.24.5",
- "@jridgewell/gen-mapping": "^0.3.5",
- "@jridgewell/trace-mapping": "^0.3.25",
+ "@babel/types": "^7.23.6",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
},
"engines": {
@@ -166,28 +177,28 @@
}
},
"node_modules/@babel/helper-module-imports": {
- "version": "7.24.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz",
- "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
+ "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.24.0"
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz",
- "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
+ "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
"dev": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-module-imports": "^7.24.3",
- "@babel/helper-simple-access": "^7.24.5",
- "@babel/helper-split-export-declaration": "^7.24.5",
- "@babel/helper-validator-identifier": "^7.24.5"
+ "@babel/helper-module-imports": "^7.22.15",
+ "@babel/helper-simple-access": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/helper-validator-identifier": "^7.22.20"
},
"engines": {
"node": ">=6.9.0"
@@ -197,51 +208,51 @@
}
},
"node_modules/@babel/helper-plugin-utils": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz",
- "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
+ "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-simple-access": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz",
- "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
+ "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.24.5"
+ "@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz",
- "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==",
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.24.5"
+ "@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.24.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
- "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
+ "version": "7.23.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
+ "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
- "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@@ -257,38 +268,37 @@
}
},
"node_modules/@babel/helpers": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz",
- "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.0.tgz",
+ "integrity": "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==",
"dev": true,
"dependencies": {
"@babel/template": "^7.24.0",
- "@babel/traverse": "^7.24.5",
- "@babel/types": "^7.24.5"
+ "@babel/traverse": "^7.24.0",
+ "@babel/types": "^7.24.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/highlight": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz",
- "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==",
+ "version": "7.23.4",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
+ "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
"dev": true,
"dependencies": {
- "@babel/helper-validator-identifier": "^7.24.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
- "js-tokens": "^4.0.0",
- "picocolors": "^1.0.0"
+ "js-tokens": "^4.0.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz",
- "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz",
+ "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@@ -358,12 +368,12 @@
}
},
"node_modules/@babel/plugin-syntax-jsx": {
- "version": "7.24.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz",
- "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz",
+ "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==",
"dev": true,
"dependencies": {
- "@babel/helper-plugin-utils": "^7.24.0"
+ "@babel/helper-plugin-utils": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
@@ -460,12 +470,12 @@
}
},
"node_modules/@babel/plugin-syntax-typescript": {
- "version": "7.24.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz",
- "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz",
+ "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==",
"dev": true,
"dependencies": {
- "@babel/helper-plugin-utils": "^7.24.0"
+ "@babel/helper-plugin-utils": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
@@ -474,6 +484,17 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/runtime": {
+ "version": "7.23.9",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
+ "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
+ "dependencies": {
+ "regenerator-runtime": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/template": {
"version": "7.24.0",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz",
@@ -489,19 +510,19 @@
}
},
"node_modules/@babel/traverse": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz",
- "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz",
+ "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.24.2",
- "@babel/generator": "^7.24.5",
+ "@babel/code-frame": "^7.23.5",
+ "@babel/generator": "^7.23.6",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.24.5",
- "@babel/parser": "^7.24.5",
- "@babel/types": "^7.24.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.24.0",
+ "@babel/types": "^7.24.0",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@@ -510,13 +531,13 @@
}
},
"node_modules/@babel/types": {
- "version": "7.24.5",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz",
- "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
+ "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
"dev": true,
"dependencies": {
- "@babel/helper-string-parser": "^7.24.1",
- "@babel/helper-validator-identifier": "^7.24.5",
+ "@babel/helper-string-parser": "^7.23.4",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -541,70 +562,6 @@
"node": ">=16.13"
}
},
- "node_modules/@cloudflare/workerd-darwin-64": {
- "version": "1.20240419.0",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240419.0.tgz",
- "integrity": "sha512-PGVe9sYWULHfvGhN0IZh8MsskNG/ufnBSqPbgFCxJHCTrVXLPuC35EoVaforyqjKRwj3U35XMyGo9KHcGnTeHQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@cloudflare/workerd-darwin-arm64": {
- "version": "1.20240419.0",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240419.0.tgz",
- "integrity": "sha512-z4etQSPiD5Gcjs962LiC7ZdmXnN6SGof5KrYoFiSI9X9kUvpuGH/lnjVVPd+NnVNeDU2kzmcAIgyZjkjTaqVXQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@cloudflare/workerd-linux-64": {
- "version": "1.20240419.0",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240419.0.tgz",
- "integrity": "sha512-lBwhg0j3sYTFMsEb4bOClbVje8nqrYOu0H3feQlX+Eks94JIhWPkf8ywK4at/BUc1comPMhCgzDHwc2OMPUGgg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@cloudflare/workerd-linux-arm64": {
- "version": "1.20240419.0",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240419.0.tgz",
- "integrity": "sha512-ZMY6wwWkxL+WPq8ydOp/irSYjAnMhBz1OC1+4z+OANtDs2beaZODmq7LEB3hb5WUAaTPY7DIjZh3DfDfty0nYg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=16"
- }
- },
"node_modules/@cloudflare/workerd-windows-64": {
"version": "1.20240419.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240419.0.tgz",
@@ -683,342 +640,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@esbuild/android-arm": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
- "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
- "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
- "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
- "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
- "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
- "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
- "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
- "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
- "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ia32": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
- "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-loong64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
- "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-mips64el": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
- "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ppc64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
- "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-riscv64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
- "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-s390x": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
- "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
- "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/netbsd-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
- "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/openbsd-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
- "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/sunos-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
- "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
- "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-ia32": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
- "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
"node_modules/@esbuild/win32-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
@@ -1149,6 +770,55 @@
"node": ">=14"
}
},
+ "node_modules/@formatjs/ecma402-abstract": {
+ "version": "1.18.2",
+ "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.2.tgz",
+ "integrity": "sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==",
+ "peer": true,
+ "dependencies": {
+ "@formatjs/intl-localematcher": "0.5.4",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@formatjs/fast-memoize": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz",
+ "integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==",
+ "peer": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@formatjs/icu-messageformat-parser": {
+ "version": "2.7.6",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.6.tgz",
+ "integrity": "sha512-etVau26po9+eewJKYoiBKP6743I1br0/Ie00Pb/S/PtmYfmjTcOn2YCh2yNkSZI12h6Rg+BOgQYborXk46BvkA==",
+ "peer": true,
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.18.2",
+ "@formatjs/icu-skeleton-parser": "1.8.0",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@formatjs/icu-skeleton-parser": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.0.tgz",
+ "integrity": "sha512-QWLAYvM0n8hv7Nq5BEs4LKIjevpVpbGLAJgOaYzg9wABEoX1j0JO1q2/jVkO6CVlq0dbsxZCngS5aXbysYueqA==",
+ "peer": true,
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.18.2",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@formatjs/intl-localematcher": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz",
+ "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==",
+ "peer": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@hono/sentry": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@hono/sentry/-/sentry-1.0.1.tgz",
@@ -1210,9 +880,9 @@
}
},
"node_modules/@humanwhocodes/object-schema": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
- "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
+ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
"dev": true
},
"node_modules/@iarna/toml": {
@@ -2032,14 +1702,14 @@
}
},
"node_modules/@jridgewell/source-map": {
- "version": "0.3.6",
- "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
- "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
+ "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
"dev": true,
"peer": true,
"dependencies": {
- "@jridgewell/gen-mapping": "^0.3.5",
- "@jridgewell/trace-mapping": "^0.3.25"
+ "@jridgewell/gen-mapping": "^0.3.0",
+ "@jridgewell/trace-mapping": "^0.3.9"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
@@ -2408,105 +2078,6 @@
"@sentry/cli-win32-x64": "2.31.0"
}
},
- "node_modules/@sentry/cli-darwin": {
- "version": "2.31.0",
- "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.31.0.tgz",
- "integrity": "sha512-VM5liyxMnm4K2g0WsrRPXRCMLhaT09C7gK5Fz/CxKYh9sbMZB7KA4hV/3klkyuyw1+ECF1J66cefhNkFZepUig==",
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@sentry/cli-linux-arm": {
- "version": "2.31.0",
- "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.31.0.tgz",
- "integrity": "sha512-AZoCN3waXEfXGCd3YSrikcX/y63oQe0Tiyapkeoifq/0QhI+2MOOrAQb60gthsXwb0UDK/XeFi3PaxyUCphzxA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux",
- "freebsd"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@sentry/cli-linux-arm64": {
- "version": "2.31.0",
- "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.31.0.tgz",
- "integrity": "sha512-eENJTmXoFX3uNr8xRW7Bua2Sw3V1tylQfdtS85pNjZPdbm3U8wYQSWu2VoZkK2ASOoC+17YC8jTQxq62KWnSeQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux",
- "freebsd"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@sentry/cli-linux-i686": {
- "version": "2.31.0",
- "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.31.0.tgz",
- "integrity": "sha512-cQUFb3brhLaNSIoNzjU/YASnTM1I3TDJP9XXzH0eLK9sSopCcDcc6OrYEYvdjJXZKzFv5sbc9UNMsIDbh4+rYg==",
- "cpu": [
- "x86",
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux",
- "freebsd"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@sentry/cli-linux-x64": {
- "version": "2.31.0",
- "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.31.0.tgz",
- "integrity": "sha512-z1zTNg91nZJRdcGHC/bCU1KwIaifV0MLJteip9KrFDprzhJk1HtMxFOS0+OZ5/UH21CjAFmg9Pj6IAGqm3BYjA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux",
- "freebsd"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@sentry/cli-win32-i686": {
- "version": "2.31.0",
- "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.31.0.tgz",
- "integrity": "sha512-+K7fdk57aUd4CmYrQfDGYPzVyxsTnVro6IPb5QSSLpP03dL7ko5208epu4m2SyN/MkFvscy9Di3n3DTvIfDU2w==",
- "cpu": [
- "x86",
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/@sentry/cli-win32-x64": {
"version": "2.31.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.31.0.tgz",
@@ -2527,6 +2098,7 @@
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.112.2.tgz",
"integrity": "sha512-gHPCcJobbMkk0VR18J65WYQTt3ED4qC6X9lHKp27Ddt63E+MDGkG6lvYBU1LS8cV7CdyBGC1XXDCfor61GvLsA==",
+ "dev": true,
"dependencies": {
"@sentry/types": "7.112.2",
"@sentry/utils": "7.112.2"
@@ -2553,6 +2125,7 @@
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.112.2.tgz",
"integrity": "sha512-ioC2yyU6DqtLkdmWnm87oNvdn2+9oKctJeA4t+jkS6JaJ10DcezjCwiLscX4rhB9aWJV3IWF7Op0O6K3w0t2Hg==",
+ "dev": true,
"dependencies": {
"@sentry/core": "7.112.2",
"@sentry/types": "7.112.2",
@@ -2567,6 +2140,7 @@
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.112.2.tgz",
"integrity": "sha512-kCMLt7yhY5OkWE9MeowlTNmox9pqDxcpvqguMo4BDNZM5+v9SEb1AauAdR78E1a1V8TyCzjBD7JDfXWhvpYBcQ==",
+ "dev": true,
"engines": {
"node": ">=8"
}
@@ -2575,6 +2149,7 @@
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.112.2.tgz",
"integrity": "sha512-OjLh0hx0t1EcL4ZIjf+4svlmmP+tHUDGcr5qpFWH78tjmkPW4+cqPuZCZfHSuWcDdeiaXi8TnYoVRqDcJKK/eQ==",
+ "dev": true,
"dependencies": {
"@sentry/types": "7.112.2"
},
@@ -2648,18 +2223,18 @@
}
},
"node_modules/@types/better-sqlite3": {
- "version": "7.6.10",
- "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.10.tgz",
- "integrity": "sha512-TZBjD+yOsyrUJGmcUj6OS3JADk3+UZcNv3NOBqGkM09bZdi28fNZw8ODqbMOLfKCu7RYCO62/ldq1iHbzxqoPw==",
+ "version": "7.6.9",
+ "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.9.tgz",
+ "integrity": "sha512-FvktcujPDj9XKMJQWFcl2vVl7OdRIqsSRX9b0acWwTmwLK9CF2eqo/FRcmMLNpugKoX/avA6pb7TorDLmpgTnQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/eslint": {
- "version": "8.56.10",
- "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
- "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==",
+ "version": "8.56.5",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz",
+ "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==",
"dev": true,
"peer": true,
"dependencies": {
@@ -2735,9 +2310,9 @@
"dev": true
},
"node_modules/@types/node": {
- "version": "20.12.7",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
- "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
+ "version": "20.11.26",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.26.tgz",
+ "integrity": "sha512-YwOMmyhNnAWijOBQweOJnQPl068Oqd4K3OFbTc6AHJwzweUwwWG3GIFY74OKks2PJUDkQPeddOQES9mLn1CTEQ==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -3075,9 +2650,9 @@
"dev": true
},
"node_modules/@webassemblyjs/ast": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
- "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
+ "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
"dev": true,
"peer": true,
"dependencies": {
@@ -3100,9 +2675,9 @@
"peer": true
},
"node_modules/@webassemblyjs/helper-buffer": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
- "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
+ "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==",
"dev": true,
"peer": true
},
@@ -3126,16 +2701,16 @@
"peer": true
},
"node_modules/@webassemblyjs/helper-wasm-section": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
- "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
+ "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
"dev": true,
"peer": true,
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
- "@webassemblyjs/helper-buffer": "1.12.1",
+ "@webassemblyjs/ast": "1.11.6",
+ "@webassemblyjs/helper-buffer": "1.11.6",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/wasm-gen": "1.12.1"
+ "@webassemblyjs/wasm-gen": "1.11.6"
}
},
"node_modules/@webassemblyjs/ieee754": {
@@ -3166,30 +2741,30 @@
"peer": true
},
"node_modules/@webassemblyjs/wasm-edit": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
- "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
+ "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
"dev": true,
"peer": true,
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
- "@webassemblyjs/helper-buffer": "1.12.1",
+ "@webassemblyjs/ast": "1.11.6",
+ "@webassemblyjs/helper-buffer": "1.11.6",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/helper-wasm-section": "1.12.1",
- "@webassemblyjs/wasm-gen": "1.12.1",
- "@webassemblyjs/wasm-opt": "1.12.1",
- "@webassemblyjs/wasm-parser": "1.12.1",
- "@webassemblyjs/wast-printer": "1.12.1"
+ "@webassemblyjs/helper-wasm-section": "1.11.6",
+ "@webassemblyjs/wasm-gen": "1.11.6",
+ "@webassemblyjs/wasm-opt": "1.11.6",
+ "@webassemblyjs/wasm-parser": "1.11.6",
+ "@webassemblyjs/wast-printer": "1.11.6"
}
},
"node_modules/@webassemblyjs/wasm-gen": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
- "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
+ "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
"dev": true,
"peer": true,
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
+ "@webassemblyjs/ast": "1.11.6",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
"@webassemblyjs/ieee754": "1.11.6",
"@webassemblyjs/leb128": "1.11.6",
@@ -3197,26 +2772,26 @@
}
},
"node_modules/@webassemblyjs/wasm-opt": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
- "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
+ "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
"dev": true,
"peer": true,
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
- "@webassemblyjs/helper-buffer": "1.12.1",
- "@webassemblyjs/wasm-gen": "1.12.1",
- "@webassemblyjs/wasm-parser": "1.12.1"
+ "@webassemblyjs/ast": "1.11.6",
+ "@webassemblyjs/helper-buffer": "1.11.6",
+ "@webassemblyjs/wasm-gen": "1.11.6",
+ "@webassemblyjs/wasm-parser": "1.11.6"
}
},
"node_modules/@webassemblyjs/wasm-parser": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
- "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
+ "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
"dev": true,
"peer": true,
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
+ "@webassemblyjs/ast": "1.11.6",
"@webassemblyjs/helper-api-error": "1.11.6",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
"@webassemblyjs/ieee754": "1.11.6",
@@ -3225,13 +2800,13 @@
}
},
"node_modules/@webassemblyjs/wast-printer": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
- "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
+ "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
"dev": true,
"peer": true,
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
+ "@webassemblyjs/ast": "1.11.6",
"@xtuc/long": "4.2.2"
}
},
@@ -3584,15 +3159,12 @@
"dev": true
},
"node_modules/binary-extensions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
- "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true,
"engines": {
"node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/blake3-wasm": {
@@ -3682,9 +3254,9 @@
"dev": true
},
"node_modules/builtins": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz",
- "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
+ "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==",
"dev": true,
"dependencies": {
"semver": "^7.0.0"
@@ -3754,9 +3326,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001614",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz",
- "integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==",
+ "version": "1.0.30001597",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz",
+ "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==",
"dev": true,
"funding": [
{
@@ -3868,9 +3440,9 @@
}
},
"node_modules/cjs-module-lexer": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz",
- "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==",
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz",
+ "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==",
"dev": true
},
"node_modules/cliui": {
@@ -4075,9 +3647,9 @@
}
},
"node_modules/dedent": {
- "version": "1.5.3",
- "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
- "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==",
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz",
+ "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==",
"dev": true,
"peerDependencies": {
"babel-plugin-macros": "^3.1.0"
@@ -4158,9 +3730,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.4.751",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz",
- "integrity": "sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw==",
+ "version": "1.4.701",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.701.tgz",
+ "integrity": "sha512-K3WPQ36bUOtXg/1+69bFlFOvdSm0/0bGqmsfPDLRXLanoKXdA+pIWuf/VbA9b+2CwBFuONgl4NEz4OEm+OJOKA==",
"dev": true
},
"node_modules/emittery": {
@@ -4204,9 +3776,9 @@
}
},
"node_modules/es-module-lexer": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.2.tgz",
- "integrity": "sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA==",
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz",
+ "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==",
"dev": true,
"peer": true
},
@@ -4805,20 +4377,6 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -5038,6 +4596,36 @@
"node": ">=10.17.0"
}
},
+ "node_modules/i18next": {
+ "version": "23.8.2",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.8.2.tgz",
+ "integrity": "sha512-Z84zyEangrlERm0ZugVy4bIt485e/H8VecGUZkZWrH7BDePG6jT73QdL9EA1tRTTVVMpry/MgWIP1FjEn0DRXA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://locize.com"
+ },
+ {
+ "type": "individual",
+ "url": "https://locize.com/i18next.html"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+ }
+ ],
+ "dependencies": {
+ "@babel/runtime": "^7.23.2"
+ }
+ },
+ "node_modules/i18next-icu": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/i18next-icu/-/i18next-icu-2.3.0.tgz",
+ "integrity": "sha512-x+j7kd5nDJCfbU53uwsMfXD7ALPu5uv0bqjAMQ5nVvXRoj1L7gkmswKtM3XDWYo4YUHf1jznlhSdPyy0xEwU+Q==",
+ "peerDependencies": {
+ "intl-messageformat": "^10.3.3"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
@@ -5112,6 +4700,18 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
+ "node_modules/intl-messageformat": {
+ "version": "10.5.11",
+ "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.11.tgz",
+ "integrity": "sha512-eYq5fkFBVxc7GIFDzpFQkDOZgNayNTQn4Oufe8jw6YY6OHVw70/4pA3FyCsQ0Gb2DnvEJEMmN2tOaXUGByM+kg==",
+ "peer": true,
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.18.2",
+ "@formatjs/fast-memoize": "2.2.0",
+ "@formatjs/icu-messageformat-parser": "2.7.6",
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -7040,9 +6640,9 @@
}
},
"node_modules/jschardet": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-3.1.2.tgz",
- "integrity": "sha512-mw3CBZGzW8nUBPYhFU2ztZ/kJ6NClQUQVpyzvFMfznZsoC///ZQ30J2RCUanNsr5yF22LqhgYr/lj807/ZleWA==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-3.0.0.tgz",
+ "integrity": "sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==",
"dev": true,
"engines": {
"node": ">=0.1.90"
@@ -7695,17 +7295,17 @@
}
},
"node_modules/optionator": {
- "version": "0.9.4",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
- "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
+ "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
"dev": true,
"dependencies": {
+ "@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.5"
+ "type-check": "^0.4.0"
},
"engines": {
"node": ">= 0.8.0"
@@ -7854,9 +7454,9 @@
}
},
"node_modules/path-to-regexp": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz",
- "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
+ "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==",
"dev": true
},
"node_modules/path-type": {
@@ -8062,9 +7662,9 @@
}
},
"node_modules/pure-rand": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
- "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz",
+ "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==",
"dev": true,
"funding": [
{
@@ -8108,9 +7708,9 @@
}
},
"node_modules/react-is": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
- "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"dev": true
},
"node_modules/readdirp": {
@@ -8125,6 +7725,11 @@
"node": ">=8.10.0"
}
},
+ "node_modules/regenerator-runtime": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
+ },
"node_modules/regexp-tree": {
"version": "0.1.27",
"resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
@@ -8633,9 +8238,9 @@
}
},
"node_modules/terser": {
- "version": "5.31.0",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz",
- "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==",
+ "version": "5.29.1",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz",
+ "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==",
"dev": true,
"peer": true,
"dependencies": {
@@ -8828,14 +8433,59 @@
}
},
"node_modules/toucan-js": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/toucan-js/-/toucan-js-3.4.0.tgz",
- "integrity": "sha512-ifqPB5QIBC07gDGhWyMpSFp6Z6cjRLsjxhQ3wZmE6YGDntJZNCage77AIyrVihQLQM6/6T8TQumEJDuWlBw56w==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/toucan-js/-/toucan-js-3.3.1.tgz",
+ "integrity": "sha512-9BpkHb/Pzsrtl1ItNq9OEQPnuUHwzce0nV2uG+DYFiQ4fPyiA6mKTBcDwQzcvNkfSER038U+8TzvdkCev+Maww==",
"dependencies": {
- "@sentry/core": "7.112.2",
- "@sentry/integrations": "7.112.2",
- "@sentry/types": "7.112.2",
- "@sentry/utils": "7.112.2"
+ "@sentry/core": "7.76.0",
+ "@sentry/integrations": "7.76.0",
+ "@sentry/types": "7.76.0",
+ "@sentry/utils": "7.76.0"
+ }
+ },
+ "node_modules/toucan-js/node_modules/@sentry/core": {
+ "version": "7.76.0",
+ "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.76.0.tgz",
+ "integrity": "sha512-M+ptkCTeCNf6fn7p2MmEb1Wd9/JXUWxIT/0QEc+t11DNR4FYy1ZP2O9Zb3Zp2XacO7ORrlL3Yc+VIfl5JTgjfw==",
+ "dependencies": {
+ "@sentry/types": "7.76.0",
+ "@sentry/utils": "7.76.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/toucan-js/node_modules/@sentry/integrations": {
+ "version": "7.76.0",
+ "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.76.0.tgz",
+ "integrity": "sha512-4ea0PNZrGN9wKuE/8bBCRrxxw4Cq5T710y8rhdKHAlSUpbLqr/atRF53h8qH3Fi+ec0m38PB+MivKem9zUwlwA==",
+ "dependencies": {
+ "@sentry/core": "7.76.0",
+ "@sentry/types": "7.76.0",
+ "@sentry/utils": "7.76.0",
+ "localforage": "^1.8.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/toucan-js/node_modules/@sentry/types": {
+ "version": "7.76.0",
+ "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.76.0.tgz",
+ "integrity": "sha512-vj6z+EAbVrKAXmJPxSv/clpwS9QjPqzkraMFk2hIdE/kii8s8kwnkBwTSpIrNc8GnzV3qYC4r3qD+BXDxAGPaw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/toucan-js/node_modules/@sentry/utils": {
+ "version": "7.76.0",
+ "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.76.0.tgz",
+ "integrity": "sha512-40jFD+yfQaKpFYINghdhovzec4IEpB7aAuyH/GtE7E0gLpcqnC72r55krEIVILfqIR2Mlr5OKUzyeoCyWAU/yw==",
+ "dependencies": {
+ "@sentry/types": "7.76.0"
+ },
+ "engines": {
+ "node": ">=8"
}
},
"node_modules/tr46": {
@@ -9067,8 +8717,7 @@
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
- "dev": true
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/type-check": {
"version": "0.4.0",
@@ -9246,9 +8895,9 @@
}
},
"node_modules/watchpack": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
- "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==",
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
+ "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
"dev": true,
"peer": true,
"dependencies": {
@@ -9266,27 +8915,27 @@
"dev": true
},
"node_modules/webpack": {
- "version": "5.91.0",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz",
- "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==",
+ "version": "5.90.3",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz",
+ "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==",
"dev": true,
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.3",
"@types/estree": "^1.0.5",
- "@webassemblyjs/ast": "^1.12.1",
- "@webassemblyjs/wasm-edit": "^1.12.1",
- "@webassemblyjs/wasm-parser": "^1.12.1",
+ "@webassemblyjs/ast": "^1.11.5",
+ "@webassemblyjs/wasm-edit": "^1.11.5",
+ "@webassemblyjs/wasm-parser": "^1.11.5",
"acorn": "^8.7.1",
"acorn-import-assertions": "^1.9.0",
"browserslist": "^4.21.10",
"chrome-trace-event": "^1.0.2",
- "enhanced-resolve": "^5.16.0",
+ "enhanced-resolve": "^5.15.0",
"es-module-lexer": "^1.2.1",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
"glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.2.11",
+ "graceful-fs": "^4.2.9",
"json-parse-even-better-errors": "^2.3.1",
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
@@ -9294,7 +8943,7 @@
"schema-utils": "^3.2.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.3.10",
- "watchpack": "^2.4.1",
+ "watchpack": "^2.4.0",
"webpack-sources": "^3.2.3"
},
"bin": {
@@ -9377,15 +9026,6 @@
"node": ">= 8"
}
},
- "node_modules/word-wrap": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
- "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/workerd": {
"version": "1.20240419.0",
"resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240419.0.tgz",
@@ -9516,9 +9156,9 @@
}
},
"node_modules/ws": {
- "version": "8.17.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz",
- "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
+ "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"dev": true,
"engines": {
"node": ">=10.0.0"
diff --git a/package.json b/package.json
index ae11c20..0c58bd2 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,8 @@
},
"dependencies": {
"@hono/sentry": "^1.0.1",
+ "i18next": "^23.8.2",
+ "i18next-icu": "^2.3.0",
"hono": "^4.2.9"
}
}
diff --git a/src/constants.ts b/src/constants.ts
index 2426cab..c5cd8ad 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -15,7 +15,7 @@ export const Constants = {
REDIRECT_URL: REDIRECT_URL,
RELEASE_NAME: RELEASE_NAME,
GIF_TRANSCODE_DOMAIN: GIF_TRANSCODE_DOMAIN,
- API_DOCS_URL: `https://github.com/dangeredwolf/FixTweet/wiki/API-Home`,
+ API_DOCS_URL: `https://github.com/FixTweet/FxTwitter/wiki/API-Home`,
TWITTER_ROOT: 'https://twitter.com',
TWITTER_GLOBAL_NAME_ROOT: 'twitter.com',
TWITTER_API_ROOT: 'https://api.twitter.com',
diff --git a/src/embed/status.ts b/src/embed/status.ts
index 99492f8..7d6fece 100644
--- a/src/embed/status.ts
+++ b/src/embed/status.ts
@@ -1,4 +1,7 @@
import { Context } from 'hono';
+import { StatusCode } from 'hono/utils/http-status';
+import i18next from 'i18next';
+import icu from "i18next-icu";
import { Constants } from '../constants';
import { handleQuote } from '../helpers/quote';
import { formatNumber, sanitizeText, truncateWithEllipsis } from '../helpers/utils';
@@ -9,7 +12,7 @@ import { renderVideo } from '../render/video';
import { renderInstantView } from '../render/instantview';
import { constructTwitterThread } from '../providers/twitter/conversation';
import { Experiment, experimentCheck } from '../experiments';
-import { StatusCode } from 'hono/utils/http-status';
+import translationResources from '../../i18n/resources.json';
export const returnError = (c: Context, error: string): Response => {
return c.html(
@@ -127,6 +130,13 @@ export const handleStatus = async (
let overrideMedia: APIMedia | undefined;
+ await i18next.use(icu).init({
+ lng: language ?? status.lang ?? 'en',
+ debug: true,
+ resources: translationResources,
+ fallbackLng: 'en'
+ });
+
// Check if mediaNumber exists, and if that media exists in status.media.all. If it does, we'll store overrideMedia variable
if (mediaNumber && status.media && status.media.all && status.media.all[mediaNumber - 1]) {
overrideMedia = status.media.all[mediaNumber - 1];
@@ -200,7 +210,8 @@ export const handleStatus = async (
status: status,
thread: thread,
text: newText,
- flags: flags
+ flags: flags,
+ targetLanguage: language ?? status.lang ?? 'en'
});
headers.push(...instructions.addHeaders);
if (instructions.authorText) {
@@ -208,7 +219,7 @@ export const handleStatus = async (
}
ivbody = instructions.text || '';
} catch (e) {
- console.log('Error rendering Instant View', e);
+ console.log('Error rendering Instant View', e, (e as Error)?.stack);
useIV = false;
}
}
@@ -219,15 +230,11 @@ export const handleStatus = async (
if (status.translation) {
const { translation } = status;
- const formatText =
- language === 'en'
- ? Strings.TRANSLATE_TEXT.format({
- language: translation.source_lang_en
- })
- : Strings.TRANSLATE_TEXT_INTL.format({
- source: translation.source_lang.toUpperCase(),
- destination: translation.target_lang.toUpperCase()
- });
+ const formatText = `๐ {translation}`.format({
+ translation: i18next.t('translatedFrom').format({
+ language: i18next.t(`language_${translation.source_lang}`)
+ })
+ });
newText = `${formatText}\n\n` + `${translation.text}\n\n`;
}
@@ -381,7 +388,10 @@ export const handleStatus = async (
});
/* Finally, add the footer of the poll with # of votes and time left */
- str += `\n${formatNumber(poll.total_votes)} votes ยท ${poll.time_left_en}`;
+ str += '\n'; /* TODO: Localize time left */
+ str += i18next
+ .t('pollVotes')
+ .format({ voteCount: formatNumber(poll.total_votes), timeLeft: poll.time_left_en });
/* Check if the poll is ongoing and apply low TTL cache control.
Yes, checking if this is a string is a hacky way to do this, but
@@ -455,13 +465,13 @@ export const handleStatus = async (
/* Special reply handling if authorText is not overriden */
if (status.replying_to && authorText === Strings.DEFAULT_AUTHOR_TEXT) {
- authorText = `โช Replying to @${status.replying_to.screen_name}`;
+ authorText = `โช ${i18next.t('replyingTo').format({ screen_name: status.replying_to.screen_name })}`;
/* We'll assume it's a thread if it's a reply to themselves */
} else if (
status.replying_to?.screen_name === status.author.screen_name &&
authorText === Strings.DEFAULT_AUTHOR_TEXT
) {
- authorText = `โช A part of @${status.author.screen_name}'s thread`;
+ authorText = `โช ${i18next.t('threadPartHeader').format({ screen_name: status.author.screen_name })}`;
}
if (!flags.gallery) {
@@ -479,7 +489,7 @@ export const handleStatus = async (
const mediaType = overrideMedia ?? status.media.videos?.[0]?.type;
if (mediaType === 'gif') {
- provider = `GIF - ${Constants.BRANDING_NAME}`;
+ provider = i18next.t('gifIndicator', { brandingName: Constants.BRANDING_NAME });
} else if (
status.embed_card === 'player' &&
providerEngagementText !== Strings.DEFAULT_AUTHOR_TEXT
diff --git a/src/helpers/pollTime.ts b/src/helpers/pollTime.ts
index 8bb8cc3..cff91e3 100644
--- a/src/helpers/pollTime.ts
+++ b/src/helpers/pollTime.ts
@@ -12,6 +12,7 @@ export const calculateTimeLeft = (date: Date) => {
return { days, hours, minutes, seconds };
};
+/* TODO: Refactor to support pluralization of other languages */
export const calculateTimeLeftString = (date: Date) => {
const { days, hours, minutes, seconds } = calculateTimeLeft(date);
const daysString =
diff --git a/src/helpers/quote.ts b/src/helpers/quote.ts
index d3fdacf..c9a0e62 100644
--- a/src/helpers/quote.ts
+++ b/src/helpers/quote.ts
@@ -1,11 +1,11 @@
-import { Strings } from '../strings';
+import i18next from 'i18next';
/* Helper for Quote Tweets */
export const handleQuote = (quote: APIStatus): string | null => {
console.log('Quoting status ', quote.id);
let str = `\n`;
- str += Strings.QUOTE_TEXT.format({
+ str += i18next.t('quotedFrom').format({
name: quote.author?.name || '',
screen_name: quote.author?.screen_name || ''
});
diff --git a/src/providers/twitter/processor.ts b/src/providers/twitter/processor.ts
index 05a721e..f23ebf5 100644
--- a/src/providers/twitter/processor.ts
+++ b/src/providers/twitter/processor.ts
@@ -150,8 +150,8 @@ export const buildAPITwitterStatus = async (
apiStatus.replying_to_status = status.legacy?.in_reply_to_status_id_str || null;
} else if (status.legacy.in_reply_to_screen_name) {
apiStatus.replying_to = {
- screen_name: status.legacy.in_reply_to_screen_name || null,
- post: status.legacy.in_reply_to_status_id_str || null
+ screen_name: status.legacy.in_reply_to_screen_name,
+ post: status.legacy.in_reply_to_status_id_str
};
} else {
apiStatus.replying_to = null;
diff --git a/src/render/instantview.ts b/src/render/instantview.ts
index 238dd8c..a7458cd 100644
--- a/src/render/instantview.ts
+++ b/src/render/instantview.ts
@@ -1,8 +1,8 @@
/* eslint-disable no-irregular-whitespace */
+import i18next from 'i18next';
import { Constants } from '../constants';
import { getSocialTextIV } from '../helpers/socialproof';
import { sanitizeText } from '../helpers/utils';
-import { Strings } from '../strings';
enum AuthorActionType {
Reply = 'Reply',
@@ -10,7 +10,7 @@ enum AuthorActionType {
FollowUp = 'FollowUp'
}
-const populateUserLinks = (status: APIStatus, text: string): string => {
+const populateUserLinks = (text: string): string => {
/* TODO: Maybe we can add username splices to our API so only genuinely valid users are linked? */
text.match(/@(\w{1,15})/g)?.forEach(match => {
const username = match.replace('@', '');
@@ -22,7 +22,7 @@ const populateUserLinks = (status: APIStatus, text: string): string => {
return text;
};
-const generateStatusMedia = (status: APIStatus, author: APIUser): string => {
+const generateStatusMedia = (status: APIStatus): string => {
let media = '';
if (status.media?.all?.length) {
status.media.all.forEach(mediaItem => {
@@ -36,10 +36,10 @@ const generateStatusMedia = (status: APIStatus, author: APIUser): string => {
});
break;
case 'video':
- media += ``;
+ media += ``;
break;
case 'gif':
- media += ``;
+ media += ``;
break;
}
});
@@ -56,11 +56,16 @@ const generateStatusMedia = (status: APIStatus, author: APIUser): string => {
// return `${hh}:${min} - ${yyyy}/${mm}/${dd}`;
// }
-const formatDate = (date: Date): string => {
- const yyyy = date.getFullYear();
- const mm = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
- const dd = String(date.getDate()).padStart(2, '0');
- return `${yyyy}/${mm}/${dd}`;
+const formatDate = (date: Date, language: string): string => {
+ if (language.startsWith('en')) {
+ language = 'en-CA'; // Use ISO dates for English to avoid problems with mm/dd vs. dd/mm
+ }
+ const formatter = new Intl.DateTimeFormat(language, {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit'
+ });
+ return formatter.format(date);
};
const htmlifyLinks = (input: string): string => {
@@ -95,32 +100,27 @@ function getTranslatedText(status: APITwitterStatus, isQuote = false): string |
let text = paragraphify(sanitizeText(status.translation?.text), isQuote);
text = htmlifyLinks(text);
text = htmlifyHashtags(text);
- text = populateUserLinks(status, text);
+ text = populateUserLinks(text);
- const formatText =
- status.translation.target_lang === 'en'
- ? Strings.TRANSLATE_TEXT.format({
- language: status.translation.source_lang_en
- })
- : Strings.TRANSLATE_TEXT_INTL.format({
- source: status.translation.source_lang.toUpperCase(),
- destination: status.translation.target_lang.toUpperCase()
- });
+ const formatText = `๐ {translation}`.format({
+ translation: i18next.t('translatedFrom').format({
+ language: i18next.t(`language_${status.translation.source_lang}`)
+ })
+ });
- return `
${formatText}
${text}Original
`;
+ return `${formatText}
${text}${i18next.t('ivOriginalText')}
`;
}
const notApplicableComment = '';
-// 1100 -> 1.1K, 1100000 -> 1.1M
-const truncateSocialCount = (count: number): string => {
- if (count >= 1000000) {
- return `${(count / 1000000).toFixed(1)}M`;
- } else if (count >= 1000) {
- return `${(count / 1000).toFixed(1)}K`;
- } else {
- return String(count);
- }
+const truncateSocialCount = (count: number, locale = 'en-US') => {
+ const formatter = new Intl.NumberFormat(locale, {
+ notation: 'compact',
+ compactDisplay: 'short',
+ maximumFractionDigits: 1
+ });
+
+ return formatter.format(count);
};
const generateInlineAuthorHeader = (
@@ -128,16 +128,28 @@ const generateInlineAuthorHeader = (
author: APIUser,
authorActionType: AuthorActionType | null
): string => {
- return ``.format(
- {
- AuthorAction:
- authorActionType === AuthorActionType.Reply
- ? 'Reply'
- : authorActionType === AuthorActionType.Original
- ? 'Original'
- : 'Follow-up'
- }
- );
+ if (authorActionType === AuthorActionType.Original) {
+ return `${i18next.t('ivAuthorActionOriginal', {
+ statusUrl: status.url,
+ authorName: author.name,
+ authorUrl: author.url,
+ authorScreenName: author.screen_name
+ })}
`;
+ } else if (authorActionType === AuthorActionType.FollowUp) {
+ return `${i18next.t('ivAuthorActionFollowUp', {
+ statusUrl: status.url,
+ authorName: author.name,
+ authorUrl: author.url,
+ authorScreenName: author.screen_name
+ })}
`;
+ }
+ // Reply / unknown
+ return `${i18next.t('ivAuthorActionReply', {
+ statusUrl: status.url,
+ authorName: author.name,
+ authorUrl: author.url,
+ authorScreenName: author.screen_name
+ })}
`;
};
const wrapForeignLinks = (url: string) => {
@@ -158,11 +170,16 @@ const wrapForeignLinks = (url: string) => {
: url;
};
-const generateStatusFooter = (status: APIStatus, isQuote = false, author: APIUser): string => {
+const generateStatusFooter = (
+ status: APIStatus,
+ isQuote = false,
+ author: APIUser,
+ language: string
+): string => {
let description = author.description;
description = htmlifyLinks(description);
description = htmlifyHashtags(description);
- description = populateUserLinks(status, description);
+ description = populateUserLinks(description);
return `
{socialText}
@@ -171,31 +188,31 @@ const generateStatusFooter = (status: APIStatus, isQuote = false, author: APIUse
{aboutSection}
`.format({
socialText: getSocialTextIV(status as APITwitterStatus) || '',
- viewOriginal: !isQuote ? `View full thread` : notApplicableComment,
+ viewOriginal: !isQuote
+ ? `${i18next.t('ivViewOriginal')}`
+ : notApplicableComment,
aboutSection: isQuote
? ''
- : `About author
+ : `${i18next.t('ivAboutAuthor')}
{pfp}
${author.name}
@${author.screen_name}
${description}
{location} {website} {joined}
- {following} Followingโ
- {followers} Followersโ
- {statuses} Posts
+ {following} ${i18next.t('ivProfileFollowing', { numFollowing: author.following })}โ
+ {followers} ${i18next.t('ivProfileFollowers', { numFollowers: author.followers })}โ
+ {statuses} ${i18next.t('ivProfileStatuses', { numStatuses: author.statuses })}
`.format({
- pfp: `
`,
+ pfp: `
`,
location: author.location ? `๐ ${author.location}` : '',
website: author.website
? `๐ ${author.website.display_url}`
: '',
- joined: author.joined ? `๐ ${formatDate(new Date(author.joined))}` : '',
- following: truncateSocialCount(author.following),
- followers: truncateSocialCount(author.followers),
- statuses: truncateSocialCount(author.statuses)
+ joined: author.joined ? `๐ ${formatDate(new Date(author.joined), language)}` : '',
+ following: truncateSocialCount(author.following, language),
+ followers: truncateSocialCount(author.followers, language),
+ statuses: truncateSocialCount(author.statuses, language)
})
});
};
@@ -209,10 +226,10 @@ const generatePoll = (poll: APIPoll, language: string): string => {
poll.choices.forEach(choice => {
const bar = 'โ'.repeat((choice.percentage / 100) * barLength);
// eslint-disable-next-line no-irregular-whitespace
- str += `${bar}
${choice.label}
${intlFormat.format(choice.count)} votes, ${intlFormat.format(choice.percentage)}%
`;
+ str += `${bar}
${choice.label}
${i18next.t('ivPollChoice', { voteCount: intlFormat.format(choice.count), percentage: intlFormat.format(choice.percentage) })}
`;
});
/* Finally, add the footer of the poll with # of votes and time left */
- str += `
${intlFormat.format(poll.total_votes)} votes ยท ${poll.time_left_en}`;
+ str += `
${i18next.t('pollVotes', { voteCount: intlFormat.format(poll.total_votes), timeLeft: poll.time_left_en })}`;
return str;
};
@@ -247,7 +264,7 @@ const generateCommunityNote = (status: APITwitterStatus): string => {
// Add the remaining text after the last link
result = `
- Readers added context they thought people might want to know |
+ ${i18next.t('ivCommunityNoteHeader')} |
${result.replace(/\n/g, '\n ')} |
@@ -262,20 +279,21 @@ const generateCommunityNote = (status: APITwitterStatus): string => {
const generateStatus = (
status: APIStatus,
author: APIUser,
+ language: string,
isQuote = false,
authorActionType: AuthorActionType | null
): string => {
let text = paragraphify(sanitizeText(status.text), isQuote);
text = htmlifyLinks(text);
text = htmlifyHashtags(text);
- text = populateUserLinks(status, text);
+ text = populateUserLinks(text);
const translatedText = getTranslatedText(status as APITwitterStatus, isQuote);
return `
{quoteHeader}
- ${generateStatusMedia(status, author)}
+ ${generateStatusMedia(status)}
${translatedText ? translatedText : notApplicableComment}
@@ -287,12 +305,20 @@ const generateStatus = (
${status.poll ? generatePoll(status.poll, status.lang ?? 'en') : notApplicableComment}
- ${!isQuote && status.quote ? generateStatus(status.quote, author, true, null) : notApplicableComment}
- `.format({
- quoteHeader: isQuote
- ? ``
- : ''
- });
+ ${!isQuote && status.quote ? generateStatus(status.quote, author, language, true, null) : notApplicableComment}`.format(
+ {
+ quoteHeader: isQuote
+ ? '' +
+ i18next.t('ivQuoteHeader').format({
+ url: status.url,
+ authorName: status.author.name,
+ authorHandle: status.author.screen_name,
+ authorURL: `${Constants.TWITTER_ROOT}/${status.author.screen_name}`
+ }) +
+ '
'
+ : ''
+ }
+ );
};
export const renderInstantView = (properties: RenderProperties): ResponseInstructions => {
@@ -331,12 +357,12 @@ export const renderInstantView = (properties: RenderProperties): ResponseInstruc
${
flags?.archive
- ? `${Constants.BRANDING_NAME} archive`
- : 'If you can see this, your browser is doing something weird with your user agent.'
- } View full thread
+ ? i18next.t('ivInternetArchiveText').format({ brandingName: Constants.BRANDING_NAME })
+ : i18next.t('ivFallbackText')
+ } ${i18next.t('ivViewOriginal')}
- View full thread
+ ${i18next.t('ivViewOriginal')}
${status.author.name} (@${status.author.screen_name})
${useThread
@@ -376,11 +402,17 @@ export const renderInstantView = (properties: RenderProperties): ResponseInstruc
previousThreadPieceAuthor = status.author?.id;
- return generateStatus(status, status.author ?? thread?.author, false, authorAction);
+ return generateStatus(
+ status,
+ status.author ?? thread?.author,
+ properties?.targetLanguage ?? 'en',
+ false,
+ authorAction
+ );
})
.join('')}
- ${generateStatusFooter(status, false, thread?.author ?? status.author)}
-
${`View full thread`}
+ ${generateStatusFooter(status, false, thread?.author ?? status.author, properties?.targetLanguage ?? 'en')}
+
${`${i18next.t('ivViewOriginal')}`}
`;
return instructions;
diff --git a/src/render/photo.ts b/src/render/photo.ts
index 62852a2..968e6f4 100644
--- a/src/render/photo.ts
+++ b/src/render/photo.ts
@@ -1,3 +1,4 @@
+import i18next from 'i18next';
import { Constants } from '../constants';
import { Strings } from '../strings';
@@ -13,7 +14,9 @@ export const renderPhoto = (
const all = status.media?.all as APIMedia[];
const baseString =
- all.length === status.media?.photos?.length ? Strings.PHOTO_COUNT : Strings.MEDIA_COUNT;
+ all.length === status.media?.photos?.length
+ ? i18next.t('photoCount')
+ : i18next.t('mediaCount');
const photoCounter = baseString.format({
number: String(all.indexOf(photo) + 1),
diff --git a/src/render/video.ts b/src/render/video.ts
index a07a867..bd00b8c 100644
--- a/src/render/video.ts
+++ b/src/render/video.ts
@@ -1,7 +1,7 @@
+import i18next from 'i18next';
import { Constants } from '../constants';
import { Experiment, experimentCheck } from '../experiments';
import { handleQuote } from '../helpers/quote';
-import { Strings } from '../strings';
export const renderVideo = (
properties: RenderProperties,
@@ -33,7 +33,9 @@ export const renderVideo = (
we'll put an indicator if there are more than one video */
if (all && all.length > 1 && (userAgent?.indexOf('Telegram') ?? 0) > -1) {
const baseString =
- all.length === status.media?.videos?.length ? Strings.VIDEO_COUNT : Strings.MEDIA_COUNT;
+ all.length === status.media?.videos?.length
+ ? i18next.t('videoCount')
+ : i18next.t('mediaCount');
const videoCounter = baseString.format({
number: String(all.indexOf(video) + 1),
total: String(all.length)
diff --git a/src/types/types.d.ts b/src/types/types.d.ts
index cc1e635..ae8964e 100644
--- a/src/types/types.d.ts
+++ b/src/types/types.d.ts
@@ -38,6 +38,7 @@ interface RenderProperties {
userAgent?: string;
text?: string;
flags?: InputFlags;
+ targetLanguage?: string;
}
interface TweetAPIResponse {
@@ -141,8 +142,8 @@ interface APIStatus {
possibly_sensitive: boolean;
replying_to: {
- screen_name: string | null;
- post: string | null;
+ screen_name: string;
+ post: string;
} | null;
source: string | null;