From 80089843a3ba98d15e5ac3078a8fce5adc22ddda Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 17:55:51 -0800 Subject: [PATCH 01/34] Install and setup i18n packages --- next-i18next.config.js | 6 + next.config.js | 2 + package-lock.json | 1271 +++++++++++++++++++++++++++++++++++++++- package.json | 7 +- 4 files changed, 1264 insertions(+), 22 deletions(-) create mode 100644 next-i18next.config.js diff --git a/next-i18next.config.js b/next-i18next.config.js new file mode 100644 index 00000000..59c3d0d6 --- /dev/null +++ b/next-i18next.config.js @@ -0,0 +1,6 @@ +module.exports = { + i18n: { + defaultLocale: 'ja', + locales: ['en', 'ja'], + } +} \ No newline at end of file diff --git a/next.config.js b/next.config.js index fc60c38f..e6b6c5e2 100644 --- a/next.config.js +++ b/next.config.js @@ -1,5 +1,6 @@ /** @type {import('next').NextConfig} */ const path = require('path') +const { i18n } = require('./next-i18next.config') module.exports = { reactStrictMode: true, @@ -7,6 +8,7 @@ module.exports = { prependData: '@import "variables";', includePaths: [path.join(__dirname, 'styles')], }, + i18n, async rewrites() { return [ { diff --git a/package-lock.json b/package-lock.json index 6d821eb4..f38ea343 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,14 +17,19 @@ "@types/axios": "^0.14.0", "axios": "^0.25.0", "classnames": "^2.3.1", + "i18next": "^21.6.13", + "i18next-browser-languagedetector": "^6.1.3", + "i18next-http-backend": "^1.3.2", "lodash.clonedeep": "^4.5.0", "lodash.debounce": "^4.0.8", "meyer-reset-scss": "^2.0.4", "next": "12.0.8", + "next-i18next": "^10.5.0", + "next-remote-watch": "^1.0.0", "react": "17.0.2", "react-cookie": "^4.1.1", "react-dom": "^17.0.2", - "react-i18next": "^11.15.3", + "react-i18next": "^11.15.5", "react-linkify": "^1.0.0-alpha", "react-scroll": "^1.8.5", "sass": "^1.49.0", @@ -3495,6 +3500,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -3594,6 +3611,11 @@ "node": ">=6.0" } }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, "node_modules/array-includes": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", @@ -3751,6 +3773,39 @@ "node": ">=8" } }, + "node_modules/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -3799,6 +3854,14 @@ "url": "https://opencollective.com/browserslist" } }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -3945,6 +4008,25 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", @@ -3959,13 +4041,28 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "engines": { "node": ">= 0.6" } }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/core-js": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", + "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-js-compat": { "version": "3.20.3", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.20.3.tgz", @@ -4013,6 +4110,33 @@ "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-fetch/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/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -4128,6 +4252,19 @@ "node": ">= 0.4" } }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -4216,6 +4353,11 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, "node_modules/electron-to-chromium": { "version": "1.4.52", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.52.tgz", @@ -4235,6 +4377,14 @@ "node": ">= 0.10" } }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", @@ -4313,6 +4463,11 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -4804,6 +4959,67 @@ "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4882,6 +5098,36 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -4932,6 +5178,22 @@ } } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -5147,15 +5409,75 @@ "void-elements": "3.1.0" } }, + "node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/i18next": { - "version": "21.6.7", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.7.tgz", - "integrity": "sha512-26dTDa2gBz+vMk6WPf1pxTx3S5HIAptbyODmni/JsN6R1W2WNkGVFXBusUK7T6y1wLeJi5CIrqmQ2gl18vdh3A==", - "peer": true, + "version": "21.6.13", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.13.tgz", + "integrity": "sha512-MVjNttw+5mIuu2/fwTpSU0EeI7iU/6pnDvGQboCzkILiv0/gD+FLZaF7qSHmUHO4ZkE6xJQ9SlBgGvMHxhC82Q==", + "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.12.0" } }, + "node_modules/i18next-browser-languagedetector": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.3.tgz", + "integrity": "sha512-T+oGXHXtrur14CGnZZ7qQ07X38XJQEI00b/4ILrtO6xPbwTlQ1wtMZC2H+tBULixHuVUXv8LKbxfjyITJkezUg==", + "dependencies": { + "@babel/runtime": "^7.14.6" + } + }, + "node_modules/i18next-fs-backend": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-1.1.4.tgz", + "integrity": "sha512-/MfAGMP0jHonV966uFf9PkWWuDjPYLIcsipnSO3NxpNtAgRUKLTwvm85fEmsF6hGeu0zbZiCQ3W74jwO6K9uXA==" + }, + "node_modules/i18next-http-backend": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-1.3.2.tgz", + "integrity": "sha512-SfcoUmsSWnc2LYsDsCq5TCg18cxJXvXymX9N37V+qqMKQY8Gf0rWkjOnRd20sMK633Dq4NF9tvqPbOiFJ49Kbw==", + "dependencies": { + "cross-fetch": "3.1.5" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -5231,6 +5553,14 @@ "loose-envify": "^1.0.0" } }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -5652,6 +5982,19 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5666,6 +6009,14 @@ "node": ">= 8" } }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/meyer-reset-scss": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/meyer-reset-scss/-/meyer-reset-scss-2.0.4.tgz", @@ -5684,6 +6035,36 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -5723,6 +6104,14 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/next": { "version": "12.0.8", "resolved": "https://registry.npmjs.org/next/-/next-12.0.8.tgz", @@ -5778,6 +6167,110 @@ } } }, + "node_modules/next-i18next": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-10.5.0.tgz", + "integrity": "sha512-+Xj/v5gqpEUBKKAaFCZ76+Ps6OGAaIgGowJTF67wTcmIQbHrcHMPjHwPTbnpXy7uHrH8os7i4eAfRENAv/6xwg==", + "dependencies": { + "@babel/runtime": "^7.13.17", + "@types/hoist-non-react-statics": "^3.3.1", + "core-js": "^3", + "hoist-non-react-statics": "^3.2.0", + "i18next": "^21.6.12", + "i18next-fs-backend": "^1.0.7", + "react-i18next": "^11.15.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/isaachinman" + }, + "peerDependencies": { + "next": ">= 10.0.0", + "react": ">= 16.8.0" + } + }, + "node_modules/next-remote-watch": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-remote-watch/-/next-remote-watch-1.0.0.tgz", + "integrity": "sha512-kV+pglCwcnKyqJIXPHUUrnZr9d3rCqCIEQWBkFYC02GDXHyKVmcFytoY6q0+wMIQqh/izIAQL1x6OKXZhksjLA==", + "dependencies": { + "body-parser": "^1.19.0", + "chalk": "^4.0.0", + "chokidar": "^3.4.0", + "commander": "^5.0.0", + "express": "^4.17.1" + }, + "bin": { + "next-remote-watch": "bin/next-remote-watch" + } + }, + "node_modules/next-remote-watch/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/next-remote-watch/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/next-remote-watch/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/next-remote-watch/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/next-remote-watch/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/next-remote-watch/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/node-fetch": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", @@ -5913,6 +6406,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -6000,6 +6504,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -6032,6 +6544,11 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -6097,6 +6614,18 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/proxy-compare": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.0.2.tgz", @@ -6111,6 +6640,17 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6131,6 +6671,28 @@ } ] }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", @@ -6170,9 +6732,9 @@ } }, "node_modules/react-i18next": { - "version": "11.15.3", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.15.3.tgz", - "integrity": "sha512-RSUEM4So3Tu2JHV0JsZ5Yje+4nz66YViMfPZoywxOy0xyn3L7tE2CHvJ7Y9LUsrTU7vGmZ5bwb8PpjnkatdIxg==", + "version": "11.15.5", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.15.5.tgz", + "integrity": "sha512-vBWuVEQgrhZrGKpyv8FmJ7Zs5jRQWl794Tte7yzJ0okZqqi3jd6j2pLYNg441WcREsbIOvWdiDXbY7W6E93p1A==", "dependencies": { "@babel/runtime": "^7.14.5", "html-escaper": "^2.0.2", @@ -6505,6 +7067,11 @@ } ] }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/sass": { "version": "1.49.0", "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.0.tgz", @@ -6538,6 +7105,66 @@ "semver": "bin/semver.js" } }, + "node_modules/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6603,6 +7230,14 @@ "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", @@ -6833,6 +7468,19 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, "node_modules/tsconfig-paths": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", @@ -6901,6 +7549,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typescript": { "version": "4.5.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", @@ -6979,6 +7639,14 @@ "cookie": "^0.4.0" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -7036,6 +7704,14 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -7073,6 +7749,14 @@ } } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -7081,6 +7765,20 @@ "node": ">=0.10.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9567,6 +10265,15 @@ "eslint-visitor-keys": "^3.0.0" } }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, "acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -9639,6 +10346,11 @@ "@babel/runtime-corejs3": "^7.10.2" } }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, "array-includes": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", @@ -9757,6 +10469,38 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, + "body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -9792,6 +10536,11 @@ "picocolors": "^1.0.0" } }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -9900,6 +10649,19 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, "convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", @@ -9916,9 +10678,19 @@ } }, "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-js": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", + "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==" }, "core-js-compat": { "version": "3.20.3", @@ -9954,6 +10726,24 @@ "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" + }, + "dependencies": { + "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" + } + } + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -10037,6 +10827,16 @@ "object-keys": "^1.0.12" } }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, "detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -10100,6 +10900,11 @@ "domhandler": "^4.2.0" } }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, "electron-to-chromium": { "version": "1.4.52", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.52.tgz", @@ -10116,6 +10921,11 @@ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, "entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", @@ -10173,6 +10983,11 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -10549,6 +11364,63 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -10617,6 +11489,35 @@ "to-regex-range": "^5.0.1" } }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -10647,6 +11548,16 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -10803,15 +11714,55 @@ "void-elements": "3.1.0" } }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, "i18next": { - "version": "21.6.7", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.7.tgz", - "integrity": "sha512-26dTDa2gBz+vMk6WPf1pxTx3S5HIAptbyODmni/JsN6R1W2WNkGVFXBusUK7T6y1wLeJi5CIrqmQ2gl18vdh3A==", - "peer": true, + "version": "21.6.13", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.13.tgz", + "integrity": "sha512-MVjNttw+5mIuu2/fwTpSU0EeI7iU/6pnDvGQboCzkILiv0/gD+FLZaF7qSHmUHO4ZkE6xJQ9SlBgGvMHxhC82Q==", "requires": { "@babel/runtime": "^7.12.0" } }, + "i18next-browser-languagedetector": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.3.tgz", + "integrity": "sha512-T+oGXHXtrur14CGnZZ7qQ07X38XJQEI00b/4ILrtO6xPbwTlQ1wtMZC2H+tBULixHuVUXv8LKbxfjyITJkezUg==", + "requires": { + "@babel/runtime": "^7.14.6" + } + }, + "i18next-fs-backend": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-1.1.4.tgz", + "integrity": "sha512-/MfAGMP0jHonV966uFf9PkWWuDjPYLIcsipnSO3NxpNtAgRUKLTwvm85fEmsF6hGeu0zbZiCQ3W74jwO6K9uXA==" + }, + "i18next-http-backend": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-1.3.2.tgz", + "integrity": "sha512-SfcoUmsSWnc2LYsDsCq5TCg18cxJXvXymX9N37V+qqMKQY8Gf0rWkjOnRd20sMK633Dq4NF9tvqPbOiFJ49Kbw==", + "requires": { + "cross-fetch": "3.1.5" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -10872,6 +11823,11 @@ "loose-envify": "^1.0.0" } }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -11184,6 +12140,16 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -11195,6 +12161,11 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, "meyer-reset-scss": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/meyer-reset-scss/-/meyer-reset-scss-2.0.4.tgz", @@ -11210,6 +12181,24 @@ "picomatch": "^2.2.3" } }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "requires": { + "mime-db": "1.51.0" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -11240,6 +12229,11 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, "next": { "version": "12.0.8", "resolved": "https://registry.npmjs.org/next/-/next-12.0.8.tgz", @@ -11269,6 +12263,77 @@ "use-subscription": "1.5.1" } }, + "next-i18next": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-10.5.0.tgz", + "integrity": "sha512-+Xj/v5gqpEUBKKAaFCZ76+Ps6OGAaIgGowJTF67wTcmIQbHrcHMPjHwPTbnpXy7uHrH8os7i4eAfRENAv/6xwg==", + "requires": { + "@babel/runtime": "^7.13.17", + "@types/hoist-non-react-statics": "^3.3.1", + "core-js": "^3", + "hoist-non-react-statics": "^3.2.0", + "i18next": "^21.6.12", + "i18next-fs-backend": "^1.0.7", + "react-i18next": "^11.15.5" + } + }, + "next-remote-watch": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-remote-watch/-/next-remote-watch-1.0.0.tgz", + "integrity": "sha512-kV+pglCwcnKyqJIXPHUUrnZr9d3rCqCIEQWBkFYC02GDXHyKVmcFytoY6q0+wMIQqh/izIAQL1x6OKXZhksjLA==", + "requires": { + "body-parser": "^1.19.0", + "chalk": "^4.0.0", + "chokidar": "^3.4.0", + "commander": "^5.0.0", + "express": "^4.17.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "node-fetch": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", @@ -11362,6 +12427,14 @@ "es-abstract": "^1.19.1" } }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -11428,6 +12501,11 @@ "lines-and-columns": "^1.1.6" } }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -11451,6 +12529,11 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -11499,6 +12582,15 @@ } } }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, "proxy-compare": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.0.2.tgz", @@ -11510,12 +12602,33 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "requires": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", @@ -11546,9 +12659,9 @@ } }, "react-i18next": { - "version": "11.15.3", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.15.3.tgz", - "integrity": "sha512-RSUEM4So3Tu2JHV0JsZ5Yje+4nz66YViMfPZoywxOy0xyn3L7tE2CHvJ7Y9LUsrTU7vGmZ5bwb8PpjnkatdIxg==", + "version": "11.15.5", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.15.5.tgz", + "integrity": "sha512-vBWuVEQgrhZrGKpyv8FmJ7Zs5jRQWl794Tte7yzJ0okZqqi3jd6j2pLYNg441WcREsbIOvWdiDXbY7W6E93p1A==", "requires": { "@babel/runtime": "^7.14.5", "html-escaper": "^2.0.2", @@ -11751,6 +12864,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "sass": { "version": "1.49.0", "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.0.tgz", @@ -11775,6 +12893,64 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, + "send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -11822,6 +12998,11 @@ "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, "stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", @@ -11990,6 +13171,16 @@ "is-number": "^7.0.0" } }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, "tsconfig-paths": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", @@ -12042,6 +13233,15 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, "typescript": { "version": "4.5.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", @@ -12098,6 +13298,11 @@ "cookie": "^0.4.0" } }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -12135,6 +13340,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -12149,11 +13359,30 @@ "proxy-compare": "2.0.2" } }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, "void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=" }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index cda3c61f..0bc6512f 100644 --- a/package.json +++ b/package.json @@ -22,14 +22,19 @@ "@types/axios": "^0.14.0", "axios": "^0.25.0", "classnames": "^2.3.1", + "i18next": "^21.6.13", + "i18next-browser-languagedetector": "^6.1.3", + "i18next-http-backend": "^1.3.2", "lodash.clonedeep": "^4.5.0", "lodash.debounce": "^4.0.8", "meyer-reset-scss": "^2.0.4", "next": "12.0.8", + "next-i18next": "^10.5.0", + "next-remote-watch": "^1.0.0", "react": "17.0.2", "react-cookie": "^4.1.1", "react-dom": "^17.0.2", - "react-i18next": "^11.15.3", + "react-i18next": "^11.15.5", "react-linkify": "^1.0.0-alpha", "react-scroll": "^1.8.5", "sass": "^1.49.0", From 62edc6ca5ceed66deaa05166cc2480ce13d4842f Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 17:56:17 -0800 Subject: [PATCH 02/34] Add appWithTranslation HOC to pages --- pages/_app.tsx | 3 ++- pages/new/index.tsx | 11 +++++++++++ pages/p/[party].tsx | 20 ++++++++++++++++++++ pages/teams.tsx | 22 +++++++++++++++++++--- 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/pages/_app.tsx b/pages/_app.tsx index 5a814d27..b1eb309e 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,5 +1,6 @@ import { useEffect } from 'react' import { useCookies, CookiesProvider } from 'react-cookie' +import { appWithTranslation } from 'next-i18next' import type { AppProps } from 'next/app' import Layout from '~components/Layout' @@ -37,4 +38,4 @@ function MyApp({ Component, pageProps }: AppProps) { ) } -export default MyApp +export default appWithTranslation(MyApp) diff --git a/pages/new/index.tsx b/pages/new/index.tsx index 98ea6549..fe4872f0 100644 --- a/pages/new/index.tsx +++ b/pages/new/index.tsx @@ -1,6 +1,8 @@ import React from 'react' import Party from '~components/Party' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' + const NewRoute = () => { function callback(path: string) { // This is scuffed, how do we do this natively? @@ -14,4 +16,13 @@ const NewRoute = () => { ) } +export async function getStaticProps({ locale }: { locale: string }) { + return { + props: { + ...(await serverSideTranslations(locale, ['common'])), + // Will be passed to the page component as props + }, + } +} + export default NewRoute \ No newline at end of file diff --git a/pages/p/[party].tsx b/pages/p/[party].tsx index 9bbad2e0..2c5e9423 100644 --- a/pages/p/[party].tsx +++ b/pages/p/[party].tsx @@ -1,5 +1,6 @@ import React from 'react' import { useRouter } from 'next/router' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import Party from '~components/Party' @@ -30,4 +31,23 @@ const PartyRoute: React.FC = () => { // } } +export async function getStaticPaths() { + return { + paths: [ + // Object variant: + { params: { party: 'string' } }, + ], + fallback: true, + } +} + +export async function getStaticProps({ locale }: { locale: string }) { + return { + props: { + ...(await serverSideTranslations(locale, ['common'])), + // Will be passed to the page component as props + }, + } +} + export default PartyRoute \ No newline at end of file diff --git a/pages/teams.tsx b/pages/teams.tsx index aa65be6d..55b115c3 100644 --- a/pages/teams.tsx +++ b/pages/teams.tsx @@ -1,9 +1,15 @@ import React, { useCallback, useEffect, useState } from 'react' import Head from 'next/head' + import { useRouter } from 'next/router' import { useCookies } from 'react-cookie' + +import { useTranslation } from 'next-i18next' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' + import clonedeep from 'lodash.clonedeep' + import api from '~utils/api' import GridRep from '~components/GridRep' @@ -12,6 +18,7 @@ import FilterBar from '~components/FilterBar' const TeamsRoute: React.FC = () => { const router = useRouter() + const { t } = useTranslation('common') // Cookies const [cookies] = useCookies(['account']) @@ -148,7 +155,7 @@ const TeamsRoute: React.FC = () => { return (
- Discover Teams + { t('teams.title') } @@ -161,7 +168,7 @@ const TeamsRoute: React.FC = () => { -

Discover Teams

+

{t('teams.title')}

@@ -188,7 +195,7 @@ const TeamsRoute: React.FC = () => { { (parties.length == 0) ?
-

{ (loading) ? 'Loading teams...' : 'No teams found' }

+

{ (loading) ? t('teams.loading') : t('teams.not_found') }

: '' }
@@ -196,4 +203,13 @@ const TeamsRoute: React.FC = () => { ) } +export async function getStaticProps({ locale }: { locale: string }) { + return { + props: { + ...(await serverSideTranslations(locale, ['common'])), + // Will be passed to the page component as props + }, + } +} + export default TeamsRoute \ No newline at end of file From 703c9f4d49c7ce660060d088148e9226b7249231 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 17:56:37 -0800 Subject: [PATCH 03/34] Localize headers --- components/BottomHeader/index.tsx | 22 +++++++++++----------- components/TopHeader/index.tsx | 12 ++++++++---- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/components/BottomHeader/index.tsx b/components/BottomHeader/index.tsx index 93eff8af..eaaec479 100644 --- a/components/BottomHeader/index.tsx +++ b/components/BottomHeader/index.tsx @@ -2,6 +2,8 @@ import React from 'react' import { useRouter } from 'next/router' import { useCookies } from 'react-cookie' import { useSnapshot } from 'valtio' +import { useTranslation } from 'next-i18next' + import clonedeep from 'lodash.clonedeep' import * as Scroll from 'react-scroll' @@ -11,15 +13,13 @@ import Header from '~components/Header' import Button from '~components/Button' import api from '~utils/api' -import { accountState } from '~utils/accountState' import { appState, initialAppState } from '~utils/appState' -import { ButtonType } from '~utils/enums' import CrossIcon from '~public/icons/Cross.svg' -import { route } from 'next/dist/server/router' const BottomHeader = () => { - const account = useSnapshot(accountState) + const { t } = useTranslation('common') + const app = useSnapshot(appState) const router = useRouter() @@ -67,9 +67,9 @@ const BottomHeader = () => { const leftNav = () => { if (router.pathname === '/p/[party]' || router.pathname === '/new') { if (app.party.detailsVisible) { - return () + return () } else { - return () + return () } } else { return (
) @@ -84,20 +84,20 @@ const BottomHeader = () => { - Delete team + {t('buttons.delete')} - Delete team + {t('delete_team.title')} - Are you sure you want to permanently delete this team? + {t('delete_team.description')}
- Nevermind - deleteTeam(e)}>Yes, delete + {t('delete_team.buttons.cancel')} + deleteTeam(e)}>{t('delete_team.buttons.confirm')}
diff --git a/components/TopHeader/index.tsx b/components/TopHeader/index.tsx index 4f5f8977..c7915304 100644 --- a/components/TopHeader/index.tsx +++ b/components/TopHeader/index.tsx @@ -1,8 +1,10 @@ import React, { useEffect } from 'react' +import { useSnapshot } from 'valtio' import { useCookies } from 'react-cookie' import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + import clonedeep from 'lodash.clonedeep' -import { useSnapshot } from 'valtio' import api from '~utils/api' import { accountState, initialAccountState } from '~utils/accountState' @@ -13,6 +15,8 @@ import Button from '~components/Button' import HeaderMenu from '~components/HeaderMenu' const TopHeader = () => { + const { t } = useTranslation('common') + // Cookies const [accountCookies, setAccountCookie, removeAccountCookie] = useCookies(['account']) const [userCookies, setUserCookies, removeUserCookie] = useCookies(['user']) @@ -100,7 +104,7 @@ const TopHeader = () => { const leftNav = () => { return (
- + { (account.user) ? : @@ -123,9 +127,9 @@ const TopHeader = () => { saveButton() : '' } { (router.route === '/p/[party]') ? - : '' + : '' } - +
) } From d16565332e90fa39594440f0d365e9ac759ef778 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 17:56:46 -0800 Subject: [PATCH 04/34] Localize PartySegmentedControl --- components/PartySegmentedControl/index.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/PartySegmentedControl/index.tsx b/components/PartySegmentedControl/index.tsx index b761f929..5a67e268 100644 --- a/components/PartySegmentedControl/index.tsx +++ b/components/PartySegmentedControl/index.tsx @@ -1,5 +1,6 @@ import React from 'react' -import './index.scss' +import { useSnapshot } from 'valtio' +import { useTranslation } from 'next-i18next' import { appState } from '~utils/appState' @@ -8,7 +9,9 @@ import Segment from '~components/Segment' import ToggleSwitch from '~components/ToggleSwitch' import { GridType } from '~utils/enums' -import { useSnapshot } from 'valtio' + + +import './index.scss' interface Props { selectedTab: GridType @@ -17,6 +20,8 @@ interface Props { } const PartySegmentedControl = (props: Props) => { + const { t } = useTranslation('common') + const { party, grid } = useSnapshot(appState) function getElement() { @@ -62,21 +67,21 @@ const PartySegmentedControl = (props: Props) => { name="characters" selected={props.selectedTab == GridType.Character} onClick={props.onClick} - >Characters + >{t('party.segmented_control.characters')} Weapons + >{t('party.segmented_control.weapons')} Summons + >{t('party.segmented_control.summons')} { From 5ea57f0e07123a778e35ea3e193a31018596633a Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 18:22:00 -0800 Subject: [PATCH 05/34] Rename canonical types to use "ja" instead of "jp" --- types/AxSkill.d.ts | 3 ++- types/Character.d.ts | 3 ++- types/Raid.d.ts | 3 ++- types/Summon.d.ts | 3 ++- types/Weapon.d.ts | 3 ++- types/WeaponKey.d.ts | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/types/AxSkill.d.ts b/types/AxSkill.d.ts index 69d42b39..f5db3305 100644 --- a/types/AxSkill.d.ts +++ b/types/AxSkill.d.ts @@ -1,7 +1,8 @@ interface AxSkill { name: { + [key: string]: string en: string, - jp: string + ja: string }, id: number, minValue: number, diff --git a/types/Character.d.ts b/types/Character.d.ts index 01037ff1..373c340f 100644 --- a/types/Character.d.ts +++ b/types/Character.d.ts @@ -8,8 +8,9 @@ interface Character { gender: number max_level: number name: { + [key: string]: string en: string - jp: string + ja: string } hp: { min_hp: number diff --git a/types/Raid.d.ts b/types/Raid.d.ts index 0540c8d6..8283d9cf 100644 --- a/types/Raid.d.ts +++ b/types/Raid.d.ts @@ -1,8 +1,9 @@ interface Raid { id: string name: { + [key: string]: string en: string - jp: string + ja: string } level: number group: number diff --git a/types/Summon.d.ts b/types/Summon.d.ts index fdd961ac..0808722d 100644 --- a/types/Summon.d.ts +++ b/types/Summon.d.ts @@ -6,8 +6,9 @@ interface Summon { element: number max_level: number name: { + [key: string]: string en: string - jp: string + ja: string } hp: { min_hp: number diff --git a/types/Weapon.d.ts b/types/Weapon.d.ts index d26caa7d..c43d3b18 100644 --- a/types/Weapon.d.ts +++ b/types/Weapon.d.ts @@ -10,8 +10,9 @@ interface Weapon { series: number ax: number name: { + [key: string]: string en: string - jp: string + ja: string } hp: { min_hp: number diff --git a/types/WeaponKey.d.ts b/types/WeaponKey.d.ts index d5541baa..53e36caa 100644 --- a/types/WeaponKey.d.ts +++ b/types/WeaponKey.d.ts @@ -1,8 +1,9 @@ interface WeaponKey { id: string name: { + [key: string]: string en: string, - jp: string + ja: string } series: integer slot: integer From b91d84028f39ebd66f37c29a8424aec151abcde1 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 18:42:06 -0800 Subject: [PATCH 06/34] Add localization for header menus/some modals --- components/AboutModal/index.tsx | 7 +++- components/AccountModal/index.scss | 4 ++ components/AccountModal/index.tsx | 27 ++++++++----- components/BottomHeader/index.tsx | 8 ++-- components/HeaderMenu/index.tsx | 23 ++++++----- public/locales/en/common.json | 63 +++++++++++++++++++++++++++++ public/locales/ja/common.json | 64 ++++++++++++++++++++++++++++++ 7 files changed, 170 insertions(+), 26 deletions(-) create mode 100644 public/locales/en/common.json create mode 100644 public/locales/ja/common.json diff --git a/components/AboutModal/index.tsx b/components/AboutModal/index.tsx index 79cd547a..501f0122 100644 --- a/components/AboutModal/index.tsx +++ b/components/AboutModal/index.tsx @@ -1,21 +1,24 @@ import React from 'react' +import { useTranslation } from 'next-i18next' import * as Dialog from '@radix-ui/react-dialog' import CrossIcon from '~public/icons/Cross.svg' import './index.scss' const AboutModal = () => { + const { t } = useTranslation('common') + return (
  • - About + {t('modals.about.title')}
  • event.preventDefault() }>
    - About + {t('menu.about')} diff --git a/components/AccountModal/index.scss b/components/AccountModal/index.scss index 81371cce..3762c2bb 100644 --- a/components/AccountModal/index.scss +++ b/components/AccountModal/index.scss @@ -98,6 +98,10 @@ font-size: $font-small; line-height: 1.1; max-width: 300px; + + &.jp { + max-width: 270px; + } } } diff --git a/components/AccountModal/index.tsx b/components/AccountModal/index.tsx index a3129c20..9868ed14 100644 --- a/components/AccountModal/index.tsx +++ b/components/AccountModal/index.tsx @@ -1,6 +1,8 @@ import React, { useEffect, useState } from 'react' import { useCookies } from 'react-cookie' +import { useRouter } from 'next/router' import { useSnapshot } from 'valtio' +import { useTranslation } from 'next-i18next' import * as Dialog from '@radix-ui/react-dialog' import * as Switch from '@radix-ui/react-switch' @@ -15,8 +17,13 @@ import CrossIcon from '~public/icons/Cross.svg' import './index.scss' const AccountModal = () => { + const { t } = useTranslation('common') + const { account } = useSnapshot(accountState) + const router = useRouter() + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + // Cookies const [accountCookies] = useCookies(['account']) const [userCookies, setUserCookies] = useCookies(['user']) @@ -46,7 +53,7 @@ const AccountModal = () => { const pictureOptions = ( pictureData.sort((a, b) => (a.name.en > b.name.en) ? 1 : -1).map((item, i) => { return ( - + ) }) ) @@ -109,14 +116,14 @@ const AccountModal = () => {
  • - Settings + {t('menu.settings')}
  • event.preventDefault() }>
    - Account Settings + {t('modals.settings.title')} @{account.user?.username}
    @@ -129,7 +136,7 @@ const AccountModal = () => {
    - +
    i.filename === picture)?.element}`}> @@ -147,18 +154,18 @@ const AccountModal = () => {
    - +
    - -

    Hide your profile and prevent your grids from showing up in collections

    + +

    {t('modals.settings.descriptions.private')}

    @@ -166,7 +173,7 @@ const AccountModal = () => {
    - + diff --git a/components/BottomHeader/index.tsx b/components/BottomHeader/index.tsx index eaaec479..abcbd7ad 100644 --- a/components/BottomHeader/index.tsx +++ b/components/BottomHeader/index.tsx @@ -90,14 +90,14 @@ const BottomHeader = () => { - {t('delete_team.title')} + {t('modals.delete_team.title')} - {t('delete_team.description')} + {t('modals.delete_team.description')}
    - {t('delete_team.buttons.cancel')} - deleteTeam(e)}>{t('delete_team.buttons.confirm')} + {t('modals.delete_team.buttons.cancel')} + deleteTeam(e)}>{t('modals.delete_team.buttons.confirm')}
    diff --git a/components/HeaderMenu/index.tsx b/components/HeaderMenu/index.tsx index 8c864238..1b437275 100644 --- a/components/HeaderMenu/index.tsx +++ b/components/HeaderMenu/index.tsx @@ -1,6 +1,7 @@ import React from 'react' import Link from 'next/link' import { useCookies } from 'react-cookie' +import { useTranslation } from 'next-i18next' import AboutModal from '~components/AboutModal' import AccountModal from '~components/AccountModal' @@ -16,6 +17,8 @@ interface Props { } const HeaderMenu = (props: Props) => { + const { t } = useTranslation('common') + const [accountCookies] = useCookies(['account']) const [userCookies] = useCookies(['user']) @@ -35,22 +38,22 @@ const HeaderMenu = (props: Props) => { /profile/${userCookies.user.picture}@2x.png 2x`} src={`/profile/${userCookies.user.picture}.png`} /> -
    +
    +
  • - Saved + {t('menu.saved')}
  • - Teams + {t('menu.teams')}
  • - Guides - Coming Soon + {t('menu.guides')} + {t('coming_soon')}
  • @@ -58,7 +61,7 @@ const HeaderMenu = (props: Props) => {
  • - Logout + {t('menu.logout')}
  • @@ -74,13 +77,13 @@ const HeaderMenu = (props: Props) => {
  • - Teams + {t('menu.teams')}
  • - Guides - Coming Soon + {t('menu.guides')} + {t('menu.logout')}
  • diff --git a/public/locales/en/common.json b/public/locales/en/common.json new file mode 100644 index 00000000..31556df2 --- /dev/null +++ b/public/locales/en/common.json @@ -0,0 +1,63 @@ +{ + "buttons": { + "copy": "Copy link", + "delete": "Delete team", + "edit_info": "Edit info", + "hide_info": "Hide info", + "menu": "Menu", + "new": "New" + }, + "modals": { + "about": { + "title": "About" + }, + "delete_team": { + "title": "Delete team", + "description": "Are you sure you want to permanently delete this team?", + "buttons": { + "confirm": "Yes, delete", + "cancel": "Nevermind" + } + }, + "settings": { + "title": "Account Settings", + "labels": { + "picture": "Picture", + "language": "Language", + "private": "Private" + }, + "descriptions": { + "private": "Hide your profile and prevent your grids from showing up in collections" + }, + "language": { + "english": "English", + "japanese": "Japanese" + }, + "buttons": { + "confirm": "Save settings" + } + } + }, + "menu": { + "about": "About", + "guides": "Guides", + "saved": "Saved", + "settings": "Settings", + "teams": "Teams", + "logout": "Logout" + }, + "party": { + "segmented_control": { + "class": "Class", + "characters": "Characters", + "weapons": "Weapons", + "summons": "Summons" + } + }, + "teams": { + "title": "Discover Teams", + "loading": "Loading teams...", + "not_found": "No teams found" + }, + "coming_soon": "Coming Soon" +} diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json new file mode 100644 index 00000000..e0ce247d --- /dev/null +++ b/public/locales/ja/common.json @@ -0,0 +1,64 @@ +{ + "buttons": { + "copy": "リンクをコピー", + "delete": "編成を削除", + "show_info": "詳細を編集", + "hide_info": "詳細を非表示", + "menu": "メニュー", + "new": "作成" + }, + "modals": { + "about": { + "title": "このサイトについて" + }, + "delete_team": { + "title": "編成を削除しますか", + "description": "編成を削除する操作は取り消せません。", + "buttons": { + "confirm": "削除", + "cancel": "キャンセル" + } + }, + "settings": { + "title": "アカウント設定", + "labels": { + "picture": "プロフィール画像", + "language": "言語", + "private": "プライベート" + }, + "descriptions": { + "private": "プロフィールを隠し、編成をコレクションに表示されないようにします" + }, + "language": { + "english": "英語", + "japanese": "日本語" + }, + "buttons": { + "confirm": "設定を保存する" + } + } + }, + "menu": { + "about": "このサイトについて", + "guides": "攻略", + "saved": "保存した編成", + "settings": "アカウント設定", + "teams": "編成一覧", + "logout": "ログアウト" + }, + "party": { + "segmented_control": { + "class": "ジョブ", + "characters": "キャラ", + "weapons": "武器", + "summons": "召喚石" + } + }, + "teams": { + "title": "編成一覧", + "loading": "ロード中...", + "not_found": "編成は見つかりませんでした" + }, + "coming_soon": "開発中" +} + \ No newline at end of file From 9ec157359bdd45d2f3e40be2d56e451d071e46a7 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 18:42:24 -0800 Subject: [PATCH 07/34] Change key name and add string query --- utils/axData.tsx | 154 +++++++++++++++++++++--------------------- utils/pictureData.tsx | 79 +++++++++++----------- 2 files changed, 117 insertions(+), 116 deletions(-) diff --git a/utils/axData.tsx b/utils/axData.tsx index 8ea007f4..1824071f 100644 --- a/utils/axData.tsx +++ b/utils/axData.tsx @@ -3,7 +3,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "ATK", - "jp": "攻撃" + "ja": "攻撃" }, id: 0, minValue: 1, @@ -13,7 +13,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "C.A. DMG", - "jp": "奥義ダメ" + "ja": "奥義ダメ" }, id: 3, minValue: 2, @@ -23,7 +23,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Double Attack Rate", - "jp": "DA確率" + "ja": "DA確率" }, id: 5, minValue: 1, @@ -33,7 +33,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Triple Attack Rate", - "jp": "TA確率" + "ja": "TA確率" }, id: 6, minValue: 1, @@ -43,7 +43,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Skill DMG Cap", - "jp": "アビ上限" + "ja": "アビ上限" }, id: 7, minValue: 1, @@ -55,7 +55,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "DEF", - "jp": "防御" + "ja": "防御" }, id: 1, minValue: 1, @@ -65,7 +65,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "HP", - "jp": "HP" + "ja": "HP" }, id: 2, minValue: 1, @@ -75,7 +75,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Debuff Resistance", - "jp": "弱体耐性" + "ja": "弱体耐性" }, id: 9, minValue: 1, @@ -85,7 +85,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Healing", - "jp": "回復性能" + "ja": "回復性能" }, id: 10, minValue: 2, @@ -95,7 +95,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Enmity", - "jp": "背水" + "ja": "背水" }, id: 11, minValue: 1, @@ -106,7 +106,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "HP", - "jp": "HP" + "ja": "HP" }, id: 2, minValue: 1, @@ -116,7 +116,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "DEF", - "jp": "防御" + "ja": "防御" }, id: 1, minValue: 1, @@ -126,7 +126,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Debuff Resistance", - "jp": "弱体耐性" + "ja": "弱体耐性" }, id: 9, minValue: 1, @@ -136,7 +136,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Healing", - "jp": "回復性能" + "ja": "回復性能" }, id: 10, minValue: 2, @@ -146,7 +146,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Stamina", - "jp": "渾身" + "ja": "渾身" }, id: 12, minValue: 1, @@ -157,7 +157,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "C.A. DMG", - "jp": "奥義ダメ" + "ja": "奥義ダメ" }, id: 3, minValue: 2, @@ -167,7 +167,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "ATK", - "jp": "攻撃" + "ja": "攻撃" }, id: 0, minValue: 1, @@ -177,7 +177,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Elemental ATK", - "jp": "全属性攻撃力" + "ja": "全属性攻撃力" }, id: 13, minValue: 1, @@ -187,7 +187,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "C.A. DMG Cap", - "jp": "奥義上限" + "ja": "奥義上限" }, id: 8, minValue: 1, @@ -197,7 +197,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Stamina", - "jp": "渾身" + "ja": "渾身" }, id: 12, minValue: 1, @@ -208,7 +208,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Multiattack Rate", - "jp": "連撃率" + "ja": "連撃率" }, id: 4, minValue: 1, @@ -218,7 +218,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "C.A. DMG", - "jp": "奥義ダメ" + "ja": "奥義ダメ" }, id: 3, minValue: 2, @@ -228,7 +228,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Elemental ATK", - "jp": "全属性攻撃力" + "ja": "全属性攻撃力" }, id: 13, minValue: 1, @@ -238,7 +238,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Double Attack Rate", - "jp": "DA確率" + "ja": "DA確率" }, id: 5, minValue: 1, @@ -248,7 +248,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Triple Attack Rate", - "jp": "TA確率" + "ja": "TA確率" }, id: 6, minValue: 1, @@ -261,7 +261,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "ATK", - "jp": "攻撃" + "ja": "攻撃" }, id: 0, minValue: 1, @@ -271,7 +271,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "C.A. DMG", - "jp": "奥義ダメ" + "ja": "奥義ダメ" }, id: 3, minValue: 2, @@ -281,7 +281,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Multiattack Rate", - "jp": "連撃確率" + "ja": "連撃確率" }, id: 4, minValue: 1.5, @@ -291,7 +291,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Normal ATK DMG Cap", - "jp": "通常ダメ上限" + "ja": "通常ダメ上限" }, id: 14, minValue: 0.5, @@ -301,7 +301,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Supplemental Skill DMG", - "jp": "アビ与ダメ上昇" + "ja": "アビ与ダメ上昇" }, id: 15, minValue: 1, @@ -312,7 +312,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "DEF", - "jp": "防御" + "ja": "防御" }, id: 1, minValue: 1, @@ -322,7 +322,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Elemental DMG Reduction", - "jp": "属性ダメ軽減" + "ja": "属性ダメ軽減" }, id: 17, minValue: 1, @@ -332,7 +332,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Debuff Resistance", - "jp": "弱体耐性" + "ja": "弱体耐性" }, id: 9, minValue: 1, @@ -342,7 +342,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Healing", - "jp": "回復性能" + "ja": "回復性能" }, id: 10, minValue: 2, @@ -352,7 +352,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Enmity", - "jp": "背水" + "ja": "背水" }, id: 11, minValue: 1, @@ -363,7 +363,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "HP", - "jp": "HP" + "ja": "HP" }, id: 2, minValue: 1, @@ -373,7 +373,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Elemental DMG Reduction", - "jp": "属性ダメ軽減" + "ja": "属性ダメ軽減" }, id: 17, minValue: 1, @@ -383,7 +383,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Debuff Resistance", - "jp": "弱体耐性" + "ja": "弱体耐性" }, id: 9, minValue: 1, @@ -393,7 +393,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Healing", - "jp": "回復性能" + "ja": "回復性能" }, id: 10, minValue: 2, @@ -403,7 +403,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Stamina", - "jp": "渾身" + "ja": "渾身" }, id: 12, minValue: 1, @@ -414,7 +414,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "C.A. DMG", - "jp": "奥義ダメ" + "ja": "奥義ダメ" }, id: 3, minValue: 2, @@ -424,7 +424,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Multiattack Rate", - "jp": "連撃率" + "ja": "連撃率" }, id: 4, minValue: 1.5, @@ -434,7 +434,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Supplemental Skill DMG", - "jp": "アビ与ダメ上昇" + "ja": "アビ与ダメ上昇" }, id: 15, minValue: 1, @@ -443,7 +443,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Supplemental C.A. DMG", - "jp": "奥義与ダメ上昇" + "ja": "奥義与ダメ上昇" }, id: 16, minValue: 1, @@ -452,7 +452,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Stamina", - "jp": "渾身" + "ja": "渾身" }, id: 12, minValue: 1, @@ -463,7 +463,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Multiattack Rate", - "jp": "連撃率" + "ja": "連撃率" }, id: 4, minValue: 1, @@ -473,7 +473,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Supplemental C.A. DMG", - "jp": "奥義与ダメ上昇" + "ja": "奥義与ダメ上昇" }, id: 16, minValue: 1, @@ -482,7 +482,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Normal ATK DMG Cap", - "jp": "通常ダメ上限" + "ja": "通常ダメ上限" }, id: 14, minValue: 0.5, @@ -492,7 +492,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Stamina", - "jp": "渾身" + "ja": "渾身" }, id: 12, minValue: 1, @@ -501,7 +501,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Enmity", - "jp": "背水" + "ja": "背水" }, id: 11, minValue: 1, @@ -513,7 +513,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "ATK", - "jp": "攻撃" + "ja": "攻撃" }, id: 0, minValue: 1, @@ -523,7 +523,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "C.A. DMG", - "jp": "奥義ダメ" + "ja": "奥義ダメ" }, id: 3, minValue: 2, @@ -533,7 +533,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Double Attack Rate", - "jp": "DA確率" + "ja": "DA確率" }, id: 5, minValue: 1, @@ -543,7 +543,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Triple Attack Rate", - "jp": "TA確率" + "ja": "TA確率" }, id: 6, minValue: 1, @@ -553,7 +553,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Skill DMG Cap", - "jp": "アビ上限" + "ja": "アビ上限" }, id: 7, minValue: 1, @@ -565,7 +565,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "DEF", - "jp": "防御" + "ja": "防御" }, id: 1, minValue: 1, @@ -575,7 +575,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "HP", - "jp": "HP" + "ja": "HP" }, id: 2, minValue: 1, @@ -585,7 +585,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Debuff Resistance", - "jp": "弱体耐性" + "ja": "弱体耐性" }, id: 9, minValue: 1, @@ -595,7 +595,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Healing", - "jp": "回復性能" + "ja": "回復性能" }, id: 10, minValue: 2, @@ -605,7 +605,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Enmity", - "jp": "背水" + "ja": "背水" }, id: 11, minValue: 1, @@ -616,7 +616,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "HP", - "jp": "HP" + "ja": "HP" }, id: 2, minValue: 1, @@ -626,7 +626,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "DEF", - "jp": "防御" + "ja": "防御" }, id: 1, minValue: 1, @@ -636,7 +636,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Debuff Resistance", - "jp": "弱体耐性" + "ja": "弱体耐性" }, id: 9, minValue: 1, @@ -646,7 +646,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Healing", - "jp": "回復性能" + "ja": "回復性能" }, id: 10, minValue: 2, @@ -656,7 +656,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Stamina", - "jp": "渾身" + "ja": "渾身" }, id: 12, minValue: 1, @@ -667,7 +667,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "C.A. DMG", - "jp": "奥義ダメ" + "ja": "奥義ダメ" }, id: 3, minValue: 2, @@ -677,7 +677,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "ATK", - "jp": "攻撃" + "ja": "攻撃" }, id: 0, minValue: 1, @@ -687,7 +687,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Elemental ATK", - "jp": "全属性攻撃力" + "ja": "全属性攻撃力" }, id: 13, minValue: 1, @@ -697,7 +697,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "C.A. DMG Cap", - "jp": "奥義上限" + "ja": "奥義上限" }, id: 8, minValue: 1, @@ -707,7 +707,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Stamina", - "jp": "渾身" + "ja": "渾身" }, id: 12, minValue: 1, @@ -718,7 +718,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Multiattack Rate", - "jp": "連撃率" + "ja": "連撃率" }, id: 4, minValue: 1, @@ -728,7 +728,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "C.A. DMG", - "jp": "奥義ダメ" + "ja": "奥義ダメ" }, id: 3, minValue: 2, @@ -738,7 +738,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Elemental ATK", - "jp": "全属性攻撃力" + "ja": "全属性攻撃力" }, id: 13, minValue: 1, @@ -748,7 +748,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Double Attack Rate", - "jp": "DA確率" + "ja": "DA確率" }, id: 5, minValue: 1, @@ -758,7 +758,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Triple Attack Rate", - "jp": "TA確率" + "ja": "TA確率" }, id: 6, minValue: 1, @@ -770,7 +770,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "EXP Up", - "jp": "EXP UP" + "ja": "EXP UP" }, id: 18, minValue: 5, @@ -780,7 +780,7 @@ export const axData: AxSkill[][] = [ { name: { "en": "Rupies", - "jp": "獲得ルピ" + "ja": "獲得ルピ" }, id: 19, minValue: 10, diff --git a/utils/pictureData.tsx b/utils/pictureData.tsx index c5720de6..ef05e4cb 100644 --- a/utils/pictureData.tsx +++ b/utils/pictureData.tsx @@ -1,7 +1,8 @@ interface Picture { name: { + [key: string]: string en: string - jp: string + ja: string } filename: string element: string @@ -11,7 +12,7 @@ export const pictureData: Picture[] = [ { name: { en: "Gran 2019", - jp: "グラン" + ja: "グラン" }, filename: "gran_19", element: "water" @@ -19,7 +20,7 @@ export const pictureData: Picture[] = [ { name: { en: "Djeeta 2019", - jp: "ジータ" + ja: "ジータ" }, filename: "djeeta_19", element: "fire" @@ -27,7 +28,7 @@ export const pictureData: Picture[] = [ { name: { en: "Gran 2020", - jp: "グラン" + ja: "グラン" }, filename: "gran_20", element: "water" @@ -35,7 +36,7 @@ export const pictureData: Picture[] = [ { name: { en: "Djeeta 2020", - jp: "ジータ" + ja: "ジータ" }, filename: "djeeta_20", element: "fire" @@ -43,7 +44,7 @@ export const pictureData: Picture[] = [ { name: { en: "Gran - Farer of the Skies", - jp: "空駆ける新鋭 グランver" + ja: "空駆ける新鋭 グランver" }, filename: "gran", element: "water" @@ -51,7 +52,7 @@ export const pictureData: Picture[] = [ { name: { en: "Djeeta - Farer of the Skies", - jp: "空駆ける新鋭 ジータver" + ja: "空駆ける新鋭 ジータver" }, filename: "djeeta", element: "fire" @@ -59,7 +60,7 @@ export const pictureData: Picture[] = [ { name: { en: "Cassius", - jp: "カシウス" + ja: "カシウス" }, filename: "cassius", element: "dark" @@ -67,7 +68,7 @@ export const pictureData: Picture[] = [ { name: { en: "Percival", - jp: "パーシヴァル" + ja: "パーシヴァル" }, filename: "percival", element: "fire" @@ -75,7 +76,7 @@ export const pictureData: Picture[] = [ { name: { en: "Vane", - jp: "ヴェイン" + ja: "ヴェイン" }, filename: "vane", element: "water" @@ -83,7 +84,7 @@ export const pictureData: Picture[] = [ { name: { en: "Heles", - jp: "ヘルエス" + ja: "ヘルエス" }, filename: "heles", element: "fire" @@ -91,7 +92,7 @@ export const pictureData: Picture[] = [ { name: { en: "Lunalu", - jp: "ルナール" + ja: "ルナール" }, filename: "lunalu", element: "dark" @@ -99,7 +100,7 @@ export const pictureData: Picture[] = [ { name: { en: "Catura", - jp: "シャトラ" + ja: "シャトラ" }, filename: "catura", element: "wind" @@ -107,7 +108,7 @@ export const pictureData: Picture[] = [ { name: { en: "Yuisis", - jp: "ユイシス" + ja: "ユイシス" }, filename: "yuisis", element: "wind" @@ -115,7 +116,7 @@ export const pictureData: Picture[] = [ { name: { en: "Meg", - jp: "メグ" + ja: "メグ" }, filename: "meg", element: "dark" @@ -123,7 +124,7 @@ export const pictureData: Picture[] = [ { name: { en: "Seofon", - jp: "シエテ" + ja: "シエテ" }, filename: "seofon", element: "wind" @@ -131,7 +132,7 @@ export const pictureData: Picture[] = [ { name: { en: "Quatre", - jp: "カトル" + ja: "カトル" }, filename: "quatre", element: "water" @@ -139,7 +140,7 @@ export const pictureData: Picture[] = [ { name: { en: "Tien", - jp: "エッセル" + ja: "エッセル" }, filename: "tien", element: "fire" @@ -147,7 +148,7 @@ export const pictureData: Picture[] = [ { name: { en: "Seox", - jp: "シス" + ja: "シス" }, filename: "seox", element: "dark" @@ -155,7 +156,7 @@ export const pictureData: Picture[] = [ { name: { en: "Aoidos", - jp: "アオイドス" + ja: "アオイドス" }, filename: "aoidos", element: "fire" @@ -163,7 +164,7 @@ export const pictureData: Picture[] = [ { name: { en: "Sandalphon", - jp: "サンダルフォン" + ja: "サンダルフォン" }, filename: "sandalphon", element: "light" @@ -171,7 +172,7 @@ export const pictureData: Picture[] = [ { name: { en: "Vikala", - jp: "ビカラ" + ja: "ビカラ" }, filename: "vikala", element: "dark" @@ -179,7 +180,7 @@ export const pictureData: Picture[] = [ { name: { en: "Belial", - jp: "ベリアル" + ja: "ベリアル" }, filename: "belial", element: "dark" @@ -187,7 +188,7 @@ export const pictureData: Picture[] = [ { name: { en: "Zeta", - jp: "ゼタ" + ja: "ゼタ" }, filename: "zeta", element: "fire" @@ -195,7 +196,7 @@ export const pictureData: Picture[] = [ { name: { en: "Beatrix", - jp: "ベアトリックス" + ja: "ベアトリックス" }, filename: "beatrix", element: "earth" @@ -203,7 +204,7 @@ export const pictureData: Picture[] = [ { name: { en: "Yuel", - jp: "ユエル" + ja: "ユエル" }, filename: "yuel", element: "fire" @@ -211,7 +212,7 @@ export const pictureData: Picture[] = [ { name: { en: "Societte", - jp: "ソシエ" + ja: "ソシエ" }, filename: "societte", element: "water" @@ -219,7 +220,7 @@ export const pictureData: Picture[] = [ { name: { en: "Kumbhira", - jp: "クビラ" + ja: "クビラ" }, filename: "kumbhira", element: "light" @@ -227,7 +228,7 @@ export const pictureData: Picture[] = [ { name: { en: "Narmaya", - jp: "ナルメア" + ja: "ナルメア" }, filename: "narmaya", element: "dark" @@ -235,7 +236,7 @@ export const pictureData: Picture[] = [ { name: { en: "Siegfried", - jp: "ジークフリード" + ja: "ジークフリード" }, filename: "siegfried", element: "earth" @@ -243,7 +244,7 @@ export const pictureData: Picture[] = [ { name: { en: "Naoise", - jp: "ノイシュ" + ja: "ノイシュ" }, filename: "naoise", element: "light" @@ -251,7 +252,7 @@ export const pictureData: Picture[] = [ { name: { en: "Scathacha", - jp: "スカーサハ" + ja: "スカーサハ" }, filename: "scathacha", element: "wind" @@ -259,7 +260,7 @@ export const pictureData: Picture[] = [ { name: { en: "Seruel", - jp: "セルエル" + ja: "セルエル" }, filename: "seruel", element: "light" @@ -267,7 +268,7 @@ export const pictureData: Picture[] = [ { name: { en: "Shiva", - jp: "シヴァ" + ja: "シヴァ" }, filename: "shiva", element: "fire" @@ -275,7 +276,7 @@ export const pictureData: Picture[] = [ { name: { en: "Europa", - jp: "エウロペ" + ja: "エウロペ" }, filename: "europa", element: "water" @@ -283,7 +284,7 @@ export const pictureData: Picture[] = [ { name: { en: "Grimnir", - jp: "グリームニル" + ja: "グリームニル" }, filename: "grimnir", element: "wind" @@ -291,7 +292,7 @@ export const pictureData: Picture[] = [ { name: { en: "Alexiel", - jp: "ブローディア" + ja: "ブローディア" }, filename: "alexiel", element: "earth" @@ -299,7 +300,7 @@ export const pictureData: Picture[] = [ { name: { en: "Sierokarte", - jp: "シェロカルテ" + ja: "シェロカルテ" }, filename: "siero", element: "wind" @@ -307,7 +308,7 @@ export const pictureData: Picture[] = [ { name: { en: "Vajra", - jp: "ヴァジラ" + ja: "ヴァジラ" }, filename: "vajra", element: "water" From 34bd98856ac6f8e2e36e9241315309c38ab053f1 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 18:46:32 -0800 Subject: [PATCH 08/34] Add locale to object unit components --- components/CharacterUnit/index.tsx | 6 +++++- components/SummonUnit/index.tsx | 6 +++++- components/WeaponUnit/index.tsx | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/components/CharacterUnit/index.tsx b/components/CharacterUnit/index.tsx index 12c66138..59e7c681 100644 --- a/components/CharacterUnit/index.tsx +++ b/components/CharacterUnit/index.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useState } from 'react' +import { useRouter } from 'next/router' import classnames from 'classnames' import SearchModal from '~components/SearchModal' @@ -18,6 +19,9 @@ interface Props { } const CharacterUnit = (props: Props) => { + const router = useRouter() + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const [imageUrl, setImageUrl] = useState('') const classes = classnames({ @@ -88,7 +92,7 @@ const CharacterUnit = (props: Props) => { updateUncap={passUncapData} special={character.special} /> : '' } -

    {character?.name.en}

    +

    {character?.name[locale]}

    ) diff --git a/components/SummonUnit/index.tsx b/components/SummonUnit/index.tsx index 43602695..adaa809c 100644 --- a/components/SummonUnit/index.tsx +++ b/components/SummonUnit/index.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useState } from 'react' +import { useRouter } from 'next/router' import classnames from 'classnames' import SearchModal from '~components/SearchModal' @@ -20,6 +21,9 @@ interface Props { const SummonUnit = (props: Props) => { const [imageUrl, setImageUrl] = useState('') + const router = useRouter() + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const classes = classnames({ SummonUnit: true, 'main': props.unitType == 0, @@ -97,7 +101,7 @@ const SummonUnit = (props: Props) => { special={false} /> : '' } -

    {summon?.name.en}

    +

    {summon?.name[locale]}

    ) diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index 6674f18e..9e8909dd 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useState } from 'react' +import Router, { useRouter } from 'next/router' import classnames from 'classnames' import SearchModal from '~components/SearchModal' @@ -24,6 +25,9 @@ interface Props { const WeaponUnit = (props: Props) => { const [imageUrl, setImageUrl] = useState('') + const router = useRouter() + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const classes = classnames({ WeaponUnit: true, 'mainhand': props.unitType == 0, @@ -108,7 +112,7 @@ const WeaponUnit = (props: Props) => { special={false} /> : '' } -

    {weapon?.name.en}

    +

    {weapon?.name[locale]}

    ) From f62a4a5637d0a50b6a49329a42fa4671f5b4352a Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 18:46:44 -0800 Subject: [PATCH 09/34] Update index.tsx --- components/AccountModal/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/AccountModal/index.tsx b/components/AccountModal/index.tsx index 9868ed14..40321d96 100644 --- a/components/AccountModal/index.tsx +++ b/components/AccountModal/index.tsx @@ -17,11 +17,10 @@ import CrossIcon from '~public/icons/Cross.svg' import './index.scss' const AccountModal = () => { - const { t } = useTranslation('common') - const { account } = useSnapshot(accountState) const router = useRouter() + const { t } = useTranslation('common') const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' // Cookies From 70fb1e63b9a3ed700570d1209b14815cf947c741 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 19:05:17 -0800 Subject: [PATCH 10/34] Add translations for hovercards --- components/CharacterHovercard/index.tsx | 15 ++++++++----- components/SummonHovercard/index.tsx | 16 +++++++++----- components/WeaponHovercard/index.tsx | 29 +++++++++++++++---------- public/locales/en/common.json | 3 ++- public/locales/ja/common.json | 3 ++- 5 files changed, 42 insertions(+), 24 deletions(-) diff --git a/components/CharacterHovercard/index.tsx b/components/CharacterHovercard/index.tsx index 73dada07..9ae4c78d 100644 --- a/components/CharacterHovercard/index.tsx +++ b/components/CharacterHovercard/index.tsx @@ -1,11 +1,12 @@ import React from 'react' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + import * as HoverCard from '@radix-ui/react-hover-card' import WeaponLabelIcon from '~components/WeaponLabelIcon' import UncapIndicator from '~components/UncapIndicator' -import { axData } from '~utils/axData' - import './index.scss' interface Props { @@ -21,6 +22,10 @@ interface KeyNames { } const CharacterHovercard = (props: Props) => { + const router = useRouter() + const { t } = useTranslation('common') + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] const Proficiency = ['none', 'sword', 'dagger', 'axe', 'spear', 'bow', 'staff', 'fist', 'harp', 'gun', 'katana'] @@ -56,8 +61,8 @@ const CharacterHovercard = (props: Props) => {
    -

    { props.gridCharacter.object.name.en }

    - {props.gridCharacter.object.name.en} +

    { props.gridCharacter.object.name[locale] }

    + {props.gridCharacter.object.name[locale]}
    @@ -76,7 +81,7 @@ const CharacterHovercard = (props: Props) => {
    - View more on gbf.wiki + {t('buttons.wiki')} diff --git a/components/SummonHovercard/index.tsx b/components/SummonHovercard/index.tsx index 5db30251..f989da7e 100644 --- a/components/SummonHovercard/index.tsx +++ b/components/SummonHovercard/index.tsx @@ -1,11 +1,12 @@ import React from 'react' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + import * as HoverCard from '@radix-ui/react-hover-card' import WeaponLabelIcon from '~components/WeaponLabelIcon' import UncapIndicator from '~components/UncapIndicator' -import { axData } from '~utils/axData' - import './index.scss' interface Props { @@ -21,8 +22,11 @@ interface KeyNames { } const SummonHovercard = (props: Props) => { + const router = useRouter() + const { t } = useTranslation('common') + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] - const Proficiency = ['none', 'sword', 'dagger', 'axe', 'spear', 'bow', 'staff', 'fist', 'harp', 'gun', 'katana'] const tintElement = Element[props.gridSummon.object.element] const wikiUrl = `https://gbf.wiki/${props.gridSummon.object.name.en.replaceAll(' ', '_')}` @@ -57,8 +61,8 @@ const SummonHovercard = (props: Props) => {
    -

    { props.gridSummon.object.name.en }

    - {props.gridSummon.object.name.en} +

    { props.gridSummon.object.name[locale] }

    + {props.gridSummon.object.name[locale]}
    @@ -72,7 +76,7 @@ const SummonHovercard = (props: Props) => { />
    - View more on gbf.wiki + {t('buttons.wiki')} diff --git a/components/WeaponHovercard/index.tsx b/components/WeaponHovercard/index.tsx index 70e5500e..5c497c5f 100644 --- a/components/WeaponHovercard/index.tsx +++ b/components/WeaponHovercard/index.tsx @@ -1,4 +1,7 @@ import React from 'react' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + import * as HoverCard from '@radix-ui/react-hover-card' import WeaponLabelIcon from '~components/WeaponLabelIcon' @@ -16,29 +19,33 @@ interface Props { interface KeyNames { [key: string]: { en: string, - jp: string + ja: string } } const WeaponHovercard = (props: Props) => { + const router = useRouter() + const { t } = useTranslation('common') + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] const Proficiency = ['none', 'sword', 'dagger', 'axe', 'spear', 'bow', 'staff', 'fist', 'harp', 'gun', 'katana'] const WeaponKeyNames: KeyNames = { '2': { en: 'Pendulum', - jp: '' + ja: 'ペンデュラム' }, '3': { en: 'Teluma', - jp: '' + ja: 'テルマ' }, '17': { en: 'Gauph Key', - jp: '' + ja: 'ガフスキー' }, '22': { en: 'Emblem', - jp: '' + ja: 'エンブレム' } } @@ -61,7 +68,7 @@ const WeaponHovercard = (props: Props) => { const simpleAxSkill = props.gridWeapon.ax[0] const axSkill = primaryAxSkills.find(skill => skill.id == simpleAxSkill.modifier) - return `${axSkill?.name.en} +${simpleAxSkill.strength}${ (axSkill?.suffix) ? axSkill.suffix : '' }` + return `${axSkill?.name[locale]} +${simpleAxSkill.strength}${ (axSkill?.suffix) ? axSkill.suffix : '' }` } return '' @@ -78,7 +85,7 @@ const WeaponHovercard = (props: Props) => { if (primaryAxSkill && primaryAxSkill.secondary) { const secondaryAxSkill = primaryAxSkill.secondary.find(skill => skill.id == secondarySimpleAxSkill.modifier) - return `${secondaryAxSkill?.name.en} +${secondarySimpleAxSkill.strength}${ (secondaryAxSkill?.suffix) ? secondaryAxSkill.suffix : '' }` + return `${secondaryAxSkill?.name[locale]} +${secondarySimpleAxSkill.strength}${ (secondaryAxSkill?.suffix) ? secondaryAxSkill.suffix : '' }` } } @@ -104,7 +111,7 @@ const WeaponHovercard = (props: Props) => { Array.from(Array(props.gridWeapon.weapon_keys.length)).map((x, i) => { return (
    - {props.gridWeapon.weapon_keys![i].name.en} + {props.gridWeapon.weapon_keys![i].name[locale]}
    ) }) : '' } @@ -137,8 +144,8 @@ const WeaponHovercard = (props: Props) => {
    -

    { props.gridWeapon.object.name.en }

    - {props.gridWeapon.object.name.en} +

    { props.gridWeapon.object.name[locale] }

    + {props.gridWeapon.object.name[locale]}
    @@ -158,7 +165,7 @@ const WeaponHovercard = (props: Props) => { { (props.gridWeapon.object.ax > 0 && props.gridWeapon.ax && props.gridWeapon.ax[0].modifier && props.gridWeapon.ax[0].strength ) ? axSection : '' } { (props.gridWeapon.weapon_keys && props.gridWeapon.weapon_keys.length > 0) ? keysSection : '' } - View more on gbf.wiki + {t('buttons.wiki')} diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 31556df2..8376ce6a 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -5,7 +5,8 @@ "edit_info": "Edit info", "hide_info": "Hide info", "menu": "Menu", - "new": "New" + "new": "New", + "wiki": "View more on gbf.wiki" }, "modals": { "about": { diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index e0ce247d..47f2d4a8 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -5,7 +5,8 @@ "show_info": "詳細を編集", "hide_info": "詳細を非表示", "menu": "メニュー", - "new": "作成" + "new": "作成", + "wiki": "gbf.wikiで詳しく見る" }, "modals": { "about": { From 159110a807f9ac7e23a5a7efd77b2e83d7a1c3c1 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 19:11:17 -0800 Subject: [PATCH 11/34] Add translations for SummonGrid --- components/ExtraSummons/index.tsx | 5 ++++- components/SummonGrid/index.tsx | 9 ++++++--- public/locales/en/common.json | 6 ++++++ public/locales/ja/common.json | 6 ++++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/components/ExtraSummons/index.tsx b/components/ExtraSummons/index.tsx index def4cc27..54e888e3 100644 --- a/components/ExtraSummons/index.tsx +++ b/components/ExtraSummons/index.tsx @@ -1,4 +1,5 @@ import React from 'react' +import { useTranslation } from 'next-i18next' import SummonUnit from '~components/SummonUnit' import './index.scss' @@ -16,9 +17,11 @@ interface Props { const ExtraSummons = (props: Props) => { const numSummons: number = 2 + const { t } = useTranslation('common') + return (
    - Sub Aura Summons + {t('summons.subaura')}
      { Array.from(Array(numSummons)).map((x, i) => { diff --git a/components/SummonGrid/index.tsx b/components/SummonGrid/index.tsx index ed0008e6..18ce4398 100644 --- a/components/SummonGrid/index.tsx +++ b/components/SummonGrid/index.tsx @@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react' import { useCookies } from 'react-cookie' import { useSnapshot } from 'valtio' +import { useTranslation } from 'next-i18next' import { AxiosResponse } from 'axios' import debounce from 'lodash.debounce' @@ -26,6 +27,8 @@ const SummonGrid = (props: Props) => { // Constants const numSummons: number = 4 + const { t } = useTranslation('common') + // Cookies const [cookies, _] = useCookies(['account']) const headers = (cookies.account != null) ? { @@ -239,7 +242,7 @@ const SummonGrid = (props: Props) => { // Render: JSX components const mainSummonElement = (
      -
      Main Summon
      +
      {t('summons.main')}
      { const friendSummonElement = (
      -
      Friend Summon
      +
      {t('summons.friend')}
      { ) const summonGridElement = (
      -
      Summons
      +
      {t('summons.summons')}
        {Array.from(Array(numSummons)).map((x, i) => { return (
      • diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 8376ce6a..6609bfe2 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -8,6 +8,12 @@ "new": "New", "wiki": "View more on gbf.wiki" }, + "summons": { + "main": "Main Summon", + "friend": "Friend Summon", + "summons": "Summons", + "subaura": "Sub Aura Summons" + }, "modals": { "about": { "title": "About" diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index 47f2d4a8..9ba8d7a3 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -8,6 +8,12 @@ "new": "作成", "wiki": "gbf.wikiで詳しく見る" }, + "summons": { + "main": "メイン", + "friend": "フレンド", + "summons": "召喚石", + "subaura": "サブ加護召喚石" + }, "modals": { "about": { "title": "このサイトについて" From d0323861dbb5bdc4c93f6a845d169c9e384d9542 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 19:20:06 -0800 Subject: [PATCH 12/34] Localize and modernize search result components --- components/CharacterResult/index.tsx | 43 ++++++++++++++------------- components/SummonResult/index.tsx | 43 ++++++++++++++------------- components/WeaponResult/index.tsx | 44 +++++++++++++++------------- 3 files changed, 69 insertions(+), 61 deletions(-) diff --git a/components/CharacterResult/index.tsx b/components/CharacterResult/index.tsx index 183ebe55..f2395019 100644 --- a/components/CharacterResult/index.tsx +++ b/components/CharacterResult/index.tsx @@ -1,4 +1,6 @@ import React from 'react' +import { useRouter } from 'next/router' + import UncapIndicator from '~components/UncapIndicator' import WeaponLabelIcon from '~components/WeaponLabelIcon' @@ -11,28 +13,29 @@ interface Props { const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] -class CharacterResult extends React.Component { - render() { - const character = this.props.data +const CharacterResult = (props: Props) => { + const router = useRouter() + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' - return ( -
      • - {character.name.en} -
        -
        {character.name.en}
        - -
        - -
        + const character = props.data + + return( +
      • + {character.name[locale]} +
        +
        {character.name[locale]}
        + +
        +
        -
      • - ) - } +
      + + ) } export default CharacterResult \ No newline at end of file diff --git a/components/SummonResult/index.tsx b/components/SummonResult/index.tsx index 2df04f44..c5c32990 100644 --- a/components/SummonResult/index.tsx +++ b/components/SummonResult/index.tsx @@ -1,4 +1,6 @@ import React from 'react' +import { useRouter } from 'next/router' + import UncapIndicator from '~components/UncapIndicator' import WeaponLabelIcon from '~components/WeaponLabelIcon' @@ -11,28 +13,29 @@ interface Props { const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] -class SummonResult extends React.Component { - render() { - const summon = this.props.data +const SummonResult = (props: Props) => { + const router = useRouter() + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' - return ( -
    • - {summon.name.en} -
      -
      {summon.name.en}
      - -
      - -
      + const summon = props.data + + return ( +
    • + {summon.name[locale]} +
      +
      {summon.name[locale]}
      + +
      +
      -
    • - ) - } +
      + + ) } export default SummonResult \ No newline at end of file diff --git a/components/WeaponResult/index.tsx b/components/WeaponResult/index.tsx index 725b924f..66b4332a 100644 --- a/components/WeaponResult/index.tsx +++ b/components/WeaponResult/index.tsx @@ -1,4 +1,6 @@ import React from 'react' +import { useRouter } from 'next/router' + import UncapIndicator from '~components/UncapIndicator' import WeaponLabelIcon from '~components/WeaponLabelIcon' @@ -13,29 +15,29 @@ const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] const Proficiency = ['none', 'sword', 'dagger', 'axe', 'spear', 'bow', 'staff', 'fist', 'harp', 'gun', 'katana'] const Series = ['seraphic', 'grand', 'opus', 'draconic', 'revenant', 'primal', 'beast','regalia', 'omega', 'olden_primal', 'hollowsky', 'xeno', 'astral', 'rose', 'ultima', 'bahamut', 'epic', 'ennead', 'cosmos', 'ancestral', 'superlative', 'vintage', 'class_champion', 'sephira', 'new_world_foundation'] -class WeaponResult extends React.Component { - render() { - const weapon = this.props.data +const WeaponResult = (props: Props) => { + const router = useRouter() + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const weapon = props.data - return ( -
    • - {weapon.name.en} -
      -
      {weapon.name.en}
      - -
      - - -
      + return ( +
    • + {weapon.name[locale]} +
      +
      {weapon.name[locale]}
      + +
      + +
      -
    • - ) - } +
      + + ) } export default WeaponResult \ No newline at end of file From 110cc0c769f45f3a0439acc32131ef69ea8e0542 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 4 Mar 2022 19:51:43 -0800 Subject: [PATCH 13/34] Localize filter bar and dropdowns --- components/ElementToggle/index.scss | 5 +++++ components/ElementToggle/index.tsx | 35 +++++++++++++++++------------ components/FilterBar/index.tsx | 33 ++++++++++++++------------- components/GridRep/index.tsx | 24 ++++++++++++-------- components/RaidDropdown/index.tsx | 10 +++++++-- public/locales/en/common.json | 33 ++++++++++++++++++++++++++- public/locales/ja/common.json | 33 ++++++++++++++++++++++++++- 7 files changed, 131 insertions(+), 42 deletions(-) diff --git a/components/ElementToggle/index.scss b/components/ElementToggle/index.scss index c97a1d19..06d7a160 100644 --- a/components/ElementToggle/index.scss +++ b/components/ElementToggle/index.scss @@ -17,6 +17,11 @@ font-size: $font-regular; padding: ($unit) $unit * 2; + &.ja { + padding-top: 6px; + padding-bottom: 10px; + } + &:hover { cursor: pointer; } diff --git a/components/ElementToggle/index.tsx b/components/ElementToggle/index.tsx index 68486bdb..fe6a9e99 100644 --- a/components/ElementToggle/index.tsx +++ b/components/ElementToggle/index.tsx @@ -1,4 +1,7 @@ import React from 'react' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + import * as ToggleGroup from '@radix-ui/react-toggle-group' import './index.scss' @@ -9,28 +12,32 @@ interface Props { } const ElementToggle = (props: Props) => { + const router = useRouter() + const { t } = useTranslation('common') + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + return ( - - Null + + {t('elements.null')} - - Wind + + {t('elements.wind')} - - Fire + + {t('elements.fire')} - - Water + + {t('elements.water')} - - Earth + + {t('elements.earth')} - - Dark + + {t('elements.dark')} - - Light + + {t('elements.light')} ) diff --git a/components/FilterBar/index.tsx b/components/FilterBar/index.tsx index c7b3c3c2..b34873ee 100644 --- a/components/FilterBar/index.tsx +++ b/components/FilterBar/index.tsx @@ -1,4 +1,5 @@ import React from 'react' +import { useTranslation } from 'next-i18next' import classNames from 'classnames' import RaidDropdown from '~components/RaidDropdown' @@ -12,6 +13,8 @@ interface Props { } const FilterBar = (props: Props) => { + const { t } = useTranslation('common') + const elementSelect = React.createRef() const raidSelect = React.createRef() const recencySelect = React.createRef() @@ -33,14 +36,14 @@ const FilterBar = (props: Props) => {
      {props.children} { ref={raidSelect} />
      ) diff --git a/components/GridRep/index.tsx b/components/GridRep/index.tsx index 86fef4b7..ba265a6a 100644 --- a/components/GridRep/index.tsx +++ b/components/GridRep/index.tsx @@ -1,6 +1,8 @@ import React, { useEffect, useState } from 'react' +import { useRouter } from 'next/router' import { useSnapshot } from 'valtio' +import { useTranslation } from 'next-i18next' import classNames from 'classnames' import { accountState } from '~utils/accountState' @@ -30,6 +32,10 @@ const GridRep = (props: Props) => { const { account } = useSnapshot(accountState) + const router = useRouter() + const { t } = useTranslation('common') + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const [mainhand, setMainhand] = useState() const [weapons, setWeapons] = useState>({}) @@ -66,12 +72,12 @@ const GridRep = (props: Props) => { function generateMainhandImage() { return (mainhand) ? - {mainhand?.name.en} : '' + {mainhand?.name[locale]} : '' } function generateGridImage(position: number) { return (weapons[position]) ? - {weapons[position]?.name.en} : '' + {weapons[position]?.name[locale]} : '' } function sendSaveData() { @@ -96,10 +102,10 @@ const GridRep = (props: Props) => { const details = (
      -

      { (props.name) ? props.name : 'Untitled' }

      +

      { (props.name) ? props.name : t('no_title') }

      -
      { (props.raid) ? props.raid.name.en : 'No raid set' }
      - +
      { (props.raid) ? props.raid.name[locale] : t('no_raid') }
      +
      ) @@ -108,8 +114,8 @@ const GridRep = (props: Props) => {
      -

      { (props.name) ? props.name : 'Untitled' }

      -
      { (props.raid) ? props.raid.name.en : 'No raid set' }
      +

      { (props.name) ? props.name : t('no_title') }

      +
      { (props.raid) ? props.raid.name[locale] : t('no_raid') }
      { (!props.user || (account.user && account.user.id !== props.user.id)) ?
      ) diff --git a/components/RaidDropdown/index.tsx b/components/RaidDropdown/index.tsx index 47ad6b26..72a27330 100644 --- a/components/RaidDropdown/index.tsx +++ b/components/RaidDropdown/index.tsx @@ -1,4 +1,6 @@ import React, { useCallback, useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' import { appState } from '~utils/appState' import api from '~utils/api' @@ -14,6 +16,10 @@ interface Props { } const RaidDropdown = React.forwardRef(function useFieldSet(props, ref) { + const router = useRouter() + const { t } = useTranslation('common') + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const [raids, setRaids] = useState() const raidGroups = [ @@ -37,7 +43,7 @@ const RaidDropdown = React.forwardRef(function useFiel id: '0', name: { en: 'All raids', - jp: '全て' + ja: '全てのマルチ' }, level: 0, group: 0, @@ -65,7 +71,7 @@ const RaidDropdown = React.forwardRef(function useFiel const options = raids && raids.length > 0 && raids[index].length > 0 && raids[index].sort((a, b) => a.element - b.element).map((item, i) => { return ( - + ) }) diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 6609bfe2..dd3ce87c 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -8,6 +8,34 @@ "new": "New", "wiki": "View more on gbf.wiki" }, + "elements": { + "null": "Null", + "wind": "Wind", + "fire": "Fire", + "water": "Water", + "earth": "Earth", + "dark": "Dark", + "light": "Light", + "full": { + "all": "All elements", + "null": "Null", + "wind": "Wind", + "fire": "Fire", + "water": "Water", + "earth": "Earth", + "dark": "Dark", + "light": "Light" + } + }, + "recency": { + "all_time": "All time", + "last_day": "Last day", + "last_week": "Last week", + "last_month": "Last month", + "last_3_months": "Last 3 months", + "last_6_months": "Last 6 months", + "last_year": "Last year" + }, "summons": { "main": "Main Summon", "friend": "Friend Summon", @@ -66,5 +94,8 @@ "loading": "Loading teams...", "not_found": "No teams found" }, - "coming_soon": "Coming Soon" + "coming_soon": "Coming Soon", + "no_title": "Untitled", + "no_raid": "No raid", + "no_user": "Anonymous" } diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index 9ba8d7a3..ee0afd09 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -8,6 +8,34 @@ "new": "作成", "wiki": "gbf.wikiで詳しく見る" }, + "elements": { + "null": "無", + "wind": "風", + "fire": "火", + "water": "水", + "earth": "土", + "dark": "闇", + "light": "光", + "full": { + "all": "全属性", + "null": "無属性", + "wind": "風属性", + "fire": "火属性", + "water": "水属性", + "earth": "土属性", + "dark": "闇属性", + "light": "光属性" + } + }, + "recency": { + "all_time": "全ての期間", + "last_day": "1日", + "last_week": "7日", + "last_month": "1ヶ月", + "last_3_months": "3ヶ月", + "last_6_months": "6ヶ月", + "last_year": "1年" + }, "summons": { "main": "メイン", "friend": "フレンド", @@ -66,6 +94,9 @@ "loading": "ロード中...", "not_found": "編成は見つかりませんでした" }, - "coming_soon": "開発中" + "coming_soon": "開発中", + "no_title": "無題", + "no_raid": "マルチなし", + "no_user": "無名" } \ No newline at end of file From 758ea1be320d871577686e89591387182de2c5f3 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 01:18:08 -0800 Subject: [PATCH 14/34] Remove language from accountState --- utils/accountState.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/utils/accountState.tsx b/utils/accountState.tsx index 3249ecf9..d57df6a2 100644 --- a/utils/accountState.tsx +++ b/utils/accountState.tsx @@ -5,7 +5,6 @@ interface AccountState { account: { authorized: boolean - language: 'en' | 'jp' user: { id: string username: string @@ -18,7 +17,6 @@ interface AccountState { export const initialAccountState: AccountState = { account: { authorized: false, - language: 'en', user: undefined } } From 6f843bbb6f089a22bb26c7c8a092e669622b8966 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 01:18:17 -0800 Subject: [PATCH 15/34] Update incorrect key for en localization --- public/locales/en/common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/locales/en/common.json b/public/locales/en/common.json index dd3ce87c..4eafeefd 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -2,7 +2,7 @@ "buttons": { "copy": "Copy link", "delete": "Delete team", - "edit_info": "Edit info", + "show_info": "Edit info", "hide_info": "Hide info", "menu": "Menu", "new": "New", From c626038f6409bbf15709a2548348af58948d79fc Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 02:29:14 -0800 Subject: [PATCH 16/34] Rudimentary unauth language switch I can't figure out how to make the current page persist when switching. Next.js adds a /ja prefix to the path and when switching to Japanese, but it doesn't remove it when switching back to English. This documentation sucks! --- components/HeaderMenu/index.scss | 69 +++++++++++++++++++++++++++++++- components/HeaderMenu/index.tsx | 38 ++++++++++++++++-- public/locales/en/common.json | 1 + public/locales/ja/common.json | 1 + 4 files changed, 105 insertions(+), 4 deletions(-) diff --git a/components/HeaderMenu/index.scss b/components/HeaderMenu/index.scss index c12e4b75..1d3d501d 100644 --- a/components/HeaderMenu/index.scss +++ b/components/HeaderMenu/index.scss @@ -26,6 +26,73 @@ padding: 6px 12px; } + &.language { + align-items: center; + display: flex; + flex-direction: row; + gap: $unit; + padding-right: $unit; + + span { + flex-grow: 1; + } + + .Switch { + $height: 24px; + + background: $grey-60; + border-radius: calc($height / 2); + border: none; + position: relative; + width: 44px; + height: $height; + + &:hover { + cursor: pointer; + } + + .Thumb { + $diameter: 18px; + + background: white; + border-radius: calc($diameter / 2); + display: block; + height: $diameter; + width: $diameter; + transition: transform 100ms; + transform: translateX(-2px); + z-index: 3; + + &:hover { + cursor: pointer; + } + + &[data-state="checked"] { + background: white; + transform: translateX(17px); + } + } + + .left, .right { + color: white; + font-size: 10px; + font-weight: $bold; + position: absolute; + z-index: 2; + } + + .left { + top: 6px; + left: 6px; + } + + .right { + top: 6px; + right: 5px; + } + } + } + a { color: $grey-40; } @@ -54,7 +121,7 @@ img { $diameter: 32px; - border-radius: $diameter / 2; + border-radius: calc($diameter / 2); height: $diameter; width: $diameter; } diff --git a/components/HeaderMenu/index.tsx b/components/HeaderMenu/index.tsx index 1b437275..abff0ba6 100644 --- a/components/HeaderMenu/index.tsx +++ b/components/HeaderMenu/index.tsx @@ -1,8 +1,11 @@ -import React from 'react' -import Link from 'next/link' +import React, { useEffect, useState } from 'react' import { useCookies } from 'react-cookie' +import Router, { useRouter } from 'next/router' import { useTranslation } from 'next-i18next' +import Link from 'next/link' +import * as Switch from '@radix-ui/react-switch' + import AboutModal from '~components/AboutModal' import AccountModal from '~components/AccountModal' import LoginModal from '~components/LoginModal' @@ -17,10 +20,29 @@ interface Props { } const HeaderMenu = (props: Props) => { + const router = useRouter() const { t } = useTranslation('common') - + const [accountCookies] = useCookies(['account']) const [userCookies] = useCookies(['user']) + const [cookies, setCookies] = useCookies() + + const [checked, setChecked] = useState(false) + + console.log(`Currently: ${checked} ${cookies['NEXT_LOCALE']}`) + + useEffect(() => { + const locale = cookies['NEXT_LOCALE'] + setChecked((locale === 'ja') ? true : false) + }, [cookies]) + + function handleCheckedChange(value: boolean) { + setChecked(value) + setCookies('NEXT_LOCALE', (value) ? 'ja' : 'en', { path: '/'}) + + // TODO: How do we persist the current page when changing languages? + window.location.href = '/' + } function authItems() { return ( @@ -72,6 +94,16 @@ const HeaderMenu = (props: Props) => { function unauthItems() { return (
        +
        +
      • + {t('menu.language')} + + + JP + EN + +
      • +
        diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 4eafeefd..1cba56d4 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -76,6 +76,7 @@ "menu": { "about": "About", "guides": "Guides", + "language": "Language", "saved": "Saved", "settings": "Settings", "teams": "Teams", diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index ee0afd09..e76b09ca 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -76,6 +76,7 @@ "menu": { "about": "このサイトについて", "guides": "攻略", + "language": "言語", "saved": "保存した編成", "settings": "アカウント設定", "teams": "編成一覧", From 92d9797c0d19796b4adc25d042eee1104d77f573 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 02:29:36 -0800 Subject: [PATCH 17/34] Don't show hearts on GridReps if user is logged out --- components/GridRep/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/GridRep/index.tsx b/components/GridRep/index.tsx index ba265a6a..14543b06 100644 --- a/components/GridRep/index.tsx +++ b/components/GridRep/index.tsx @@ -109,7 +109,7 @@ const GridRep = (props: Props) => {
    ) - + const detailsWithUsername = (
    @@ -117,7 +117,7 @@ const GridRep = (props: Props) => {

    { (props.name) ? props.name : t('no_title') }

    { (props.raid) ? props.raid.name[locale] : t('no_raid') }
    - { (!props.user || (account.user && account.user.id !== props.user.id)) ? + { (account.authorized && (props.user && account.user && account.user.id !== props.user.id)) ?
    - +
  • + {t('menu.teams')} +
  • + +
  • +
    + {t('menu.guides')} + {t('menu.logout')} +
    +
  • -
  • - {t('menu.teams')} -
  • - -
  • -
    - {t('menu.guides')} - {t('menu.logout')} -
    -
  • -
    + +
    From e902cdc1f59e3ebaca1c7152b810e8e0dbc07533 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 10:55:09 -0800 Subject: [PATCH 21/34] Fix HeaderMenu Coming Soon tag --- components/HeaderMenu/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/HeaderMenu/index.tsx b/components/HeaderMenu/index.tsx index 0ceec165..bd375899 100644 --- a/components/HeaderMenu/index.tsx +++ b/components/HeaderMenu/index.tsx @@ -111,7 +111,7 @@ const HeaderMenu = (props: Props) => {
  • {t('menu.guides')} - {t('menu.logout')} + {t('menu.coming_soon')}
  • From 269152ee58e5dc5212fb08a334014550facbf426 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 10:55:28 -0800 Subject: [PATCH 22/34] Actually fix tag --- components/HeaderMenu/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/HeaderMenu/index.tsx b/components/HeaderMenu/index.tsx index bd375899..e6dcbae5 100644 --- a/components/HeaderMenu/index.tsx +++ b/components/HeaderMenu/index.tsx @@ -111,7 +111,7 @@ const HeaderMenu = (props: Props) => {
  • {t('menu.guides')} - {t('menu.coming_soon')} + {t('coming_soon')}
  • From d79a13dc8a77b01bfb472fd0dbf2f0e593a14319 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 13:24:39 -0800 Subject: [PATCH 23/34] Localized signup and login --- components/LoginModal/index.tsx | 26 +++++++++++-------- components/SignupModal/index.tsx | 37 +++++++++++++++------------ public/locales/en/common.json | 42 +++++++++++++++++++++++++++++++ public/locales/ja/common.json | 43 ++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 27 deletions(-) diff --git a/components/LoginModal/index.tsx b/components/LoginModal/index.tsx index 2b79c49e..eb11dc41 100644 --- a/components/LoginModal/index.tsx +++ b/components/LoginModal/index.tsx @@ -1,5 +1,6 @@ import React, { useState } from 'react' import { useCookies } from 'react-cookie' +import { useTranslation } from 'react-i18next' import { AxiosResponse } from 'axios' import * as Dialog from '@radix-ui/react-dialog' @@ -24,6 +25,8 @@ interface ErrorMap { const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ const LoginModal = (props: Props) => { + const { t } = useTranslation('common') + // Set up form states and error handling const [formValid, setFormValid] = useState(false) const [errors, setErrors] = useState({ @@ -49,16 +52,16 @@ const LoginModal = (props: Props) => { switch(name) { case 'email': if (value.length == 0) - newErrors.email = 'Please enter your email' + newErrors.email = t('modals.login.errors.empty_email') else if (!emailRegex.test(value)) - newErrors.email = 'That email address is not valid' + newErrors.email = t('modals.login.errors.invalid_email') else newErrors.email = '' break case 'password': newErrors.password = value.length == 0 - ? 'Please enter your password' + ? t('modals.login.errors.empty_password') : '' break @@ -117,21 +120,22 @@ const LoginModal = (props: Props) => { access_token: response.data.access_token } - setCookies('account', cookieObj, { path: '/'}) + setCookies('account', cookieObj, { path: '/' }) } function storeUserInfo(response: AxiosResponse) { const user = response.data.user + setCookies('NEXT_LOCALE', user.language, { path: '/' }) + const cookieObj = { picture: user.picture.picture, element: user.picture.element, language: user.language, } - setCookies('user', cookieObj, { path: '/'}) + setCookies('user', cookieObj, { path: '/' }) - accountState.account.language = user.language accountState.account.user = { id: user.id, username: user.username, @@ -155,13 +159,13 @@ const LoginModal = (props: Props) => {
  • - Log in + {t('menu.login')}
  • event.preventDefault() }>
    - Log in + {t('modals.login.title')} @@ -172,7 +176,7 @@ const LoginModal = (props: Props) => {
    {
    - + diff --git a/components/SignupModal/index.tsx b/components/SignupModal/index.tsx index 2c637753..7f3dadf7 100644 --- a/components/SignupModal/index.tsx +++ b/components/SignupModal/index.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react' import { useCookies } from 'react-cookie' +import { Trans, useTranslation } from 'next-i18next' import { AxiosResponse } from 'axios' import * as Dialog from '@radix-ui/react-dialog' @@ -26,6 +27,8 @@ interface ErrorMap { const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ const SignupModal = (props: Props) => { + const { t } = useTranslation('common') + // Set up form states and error handling const [formValid, setFormValid] = useState(false) const [errors, setErrors] = useState({ @@ -95,9 +98,9 @@ const SignupModal = (props: Props) => { language: user.language, } + // TODO: Set language setCookies('user', cookieObj, { path: '/'}) - accountState.account.language = user.language accountState.account.user = { id: user.id, username: user.username, @@ -138,7 +141,7 @@ const SignupModal = (props: Props) => { validateName(fieldName, value) } else { - newErrors[fieldName] = `This ${fieldName} is already in use` + newErrors[fieldName] = t('modals.signup.errors.field_in_use', { field: fieldName}) setErrors(newErrors) setFormValid(false) } @@ -150,9 +153,9 @@ const SignupModal = (props: Props) => { switch(fieldName) { case 'username': if (value.length < 3) - newErrors.username = 'Username must be at least 3 characters' + newErrors.username = t('modals.signup.errors.username_too_short') else if (value.length > 20) - newErrors.username = 'Username must be less than 20 characters' + newErrors.username = t('modals.signup.errors.username_too_long') else newErrors.username = '' @@ -161,7 +164,7 @@ const SignupModal = (props: Props) => { case 'email': newErrors.email = emailRegex.test(value) ? '' - : 'That email address is not valid' + : t('modals.signup.errors.invalid_email') break default: @@ -180,20 +183,20 @@ const SignupModal = (props: Props) => { switch(name) { case 'password': newErrors.password = passwordInput.current?.value.includes(usernameInput.current?.value!) - ? 'Your password should not contain your username' + ? t('modals.signup.errors.password_contains_username') : '' break case 'password': newErrors.password = value.length < 8 - ? 'Password must be at least 8 characters' + ? t('modals.signup.errors.password_too_short') : '' break case 'confirm_password': newErrors.passwordConfirmation = passwordInput.current?.value === passwordConfirmationInput.current?.value ? '' - : 'Your passwords don\'t match' + : t('modals.signup.errors.passwords_dont_match') break default: @@ -231,13 +234,13 @@ const SignupModal = (props: Props) => {
  • - Sign up + {t('menu.signup')}
  • event.preventDefault() }>
    - Sign up + {t('modals.signup.title')} @@ -248,7 +251,7 @@ const SignupModal = (props: Props) => {
    {
    {
    {
    - + - By signing up, I agree to the
    Terms and Conditions and Usage Guidelines. + + By signing up, I agree to the Privacy PolicyUsage Guidelines. +
    diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 1cba56d4..8620f84a 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -54,6 +54,22 @@ "cancel": "Nevermind" } }, + "login": { + "title": "Log in", + "buttons": { + "confirm": "Log in" + }, + "errors": { + "empty_email": "Please enter your email", + "empty_password": "Please enter your password", + "invalid_email": "That email address is not valid", + "invalid_credentials": "Your email address or password is incorrect" + }, + "placeholders": { + "email": "Email address", + "password": "Password" + } + }, "settings": { "title": "Account Settings", "labels": { @@ -71,14 +87,40 @@ "buttons": { "confirm": "Save settings" } + }, + "signup": { + "title": "Create an account", + "buttons": { + "confirm": "Sign up" + }, + "agreement": "By signing up, I agree to the
    <2>Privacy Policy and <1>Usage Guidelines.", + "errors": { + "field_in_use": "This {{field}} is already in use", + "empty_email": "Please enter your email", + "invalid_email": "That email address is not valid", + "username_too_short": "Username must be at least 3 characters", + "username_too_long": "Username must be less than 20 characters", + "empty_password": "Please enter your password", + "password_contains_username": "Your password should not contain your username", + "password_too_short": "Password must be at least 8 characters", + "mismatched_passwords": "Your passwords don't match" + }, + "placeholders": { + "username": "Username", + "email": "Email address", + "password": "Password", + "password_confirm": "Password (again)" + } } }, "menu": { "about": "About", "guides": "Guides", "language": "Language", + "login": "Log in", "saved": "Saved", "settings": "Settings", + "signup": "Sign up", "teams": "Teams", "logout": "Logout" }, diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index e76b09ca..e77619e9 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -54,6 +54,22 @@ "cancel": "キャンセル" } }, + "login": { + "title": "ログイン", + "buttons": { + "confirm": "ログイン" + }, + "errors": { + "empty_email": "メールアドレスを入力して下さい", + "empty_password": "パスワードを入力して下さい", + "invalid_email": "メールアドレスは有効ではありません", + "invalid_credentials": "パスワードまたはメールアドレスが違います" + }, + "placeholders": { + "email": "メールアドレス", + "password": "パスワード" + } + }, "settings": { "title": "アカウント設定", "labels": { @@ -71,14 +87,41 @@ "buttons": { "confirm": "設定を保存する" } + }, + "signup": { + "title": "アカウント登録", + "buttons": { + "confirm": "登録する" + }, + "agreement": "続行することで<1>利用規約に同意し、
    <1>プライバシーポリシーを読んだものとみなされます。", + "errors": { + "field_in_use": "入力された{{field}}は既に登録済みです", + "empty_email": "メールアドレスを入力して下さい", + "invalid_email": "メールアドレスは有効ではありません", + "username_too_short": "ユーザーネームは3文字以上で入力してください", + "username_too_long": "ユーザーネームは20文字以内で入力してください", + "empty_password": "パスワードを入力して下さい", + "password_contains_username": "パスワードにはユーザー名を含めないでください", + "password_too_short": "パスワードは8文字以上で入力してください", + "mismatched_passwords": "パスワードとパスワード確認を確かめてください", + "invalid_credentials": "パスワードまたはメールアドレスが違います" + }, + "placeholders": { + "username": "ユーザー名", + "email": "メールアドレス", + "password": "パスワード", + "password_confirm": "パスワード確認" + } } }, "menu": { "about": "このサイトについて", "guides": "攻略", "language": "言語", + "login": "ログイン", "saved": "保存した編成", "settings": "アカウント設定", + "signup": "登録", "teams": "編成一覧", "logout": "ログアウト" }, From 497c309bd1f54fd21c6277c442ef18d21bd0ec2b Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 13:32:03 -0800 Subject: [PATCH 24/34] Get logged in language switching working --- components/AccountModal/index.tsx | 29 ++++++++++++++++++----------- components/HeaderMenu/index.tsx | 1 - 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/components/AccountModal/index.tsx b/components/AccountModal/index.tsx index 40321d96..d79a26fb 100644 --- a/components/AccountModal/index.tsx +++ b/components/AccountModal/index.tsx @@ -24,12 +24,11 @@ const AccountModal = () => { const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' // Cookies - const [accountCookies] = useCookies(['account']) - const [userCookies, setUserCookies] = useCookies(['user']) + const [cookies, setCookies] = useCookies() - const headers = (accountCookies.account != null) ? { + const headers = (cookies.account != null) ? { headers: { - 'Authorization': `Bearer ${accountCookies.account.access_token}` + 'Authorization': `Bearer ${cookies.account.access_token}` } } : {} @@ -45,9 +44,10 @@ const AccountModal = () => { const privateSelect = React.createRef() useEffect(() => { - if (userCookies.user) setPicture(userCookies.user.picture) - if (userCookies.user) setLanguage(userCookies.user.language) - }, [userCookies]) + console.log(cookies.user) + if (cookies.user) setPicture(cookies.user.picture) + if (cookies.user) setLanguage(cookies.user.language) + }, [cookies]) const pictureOptions = ( pictureData.sort((a, b) => (a.name.en > b.name.en) ? 1 : -1).map((item, i) => { @@ -83,7 +83,7 @@ const AccountModal = () => { } } - api.endpoints.users.update(accountCookies.account.user_id, object, headers) + api.endpoints.users.update(cookies.account.user_id, object, headers) .then(response => { const user = response.data.user @@ -93,9 +93,8 @@ const AccountModal = () => { language: user.language, } - setUserCookies('user', cookieObj, { path: '/'}) + setCookies('user', cookieObj, { path: '/'}) - accountState.account.language = user.language accountState.account.user = { id: user.id, username: user.username, @@ -104,9 +103,17 @@ const AccountModal = () => { } setOpen(false) + changeLanguage(user.language) }) } + function changeLanguage(newLanguage: string) { + if (newLanguage !== router.locale) { + setCookies('NEXT_LOCALE', language, { path: '/'}) + router.push(router.asPath, undefined, { locale: language }) + } + } + function openChange(open: boolean) { setOpen(open) } @@ -158,7 +165,7 @@ const AccountModal = () => {
    diff --git a/components/HeaderMenu/index.tsx b/components/HeaderMenu/index.tsx index e6dcbae5..24b4ff78 100644 --- a/components/HeaderMenu/index.tsx +++ b/components/HeaderMenu/index.tsx @@ -40,7 +40,6 @@ const HeaderMenu = (props: Props) => { const language = (value) ? 'ja' : 'en' setCookies('NEXT_LOCALE', language, { path: '/'}) router.push(router.asPath, undefined, { locale: language }) - // router.reload() } function authItems() { From 9e3ab298e86d82a68a6f84811471274e88e1e8d5 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 13:54:14 -0800 Subject: [PATCH 25/34] Profile wasn't properly localizing --- pages/[username].tsx | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/pages/[username].tsx b/pages/[username].tsx index 50bec0fe..46b34e34 100644 --- a/pages/[username].tsx +++ b/pages/[username].tsx @@ -1,6 +1,7 @@ import React, { useCallback, useEffect, useState } from 'react' import Head from 'next/head' import { useRouter } from 'next/router' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import { useCookies } from 'react-cookie' import api from '~utils/api' @@ -177,4 +178,23 @@ const ProfileRoute: React.FC = () => { ) } -export default ProfileRoute \ No newline at end of file +export async function getStaticPaths() { + return { + paths: [ + // Object variant: + { params: { username: 'string' } }, + ], + fallback: true, + } +} + +export async function getStaticProps({ locale }: { locale: string }) { + return { + props: { + ...(await serverSideTranslations(locale, ['common'])), + // Will be passed to the page component as props + }, + } +} + +export default ProfileRoute From a109a85232a61be323483b4535cd102c25e3ff54 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 13:54:23 -0800 Subject: [PATCH 26/34] Send locale when creating a user --- components/SignupModal/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/SignupModal/index.tsx b/components/SignupModal/index.tsx index 7f3dadf7..5a28b70e 100644 --- a/components/SignupModal/index.tsx +++ b/components/SignupModal/index.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react' import { useCookies } from 'react-cookie' +import { useRouter } from 'next/router' import { Trans, useTranslation } from 'next-i18next' import { AxiosResponse } from 'axios' @@ -27,6 +28,7 @@ interface ErrorMap { const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ const SignupModal = (props: Props) => { + const router = useRouter() const { t } = useTranslation('common') // Set up form states and error handling @@ -59,7 +61,8 @@ const SignupModal = (props: Props) => { username: usernameInput.current?.value, email: emailInput.current?.value, password: passwordInput.current?.value, - password_confirmation: passwordConfirmationInput.current?.value + password_confirmation: passwordConfirmationInput.current?.value, + language: router.locale } } From 75f77ced203295793fac37e187934f2c80253d5c Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 13:54:46 -0800 Subject: [PATCH 27/34] Switch locale when logging in --- components/AccountModal/index.tsx | 4 ++-- components/LoginModal/index.tsx | 13 +++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/components/AccountModal/index.tsx b/components/AccountModal/index.tsx index d79a26fb..87f0851a 100644 --- a/components/AccountModal/index.tsx +++ b/components/AccountModal/index.tsx @@ -109,8 +109,8 @@ const AccountModal = () => { function changeLanguage(newLanguage: string) { if (newLanguage !== router.locale) { - setCookies('NEXT_LOCALE', language, { path: '/'}) - router.push(router.asPath, undefined, { locale: language }) + setCookies('NEXT_LOCALE', newLanguage, { path: '/'}) + router.push(router.asPath, undefined, { locale: newLanguage }) } } diff --git a/components/LoginModal/index.tsx b/components/LoginModal/index.tsx index eb11dc41..831e35d5 100644 --- a/components/LoginModal/index.tsx +++ b/components/LoginModal/index.tsx @@ -1,5 +1,6 @@ import React, { useState } from 'react' import { useCookies } from 'react-cookie' +import Router, { useRouter } from 'next/router' import { useTranslation } from 'react-i18next' import { AxiosResponse } from 'axios' @@ -25,6 +26,7 @@ interface ErrorMap { const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ const LoginModal = (props: Props) => { + const router = useRouter() const { t } = useTranslation('common') // Set up form states and error handling @@ -126,8 +128,6 @@ const LoginModal = (props: Props) => { function storeUserInfo(response: AxiosResponse) { const user = response.data.user - setCookies('NEXT_LOCALE', user.language, { path: '/' }) - const cookieObj = { picture: user.picture.picture, element: user.picture.element, @@ -144,7 +144,16 @@ const LoginModal = (props: Props) => { } accountState.account.authorized = true + setOpen(false) + changeLanguage(user.language) + } + + function changeLanguage(newLanguage: string) { + if (newLanguage !== router.locale) { + setCookies('NEXT_LOCALE', newLanguage, { path: '/'}) + router.push(router.asPath, undefined, { locale: newLanguage }) + } } function openChange(open: boolean) { From 5a184ed8aa81b61b3de0e8cc317b4ada391902d3 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 14:01:57 -0800 Subject: [PATCH 28/34] Localized saved teams --- pages/[username].tsx | 9 ++++++--- pages/saved.tsx | 21 +++++++++++++++++---- pages/teams.tsx | 2 +- public/locales/en/common.json | 5 +++++ public/locales/ja/common.json | 5 +++++ 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/pages/[username].tsx b/pages/[username].tsx index 46b34e34..5a3d4243 100644 --- a/pages/[username].tsx +++ b/pages/[username].tsx @@ -1,8 +1,10 @@ import React, { useCallback, useEffect, useState } from 'react' import Head from 'next/head' -import { useRouter } from 'next/router' -import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import { useCookies } from 'react-cookie' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import api from '~utils/api' @@ -14,6 +16,7 @@ const ProfileRoute: React.FC = () => { const router = useRouter() const { username } = router.query + const { t } = useTranslation('common') const [cookies] = useCookies(['account']) const [found, setFound] = useState(false) @@ -170,7 +173,7 @@ const ProfileRoute: React.FC = () => { { (parties.length == 0) ?
    -

    { (loading) ? 'Loading teams...' : 'No teams found' }

    +

    { (loading) ? t('teams.loading') : t('teams.not_found') }

    : '' } diff --git a/pages/saved.tsx b/pages/saved.tsx index 44811d0c..d42b5627 100644 --- a/pages/saved.tsx +++ b/pages/saved.tsx @@ -1,8 +1,11 @@ import React, { useCallback, useEffect, useState } from 'react' import Head from 'next/head' -import { useRouter } from 'next/router' import { useCookies } from 'react-cookie' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + import clonedeep from 'lodash.clonedeep' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import api from '~utils/api' @@ -12,6 +15,7 @@ import FilterBar from '~components/FilterBar' const SavedRoute: React.FC = () => { const router = useRouter() + const { t } = useTranslation('common') // Cookies const [cookies] = useCookies(['account']) @@ -143,7 +147,7 @@ const SavedRoute: React.FC = () => { return (
    - Your saved Teams + {t('saved.title')} @@ -155,7 +159,7 @@ const SavedRoute: React.FC = () => { -

    Your saved Teams

    +

    {t('saved.title')}

    @@ -182,7 +186,7 @@ const SavedRoute: React.FC = () => { { (parties.length == 0) ?
    -

    { (loading) ? 'Loading saved teams...' : 'You haven't saved any teams yet' }

    +

    { (loading) ? t('saved.loading') : t('saved.not_found') }

    : '' }
    @@ -190,4 +194,13 @@ const SavedRoute: React.FC = () => { ) } +export async function getStaticProps({ locale }: { locale: string }) { + return { + props: { + ...(await serverSideTranslations(locale, ['common'])), + // Will be passed to the page component as props + }, + } +} + export default SavedRoute \ No newline at end of file diff --git a/pages/teams.tsx b/pages/teams.tsx index 55b115c3..2a513939 100644 --- a/pages/teams.tsx +++ b/pages/teams.tsx @@ -3,8 +3,8 @@ import Head from 'next/head' import { useRouter } from 'next/router' import { useCookies } from 'react-cookie' - import { useTranslation } from 'next-i18next' + import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import clonedeep from 'lodash.clonedeep' diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 8620f84a..191ab614 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -132,6 +132,11 @@ "summons": "Summons" } }, + "saved": { + "title": "Your saved Teams", + "loading": "Loading saved teams...", + "not_found": "You haven't saved any teams" + }, "teams": { "title": "Discover Teams", "loading": "Loading teams...", diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index e77619e9..f4018399 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -133,6 +133,11 @@ "summons": "召喚石" } }, + "saved": { + "title": "保存した編成", + "loading": "ロード中...", + "not_found": "編成はまだ保存していません" + }, "teams": { "title": "編成一覧", "loading": "ロード中...", From dfd2bbff1985bb150666bc72fa14c5453354c5d3 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 14:30:34 -0800 Subject: [PATCH 29/34] Localize WeaponModal and AxSelect --- components/AxSelect/index.tsx | 47 ++++++++++++++++++++++++-------- components/WeaponModal/index.tsx | 18 ++++++++---- public/locales/en/common.json | 20 ++++++++++++++ public/locales/ja/common.json | 20 ++++++++++++++ 4 files changed, 88 insertions(+), 17 deletions(-) diff --git a/components/AxSelect/index.tsx b/components/AxSelect/index.tsx index 636261ba..510920c9 100644 --- a/components/AxSelect/index.tsx +++ b/components/AxSelect/index.tsx @@ -1,4 +1,7 @@ import React, { useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + import classNames from 'classnames' import { axData } from '~utils/axData' @@ -19,6 +22,10 @@ interface Props { } const AXSelect = (props: Props) => { + const router = useRouter() + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const { t } = useTranslation('common') + // Set up form states and error handling const [errors, setErrors] = useState({ axValue1: '', @@ -84,7 +91,7 @@ const AXSelect = (props: Props) => { if (modifierSet == 0) { axOptionElements = axOptions.map((ax, i) => { return ( - + ) }) } else { @@ -103,14 +110,14 @@ const AXSelect = (props: Props) => { const secondaryAxOptions = primarySkill.secondary axOptionElements = secondaryAxOptions.map((ax, i) => { return ( - + ) }) } } } - axOptionElements?.unshift() + axOptionElements?.unshift() return axOptionElements } @@ -156,11 +163,19 @@ const AXSelect = (props: Props) => { let newErrors = {...errors} if (value < primaryAxSkill.minValue) { - newErrors.axValue1 = `${primaryAxSkill.name.en} must be at least ${primaryAxSkill.minValue}${ (primaryAxSkill.suffix) ? primaryAxSkill.suffix : ''}` + newErrors.axValue1 = t('ax.errors.value_too_low', { + name: primaryAxSkill.name[locale], + minValue: primaryAxSkill.minValue, + suffix: (primaryAxSkill.suffix) ? primaryAxSkill.suffix : '' + }) } else if (value > primaryAxSkill.maxValue) { - newErrors.axValue1 = `${primaryAxSkill.name.en} cannot be greater than ${primaryAxSkill.maxValue}${ (primaryAxSkill.suffix) ? primaryAxSkill.suffix : ''}` + newErrors.axValue1 = t('ax.errors.value_too_high', { + name: primaryAxSkill.name[locale], + maxValue: primaryAxSkill.minValue, + suffix: (primaryAxSkill.suffix) ? primaryAxSkill.suffix : '' + }) } else if (!value || value <= 0) { - newErrors.axValue1 = `${primaryAxSkill.name.en} must have a value` + newErrors.axValue1 = t('ax.errors.value_empty', { name: primaryAxSkill.name[locale] }) } else { newErrors.axValue1 = '' } @@ -179,13 +194,21 @@ const AXSelect = (props: Props) => { if (secondaryAxSkill) { if (value < secondaryAxSkill.minValue) { - newErrors.axValue2 = `${secondaryAxSkill.name.en} must be at least ${secondaryAxSkill.minValue}${ (secondaryAxSkill.suffix) ? secondaryAxSkill.suffix : ''}` + newErrors.axValue2 = t('ax.errors.value_too_low', { + name: secondaryAxSkill.name[locale], + minValue: secondaryAxSkill.minValue, + suffix: (secondaryAxSkill.suffix) ? secondaryAxSkill.suffix : '' + }) } else if (value > secondaryAxSkill.maxValue) { - newErrors.axValue2 = `${secondaryAxSkill.name.en} cannot be greater than ${secondaryAxSkill.maxValue}${ (secondaryAxSkill.suffix) ? secondaryAxSkill.suffix : ''}` + newErrors.axValue2 = t('ax.errors.value_too_high', { + name: secondaryAxSkill.name[locale], + maxValue: secondaryAxSkill.minValue, + suffix: (secondaryAxSkill.suffix) ? secondaryAxSkill.suffix : '' + }) } else if (!secondaryAxSkill.suffix && value % 1 !== 0) { - newErrors.axValue2 = `${secondaryAxSkill.name.en} must be a whole number` + newErrors.axValue2 = t('ax.errors.value_not_whole', { name: secondaryAxSkill.name[locale] }) } else if (primaryAxValue <= 0) { - newErrors.axValue1 = `${primaryAxSkill.name.en} must have a value` + newErrors.axValue1 = t('ax.errors.value_empty', { name: primaryAxSkill.name[locale] }) } else { newErrors.axValue2 = '' } @@ -224,7 +247,7 @@ const AXSelect = (props: Props) => {
    - +

    {errors.axValue1}

    @@ -232,7 +255,7 @@ const AXSelect = (props: Props) => {
    - +

    {errors.axValue2}

    diff --git a/components/WeaponModal/index.tsx b/components/WeaponModal/index.tsx index 69e741c8..1f8a684c 100644 --- a/components/WeaponModal/index.tsx +++ b/components/WeaponModal/index.tsx @@ -1,6 +1,9 @@ import React, { useState } from 'react' import { useCookies } from 'react-cookie' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' import { AxiosResponse } from 'axios' + import * as Dialog from '@radix-ui/react-dialog' import AXSelect from '~components/AxSelect' @@ -33,6 +36,10 @@ interface Props { } const WeaponModal = (props: Props) => { + const router = useRouter() + const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const { t } = useTranslation('common') + // Cookies const [cookies] = useCookies(['account']) const headers = (cookies.account != null) ? { @@ -122,7 +129,7 @@ const WeaponModal = (props: Props) => { const elementSelect = () => { return (
    -

    Element

    +

    {t('modals.weapon.subtitles.element')}

    { const keySelect = () => { return (
    -

    Weapon Keys

    +

    {t('modals.weapon.subtitles.weapon_keys')}

    { ([2, 3, 17, 22].includes(props.gridWeapon.object.series)) ? { const axSelect = () => { return (
    +

    {t('modals.weapon.subtitles.ax_skills')}

    { event.preventDefault() }>
    - Modify Weapon - {props.gridWeapon.object.name.en} + {t('modals.weapon.title')} + {props.gridWeapon.object.name[locale]}
    @@ -203,7 +211,7 @@ const WeaponModal = (props: Props) => { { (props.gridWeapon.object.element == 0) ? elementSelect() : '' } { ([2, 3, 17, 24].includes(props.gridWeapon.object.series)) ? keySelect() : '' } { (props.gridWeapon.object.ax > 0) ? axSelect() : '' } - +
    diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 191ab614..1b4c632b 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -1,4 +1,13 @@ { + "ax": { + "no_skill": "No AX Skill", + "errors": { + "value_too_low": "{{name}} must be at least {{minValue}}{{suffix}}", + "value_too_high": "{{name}} cannot be greater than {{maxValue}}{{suffix}}", + "value_not_whole": "{{name}} must be a whole number", + "value_empty": "{{name}} must have a value" + } + }, "buttons": { "copy": "Copy link", "delete": "Delete team", @@ -111,6 +120,17 @@ "password": "Password", "password_confirm": "Password (again)" } + }, + "weapon": { + "title": "Modify Weapon", + "buttons": { + "confirm": "Save weapon" + }, + "subtitles": { + "element": "Element", + "ax_skills": "AX Skills", + "weapon_keys": "Weapon Keys" + } } }, "menu": { diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index f4018399..eee473e1 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -1,4 +1,13 @@ { + "ax": { + "no_skill": "EXスキルなし", + "errors": { + "value_too_low": "{{name}}は最低{{minValue}}{{suffix}}を入力してください", + "value_too_high": "{{name}}は最大{{maxValue}}を入力してください", + "value_not_whole": "{{name}}は整数でなければなりません", + "value_empty": "{{name}}を入力してください" + } + }, "buttons": { "copy": "リンクをコピー", "delete": "編成を削除", @@ -112,6 +121,17 @@ "password": "パスワード", "password_confirm": "パスワード確認" } + }, + "weapon": { + "title": "武器変更", + "buttons": { + "confirm": "武器を変更する" + }, + "subtitles": { + "element": "属性", + "ax_skills": "EXスキル", + "weapon_keys": "武器スキル" + } } }, "menu": { From 82a1231b040b9f2a5e135c9361f3eb9679acc1f0 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 14:35:44 -0800 Subject: [PATCH 30/34] Add missing translations to WeaponHovercard --- components/WeaponHovercard/index.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/WeaponHovercard/index.tsx b/components/WeaponHovercard/index.tsx index 5c497c5f..08521ea8 100644 --- a/components/WeaponHovercard/index.tsx +++ b/components/WeaponHovercard/index.tsx @@ -18,6 +18,7 @@ interface Props { interface KeyNames { [key: string]: { + [key: string]: string en: string, ja: string } @@ -104,7 +105,7 @@ const WeaponHovercard = (props: Props) => { const keysSection = (
    { (WeaponKeyNames[props.gridWeapon.object.series]) ? -
    { WeaponKeyNames[props.gridWeapon.object.series].en }s
    : '' +
    { WeaponKeyNames[props.gridWeapon.object.series][locale] }{ (locale === 'en') ? 's' : '' }
    : '' } { (props.gridWeapon.weapon_keys) ? @@ -120,7 +121,7 @@ const WeaponHovercard = (props: Props) => { const axSection = (
    -
    AX Skills
    +
    {t('modals.weapon.subtitles.ax_skills')}
    From c3186b28997fbac2c3d1f07998dadc5cd384fa7f Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 14:50:56 -0800 Subject: [PATCH 31/34] Add localizations for SearchModal --- components/CharacterUnit/index.tsx | 5 ++++- components/SummonUnit/index.tsx | 5 ++++- components/WeaponUnit/index.tsx | 7 +++++-- public/locales/en/common.json | 12 ++++++++++++ public/locales/ja/common.json | 12 ++++++++++++ 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/components/CharacterUnit/index.tsx b/components/CharacterUnit/index.tsx index 59e7c681..02d5bc24 100644 --- a/components/CharacterUnit/index.tsx +++ b/components/CharacterUnit/index.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react' import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' import classnames from 'classnames' import SearchModal from '~components/SearchModal' @@ -19,6 +20,8 @@ interface Props { } const CharacterUnit = (props: Props) => { + const { t } = useTranslation('common') + const router = useRouter() const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' @@ -72,7 +75,7 @@ const CharacterUnit = (props: Props) => { const editableImage = ( diff --git a/components/SummonUnit/index.tsx b/components/SummonUnit/index.tsx index adaa809c..ffdc73a4 100644 --- a/components/SummonUnit/index.tsx +++ b/components/SummonUnit/index.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react' import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' import classnames from 'classnames' import SearchModal from '~components/SearchModal' @@ -19,6 +20,8 @@ interface Props { } const SummonUnit = (props: Props) => { + const { t } = useTranslation('common') + const [imageUrl, setImageUrl] = useState('') const router = useRouter() @@ -80,7 +83,7 @@ const SummonUnit = (props: Props) => { const editableImage = ( diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index 9e8909dd..815a0d38 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react' -import Router, { useRouter } from 'next/router' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' import classnames from 'classnames' import SearchModal from '~components/SearchModal' @@ -23,6 +24,8 @@ interface Props { } const WeaponUnit = (props: Props) => { + const { t } = useTranslation('common') + const [imageUrl, setImageUrl] = useState('') const router = useRouter() @@ -85,7 +88,7 @@ const WeaponUnit = (props: Props) => { const editableImage = ( diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 1b4c632b..f6437472 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -157,6 +157,18 @@ "loading": "Loading saved teams...", "not_found": "You haven't saved any teams" }, + "search": { + "errors": { + "start_typing": "Start typing the name of a {{object}}", + "min_length": "Type at least 3 characters", + "no_results": "No results found for '{{query}}'" + }, + "placeholders": { + "weapon": "Search for a weapon...", + "summon": "Search for a summon...", + "character": "Search for a weapon..." + } + }, "teams": { "title": "Discover Teams", "loading": "Loading teams...", diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index eee473e1..c2711360 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -158,6 +158,18 @@ "loading": "ロード中...", "not_found": "編成はまだ保存していません" }, + "search": { + "errors": { + "start_typing": "{{object}}名を入力してください", + "min_length": "3文字以上を入力してください", + "no_results": "'{{query}}'の検索結果が見つかりませんでした" + }, + "placeholders": { + "weapon": "武器を検索...", + "summon": "召喚石を検索...", + "character": "キャラを検索..." + } + }, "teams": { "title": "編成一覧", "loading": "ロード中...", From 4ed07f83a28479f567d9acba282bee3cdbad40de Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 5 Mar 2022 16:30:52 -0800 Subject: [PATCH 32/34] They really call it Additional Weapons in Japanese too huh --- components/ExtraWeapons/index.tsx | 4 +++- public/locales/en/common.json | 1 + public/locales/ja/common.json | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/components/ExtraWeapons/index.tsx b/components/ExtraWeapons/index.tsx index 100d4ce6..235bb8f3 100644 --- a/components/ExtraWeapons/index.tsx +++ b/components/ExtraWeapons/index.tsx @@ -1,4 +1,5 @@ import React from 'react' +import { useTranslation } from 'next-i18next' import WeaponUnit from '~components/WeaponUnit' import './index.scss' @@ -15,10 +16,11 @@ interface Props { const ExtraWeapons = (props: Props) => { const numWeapons: number = 3 + const { t } = useTranslation('common') return (
    - Additional
    Weapons
    + {t('extra_weapons')}