mirror of
				https://github.com/karl0ss/homepage.git
				synced 2025-10-31 14:34:00 +00:00 
			
		
		
		
	refactor i18n to be server side
This commit is contained in:
		
							parent
							
								
									3ae4113043
								
							
						
					
					
						commit
						8bc240b934
					
				
							
								
								
									
										143
									
								
								next-i18next.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								next-i18next.config.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,143 @@ | ||||
| // prettyBytes taken from https://github.com/sindresorhus/pretty-bytes
 | ||||
| 
 | ||||
| /* eslint-disable no-param-reassign */ | ||||
| const BYTE_UNITS = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; | ||||
| 
 | ||||
| const BIBYTE_UNITS = ["B", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]; | ||||
| 
 | ||||
| const BIT_UNITS = ["b", "kbit", "Mbit", "Gbit", "Tbit", "Pbit", "Ebit", "Zbit", "Ybit"]; | ||||
| 
 | ||||
| const BIBIT_UNITS = ["b", "kibit", "Mibit", "Gibit", "Tibit", "Pibit", "Eibit", "Zibit", "Yibit"]; | ||||
| 
 | ||||
| /* | ||||
| Formats the given number using `Number#toLocaleString`. | ||||
| - If locale is a string, the value is expected to be a locale-key (for example: `de`). | ||||
| - If locale is true, the system default locale is used for translation. | ||||
| - If no value for locale is specified, the number is returned unmodified. | ||||
| */ | ||||
| const toLocaleString = (number, locale, options) => { | ||||
|   let result = number; | ||||
|   if (typeof locale === "string" || Array.isArray(locale)) { | ||||
|     result = number.toLocaleString(locale, options); | ||||
|   } else if (locale === true || options !== undefined) { | ||||
|     result = number.toLocaleString(undefined, options); | ||||
|   } | ||||
| 
 | ||||
|   return result; | ||||
| }; | ||||
| 
 | ||||
