diff --git a/components/search.tsx b/components/search.tsx index 8c4bbe8..fc14012 100644 --- a/components/search.tsx +++ b/components/search.tsx @@ -5,9 +5,11 @@ import { queryAtom } from "lib/state/query"; import { selectedSuggestionAtom } from "lib/state/suggestionSelection"; import handleEnter from "lib/onesearch/handleEnter"; import { suggestionAtom } from "lib/state/suggestion"; +import { useTranslation } from "react-i18next"; export default function Search(props: { onFocus: () => void }) { + const { t } = useTranslation(); const settings = useAtomValue(settingsAtom); const [query, setQuery] = useAtom(queryAtom); const [selectedSuggestion, setSelected] = useAtom(selectedSuggestionAtom); @@ -43,7 +45,7 @@ export default function Search(props: { onFocus: () => void }) { dark:placeholder:text-slate-400 text-slate-900 dark:text-white" id="searchBox" type="text" - placeholder="placeholder" + placeholder={t('search.placeholder')} onFocus={props.onFocus} onKeyDown={handleKeydown} onChange={(e) => diff --git a/components/time.tsx b/components/time.tsx index fb3f9c0..c33a6b1 100644 --- a/components/time.tsx +++ b/components/time.tsx @@ -38,7 +38,9 @@ export default function Time(props: { {formatTime()}{" "} {new Intl.DateTimeFormat(navigator.language, { - dateStyle: "medium" + year: "numeric", + month: "short", + day: "numeric" }).format(currentTime)} diff --git a/i18n/ar.json b/i18n/ar.json new file mode 100755 index 0000000..0d329a3 --- /dev/null +++ b/i18n/ar.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "ابحث أو اكتب عنوان URL" + } +} \ No newline at end of file diff --git a/i18n/de.json b/i18n/de.json new file mode 100755 index 0000000..47a7c7e --- /dev/null +++ b/i18n/de.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "Suche oder gib eine URL ein" + } +} \ No newline at end of file diff --git a/i18n/en.json b/i18n/en.json new file mode 100755 index 0000000..b03c753 --- /dev/null +++ b/i18n/en.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "Search or type a URL" + } +} \ No newline at end of file diff --git a/i18n/es.json b/i18n/es.json new file mode 100755 index 0000000..c79c404 --- /dev/null +++ b/i18n/es.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "Buscar o escribir una URL" + } +} \ No newline at end of file diff --git a/i18n/fr.json b/i18n/fr.json new file mode 100755 index 0000000..d9f6e0b --- /dev/null +++ b/i18n/fr.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "Rechercher ou saisir une URL" + } +} \ No newline at end of file diff --git a/i18n/it.json b/i18n/it.json new file mode 100755 index 0000000..23f0358 --- /dev/null +++ b/i18n/it.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "Cerca o digita un URL" + } +} \ No newline at end of file diff --git a/i18n/ja.json b/i18n/ja.json new file mode 100755 index 0000000..d3b3714 --- /dev/null +++ b/i18n/ja.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "検索またはURLを入力" + } +} \ No newline at end of file diff --git a/i18n/ko.json b/i18n/ko.json new file mode 100755 index 0000000..f93197a --- /dev/null +++ b/i18n/ko.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "검색 또는 URL 입력" + } +} \ No newline at end of file diff --git a/i18n/pt.json b/i18n/pt.json new file mode 100755 index 0000000..2fad8f3 --- /dev/null +++ b/i18n/pt.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "Pesquisar ou digitar uma URL" + } +} \ No newline at end of file diff --git a/i18n/ru.json b/i18n/ru.json new file mode 100755 index 0000000..b23cc86 --- /dev/null +++ b/i18n/ru.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "Искать или ввести URL" + } +} \ No newline at end of file diff --git a/i18n/zh.json b/i18n/zh.json new file mode 100755 index 0000000..0c7e1d4 --- /dev/null +++ b/i18n/zh.json @@ -0,0 +1,5 @@ +{ + "search" : { + "placeholder" : "搜索或输入网址" + } +} \ No newline at end of file diff --git a/package.json b/package.json index dd1c46c..56f1001 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sparkhome", "private": false, - "version": "5.0.0", + "version": "5.1.0", "type": "module", "scripts": { "dev": "vite", @@ -10,9 +10,13 @@ "preview": "vite preview" }, "dependencies": { + "i18next": "^23.11.5", + "i18next-browser-languagedetector": "^8.0.0", + "i18next-icu": "^2.3.0", "jotai": "^2.8.3", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-i18next": "^14.1.2", "react-router": "^6.23.1", "react-router-dom": "^6.23.1", "search-engine-autocomplete": "^0.4.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8eaf75d..1d1a8e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,15 @@ importers: .: dependencies: + i18next: + specifier: ^23.11.5 + version: 23.11.5 + i18next-browser-languagedetector: + specifier: ^8.0.0 + version: 8.0.0 + i18next-icu: + specifier: ^2.3.0 + version: 2.3.0(intl-messageformat@10.5.14) jotai: specifier: ^2.8.3 version: 2.8.3(@types/react@18.3.3)(react@18.3.1) @@ -17,9 +26,9 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) - react-intl: - specifier: ^6.6.8 - version: 6.6.8(react@18.3.1)(typescript@5.5.2) + react-i18next: + specifier: ^14.1.2 + version: 14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-router: specifier: ^6.23.1 version: 6.23.1(react@18.3.1) @@ -53,7 +62,7 @@ importers: version: 7.13.1(eslint@8.57.0)(typescript@5.5.2) '@vitejs/plugin-react-swc': specifier: ^3.5.0 - version: 3.7.0(vite@5.3.1) + version: 3.7.0(vite@5.3.1(@types/node@20.14.8)) autoprefixer: specifier: ^10.4.19 version: 10.4.19(postcss@8.4.38) @@ -77,13 +86,13 @@ importers: version: 5.5.2 vite: specifier: ^5.3.1 - version: 5.3.1 + version: 5.3.1(@types/node@20.14.8) vite-plugin-pages: specifier: ^0.32.2 - version: 0.32.2(react-router@6.23.1(react@18.3.1))(vite@5.3.1) + version: 0.32.2(react-router@6.23.1(react@18.3.1))(vite@5.3.1(@types/node@20.14.8)) vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.5.2)(vite@5.3.1) + version: 4.3.2(typescript@5.5.2)(vite@5.3.1(@types/node@20.14.8)) packages: @@ -91,6 +100,10 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@babel/runtime@7.24.7': + resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} + engines: {node: '>=6.9.0'} + '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -259,23 +272,9 @@ packages: '@formatjs/icu-skeleton-parser@1.8.2': resolution: {integrity: sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==} - '@formatjs/intl-displaynames@6.6.8': - resolution: {integrity: sha512-Lgx6n5KxN16B3Pb05z3NLEBQkGoXnGjkTBNCZI+Cn17YjHJ3fhCeEJJUqRlIZmJdmaXQhjcQVDp6WIiNeRYT5g==} - - '@formatjs/intl-listformat@7.5.7': - resolution: {integrity: sha512-MG2TSChQJQT9f7Rlv+eXwUFiG24mKSzmF144PLb8m8OixyXqn4+YWU+5wZracZGCgVTVmx8viCf7IH3QXoiB2g==} - '@formatjs/intl-localematcher@0.5.4': resolution: {integrity: sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==} - '@formatjs/intl@2.10.4': - resolution: {integrity: sha512-56483O+HVcL0c7VucAS2tyH020mt9XTozZO67cwtGg0a7KWDukS/FzW3OnvaHmTHDuYsoPIzO+ZHVfU6fT/bJw==} - peerDependencies: - typescript: ^4.7 || 5 - peerDependenciesMeta: - typescript: - optional: true - '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -492,12 +491,12 @@ packages: '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - '@types/hoist-non-react-statics@3.3.5': - resolution: {integrity: sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==} - '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + '@types/node@20.14.8': + resolution: {integrity: sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA==} + '@types/prop-types@15.7.12': resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} @@ -965,8 +964,19 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + html-parse-stringify@3.0.1: + resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + + i18next-browser-languagedetector@8.0.0: + resolution: {integrity: sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==} + + i18next-icu@2.3.0: + resolution: {integrity: sha512-x+j7kd5nDJCfbU53uwsMfXD7ALPu5uv0bqjAMQ5nVvXRoj1L7gkmswKtM3XDWYo4YUHf1jznlhSdPyy0xEwU+Q==} + peerDependencies: + intl-messageformat: ^10.3.3 + + i18next@23.11.5: + resolution: {integrity: sha512-41pvpVbW9rhZPk5xjCX2TPJi2861LEig/YRhUkY+1FQ2IQPS0bKUDYnEqY8XPPbB48h1uIwLnP9iiEfuSl20CA==} ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} @@ -1367,17 +1377,18 @@ packages: peerDependencies: react: ^18.3.1 - react-intl@6.6.8: - resolution: {integrity: sha512-M0pkhzcgV31h++2901BiRXWl69hp2zPyLxRrSwRjd1ErXbNoubz/f4M6DrRTd4OiSUrT4ajRQzrmtS5plG4FtA==} + react-i18next@14.1.2: + resolution: {integrity: sha512-FSIcJy6oauJbGEXfhUgVeLzvWBhIBIS+/9c6Lj4niwKZyGaGb4V4vUbATXSlsHJDXXB+ociNxqFNiFuV1gmoqg==} peerDependencies: - react: ^16.6.0 || 17 || 18 - typescript: ^4.7 || 5 + i18next: '>= 23.2.3' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' peerDependenciesMeta: - typescript: + react-dom: + optional: true + react-native: optional: true - - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} react-router-dom@6.23.1: resolution: {integrity: sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==} @@ -1403,6 +1414,9 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + regexp.prototype.flags@1.5.2: resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} engines: {node: '>= 0.4'} @@ -1569,6 +1583,9 @@ packages: ufo@1.5.3: resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + update-browserslist-db@1.0.16: resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} hasBin: true @@ -1641,6 +1658,10 @@ packages: terser: optional: true + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} @@ -1685,6 +1706,10 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@babel/runtime@7.24.7': + dependencies: + regenerator-runtime: 0.14.1 + '@esbuild/aix-ppc64@0.21.5': optional: true @@ -1797,34 +1822,10 @@ snapshots: '@formatjs/ecma402-abstract': 2.0.0 tslib: 2.6.3 - '@formatjs/intl-displaynames@6.6.8': - dependencies: - '@formatjs/ecma402-abstract': 2.0.0 - '@formatjs/intl-localematcher': 0.5.4 - tslib: 2.6.3 - - '@formatjs/intl-listformat@7.5.7': - dependencies: - '@formatjs/ecma402-abstract': 2.0.0 - '@formatjs/intl-localematcher': 0.5.4 - tslib: 2.6.3 - '@formatjs/intl-localematcher@0.5.4': dependencies: tslib: 2.6.3 - '@formatjs/intl@2.10.4(typescript@5.5.2)': - dependencies: - '@formatjs/ecma402-abstract': 2.0.0 - '@formatjs/fast-memoize': 2.2.0 - '@formatjs/icu-messageformat-parser': 2.7.8 - '@formatjs/intl-displaynames': 6.6.8 - '@formatjs/intl-listformat': 7.5.7 - intl-messageformat: 10.5.14 - tslib: 2.6.3 - optionalDependencies: - typescript: 5.5.2 - '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -1986,13 +1987,13 @@ snapshots: '@types/estree@1.0.5': {} - '@types/hoist-non-react-statics@3.3.5': - dependencies: - '@types/react': 18.3.3 - hoist-non-react-statics: 3.3.2 - '@types/ms@0.7.34': {} + '@types/node@20.14.8': + dependencies: + undici-types: 5.26.5 + optional: true + '@types/prop-types@15.7.12': {} '@types/react-dom@18.3.0': @@ -2089,10 +2090,10 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-react-swc@3.7.0(vite@5.3.1)': + '@vitejs/plugin-react-swc@3.7.0(vite@5.3.1(@types/node@20.14.8))': dependencies: '@swc/core': 1.6.5 - vite: 5.3.1 + vite: 5.3.1(@types/node@20.14.8) transitivePeerDependencies: - '@swc/helpers' @@ -2556,9 +2557,21 @@ snapshots: dependencies: function-bind: 1.1.2 - hoist-non-react-statics@3.3.2: + html-parse-stringify@3.0.1: dependencies: - react-is: 16.13.1 + void-elements: 3.1.0 + + i18next-browser-languagedetector@8.0.0: + dependencies: + '@babel/runtime': 7.24.7 + + i18next-icu@2.3.0(intl-messageformat@10.5.14): + dependencies: + intl-messageformat: 10.5.14 + + i18next@23.11.5: + dependencies: + '@babel/runtime': 7.24.7 ignore@5.3.1: {} @@ -2902,23 +2915,14 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 - react-intl@6.6.8(react@18.3.1)(typescript@5.5.2): + react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@formatjs/ecma402-abstract': 2.0.0 - '@formatjs/icu-messageformat-parser': 2.7.8 - '@formatjs/intl': 2.10.4(typescript@5.5.2) - '@formatjs/intl-displaynames': 6.6.8 - '@formatjs/intl-listformat': 7.5.7 - '@types/hoist-non-react-statics': 3.3.5 - '@types/react': 18.3.3 - hoist-non-react-statics: 3.3.2 - intl-messageformat: 10.5.14 + '@babel/runtime': 7.24.7 + html-parse-stringify: 3.0.1 + i18next: 23.11.5 react: 18.3.1 - tslib: 2.6.3 optionalDependencies: - typescript: 5.5.2 - - react-is@16.13.1: {} + react-dom: 18.3.1(react@18.3.1) react-router-dom@6.23.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -2944,6 +2948,8 @@ snapshots: dependencies: picomatch: 2.3.1 + regenerator-runtime@0.14.1: {} + regexp.prototype.flags@1.5.2: dependencies: call-bind: 1.0.7 @@ -3139,6 +3145,9 @@ snapshots: ufo@1.5.3: {} + undici-types@5.26.5: + optional: true + update-browserslist-db@1.0.16(browserslist@4.23.1): dependencies: browserslist: 4.23.1 @@ -3155,7 +3164,7 @@ snapshots: validate-color@2.2.4: {} - vite-plugin-pages@0.32.2(react-router@6.23.1(react@18.3.1))(vite@5.3.1): + vite-plugin-pages@0.32.2(react-router@6.23.1(react@18.3.1))(vite@5.3.1(@types/node@20.14.8)): dependencies: '@types/debug': 4.1.12 debug: 4.3.5 @@ -3165,32 +3174,35 @@ snapshots: json5: 2.2.3 local-pkg: 0.5.0 picocolors: 1.0.1 - vite: 5.3.1 + vite: 5.3.1(@types/node@20.14.8) yaml: 2.4.5 optionalDependencies: react-router: 6.23.1(react@18.3.1) transitivePeerDependencies: - supports-color - vite-tsconfig-paths@4.3.2(typescript@5.5.2)(vite@5.3.1): + vite-tsconfig-paths@4.3.2(typescript@5.5.2)(vite@5.3.1(@types/node@20.14.8)): dependencies: debug: 4.3.5 globrex: 0.1.2 tsconfck: 3.1.0(typescript@5.5.2) optionalDependencies: - vite: 5.3.1 + vite: 5.3.1(@types/node@20.14.8) transitivePeerDependencies: - supports-color - typescript - vite@5.3.1: + vite@5.3.1(@types/node@20.14.8): dependencies: esbuild: 0.21.5 postcss: 8.4.38 rollup: 4.18.0 optionalDependencies: + '@types/node': 20.14.8 fsevents: 2.3.3 + void-elements@3.1.0: {} + which-boxed-primitive@1.0.2: dependencies: is-bigint: 1.0.4 diff --git a/src/app.tsx b/src/app.tsx index bec4ca9..ce118cb 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,11 +1,74 @@ import { Suspense } from "react"; import { useRoutes } from "react-router-dom"; import routes from "~react-pages"; +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; +import LanguageDetector from 'i18next-browser-languagedetector'; +import ICU from 'i18next-icu'; +import * as en from "i18n/en.json" +import * as zh from "i18n/zh.json" +import * as ja from "i18n/ja.json" +import * as ar from "i18n/ar.json" +import * as de from "i18n/de.json" +import * as es from "i18n/es.json" +import * as fr from "i18n/fr.json" +import * as it from "i18n/it.json" +import * as ko from "i18n/ko.json" +import * as pt from "i18n/pt.json" +import * as ru from "i18n/ru.json" + +i18n.use(initReactI18next) // passes i18n down to react-i18next + .use(LanguageDetector) + .use(ICU) + .init({ + resources: { + en: { + translation: en + }, + zh: { + translation: zh + }, + ja: { + translation: ja + }, + ar: { + translation: ar + }, + de: { + translation: de + }, + es: { + translation: es + }, + fr: { + translation: fr + }, + it: { + translation: it + }, + ko: { + translation: ko + }, + pt: { + translation: pt + }, + ru: { + translation: ru + } + }, + fallbackLng: "en", + + interpolation: { + escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape + }, + + detection: { + order: ['navigator'], + caches: [] + } + }); + export function App() { - return ( - Loading...

}> - {useRoutes(routes)} -
- ) -} \ No newline at end of file + return Loading...

}>{useRoutes(routes)}
; +}