diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7681d45..5fbd1ff 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -33,9 +33,19 @@
- [x] Updated button look
- [x] Changed date
-### Upcoming
+### Version 1.5
+ - [x] Added translations (en, es, fr, zh, de)
- [x] New Themes
- [x] Updated scrollbar
+ - [x] Docker support
+ - [x] Fixed links style
+ - [x] Fixed links underline when obfuscated
+
+### Upcoming
+ - [ ] Translate page titles
+ - [ ] Obfuscate more text
+ - [ ] Obfuscate links (href)
+ - [ ] No obfuscation option in "/consts.js"
- [ ] Update proxies
- [ ] Add games
- [ ] Custom themes
diff --git a/package-lock.json b/package-lock.json
index 32d3b30..736e53b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,7 +16,11 @@
"@tomphttp/bare-client": "^1.1.0",
"clsx": "^1.2.1",
"http-server": "^14.1.1",
+ "i18next": "^22.4.10",
+ "i18next-fs-backend": "^2.1.1",
+ "i18next-http-backend": "^2.1.1",
"random-seed": "^0.3.0",
+ "react-i18next": "^12.2.0",
"react-router-dom": "^6.4.1",
"react-tsparticles": "^2.3.2",
"tsparticles": "^2.3.2"
@@ -1858,11 +1862,11 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz",
- "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==",
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
+ "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
"dependencies": {
- "regenerator-runtime": "^0.13.4"
+ "regenerator-runtime": "^0.13.11"
},
"engines": {
"node": ">=6.9.0"
@@ -6863,6 +6867,14 @@
"node": ">=10"
}
},
+ "node_modules/cross-fetch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
+ "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
+ "dependencies": {
+ "node-fetch": "2.6.7"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -9817,6 +9829,14 @@
"node": ">=12"
}
},
+ "node_modules/html-parse-stringify": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
+ "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
+ "dependencies": {
+ "void-elements": "3.1.0"
+ }
+ },
"node_modules/html-webpack-plugin": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz",
@@ -10050,6 +10070,41 @@
"node": ">=10.17.0"
}
},
+ "node_modules/i18next": {
+ "version": "22.4.10",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.10.tgz",
+ "integrity": "sha512-3EqgGK6fAJRjnGgfkNSStl4mYLCjUoJID338yVyLMj5APT67HUtWoqSayZewiiC5elzMUB1VEUwcmSCoeQcNEA==",
+ "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.20.6"
+ }
+ },
+ "node_modules/i18next-fs-backend": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.1.1.tgz",
+ "integrity": "sha512-FTnj+UmNgT3YRml5ruRv0jMZDG7odOL/OP5PF5mOqvXud2vHrPOOs68Zdk6iqzL47cnnM0ZVkK2BAvpFeDJToA=="
+ },
+ "node_modules/i18next-http-backend": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.1.1.tgz",
+ "integrity": "sha512-jByfUCDVgQ8+/Wens7queQhYYvMcGTW/lR4IJJNEDDXnmqjLrwi8ubXKpmp76/JIWEZHffNdWqnxFJcTVGeaOw==",
+ "dependencies": {
+ "cross-fetch": "3.1.5"
+ }
+ },
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -13481,6 +13536,44 @@
"tslib": "^2.0.3"
}
},
+ "node_modules/node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-fetch/node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "node_modules/node-fetch/node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "node_modules/node-fetch/node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/node-forge": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
@@ -15860,6 +15953,27 @@
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==",
"dev": true
},
+ "node_modules/react-i18next": {
+ "version": "12.2.0",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.2.0.tgz",
+ "integrity": "sha512-5XeVgSygaGfyFmDd2WcXvINRw2WEC1XviW1LXY/xLOEMzsCFRwKqfnHN+hUjla8ZipbVJR27GCMSuTr0BhBBBQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.20.6",
+ "html-parse-stringify": "^3.0.1"
+ },
+ "peerDependencies": {
+ "i18next": ">= 19.0.0",
+ "react": ">= 16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -16123,9 +16237,9 @@
}
},
"node_modules/regenerator-runtime": {
- "version": "0.13.9",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/regenerator-transform": {
"version": "0.15.0",
@@ -18429,6 +18543,14 @@
"node": ">= 0.8"
}
},
+ "node_modules/void-elements": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+ "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
@@ -20661,11 +20783,11 @@
}
},
"@babel/runtime": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz",
- "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==",
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
+ "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
"requires": {
- "regenerator-runtime": "^0.13.4"
+ "regenerator-runtime": "^0.13.11"
}
},
"@babel/runtime-corejs3": {
@@ -24333,6 +24455,14 @@
"yaml": "^1.10.0"
}
},
+ "cross-fetch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
+ "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
+ "requires": {
+ "node-fetch": "2.6.7"
+ }
+ },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -26524,6 +26654,14 @@
"terser": "^5.10.0"
}
},
+ "html-parse-stringify": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
+ "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
+ "requires": {
+ "void-elements": "3.1.0"
+ }
+ },
"html-webpack-plugin": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz",
@@ -26689,6 +26827,27 @@
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
"dev": true
},
+ "i18next": {
+ "version": "22.4.10",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.10.tgz",
+ "integrity": "sha512-3EqgGK6fAJRjnGgfkNSStl4mYLCjUoJID338yVyLMj5APT67HUtWoqSayZewiiC5elzMUB1VEUwcmSCoeQcNEA==",
+ "requires": {
+ "@babel/runtime": "^7.20.6"
+ }
+ },
+ "i18next-fs-backend": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.1.1.tgz",
+ "integrity": "sha512-FTnj+UmNgT3YRml5ruRv0jMZDG7odOL/OP5PF5mOqvXud2vHrPOOs68Zdk6iqzL47cnnM0ZVkK2BAvpFeDJToA=="
+ },
+ "i18next-http-backend": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.1.1.tgz",
+ "integrity": "sha512-jByfUCDVgQ8+/Wens7queQhYYvMcGTW/lR4IJJNEDDXnmqjLrwi8ubXKpmp76/JIWEZHffNdWqnxFJcTVGeaOw==",
+ "requires": {
+ "cross-fetch": "3.1.5"
+ }
+ },
"iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -29250,6 +29409,35 @@
"tslib": "^2.0.3"
}
},
+ "node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "requires": {
+ "whatwg-url": "^5.0.0"
+ },
+ "dependencies": {
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "requires": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ }
+ }
+ },
"node-forge": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
@@ -30821,6 +31009,15 @@
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==",
"dev": true
},
+ "react-i18next": {
+ "version": "12.2.0",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.2.0.tgz",
+ "integrity": "sha512-5XeVgSygaGfyFmDd2WcXvINRw2WEC1XviW1LXY/xLOEMzsCFRwKqfnHN+hUjla8ZipbVJR27GCMSuTr0BhBBBQ==",
+ "requires": {
+ "@babel/runtime": "^7.20.6",
+ "html-parse-stringify": "^3.0.1"
+ }
+ },
"react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -31013,9 +31210,9 @@
}
},
"regenerator-runtime": {
- "version": "0.13.9",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"regenerator-transform": {
"version": "0.15.0",
@@ -32833,6 +33030,11 @@
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"dev": true
},
+ "void-elements": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+ "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="
+ },
"w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
diff --git a/package.json b/package.json
index cef7437..22ed731 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,11 @@
"@tomphttp/bare-client": "^1.1.0",
"clsx": "^1.2.1",
"http-server": "^14.1.1",
+ "i18next": "^22.4.10",
+ "i18next-fs-backend": "^2.1.1",
+ "i18next-http-backend": "^2.1.1",
"random-seed": "^0.3.0",
+ "react-i18next": "^12.2.0",
"react-router-dom": "^6.4.1",
"react-tsparticles": "^2.3.2",
"tsparticles": "^2.3.2"
diff --git a/public/manifest.json b/public/manifest.json
index 75afa4a..11dc812 100644
--- a/public/manifest.json
+++ b/public/manifest.json
@@ -3,15 +3,15 @@
"short_name": "Metallic",
"description": "A powerful web proxy build for speed and customization.",
"icons": [
- {
- "src": "/logo.png",
- "sizes": "120x120",
- "type": "image/png"
- }
+ {
+ "src": "/logo.png",
+ "sizes": "120x120",
+ "type": "image/png"
+ }
],
"lang": "en-US",
"start_url": "/",
"display": "standalone",
"background_color": "black",
"theme_color": "black"
-}
+}
\ No newline at end of file
diff --git a/src/SettingsLayout.js b/src/SettingsLayout.js
index 11d5420..3c7c00f 100644
--- a/src/SettingsLayout.js
+++ b/src/SettingsLayout.js
@@ -4,6 +4,7 @@ import Nav from "./components/nav.js";
import Head from "./components/head.js";
import Obfuscate from "./components/obfuscate.js";
import clsx from "clsx";
+import { useTranslation } from 'react-i18next';
function Tab({ to, children }) {
const location = useLocation();
@@ -23,25 +24,27 @@ function Tab({ to, children }) {
}
export default function SettingsLayout({ children }) {
+ const { t } = useTranslation("settings");
+
return (
<>
- Settings
+ {t("title")}
- Search
+ {t("sidebar.search")}
- Tab
+ {t("sidebar.tab")}
- Appearance
+ {t("sidebar.appearance")}
- UI
+ {t("sidebar.ui")}
{children}
diff --git a/src/i18n.js b/src/i18n.js
new file mode 100644
index 0000000..15e7f14
--- /dev/null
+++ b/src/i18n.js
@@ -0,0 +1,38 @@
+import i18n from "i18next";
+import { initReactI18next } from "react-i18next";
+import languages from "./locales/index.js";
+
+var language = localStorage.getItem("language") || "en"
+
+if (!languages[language]) {
+ language = "en"
+}
+
+export function getLanguage() {
+ return language;
+}
+
+export function setLanguage(newLanguage) {
+ language = newLanguage;
+ localStorage.setItem("language", language);
+ i18n.changeLanguage(language);
+};
+
+i18n
+ .use(initReactI18next)
+ .init({
+ resources: {
+ en: languages.en,
+ es: languages.es,
+ fr: languages.fr,
+ zh: languages.zh,
+ de: languages.de,
+ },
+ lng: language,
+ fallbackLng: "en",
+ interpolation: {
+ escapeValue: false,
+ },
+ });
+
+export default i18n;
\ No newline at end of file
diff --git a/src/locales/de/credits.json b/src/locales/de/credits.json
new file mode 100644
index 0000000..2d876ca
--- /dev/null
+++ b/src/locales/de/credits.json
@@ -0,0 +1,10 @@
+{
+ "title": "Kredite",
+ "developers": "Entwickler",
+ "proxies": "Proxys",
+ "games": "Spiele",
+ "others": "Andere",
+ "othersMessage": "Alle anderen in der Community :)",
+ "mainDevText": "Eigentümer und Hauptentwickler",
+ "devText": "Entwickler"
+}
\ No newline at end of file
diff --git a/src/locales/de/error.json b/src/locales/de/error.json
new file mode 100644
index 0000000..829ed04
--- /dev/null
+++ b/src/locales/de/error.json
@@ -0,0 +1,8 @@
+{
+ "page": "Diese angeforderte Seite {{pathname}} ist nicht vorhanden.",
+ "support": [
+ "Besuche den ",
+ "Unterstützung",
+ " Seite für Hilfe."
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/de/games.json b/src/locales/de/games.json
new file mode 100644
index 0000000..a766ce8
--- /dev/null
+++ b/src/locales/de/games.json
@@ -0,0 +1,3 @@
+{
+ "comingSoon": "Spiele - Demnächst!"
+}
\ No newline at end of file
diff --git a/src/locales/de/home.json b/src/locales/de/home.json
new file mode 100644
index 0000000..f65a588
--- /dev/null
+++ b/src/locales/de/home.json
@@ -0,0 +1,4 @@
+{
+ "privacy": "Privatsphäre",
+ "credits": "Credits"
+}
\ No newline at end of file
diff --git a/src/locales/de/index.js b/src/locales/de/index.js
new file mode 100644
index 0000000..473fd7f
--- /dev/null
+++ b/src/locales/de/index.js
@@ -0,0 +1,19 @@
+import home from "./home.json"
+import games from "./games.json"
+import settings from "./settings.json"
+import error from "./error.json"
+import support from "./support.json"
+import credits from "./credits.json"
+import privacy from "./privacy.json"
+
+var en = {
+ "home": home,
+ "games": games,
+ "settings": settings,
+ "error": error,
+ "support": support,
+ "credits": credits,
+ "privacy": privacy
+}
+
+export default en;
\ No newline at end of file
diff --git a/src/locales/de/privacy.json b/src/locales/de/privacy.json
new file mode 100644
index 0000000..f20ab93
--- /dev/null
+++ b/src/locales/de/privacy.json
@@ -0,0 +1,18 @@
+{
+ "title": "Datenschutz-Bestimmungen",
+ "policy": [
+ {
+ "title": "Zustimmung",
+ "text": "Durch die Nutzung unseres Dienstes stimmen Sie unserer Datenschutzerklärung unserer Verwendung von Informationen zu."
+ },
+ {
+ "title": "Informationssammlung",
+ "text": "Wir erheben keine Ihrer personenbezogenen Daten. "
+ },
+ {
+ "title": "Kontakt",
+ "text": "Kontaktdaten finden Sie auf der ",
+ "page": "Support-Seite."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/de/settings.json b/src/locales/de/settings.json
new file mode 100644
index 0000000..e8f1bab
--- /dev/null
+++ b/src/locales/de/settings.json
@@ -0,0 +1,30 @@
+{
+ "title": "Einstellungen",
+ "sidebar": {
+ "search": "Suchen",
+ "tab": "Tab",
+ "appearance": "Aussehen",
+ "ui": "Benutzeroberfläche"
+ },
+ "search": {
+ "proxy": "Proxy",
+ "engine": "Suchmaschine"
+ },
+ "tab": {
+ "cloak": "Tab-Umhang",
+ "custom": "Brauch",
+ "urlPlaceholder": "Geben Sie eine URL ein",
+ "titlePlaceholder": "Geben Sie einen Titel ein",
+ "iconPlaceholder": "Geben Sie eine Symbol-URL ein"
+ },
+ "appearance": {
+ "language": "Sprache",
+ "theme": "Thema",
+ "background": "Hintergrund"
+ },
+ "ui": {
+ "window": "Fenster",
+ "controls": "Kontrollen",
+ "rounding": "Rundung"
+ }
+}
\ No newline at end of file
diff --git a/src/locales/de/support.json b/src/locales/de/support.json
new file mode 100644
index 0000000..f7bbd77
--- /dev/null
+++ b/src/locales/de/support.json
@@ -0,0 +1,23 @@
+{
+ "faq": "FAQ",
+ "contact": "Kontakt",
+ "email": "Email",
+ "questions": [
+ {
+ "title": "Der Proxy wird nicht geladen",
+ "answer": "Wenn Sie eine Fehlerseite sehen, versuchen Sie, die Website neu zu laden. "
+ },
+ {
+ "title": "Wo erhalte ich weitere Links zu Metallic?",
+ "answer": "Ich poste nicht viele Links, aber sieh dir den TN-Proxy-Server an discord.gg/unblock Ich könnte einige posten."
+ },
+ {
+ "title": "Sind meine Informationen sicher?",
+ "answer": "Wir sammeln keine Daten von Ihnen, aber jede Website, die Sie besuchen, kann dies tun."
+ },
+ {
+ "title": "Können Sie Metallic selbst hosten?",
+ "answer": "Sehen Sie sich das Github-Repository für Quellcode und Informationen zum Hosting an."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/en/credits.json b/src/locales/en/credits.json
new file mode 100644
index 0000000..0abf9e2
--- /dev/null
+++ b/src/locales/en/credits.json
@@ -0,0 +1,10 @@
+{
+ "title": "Credits",
+ "developers": "Developers",
+ "proxies": "Proxies",
+ "games": "Games",
+ "others": "Others",
+ "othersMessage": "Everyone else in the community :)",
+ "mainDevText": "Owner and main developer",
+ "devText": "Developer"
+}
\ No newline at end of file
diff --git a/src/locales/en/error.json b/src/locales/en/error.json
new file mode 100644
index 0000000..8983c55
--- /dev/null
+++ b/src/locales/en/error.json
@@ -0,0 +1,8 @@
+{
+ "page": "This requested page {{pathname}} does not exist.",
+ "support": [
+ "Visit the ",
+ "support",
+ " page for help."
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/en/games.json b/src/locales/en/games.json
new file mode 100644
index 0000000..6fb52a8
--- /dev/null
+++ b/src/locales/en/games.json
@@ -0,0 +1,3 @@
+{
+ "comingSoon": "Games - Coming Soon!"
+}
\ No newline at end of file
diff --git a/src/locales/en/home.json b/src/locales/en/home.json
new file mode 100644
index 0000000..6b052c7
--- /dev/null
+++ b/src/locales/en/home.json
@@ -0,0 +1,4 @@
+{
+ "privacy": "Privacidad",
+ "credits": "Créditos"
+}
\ No newline at end of file
diff --git a/src/locales/en/index.js b/src/locales/en/index.js
new file mode 100644
index 0000000..473fd7f
--- /dev/null
+++ b/src/locales/en/index.js
@@ -0,0 +1,19 @@
+import home from "./home.json"
+import games from "./games.json"
+import settings from "./settings.json"
+import error from "./error.json"
+import support from "./support.json"
+import credits from "./credits.json"
+import privacy from "./privacy.json"
+
+var en = {
+ "home": home,
+ "games": games,
+ "settings": settings,
+ "error": error,
+ "support": support,
+ "credits": credits,
+ "privacy": privacy
+}
+
+export default en;
\ No newline at end of file
diff --git a/src/locales/en/privacy.json b/src/locales/en/privacy.json
new file mode 100644
index 0000000..1d8b743
--- /dev/null
+++ b/src/locales/en/privacy.json
@@ -0,0 +1,18 @@
+{
+ "title": "Privacy Policy",
+ "policy": [
+ {
+ "title": "Consent",
+ "text": "By using our service, you agree to our Privacy Policy our use of information."
+ },
+ {
+ "title": "Information Collection",
+ "text": "We do not collect any of your personal data. However, visiting third party websites using our proxy may use your data. Read the privay policy from each website you visit for more info on how they collect your data."
+ },
+ {
+ "title": "Contact",
+ "text": "Contact information can be found on the ",
+ "page": "support page."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/en/settings.json b/src/locales/en/settings.json
new file mode 100644
index 0000000..b39c906
--- /dev/null
+++ b/src/locales/en/settings.json
@@ -0,0 +1,30 @@
+{
+ "title": "Settings",
+ "sidebar": {
+ "search": "Search",
+ "tab": "Tab",
+ "appearance": "Appearance",
+ "ui": "UI"
+ },
+ "search": {
+ "proxy": "Proxy",
+ "engine": "Search Engine"
+ },
+ "tab": {
+ "cloak": "Tab Cloak",
+ "custom": "Custom",
+ "urlPlaceholder": "Enter a URL",
+ "titlePlaceholder": "Enter a title",
+ "iconPlaceholder": "Enter an icon URL"
+ },
+ "appearance": {
+ "language": "Language",
+ "theme": "Theme",
+ "background": "Background"
+ },
+ "ui": {
+ "window": "Window",
+ "controls": "Controls",
+ "rounding": "Rounding"
+ }
+}
\ No newline at end of file
diff --git a/src/locales/en/support.json b/src/locales/en/support.json
new file mode 100644
index 0000000..2cf5d02
--- /dev/null
+++ b/src/locales/en/support.json
@@ -0,0 +1,23 @@
+{
+ "faq": "FAQ",
+ "contact": "Contact",
+ "email": "Email",
+ "questions": [
+ {
+ "title": "The proxy is not loading",
+ "answer": "If you see an error page try reloading the website. If the website is not supported there is nothing we can do."
+ },
+ {
+ "title": "Where can I obtain more links to Metallic?",
+ "answer": "I don't post links much but check out the TN proxy server discord.gg/unblock I might post some."
+ },
+ {
+ "title": "Is my information secure?",
+ "answer": "We do not collect any data from you but any website you visit can."
+ },
+ {
+ "title": "Can you self-host Metallic?",
+ "answer": "Check out the Github repository for source code and info about hosting."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/es/credits.json b/src/locales/es/credits.json
new file mode 100644
index 0000000..f4b0fdf
--- /dev/null
+++ b/src/locales/es/credits.json
@@ -0,0 +1,10 @@
+{
+ "title": "Créditos",
+ "developers": "Desarrolladores",
+ "proxies": "Apoderados",
+ "games": "Juegos",
+ "others": "Otros",
+ "othersMessage": "Todos los demás en la comunidad :)",
+ "mainDevText": "Propietario y desarrollador principal",
+ "devText": "Desarrollador"
+}
\ No newline at end of file
diff --git a/src/locales/es/error.json b/src/locales/es/error.json
new file mode 100644
index 0000000..cddb586
--- /dev/null
+++ b/src/locales/es/error.json
@@ -0,0 +1,8 @@
+{
+ "page": "Esta página solicitada {{pathname}} no existe.",
+ "support": [
+ "Visite la ",
+ "página de soporte",
+ " para obtener ayuda."
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/es/games.json b/src/locales/es/games.json
new file mode 100644
index 0000000..b30ea42
--- /dev/null
+++ b/src/locales/es/games.json
@@ -0,0 +1,3 @@
+{
+ "comingSoon": "Juegos - ¡Próximamente!"
+}
\ No newline at end of file
diff --git a/src/locales/es/home.json b/src/locales/es/home.json
new file mode 100644
index 0000000..e0ee73c
--- /dev/null
+++ b/src/locales/es/home.json
@@ -0,0 +1,4 @@
+{
+ "privacy": "Privacidad",
+ "credits": "Créditos"
+}
\ No newline at end of file
diff --git a/src/locales/es/index.js b/src/locales/es/index.js
new file mode 100644
index 0000000..6c33437
--- /dev/null
+++ b/src/locales/es/index.js
@@ -0,0 +1,19 @@
+import home from "./home.json"
+import games from "./games.json"
+import settings from "./settings.json"
+import error from "./error.json"
+import support from "./support.json"
+import credits from "./credits.json"
+import privacy from "./privacy.json"
+
+var es = {
+ "home": home,
+ "games": games,
+ "settings": settings,
+ "error": error,
+ "support": support,
+ "credits": credits,
+ "privacy": privacy
+}
+
+export default es;
\ No newline at end of file
diff --git a/src/locales/es/privacy.json b/src/locales/es/privacy.json
new file mode 100644
index 0000000..9cbe925
--- /dev/null
+++ b/src/locales/es/privacy.json
@@ -0,0 +1,18 @@
+{
+ "title": "política de privacidad",
+ "policy": [
+ {
+ "title": "Consentir",
+ "text": "Al utilizar nuestro servicio, usted acepta nuestra Política de privacidad y nuestro uso de la información."
+ },
+ {
+ "title": "Recopilación de información",
+ "text": "No recopilamos ninguno de sus datos personales. Sin embargo, visitar sitios web de terceros utilizando nuestro proxy puede usar sus datos. Lea la política de privacidad de cada sitio web que visite para obtener más información sobre cómo recopilan sus datos."
+ },
+ {
+ "title": "Contacto",
+ "text": "La información de contacto se puede encontrar en la ",
+ "page": "página de soporte."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/es/settings.json b/src/locales/es/settings.json
new file mode 100644
index 0000000..1d9c7a1
--- /dev/null
+++ b/src/locales/es/settings.json
@@ -0,0 +1,30 @@
+{
+ "title": "Ajustes",
+ "sidebar": {
+ "search": "Buscar",
+ "tab": "Pestaña",
+ "appearance": "Apariencia",
+ "ui": "interfaz de usuario"
+ },
+ "search": {
+ "proxy": "Proxy",
+ "engine": "Buscador"
+ },
+ "tab": {
+ "cloak": "Capa de pestaña",
+ "custom": "Costumbre",
+ "urlPlaceholder": "Introduce una URL",
+ "titlePlaceholder": "Introduce un título",
+ "iconPlaceholder": "Introduzca una URL de icono"
+ },
+ "appearance": {
+ "language": "Idioma",
+ "theme": "Tema",
+ "background": "Fondo"
+ },
+ "ui": {
+ "window": "Ventana",
+ "controls": "Control S",
+ "rounding": "Redondeo"
+ }
+}
\ No newline at end of file
diff --git a/src/locales/es/support.json b/src/locales/es/support.json
new file mode 100644
index 0000000..390d738
--- /dev/null
+++ b/src/locales/es/support.json
@@ -0,0 +1,23 @@
+{
+ "faq": "Preguntas más frecuentes",
+ "contact": "Contacto",
+ "email": "Correo electrónico",
+ "questions": [
+ {
+ "title": "El proxy no carga",
+ "answer": "Si ve una página de error, intente volver a cargar el sitio web. Si el sitio web no es compatible, no hay nada que podamos hacer."
+ },
+ {
+ "title": "¿Dónde puedo obtener más enlaces a Metallic?",
+ "answer": "No publico muchos enlaces, pero echa un vistazo al servidor proxy TN discord.gg/unblock. Podría publicar algunos."
+ },
+ {
+ "title": "¿Está segura mi información?",
+ "answer": "No recopilamos ningún dato suyo, pero cualquier sitio web que visite puede hacerlo."
+ },
+ {
+ "title": "¿Puedes auto-anfitrión de Metallic?",
+ "answer": "Consulte el repositorio de Github para obtener el código fuente y la información sobre alojamiento."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/fr/credits.json b/src/locales/fr/credits.json
new file mode 100644
index 0000000..1bed1d2
--- /dev/null
+++ b/src/locales/fr/credits.json
@@ -0,0 +1,10 @@
+{
+ "title": "Crédits",
+ "developers": "Développeurs",
+ "proxies": "Procurations",
+ "games": "Jeux",
+ "others": "Autres",
+ "othersMessage": "Tout le monde dans la communauté :)",
+ "mainDevText": "Propriétaire et développeur principal",
+ "devText": "Développeur"
+}
\ No newline at end of file
diff --git a/src/locales/fr/error.json b/src/locales/fr/error.json
new file mode 100644
index 0000000..287d5c8
--- /dev/null
+++ b/src/locales/fr/error.json
@@ -0,0 +1,8 @@
+{
+ "page": "Cette page demandée {{pathname}} n'existe pas.",
+ "support": [
+ "Visiter le ",
+ "soutien",
+ " page d'aide."
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/fr/games.json b/src/locales/fr/games.json
new file mode 100644
index 0000000..7a11164
--- /dev/null
+++ b/src/locales/fr/games.json
@@ -0,0 +1,3 @@
+{
+ "comingSoon": "Jeux - Bientôt disponible!"
+}
\ No newline at end of file
diff --git a/src/locales/fr/home.json b/src/locales/fr/home.json
new file mode 100644
index 0000000..c715acd
--- /dev/null
+++ b/src/locales/fr/home.json
@@ -0,0 +1,4 @@
+{
+ "privacy": "Confidentialité",
+ "credits": "Crédits"
+}
\ No newline at end of file
diff --git a/src/locales/fr/index.js b/src/locales/fr/index.js
new file mode 100644
index 0000000..473fd7f
--- /dev/null
+++ b/src/locales/fr/index.js
@@ -0,0 +1,19 @@
+import home from "./home.json"
+import games from "./games.json"
+import settings from "./settings.json"
+import error from "./error.json"
+import support from "./support.json"
+import credits from "./credits.json"
+import privacy from "./privacy.json"
+
+var en = {
+ "home": home,
+ "games": games,
+ "settings": settings,
+ "error": error,
+ "support": support,
+ "credits": credits,
+ "privacy": privacy
+}
+
+export default en;
\ No newline at end of file
diff --git a/src/locales/fr/privacy.json b/src/locales/fr/privacy.json
new file mode 100644
index 0000000..2535e3f
--- /dev/null
+++ b/src/locales/fr/privacy.json
@@ -0,0 +1,18 @@
+{
+ "title": "politique de confidentialité",
+ "policy": [
+ {
+ "title": "Consentement",
+ "text": "En utilisant notre service, vous acceptez notre politique de confidentialité notre utilisation des informations."
+ },
+ {
+ "title": "Collecte d'informations",
+ "text": "Nous ne collectons aucune de vos données personnelles. "
+ },
+ {
+ "title": "Contact",
+ "text": "Les coordonnées se trouvent sur le ",
+ "page": "page d'assistance."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/fr/settings.json b/src/locales/fr/settings.json
new file mode 100644
index 0000000..6d3e7e0
--- /dev/null
+++ b/src/locales/fr/settings.json
@@ -0,0 +1,30 @@
+{
+ "title": "Paramètres",
+ "sidebar": {
+ "search": "Recherche",
+ "tab": "Languette",
+ "appearance": "Apparence",
+ "ui": "interface utilisateur"
+ },
+ "search": {
+ "proxy": "Procuration",
+ "engine": "Moteur de recherche"
+ },
+ "tab": {
+ "cloak": "Cape d'onglet",
+ "custom": "Coutume",
+ "urlPlaceholder": "Entrez une URL",
+ "titlePlaceholder": "Entrez un titre",
+ "iconPlaceholder": "Entrez une URL d'icône"
+ },
+ "appearance": {
+ "language": "Langue",
+ "theme": "Thème",
+ "background": "Arrière-plan"
+ },
+ "ui": {
+ "window": "Fenêtre",
+ "controls": "Contrôles",
+ "rounding": "Arrondi"
+ }
+}
\ No newline at end of file
diff --git a/src/locales/fr/support.json b/src/locales/fr/support.json
new file mode 100644
index 0000000..76decc7
--- /dev/null
+++ b/src/locales/fr/support.json
@@ -0,0 +1,23 @@
+{
+ "faq": "FAQ",
+ "contact": "Contact",
+ "email": "E-mail",
+ "questions": [
+ {
+ "title": "Le proxy ne se charge pas",
+ "answer": "Si vous voyez une page d'erreur, essayez de recharger le site Web. "
+ },
+ {
+ "title": "Où puis-je obtenir plus de liens vers Metallic ?",
+ "answer": "Je ne publie pas beaucoup de liens, mais consultez le serveur proxy TN discord.gg/unblock, je pourrais en publier."
+ },
+ {
+ "title": "Mes informations sont-elles sécurisées ?",
+ "answer": "Nous ne collectons aucune donnée auprès de vous, mais tout site Web que vous visitez peut le faire."
+ },
+ {
+ "title": "Pouvez-vous auto-héberger Metallic ?",
+ "answer": "Consultez le référentiel Github pour le code source et des informations sur l'hébergement."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/index.js b/src/locales/index.js
new file mode 100644
index 0000000..d2b8f3d
--- /dev/null
+++ b/src/locales/index.js
@@ -0,0 +1,9 @@
+import en from "./en/index.js"
+import es from "./es/index.js"
+import fr from "./fr/index.js"
+import zh from "./zh/index.js"
+import de from "./de/index.js"
+
+var languages = {en, es, fr, zh, de}
+
+export default languages;
\ No newline at end of file
diff --git a/src/locales/zh/credits.json b/src/locales/zh/credits.json
new file mode 100644
index 0000000..44cc634
--- /dev/null
+++ b/src/locales/zh/credits.json
@@ -0,0 +1,10 @@
+{
+ "title": "学分",
+ "developers": "开发商",
+ "proxies": "代理",
+ "games": "游戏",
+ "others": "其他的",
+ "othersMessage": "社区中的其他人 :)",
+ "mainDevText": "业主和主要开发商",
+ "devText": "开发商"
+}
\ No newline at end of file
diff --git a/src/locales/zh/error.json b/src/locales/zh/error.json
new file mode 100644
index 0000000..97cc100
--- /dev/null
+++ b/src/locales/zh/error.json
@@ -0,0 +1,8 @@
+{
+ "page": "这个请求的页面 {{pathname}} 不存在。",
+ "support": [
+ "参观 ",
+ "支持",
+ " 求助页面。"
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/zh/games.json b/src/locales/zh/games.json
new file mode 100644
index 0000000..7f5d40c
--- /dev/null
+++ b/src/locales/zh/games.json
@@ -0,0 +1,3 @@
+{
+ "comingSoon": "游戏 - 即将推出!"
+}
\ No newline at end of file
diff --git a/src/locales/zh/home.json b/src/locales/zh/home.json
new file mode 100644
index 0000000..562550e
--- /dev/null
+++ b/src/locales/zh/home.json
@@ -0,0 +1,4 @@
+{
+ "privacy": "隐私权",
+ "credits": "出处"
+}
\ No newline at end of file
diff --git a/src/locales/zh/index.js b/src/locales/zh/index.js
new file mode 100644
index 0000000..473fd7f
--- /dev/null
+++ b/src/locales/zh/index.js
@@ -0,0 +1,19 @@
+import home from "./home.json"
+import games from "./games.json"
+import settings from "./settings.json"
+import error from "./error.json"
+import support from "./support.json"
+import credits from "./credits.json"
+import privacy from "./privacy.json"
+
+var en = {
+ "home": home,
+ "games": games,
+ "settings": settings,
+ "error": error,
+ "support": support,
+ "credits": credits,
+ "privacy": privacy
+}
+
+export default en;
\ No newline at end of file
diff --git a/src/locales/zh/privacy.json b/src/locales/zh/privacy.json
new file mode 100644
index 0000000..500880b
--- /dev/null
+++ b/src/locales/zh/privacy.json
@@ -0,0 +1,18 @@
+{
+ "title": "隐私政策",
+ "policy": [
+ {
+ "title": "同意",
+ "text": "使用我们的服务,即表示您同意我们使用信息的隐私政策。"
+ },
+ {
+ "title": "信息收集",
+ "text": "我们不收集您的任何个人数据。"
+ },
+ {
+ "title": "接触",
+ "text": "联系信息可在 ",
+ "page": "支持页面。"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/locales/zh/settings.json b/src/locales/zh/settings.json
new file mode 100644
index 0000000..7bceb9b
--- /dev/null
+++ b/src/locales/zh/settings.json
@@ -0,0 +1,30 @@
+{
+ "title": "设置",
+ "sidebar": {
+ "search": "搜索",
+ "tab": "标签",
+ "appearance": "外貌",
+ "ui": "用户界面"
+ },
+ "search": {
+ "proxy": "代理人",
+ "engine": "搜索引擎"
+ },
+ "tab": {
+ "cloak": "标签斗篷",
+ "custom": "风俗",
+ "urlPlaceholder": "输入网址",
+ "titlePlaceholder": "输入标题",
+ "iconPlaceholder": "输入图标 URL"
+ },
+ "appearance": {
+ "language": "语言",
+ "theme": "主题",
+ "background": "背景"
+ },
+ "ui": {
+ "window": "窗户",
+ "controls": "控件",
+ "rounding": "四舍五入"
+ }
+}
\ No newline at end of file
diff --git a/src/locales/zh/support.json b/src/locales/zh/support.json
new file mode 100644
index 0000000..8705f09
--- /dev/null
+++ b/src/locales/zh/support.json
@@ -0,0 +1,23 @@
+{
+ "faq": "常问问题",
+ "contact": "接触",
+ "email": "电子邮件",
+ "questions": [
+ {
+ "title": "代理未加载",
+ "answer": "如果您看到错误页面,请尝试重新加载网站。"
+ },
+ {
+ "title": "我在哪里可以获得更多指向 Metallic 的链接?",
+ "answer": "我发布的链接不多,但查看 TN 代理服务器 discord.gg/unblock 我可能会发布一些。"
+ },
+ {
+ "title": "我的信息安全吗?",
+ "answer": "我们不会收集您的任何数据,但您访问的任何网站都可以。"
+ },
+ {
+ "title": "您可以自行托管 Metallic 吗?",
+ "answer": "查看 Github 存储库以获取源代码和有关托管的信息。"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/pages/app.js b/src/pages/app.js
index 9bf5795..6350a53 100644
--- a/src/pages/app.js
+++ b/src/pages/app.js
@@ -1,5 +1,6 @@
import React, { Suspense } from "react";
import { Routes, Route } from "react-router-dom";
+import "../i18n.js";
import "../style/index.css";
import "../proxy.js";
import Background from "../components/background.js";
diff --git a/src/pages/credits.js b/src/pages/credits.js
index 33e6e3c..97a94c8 100644
--- a/src/pages/credits.js
+++ b/src/pages/credits.js
@@ -2,27 +2,30 @@ import React from "react";
import Nav from "../components/nav.js";
import Head from "../components/head.js";
import Obfuscate from "../components/obfuscate.js";
+import { useTranslation } from 'react-i18next';
function Support() {
+ const { t } = useTranslation("credits");
+
return (
<>
- Credits
+ {t("title")}
- Developers
+ {t("developers")}
- Nebeung - Owner and main developer
+ Nebeung - {t("mainDevText")}
- Divide - Developer
+ Divide - {t("devText")}
- Proxies
+ {t("proxies")}
Divide - TOMP
@@ -43,7 +46,7 @@ function Support() {
EndlessVortex - Aero
- Games
+ {t("games")}
BinBashBanana - gfiles
@@ -52,10 +55,10 @@ function Support() {
BinBashBanana - WebRetro
- Others
+ {t("others")}
- Everyone else in the TN/Fog community :)
+ {t("othersMessage")}
>
diff --git a/src/pages/error.js b/src/pages/error.js
index 5050695..dde6fd0 100644
--- a/src/pages/error.js
+++ b/src/pages/error.js
@@ -3,8 +3,11 @@ import { Link } from "react-router-dom";
import Nav from "../components/nav.js";
import Head from "../components/head.js";
import Obfuscate from "../components/obfuscate.js";
+import { useTranslation } from 'react-i18next';
function Error() {
+ const { t } = useTranslation("error");
+
return (
<>
@@ -14,14 +17,14 @@ function Error() {
- This requested page {window.location.pathname} does not exist.
+ {t("page", {pathname: window.location.pathname})}
- Visit the
+ {t("support.0")}
- support
+ {t("support.1")}
- page for help.
+ {t("support.2")}
>
);
diff --git a/src/pages/games.js b/src/pages/games.js
index 494b060..7a1000f 100644
--- a/src/pages/games.js
+++ b/src/pages/games.js
@@ -2,14 +2,17 @@ import React from "react";
import Nav from "../components/nav.js";
import Head from "../components/head.js";
import Obfuscate from "../components/obfuscate.js";
+import { useTranslation } from 'react-i18next';
function Games() {
+ const { t } = useTranslation("games");
+
return (
<>
- Games - Coming Soon!
+ {t("comingSoon")}
>
);
diff --git a/src/pages/home.js b/src/pages/home.js
index 793e6fe..8eb45f0 100644
--- a/src/pages/home.js
+++ b/src/pages/home.js
@@ -8,8 +8,11 @@ import BareClient from "@tomphttp/bare-client";
import { bareServerURL } from "../consts.js";
import { getLink } from "../util.js";
import { useLocalAppearance } from "../settings.js";
+import { useTranslation } from 'react-i18next';
function Home() {
+ const { t } = useTranslation("home");
+
var proxy = React.useRef();
var [suggestions, setSuggestions] = React.useState([]);
@@ -170,10 +173,10 @@ function Home() {
- Privacy
+ {t("privacy")}
- Credits
+ {t("credits")}
diff --git a/src/pages/privacy.js b/src/pages/privacy.js
index f06a4eb..456607c 100644
--- a/src/pages/privacy.js
+++ b/src/pages/privacy.js
@@ -3,46 +3,38 @@ import Nav from "../components/nav.js";
import Head from "../components/head.js";
import Obfuscate from "../components/obfuscate.js";
import { Link } from "react-router-dom";
+import { useTranslation } from 'react-i18next';
function Privacy() {
+ const { t } = useTranslation("privacy");
+
return (
<>
- Privacy Policy
+ {t("title")}
- Consent
+ {t("policy.0.title")}
-
- By using our service, you agree to our Privacy Policy our use of
- information.
-
+ {t("policy.0.text")}
- Information Collection
+ {t("policy.1.title")}
-
- We do not collect any of your personal data. However, visiting third
- party websites using our proxy may use you data.
-
-
-
- Read the privay policy from each website you visit for more info on
- how they collect your data.
-
+ {t("policy.1.text")}
- Contact
+ {t("policy.2.title")}
- Contact information can be found on the
+ {t("policy.2.text")}
- support page
+ {t("policy.2.page")}
diff --git a/src/pages/settings/appearance.js b/src/pages/settings/appearance.js
index b4cffcf..3ff726b 100644
--- a/src/pages/settings/appearance.js
+++ b/src/pages/settings/appearance.js
@@ -1,7 +1,28 @@
import clsx from "clsx";
import React from "react";
import Obfuscate from "../../components/obfuscate.js";
-import { useLocalAppearance, useLocalBackground } from "../../settings.js";
+import { useLocalLanguage, useLocalAppearance, useLocalBackground } from "../../settings.js";
+import { setLanguage } from "../../i18n.js";
+import { useTranslation } from 'react-i18next';
+
+function LanguageOption({ type, children }) {
+ const [localLanguage, setLocalLanguage] = useLocalLanguage();
+
+ return (
+
{
+ setLanguage(type)
+ setLocalLanguage(type)
+ }}
+ className={clsx(
+ "optionchoose",
+ type === localLanguage && "chooseactive"
+ )}
+ >
+ {children}
+
+ );
+}
function ThemeOption({ type, children }) {
const [localAppearance, setLocalAppearance] = useLocalAppearance();
@@ -40,10 +61,32 @@ function BackgroundOption({ type, children }) {
}
function Appearance() {
+ const { t } = useTranslation("settings");
+
return (
<>
- Theme
+ {t("appearance.language")}
+
+
+
+ English
+
+
+ Spanish
+
+
+ French
+
+
+ Chinese
+
+
+ German
+
+
+
+ {t("appearance.theme")}
@@ -141,7 +184,7 @@ function Appearance() {
}
- Background
+ {t("appearance.background")}
None
diff --git a/src/pages/settings/search.js b/src/pages/settings/search.js
index 76a2c48..55256e4 100644
--- a/src/pages/settings/search.js
+++ b/src/pages/settings/search.js
@@ -2,6 +2,7 @@ import clsx from "clsx";
import React from "react";
import Obfuscate from "../../components/obfuscate.js";
import { useLocalEngine, useLocalProxy } from "../../settings.js";
+import { useTranslation } from 'react-i18next';
function EngineOption({ type, children }) {
var [localEngine, setLocalEngine] = useLocalEngine();
@@ -34,10 +35,12 @@ function ProxyOption({ type, children }) {
}
function Search() {
+ const { t } = useTranslation("settings");
+
return (
<>
- Proxy
+ {t("search.proxy")}
@@ -57,7 +60,7 @@ function Search() {
- Search Engine
+ {t("search.engine")}
diff --git a/src/pages/settings/tab.js b/src/pages/settings/tab.js
index 8ccaa89..f41e18a 100644
--- a/src/pages/settings/tab.js
+++ b/src/pages/settings/tab.js
@@ -4,8 +4,11 @@ import ClearIcon from "@mui/icons-material/Clear";
import BareClient from "@tomphttp/bare-client";
import { useLocalIcon, useLocalTitle } from "../../settings.js";
import { bareServerURL } from "../../consts.js";
+import { useTranslation } from 'react-i18next';
function Tab() {
+ const { t } = useTranslation("settings");
+
const bare = React.useMemo(() => new BareClient(bareServerURL), []);
var url = React.useRef();
@@ -60,7 +63,7 @@ function Tab() {
return (
<>
- Tab Cloak
+ {t("tab.cloak")}
@@ -86,17 +89,17 @@ function Tab() {
setTab(url.current.value)}
/>
- Custom
+ {t("tab.custom")}
setLocalTitle(e.target.value)}
value={localTitle}
@@ -104,7 +107,7 @@ function Tab() {
/>
setLocalIcon(e.target.value)}
value={localIcon}
diff --git a/src/pages/settings/ui.js b/src/pages/settings/ui.js
index a69a2c1..3031923 100644
--- a/src/pages/settings/ui.js
+++ b/src/pages/settings/ui.js
@@ -2,6 +2,7 @@ import clsx from "clsx";
import React from "react";
import Obfuscate from "../../components/obfuscate.js";
import { useLocalControls, useLocalWindow, useLocalRounding } from "../../settings.js";
+import { useTranslation } from 'react-i18next';
function WindowOption({ type, children }) {
const [localWindow, setLocalWindow] = useLocalWindow();
@@ -49,10 +50,12 @@ function RoundingOption({ type, children }) {
}
function UI() {
+ const { t } = useTranslation("settings");
+
return (
<>
- Window
+ {t("ui.window")}
@@ -66,7 +69,7 @@ function UI() {
- Controls
+ {t("ui.controls")}
@@ -80,7 +83,7 @@ function UI() {
- Rounding
+ {t("ui.rounding")}
diff --git a/src/pages/support.js b/src/pages/support.js
index cb93156..2292935 100644
--- a/src/pages/support.js
+++ b/src/pages/support.js
@@ -2,56 +2,48 @@ import React from "react";
import Nav from "../components/nav.js";
import Head from "../components/head.js";
import Obfuscate from "../components/obfuscate.js";
+import { useTranslation } from 'react-i18next';
function Support() {
+ const { t } = useTranslation("support");
+
return (
<>
- FAQ
+ {t("faq")}
- The proxy is not loading
+ {t("questions.0.title")}
-
- If you see an error page try reloading the website. If the website
- is not supported there is nothing we can do.
-
+ {t("questions.0.answer")}
- Where can I obtain more links to Metallic?
+ {t("questions.1.title")}
-
- You can find more link on our discord here. Go to #proxy-bot and
- choose Metallic for a randomized link.
-
+ {t("questions.1.answer")}
- Is my information secure?
+ {t("questions.2.title")}
-
- We do not collect any data from you but any website you visit can.
-
+ {t("questions.2.answer")}
- How to self-host Metallic
+ {t("questions.3.title")}
-
- Check out the github repository for source code and info about
- hosting.
-
+ {t("questions.3.answer")}
- Contact
+ {t("contact")}
- Email
+ {t("email")}
diff --git a/src/settings.js b/src/settings.js
index bab89a9..67edf23 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -5,6 +5,7 @@ const useLocalFallback = (key, fallback) => {
return [local === null ? fallback : local, setLocal];
};
+export var useLocalLanguage = () => useLocalFallback("language", "en");
export var useLocalEngine = () => useLocalFallback("engine", "Google");
export var useLocalBackground = () => useLocalFallback("background", "none");
export var useLocalAppearance = () => useLocalFallback("appearance", "default");
diff --git a/src/style/style.css b/src/style/style.css
index 6c7e6f3..2e84ff6 100644
--- a/src/style/style.css
+++ b/src/style/style.css
@@ -37,6 +37,10 @@ body {
color: var(--placeholder);
}
+a {
+ text-decoration: none;
+}
+
.hometitle {
font-family: var(--font-title) !important;
font-size: 85px;
@@ -202,6 +206,10 @@ body {
text-decoration: underline;
}
+.link:hover span[class] {
+ text-decoration: underline;
+}
+
.footer {
color: var(--text);
margin-top: auto;