| function prettyBytes(number, options) { | ||||
|   if (!Number.isFinite(number)) { | ||||
|     throw new TypeError(`Expected a finite number, got ${typeof number}: ${number}`); | ||||
|   } | ||||
| 
 | ||||
|   options = { | ||||
|     bits: false, | ||||
|     binary: false, | ||||
|     ...options, | ||||
|   }; | ||||
| 
 | ||||
|   // eslint-disable-next-line no-nested-ternary
 | ||||
|   const UNITS = options.bits ? (options.binary ? BIBIT_UNITS : BIT_UNITS) : options.binary ? BIBYTE_UNITS : BYTE_UNITS; | ||||
| 
 | ||||
|   if (options.signed && number === 0) { | ||||
|     return ` 0 ${UNITS[0]}`; | ||||
|   } | ||||
| 
 | ||||
|   const isNegative = number < 0; | ||||
|   // eslint-disable-next-line no-nested-ternary
 | ||||
|   const prefix = isNegative ? "-" : options.signed ? "+" : ""; | ||||
| 
 | ||||
|   if (isNegative) { | ||||
|     number = -number; | ||||
|   } | ||||
| 
 | ||||
|   let localeOptions; | ||||
| 
 | ||||
|   if (options.minimumFractionDigits !== undefined) { | ||||
|     localeOptions = { minimumFractionDigits: options.minimumFractionDigits }; | ||||
|   } | ||||
| 
 | ||||
|   if (options.maximumFractionDigits !== undefined) { | ||||
|     localeOptions = { maximumFractionDigits: options.maximumFractionDigits, ...localeOptions }; | ||||
|   } | ||||
| 
 | ||||
|   if (number < 1) { | ||||
|     const numberString = toLocaleString(number, options.locale, localeOptions); | ||||
|     return `${prefix + numberString} ${UNITS[0]}`; | ||||
|   } | ||||
| 
 | ||||
|   const exponent = Math.min( | ||||
|     Math.floor(options.binary ? Math.log(number) / Math.log(1024) : Math.log10(number) / 3), | ||||
|     UNITS.length - 1 | ||||
|   ); | ||||
|   number /= (options.binary ? 1024 : 1000) ** exponent; | ||||
| 
 | ||||
|   if (!localeOptions) { | ||||
|     number = number.toPrecision(3); | ||||
|   } | ||||
| 
 | ||||
|   const numberString = toLocaleString(Number(number), options.locale, localeOptions); | ||||
| 
 | ||||
|   const unit = UNITS[exponent]; | ||||
| 
 | ||||
|   return `${prefix + numberString} ${unit}`; | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|   i18n: { | ||||
|     defaultLocale: "en", | ||||
|     locales: [ | ||||
|       "en", | ||||
|       "ca", | ||||
|       "de", | ||||
|       "es", | ||||
|       "fr", | ||||
|       "he", | ||||
|       "hr", | ||||
|       "hu", | ||||
|       "it", | ||||
|       "nb-NO", | ||||
|       "nl", | ||||
|       "pl", | ||||
|       "pt", | ||||
|       "ro", | ||||
|       "ru", | ||||
|       "sv", | ||||
|       "vi", | ||||
|       "zh-CN", | ||||
|     ], | ||||
|   }, | ||||
|   serializeConfig: false, | ||||
|   use: [ | ||||
|     { | ||||
|       init: (i18next) => { | ||||
|         i18next.services.formatter.add("bytes", (value, lng, options) => | ||||
|           prettyBytes(parseFloat(value), { locale: lng, ...options }) | ||||
|         ); | ||||
| 
 | ||||
|         i18next.services.formatter.add("rate", (value, lng, options) => { | ||||
|           if (value === 0) return "0 Bps"; | ||||
| 
 | ||||
|           const bits = options.bits ? value : value / 8; | ||||
|           const k = 1024; | ||||
|           const dm = options.decimals ? options.decimals : 0; | ||||
|           const sizes = ["Bps", "Kbps", "Mbps", "Gbps", "Tbps", "Pbps", "Ebps", "Zbps", "Ybps"]; | ||||
| 
 | ||||
|           const i = Math.floor(Math.log(bits) / Math.log(k)); | ||||
| 
 | ||||
|           const formatted = new Intl.NumberFormat(lng, { maximumFractionDigits: dm, minimumFractionDigits: dm }).format( | ||||
|             parseFloat(bits / k ** i) | ||||
|           ); | ||||
| 
 | ||||
|           return `${formatted} ${sizes[i]}`; | ||||
|         }); | ||||
| 
 | ||||
|         i18next.services.formatter.add("percent", (value, lng, options) => | ||||
|           new Intl.NumberFormat(lng, { style: "percent", ...options }).format(parseFloat(value) / 100.0) | ||||
|         ); | ||||
|       }, | ||||
|       type: "3rdParty", | ||||
|     }, | ||||
|   ], | ||||
| }; | ||||
| @ -1,3 +1,5 @@ | ||||
| const { i18n } = require("./next-i18next.config"); | ||||
| 
 | ||||
| /** @type {import('next').NextConfig} */ | ||||
| const nextConfig = { | ||||
|   reactStrictMode: true, | ||||
| @ -7,6 +9,7 @@ const nextConfig = { | ||||
|     domains: ["cdn.jsdelivr.net"], | ||||
|     unoptimized: true, | ||||
|   }, | ||||
|   i18n, | ||||
| }; | ||||
| 
 | ||||
