mirror of
https://github.com/Qortal/names.git
synced 2025-06-14 02:11:20 +00:00
started internationalization
This commit is contained in:
parent
18151bfa9b
commit
aa7452713f
267
package-lock.json
generated
267
package-lock.json
generated
@ -12,10 +12,12 @@
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^7.0.1",
|
||||
"@mui/material": "^7.0.1",
|
||||
"i18next": "^25.1.2",
|
||||
"jotai": "^2.12.3",
|
||||
"qapp-core": "^1.0.30",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-i18next": "^15.5.1",
|
||||
"react-router-dom": "^7.3.0",
|
||||
"react-virtuoso": "^4.12.7"
|
||||
},
|
||||
@ -48,13 +50,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.26.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
|
||||
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
|
||||
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.25.9",
|
||||
"@babel/helper-validator-identifier": "^7.27.1",
|
||||
"js-tokens": "^4.0.0",
|
||||
"picocolors": "^1.0.0"
|
||||
"picocolors": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@ -169,17 +172,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
|
||||
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
||||
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
|
||||
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
|
||||
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@ -194,24 +199,26 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.9.tgz",
|
||||
"integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==",
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz",
|
||||
"integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.26.9",
|
||||
"@babel/types": "^7.26.9"
|
||||
"@babel/template": "^7.27.1",
|
||||
"@babel/types": "^7.27.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz",
|
||||
"integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==",
|
||||
"version": "7.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz",
|
||||
"integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.26.9"
|
||||
"@babel/types": "^7.27.1"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
@ -259,13 +266,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
|
||||
"integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
|
||||
"version": "7.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
|
||||
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.26.2",
|
||||
"@babel/parser": "^7.26.9",
|
||||
"@babel/types": "^7.26.9"
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/parser": "^7.27.2",
|
||||
"@babel/types": "^7.27.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@ -297,12 +305,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz",
|
||||
"integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==",
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz",
|
||||
"integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.25.9",
|
||||
"@babel/helper-validator-identifier": "^7.25.9"
|
||||
"@babel/helper-string-parser": "^7.27.1",
|
||||
"@babel/helper-validator-identifier": "^7.27.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@ -1672,11 +1681,6 @@
|
||||
"@babel/types": "^7.20.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||
@ -2270,6 +2274,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
|
||||
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -2849,6 +2854,46 @@
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/html-parse-stringify": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
|
||||
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"void-elements": "3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "25.2.0",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.2.0.tgz",
|
||||
"integrity": "sha512-ERhJICsxkw1vE7G0lhCUYv4ZxdBEs03qblt1myJs94rYRK9loJF3xDj8mgQz3LmCyp0yYrNjbN/1/GWZTZDGCA==",
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
@ -3554,6 +3599,32 @@
|
||||
"react-dom": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/react-i18next": {
|
||||
"version": "15.5.1",
|
||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.5.1.tgz",
|
||||
"integrity": "sha512-C8RZ7N7H0L+flitiX6ASjq9p5puVJU1Z8VyL3OgM/QOMRf40BMZX+5TkpxzZVcTmOLPX5zlti4InEX5pFyiVeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.0",
|
||||
"html-parse-stringify": "^3.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"i18next": ">= 23.2.3",
|
||||
"react": ">= 16.8.0",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native": {
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-intersection-observer": {
|
||||
"version": "9.16.0",
|
||||
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz",
|
||||
@ -3583,14 +3654,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.3.0.tgz",
|
||||
"integrity": "sha512-466f2W7HIWaNXTKM5nHTqNxLrHTyXybm7R0eBlVSt0k/u55tTCDO194OIx/NrYD4TS5SXKTNekXfT37kMKUjgw==",
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz",
|
||||
"integrity": "sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.6.0",
|
||||
"cookie": "^1.0.1",
|
||||
"set-cookie-parser": "^2.6.0",
|
||||
"turbo-stream": "2.4.0"
|
||||
"set-cookie-parser": "^2.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
@ -3606,11 +3676,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.3.0.tgz",
|
||||
"integrity": "sha512-z7Q5FTiHGgQfEurX/FBinkOXhWREJIAB2RiU24lvcBa82PxUpwqvs/PAXb9lJyPjTs2jrl6UkLvCZVGJPeNuuQ==",
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.0.tgz",
|
||||
"integrity": "sha512-DYgm6RDEuKdopSyGOWZGtDfSm7Aofb8CCzgkliTjtu/eDuB0gcsv6qdFhhi8HdtmA+KHkt5MfZ5K2PdzjugYsA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-router": "7.3.0"
|
||||
"react-router": "7.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
@ -3770,7 +3841,8 @@
|
||||
"node_modules/set-cookie-parser": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
|
||||
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="
|
||||
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
@ -3859,6 +3931,51 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
|
||||
"integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/fdir": {
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
|
||||
"integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@ -3888,11 +4005,6 @@
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
||||
},
|
||||
"node_modules/turbo-stream": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
|
||||
"integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g=="
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@ -3909,7 +4021,7 @@
|
||||
"version": "5.7.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
|
||||
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@ -3988,14 +4100,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.1.tgz",
|
||||
"integrity": "sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==",
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
|
||||
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2",
|
||||
"postcss": "^8.5.3",
|
||||
"rollup": "^4.30.1"
|
||||
"rollup": "^4.34.9",
|
||||
"tinyglobby": "^0.2.13"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
@ -4058,6 +4174,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vite/node_modules/fdir": {
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
|
||||
"integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vite/node_modules/picomatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/void-elements": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
@ -20,7 +20,9 @@
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-router-dom": "^7.3.0",
|
||||
"react-virtuoso": "^4.12.7"
|
||||
"react-virtuoso": "^4.12.7",
|
||||
"i18next": "^25.1.2",
|
||||
"react-i18next": "^15.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.21.0",
|
||||
|
@ -30,6 +30,7 @@ import {
|
||||
primaryNameAtom,
|
||||
} from '../state/global/names';
|
||||
import { Availability } from '../interfaces';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const Label = styled('label')`
|
||||
display: block;
|
||||
@ -40,6 +41,8 @@ const Label = styled('label')`
|
||||
`;
|
||||
|
||||
const RegisterName = () => {
|
||||
const { t } = useTranslation(['core']);
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const balance = useGlobal().auth.balance;
|
||||
const setNames = useSetAtom(namesAtom);
|
||||
@ -77,7 +80,11 @@ const RegisterName = () => {
|
||||
}, [namesForSale, primaryName, pendingTxs]);
|
||||
const registerNameFunc = async () => {
|
||||
if (!address) return;
|
||||
const loadId = showLoading('Registering name...please wait');
|
||||
const loadId = showLoading(
|
||||
t('core:new_name.responses.loading', {
|
||||
postProcess: 'capitalize',
|
||||
})
|
||||
);
|
||||
try {
|
||||
setIsLoadingRegisterName(true);
|
||||
const res = await qortalRequest({
|
||||
@ -105,14 +112,22 @@ const RegisterName = () => {
|
||||
},
|
||||
};
|
||||
});
|
||||
showSuccess('Successfully registered a name');
|
||||
showSuccess(
|
||||
t('core:new_name.responses.success', {
|
||||
postProcess: 'capitalize',
|
||||
})
|
||||
);
|
||||
setNameValue('');
|
||||
setIsOpen(false);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
showError(error.message);
|
||||
} else {
|
||||
showError('Unable to register name');
|
||||
showError(
|
||||
t('core:new_name.responses.error', {
|
||||
postProcess: 'capitalize',
|
||||
})
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
setIsLoadingRegisterName(false);
|
||||
@ -175,14 +190,20 @@ const RegisterName = () => {
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
new name
|
||||
{t('core:actions.new_name', {
|
||||
postProcess: 'capitalize',
|
||||
})}
|
||||
</Button>
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">{'Register name'}</DialogTitle>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{t('core:actions.register_name', {
|
||||
postProcess: 'capitalize',
|
||||
})}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Box
|
||||
sx={{
|
||||
@ -197,13 +218,15 @@ const RegisterName = () => {
|
||||
padding: '10px',
|
||||
}}
|
||||
>
|
||||
<Label>Choose a name</Label>
|
||||
<Label></Label>
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
onChange={(e) => setNameValue(e.target.value)}
|
||||
value={nameValue}
|
||||
placeholder="Choose a name"
|
||||
placeholder={t('core:new_name.choose_name', {
|
||||
postProcess: 'capitalize',
|
||||
})}
|
||||
/>
|
||||
{(!balance || (nameFee && balance && balance < nameFee)) && (
|
||||
<>
|
||||
@ -221,8 +244,11 @@ const RegisterName = () => {
|
||||
}}
|
||||
/>
|
||||
<Typography>
|
||||
Your balance is {balance ?? 0} QORT. A name registration
|
||||
requires a {nameFee} QORT fee
|
||||
{t('balance_message', {
|
||||
balance: balance ?? 0,
|
||||
nameFee,
|
||||
postProcess: 'capitalize',
|
||||
})}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Spacer height="10px" />
|
||||
@ -242,7 +268,9 @@ const RegisterName = () => {
|
||||
color: theme.palette.text.primary,
|
||||
}}
|
||||
/>
|
||||
<Typography>{nameValue} is available</Typography>
|
||||
<Typography>
|
||||
{t('core:new_name.name_available', { name: nameValue })}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
{isNameAvailable === Availability.NOT_AVAILABLE && (
|
||||
@ -258,7 +286,9 @@ const RegisterName = () => {
|
||||
color: theme.palette.text.primary,
|
||||
}}
|
||||
/>
|
||||
<Typography>{nameValue} is unavailable</Typography>
|
||||
<Typography>
|
||||
{t('core:new_name.name_unavailable', { name: nameValue })}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
{isNameAvailable === Availability.LOADING && (
|
||||
@ -270,7 +300,11 @@ const RegisterName = () => {
|
||||
}}
|
||||
>
|
||||
<BarSpinner width="16px" color={theme.palette.text.primary} />
|
||||
<Typography>Checking if name already existis</Typography>
|
||||
<Typography>
|
||||
{t('core:new_name.checking_name', {
|
||||
postProcess: 'capitalize',
|
||||
})}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
@ -284,7 +318,9 @@ const RegisterName = () => {
|
||||
setNameValue('');
|
||||
}}
|
||||
>
|
||||
Close
|
||||
{t('core:actions.close', {
|
||||
postProcess: 'capitalize',
|
||||
})}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={Boolean(
|
||||
@ -298,7 +334,9 @@ const RegisterName = () => {
|
||||
onClick={registerNameFunc}
|
||||
autoFocus
|
||||
>
|
||||
Register Name
|
||||
{t('core:actions.register_name', {
|
||||
postProcess: 'capitalize',
|
||||
})}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
@ -2,14 +2,21 @@ import { useEffect } from 'react';
|
||||
import { To, useNavigate } from 'react-router-dom';
|
||||
import { EnumTheme, themeAtom } from '../state/global/system';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { supportedLanguages } from '../i18n/i18n';
|
||||
|
||||
type Language = 'de' | 'en' | 'es' | 'fr' | 'it' | 'ru';
|
||||
type Theme = 'dark' | 'light';
|
||||
|
||||
interface CustomWindow extends Window {
|
||||
_qdnTheme: string;
|
||||
_qdnTheme: Theme;
|
||||
_qdnLang: Language;
|
||||
}
|
||||
const customWindow = window as unknown as CustomWindow;
|
||||
|
||||
export const useIframe = () => {
|
||||
const setTheme = useSetAtom(themeAtom);
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
const navigate = useNavigate();
|
||||
useEffect(() => {
|
||||
@ -19,8 +26,20 @@ export const useIframe = () => {
|
||||
} else if (themeColorDefault === 'light') {
|
||||
setTheme(EnumTheme.LIGHT);
|
||||
}
|
||||
|
||||
const languageDefault = customWindow?._qdnLang;
|
||||
|
||||
if (supportedLanguages?.includes(languageDefault)) {
|
||||
i18n.changeLanguage(languageDefault);
|
||||
}
|
||||
|
||||
function handleNavigation(event: {
|
||||
data: { action: string; path: To; theme: 'dark' | 'light' };
|
||||
data: {
|
||||
action: string;
|
||||
path: To;
|
||||
theme: Theme;
|
||||
language: Language;
|
||||
};
|
||||
}) {
|
||||
if (event.data?.action === 'NAVIGATE_TO_PATH' && event.data.path) {
|
||||
navigate(event.data.path); // Navigate directly to the specified path
|
||||
@ -37,6 +56,12 @@ export const useIframe = () => {
|
||||
} else if (themeColor === 'light') {
|
||||
setTheme(EnumTheme.LIGHT);
|
||||
}
|
||||
} else if (
|
||||
event.data?.action === 'LANGUAGE_CHANGED' &&
|
||||
event.data.language
|
||||
) {
|
||||
if (!supportedLanguages?.includes(event.data.language)) return;
|
||||
i18n.changeLanguage(event.data.language);
|
||||
}
|
||||
}
|
||||
|
||||
|
56
src/i18n/i18n.ts
Normal file
56
src/i18n/i18n.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import {
|
||||
capitalizeAll,
|
||||
capitalizeFirstChar,
|
||||
capitalizeFirstWord,
|
||||
} from './processors';
|
||||
|
||||
// Load all locale JSON files
|
||||
const modules = import.meta.glob('./locales/**/*.json', {
|
||||
eager: true,
|
||||
}) as Record<string, any>;
|
||||
|
||||
// Dynamically detect unique language codes
|
||||
export const supportedLanguages: string[] = Array.from(
|
||||
new Set(
|
||||
Object.keys(modules)
|
||||
.map((path) => {
|
||||
const match = path.match(/\.\/locales\/([^/]+)\//);
|
||||
return match ? match[1] : null;
|
||||
})
|
||||
.filter((lang): lang is string => typeof lang === 'string')
|
||||
)
|
||||
);
|
||||
|
||||
// Construct i18n resources object
|
||||
const resources: Record<string, Record<string, any>> = {};
|
||||
|
||||
for (const path in modules) {
|
||||
// Path format: './locales/en/core.json'
|
||||
const match = path.match(/\.\/locales\/([^/]+)\/([^/]+)\.json$/);
|
||||
if (!match) continue;
|
||||
|
||||
const [, lang, ns] = match;
|
||||
resources[lang] = resources[lang] || {};
|
||||
resources[lang][ns] = modules[path].default;
|
||||
}
|
||||
|
||||
i18n
|
||||
.use(initReactI18next)
|
||||
.use(capitalizeAll as any)
|
||||
.use(capitalizeFirstChar as any)
|
||||
.use(capitalizeFirstWord as any)
|
||||
.init({
|
||||
resources,
|
||||
fallbackLng: 'en',
|
||||
lng: navigator.language,
|
||||
supportedLngs: supportedLanguages,
|
||||
ns: ['core'],
|
||||
defaultNS: 'core',
|
||||
interpolation: { escapeValue: false },
|
||||
react: { useSuspense: false },
|
||||
debug: import.meta.env.MODE === 'development',
|
||||
});
|
||||
|
||||
export default i18n;
|
26
src/i18n/locales/en/core.json
Normal file
26
src/i18n/locales/en/core.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"header": {
|
||||
"my_names": "my names",
|
||||
"market": "names for sale"
|
||||
},
|
||||
"inputs": {
|
||||
"filter_names": "filter names"
|
||||
},
|
||||
"actions": {
|
||||
"new_name": "new name",
|
||||
"register_name": "register name",
|
||||
"close": "close"
|
||||
},
|
||||
"new_name": {
|
||||
"choose_name": "choose a name",
|
||||
"balance_message": "Your balance is {{balance}} QORT. A name registration requires a {{nameFee}} QORT fee.",
|
||||
"name_available": "{{name}} is available",
|
||||
"name_unavailable": "{{name}} is unavailable",
|
||||
"checking_name": "checking if name already exists",
|
||||
"responses": {
|
||||
"success": "successfully registered a name",
|
||||
"error": "unable to register name",
|
||||
"loading": "Registering name...please wait"
|
||||
}
|
||||
}
|
||||
}
|
6
src/i18n/locales/es/core.json
Normal file
6
src/i18n/locales/es/core.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"header": {
|
||||
"my_names": "mis nombres",
|
||||
"market": ""
|
||||
}
|
||||
}
|
32
src/i18n/processors.ts
Normal file
32
src/i18n/processors.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export const capitalizeAll = {
|
||||
type: 'postProcessor',
|
||||
name: 'capitalizeAll',
|
||||
process: (value: string) => value.toUpperCase(),
|
||||
};
|
||||
|
||||
export const capitalizeFirstChar = {
|
||||
type: 'postProcessor',
|
||||
name: 'capitalizeFirstChar',
|
||||
process: (value: string) => value.charAt(0).toUpperCase() + value.slice(1),
|
||||
};
|
||||
|
||||
export const capitalizeFirstWord = {
|
||||
type: 'postProcessor',
|
||||
name: 'capitalizeFirstWord',
|
||||
process: (value: string) => {
|
||||
if (!value?.trim()) return value;
|
||||
|
||||
const trimmed = value.trimStart();
|
||||
const firstSpaceIndex = trimmed.indexOf(' ');
|
||||
|
||||
if (firstSpaceIndex === -1) {
|
||||
return trimmed.charAt(0).toUpperCase() + trimmed.slice(1);
|
||||
}
|
||||
|
||||
const firstWord = trimmed.slice(0, firstSpaceIndex);
|
||||
const restOfString = trimmed.slice(firstSpaceIndex);
|
||||
const trailingSpaces = value.slice(trimmed.length);
|
||||
|
||||
return firstWord.toUpperCase() + restOfString + trailingSpaces;
|
||||
},
|
||||
};
|
13
src/main.tsx
13
src/main.tsx
@ -1,10 +1,11 @@
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./index.css";
|
||||
import ThemeProviderWrapper from "./styles/theme/theme-provider.tsx";
|
||||
import { AppWrapper } from "./AppWrapper.tsx";
|
||||
import { StrictMode } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import './index.css';
|
||||
import ThemeProviderWrapper from './styles/theme/theme-provider.tsx';
|
||||
import { AppWrapper } from './AppWrapper.tsx';
|
||||
import './i18n/i18n.ts';
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<ThemeProviderWrapper>
|
||||
<AppWrapper />
|
||||
|
@ -8,8 +8,11 @@ import {
|
||||
} from '../state/global/names';
|
||||
import { useAtom } from 'jotai';
|
||||
import { SortBy, SortDirection } from '../interfaces';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const Market = () => {
|
||||
const { t } = useTranslation(['core']);
|
||||
|
||||
const [namesForSale] = useAtom(forSaleAtom);
|
||||
const [pendingTxs] = useAtom(pendingTxsAtom);
|
||||
const [primaryName] = useAtom(primaryNameAtom);
|
||||
@ -106,7 +109,9 @@ export const Market = () => {
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
placeholder="Filter names"
|
||||
placeholder={t('core:inputs.filter_names', {
|
||||
postProcess: 'capitalize',
|
||||
})}
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
size="small"
|
||||
|
@ -4,8 +4,11 @@ import { namesAtom, primaryNameAtom } from '../state/global/names';
|
||||
import { NameTable } from '../components/Tables/NameTable';
|
||||
import { Box, TextField } from '@mui/material';
|
||||
import RegisterName from '../components/RegisterName';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const MyNames = () => {
|
||||
const { t } = useTranslation(['core']);
|
||||
|
||||
const [names] = useAtom(namesAtom);
|
||||
const [value, setValue] = useState('');
|
||||
const [filterValue, setFilterValue] = useState('');
|
||||
@ -50,7 +53,9 @@ export const MyNames = () => {
|
||||
>
|
||||
{' '}
|
||||
<TextField
|
||||
placeholder="Filter names"
|
||||
placeholder={t('core:inputs.filter_names', {
|
||||
postProcess: 'capitalize',
|
||||
})}
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
size="small"
|
||||
|
@ -4,16 +4,26 @@ import { AppBar, Toolbar, Button, Box, useTheme } from '@mui/material';
|
||||
import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted';
|
||||
import StorefrontIcon from '@mui/icons-material/Storefront';
|
||||
import { PendingTxsTable } from '../components/Tables/PendingTxsTable';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const Layout = () => {
|
||||
useIframe();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation(['core']);
|
||||
|
||||
const navItems = [
|
||||
{ label: 'My names', path: '/', Icon: FormatListBulletedIcon },
|
||||
{ label: 'Names for sale', path: '/market', Icon: StorefrontIcon },
|
||||
{
|
||||
label: t('core:header.my_names', { postProcess: 'capitalize' }),
|
||||
path: '/',
|
||||
Icon: FormatListBulletedIcon,
|
||||
},
|
||||
{
|
||||
label: t('core:header.market', { postProcess: 'capitalize' }),
|
||||
path: '/market',
|
||||
Icon: StorefrontIcon,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
|
Loading…
x
Reference in New Issue
Block a user