diff --git a/package-lock.json b/package-lock.json index 2d67129..fe4d6ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,10 +5,13 @@ "packages": { "": { "dependencies": { + "i18next": "^23.7.8", + "i18next-browser-languagedetector": "^7.2.0", "million": "^2.6.4", "preact": "^10.13.1", "preact-iso": "^2.3.2", - "preact-render-to-string": "^6.3.1" + "preact-render-to-string": "^6.3.1", + "react-i18next": "^13.5.0" }, "devDependencies": { "@preact/preset-vite": "^2.5.0", @@ -411,6 +414,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", @@ -2902,6 +2916,44 @@ "node": ">= 0.4" } }, + "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/i18next": { + "version": "23.7.8", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.7.8.tgz", + "integrity": "sha512-yCe9964O+1abdIG01AOzk6P9mQi0HVJV1B57whYJQu6TjmrB9JHHDYonDI8amGt6M6b9bP3x3R0Zh7ROmvX7JQ==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.2.0.tgz", + "integrity": "sha512-U00DbDtFIYD3wkWsr2aVGfXGAj2TgnELzOX9qv8bT0aJtvPV9CRO77h+vgmHFBMe7LAxdwvT/7VkCWGya6L3tA==", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, "node_modules/ignore": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", @@ -3476,7 +3528,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -4102,6 +4153,39 @@ } ] }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-i18next": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-13.5.0.tgz", + "integrity": "sha512-CFJ5NDGJ2MUyBohEHxljOq/39NQ972rh1ajnadG9BjTk+UXbHLq4z5DKEbEQBDoIhUmmbuS/fIMJKo6VOax1HA==", + "dependencies": { + "@babel/runtime": "^7.22.5", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -4148,6 +4232,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", @@ -4867,6 +4956,14 @@ } } }, + "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/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", diff --git a/package.json b/package.json index b166921..48d987d 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,13 @@ "preview": "vite preview" }, "dependencies": { + "i18next": "^23.7.8", + "i18next-browser-languagedetector": "^7.2.0", "million": "^2.6.4", "preact": "^10.13.1", "preact-iso": "^2.3.2", - "preact-render-to-string": "^6.3.1" + "preact-render-to-string": "^6.3.1", + "react-i18next": "^13.5.0" }, "devDependencies": { "@preact/preset-vite": "^2.5.0", diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 1fa720d..fd375ab 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -4,15 +4,17 @@ import LogoSvg from "../assets/logo.svg"; import GamesSvg from '../assets/games.svg'; import { useState, useEffect } from "preact/hooks" +import { useTranslation } from 'react-i18next'; export function Header() { const { url } = useLocation(); + const { t, i18n } = useTranslation(); return (
diff --git a/src/i18n.ts b/src/i18n.ts new file mode 100644 index 0000000..eee01c3 --- /dev/null +++ b/src/i18n.ts @@ -0,0 +1,28 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; + +import translationEN from './locales/EN.json'; +import translationJA from './locales/ja.json'; + +const resources = { + en: { + translation: translationEN, + }, + ja: { + translation: translationJA, + }, +}; + +i18n + .use(initReactI18next) + .use(LanguageDetector) + .init({ + resources, + fallbackLng: 'en', + interpolation: { + escapeValue: false, + }, + }); + +export default i18n; \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index fe6581f..dddbeb8 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -6,6 +6,7 @@ import { Home } from './pages/Home'; import { NotFound } from './pages/_404.jsx'; import './style.css'; import './themes/main.css'; +import './i18n'; export function App() { return ( diff --git a/src/locales/en.json b/src/locales/en.json new file mode 100644 index 0000000..7061e62 --- /dev/null +++ b/src/locales/en.json @@ -0,0 +1,8 @@ +{ + "header": { + "title": "nebula.", + "games": "Games", + "settings": "Settings", + "discord": "Want more links?" + } +} \ No newline at end of file diff --git a/src/locales/ja.json b/src/locales/ja.json new file mode 100644 index 0000000..926d948 --- /dev/null +++ b/src/locales/ja.json @@ -0,0 +1,8 @@ +{ + "header": { + "title": "ネブラ。", + "games": "ゲーム", + "settings": "セッティング", + "discord": "もっとリンクが欲しいですか?" + } +} \ No newline at end of file