Merge pull request #88 from WardPearce/update/localization

Started translation support
This commit is contained in:
Ward
2024-04-10 23:46:49 +12:00
committed by GitHub
23 changed files with 911 additions and 112 deletions
+11
View File
@@ -0,0 +1,11 @@
{
"i18n-ally.defaultNamespace": "",
"i18n-ally.enabledFrameworks": [
"svelte"
],
"i18n-ally.localesPaths": [
"materialious/src/lib/i18n",
"materialious/src/lib/i18n/locales"
],
"i18n-ally.extract.autoDetect": true
}
+2
View File
@@ -11,6 +11,8 @@
![Preview of homepage](./previews/home-preview.png)
[Help translate Materialious!](https://fink.inlang.com/github.com/WardPearce/Materialious)
# Features
- Watch sync parties!
- Sponsorblock built-in.
+622 -10
View File
@@ -14,6 +14,7 @@
"media-icons": "^0.10.0",
"peerjs": "^1.5.2",
"sponsorblock-api": "^0.2.4",
"svelte-i18n": "^4.0.0",
"svelte-infinite-loading": "^1.3.8",
"svelte-persisted-store": "^0.9.1",
"vidstack": "^1.11.13"
@@ -2504,6 +2505,50 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"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==",
"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==",
"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==",
"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==",
"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==",
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -3856,6 +3901,21 @@
"node": ">= 6"
}
},
"node_modules/cli-color": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.4.tgz",
"integrity": "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==",
"dependencies": {
"d": "^1.0.1",
"es5-ext": "^0.10.64",
"es6-iterator": "^2.0.3",
"memoizee": "^0.4.15",
"timers-ext": "^0.1.7"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/code-red": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
@@ -4003,6 +4063,18 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/d": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz",
"integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
"dependencies": {
"es5-ext": "^0.10.64",
"type": "^2.7.2"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/data-view-buffer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
@@ -4084,7 +4156,6 @@
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -4353,12 +4424,60 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/es5-ext": {
"version": "0.10.64",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz",
"integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
"hasInstallScript": true,
"dependencies": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
"esniff": "^2.0.1",
"next-tick": "^1.1.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
"dependencies": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"node_modules/es6-promise": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
"integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==",
"dev": true
},
"node_modules/es6-symbol": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz",
"integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
"dependencies": {
"d": "^1.0.2",
"ext": "^1.7.0"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/es6-weak-map": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
"integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
"dependencies": {
"d": "1",
"es5-ext": "^0.10.46",
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.1"
}
},
"node_modules/esbuild": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
@@ -4592,6 +4711,20 @@
"integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==",
"dev": true
},
"node_modules/esniff": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz",
"integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
"dependencies": {
"d": "^1.0.1",
"es5-ext": "^0.10.62",
"event-emitter": "^0.3.5",
"type": "^2.7.2"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/espree": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
@@ -4659,11 +4792,28 @@
"node": ">=0.10.0"
}
},
"node_modules/event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
"dependencies": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
},
"node_modules/ext": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
"integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
"dependencies": {
"type": "^2.7.2"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -5068,8 +5218,7 @@
"node_modules/globalyzer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
"dev": true
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="
},
"node_modules/globby": {
"version": "11.1.0",
@@ -5094,8 +5243,7 @@
"node_modules/globrex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
"dev": true
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="
},
"node_modules/gopd": {
"version": "1.0.1",
@@ -5302,6 +5450,17 @@
"node": ">= 0.4"
}
},
"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==",
"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-array-buffer": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
@@ -5500,6 +5659,11 @@
"node": ">=8"
}
},
"node_modules/is-promise": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
"integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
},
"node_modules/is-reference": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
@@ -5910,6 +6074,14 @@
"node": ">=10"
}
},
"node_modules/lru-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
"integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==",
"dependencies": {
"es5-ext": "~0.10.2"
}
},
"node_modules/magic-string": {
"version": "0.30.8",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
@@ -5953,6 +6125,21 @@
"node": ">=16"
}
},
"node_modules/memoizee": {
"version": "0.4.15",
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
"integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==",
"dependencies": {
"d": "^1.0.1",
"es5-ext": "^0.10.53",
"es6-weak-map": "^2.0.3",
"event-emitter": "^0.3.5",
"is-promise": "^2.2.2",
"lru-queue": "^0.1.0",
"next-tick": "^1.1.0",
"timers-ext": "^0.1.7"
}
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -6050,7 +6237,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
"dev": true,
"engines": {
"node": ">=4"
}
@@ -6093,6 +6279,11 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"node_modules/next-tick": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
},
"node_modules/node-gyp-build-optional-packages": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz",
@@ -6783,7 +6974,6 @@
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
"integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
"dev": true,
"dependencies": {
"mri": "^1.1.0"
},
@@ -7329,6 +7519,416 @@
"svelte": "^3.19.0 || ^4.0.0"
}
},
"node_modules/svelte-i18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/svelte-i18n/-/svelte-i18n-4.0.0.tgz",
"integrity": "sha512-4vivjKZADUMRIhTs38JuBNy3unbnh9AFRxWFLxq62P4NHic+/BaIZZlAsvqsCdnp7IdJf5EoSiH6TNdItcjA6g==",
"dependencies": {
"cli-color": "^2.0.3",
"deepmerge": "^4.2.2",
"esbuild": "^0.19.2",
"estree-walker": "^2",
"intl-messageformat": "^10.5.3",
"sade": "^1.8.1",
"tiny-glob": "^0.2.9"
},
"bin": {
"svelte-i18n": "dist/cli.js"
},
"engines": {
"node": ">= 16"
},
"peerDependencies": {
"svelte": "^3 || ^4"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/aix-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
"integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
"cpu": [
"ppc64"
],
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/android-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
"integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/android-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
"integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/android-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
"integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/darwin-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
"integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/darwin-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
"integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
"integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/freebsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
"integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/linux-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
"integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/linux-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
"integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/linux-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
"integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/linux-loong64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
"integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
"cpu": [
"loong64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/linux-mips64el": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
"integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
"cpu": [
"mips64el"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/linux-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
"integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
"cpu": [
"ppc64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/linux-riscv64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
"integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
"cpu": [
"riscv64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/linux-s390x": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
"integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
"cpu": [
"s390x"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/linux-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
"integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/netbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
"integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/openbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
"integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/sunos-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
"integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/win32-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
"integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/win32-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
"integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/@esbuild/win32-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
"integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/svelte-i18n/node_modules/esbuild": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
"integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.19.12",
"@esbuild/android-arm": "0.19.12",
"@esbuild/android-arm64": "0.19.12",
"@esbuild/android-x64": "0.19.12",
"@esbuild/darwin-arm64": "0.19.12",
"@esbuild/darwin-x64": "0.19.12",
"@esbuild/freebsd-arm64": "0.19.12",
"@esbuild/freebsd-x64": "0.19.12",
"@esbuild/linux-arm": "0.19.12",
"@esbuild/linux-arm64": "0.19.12",
"@esbuild/linux-ia32": "0.19.12",
"@esbuild/linux-loong64": "0.19.12",
"@esbuild/linux-mips64el": "0.19.12",
"@esbuild/linux-ppc64": "0.19.12",
"@esbuild/linux-riscv64": "0.19.12",
"@esbuild/linux-s390x": "0.19.12",
"@esbuild/linux-x64": "0.19.12",
"@esbuild/netbsd-x64": "0.19.12",
"@esbuild/openbsd-x64": "0.19.12",
"@esbuild/sunos-x64": "0.19.12",
"@esbuild/win32-arm64": "0.19.12",
"@esbuild/win32-ia32": "0.19.12",
"@esbuild/win32-x64": "0.19.12"
}
},
"node_modules/svelte-i18n/node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
},
"node_modules/svelte-infinite-loading": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/svelte-infinite-loading/-/svelte-infinite-loading-1.3.8.tgz",
@@ -7475,11 +8075,19 @@
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true
},
"node_modules/timers-ext": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
"integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
"dependencies": {
"es5-ext": "~0.10.46",
"next-tick": "1"
}
},
"node_modules/tiny-glob": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
"dev": true,
"dependencies": {
"globalyzer": "0.1.0",
"globrex": "^0.1.2"
@@ -7540,8 +8148,12 @@
"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": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
"integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
},
"node_modules/type-check": {
"version": "0.4.0",
+1
View File
@@ -41,6 +41,7 @@
"media-icons": "^0.10.0",
"peerjs": "^1.5.2",
"sponsorblock-api": "^0.2.4",
"svelte-i18n": "^4.0.0",
"svelte-infinite-loading": "^1.3.8",
"svelte-persisted-store": "^0.9.1",
"vidstack": "^1.11.13"
+3 -1
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import type { Channel } from './Api/model';
import { cleanNumber, truncate } from './misc';
@@ -37,7 +38,8 @@
</div>
<h5 class="center-align">{truncate(channel.author, 14)}</h5>
<h6 style="margin-top: 0;" class="center-align grey-text medium-text">
{cleanNumber(channel.subCount)} subscribers
{cleanNumber(channel.subCount)}
{$_('subscribers')}
</h6>
<p>{channel.description}</p>
</div>
+2 -1
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import { _ } from 'svelte-i18n';
import { getComments } from './Api';
import { type Comment, type Comments } from './Api/model';
import { numberWithCommas } from './misc';
@@ -68,7 +69,7 @@
class="transparent replies"
>
<i class="primary-text">expand_more</i>
<span class="primary-text">{comment.replies.replyCount} replies</span>
<span class="primary-text">{comment.replies.replyCount} {$_('replies')}</span>
</button>
{/if}
</div>
+3 -2
View File
@@ -4,6 +4,7 @@
import { goto } from '$app/navigation';
import { SponsorBlock, type Category } from 'sponsorblock-api';
import { onDestroy, onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import type { MediaTimeUpdateEvent, PlayerSrc } from 'vidstack';
import type { MediaPlayerElement } from 'vidstack/elements';
@@ -254,7 +255,7 @@
<div class="snackbar" id="sponsorblock-alert">
<span
>Skipping <span class="bold" style="text-transform: capitalize;">{categoryBeingSkipped}</span
></span
>{$_('skipping')}
<span class="bold" style="text-transform: capitalize;">{categoryBeingSkipped}</span></span
>
</div>
@@ -1,5 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import type { Playlist } from './Api/model';
import { truncate } from './misc';
@@ -48,7 +49,8 @@
{/if}
{/if}
<div class="absolute right bottom small-margin black white-text small-text thumbnail-corner">
{playlist.videoCount} videos
{playlist.videoCount}
{$_('videos')}
</div>
</a>
+2 -1
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { _ } from 'svelte-i18n';
import { interfaceSearchSuggestions } from '../store';
import { getSearchSuggestions } from './Api';
@@ -29,7 +30,7 @@
<i class="front">search</i><input
data-ui="search-suggestions"
type="text"
placeholder="Search..."
placeholder={$_('searchPlaceholder')}
bind:value={search}
on:keyup={(target) => debouncedSearch(target)}
/>
+3 -2
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import {
deArrowEnabled,
@@ -145,7 +146,7 @@
alt="Thumbnail for video"
/>
{:else}
<p>Failed to load image</p>
<p>{$_('thumbnail.failedToLoadImage')}</p>
{/if}
{#if progress}
<progress
@@ -163,7 +164,7 @@
{/if}
{:else}
<div class="absolute right bottom small-margin red white-text small-text thumbnail-corner">
LIVE
{$_('thumbnail.live')}
</div>
{/if}
</a>
+11
View File
@@ -0,0 +1,11 @@
import { browser } from '$app/environment';
import { init, register } from 'svelte-i18n';
const defaultLocale = 'en';
register('en', () => import('./locales/en.json'));
init({
fallbackLocale: defaultLocale,
initialLocale: browser ? window.navigator.language : defaultLocale,
});
+110
View File
@@ -0,0 +1,110 @@
{
"enabled": "Enabled",
"copyUrl": "Copy URL",
"loadMore": "Load more",
"views": "views",
"videos": "videos",
"cancel": "Cancel",
"create": "Create",
"title": "Title",
"searchPlaceholder": "Search...",
"deleteAllHistory": "Delete all history",
"skipping": "Skipping",
"replies": "replies",
"videoTabs": {
"all": "All",
"videos": "Videos",
"playlists": "Playlists",
"channels": "Channels",
"shorts": "Shorts",
"streams": "Streams"
},
"subscriptions": {
"manageSubscriptions": "Manage subscriptions"
},
"playlist": {
"createPlaylist": "Create playlist",
"public": "Public",
"unlisted": "Unlisted",
"private": "Private"
},
"thumbnail": {
"live": "LIVE",
"failedToLoadImage": "Failed to load image"
},
"pages": {
"home": "Home",
"trending": "Trending",
"subscriptions": "Subscriptions",
"playlists": "Playlists",
"history": "History"
},
"subscribers": "subscribers",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"loginRequired": "Login required",
"player": {
"audioOnly": "Audio only",
"theatreMode": "Theatre mode",
"share": {
"title": "Share",
"materialiousLink": "Copy Materialious link",
"invidiousRedirect": "Copy Invidious redirect link",
"youtubeLink": "Copy Youtube link"
},
"download": "Download",
"addToPlaylist": "Add to playlist",
"noPlaylists": "No playlists",
"unableToLoadComments": "Unable to load comments"
},
"layout": {
"star": "Star us on Github!",
"syncParty": "Sync party",
"syncPartyWarning": "Please note your IP will be visible to users you invite.",
"startSyncParty": "Start sync party",
"endSyncParty": "End sync party",
"notifications": "Notifications",
"noNewNotifications": "No new notifications here",
"settings": "Settings",
"login": "Login",
"logout": "Logout",
"customize": "Customize",
"theme": {
"theme": "Theme",
"darkMode": "Dark mode",
"lightMode": "Light mode",
"color": "Color"
},
"searchSuggestions": "Search suggestions",
"dataPreferences": {
"dataPreferences": "Data preferences",
"content": "Looking to import/export subscriptions, change password or delete account? Click here and scroll to the bottom of the page."
},
"player": {
"title": "Player",
"autoPlay": "Autoplay video",
"alwaysLoopVideo": "Always loop video",
"proxyVideos": "Proxy videos",
"savePlaybackPosition": "Save playback position",
"listenByDefault": "Listen by default",
"theatreModeByDefault": "Theatre mode by default",
"autoPlayNextByDefault": "Autoplay next by default",
"dash": "Dash"
},
"instanceUrl": "Instance URL",
"sponsors": {
"sponsor": "Sponsor",
"unpaidSelfPromotion": "Unpaid/Self Promotion",
"interactionReminder": "Interaction Reminder (Subscribe)",
"intermissionIntroAnimation": "Intermission/Intro Animation",
"credits": "Endcards/Credits",
"preViewRecapHook": "Preview/Recap/Hook",
"tangentJokes": "Filler Tangent/Jokes"
},
"deArrow": {
"title": "DeArrow",
"thumbnailInstanceUrl": "Thumbnail instance URL"
},
"bookmarklet": "Bookmarklet"
}
}
+55 -55
View File
@@ -13,6 +13,7 @@
import type { DataConnection } from 'peerjs';
import Peer from 'peerjs';
import { onDestroy, onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import { pwaInfo } from 'virtual:pwa-info';
import {
@@ -66,43 +67,43 @@
{
icon: 'home',
href: '/',
name: 'Home',
name: $_('pages.home'),
requiresAuth: false
},
{
icon: 'whatshot',
href: '/trending',
name: 'Trending',
name: $_('pages.trending'),
requiresAuth: false
},
{
icon: 'subscriptions',
href: '/subscriptions',
name: 'Subscriptions',
name: $_('pages.subscriptions'),
requiresAuth: true
},
{
icon: 'video_library',
href: '/playlists',
name: 'Playlists',
name: $_('pages.playlists'),
requiresAuth: true
},
{
icon: 'history',
href: '/history',
name: 'History',
name: $_('pages.history'),
requiresAuth: true
}
];
const sponsorCategories = [
{ name: 'Sponsor', category: 'sponsor' },
{ name: 'Unpaid/Self Promotion', category: 'selfpromo' },
{ name: 'Interaction Reminder (Subscribe)', category: 'interaction' },
{ name: 'Intermission/Intro Animation', category: 'intro' },
{ name: 'Endcards/Credits', category: 'outro' },
{ name: 'Preview/Recap/Hook', category: 'preview' },
{ name: 'Filler Tangent/Jokes', category: 'filler' }
{ name: $_('layout.sponsors.sponsor'), category: 'sponsor' },
{ name: $_('layout.sponsors.unpaidSelfPromotion'), category: 'selfpromo' },
{ name: $_('layout.sponsors.interactionReminder'), category: 'interaction' },
{ name: $_('layout.sponsors.intermissionIntroAnimation'), category: 'intro' },
{ name: $_('layout.sponsors.credits'), category: 'outro' },
{ name: $_('layout.sponsors.preViewRecapHook'), category: 'preview' },
{ name: $_('layout.sponsors.tangentJokes'), category: 'filler' }
];
function changeVideoEvent(conn: DataConnection) {
@@ -315,57 +316,57 @@
class="button circle large transparent"
>
<i>code</i>
<div class="tooltip bottom">Star us on Github!</div>
<div class="tooltip bottom">{$_('layout.star')}</div>
</a>
<button data-ui="#sync-party" class="circle large transparent">
<i class:primary-text={$syncPartyPeer}>group</i>
<div class="tooltip bottom">Sync party</div>
<div class="tooltip bottom">{$_('layout.syncParty')}</div>
</button>
{#if isLoggedIn}
<button class="circle large transparent" data-ui="#dialog-notifications"
><i>notifications</i>
<div class="tooltip bottom">Notifications</div>
<div class="tooltip bottom">{$_('layout.notifications')}</div>
</button>
{/if}
<button class="circle large transparent" data-ui="#dialog-settings">
<i>settings</i>
<div class="tooltip bottom">Settings</div>
<div class="tooltip bottom">{$_('layout.settings')}</div>
</button>
{#if !isLoggedIn}
<button on:click={login} class="circle large transparent">
<i>login</i>
<div class="tooltip bottom">Login</div>
<div class="tooltip bottom">{$_('layout.login')}</div>
</button>
{:else}
<button on:click={logout} class="circle large transparent">
<i>logout</i>
<div class="tooltip bottom">Logout</div>
<div class="tooltip bottom">{$_('layout.logout')}</div>
</button>
{/if}
</nav>
<dialog class="right" id="dialog-settings">
<nav>
<h4 class="max">Settings</h4>
<h4 class="max">{$_('layout.settings')}</h4>
<button class="circle transparent" data-ui="#dialog-settings"><i>close</i></button>
</nav>
<p>Customize Materialious</p>
<p>{$_('layout.customize')} Materialious</p>
<div class="settings">
<h6>Theme</h6>
<h6>{$_('layout.theme.theme')}</h6>
<button on:click={toggleDarkMode} class="no-margin">
{#if !$darkMode}
<i>dark_mode</i>
<span>Dark mode</span>
<span>{$_('layout.theme.darkMode')}</span>
{:else}
<i>light_mode</i>
<span>Light mode</span>
<span>{$_('layout.theme.lightMode')}</span>
{/if}
</button>
<button>
<i>palette</i>
<span>Color</span>
<span>{$_('layout.theme.color')}</span>
<input on:change={setColor} type="color" />
</button>
</div>
@@ -375,7 +376,7 @@
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Search suggestions</div>
<div>{$_('layout.searchSuggestions')}</div>
</div>
<label class="switch">
<input
@@ -390,27 +391,25 @@
</div>
<div class="settings">
<h6>Data preferences</h6>
<h6>{$_('layout.dataPreferences.dataPreferences')}</h6>
<p style="width: 240px;">
Looking to import/export subscriptions, change password or delete account?
<a
href={`${import.meta.env.VITE_DEFAULT_INVIDIOUS_INSTANCE}/preferences`}
target="_blank"
rel="noopener noreferrer"
class="link"
>
Go here
{$_('layout.dataPreferences.content')}
</a>
and scroll to the bottom of the page.
</p>
</div>
<div class="settings">
<h6>Player</h6>
<h6>{$_('layout.player.title')}</h6>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Autoplay video</div>
<div>{$_('layout.player.autoPlay')}</div>
</div>
<label class="switch">
<input
@@ -426,7 +425,7 @@
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Always loop video</div>
<div>{$_('layout.player.alwaysLoopVideo')}</div>
</div>
<label class="switch">
<input
@@ -442,7 +441,7 @@
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Proxy videos</div>
<div>{$_('layout.player.proxyVideos')}</div>
</div>
<label class="switch">
<input
@@ -458,7 +457,7 @@
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Save playback position</div>
<div>{$_('layout.player.savePlaybackPosition')}</div>
</div>
<label class="switch">
<input
@@ -474,7 +473,7 @@
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Listen by default</div>
<div>{$_('layout.player.listenByDefault')}</div>
</div>
<label class="switch">
<input
@@ -490,7 +489,7 @@
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Theatre mode by default</div>
<div>{$_('layout.player.theatreModeByDefault')}</div>
</div>
<label class="switch">
<input
@@ -506,7 +505,7 @@
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Autoplay next by default</div>
<div>{$_('layout.player.autoPlayNextByDefault')}</div>
</div>
<label class="switch">
<input
@@ -522,7 +521,7 @@
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Dash</div>
<div>{$_('layout.player.dash')}</div>
</div>
<label class="switch">
<input
@@ -543,7 +542,7 @@
<nav>
<div class="field label border">
<input bind:value={returnYTInstance} name="returnyt-instance" type="text" />
<label for="returnyt-instance">Instance URL</label>
<label for="returnyt-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
@@ -553,7 +552,7 @@
<nav class="no-padding">
<div class="max">
<p>Enabled</p>
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
@@ -573,7 +572,7 @@
<nav>
<div class="field label border">
<input bind:value={sponsorBlockInstance} name="sponsorblock-instance" type="text" />
<label for="sponsorblock-instance">Instance URL</label>
<label for="sponsorblock-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
@@ -583,7 +582,7 @@
<nav class="no-padding">
<div class="max">
<p>Enabled</p>
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
@@ -615,13 +614,13 @@
</div>
<div class="settings">
<h6>DeArrow</h6>
<h6>{$_('layout.deArrow.title')}</h6>
<form on:submit|preventDefault={() => deArrowInstance.set(deArrowUrl)}>
<nav>
<div class="field label border">
<input bind:value={deArrowUrl} name="dearrow-instance" type="text" />
<label for="dearrow-instance">Instance URL</label>
<label for="dearrow-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
@@ -633,7 +632,8 @@
<nav>
<div class="field label border">
<input bind:value={deArrowThumbnailUrl} name="dearrow-thumbnail-instance" type="text" />
<label for="dearrow-thumbnail-instance">Thumbnail instance URL</label>
<label for="dearrow-thumbnail-instance">{$_('layout.deArrow.thumbnailInstanceUrl')}</label
>
</div>
<button class="square round">
<i>done</i>
@@ -643,7 +643,7 @@
<nav class="no-padding">
<div class="max">
<p>Enabled</p>
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
@@ -657,22 +657,22 @@
</div>
<div class="settings">
<h6>Bookmarklet</h6>
<h6>{$_('layout.bookmarklet')}</h6>
<button
class="no-margin"
on:click={async () => await navigator.clipboard.writeText(bookmarkletSaveToUrl())}
>Copy URL</button
>{$_('copyUrl')}</button
>
</div>
</dialog>
<dialog class="right" id="dialog-notifications">
<nav>
<h5 class="max">Notifications</h5>
<h5 class="max">{$_('layout.notifications')}</h5>
<button class="circle transparent" data-ui="#dialog-notifications"><i>close</i></button>
</nav>
{#if notifications.length === 0}
<p>No new notifications here</p>
<p>{$_('layout.noNewNotifications')}</p>
{:else}
{#each notifications as notification}
<article class="no-padding">
@@ -710,8 +710,8 @@
</dialog>
<dialog id="sync-party">
<h6>Sync party</h6>
<p>Please note your IP will be visible to users you invite.</p>
<h6>{$_('layout.syncParty')}</h6>
<p>{$_('layout.syncPartyWarning')}</p>
{#if $syncPartyPeer}
<nav>
<div class="field label border">
@@ -741,10 +741,10 @@
on:click={startWatchSync}
data-ui={`${$syncPartyPeer ? '#sync-party' : ''}`}
>{#if $syncPartyPeer}
End
{$_('layout.endSyncParty')}
{:else}
Start
{/if} sync party
{$_('layout.startSyncParty')}
{/if}
</button>
</dialog>
+12
View File
@@ -1 +1,13 @@
import { browser } from '$app/environment';
import '$lib/i18n'; // Import to initialize. Important :)
import { locale, waitLocale } from 'svelte-i18n';
import type { LayoutLoad } from './$types';
export let ssr = false;
export const load: LayoutLoad = async () => {
if (browser) {
locale.set(window.navigator.language);
}
await waitLocale();
};
@@ -6,6 +6,7 @@
import Thumbnail from '$lib/Thumbnail.svelte';
import { cleanNumber } from '$lib/misc';
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading';
import { get } from 'svelte/store';
import { activePage, auth } from '../../../store';
@@ -83,7 +84,7 @@
/>
<div>
<h2>{data.channel.author}</h2>
<p>{cleanNumber(data.channel.subCount)} subscribers</p>
<p>{cleanNumber(data.channel.subCount)} {$_('subscribers')}</p>
<p style="width: 60vw;">{data.channel.description}</p>
</div>
<button
@@ -92,9 +93,9 @@
class:border={isSubscribed}
>
{#if !isSubscribed}
Subscribe
{$_('subscribe')}
{:else}
Unsubscribe
{$_('unsubscribe')}
{/if}
</button>
</div>
@@ -103,19 +104,19 @@
{#if data.channel.tabs.includes('videos')}
<a class:active={tab === 'videos'} on:click={() => changeTab('videos')} href={`#video`}>
<i>movie</i>
<span>Videos</span>
<span>{$_('videoTabs.videos')}</span>
</a>
{/if}
{#if data.channel.tabs.includes('shorts')}
<a class:active={tab === 'shorts'} on:click={() => changeTab('shorts')} href={`#short`}>
<i>smartphone</i>
<span>Shorts</span>
<span>{$_('videoTabs.shorts')}</span>
</a>
{/if}
{#if data.channel.tabs.includes('streams')}
<a class:active={tab === 'streams'} on:click={() => changeTab('streams')} href={`#stream`}>
<i>stream</i>
<span>Streams</span>
<span>{$_('videoTabs.streams')}</span>
</a>
{/if}
{#if data.channel.tabs.includes('playlists')}
@@ -125,7 +126,7 @@
href={`#playlist`}
>
<i>playlist_add_check</i>
<span>Playlists</span>
<span>{$_('videoTabs.playlists')}</span>
</a>
{/if}
</div>
+2 -1
View File
@@ -4,6 +4,7 @@
import VideoList from '$lib/VideoList.svelte';
import { error } from '@sveltejs/kit';
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading';
import { activePage } from '../../store';
@@ -62,7 +63,7 @@
}}
>
<i>delete_sweep</i>
<span>Delete all history</span>
<span>{$_('deleteAllHistory')}</span>
</button>
</div>
@@ -4,6 +4,7 @@
import VideoList from '$lib/VideoList.svelte';
import { cleanNumber } from '$lib/misc.js';
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { activePage } from '../../../store';
export let data;
@@ -36,7 +37,11 @@
<article>
<h3>{data.playlist.title}</h3>
<p>{cleanNumber(data.playlist.viewCount)} views • {data.playlist.videoCount} videos</p>
<p>
{cleanNumber(data.playlist.viewCount)}
{$_('views')}{data.playlist.videoCount}
{$_('videos')}
</p>
<div class="divider" style="margin-bottom: 1em;"></div>
<p style="white-space: pre-line;word-wrap: break-word;">{data.playlist.description}</p>
</article>
@@ -1,6 +1,7 @@
<script lang="ts">
import { deletePersonalPlaylist, getPersonalPlaylists, postPersonalPlaylist } from '$lib/Api';
import PlaylistThumbnail from '$lib/PlaylistThumbnail.svelte';
import { _ } from 'svelte-i18n';
import { activePage } from '../../store';
export let data;
@@ -53,7 +54,7 @@
<article style="height: 100%;display: flex;align-items: center;justify-content: center;">
<button data-ui="#create-playlist" class="round extra">
<i>add_circle</i>
<span>Create playlist</span>
<span>{$_('playlist.createPlaylist')}</span>
</button>
</article>
</div>
@@ -64,27 +65,27 @@
<form on:submit|preventDefault={createPlaylist}>
<div class="field label border">
<input bind:value={playlistTitle} required name="title" type="text" />
<label for="title">Title</label>
<label for="title">{$_('title')}</label>
</div>
<div class="field middle-align">
<nav>
<label class="radio">
<input checked on:change={onPrivacyChange} value="public" type="radio" name="privacy" />
<span>Public</span>
<span>{$_('playlist.public')}</span>
</label>
<label class="radio">
<input on:change={onPrivacyChange} type="radio" value="unlisted" name="privacy" />
<span>Unlisted</span>
<span>{$_('playlist.unlisted')}</span>
</label>
<label class="radio">
<input on:change={onPrivacyChange} type="radio" value="private" name="privacy" />
<span>Private</span>
<span>{$_('playlist.private')}</span>
</label>
</nav>
</div>
<nav class="right-align">
<button type="button" data-ui="#create-playlist">Cancel</button>
<button type="submit">Create</button>
<button type="button" data-ui="#create-playlist">{$_('cancel')}</button>
<button type="submit">{$_('create')}</button>
</nav>
</form>
</dialog>
@@ -4,6 +4,7 @@
import PageLoading from '$lib/PageLoading.svelte';
import PlaylistThumbnail from '$lib/PlaylistThumbnail.svelte';
import Thumbnail from '$lib/Thumbnail.svelte';
import { _ } from 'svelte-i18n';
import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading';
import { activePage } from '../../../store';
@@ -46,7 +47,7 @@
on:click={async () => changeType('all')}
>
<i>home</i>
<span>All</span>
<span>{$_('videoTabs.all')}</span>
</a>
<a
class:active={data.searchType === 'video'}
@@ -54,7 +55,7 @@
on:click={async () => changeType('video')}
>
<i>movie</i>
<span>Videos</span>
<span>{$_('videoTabs.videos')}</span>
</a>
<a
class:active={data.searchType === 'playlist'}
@@ -62,7 +63,7 @@
on:click={async () => changeType('playlist')}
>
<i>playlist_add_check</i>
<span>Playlists</span>
<span>{$_('videoTabs.playlists')}</span>
</a>
<a
class:active={data.searchType === 'channel'}
@@ -70,7 +71,7 @@
on:click={async () => changeType('channel')}
>
<i>person</i>
<span>Channels</span>
<span>{$_('videoTabs.channels')}</span>
</a>
</div>
</div>
@@ -1,6 +1,7 @@
<script lang="ts">
import { getFeed } from '$lib/Api/index.js';
import VideoList from '$lib/VideoList.svelte';
import { _ } from 'svelte-i18n';
import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading';
import { activePage } from '../../store';
@@ -27,7 +28,7 @@
<nav class="right-align">
<a class="button" href="/subscriptions/manage">
<i>subscriptions</i>
<span>Manage subscriptions</span>
<span>{$_('subscriptions.manageSubscriptions')}</span>
</a>
</nav>
@@ -2,6 +2,7 @@
import { deleteUnsubscribe } from '$lib/Api';
import { truncate } from '$lib/misc';
import Fuse from 'fuse.js';
import { _ } from 'svelte-i18n';
import { activePage } from '../../../store';
activePage.set(null);
@@ -41,7 +42,7 @@
bind:value={search}
on:input={searchSubs}
type="text"
placeholder="Search..."
placeholder={$_('searchPlaceholder')}
/>
</div>
@@ -17,6 +17,7 @@
import type { PlayerEvents } from '$lib/player';
import type { DataConnection } from 'peerjs';
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import type { MediaPlayerElement } from 'vidstack/elements';
import {
@@ -282,15 +283,17 @@
class:border={data.subscribed}
>
{#if !data.subscribed}
Subscribe
{$_('subscribe')}
{:else}
Unsubscribe
{$_('unsubscribe')}
{/if}
</button>
{:else}
<button class="inverse-surface" disabled>
Subscribe
<div class="tooltip">Login required</div>
{$_('subscribe')}
<div class="tooltip">
{$_('loginRequired')}
</div>
</button>
{/if}
</nav>
@@ -312,15 +315,17 @@
<div>
<button on:click={() => (audioMode = !audioMode)} class:border={!audioMode}>
<i>headphones</i>
<div class="tooltip">Audio only</div>
<div class="tooltip">{$_('player.audioOnly')}</div>
</button>
<button on:click={toggleTheatreMode} class="m l" class:border={!theatreMode}>
<i>width_wide</i>
<div class="tooltip">Theatre mode</div>
<div class="tooltip">{$_('player.theatreMode')}</div>
</button>
<button class="border"
><i>share</i>
<div class="tooltip">Share</div>
<div class="tooltip">
{$_('player.share.title')}
</div>
<menu class="no-wrap">
<a
class="row"
@@ -330,7 +335,7 @@
`${import.meta.env.VITE_DEFAULT_FRONTEND_URL}/watch/${data.video.videoId}`
)}
>
<div class="min">Copy Materialious link</div></a
<div class="min">{$_('player.share.materialiousLink')}</div></a
><a
href="#copy"
class="row"
@@ -339,7 +344,7 @@
`https://redirect.invidious.io/watch?v=${data.video.videoId}`
)}
>
<div class="min">Copy Invidious redirect link</div></a
<div class="min">{$_('player.share.invidiousRedirect')}</div></a
><a
class="row"
href="#copy"
@@ -348,14 +353,14 @@
`https://www.youtube.com/watch?v=${data.video.videoId}`
)}
>
<div class="min">Copy Youtube link</div></a
<div class="min">{$_('player.share.youtubeLink')}</div></a
></menu
></button
>
{#if data.downloadOptions.length > 0}
<button class="border"
><i>download</i>
<div class="tooltip">Download</div>
<div class="tooltip">{$_('player.download')}</div>
<menu class="no-wrap">
{#each data.downloadOptions as download}
<a class="row" href={download.url} target="_blank" rel="noopener noreferrer"
@@ -368,7 +373,7 @@
{#if data.personalPlaylists}
<button class="border">
<i>add</i>
<div class="tooltip">Add to playlist</div>
<div class="tooltip">{$_('player.addToPlaylist')}</div>
<menu>
{#each data.personalPlaylists as personalPlaylist}
<a
@@ -384,9 +389,9 @@
<i>add</i>
<div class="tooltip">
{#if $auth}
No playlists
{$_('player.noPlaylists')}
{:else}
Login required
{$_('loginRequired')}
{/if}
</div>
</button>
@@ -435,10 +440,10 @@
<Comment {comment} videoId={data.video.videoId}></Comment>
{/each}
{#if comments.continuation}
<button on:click={loadMoreComments} class="margin">Load more</button>
<button on:click={loadMoreComments} class="margin">{$_('loadMore')}</button>
{/if}
{:else}
<h6>Unable to load comments</h6>
<h6>{$_('player.unableToLoadComments')}</h6>
{/if}
</div>
{#if !theatreMode}
@@ -461,7 +466,11 @@
>
<article class="no-elevate" style="position: sticky; top: 0; z-index: 3;">
<h6>{playlist.title}</h6>
<p>{cleanNumber(playlist.viewCount)} views • {playlist.videoCount} videos</p>
<p>
{cleanNumber(playlist.viewCount)}
{$_('views')} • {playlist.videoCount}
{$_('videos')}
</p>
<p><a href={`/channel/${playlist.authorId}`}>{playlist.author}</a></p>
<div class="divider"></div>
</article>
+12
View File
@@ -0,0 +1,12 @@
{
"sourceLanguageTag": "en",
"languageTags": [
"en"
],
"modules": [
"https://cdn.jsdelivr.net/npm/@inlang/plugin-i18next@latest/dist/index.js"
],
"plugin.inlang.i18next": {
"pathPattern": "./materialious/src/i18n/locales/{languageTag}.json"
}
}