refactor i18n to be server side

pull/302/head
Ben Phelps 2 years ago
parent 3ae4113043
commit 8bc240b934

@ -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} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
reactStrictMode: true, reactStrictMode: true,
@ -7,6 +9,7 @@ const nextConfig = {
domains: ["cdn.jsdelivr.net"], domains: ["cdn.jsdelivr.net"],
unoptimized: true, unoptimized: true,
}, },
i18n,
}; };
module.exports = nextConfig; module.exports = nextConfig;

@ -15,20 +15,19 @@
"compare-versions": "^5.0.1", "compare-versions": "^5.0.1",
"dockerode": "^3.3.4", "dockerode": "^3.3.4",
"follow-redirects": "^1.15.2", "follow-redirects": "^1.15.2",
"i18next-browser-languagedetector": "^6.1.5",
"i18next-http-backend": "^1.4.4",
"i18next": "^21.9.2", "i18next": "^21.9.2",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"json-rpc-2.0": "^1.4.1", "json-rpc-2.0": "^1.4.1",
"memory-cache": "^0.2.0", "memory-cache": "^0.2.0",
"next": "^12.3.1", "next": "^12.3.1",
"next-i18next": "^12.0.1",
"node-os-utils": "^1.3.7", "node-os-utils": "^1.3.7",
"pretty-bytes": "^6.0.0", "pretty-bytes": "^6.0.0",
"raw-body": "^2.5.1", "raw-body": "^2.5.1",
"react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-i18next": "^11.18.6", "react-i18next": "^11.18.6",
"react-icons": "^4.4.0", "react-icons": "^4.4.0",
"react": "^18.2.0",
"rutorrent-promise": "^2.0.0", "rutorrent-promise": "^2.0.0",
"shvl": "^3.0.0", "shvl": "^3.0.0",
"swr": "^1.3.0", "swr": "^1.3.0",
@ -38,15 +37,15 @@
"devDependencies": { "devDependencies": {
"@tailwindcss/forms": "^0.5.3", "@tailwindcss/forms": "^0.5.3",
"autoprefixer": "^10.4.12", "autoprefixer": "^10.4.12",
"eslint": "^8.24.0",
"eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb": "^19.0.4",
"eslint-config-next": "^12.3.1", "eslint-config-next": "^12.3.1",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react": "^7.31.8", "eslint-plugin-react": "^7.31.8",
"eslint": "^8.24.0", "eslint-plugin-react-hooks": "^4.6.0",
"postcss": "^8.4.16", "postcss": "^8.4.16",
"prettier": "^2.7.1", "prettier": "^2.7.1",
"tailwind-scrollbar": "^2.0.1", "tailwind-scrollbar": "^2.0.1",

@ -18,12 +18,11 @@ specifiers:
eslint-plugin-react-hooks: ^4.6.0 eslint-plugin-react-hooks: ^4.6.0
follow-redirects: ^1.15.2 follow-redirects: ^1.15.2
i18next: ^21.9.2 i18next: ^21.9.2
i18next-browser-languagedetector: ^6.1.5
i18next-http-backend: ^1.4.4
js-yaml: ^4.1.0 js-yaml: ^4.1.0
json-rpc-2.0: ^1.4.1 json-rpc-2.0: ^1.4.1
memory-cache: ^0.2.0 memory-cache: ^0.2.0
next: ^12.3.1 next: ^12.3.1
next-i18next: ^12.0.1
node-os-utils: ^1.3.7 node-os-utils: ^1.3.7
postcss: ^8.4.16 postcss: ^8.4.16
prettier: ^2.7.1 prettier: ^2.7.1
@ -49,12 +48,11 @@ dependencies:
dockerode: 3.3.4 dockerode: 3.3.4
follow-redirects: 1.15.2 follow-redirects: 1.15.2
i18next: 21.9.2 i18next: 21.9.2
i18next-browser-languagedetector: 6.1.5
i18next-http-backend: 1.4.4
js-yaml: 4.1.0 js-yaml: 4.1.0
json-rpc-2.0: 1.4.1 json-rpc-2.0: 1.4.1
memory-cache: 0.2.0 memory-cache: 0.2.0
next: 12.3.1_biqbaboplfbrettd7655fr4n2y next: 12.3.1_biqbaboplfbrettd7655fr4n2y
next-i18next: 12.0.1_azq6kxkn3od7qdylwkyksrwopy
node-os-utils: 1.3.7 node-os-utils: 1.3.7
pretty-bytes: 6.0.0 pretty-bytes: 6.0.0
raw-body: 2.5.1 raw-body: 2.5.1
@ -338,10 +336,33 @@ packages:
tailwindcss: 3.1.8_postcss@8.4.16 tailwindcss: 3.1.8_postcss@8.4.16
dev: true 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: /@types/json5/0.0.29:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true 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: /@typescript-eslint/parser/5.38.0_7ilbxdl5iguzcjriqqcg2m5cku:
resolution: {integrity: sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==} resolution: {integrity: sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -746,6 +767,11 @@ packages:
requiresBuild: true requiresBuild: true
dev: true dev: true
/core-js/3.25.2:
resolution: {integrity: sha512-YB4IAT1bjEfxTJ1XYy11hJAKskO+qmhuDBM8/guIfMz4JvdsAQAqvyb97zXX7JgSrfPLG5mRGFWJwJD39ruq2A==}
requiresBuild: true
dev: false
/cpu-features/0.0.4: /cpu-features/0.0.4:
resolution: {integrity: sha512-fKiZ/zp1mUwQbnzb9IghXtHtDoTMtNeb8oYGx6kX2SYfhnG0HNdBEBIzB9b5KlXu5DQPhfy3mInbBxFcgwAr3A==} resolution: {integrity: sha512-fKiZ/zp1mUwQbnzb9IghXtHtDoTMtNeb8oYGx6kX2SYfhnG0HNdBEBIzB9b5KlXu5DQPhfy3mInbBxFcgwAr3A==}
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
@ -756,14 +782,6 @@ packages:
dev: false dev: false
optional: true 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: /cross-spawn/7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@ -779,6 +797,10 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/csstype/3.1.1:
resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
dev: false
/damerau-levenshtein/1.0.8: /damerau-levenshtein/1.0.8:
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
dev: true dev: true
@ -1613,6 +1635,12 @@ packages:
function-bind: 1.1.1 function-bind: 1.1.1
dev: true 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: /html-parse-stringify/3.0.1:
resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
dependencies: dependencies:
@ -1630,18 +1658,8 @@ packages:
toidentifier: 1.0.1 toidentifier: 1.0.1
dev: false dev: false
/i18next-browser-languagedetector/6.1.5: /i18next-fs-backend/1.1.5:
resolution: {integrity: sha512-11t7b39oKeZe4uyMxLSPnfw28BCPNLZgUk7zyufex0zKXZ+Bv+JnmJgoB+IfQLZwDt1d71PM8vwBX1NCgliY3g==} resolution: {integrity: sha512-raTel3EfshiUXxR0gvmIoqp75jhkj8+7R1LjB006VZKPTFBbXyx6TlUVhb8Z9+7ahgpFbcQg1QWVOdf/iNzI5A==}
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
dev: false dev: false
/i18next/21.9.2: /i18next/21.9.2:
@ -1986,6 +2004,27 @@ packages:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true 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: /next/12.3.1_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==} resolution: {integrity: sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==}
engines: {node: '>=12.22.0'} engines: {node: '>=12.22.0'}
@ -2393,7 +2432,6 @@ packages:
/react-is/16.13.1: /react-is/16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
dev: true
/react/18.2.0: /react/18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { useTranslation } from "next-i18next";
const Sonarr = dynamic(() => import("./widgets/service/sonarr")); const Sonarr = dynamic(() => import("./widgets/service/sonarr"));
const Radarr = dynamic(() => import("./widgets/service/radarr")); const Radarr = dynamic(() => import("./widgets/service/radarr"));

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,6 +1,6 @@
import useSWR from "swr"; import useSWR from "swr";
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import classNames from "classnames"; import classNames from "classnames";
import Widget from "../widget"; import Widget from "../widget";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; 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 { BsVolumeMuteFill, BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs";
import { MdOutlineSmartDisplay } from "react-icons/md"; import { MdOutlineSmartDisplay } from "react-icons/md";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,10 +1,9 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";
import { formatApiUrl } from "utils/api-helpers";
export default function Radarr({ service }) { export default function Radarr({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,6 +1,6 @@
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import { BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs"; import { BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs";
import { MdOutlineSmartDisplay, MdSmartDisplay } from "react-icons/md"; import { MdOutlineSmartDisplay, MdSmartDisplay } from "react-icons/md";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,5 +1,5 @@
import useSWR from "swr"; import useSWR from "swr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Widget from "../widget"; import Widget from "../widget";
import Block from "../block"; import Block from "../block";

@ -1,4 +1,4 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import useSWR from "swr"; import useSWR from "swr";
import { compareVersions } from "compare-versions"; import { compareVersions } from "compare-versions";
import { MdNewReleases } from "react-icons/md"; import { MdNewReleases } from "react-icons/md";

@ -1,5 +1,5 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
const textSizes = { const textSizes = {
"4xl": "text-4xl", "4xl": "text-4xl",

@ -3,7 +3,7 @@ import { useState } from "react";
import { BiError } from "react-icons/bi"; import { BiError } from "react-icons/bi";
import { WiCloudDown } from "react-icons/wi"; import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md"; import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Icon from "./icon"; import Icon from "./icon";

@ -1,7 +1,7 @@
import useSWR from "swr"; import useSWR from "swr";
import { FiCpu } from "react-icons/fi"; import { FiCpu } from "react-icons/fi";
import { BiError } from "react-icons/bi"; import { BiError } from "react-icons/bi";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import UsageBar from "./usage-bar"; import UsageBar from "./usage-bar";

@ -1,7 +1,7 @@
import useSWR from "swr"; import useSWR from "swr";
import { FiHardDrive } from "react-icons/fi"; import { FiHardDrive } from "react-icons/fi";
import { BiError } from "react-icons/bi"; import { BiError } from "react-icons/bi";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import UsageBar from "./usage-bar"; import UsageBar from "./usage-bar";

@ -1,7 +1,7 @@
import useSWR from "swr"; import useSWR from "swr";
import { FaMemory } from "react-icons/fa"; import { FaMemory } from "react-icons/fa";
import { BiError } from "react-icons/bi"; import { BiError } from "react-icons/bi";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import UsageBar from "./usage-bar"; import UsageBar from "./usage-bar";

@ -1,5 +1,5 @@
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import { FiSearch } from "react-icons/fi"; import { FiSearch } from "react-icons/fi";
import { SiDuckduckgo, SiMicrosoftbing, SiGoogle } from "react-icons/si"; import { SiDuckduckgo, SiMicrosoftbing, SiGoogle } from "react-icons/si";

@ -3,7 +3,7 @@ import { useState } from "react";
import { BiError } from "react-icons/bi"; import { BiError } from "react-icons/bi";
import { WiCloudDown } from "react-icons/wi"; import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md"; import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import Icon from "./icon"; import Icon from "./icon";

@ -1,11 +1,12 @@
/* eslint-disable react/jsx-props-no-spreading */ /* eslint-disable react/jsx-props-no-spreading */
import { SWRConfig } from "swr"; import { SWRConfig } from "swr";
import { appWithTranslation } from "next-i18next";
import "styles/globals.css"; import "styles/globals.css";
import "styles/theme.css"; import "styles/theme.css";
import "styles/manrope.css"; import "styles/manrope.css";
import nextI18nextConfig from "../../next-i18next.config";
import "utils/i18n";
import { ColorProvider } from "utils/color-context"; import { ColorProvider } from "utils/color-context";
import { ThemeProvider } from "utils/theme-context"; import { ThemeProvider } from "utils/theme-context";
import { SettingsProvider } from "utils/settings-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 useSWR from "swr";
import Head from "next/head"; import Head from "next/head";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { useTranslation } from "react-i18next"; import { useTranslation } from "next-i18next";
import { useEffect, useContext } from "react"; import { useEffect, useContext } from "react";
import { BiError } from "react-icons/bi"; import { BiError } from "react-icons/bi";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import ServicesGroup from "components/services/group"; import ServicesGroup from "components/services/group";
import BookmarksGroup from "components/bookmarks/group"; import BookmarksGroup from "components/bookmarks/group";
@ -30,7 +31,7 @@ const Version = dynamic(() => import("components/version"), {
const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search", "datetime"]; const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search", "datetime"];
export function getStaticProps() { export async function getStaticProps() {
let logger; let logger;
try { try {
logger = createLogger("index"); logger = createLogger("index");
@ -39,6 +40,7 @@ export function getStaticProps() {
return { return {
props: { props: {
initialSettings: settings, initialSettings: settings,
...(await serverSideTranslations(settings.language ?? "en")),
}, },
}; };
} catch (e) { } catch (e) {
@ -48,6 +50,7 @@ export function getStaticProps() {
return { return {
props: { props: {
initialSettings: {}, 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…
Cancel
Save