| module.exports = nextConfig; | ||||
|  | ||||
| @ -15,20 +15,19 @@ | ||||
|     "compare-versions": "^5.0.1", | ||||
|     "dockerode": "^3.3.4", | ||||
|     "follow-redirects": "^1.15.2", | ||||
|     "i18next-browser-languagedetector": "^6.1.5", | ||||
|     "i18next-http-backend": "^1.4.4", | ||||
|     "i18next": "^21.9.2", | ||||
|     "js-yaml": "^4.1.0", | ||||
|     "json-rpc-2.0": "^1.4.1", | ||||
|     "memory-cache": "^0.2.0", | ||||
|     "next": "^12.3.1", | ||||
|     "next-i18next": "^12.0.1", | ||||
|     "node-os-utils": "^1.3.7", | ||||
|     "pretty-bytes": "^6.0.0", | ||||
|     "raw-body": "^2.5.1", | ||||
|     "react": "^18.2.0", | ||||
|     "react-dom": "^18.2.0", | ||||
|     "react-i18next": "^11.18.6", | ||||
|     "react-icons": "^4.4.0", | ||||
|     "react": "^18.2.0", | ||||
|     "rutorrent-promise": "^2.0.0", | ||||
|     "shvl": "^3.0.0", | ||||
|     "swr": "^1.3.0", | ||||
| @ -38,15 +37,15 @@ | ||||
|   "devDependencies": { | ||||
|     "@tailwindcss/forms": "^0.5.3", | ||||
|     "autoprefixer": "^10.4.12", | ||||
|     "eslint": "^8.24.0", | ||||
|     "eslint-config-airbnb": "^19.0.4", | ||||
|     "eslint-config-next": "^12.3.1", | ||||
|     "eslint-config-prettier": "^8.5.0", | ||||
|     "eslint-plugin-import": "^2.26.0", | ||||
|     "eslint-plugin-jsx-a11y": "^6.6.1", | ||||
|     "eslint-plugin-prettier": "^4.2.1", | ||||
|     "eslint-plugin-react-hooks": "^4.6.0", | ||||
|     "eslint-plugin-react": "^7.31.8", | ||||
|     "eslint": "^8.24.0", | ||||
|     "eslint-plugin-react-hooks": "^4.6.0", | ||||
|     "postcss": "^8.4.16", | ||||
|     "prettier": "^2.7.1", | ||||
|     "tailwind-scrollbar": "^2.0.1", | ||||
|  | ||||
							
								
								
									
										88
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										88
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @ -18,12 +18,11 @@ specifiers: | ||||
|   eslint-plugin-react-hooks: ^4.6.0 | ||||
|   follow-redirects: ^1.15.2 | ||||
|   i18next: ^21.9.2 | ||||
|   i18next-browser-languagedetector: ^6.1.5 | ||||
|   i18next-http-backend: ^1.4.4 | ||||
|   js-yaml: ^4.1.0 | ||||
|   json-rpc-2.0: ^1.4.1 | ||||
|   memory-cache: ^0.2.0 | ||||
|   next: ^12.3.1 | ||||
|   next-i18next: ^12.0.1 | ||||
|   node-os-utils: ^1.3.7 | ||||
|   postcss: ^8.4.16 | ||||
|   prettier: ^2.7.1 | ||||
| @ -49,12 +48,11 @@ dependencies: | ||||
|   dockerode: 3.3.4 | ||||
|   follow-redirects: 1.15.2 | ||||
|   i18next: 21.9.2 | ||||
|   i18next-browser-languagedetector: 6.1.5 | ||||
|   i18next-http-backend: 1.4.4 | ||||
|   js-yaml: 4.1.0 | ||||
|   json-rpc-2.0: 1.4.1 | ||||
|   memory-cache: 0.2.0 | ||||
|   next: 12.3.1_biqbaboplfbrettd7655fr4n2y | ||||
|   next-i18next: 12.0.1_azq6kxkn3od7qdylwkyksrwopy | ||||
|   node-os-utils: 1.3.7 | ||||
|   pretty-bytes: 6.0.0 | ||||
|   raw-body: 2.5.1 | ||||
| @ -338,10 +336,33 @@ packages: | ||||
|       tailwindcss: 3.1.8_postcss@8.4.16 | ||||
|     dev: true | ||||
| 
 | ||||
|   /@types/hoist-non-react-statics/3.3.1: | ||||
|     resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==} | ||||
|     dependencies: | ||||
|       '@types/react': 18.0.21 | ||||
|       hoist-non-react-statics: 3.3.2 | ||||
|     dev: false | ||||
| 
 | ||||
|   /@types/json5/0.0.29: | ||||
|     resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} | ||||
|     dev: true | ||||
| 
 | ||||
|   /@types/prop-types/15.7.5: | ||||
|     resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} | ||||
|     dev: false | ||||
| 
 | ||||
|   /@types/react/18.0.21: | ||||
|     resolution: {integrity: sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==} | ||||
|     dependencies: | ||||
|       '@types/prop-types': 15.7.5 | ||||
|       '@types/scheduler': 0.16.2 | ||||
|       csstype: 3.1.1 | ||||
|     dev: false | ||||
| 
 | ||||
|   /@types/scheduler/0.16.2: | ||||
|     resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} | ||||
|     dev: false | ||||
| 
 | ||||
|   /@typescript-eslint/parser/5.38.0_7ilbxdl5iguzcjriqqcg2m5cku: | ||||
|     resolution: {integrity: sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==} | ||||
|     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} | ||||
| @ -746,6 +767,11 @@ packages: | ||||
|     requiresBuild: true | ||||
|     dev: true | ||||
| 
 | ||||
|   /core-js/3.25.2: | ||||
|     resolution: {integrity: sha512-YB4IAT1bjEfxTJ1XYy11hJAKskO+qmhuDBM8/guIfMz4JvdsAQAqvyb97zXX7JgSrfPLG5mRGFWJwJD39ruq2A==} | ||||
|     requiresBuild: true | ||||
|     dev: false | ||||
| 
 | ||||
|   /cpu-features/0.0.4: | ||||
|     resolution: {integrity: sha512-fKiZ/zp1mUwQbnzb9IghXtHtDoTMtNeb8oYGx6kX2SYfhnG0HNdBEBIzB9b5KlXu5DQPhfy3mInbBxFcgwAr3A==} | ||||
|     engines: {node: '>=10.0.0'} | ||||
| @ -756,14 +782,6 @@ packages: | ||||
|     dev: false | ||||
|     optional: true | ||||
| 
 | ||||
|   /cross-fetch/3.1.5: | ||||
|     resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==} | ||||
|     dependencies: | ||||
|       node-fetch: 2.6.7 | ||||
|     transitivePeerDependencies: | ||||
|       - encoding | ||||
|     dev: false | ||||
| 
 | ||||
|   /cross-spawn/7.0.3: | ||||
|     resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} | ||||
|     engines: {node: '>= 8'} | ||||
| @ -779,6 +797,10 @@ packages: | ||||
|     hasBin: true | ||||
|     dev: true | ||||
| 
 | ||||
|   /csstype/3.1.1: | ||||
|     resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} | ||||
|     dev: false | ||||
| 
 | ||||
|   /damerau-levenshtein/1.0.8: | ||||
|     resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} | ||||
|     dev: true | ||||
| @ -1613,6 +1635,12 @@ packages: | ||||
|       function-bind: 1.1.1 | ||||
|     dev: true | ||||
| 
 | ||||
|   /hoist-non-react-statics/3.3.2: | ||||
|     resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} | ||||
|     dependencies: | ||||
|       react-is: 16.13.1 | ||||
|     dev: false | ||||
| 
 | ||||
|   /html-parse-stringify/3.0.1: | ||||
|     resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} | ||||
|     dependencies: | ||||
| @ -1630,18 +1658,8 @@ packages: | ||||
|       toidentifier: 1.0.1 | ||||
|     dev: false | ||||
| 
 | ||||
|   /i18next-browser-languagedetector/6.1.5: | ||||
|     resolution: {integrity: sha512-11t7b39oKeZe4uyMxLSPnfw28BCPNLZgUk7zyufex0zKXZ+Bv+JnmJgoB+IfQLZwDt1d71PM8vwBX1NCgliY3g==} | ||||
|     dependencies: | ||||
|       '@babel/runtime': 7.19.0 | ||||
|     dev: false | ||||
| 
 | ||||
|   /i18next-http-backend/1.4.4: | ||||
|     resolution: {integrity: sha512-M4gLPe6JKZ2p1UmE6t4rzWV/sAxgrLThW7ztXAsTpFwFqXoyzhTzX8eYxVv9KjpCQh4K9nwxnEjEi+74C4Thbg==} | ||||
|     dependencies: | ||||
|       cross-fetch: 3.1.5 | ||||
|     transitivePeerDependencies: | ||||
|       - encoding | ||||
|   /i18next-fs-backend/1.1.5: | ||||
|     resolution: {integrity: sha512-raTel3EfshiUXxR0gvmIoqp75jhkj8+7R1LjB006VZKPTFBbXyx6TlUVhb8Z9+7ahgpFbcQg1QWVOdf/iNzI5A==} | ||||
|     dev: false | ||||
| 
 | ||||
|   /i18next/21.9.2: | ||||
| @ -1986,6 +2004,27 @@ packages: | ||||
|     resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} | ||||
|     dev: true | ||||
| 
 | ||||
|   /next-i18next/12.0.1_azq6kxkn3od7qdylwkyksrwopy: | ||||
|     resolution: {integrity: sha512-i1yLpOvokldjqnnkP4KfZtnbp2+DILlUvavzJ9rvCSu1Yk5w45IRAYrJfu20/0WDeWxea/ktYDmXw+z/2roo3g==} | ||||
|     engines: {node: '>=12'} | ||||
|     peerDependencies: | ||||
|       next: '>= 10.0.0' | ||||
|       react: '>= 16.8.0' | ||||
|     dependencies: | ||||
|       '@babel/runtime': 7.19.0 | ||||
|       '@types/hoist-non-react-statics': 3.3.1 | ||||
|       core-js: 3.25.2 | ||||
|       hoist-non-react-statics: 3.3.2 | ||||
|       i18next: 21.9.2 | ||||
|       i18next-fs-backend: 1.1.5 | ||||
|       next: 12.3.1_biqbaboplfbrettd7655fr4n2y | ||||
|       react: 18.2.0 | ||||
|       react-i18next: 11.18.6_ulhmqqxshznzmtuvahdi5nasbq | ||||
|     transitivePeerDependencies: | ||||
|       - react-dom | ||||
|       - react-native | ||||
|     dev: false | ||||
| 
 | ||||
|   /next/12.3.1_biqbaboplfbrettd7655fr4n2y: | ||||
|     resolution: {integrity: sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==} | ||||
|     engines: {node: '>=12.22.0'} | ||||
| @ -2393,7 +2432,6 @@ packages: | ||||
| 
 | ||||
|   /react-is/16.13.1: | ||||
|     resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} | ||||
|     dev: true | ||||
| 
 | ||||
|   /react/18.2.0: | ||||
|     resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import dynamic from "next/dynamic"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| const Sonarr = dynamic(() => import("./widgets/service/sonarr")); | ||||
| const Radarr = dynamic(() => import("./widgets/service/radarr")); | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useState } from "react"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| import classNames from "classnames"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| import { BsVolumeMuteFill, BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs"; | ||||
| import { MdOutlineSmartDisplay } from "react-icons/md"; | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,10 +1,9 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
| 
 | ||||
| import { formatApiUrl } from "utils/api-helpers"; | ||||
| 
 | ||||
| export default function Radarr({ service }) { | ||||
|   const { t } = useTranslation(); | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| /* eslint-disable camelcase */ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| import { BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs"; | ||||
| import { MdOutlineSmartDisplay, MdSmartDisplay } from "react-icons/md"; | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import useSWR from "swr"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Widget from "../widget"; | ||||
| import Block from "../block"; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| import useSWR from "swr"; | ||||
| import { compareVersions } from "compare-versions"; | ||||
| import { MdNewReleases } from "react-icons/md"; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { useState, useEffect } from "react"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| const textSizes = { | ||||
|   "4xl": "text-4xl", | ||||
|  | ||||
| @ -3,7 +3,7 @@ import { useState } from "react"; | ||||
| import { BiError } from "react-icons/bi"; | ||||
| import { WiCloudDown } from "react-icons/wi"; | ||||
| import { MdLocationDisabled, MdLocationSearching } from "react-icons/md"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Icon from "./icon"; | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import useSWR from "swr"; | ||||
| import { FiCpu } from "react-icons/fi"; | ||||
| import { BiError } from "react-icons/bi"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import UsageBar from "./usage-bar"; | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import useSWR from "swr"; | ||||
| import { FiHardDrive } from "react-icons/fi"; | ||||
| import { BiError } from "react-icons/bi"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import UsageBar from "./usage-bar"; | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import useSWR from "swr"; | ||||
| import { FaMemory } from "react-icons/fa"; | ||||
| import { BiError } from "react-icons/bi"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import UsageBar from "./usage-bar"; | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { useState } from "react"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| import { FiSearch } from "react-icons/fi"; | ||||
| import { SiDuckduckgo, SiMicrosoftbing, SiGoogle } from "react-icons/si"; | ||||
| 
 | ||||
|  | ||||
| @ -3,7 +3,7 @@ import { useState } from "react"; | ||||
| import { BiError } from "react-icons/bi"; | ||||
| import { WiCloudDown } from "react-icons/wi"; | ||||
| import { MdLocationDisabled, MdLocationSearching } from "react-icons/md"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import Icon from "./icon"; | ||||
| 
 | ||||
|  | ||||
| @ -1,11 +1,12 @@ | ||||
| /* eslint-disable react/jsx-props-no-spreading */ | ||||
| import { SWRConfig } from "swr"; | ||||
| import { appWithTranslation } from "next-i18next"; | ||||
| 
 | ||||
| import "styles/globals.css"; | ||||
| import "styles/theme.css"; | ||||
| import "styles/manrope.css"; | ||||
| import nextI18nextConfig from "../../next-i18next.config"; | ||||
| 
 | ||||
| import "utils/i18n"; | ||||
| import { ColorProvider } from "utils/color-context"; | ||||
| import { ThemeProvider } from "utils/theme-context"; | ||||
| import { SettingsProvider } from "utils/settings-context"; | ||||
| @ -28,4 +29,4 @@ function MyApp({ Component, pageProps }) { | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default MyApp; | ||||
| export default appWithTranslation(MyApp, nextI18nextConfig); | ||||
|  | ||||
| @ -2,9 +2,10 @@ | ||||
| import useSWR from "swr"; | ||||
| import Head from "next/head"; | ||||
| import dynamic from "next/dynamic"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { useTranslation } from "next-i18next"; | ||||
| import { useEffect, useContext } from "react"; | ||||
| import { BiError } from "react-icons/bi"; | ||||
| import { serverSideTranslations } from "next-i18next/serverSideTranslations"; | ||||
| 
 | ||||
| import ServicesGroup from "components/services/group"; | ||||
| import BookmarksGroup from "components/bookmarks/group"; | ||||
| @ -30,7 +31,7 @@ const Version = dynamic(() => import("components/version"), { | ||||
| 
 | ||||
| const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search", "datetime"]; | ||||
| 
 | ||||
| export function getStaticProps() { | ||||
| export async function getStaticProps() { | ||||
|   let logger; | ||||
|   try { | ||||
|     logger = createLogger("index"); | ||||
| @ -39,6 +40,7 @@ export function getStaticProps() { | ||||
|     return { | ||||
|       props: { | ||||
|         initialSettings: settings, | ||||
|         ...(await serverSideTranslations(settings.language ?? "en")), | ||||
|       }, | ||||
|     }; | ||||
|   } catch (e) { | ||||
| @ -48,6 +50,7 @@ export function getStaticProps() { | ||||
|     return { | ||||
|       props: { | ||||
|         initialSettings: {}, | ||||
|         ...(await serverSideTranslations("en")), | ||||
|       }, | ||||
|     }; | ||||
|   } | ||||
|  | ||||
| @ -1,50 +0,0 @@ | ||||
| import i18n from "i18next"; | ||||
| import { initReactI18next } from "react-i18next"; | ||||
| import Backend from "i18next-http-backend"; | ||||
| import LanguageDetector from "i18next-browser-languagedetector"; | ||||
| import prettyBytes from "pretty-bytes"; | ||||
| 
 | ||||
| i18n | ||||
|   .use(Backend) | ||||
|   .use(LanguageDetector) | ||||
|   .use(initReactI18next) | ||||
|   .init({ | ||||
|     fallbackLng: "en", | ||||
|     ns: ["common"], | ||||
|     // debug: process.env.NODE_ENV === "development",
 | ||||
|     defaultNS: "common", | ||||
|     nonExplicitSupportedLngs: true, | ||||
|     interpolation: { | ||||
|       escapeValue: false, | ||||
|     }, | ||||
|     backend: { | ||||
|       loadPath: "/locales/{{lng}}/{{ns}}.json", | ||||
|     }, | ||||
|   }); | ||||
| 
 | ||||
| i18n.services.formatter.add("bytes", (value, lng, options) => | ||||
|   prettyBytes(parseFloat(value), { locale: lng, ...options }) | ||||
| ); | ||||
| 
 | ||||
| i18n.services.formatter.add("rate", (value, lng, options) => { | ||||
|   if (value === 0) return "0 Bps"; | ||||
| 
 | ||||
|   const bits = options.bits ? value : value / 8; | ||||
|   const k = 1024; | ||||
|   const dm = options.decimals ? options.decimals : 0; | ||||
|   const sizes = ["Bps", "Kbps", "Mbps", "Gbps", "Tbps", "Pbps", "Ebps", "Zbps", "Ybps"]; | ||||
| 
 | ||||
|   const i = Math.floor(Math.log(bits) / Math.log(k)); | ||||
| 
 | ||||
|   const formatted = new Intl.NumberFormat(lng, { maximumFractionDigits: dm, minimumFractionDigits: dm }).format( | ||||
|     parseFloat(bits / k ** i) | ||||
|   ); | ||||
| 
 | ||||
|   return `${formatted} ${sizes[i]}`; | ||||
| }); | ||||
| 
 | ||||
| i18n.services.formatter.add("percent", (value, lng, options) => | ||||
|   new Intl.NumberFormat(lng, { style: "percent", ...options }).format(parseFloat(value) / 100.0) | ||||
| ); | ||||
| 
 | ||||
| export default i18n; | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Ben Phelps
						Ben Phelps