forked from ppfun/pixelplanet
Compare commits
No commits in common. "45fc4b4d9ce66a731ad27df11789ac369fdee4ca" and "878f2cd269de9af1c736ba2aa4aeec5d9aeaaff4" have entirely different histories.
45fc4b4d9c
...
878f2cd269
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,7 +10,6 @@ logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
*.tmp
|
*.tmp
|
||||||
records.json
|
|
||||||
|
|
||||||
pids
|
pids
|
||||||
*.pid
|
*.pid
|
||||||
|
|
18
README.md
18
README.md
|
@ -1,5 +1,3 @@
|
||||||
> **Currently pixelplanet is being developed in a another private repository. This development version diverted and is incompatible with the stable version here. Until it is ready, this public repository will be frozen.**
|
|
||||||
|
|
||||||
# PixelPlanet.fun
|
# PixelPlanet.fun
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +7,7 @@ Official repository of [pixelplanet.fun](http://www.pixelplanet.fun).
|
||||||
|
|
||||||
![videothumb](promotion/videothumb.gif)
|
![videothumb](promotion/videothumb.gif)
|
||||||
|
|
||||||
> If you want to help us translate pixelplanet.fun, look into [i18n](./i18n)
|
> **TRANSLATORS NEEDED** If you want to help us translate pixelplanet.fun, look into [i18n](./i18n)
|
||||||
|
|
||||||
To the 2nd anniversary of r/space, pixelplanet takes pixelgames to a new level. Place pixels, create pixelart and fight faction wars on pixelplanet.fun.
|
To the 2nd anniversary of r/space, pixelplanet takes pixelgames to a new level. Place pixels, create pixelart and fight faction wars on pixelplanet.fun.
|
||||||
Pixelplanet is a 65k x 65k large canvas that is a map of the world and can also be seen as 3d globe, you can place pixels where ever you want, build an island, take over another country with a flag or just create pixelart.
|
Pixelplanet is a 65k x 65k large canvas that is a map of the world and can also be seen as 3d globe, you can place pixels where ever you want, build an island, take over another country with a flag or just create pixelart.
|
||||||
|
@ -258,19 +256,11 @@ If v is set and true for a canvas in the canvas.json, it will be a 3D voxel canv
|
||||||
|
|
||||||
Run `npm run lint:src` to check for code errors and warnings or `npm run lint -- ./your/file.js` to check a single file.
|
Run `npm run lint:src` to check for code errors and warnings or `npm run lint -- ./your/file.js` to check a single file.
|
||||||
|
|
||||||
Compile with source-maps and debug options (but only english language) with
|
[ttag](https://github.com/ttag-org/ttag/) is used for handling translations. For server-side rendering the `Accept-Language` header gets checked and the first locale used and on-the-fly translated (`src/core/ttag.js` provides the functions for it). On the client-side a seperate bundle for every language gets provided.
|
||||||
|
The language definitions in `i18n/template.pot` and `i18n/template-ssr.pot` get updated when doing a dev build with
|
||||||
```
|
```
|
||||||
npm run build:dev
|
npm run build:dev
|
||||||
```
|
```
|
||||||
|
which also only builds the default local in a development environment for debugging.
|
||||||
[ttag](https://github.com/ttag-org/ttag/) is used for handling translations. For server-side rendering the `Accept-Language` header gets checked and the first locale used and on-the-fly translated (`src/core/ttag.js` provides the functions for it). On the client-side a seperate bundle for every language gets provided.
|
|
||||||
The language definitions in `i18n/template.pot` and `i18n/template-ssr.pot` get updated when doing a full production build with all languages (`npm run build`)-
|
|
||||||
|
|
||||||
To build only specific languages, you can define them with the `--langs` flag:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run build -- --langs de,gr
|
|
||||||
```
|
|
||||||
|
|
||||||
You can use `npm run babel-node ./utils/script.js` to execute a script with local babel (path always relative to the root directory).
|
You can use `npm run babel-node ./utils/script.js` to execute a script with local babel (path always relative to the root directory).
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
apps:
|
apps:
|
||||||
- script : ./server.js
|
- script : ./server.js
|
||||||
name : 'ppfun'
|
name : 'ppfun-server'
|
||||||
node_args : --nouse-idle-notification --expose-gc
|
node_args: --nouse-idle-notification --expose-gc
|
||||||
watch : [ 'server.js' ]
|
|
||||||
watch_delay: 5000
|
|
||||||
env:
|
env:
|
||||||
PORT: 5000
|
PORT: 80
|
||||||
HOST: "localhost"
|
HOST: "localhost"
|
||||||
REDIS_URL: 'redis://localhost:6379'
|
REDIS_URL: 'redis://localhost:6379'
|
||||||
MYSQL_HOST: "localhost"
|
MYSQL_HOST: "localhost"
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# This hook builds pixelplanet after a push to a development branch,
|
# This hook builds pixelplanet after a push, and deploys it, it should be ron post-receive
|
||||||
# and starts the dev-canvas
|
# If it is the master branch, it will deploy it on the life system, and other branch will get deployed to the dev-canvas (a second canvas that is running on the server)
|
||||||
#
|
#
|
||||||
# To set up a server to use this, you have to go through the building steps manually first.
|
# To set up a server to use this, you have to go through the building steps manually first.
|
||||||
#
|
#
|
||||||
#folder for building the canvas (the git repository will get checkout there and the canvas will get built thtere)
|
#folder for building the canvas (the git repository will get checkout there and the canvas will get buil thtere)
|
||||||
BUILDDIR="/home/pixelpla/pixelplanet-build"
|
BUILDDIR="/home/pixelpla/pixelplanet-build"
|
||||||
#folder for dev canvas
|
#folder for dev canvas
|
||||||
DEVFOLDER="/home/pixelpla/pixelplanet-dev"
|
DEVFOLDER="/home/pixelpla/pixelplanet-dev"
|
||||||
|
#folder for production canvas
|
||||||
|
PFOLDER="/home/pixelpla/pixelplanet"
|
||||||
|
|
||||||
should_reinstall () {
|
should_reinstall () {
|
||||||
local TMPFILE="${BUILDDIR}/package.json.${1}.tmp"
|
local TMPFILE="${BUILDDIR}/package.json.${1}.tmp"
|
||||||
|
@ -31,12 +33,14 @@ npm_reinstall () {
|
||||||
copy () {
|
copy () {
|
||||||
local TARGETDIR="${1}"
|
local TARGETDIR="${1}"
|
||||||
local REINSTALL="${2}"
|
local REINSTALL="${2}"
|
||||||
cp -r "${BUILDDIR}"/dist/*.js "${TARGETDIR}/"
|
cp -r dist/*.js "${TARGETDIR}/"
|
||||||
cp -r "${BUILDDIR}"/dist/workers "${TARGETDIR}/"
|
cp -r dist/workers "${TARGETDIR}/"
|
||||||
rm -rf "${TARGETDIR}/public/assets"
|
rm -rf "${TARGETDIR}/public/assets"
|
||||||
cp -r "${BUILDDIR}"/dist/public "${TARGETDIR}/"
|
cp -r dist/public "${TARGETDIR}/"
|
||||||
cp -r "${BUILDDIR}"/dist/captchaFonts "${TARGETDIR}/"
|
cp -r dist/captchaFonts "${TARGETDIR}/"
|
||||||
cp -r "${BUILDDIR}"/dist/package.json "${TARGETDIR}/"
|
cp -r dist/package.json "${TARGETDIR}/"
|
||||||
|
cp -r dist/assets.json "${TARGETDIR}/"
|
||||||
|
cp -r dist/styleassets.json "${TARGETDIR}/"
|
||||||
mkdir -p "${TARGETDIR}/log"
|
mkdir -p "${TARGETDIR}/log"
|
||||||
cd "${TARGETDIR}"
|
cd "${TARGETDIR}"
|
||||||
[ $REINSTALL -eq 0 ] && npm_reinstall
|
[ $REINSTALL -eq 0 ] && npm_reinstall
|
||||||
|
@ -49,10 +53,28 @@ do
|
||||||
GIT_WORK_TREE="$BUILDDIR" GIT_DIR="${BUILDDIR}/.git" git fetch --all
|
GIT_WORK_TREE="$BUILDDIR" GIT_DIR="${BUILDDIR}/.git" git fetch --all
|
||||||
cd "$BUILDDIR"
|
cd "$BUILDDIR"
|
||||||
branch=$(git rev-parse --symbolic --abbrev-ref $refname)
|
branch=$(git rev-parse --symbolic --abbrev-ref $refname)
|
||||||
if [ "test" == "$branch" ] || [ "devel" == "$branch" ]; then
|
if [ "master" == "$branch" ]; then
|
||||||
|
echo "---UPDATING REPO ON PRODUCTION SERVER---"
|
||||||
|
GIT_WORK_TREE="$BUILDDIR" GIT_DIR="${BUILDDIR}/.git" git reset --hard "origin/$branch"
|
||||||
|
COMMITS=`git log --pretty=format:'- %s%b' $newrev ^$oldrev`
|
||||||
|
COMMITS=`echo "$COMMITS" | sed ':a;N;$!ba;s/\n/\\\n/g'`
|
||||||
|
echo "---BUILDING pixelplanet---"
|
||||||
|
should_reinstall master
|
||||||
|
DO_REINSTALL=$?
|
||||||
|
[ $DO_REINSTALL -eq 0 ] && npm_reinstall
|
||||||
|
npm run build
|
||||||
|
echo "---RESTARTING CANVAS---"
|
||||||
|
pm2 stop ppfun-server
|
||||||
|
pm2 stop ppfun-backups
|
||||||
|
copy "${PFOLDER}" "${DO_REINSTALL}"
|
||||||
|
cd "$PFOLDER"
|
||||||
|
pm2 start ecosystem-backup.yml
|
||||||
|
else
|
||||||
echo "---UPDATING REPO ON DEV SERVER---"
|
echo "---UPDATING REPO ON DEV SERVER---"
|
||||||
pm2 stop ppfun-server-dev
|
pm2 stop ppfun-server-dev
|
||||||
GIT_WORK_TREE="$BUILDDIR" GIT_DIR="${BUILDDIR}/.git" git reset --hard "origin/$branch"
|
GIT_WORK_TREE="$BUILDDIR" GIT_DIR="${BUILDDIR}/.git" git reset --hard "origin/$branch"
|
||||||
|
COMMITS=`git log --pretty=format:'- %s%b' $newrev ^$oldrev`
|
||||||
|
COMMITS=`echo "$COMMITS" | sed ':a;N;$!ba;s/\n/\\\n/g'`
|
||||||
echo "---BUILDING pixelplanet---"
|
echo "---BUILDING pixelplanet---"
|
||||||
should_reinstall dev
|
should_reinstall dev
|
||||||
DO_REINSTALL=$?
|
DO_REINSTALL=$?
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Rebuild and Restert pixelplanet
|
# Rebuild from master branch and restart pixelplanet
|
||||||
|
|
||||||
#folder for building the canvas (the git repository will get checkout there and the canvas will get buil thtere)
|
#folder for building the canvas (the git repository will get checkout there and the canvas will get buil thtere)
|
||||||
BUILDDIR="/home/pixelpla/pixelplanet-build"
|
BUILDDIR="/home/pixelpla/pixelplanet-build"
|
||||||
#folder for dev canvas
|
#folder for dev canvas
|
||||||
DEVFOLDER="/home/pixelpla/pixelplanet-dev"
|
DEVFOLDER="/home/pixelpla/pixelplanet-dev"
|
||||||
|
#folder for shards
|
||||||
|
SCBFOLDER="/home/pixelpla/pixelplanet-scb"
|
||||||
|
SCCFOLDER="/home/pixelpla/pixelplanet-scc"
|
||||||
|
SCDFOLDER="/home/pixelpla/pixelplanet-scd"
|
||||||
|
SCEFOLDER="/home/pixelpla/pixelplanet-sce"
|
||||||
|
SCFFOLDER="/home/pixelpla/pixelplanet-scf"
|
||||||
|
SCGFOLDER="/home/pixelpla/pixelplanet-scg"
|
||||||
|
SCHFOLDER="/home/pixelpla/pixelplanet-sch"
|
||||||
#folder for production canvas
|
#folder for production canvas
|
||||||
PFOLDER="/home/pixelpla/pixelplanet"
|
PFOLDER="/home/pixelpla/pixelplanet"
|
||||||
#which branch to use
|
#which branch to use
|
||||||
|
@ -32,20 +40,23 @@ npm_reinstall () {
|
||||||
copy () {
|
copy () {
|
||||||
local TARGETDIR="${1}"
|
local TARGETDIR="${1}"
|
||||||
local REINSTALL="${2}"
|
local REINSTALL="${2}"
|
||||||
cp -r "${BUILDDIR}"/dist/*.js "${TARGETDIR}/"
|
cp -r dist/*.js "${TARGETDIR}/"
|
||||||
cp -r "${BUILDDIR}"/dist/workers "${TARGETDIR}/"
|
cp -r dist/workers "${TARGETDIR}/"
|
||||||
rm -rf "${TARGETDIR}/public/assets"
|
rm -rf "${TARGETDIR}/public/assets"
|
||||||
cp -r "${BUILDDIR}"/dist/public "${TARGETDIR}/"
|
cp -r dist/public "${TARGETDIR}/"
|
||||||
cp -r "${BUILDDIR}"/dist/captchaFonts "${TARGETDIR}/"
|
cp -r dist/captchaFonts "${TARGETDIR}/"
|
||||||
cp -r "${BUILDDIR}"/dist/package.json "${TARGETDIR}/"
|
cp -r dist/package.json "${TARGETDIR}/"
|
||||||
|
cp -r dist/assets.json "${TARGETDIR}/"
|
||||||
|
cp -r dist/styleassets.json "${TARGETDIR}/"
|
||||||
mkdir -p "${TARGETDIR}/log"
|
mkdir -p "${TARGETDIR}/log"
|
||||||
cd "${TARGETDIR}"
|
cd "${TARGETDIR}"
|
||||||
[ ${REINSTALL} -eq 0 ] && npm_reinstall
|
[ $REINSTALL -eq 0 ] && npm_reinstall
|
||||||
|
pm2 start ecosystem.yml
|
||||||
cd -
|
cd -
|
||||||
}
|
}
|
||||||
|
|
||||||
cd "$BUILDDIR"
|
|
||||||
GIT_WORK_TREE="$BUILDDIR" GIT_DIR="${BUILDDIR}/.git" git fetch --all
|
GIT_WORK_TREE="$BUILDDIR" GIT_DIR="${BUILDDIR}/.git" git fetch --all
|
||||||
|
cd "$BUILDDIR"
|
||||||
echo "---UPDATING REPO ON PRODUCTION SERVER---"
|
echo "---UPDATING REPO ON PRODUCTION SERVER---"
|
||||||
GIT_WORK_TREE="$BUILDDIR" GIT_DIR="${BUILDDIR}/.git" git reset --hard "origin/${BRANCH}"
|
GIT_WORK_TREE="$BUILDDIR" GIT_DIR="${BUILDDIR}/.git" git reset --hard "origin/${BRANCH}"
|
||||||
echo "---BUILDING pixelplanet---"
|
echo "---BUILDING pixelplanet---"
|
||||||
|
@ -54,10 +65,22 @@ DO_REINSTALL=$?
|
||||||
[ $DO_REINSTALL -eq 0 ] && npm_reinstall
|
[ $DO_REINSTALL -eq 0 ] && npm_reinstall
|
||||||
npm run build
|
npm run build
|
||||||
echo "---RESTARTING CANVAS---"
|
echo "---RESTARTING CANVAS---"
|
||||||
cp dist/canvases.json ~/
|
pm2 stop ppfun-server
|
||||||
cd "$PFOLDER"
|
|
||||||
pm2 stop ppfun-backups
|
pm2 stop ppfun-backups
|
||||||
pm2 stop ecosystem.config.js
|
pm2 stop ppfun-scb
|
||||||
|
pm2 stop ppfun-scc
|
||||||
|
pm2 stop ppfun-scd
|
||||||
|
pm2 stop ppfun-sce
|
||||||
|
pm2 stop ppfun-scf
|
||||||
|
pm2 stop ppfun-scg
|
||||||
|
pm2 stop ppfun-sch
|
||||||
copy "${PFOLDER}" "${DO_REINSTALL}"
|
copy "${PFOLDER}" "${DO_REINSTALL}"
|
||||||
|
copy "${SCBFOLDER}" 1
|
||||||
|
copy "${SCCFOLDER}" 1
|
||||||
|
copy "${SCDFOLDER}" 1
|
||||||
|
copy "${SCEFOLDER}" 1
|
||||||
|
copy "${SCFFOLDER}" 1
|
||||||
|
copy "${SCGFOLDER}" 1
|
||||||
|
copy "${SCHFOLDER}" 1
|
||||||
|
cd "$PFOLDER"
|
||||||
pm2 start ecosystem-backup.yml
|
pm2 start ecosystem-backup.yml
|
||||||
pm2 start ecosystem.config.js
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ Translation files can be created out of the templates [template.pot](https://git
|
||||||
|
|
||||||
All translated languages get an own chat channel that just people who use this language can access.
|
All translated languages get an own chat channel that just people who use this language can access.
|
||||||
|
|
||||||
If a language code differs from the country code of a wanted flag, it can be defined in the ssr filename, like `ssr-en-gb.po` would be the english language, with the flag of Great Britain.
|
|
||||||
|
|
||||||
## With poedit
|
## With poedit
|
||||||
|
|
||||||
### Create new translation
|
### Create new translation
|
||||||
|
|
|
@ -29,7 +29,6 @@ msgid "You are muted for another ${ timeMin } minutes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/core/ChatProvider.js:450
|
#: src/core/ChatProvider.js:450
|
||||||
#, javascript-format
|
|
||||||
msgid "You are muted for another ${ ttl } seconds"
|
msgid "You are muted for another ${ ttl } seconds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -82,35 +81,35 @@ msgstr ""
|
||||||
msgid "Invalid url :( Please check your mail again."
|
msgid "Invalid url :( Please check your mail again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/ssr/Globe.jsx:37
|
#: src/ssr/Globe.jsx:32
|
||||||
msgid "PixelPlanet.Fun 3DGlobe"
|
msgid "PixelPlanet.Fun 3DGlobe"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/ssr/Globe.jsx:38
|
#: src/ssr/Globe.jsx:33
|
||||||
msgid "A 3D globe of our whole map"
|
msgid "A 3D globe of our whole map"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/ssr/Globe.jsx:51
|
#: src/ssr/Globe.jsx:46
|
||||||
msgid "Double click on globe to go back."
|
msgid "Double click on globe to go back."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/ssr/Globe.jsx:52
|
#: src/ssr/Globe.jsx:47
|
||||||
msgid "Loading..."
|
msgid "Loading..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/ssr/PopUp.jsx:55
|
#: src/ssr/PopUp.jsx:58
|
||||||
msgid "ppfun"
|
msgid "ppfun"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/ssr/PopUp.jsx:56
|
#: src/ssr/PopUp.jsx:59
|
||||||
msgid "PixelPlanet.Fun PopUp"
|
msgid "PixelPlanet.Fun PopUp"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/ssr/Main.jsx:64
|
#: src/ssr/Main.jsx:67
|
||||||
msgid "PixelPlanet.Fun"
|
msgid "PixelPlanet.Fun"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/ssr/Main.jsx:65
|
#: src/ssr/Main.jsx:68
|
||||||
msgid "Place color pixels on an map styled canvas with other players online"
|
msgid "Place color pixels on an map styled canvas with other players online"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -220,7 +219,31 @@ msgstr ""
|
||||||
msgid "You are not banned"
|
msgid "You are not banned"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/routes/api/auth/change_mail.js:22
|
#: src/routes/api/auth/logout.js:11
|
||||||
|
msgid "You are not even logged in."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/routes/api/auth/delete_account.js:55
|
||||||
|
#: src/routes/api/auth/logout.js:20
|
||||||
|
msgid "Server error when logging out."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/routes/api/auth/verify.js:26
|
||||||
|
#: src/routes/api/auth/verify.js:35
|
||||||
|
msgid "Mail verification"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/routes/api/auth/verify.js:27
|
||||||
|
msgid "You are now verified :)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/routes/api/auth/verify.js:35
|
||||||
|
msgid ""
|
||||||
|
"Your mail verification code is invalid or already expired :(, please "
|
||||||
|
"request a new one."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/routes/api/auth/change_mail.js:21
|
||||||
#: src/routes/api/auth/register.js:24
|
#: src/routes/api/auth/register.js:24
|
||||||
msgid "This email provider is not allowed"
|
msgid "This email provider is not allowed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -257,50 +280,18 @@ msgstr ""
|
||||||
msgid "Failed to establish session after register :("
|
msgid "Failed to establish session after register :("
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/routes/api/auth/verify.js:26
|
#: src/routes/api/auth/change_mail.js:43
|
||||||
#: src/routes/api/auth/verify.js:35
|
|
||||||
msgid "Mail verification"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/routes/api/auth/verify.js:27
|
|
||||||
msgid "You are now verified :)"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/routes/api/auth/verify.js:35
|
|
||||||
msgid ""
|
|
||||||
"Your mail verification code is invalid or already expired :(, please "
|
|
||||||
"request a new one."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/routes/api/auth/logout.js:11
|
|
||||||
msgid "You are not even logged in."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/routes/api/auth/delete_account.js:65
|
|
||||||
#: src/routes/api/auth/logout.js:20
|
|
||||||
msgid "Server error when logging out."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/routes/api/auth/change_mail.js:44
|
|
||||||
#: src/routes/api/auth/change_passwd.js:34
|
#: src/routes/api/auth/change_passwd.js:34
|
||||||
#: src/routes/api/auth/delete_account.js:36
|
#: src/routes/api/auth/delete_account.js:35
|
||||||
msgid "You are not authenticated."
|
msgid "You are not authenticated."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/routes/api/auth/change_mail.js:53
|
#: src/routes/api/auth/change_mail.js:52
|
||||||
#: src/routes/api/auth/change_passwd.js:43
|
#: src/routes/api/auth/change_passwd.js:43
|
||||||
#: src/routes/api/auth/delete_account.js:55
|
#: src/routes/api/auth/delete_account.js:45
|
||||||
msgid "Incorrect password!"
|
msgid "Incorrect password!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/routes/api/auth/delete_account.js:46
|
|
||||||
msgid "Muted users can not delete their account."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/routes/api/auth/change_mail.js:62
|
|
||||||
msgid "Muted users can not do this."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/ssr/RedirectionPage.jsx:19
|
#: src/ssr/RedirectionPage.jsx:19
|
||||||
msgid "PixelPlanet.fun Accounts"
|
msgid "PixelPlanet.fun Accounts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -346,59 +337,48 @@ msgstr ""
|
||||||
msgid "Top10"
|
msgid "Top10"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/canvasesDesc.js:27
|
#: src/canvasesDesc.js:29
|
||||||
msgid "Thoia"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/canvasesDesc.js:30
|
|
||||||
msgid "Our main canvas, a huge map of the world. Place everywhere you like"
|
msgid "Our main canvas, a huge map of the world. Place everywhere you like"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/canvasesDesc.js:31
|
#: src/canvasesDesc.js:30
|
||||||
msgid ""
|
msgid ""
|
||||||
"Moon canvas. Safe space for art. No flags or large text (unless part of "
|
"Moon canvas. Safe space for art. No flags or large text (unless part of "
|
||||||
"art) or art larger than 1.5k x 1.5k pixels."
|
"art) or art larger than 1.5k x 1.5k pixels."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/canvasesDesc.js:32
|
#: src/canvasesDesc.js:31
|
||||||
msgid "Place Voxels on a 3D canvas with others"
|
msgid "Place Voxels on a 3D canvas with others"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/canvasesDesc.js:33
|
#: src/canvasesDesc.js:32
|
||||||
msgid "Special canvas to spread awareness of SARS-CoV2"
|
msgid "Special canvas to spread awareness of SARS-CoV2"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/canvasesDesc.js:34
|
#: src/canvasesDesc.js:33
|
||||||
msgid "Mirror of PixelZone"
|
msgid "Mirror of PixelZone"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/canvasesDesc.js:35
|
#: src/canvasesDesc.js:34
|
||||||
msgid "Mirror of PixelCanvas"
|
msgid "Mirror of PixelCanvas"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/canvasesDesc.js:36
|
#: src/canvasesDesc.js:35
|
||||||
msgid "Black and White canvas"
|
msgid "Black and White canvas"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/canvasesDesc.js:37
|
#: src/canvasesDesc.js:36
|
||||||
msgid ""
|
msgid ""
|
||||||
"A canvas for the most active players from the the previous day. Daily "
|
"A canvas for the most active players from the the previous day. Daily "
|
||||||
"ranking updates at 00:00 UTC."
|
"ranking updates at 00:00 UTC."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/canvasesDesc.js:38
|
|
||||||
msgid ""
|
|
||||||
"Thoia World Canvas. Advanced fictional worldbuilding and arts. Abandon the "
|
|
||||||
"old world and all it entails."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/core/MailProvider.js:66
|
#: src/core/MailProvider.js:66
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Welcome ${ name } to PixelPlanet, please verify your mail"
|
msgid "Welcome ${ name } to PixelPlanet, please verify your mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/core/MailProvider.js:67
|
#: src/core/MailProvider.js:67
|
||||||
#, javascript-format
|
|
||||||
msgid "Hello ${ name }"
|
msgid "Hello ${ name }"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,6 @@ msgid "try again after ${ ti }min"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/store/actions/fetch.js:70
|
#: src/store/actions/fetch.js:70
|
||||||
#, javascript-format
|
|
||||||
msgid "Connection error ${ code } :("
|
msgid "Connection error ${ code } :("
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -231,6 +230,12 @@ msgstr ""
|
||||||
msgid "You have new messages in chat"
|
msgid "You have new messages in chat"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/Converter.jsx:561
|
||||||
|
#: src/components/CoordinatesBox.jsx:31
|
||||||
|
#: src/components/ModWatchtools.jsx:371
|
||||||
|
msgid "Copy to Clipboard"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/OnlineBox.jsx:40
|
#: src/components/OnlineBox.jsx:40
|
||||||
msgid "Online Users on Canvas"
|
msgid "Online Users on Canvas"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -243,13 +248,6 @@ msgstr ""
|
||||||
msgid "Pixels placed"
|
msgid "Pixels placed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:565
|
|
||||||
#: src/components/CoordinatesBox.jsx:31
|
|
||||||
#: src/components/ModWatchtools.jsx:378
|
|
||||||
#: src/components/ModWatchtools.jsx:396
|
|
||||||
msgid "Copy to Clipboard"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/buttons/CanvasSwitchButton.jsx:20
|
#: src/components/buttons/CanvasSwitchButton.jsx:20
|
||||||
#: src/components/windows/index.js:19
|
#: src/components/windows/index.js:19
|
||||||
msgid "Canvas Selection"
|
msgid "Canvas Selection"
|
||||||
|
@ -281,7 +279,7 @@ msgstr ""
|
||||||
|
|
||||||
#: src/components/Admintools.jsx:103
|
#: src/components/Admintools.jsx:103
|
||||||
#: src/components/ModCanvastools.jsx:222
|
#: src/components/ModCanvastools.jsx:222
|
||||||
#: src/components/ModWatchtools.jsx:120
|
#: src/components/ModWatchtools.jsx:118
|
||||||
#: src/components/Window.jsx:157
|
#: src/components/Window.jsx:157
|
||||||
#: src/components/Window.jsx:260
|
#: src/components/Window.jsx:260
|
||||||
#: src/components/contextmenus/ChannelContextMenu.jsx:59
|
#: src/components/contextmenus/ChannelContextMenu.jsx:59
|
||||||
|
@ -312,26 +310,6 @@ msgstr ""
|
||||||
msgid "Resize"
|
msgid "Resize"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/BanInfo.jsx:75
|
|
||||||
#: src/components/buttons/HelpButton.jsx:20
|
|
||||||
#: src/components/windows/index.js:13
|
|
||||||
msgid "Help"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/buttons/SettingsButton.jsx:21
|
|
||||||
#: src/components/windows/index.js:14
|
|
||||||
msgid "Settings"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/buttons/LogInButton.jsx:20
|
|
||||||
#: src/components/windows/index.js:15
|
|
||||||
msgid "User Area"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/buttons/DownloadButton.jsx:36
|
|
||||||
msgid "Make Screenshot"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/buttons/GlobeButton.jsx:34
|
#: src/components/buttons/GlobeButton.jsx:34
|
||||||
msgid "Globe View"
|
msgid "Globe View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -344,6 +322,26 @@ msgstr ""
|
||||||
msgid "Open Palette"
|
msgid "Open Palette"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/buttons/SettingsButton.jsx:21
|
||||||
|
#: src/components/windows/index.js:14
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/BanInfo.jsx:75
|
||||||
|
#: src/components/buttons/HelpButton.jsx:20
|
||||||
|
#: src/components/windows/index.js:13
|
||||||
|
msgid "Help"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/buttons/LogInButton.jsx:20
|
||||||
|
#: src/components/windows/index.js:15
|
||||||
|
msgid "User Area"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/buttons/DownloadButton.jsx:36
|
||||||
|
msgid "Make Screenshot"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/index.js:16
|
#: src/components/windows/index.js:16
|
||||||
msgid "Registration"
|
msgid "Registration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -449,6 +447,99 @@ msgstr ""
|
||||||
msgid "Why?"
|
msgid "Why?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:86
|
||||||
|
msgid "Show Grid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:91
|
||||||
|
msgid "Turn on grid to highlight pixel borders."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:94
|
||||||
|
msgid "Show Pixel Activity"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:99
|
||||||
|
msgid "Show circles where pixels are placed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:102
|
||||||
|
msgid "Disable Game Sounds"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:108
|
||||||
|
msgid "All sound effects will be disabled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:112
|
||||||
|
msgid ""
|
||||||
|
"Your Browser doesn't allow us to use AudioContext to play sounds. Do you "
|
||||||
|
"have some privacy feature blocking us?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:118
|
||||||
|
msgid "Enable chat notifications"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:122
|
||||||
|
msgid "Play a sound when new chat messages arrive"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:125
|
||||||
|
msgid "Auto Zoom In"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:130
|
||||||
|
msgid ""
|
||||||
|
"Zoom in instead of placing a pixel when you tap the canvas and your zoom is "
|
||||||
|
"small."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:133
|
||||||
|
msgid "Compact Palette"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:138
|
||||||
|
msgid "Display Palette in a compact form that takes less screen space."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:141
|
||||||
|
msgid "Potato Mode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:145
|
||||||
|
msgid "For when you are playing on a potato."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/Converter.jsx:376
|
||||||
|
#: src/components/windows/Settings.jsx:148
|
||||||
|
msgid "Light Grid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:152
|
||||||
|
msgid "Show Grid in white instead of black."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:156
|
||||||
|
msgid "Historical View"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:161
|
||||||
|
msgid "Check out past versions of the canvas."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:166
|
||||||
|
msgid "Themes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:171
|
||||||
|
msgid "How pixelplanet should look like."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:178
|
||||||
|
msgid "Select Language"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:42
|
#: src/components/windows/Help.jsx:42
|
||||||
msgid "Place color pixels on a large canvas with other players online!"
|
msgid "Place color pixels on a large canvas with other players online!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -518,7 +609,6 @@ msgid "Press ${ bindG } to toggle grid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:64
|
#: src/components/windows/Help.jsx:64
|
||||||
#, javascript-format
|
|
||||||
msgid "Press ${ bindX } to toggle showing of pixel activity"
|
msgid "Press ${ bindX } to toggle showing of pixel activity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -528,7 +618,6 @@ msgid "Press ${ bindH } to toggle historical view"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:66
|
#: src/components/windows/Help.jsx:66
|
||||||
#, javascript-format
|
|
||||||
msgid "Press ${ bindR } to copy coordinates"
|
msgid "Press ${ bindR } to copy coordinates"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -550,7 +639,6 @@ msgid "Press ${ bindAUp }, ${ bindALeft }, ${ bindADown }, ${ bindARight } to mo
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:70
|
#: src/components/windows/Help.jsx:70
|
||||||
#, javascript-format
|
|
||||||
msgid "Drag ${ mouseSymbol } mouse or ${ touchSymbol } pan to move"
|
msgid "Drag ${ mouseSymbol } mouse or ${ touchSymbol } pan to move"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -560,7 +648,6 @@ msgid "Scroll ${ mouseSymbol } mouse wheel or ${ touchSymbol } pinch to zoom"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:72
|
#: src/components/windows/Help.jsx:72
|
||||||
#, javascript-format
|
|
||||||
msgid "Hold left ${ bindShift } for placing while moving mouse"
|
msgid "Hold left ${ bindShift } for placing while moving mouse"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -579,14 +666,12 @@ msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:75
|
#: src/components/windows/Help.jsx:75
|
||||||
#: src/components/windows/Help.jsx:87
|
#: src/components/windows/Help.jsx:87
|
||||||
#, javascript-format
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click ${ mouseSymbol } middle mouse button or ${ touchSymbol } long-tap to "
|
"Click ${ mouseSymbol } middle mouse button or ${ touchSymbol } long-tap to "
|
||||||
"select current hovering color"
|
"select current hovering color"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:81
|
#: src/components/windows/Help.jsx:81
|
||||||
#, javascript-format
|
|
||||||
msgid "Press ${ bindE } and ${ bindC } to fly up and down"
|
msgid "Press ${ bindE } and ${ bindC } to fly up and down"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -603,7 +688,6 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:84
|
#: src/components/windows/Help.jsx:84
|
||||||
#, javascript-format
|
|
||||||
msgid "${ mouseSymbol } Right click and drag mouse to pan"
|
msgid "${ mouseSymbol } Right click and drag mouse to pan"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -626,103 +710,9 @@ msgid "Credit for the Palette of the Moon goes to ${ starhouseLink }."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:97
|
#: src/components/windows/Help.jsx:97
|
||||||
#, javascript-format
|
|
||||||
msgid "Credit for the Palette of the Top10 canvas goes to ${ vinikLink }."
|
msgid "Credit for the Palette of the Top10 canvas goes to ${ vinikLink }."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:86
|
|
||||||
msgid "Show Grid"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:91
|
|
||||||
msgid "Turn on grid to highlight pixel borders."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:94
|
|
||||||
msgid "Show Pixel Activity"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:99
|
|
||||||
msgid "Show circles where pixels are placed."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:102
|
|
||||||
msgid "Disable Game Sounds"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:108
|
|
||||||
msgid "All sound effects will be disabled."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:112
|
|
||||||
msgid ""
|
|
||||||
"Your Browser doesn't allow us to use AudioContext to play sounds. Do you "
|
|
||||||
"have some privacy feature blocking us?"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:118
|
|
||||||
msgid "Enable chat notifications"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:122
|
|
||||||
msgid "Play a sound when new chat messages arrive"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:125
|
|
||||||
msgid "Auto Zoom In"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:130
|
|
||||||
msgid ""
|
|
||||||
"Zoom in instead of placing a pixel when you tap the canvas and your zoom is "
|
|
||||||
"small."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:133
|
|
||||||
msgid "Compact Palette"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:138
|
|
||||||
msgid "Display Palette in a compact form that takes less screen space."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:141
|
|
||||||
msgid "Potato Mode"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:145
|
|
||||||
msgid "For when you are playing on a potato."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/Converter.jsx:380
|
|
||||||
#: src/components/windows/Settings.jsx:148
|
|
||||||
msgid "Light Grid"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:152
|
|
||||||
msgid "Show Grid in white instead of black."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:156
|
|
||||||
msgid "Historical View"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:161
|
|
||||||
msgid "Check out past versions of the canvas."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:166
|
|
||||||
msgid "Themes"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:171
|
|
||||||
msgid "How pixelplanet should look like."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:178
|
|
||||||
msgid "Select Language"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/UserArea.jsx:36
|
#: src/components/windows/UserArea.jsx:36
|
||||||
#: src/components/windows/UserArea.jsx:56
|
#: src/components/windows/UserArea.jsx:56
|
||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
|
@ -836,6 +826,14 @@ msgid ""
|
||||||
"how the canvas was at that time."
|
"how the canvas was at that time."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/ForgotPassword.jsx:58
|
||||||
|
msgid "Sent you a mail with instructions to reset your password."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/ForgotPassword.jsx:69
|
||||||
|
msgid "Enter your mail address and we will send you a new password:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Chat.jsx:180
|
#: src/components/windows/Chat.jsx:180
|
||||||
msgid "Start chatting here"
|
msgid "Start chatting here"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -852,14 +850,6 @@ msgstr ""
|
||||||
msgid "Channel settings"
|
msgid "Channel settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/ForgotPassword.jsx:58
|
|
||||||
msgid "Sent you a mail with instructions to reset your password."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/ForgotPassword.jsx:69
|
|
||||||
msgid "Enter your mail address and we will send you a new password:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/Captcha.jsx:51
|
#: src/components/Captcha.jsx:51
|
||||||
#: src/components/Captcha.jsx:105
|
#: src/components/Captcha.jsx:105
|
||||||
msgid "Could not load captcha"
|
msgid "Could not load captcha"
|
||||||
|
@ -941,6 +931,13 @@ msgstr ""
|
||||||
msgid "Password must be shorter than 60 characters."
|
msgid "Password must be shorter than 60 characters."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ChangeMail.jsx:91
|
||||||
|
#: src/components/ChangeName.jsx:68
|
||||||
|
#: src/components/ChangePassword.jsx:109
|
||||||
|
#: src/components/LanguageSelect.jsx:80
|
||||||
|
msgid "Save"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/GetIID.jsx:44
|
#: src/components/GetIID.jsx:44
|
||||||
msgid "Get IID"
|
msgid "Get IID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -949,13 +946,6 @@ msgstr ""
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/ChangeMail.jsx:91
|
|
||||||
#: src/components/ChangeName.jsx:68
|
|
||||||
#: src/components/ChangePassword.jsx:109
|
|
||||||
#: src/components/LanguageSelect.jsx:80
|
|
||||||
msgid "Save"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/LogInArea.jsx:19
|
#: src/components/LogInArea.jsx:19
|
||||||
msgid "Login to access more features and stats."
|
msgid "Login to access more features and stats."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1030,77 +1020,77 @@ msgstr ""
|
||||||
msgid "Choose Canvas"
|
msgid "Choose Canvas"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:217
|
#: src/components/Converter.jsx:216
|
||||||
msgid "Palette Download"
|
msgid "Palette Download"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:219
|
#: src/components/Converter.jsx:218
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Palette for ${ gimpLink }"
|
msgid "Palette for ${ gimpLink }"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:240
|
#: src/components/Converter.jsx:236
|
||||||
msgid "Image Converter"
|
msgid "Image Converter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:241
|
#: src/components/Converter.jsx:237
|
||||||
msgid "Convert an image to canvas colors"
|
msgid "Convert an image to canvas colors"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:260
|
#: src/components/Converter.jsx:256
|
||||||
msgid "Choose Strategy"
|
msgid "Choose Strategy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:298
|
#: src/components/Converter.jsx:294
|
||||||
msgid "Serpentine"
|
msgid "Serpentine"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:300
|
#: src/components/Converter.jsx:296
|
||||||
msgid "Minimum Color Distance"
|
msgid "Minimum Color Distance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:327
|
#: src/components/Converter.jsx:323
|
||||||
msgid "Calculate like GIMP"
|
msgid "Calculate like GIMP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:331
|
#: src/components/Converter.jsx:327
|
||||||
msgid "Choose Color Mode"
|
msgid "Choose Color Mode"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:360
|
#: src/components/Converter.jsx:356
|
||||||
msgid "Add Grid (uncheck if you need a 1:1 template)"
|
msgid "Add Grid (uncheck if you need a 1:1 template)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:382
|
#: src/components/Converter.jsx:378
|
||||||
#: src/components/Converter.jsx:398
|
#: src/components/Converter.jsx:394
|
||||||
msgid "Offset"
|
msgid "Offset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:427
|
#: src/components/Converter.jsx:423
|
||||||
msgid "Scale Image"
|
msgid "Scale Image"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:438
|
#: src/components/Converter.jsx:434
|
||||||
msgid "Width"
|
msgid "Width"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:469
|
#: src/components/Converter.jsx:465
|
||||||
msgid "Height"
|
msgid "Height"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:508
|
#: src/components/Converter.jsx:504
|
||||||
msgid "Keep Ratio"
|
msgid "Keep Ratio"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:521
|
#: src/components/Converter.jsx:517
|
||||||
msgid "Anti Aliasing"
|
msgid "Anti Aliasing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:535
|
#: src/components/Converter.jsx:531
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Converter.jsx:553
|
#: src/components/Converter.jsx:549
|
||||||
msgid "Download Template"
|
msgid "Download Template"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1199,7 +1189,7 @@ msgstr ""
|
||||||
msgid "Countries by Pixels Today"
|
msgid "Countries by Pixels Today"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/core/chartSettings.js:351
|
#: src/core/chartSettings.js:352
|
||||||
msgid "Total Pixels placed per day"
|
msgid "Total Pixels placed per day"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1225,6 +1215,10 @@ msgstr ""
|
||||||
msgid "Click here to request a new verification mail."
|
msgid "Click here to request a new verification mail."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ChangeName.jsx:64
|
||||||
|
msgid "New Username"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/ChangePassword.jsx:21
|
#: src/components/ChangePassword.jsx:21
|
||||||
msgid "Passwords do not match."
|
msgid "Passwords do not match."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1245,10 +1239,6 @@ msgstr ""
|
||||||
msgid "Confirm New Password"
|
msgid "Confirm New Password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/ChangeName.jsx:64
|
|
||||||
msgid "New Username"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ChangeMail.jsx:59
|
#: src/components/ChangeMail.jsx:59
|
||||||
msgid ""
|
msgid ""
|
||||||
"Changed Mail successfully. We sent you a verification mail, "
|
"Changed Mail successfully. We sent you a verification mail, "
|
||||||
|
@ -1349,14 +1339,14 @@ msgstr ""
|
||||||
#: src/components/ModCanvastools.jsx:330
|
#: src/components/ModCanvastools.jsx:330
|
||||||
#: src/components/ModCanvastools.jsx:403
|
#: src/components/ModCanvastools.jsx:403
|
||||||
#: src/components/ModCanvastools.jsx:486
|
#: src/components/ModCanvastools.jsx:486
|
||||||
#: src/components/ModWatchtools.jsx:176
|
#: src/components/ModWatchtools.jsx:174
|
||||||
msgid "Top-left corner"
|
msgid "Top-left corner"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/ModCanvastools.jsx:347
|
#: src/components/ModCanvastools.jsx:347
|
||||||
#: src/components/ModCanvastools.jsx:420
|
#: src/components/ModCanvastools.jsx:420
|
||||||
#: src/components/ModCanvastools.jsx:503
|
#: src/components/ModCanvastools.jsx:503
|
||||||
#: src/components/ModWatchtools.jsx:193
|
#: src/components/ModWatchtools.jsx:191
|
||||||
msgid "Bottom-right corner"
|
msgid "Bottom-right corner"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1380,6 +1370,54 @@ msgstr ""
|
||||||
msgid "Stop Cleaner"
|
msgid "Stop Cleaner"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModWatchtools.jsx:48
|
||||||
|
msgid "Interval is invalid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModWatchtools.jsx:122
|
||||||
|
msgid "Check who placed in an area"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModWatchtools.jsx:123
|
||||||
|
msgid "Canvas"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModWatchtools.jsx:142
|
||||||
|
msgid "Interval"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModWatchtools.jsx:157
|
||||||
|
msgid "IID (optional)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModWatchtools.jsx:236
|
||||||
|
msgid "Get Pixels"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModWatchtools.jsx:267
|
||||||
|
msgid "Get Users"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModIIDtools.jsx:20
|
||||||
|
msgid "You must enter a duration"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModIIDtools.jsx:24
|
||||||
|
msgid "You must enter an IID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModIIDtools.jsx:53
|
||||||
|
msgid "IID Actions"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModIIDtools.jsx:80
|
||||||
|
msgid "Enter Reason"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/ModIIDtools.jsx:97
|
||||||
|
msgid "(0 = infinite)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Admintools.jsx:109
|
#: src/components/Admintools.jsx:109
|
||||||
msgid "IP Actions"
|
msgid "IP Actions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1412,52 +1450,8 @@ msgstr ""
|
||||||
msgid "User Name"
|
msgid "User Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/ModWatchtools.jsx:48
|
#: src/components/contextmenus/ChannelContextMenu.jsx:46
|
||||||
msgid "Interval is invalid"
|
msgid "Mute"
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModWatchtools.jsx:124
|
|
||||||
msgid "Check who placed in an area"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModWatchtools.jsx:125
|
|
||||||
msgid "Canvas"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModWatchtools.jsx:144
|
|
||||||
msgid "Interval"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModWatchtools.jsx:159
|
|
||||||
msgid "IID (optional)"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModWatchtools.jsx:239
|
|
||||||
msgid "Get Pixels"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModWatchtools.jsx:271
|
|
||||||
msgid "Get Users"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModIIDtools.jsx:20
|
|
||||||
msgid "You must enter a duration"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModIIDtools.jsx:24
|
|
||||||
msgid "You must enter an IID"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModIIDtools.jsx:53
|
|
||||||
msgid "IID Actions"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModIIDtools.jsx:80
|
|
||||||
msgid "Enter Reason"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/ModIIDtools.jsx:97
|
|
||||||
msgid "(0 = infinite)"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/contextmenus/UserContextMenu.jsx:49
|
#: src/components/contextmenus/UserContextMenu.jsx:49
|
||||||
|
@ -1472,10 +1466,6 @@ msgstr ""
|
||||||
msgid "Block"
|
msgid "Block"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/contextmenus/ChannelContextMenu.jsx:46
|
|
||||||
msgid "Mute"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:15
|
#: src/components/windows/Help.jsx:15
|
||||||
#: src/components/windows/Settings.jsx:87
|
#: src/components/windows/Settings.jsx:87
|
||||||
msgctxt "keybinds"
|
msgctxt "keybinds"
|
||||||
|
@ -1488,6 +1478,11 @@ msgctxt "keybinds"
|
||||||
msgid "X"
|
msgid "X"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/windows/Settings.jsx:103
|
||||||
|
msgctxt "keybinds"
|
||||||
|
msgid "M"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Help.jsx:17
|
#: src/components/windows/Help.jsx:17
|
||||||
#: src/components/windows/Settings.jsx:158
|
#: src/components/windows/Settings.jsx:158
|
||||||
msgctxt "keybinds"
|
msgctxt "keybinds"
|
||||||
|
@ -1538,8 +1533,3 @@ msgstr ""
|
||||||
msgctxt "keybinds"
|
msgctxt "keybinds"
|
||||||
msgid "C"
|
msgid "C"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/windows/Settings.jsx:103
|
|
||||||
msgctxt "keybinds"
|
|
||||||
msgid "M"
|
|
||||||
msgstr ""
|
|
||||||
|
|
7649
package-lock.json
generated
7649
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
66
package.json
66
package.json
|
@ -8,11 +8,8 @@
|
||||||
"description": "Unlimited planet canvas for placing pixels",
|
"description": "Unlimited planet canvas for placing pixels",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node scripts/build.js",
|
"build": "node scripts/build.js && npm run minify-css",
|
||||||
"build:server": "webpack --config ./webpack.config.server.js",
|
"build:dev": "webpack --env extract --config ./webpack.config.server.js && webpack --env extract --env development --config ./webpack.config.client.js && npm run minify-css",
|
||||||
"build:client": "node scripts/build.js --client",
|
|
||||||
"build:dev": "webpack --config ./webpack.config.server.js && webpack --env development --config ./webpack.config.client.js && npm run minify-css",
|
|
||||||
"update-browserlist": "browserslist --update-db",
|
|
||||||
"deploy": "ssh pixelplanet /home/pixelpla/rebuild.sh",
|
"deploy": "ssh pixelplanet /home/pixelpla/rebuild.sh",
|
||||||
"minify-css": "node scripts/minifyCss.js",
|
"minify-css": "node scripts/minifyCss.js",
|
||||||
"babel-node": "babel-node",
|
"babel-node": "babel-node",
|
||||||
|
@ -26,11 +23,11 @@
|
||||||
"not IE_Mob 11"
|
"not IE_Mob 11"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.0.1",
|
||||||
"chart.js": "^3.9.1",
|
"chart.js": "^3.9.1",
|
||||||
"compression": "^1.7.3",
|
"compression": "^1.7.3",
|
||||||
"cookie": "^0.5.0",
|
"cookie": "^0.5.0",
|
||||||
"core-js": "^3.34.0",
|
"core-js": "^3.23.4",
|
||||||
"etag": "^1.8.1",
|
"etag": "^1.8.1",
|
||||||
"express": "^4.17.2",
|
"express": "^4.17.2",
|
||||||
"express-session": "^1.17.2",
|
"express-session": "^1.17.2",
|
||||||
|
@ -39,7 +36,7 @@
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"mysql2": "^2.3.3",
|
"mysql2": "^2.3.3",
|
||||||
"nodemailer": "^6.9.7",
|
"nodemailer": "^6.7.8",
|
||||||
"passport": "^0.6.0",
|
"passport": "^0.6.0",
|
||||||
"passport-discord": "^0.1.4",
|
"passport-discord": "^0.1.4",
|
||||||
"passport-facebook": "^3.0.0",
|
"passport-facebook": "^3.0.0",
|
||||||
|
@ -51,56 +48,57 @@
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-chartjs-2": "^4.3.1",
|
"react-chartjs-2": "^4.3.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.3.1",
|
||||||
"react-redux": "^8.0.2",
|
"react-redux": "^8.0.2",
|
||||||
"react-stay-scrolled": "^8.0.0",
|
"react-stay-scrolled": "^8.0.0",
|
||||||
"react-toggle": "^4.1.3",
|
"react-toggle": "^4.1.3",
|
||||||
"redis": "^4.6.11",
|
"redis": "^4.3.1",
|
||||||
"redux": "^4.1.2",
|
"redux": "^4.1.2",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-thunk": "^2.4.1",
|
"redux-thunk": "^2.4.1",
|
||||||
"reselect": "^4.1.6",
|
"reselect": "^4.1.6",
|
||||||
"sequelize": "^6.35.2",
|
"sequelize": "^6.21.6",
|
||||||
"sharp": "^0.31.0",
|
"sharp": "^0.31.0",
|
||||||
"startaudiocontext": "^1.2.1",
|
"startaudiocontext": "^1.2.1",
|
||||||
"three": "^0.143.0",
|
"three": "^0.143.0",
|
||||||
"three-trackballcontrols": "^0.9.0",
|
"three-trackballcontrols": "^0.9.0",
|
||||||
"ttag": "^1.8.3",
|
"ttag": "^1.7.24",
|
||||||
"url-search-params-polyfill": "^8.2.5",
|
"url-search-params-polyfill": "^8.1.1",
|
||||||
"winston": "^3.11.0",
|
"winston": "^3.8.2",
|
||||||
"winston-daily-rotate-file": "^4.5.5",
|
"winston-daily-rotate-file": "^4.5.5",
|
||||||
"ws": "^8.15.1"
|
"ws": "^8.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.23.4",
|
"@babel/cli": "^7.21.0",
|
||||||
"@babel/core": "^7.23.6",
|
"@babel/core": "^7.21.0",
|
||||||
"@babel/eslint-parser": "^7.23.3",
|
"@babel/eslint-parser": "^7.19.1",
|
||||||
"@babel/node": "^7.22.19",
|
"@babel/node": "^7.20.7",
|
||||||
"@babel/plugin-transform-react-constant-elements": "^7.23.3",
|
"@babel/plugin-transform-react-constant-elements": "^7.20.2",
|
||||||
"@babel/plugin-transform-react-inline-elements": "^7.23.3",
|
"@babel/plugin-transform-react-inline-elements": "^7.21.0",
|
||||||
"@babel/preset-env": "^7.23.6",
|
"@babel/preset-env": "^7.20.2",
|
||||||
"@babel/preset-react": "^7.23.3",
|
"@babel/preset-react": "^7.18.6",
|
||||||
"babel-loader": "^9.1.3",
|
"assets-webpack-plugin": "^7.1.1",
|
||||||
|
"babel-loader": "^8.2.3",
|
||||||
"babel-plugin-transform-react-pure-class-to-function": "^1.0.1",
|
"babel-plugin-transform-react-pure-class-to-function": "^1.0.1",
|
||||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
||||||
"babel-plugin-ttag": "^1.8.5",
|
"babel-plugin-ttag": "^1.8.5",
|
||||||
"clean-css": "^5.2.2",
|
"clean-css": "^5.2.2",
|
||||||
"clean-css-loader": "^4.2.1",
|
"clean-css-loader": "^4.1.1",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"css-loader": "^6.8.1",
|
"css-loader": "^6.5.1",
|
||||||
"eslint": "^8.55.0",
|
"eslint": "^8.36.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-plugin-import": "^2.29.0",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.32.2",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"generate-package-json-webpack-plugin": "^2.6.0",
|
"generate-package-json-webpack-plugin": "^2.6.0",
|
||||||
"ttag-cli": "^1.10.9",
|
"ttag-cli": "^1.9.3",
|
||||||
"ttag-po-loader": "0.0.2",
|
"ttag-po-loader": "0.0.2",
|
||||||
"webpack": "^5.89.0",
|
"webpack": "^5.67.0",
|
||||||
"webpack-bundle-analyzer": "^4.10.1",
|
"webpack-bundle-analyzer": "^4.5.0",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-cli": "^4.9.2",
|
||||||
"webpack-node-externals": "^3.0.0"
|
"webpack-node-externals": "^3.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
* webpack loader that
|
|
||||||
* marks modules that include ttag as non-cachable
|
|
||||||
*/
|
|
||||||
const filtered = {};
|
|
||||||
|
|
||||||
module.exports = function (source) {
|
|
||||||
if (filtered.hasOwnProperty(this.resourcePath)) {
|
|
||||||
if (filtered[this.resourcePath]) {
|
|
||||||
this.cacheable(false);
|
|
||||||
}
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
const hasTtag = source.slice(0, 400).includes('ttag');
|
|
||||||
filtered[this.resourcePath] = hasTtag;
|
|
||||||
if (hasTtag) {
|
|
||||||
this.cacheable(false);
|
|
||||||
}
|
|
||||||
return source;
|
|
||||||
}
|
|
181
scripts/build.js
181
scripts/build.js
|
@ -3,52 +3,14 @@
|
||||||
* Lets split that here
|
* Lets split that here
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const fs = require('fs');
|
|
||||||
const { spawn } = require('child_process');
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
|
||||||
const minifyCss = require('./minifyCss');
|
|
||||||
const serverConfig = require('../webpack.config.server.js');
|
const serverConfig = require('../webpack.config.server.js');
|
||||||
const clientConfig = require('../webpack.config.client.js');
|
const clientConfig = require('../webpack.config.client.js');
|
||||||
const { getAllAvailableLocals } = clientConfig;
|
const { getAllAvailableLocals } = clientConfig;
|
||||||
|
|
||||||
let langs = 'all';
|
|
||||||
let doBuildServer = false;
|
|
||||||
let doBuildClient = false;
|
|
||||||
let parallel = false;
|
|
||||||
let recursion = false;
|
|
||||||
for (let i = 0; i < process.argv.length; i += 1) {
|
|
||||||
switch (process.argv[i]) {
|
|
||||||
case '--langs': {
|
|
||||||
const newLangs = process.argv[++i];
|
|
||||||
if (newLangs) langs = newLangs;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case '--client':
|
|
||||||
doBuildClient = true;
|
|
||||||
break;
|
|
||||||
case `--server`:
|
|
||||||
doBuildServer = true;
|
|
||||||
break;
|
|
||||||
case '--parallel':
|
|
||||||
parallel = true;
|
|
||||||
break;
|
|
||||||
case '--recursion':
|
|
||||||
recursion = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!doBuildServer && !doBuildClient) {
|
|
||||||
doBuildServer = true;
|
|
||||||
doBuildClient = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function compile(webpackConfig) {
|
function compile(webpackConfig) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
webpack(webpackConfig, (err, stats) => {
|
webpack(webpackConfig).run((err, stats) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
|
@ -59,146 +21,31 @@ function compile(webpackConfig) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildServer() {
|
async function buildProduction() {
|
||||||
|
// server files
|
||||||
console.log('-----------------------------');
|
console.log('-----------------------------');
|
||||||
console.log(`Build server...`);
|
console.log(`Build server...`);
|
||||||
console.log('-----------------------------');
|
console.log('-----------------------------');
|
||||||
const ts = Date.now();
|
await compile(serverConfig({
|
||||||
|
development: false,
|
||||||
return new Promise((resolve, reject) => {
|
extract: false,
|
||||||
const argsc = (langs === 'all')
|
}));
|
||||||
? ['webpack', '--env', 'extract', '--config', './webpack.config.server.js']
|
// client files
|
||||||
: ['webpack', '--config', './webpack.config.server.js']
|
const langs = getAllAvailableLocals();
|
||||||
const serverCompile = spawn('npx', argsc);
|
console.log('Available locales:', langs);
|
||||||
serverCompile.stdout.on('data', (data) => {
|
const st = Date.now();
|
||||||
console.log(data.toString());
|
for(let i = 0; i < langs.length; i += 1) {
|
||||||
});
|
const lang = langs[i];
|
||||||
serverCompile.stderr.on('data', (data) => {
|
|
||||||
console.error(data.toString());
|
|
||||||
});
|
|
||||||
serverCompile.on('close', (code) => {
|
|
||||||
if (code) {
|
|
||||||
reject(new Error('Server compilation failed!'));
|
|
||||||
} else {
|
|
||||||
console.log('---------------------------------------');
|
|
||||||
console.log(`Server Compilation finished in ${Math.floor((Date.now() - ts) / 1000)}s`);
|
|
||||||
console.log('---------------------------------------');
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildClients(slangs) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const clientCompile = spawn('npm', ['run', 'build', '--', '--client', '--recursion', '--langs', slangs.join(',')]);
|
|
||||||
clientCompile.stdout.on('data', (data) => {
|
|
||||||
console.log(data.toString());
|
|
||||||
});
|
|
||||||
clientCompile.stderr.on('data', (data) => {
|
|
||||||
console.error(data.toString());
|
|
||||||
});
|
|
||||||
clientCompile.on('close', (code) => {
|
|
||||||
if (code) {
|
|
||||||
reject(new Error('Client compilation failed!'));
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function buildClientsSync(avlangs) {
|
|
||||||
for(let i = 0; i < avlangs.length; i += 1) {
|
|
||||||
const lang = avlangs[i];
|
|
||||||
console.log(`Build client for locale ${lang}...`);
|
console.log(`Build client for locale ${lang}...`);
|
||||||
|
console.log('-----------------------------');
|
||||||
await compile(clientConfig({
|
await compile(clientConfig({
|
||||||
development: false,
|
development: false,
|
||||||
analyze: false,
|
analyze: false,
|
||||||
extract: false,
|
extract: false,
|
||||||
locale: lang,
|
locale: lang,
|
||||||
clean: false,
|
|
||||||
readonly: recursion,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function buildClientsParallel(avlangs) {
|
|
||||||
const st = Date.now();
|
|
||||||
const numProc = 3;
|
|
||||||
let nump = Math.floor(avlangs.length / numProc);
|
|
||||||
if (!nump) nump = 1;
|
|
||||||
|
|
||||||
const promises = [];
|
|
||||||
while (avlangs.length >= nump) {
|
|
||||||
const slangs = avlangs.splice(0, nump);
|
|
||||||
promises.push(buildClients(slangs));
|
|
||||||
}
|
|
||||||
if (avlangs.length) {
|
|
||||||
promises.push(buildClientsSync(avlangs));
|
|
||||||
}
|
|
||||||
return Promise.all(promises);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function buildProduction() {
|
|
||||||
const st = Date.now();
|
|
||||||
// cleanup old files
|
|
||||||
if (!recursion) {
|
|
||||||
fs.rmSync(path.resolve(__dirname, '..', 'node_modules', '.cache', 'webpack'), { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
// decide which languages to build
|
|
||||||
let avlangs = getAllAvailableLocals();
|
|
||||||
if (langs !== 'all') {
|
|
||||||
avlangs = langs.split(',').map((l) => l.trim())
|
|
||||||
.filter((l) => avlangs.includes(l));
|
|
||||||
if (!avlangs.length) {
|
|
||||||
console.error(`ERROR: language ${langs} not available`);
|
|
||||||
process.exit(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log('Building locales:', avlangs);
|
|
||||||
|
|
||||||
const promises = [];
|
|
||||||
|
|
||||||
if (doBuildServer) {
|
|
||||||
promises.push(buildServer());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doBuildClient) {
|
|
||||||
if (!recursion) {
|
|
||||||
console.log(
|
|
||||||
'Building one package seperately to populate cache and possibly extract langs...',
|
|
||||||
);
|
|
||||||
await compile(clientConfig({
|
|
||||||
development: false,
|
|
||||||
analyze: false,
|
|
||||||
extract: (langs === 'all'),
|
|
||||||
locale: avlangs.shift(),
|
|
||||||
clean: true,
|
|
||||||
readonly: false,
|
|
||||||
}));
|
|
||||||
|
|
||||||
console.log('-----------------------------');
|
|
||||||
console.log(`Minify CSS assets...`);
|
|
||||||
console.log('-----------------------------');
|
|
||||||
await minifyCss();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parallel) {
|
|
||||||
promises.push(buildClientsParallel(avlangs));
|
|
||||||
} else {
|
|
||||||
promises.push(buildClientsSync(avlangs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Promise.all(promises);
|
|
||||||
|
|
||||||
if (!recursion) {
|
|
||||||
console.log(`Finished building in ${(Date.now() - st) / 1000}s`);
|
console.log(`Finished building in ${(Date.now() - st) / 1000}s`);
|
||||||
} else {
|
|
||||||
console.log(`Worker done in ${(Date.now() - st) / 1000}s`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildProduction();
|
buildProduction();
|
||||||
|
|
|
@ -14,7 +14,6 @@ const path = require('path');
|
||||||
const CleanCSS = require('clean-css');
|
const CleanCSS = require('clean-css');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
const buildTs = Date.now();
|
|
||||||
const assetdir = path.resolve(__dirname, '..', 'dist', 'public', 'assets');
|
const assetdir = path.resolve(__dirname, '..', 'dist', 'public', 'assets');
|
||||||
const builddir = path.resolve(__dirname, '..', 'dist');
|
const builddir = path.resolve(__dirname, '..', 'dist');
|
||||||
|
|
||||||
|
@ -24,6 +23,7 @@ FILES.push('default.css');
|
||||||
|
|
||||||
async function minifyCss() {
|
async function minifyCss() {
|
||||||
console.log('Minifying css');
|
console.log('Minifying css');
|
||||||
|
const assets = {};
|
||||||
FILES.forEach((file) => {
|
FILES.forEach((file) => {
|
||||||
const input = fs.readFileSync(path.resolve(FOLDER, file), 'utf8');
|
const input = fs.readFileSync(path.resolve(FOLDER, file), 'utf8');
|
||||||
const options = {};
|
const options = {};
|
||||||
|
@ -48,7 +48,10 @@ async function minifyCss() {
|
||||||
}
|
}
|
||||||
const filename = `${key}.${hash.substr(0, 8)}.css`;
|
const filename = `${key}.${hash.substr(0, 8)}.css`;
|
||||||
fs.writeFileSync(path.resolve(assetdir, filename), output.styles, 'utf8');
|
fs.writeFileSync(path.resolve(assetdir, filename), output.styles, 'utf8');
|
||||||
|
assets[key] = `/assets/${filename}`;
|
||||||
});
|
});
|
||||||
|
const json = JSON.stringify(assets);
|
||||||
|
fs.writeFileSync(path.resolve(builddir, 'styleassets.json'), json);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doMinifyCss() {
|
async function doMinifyCss() {
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import assetWatcher from './core/fsWatcher';
|
|
||||||
import canvases from './core/canvases';
|
import canvases from './core/canvases';
|
||||||
import ttag from './core/ttag';
|
import ttag from './core/ttag';
|
||||||
|
|
||||||
|
@ -59,21 +58,16 @@ function getCanvases(t) {
|
||||||
return localizedCanvases;
|
return localizedCanvases;
|
||||||
}
|
}
|
||||||
|
|
||||||
function translateCanvases() {
|
const lCanvases = {};
|
||||||
const parsedCanvases = {};
|
(() => {
|
||||||
const langs = Object.keys(ttag);
|
const langs = Object.keys(ttag);
|
||||||
langs.forEach((lang) => {
|
langs.forEach((lang) => {
|
||||||
parsedCanvases[lang] = getCanvases(ttag[lang].t);
|
lCanvases[lang] = getCanvases(ttag[lang].t);
|
||||||
});
|
});
|
||||||
return parsedCanvases;
|
})();
|
||||||
|
|
||||||
|
export function getLocalizedCanvases(lang) {
|
||||||
|
return lCanvases[lang] || lCanvases.default;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lCanvases = translateCanvases();
|
export default lCanvases;
|
||||||
// reload on asset change
|
|
||||||
assetWatcher.onChange(() => {
|
|
||||||
lCanvases = translateCanvases();
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function getLocalizedCanvases(lang = 'en') {
|
|
||||||
return lCanvases[lang] || lCanvases.en;
|
|
||||||
}
|
|
||||||
|
|
|
@ -66,14 +66,14 @@ function LanguageSelect() {
|
||||||
/* set with selected language */
|
/* set with selected language */
|
||||||
const d = new Date();
|
const d = new Date();
|
||||||
d.setTime(d.getTime() + 24 * MONTH);
|
d.setTime(d.getTime() + 24 * MONTH);
|
||||||
let { hostname } = window.location;
|
let { host } = window.location;
|
||||||
if (hostname.lastIndexOf('.') !== hostname.indexOf('.')) {
|
if (host.lastIndexOf('.') !== host.indexOf('.')) {
|
||||||
hostname = hostname.slice(hostname.indexOf('.'));
|
host = host.slice(host.indexOf('.'));
|
||||||
} else {
|
} else {
|
||||||
hostname = `.${hostname}`;
|
host = `.${host}`;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
document.cookie = `plang=${langSel};expires=${d.toUTCString()};path=/;domain=${hostname}`;
|
document.cookie = `plang=${langSel};expires=${d.toUTCString()};path=/;domain=${host}`;
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -192,7 +192,7 @@ export class ChatProvider {
|
||||||
|
|
||||||
getDefaultChannels(lang) {
|
getDefaultChannels(lang) {
|
||||||
const langChannel = {};
|
const langChannel = {};
|
||||||
if (lang && lang !== 'en') {
|
if (lang && lang !== 'default') {
|
||||||
const { langChannels } = this;
|
const { langChannels } = this;
|
||||||
if (langChannels[lang]) {
|
if (langChannels[lang]) {
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -68,7 +68,7 @@ export class MailProvider {
|
||||||
${t`welcome to our little community of pixelplacers, to use your account, you have to verify your mail. You can do that here: `} <a href="${verifyUrl}">${t`Click to Verify`}</a>. ${t`Or by copying following url:`}<br />${verifyUrl}\n<br />
|
${t`welcome to our little community of pixelplacers, to use your account, you have to verify your mail. You can do that here: `} <a href="${verifyUrl}">${t`Click to Verify`}</a>. ${t`Or by copying following url:`}<br />${verifyUrl}\n<br />
|
||||||
${t`Have fun and don't hesitate to contact us if you encounter any problems :)`}<br />
|
${t`Have fun and don't hesitate to contact us if you encounter any problems :)`}<br />
|
||||||
${t`Thanks`}<br /><br />
|
${t`Thanks`}<br /><br />
|
||||||
<img alt="" src="https://pixelplanet.fun/tile.png" style="height:64px; width:64px" />`;
|
<img alt="" src="https://assets.pixelplanet.fun/tile.png" style="height:64px; width:64px" />`;
|
||||||
this.sendMail(to, subject, html);
|
this.sendMail(to, subject, html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ export class MailProvider {
|
||||||
const html = `<em>${t`Hello`}</em>,<br />
|
const html = `<em>${t`Hello`}</em>,<br />
|
||||||
${t`You requested to get a new password. You can change your password within the next 30min here: `} <a href="${restoreUrl}">${t`Reset Password`}</a>. ${t`Or by copying following url:`}<br />${restoreUrl}\n<br />
|
${t`You requested to get a new password. You can change your password within the next 30min here: `} <a href="${restoreUrl}">${t`Reset Password`}</a>. ${t`Or by copying following url:`}<br />${restoreUrl}\n<br />
|
||||||
${t`If you did not request this mail, please just ignore it (the ip that requested this mail was ${ip}).`}<br />
|
${t`If you did not request this mail, please just ignore it (the ip that requested this mail was ${ip}).`}<br />
|
||||||
${t`Thanks`}<br /><br />\n<img alt="" src="https://pixelplanet.fun/tile.png" style="height:64px; width:64px" />`;
|
${t`Thanks`}<br /><br />\n<img alt="" src="https://assets.pixelplanet.fun/tile.png" style="height:64px; width:64px" />`;
|
||||||
this.sendMail(to, subject, html);
|
this.sendMail(to, subject, html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -268,7 +268,6 @@ export async function executeImageAction(
|
||||||
* register responses on socket for Watch Actions
|
* register responses on socket for Watch Actions
|
||||||
*/
|
*/
|
||||||
socketEvents.onReq('watch', (action, ...args) => {
|
socketEvents.onReq('watch', (action, ...args) => {
|
||||||
try {
|
|
||||||
if (action === 'getIIDSummary') {
|
if (action === 'getIIDSummary') {
|
||||||
return getIIDSummary(...args);
|
return getIIDSummary(...args);
|
||||||
} if (action === 'getIIDPixels') {
|
} if (action === 'getIIDPixels') {
|
||||||
|
@ -278,9 +277,6 @@ socketEvents.onReq('watch', (action, ...args) => {
|
||||||
} if (action === 'getPixelsFromArea') {
|
} if (action === 'getPixelsFromArea') {
|
||||||
return getPixelsFromArea(...args);
|
return getPixelsFromArea(...args);
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
// silently fail when file couldn't be parsed
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,133 +1,9 @@
|
||||||
/*
|
|
||||||
* Provide css and js asset files for client
|
|
||||||
*/
|
|
||||||
|
|
||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
|
||||||
import assetWatcher from './fsWatcher';
|
export const assets = JSON.parse(readFileSync(
|
||||||
import { ASSET_DIR } from './config';
|
path.resolve(__dirname, './assets.json'),
|
||||||
|
));
|
||||||
const assetDir = path.join(__dirname, 'public', ASSET_DIR);
|
export const styleassets = JSON.parse(readFileSync(
|
||||||
/*
|
path.resolve(__dirname, './styleassets.json'),
|
||||||
* {
|
));
|
||||||
* js:
|
|
||||||
* client:
|
|
||||||
* en: "/assets/client.defult.134234.js",
|
|
||||||
* de: "/assets/client.de.32834234.js",
|
|
||||||
* [...]
|
|
||||||
* [...]
|
|
||||||
* css:
|
|
||||||
* default: "/assets/default.234234.css",
|
|
||||||
* dark-round: "/assets/dark-round.234233324.css",
|
|
||||||
* [...]
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
let assets;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* check files in asset folder and write insto assets object
|
|
||||||
*/
|
|
||||||
function checkAssets() {
|
|
||||||
const parsedAssets = {
|
|
||||||
js: {},
|
|
||||||
css: {},
|
|
||||||
};
|
|
||||||
const assetFiles = fs.readdirSync(assetDir);
|
|
||||||
const mtimes = {};
|
|
||||||
|
|
||||||
for (const filename of assetFiles) {
|
|
||||||
const parts = filename.split('.');
|
|
||||||
|
|
||||||
// File needs to have a timestamp in its name
|
|
||||||
if (parts.length < 3) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// if multiple candidates exist, take most recent created file
|
|
||||||
const mtime = fs.statSync(path.resolve(assetDir, filename))
|
|
||||||
.mtime.getTime();
|
|
||||||
const ident = parts.filter((a, ind) => ind !== parts.length - 2).join('.');
|
|
||||||
if (mtimes[ident] && mtimes[ident] > mtime) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mtimes[ident] = mtime;
|
|
||||||
|
|
||||||
const ext = parts[parts.length - 1];
|
|
||||||
const relPath = `${ASSET_DIR}/${filename}`;
|
|
||||||
|
|
||||||
switch (ext.toLowerCase()) {
|
|
||||||
case 'js': {
|
|
||||||
// Format: name.[lang].[timestamp].js
|
|
||||||
if (parts.length === 4) {
|
|
||||||
const [name, lang] = parts;
|
|
||||||
let nameObj = parsedAssets.js[name];
|
|
||||||
if (typeof nameObj !== 'object') {
|
|
||||||
nameObj = {};
|
|
||||||
parsedAssets.js[name] = nameObj;
|
|
||||||
}
|
|
||||||
nameObj[lang] = relPath;
|
|
||||||
} else {
|
|
||||||
const [name] = parts;
|
|
||||||
parsedAssets.js[name] = relPath;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'css': {
|
|
||||||
// Format: [dark-]name.[timestamp].js
|
|
||||||
parsedAssets.css[parts[0]] = relPath;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return parsedAssets;
|
|
||||||
}
|
|
||||||
|
|
||||||
assets = checkAssets();
|
|
||||||
// reload on asset change
|
|
||||||
assetWatcher.onChange(() => {
|
|
||||||
assets = checkAssets();
|
|
||||||
});
|
|
||||||
|
|
||||||
export function getLangsOfJsAsset(name) {
|
|
||||||
const nameAssets = assets.js[name];
|
|
||||||
if (!nameAssets) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return Object.keys(nameAssets);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getJsAssets(name, lang) {
|
|
||||||
const jsAssets = [];
|
|
||||||
|
|
||||||
switch (name) {
|
|
||||||
case 'client':
|
|
||||||
jsAssets.push(assets.js.vendor);
|
|
||||||
break;
|
|
||||||
case 'globe':
|
|
||||||
jsAssets.push(assets.js.three);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
const nameAssets = assets.js[name];
|
|
||||||
let mainAsset;
|
|
||||||
if (typeof nameAssets === 'object') {
|
|
||||||
mainAsset = (lang && nameAssets[lang])
|
|
||||||
|| nameAssets.en
|
|
||||||
|| Object.values(nameAssets)[0];
|
|
||||||
} else {
|
|
||||||
mainAsset = nameAssets;
|
|
||||||
}
|
|
||||||
if (mainAsset) {
|
|
||||||
jsAssets.push(mainAsset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsAssets;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCssAssets() {
|
|
||||||
return assets.css;
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,8 +10,6 @@ if (process.env.BROWSER) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ASSET_DIR = '/assets';
|
|
||||||
|
|
||||||
export const PORT = process.env.PORT || 8080;
|
export const PORT = process.env.PORT || 8080;
|
||||||
export const HOST = process.env.HOST || 'localhost';
|
export const HOST = process.env.HOST || 'localhost';
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ export const DEFAULT_CANVASES = {
|
||||||
ranked: true,
|
ranked: true,
|
||||||
req: -1,
|
req: -1,
|
||||||
sd: '2020-01-08',
|
sd: '2020-01-08',
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TILE_LOADING_IMAGE = './loading.png';
|
export const TILE_LOADING_IMAGE = './loading.png';
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Watch for filesystem changes
|
|
||||||
*/
|
|
||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
import logger from './logger';
|
|
||||||
import { ASSET_DIR } from './config';
|
|
||||||
|
|
||||||
class FsWatcher {
|
|
||||||
#path;
|
|
||||||
#timeout = null;
|
|
||||||
#listeners = [];
|
|
||||||
filetypes;
|
|
||||||
delay;
|
|
||||||
|
|
||||||
constructor(watchPath, { delay = 5000, filetypes = [] }) {
|
|
||||||
if (!watchPath) {
|
|
||||||
throw new Error('Must define a path to watch');
|
|
||||||
}
|
|
||||||
this.#path = watchPath;
|
|
||||||
this.delay = delay;
|
|
||||||
this.filetypes = filetypes;
|
|
||||||
this.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize() {
|
|
||||||
const watchPath = this.#path;
|
|
||||||
fs.watch(watchPath, (eventType, filename) => {
|
|
||||||
if (filename && this.filetypes.length) {
|
|
||||||
const ext = filename.split('.').pop();
|
|
||||||
if (!this.filetypes.includes(ext)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.#timeout) {
|
|
||||||
clearTimeout(this.#timeout);
|
|
||||||
}
|
|
||||||
this.#timeout = setTimeout(() => {
|
|
||||||
logger.info('ASSET CHANGE, detected change in asset files');
|
|
||||||
this.#listeners.forEach((cb) => cb(eventType, filename));
|
|
||||||
}, this.delay);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange(cb) {
|
|
||||||
this.#listeners.push(cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const assetWatcher = new FsWatcher(
|
|
||||||
path.join(__dirname, 'public', ASSET_DIR),
|
|
||||||
{ filetypes: ['js', 'css'] },
|
|
||||||
);
|
|
||||||
export default assetWatcher;
|
|
|
@ -7,14 +7,7 @@
|
||||||
import { createLogger, format, transports } from 'winston';
|
import { createLogger, format, transports } from 'winston';
|
||||||
import DailyRotateFile from 'winston-daily-rotate-file';
|
import DailyRotateFile from 'winston-daily-rotate-file';
|
||||||
|
|
||||||
import { SHARD_NAME } from './config';
|
export const PIXELLOGGER_PREFIX = './log/pixels-';
|
||||||
|
|
||||||
export const PIXELLOGGER_PREFIX = (SHARD_NAME)
|
|
||||||
? `./log/pixels-${SHARD_NAME}-` : './log/pixels-';
|
|
||||||
const PROXYLOGGER_PREFIX = (SHARD_NAME)
|
|
||||||
? `./log/proxycheck-${SHARD_NAME}-` : './log/proxycheck-';
|
|
||||||
const MODTOOLLOGGER_PREFIX = (SHARD_NAME)
|
|
||||||
? `./log/modtools-${SHARD_NAME}-` : './log/modtools-';
|
|
||||||
|
|
||||||
const logger = createLogger({
|
const logger = createLogger({
|
||||||
level: 'info',
|
level: 'info',
|
||||||
|
@ -47,7 +40,7 @@ export const proxyLogger = createLogger({
|
||||||
transports: [
|
transports: [
|
||||||
new DailyRotateFile({
|
new DailyRotateFile({
|
||||||
level: 'info',
|
level: 'info',
|
||||||
filename: `${PROXYLOGGER_PREFIX}%DATE%.log`,
|
filename: './log/proxycheck-%DATE%.log',
|
||||||
maxsize: '10m',
|
maxsize: '10m',
|
||||||
maxFiles: '14d',
|
maxFiles: '14d',
|
||||||
utc: true,
|
utc: true,
|
||||||
|
@ -61,7 +54,7 @@ export const modtoolsLogger = createLogger({
|
||||||
transports: [
|
transports: [
|
||||||
new DailyRotateFile({
|
new DailyRotateFile({
|
||||||
level: 'info',
|
level: 'info',
|
||||||
filename: `${MODTOOLLOGGER_PREFIX}%DATE%.log`,
|
filename: './log/moderation/modtools-%DATE%.log',
|
||||||
maxSize: '20m',
|
maxSize: '20m',
|
||||||
maxFiles: '14d',
|
maxFiles: '14d',
|
||||||
utc: true,
|
utc: true,
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
* various api endpoints.
|
* various api endpoints.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
import getLocalizedCanvases from '../canvasesDesc';
|
import { getLocalizedCanvases } from '../canvasesDesc';
|
||||||
import { USE_MAILER } from './config';
|
import { USE_MAILER } from './config';
|
||||||
import chatProvider from './ChatProvider';
|
import chatProvider from './ChatProvider';
|
||||||
|
|
||||||
|
|
||||||
export default async function getMe(user, lang) {
|
export default async function getMe(user, lang = 'default') {
|
||||||
const userdata = await user.getUserData();
|
const userdata = await user.getUserData();
|
||||||
// sanitize data
|
// sanitize data
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -4,91 +4,30 @@
|
||||||
import { TTag } from 'ttag';
|
import { TTag } from 'ttag';
|
||||||
import cookie from 'cookie';
|
import cookie from 'cookie';
|
||||||
|
|
||||||
import assetWatcher from './fsWatcher';
|
import { languageFromLocalisation } from '../utils/location';
|
||||||
import { getLangsOfJsAsset } from './assets';
|
|
||||||
|
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
const localeImports = require.context('../../i18n', false, /^\.[/\\]ssr-.+\.po$/);
|
const localeImports = require.context('../../i18n', false, /^\.[/\\]ssr-.+\.po$/);
|
||||||
|
|
||||||
const ttags = {};
|
const ttags = {
|
||||||
|
default: new TTag(),
|
||||||
|
};
|
||||||
|
|
||||||
export const availableLangs = [];
|
(() => {
|
||||||
|
|
||||||
function loadTtags() {
|
|
||||||
const langs = localeImports.keys();
|
const langs = localeImports.keys();
|
||||||
const jsLangs = getLangsOfJsAsset('client');
|
|
||||||
availableLangs.length = 0;
|
|
||||||
|
|
||||||
if (jsLangs.includes('en')) {
|
|
||||||
if (!ttags.en) {
|
|
||||||
ttags.en = new TTag();
|
|
||||||
}
|
|
||||||
availableLangs.push(['en', 'gb']);
|
|
||||||
} else if (ttags.en) {
|
|
||||||
delete ttags.en;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < langs.length; i += 1) {
|
for (let i = 0; i < langs.length; i += 1) {
|
||||||
const file = langs[i];
|
const file = langs[i];
|
||||||
// ./ssr-de.po
|
|
||||||
let lang = file.replace('./ssr-', '').replace('.po', '').toLowerCase();
|
|
||||||
let flag = lang;
|
|
||||||
/*
|
|
||||||
* in cases where the language code and country code differ,
|
|
||||||
* the country code can be given seperately in the file name
|
|
||||||
* i.e.: ./ssr-en-gb.po
|
|
||||||
*/
|
|
||||||
const seperator = lang.indexOf('-');
|
|
||||||
if (seperator !== -1) {
|
|
||||||
[lang, flag] = lang.split('-');
|
|
||||||
}
|
|
||||||
if (jsLangs.includes(lang)) {
|
|
||||||
if (!ttags[lang]) {
|
|
||||||
const ttag = new TTag();
|
const ttag = new TTag();
|
||||||
|
// ./ssr-de.po
|
||||||
|
const lang = file.replace('./ssr-', '').replace('.po', '');
|
||||||
ttag.addLocale(lang, localeImports(file).default);
|
ttag.addLocale(lang, localeImports(file).default);
|
||||||
ttag.useLocale(lang);
|
ttag.useLocale(lang);
|
||||||
ttags[lang] = ttag;
|
ttags[lang] = ttag;
|
||||||
}
|
}
|
||||||
availableLangs.push([lang, flag]);
|
})();
|
||||||
} else if (ttags[lang]) {
|
|
||||||
delete ttags[lang];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadTtags();
|
|
||||||
// reload on asset change
|
|
||||||
assetWatcher.onChange(() => {
|
|
||||||
loadTtags();
|
|
||||||
});
|
|
||||||
|
|
||||||
export function getTTag(lang) {
|
export function getTTag(lang) {
|
||||||
return ttags[lang] || ttags.en || Object.values(ttags)[0];
|
return ttags[lang] || ttags.default;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* gets preferred language out of localisation string
|
|
||||||
* @param location string (like from accept-language header)
|
|
||||||
* @return language code
|
|
||||||
*/
|
|
||||||
function languageFromLocalisation(localisation) {
|
|
||||||
if (!localisation) {
|
|
||||||
return 'en';
|
|
||||||
}
|
|
||||||
let lang = localisation;
|
|
||||||
let i = lang.indexOf('-');
|
|
||||||
if (i !== -1) {
|
|
||||||
lang = lang.slice(0, i);
|
|
||||||
}
|
|
||||||
i = lang.indexOf(',');
|
|
||||||
if (i !== -1) {
|
|
||||||
lang = lang.slice(0, i);
|
|
||||||
}
|
|
||||||
i = lang.indexOf(';');
|
|
||||||
if (i !== -1) {
|
|
||||||
lang = lang.slice(0, i);
|
|
||||||
}
|
|
||||||
return lang.toLowerCase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -99,16 +38,8 @@ function languageFromLocalisation(localisation) {
|
||||||
export function expressTTag(req, res, next) {
|
export function expressTTag(req, res, next) {
|
||||||
const cookies = cookie.parse(req.headers.cookie || '');
|
const cookies = cookie.parse(req.headers.cookie || '');
|
||||||
const language = cookies.plang || req.headers['accept-language'];
|
const language = cookies.plang || req.headers['accept-language'];
|
||||||
let lang = languageFromLocalisation(language);
|
req.lang = languageFromLocalisation(language);
|
||||||
if (!ttags[lang]) {
|
req.ttag = getTTag(req.lang);
|
||||||
if (ttags.en) {
|
|
||||||
lang = 'en';
|
|
||||||
} else {
|
|
||||||
[lang] = Object.keys(ttags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req.lang = lang;
|
|
||||||
req.ttag = ttags[lang];
|
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
import etag from 'etag';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import ranking from './ranking';
|
import ranking from './ranking';
|
||||||
|
@ -15,6 +16,7 @@ import captcha from './captcha';
|
||||||
import resetPassword from './reset_password';
|
import resetPassword from './reset_password';
|
||||||
import api from './api';
|
import api from './api';
|
||||||
|
|
||||||
|
import { assets } from '../core/assets';
|
||||||
import { expressTTag } from '../core/ttag';
|
import { expressTTag } from '../core/ttag';
|
||||||
import corsMiddleware from '../utils/corsMiddleware';
|
import corsMiddleware from '../utils/corsMiddleware';
|
||||||
import generateGlobePage from '../ssr/Globe';
|
import generateGlobePage from '../ssr/Globe';
|
||||||
|
@ -70,26 +72,34 @@ router.use(expressTTag);
|
||||||
//
|
//
|
||||||
// 3D Globe (react generated)
|
// 3D Globe (react generated)
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
const globeEtag = etag(
|
||||||
|
assets.globe.js.join('_'),
|
||||||
|
{ weak: true },
|
||||||
|
);
|
||||||
router.get('/globe', (req, res) => {
|
router.get('/globe', (req, res) => {
|
||||||
const { html, etag: globeEtag } = generateGlobePage(req);
|
|
||||||
|
|
||||||
res.set({
|
res.set({
|
||||||
'Cache-Control': 'private, no-cache', // seconds
|
'Cache-Control': `private, max-age=${15 * 60}`, // seconds
|
||||||
ETag: globeEtag,
|
ETag: globeEtag,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!html) {
|
if (req.headers['if-none-match'] === globeEtag) {
|
||||||
res.status(304).end();
|
res.status(304).end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.set('Content-Type', 'text/html; charset=utf-8');
|
res.set('Content-Type', 'text/html; charset=utf-8');
|
||||||
res.status(200).send(html);
|
|
||||||
|
res.status(200).send(generateGlobePage(req.lang));
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// PopUps
|
// PopUps
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
const winEtag = etag(
|
||||||
|
assets.popup.js,
|
||||||
|
{ weak: true },
|
||||||
|
);
|
||||||
|
|
||||||
router.use(
|
router.use(
|
||||||
AVAILABLE_POPUPS.map((p) => `/${p.toLowerCase()}`),
|
AVAILABLE_POPUPS.map((p) => `/${p.toLowerCase()}`),
|
||||||
(req, res, next) => {
|
(req, res, next) => {
|
||||||
|
@ -98,43 +108,48 @@ router.use(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { html, etag: winEtag } = generatePopUpPage(req);
|
|
||||||
|
|
||||||
res.set({
|
res.set({
|
||||||
'Cache-Control': 'private, no-cache', // seconds
|
'Cache-Control': `private, max-age=${15 * 60}`, // seconds
|
||||||
ETag: winEtag,
|
ETag: winEtag,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!html) {
|
if (req.headers['if-none-match'] === winEtag) {
|
||||||
res.status(304).end();
|
res.status(304).end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.set('Content-Type', 'text/html; charset=utf-8');
|
res.set('Content-Type', 'text/html; charset=utf-8');
|
||||||
res.status(200).send(html);
|
|
||||||
|
res.status(200).send(generatePopUpPage(req));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Main Page
|
// Main Page (react generated)
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
router.get('/', (req, res) => {
|
const indexEtag = etag(
|
||||||
const { html, csp, etag: mainEtag } = generateMainPage(req);
|
assets.client.js.join('_'),
|
||||||
|
{ weak: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
router.get('/', (req, res) => {
|
||||||
res.set({
|
res.set({
|
||||||
'Cache-Control': 'private, no-cache', // seconds
|
'Cache-Control': `private, max-age=${15 * 60}`, // seconds
|
||||||
'Content-Security-Policy': csp,
|
ETag: indexEtag,
|
||||||
ETag: mainEtag,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!html) {
|
if (req.headers['if-none-match'] === indexEtag) {
|
||||||
res.status(304).end();
|
res.status(304).end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [html, csp] = generateMainPage(req);
|
||||||
|
|
||||||
res.set({
|
res.set({
|
||||||
'Content-Type': 'text/html; charset=utf-8',
|
'Content-Type': 'text/html; charset=utf-8',
|
||||||
|
'Content-Security-Policy': csp,
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(200).send(html);
|
res.status(200).send(html);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable max-len */
|
/* eslint-disable max-len */
|
||||||
import etag from 'etag';
|
|
||||||
|
|
||||||
import { getTTag } from '../core/ttag';
|
import { getTTag } from '../core/ttag';
|
||||||
|
|
||||||
/* this will be set by webpack */
|
/* this will be set by webpack */
|
||||||
import { getJsAssets } from '../core/assets';
|
import { assets } from '../core/assets';
|
||||||
|
|
||||||
import globeCss from '../styles/globe.css';
|
import globeCss from '../styles/globe.css';
|
||||||
|
|
||||||
|
@ -18,14 +17,10 @@ import globeCss from '../styles/globe.css';
|
||||||
* @param lang language code
|
* @param lang language code
|
||||||
* @return html of mainpage
|
* @return html of mainpage
|
||||||
*/
|
*/
|
||||||
function generateGlobePage(req) {
|
function generateGlobePage(lang) {
|
||||||
const { lang } = req;
|
const scripts = (assets[`globe-${lang}`])
|
||||||
const scripts = getJsAssets('globe', lang);
|
? assets[`globe-${lang}`].js
|
||||||
|
: assets.globe.js;
|
||||||
const globeEtag = etag(scripts.join('_'), { weak: true });
|
|
||||||
if (req.headers['if-none-match'] === globeEtag) {
|
|
||||||
return { html: null, etag: globeEtag };
|
|
||||||
}
|
|
||||||
|
|
||||||
const { t } = getTTag(lang);
|
const { t } = getTTag(lang);
|
||||||
|
|
||||||
|
@ -55,7 +50,7 @@ function generateGlobePage(req) {
|
||||||
</html>
|
</html>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return { html, etag: globeEtag };
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default generateGlobePage;
|
export default generateGlobePage;
|
||||||
|
|
|
@ -4,14 +4,32 @@
|
||||||
|
|
||||||
/* eslint-disable max-len */
|
/* eslint-disable max-len */
|
||||||
import { createHash } from 'crypto';
|
import { createHash } from 'crypto';
|
||||||
import etag from 'etag';
|
|
||||||
|
|
||||||
import { getTTag, availableLangs as langs } from '../core/ttag';
|
import { langCodeToCC } from '../utils/location';
|
||||||
import { getJsAssets, getCssAssets } from '../core/assets';
|
import ttags, { getTTag } from '../core/ttag';
|
||||||
|
import { styleassets, assets } from '../core/assets';
|
||||||
import socketEvents from '../socket/socketEvents';
|
import socketEvents from '../socket/socketEvents';
|
||||||
import { BACKUP_URL } from '../core/config';
|
import { BACKUP_URL } from '../core/config';
|
||||||
import { getHostFromRequest } from '../utils/ip';
|
import { getHostFromRequest } from '../utils/ip';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* generate language list
|
||||||
|
*/
|
||||||
|
const langs = Object.keys(ttags)
|
||||||
|
.map((l) => (l === 'default' ? 'en' : l))
|
||||||
|
.map((l) => [l, langCodeToCC(l)]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* values that we pass to client scripts
|
||||||
|
*/
|
||||||
|
const ssv = {
|
||||||
|
availableStyles: styleassets,
|
||||||
|
langs,
|
||||||
|
};
|
||||||
|
if (BACKUP_URL) {
|
||||||
|
ssv.backupurl = BACKUP_URL;
|
||||||
|
}
|
||||||
|
|
||||||
const bodyScript = '(function(){const sr=(e)=>{if(e.shadowRoot)e.remove();else if(e.children){for(let i=0;i<e.children.length;i+=1)sr(e.children[i]);}};const a=new MutationObserver(e=>e.forEach(e=>e.addedNodes.forEach((l)=>{if(l.querySelectorAll)l.querySelectorAll("option").forEach((o)=>{if(o.value==="random")window.location="https://discord.io/pixeltraaa";});sr(l);})));a.observe(document.body,{childList:!0});})()';
|
const bodyScript = '(function(){const sr=(e)=>{if(e.shadowRoot)e.remove();else if(e.children){for(let i=0;i<e.children.length;i+=1)sr(e.children[i]);}};const a=new MutationObserver(e=>e.forEach(e=>e.addedNodes.forEach((l)=>{if(l.querySelectorAll)l.querySelectorAll("option").forEach((o)=>{if(o.value==="random")window.location="https://discord.io/pixeltraaa";});sr(l);})));a.observe(document.body,{childList:!0});})()';
|
||||||
const bodyScriptHash = createHash('sha256').update(bodyScript).digest('base64');
|
const bodyScriptHash = createHash('sha256').update(bodyScript).digest('base64');
|
||||||
|
|
||||||
|
@ -24,27 +42,21 @@ const bodyScriptHash = createHash('sha256').update(bodyScript).digest('base64');
|
||||||
function generateMainPage(req) {
|
function generateMainPage(req) {
|
||||||
const { lang } = req;
|
const { lang } = req;
|
||||||
const host = getHostFromRequest(req, false);
|
const host = getHostFromRequest(req, false);
|
||||||
const shard = (host.startsWith(`${socketEvents.thisShard}.`))
|
const ssvR = {
|
||||||
? null : socketEvents.getLowestActiveShard();
|
...ssv,
|
||||||
const ssvR = JSON.stringify({
|
shard: (host.startsWith(`${socketEvents.thisShard}.`))
|
||||||
availableStyles: getCssAssets(),
|
? null : socketEvents.getLowestActiveShard(),
|
||||||
langs,
|
lang: lang === 'default' ? 'en' : lang,
|
||||||
backupurl: BACKUP_URL,
|
};
|
||||||
shard,
|
const scripts = (assets[`client-${lang}`])
|
||||||
lang,
|
? assets[`client-${lang}`].js
|
||||||
});
|
: assets.client.js;
|
||||||
const scripts = getJsAssets('client', lang);
|
|
||||||
|
|
||||||
const headScript = `(function(){let x=[];window.WebSocket=class extends WebSocket{constructor(...args){super(...args);x=x.filter((w)=>w.readyState<=WebSocket.OPEN);if(x.length)window.location="https://discord.io/pixeltraaa";x.push(this)}};const o=XMLHttpRequest.prototype.open;const f=fetch;const us=URL.prototype.toString;c=(u)=>{try{if(u.constructor===URL)u=us.apply(u);else if(u.constructor===Request)u=u.url;else if(typeof u!=="string")u=null;u=decodeURIComponent(u.toLowerCase());}catch{u=null};if(u&&(u.includes("glitch.me")||u.includes("touchedbydarkness")))window.location="https://discord.io/pixeltraaa";};XMLHttpRequest.prototype.open=function(...args){c(args[1]);return o.apply(this,args)};window.fetch=function(...args){c(args[0]);return f.apply(this,args)};window.ssv=JSON.parse('${ssvR}');})();`;
|
const headScript = `(function(){let x=[];window.WebSocket=class extends WebSocket{constructor(...args){super(...args);x=x.filter((w)=>w.readyState<=WebSocket.OPEN);if(x.length)window.location="https://discord.io/pixeltraaa";x.push(this)}};const o=XMLHttpRequest.prototype.open;const f=fetch;const us=URL.prototype.toString;c=(u)=>{try{if(u.constructor===URL)u=us.apply(u);else if(u.constructor===Request)u=u.url;else if(typeof u!=="string")u=null;u=decodeURIComponent(u.toLowerCase());}catch{u=null};if(u&&(u.includes("glitch.me")||u.includes("touchedbydarkness")))window.location="https://discord.io/pixeltraaa";};XMLHttpRequest.prototype.open=function(...args){c(args[1]);return o.apply(this,args)};window.fetch=function(...args){c(args[0]);return f.apply(this,args)};window.ssv=JSON.parse('${JSON.stringify(ssvR)}');})();`;
|
||||||
const scriptHash = createHash('sha256').update(headScript).digest('base64');
|
const scriptHash = createHash('sha256').update(headScript).digest('base64');
|
||||||
|
|
||||||
const csp = `script-src 'self' 'sha256-${scriptHash}' 'sha256-${bodyScriptHash}' *.tiktok.com *.ttwstatic.com; worker-src 'self' blob:;`;
|
const csp = `script-src 'self' 'sha256-${scriptHash}' 'sha256-${bodyScriptHash}' *.tiktok.com *.ttwstatic.com; worker-src 'self' blob:;`;
|
||||||
|
|
||||||
const mainEtag = etag(scripts.concat(ssvR).join('_'), { weak: true });
|
|
||||||
if (req.headers['if-none-match'] === mainEtag) {
|
|
||||||
return { html: null, csp, etag: mainEtag };
|
|
||||||
}
|
|
||||||
|
|
||||||
const { t } = getTTag(lang);
|
const { t } = getTTag(lang);
|
||||||
|
|
||||||
const html = `
|
const html = `
|
||||||
|
@ -62,7 +74,7 @@ function generateMainPage(req) {
|
||||||
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
|
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
|
||||||
<script>${headScript}</script>
|
<script>${headScript}</script>
|
||||||
<link rel="stylesheet" type="text/css" id="globcss" href="${getCssAssets().default}" />
|
<link rel="stylesheet" type="text/css" id="globcss" href="${styleassets.default}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
@ -71,8 +83,7 @@ function generateMainPage(req) {
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`;
|
`;
|
||||||
|
return [html, csp];
|
||||||
return { html, csp, etag: mainEtag };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default generateMainPage;
|
export default generateMainPage;
|
||||||
|
|
|
@ -4,38 +4,49 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable max-len */
|
/* eslint-disable max-len */
|
||||||
import etag from 'etag';
|
|
||||||
|
|
||||||
import { getTTag, availableLangs as langs } from '../core/ttag';
|
import { langCodeToCC } from '../utils/location';
|
||||||
|
import ttags, { getTTag } from '../core/ttag';
|
||||||
import socketEvents from '../socket/socketEvents';
|
import socketEvents from '../socket/socketEvents';
|
||||||
import { getJsAssets, getCssAssets } from '../core/assets';
|
import { styleassets, assets } from '../core/assets';
|
||||||
import { BACKUP_URL } from '../core/config';
|
import { BACKUP_URL } from '../core/config';
|
||||||
import { getHostFromRequest } from '../utils/ip';
|
import { getHostFromRequest } from '../utils/ip';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* generate language list
|
||||||
|
*/
|
||||||
|
const langs = Object.keys(ttags)
|
||||||
|
.map((l) => (l === 'default' ? 'en' : l))
|
||||||
|
.map((l) => [l, langCodeToCC(l)]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* values that we pass to client scripts
|
||||||
|
*/
|
||||||
|
const ssv = {
|
||||||
|
availableStyles: styleassets,
|
||||||
|
langs,
|
||||||
|
};
|
||||||
|
if (BACKUP_URL) {
|
||||||
|
ssv.backupurl = BACKUP_URL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* generates string with html of win page
|
* generates string with html of win page
|
||||||
* @param lang language code
|
* @param lang language code
|
||||||
* @return html and etag of popup page
|
* @return html of mainpage
|
||||||
*/
|
*/
|
||||||
function generatePopUpPage(req) {
|
function generatePopUpPage(req) {
|
||||||
const { lang } = req;
|
const { lang } = req;
|
||||||
const host = getHostFromRequest(req);
|
const host = getHostFromRequest(req);
|
||||||
const shard = (host.startsWith(`${socketEvents.thisShard}.`))
|
const ssvR = {
|
||||||
? null : socketEvents.getLowestActiveShard();
|
...ssv,
|
||||||
const ssvR = JSON.stringify({
|
shard: (host.startsWith(`${socketEvents.thisShard}.`))
|
||||||
availableStyles: getCssAssets(),
|
? null : socketEvents.getLowestActiveShard(),
|
||||||
langs,
|
lang: lang === 'default' ? 'en' : lang,
|
||||||
backupurl: BACKUP_URL,
|
};
|
||||||
shard,
|
const script = (assets[`popup-${lang}`])
|
||||||
lang,
|
? assets[`popup-${lang}`].js
|
||||||
});
|
: assets.popup.js;
|
||||||
const scripts = getJsAssets('popup', lang);
|
|
||||||
|
|
||||||
const popEtag = etag(scripts.concat(ssvR).join('_'), { weak: true });
|
|
||||||
if (req.headers['if-none-match'] === popEtag) {
|
|
||||||
return { html: null, etag: popEtag };
|
|
||||||
}
|
|
||||||
|
|
||||||
const { t } = getTTag(lang);
|
const { t } = getTTag(lang);
|
||||||
|
|
||||||
|
@ -53,18 +64,18 @@ function generatePopUpPage(req) {
|
||||||
/>
|
/>
|
||||||
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
|
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
|
||||||
<script>window.ssv=JSON.parse('${ssvR}')</script>
|
<script>window.ssv=JSON.parse('${JSON.stringify(ssvR)}')</script>
|
||||||
<link rel="stylesheet" type="text/css" id="globcss" href="${getCssAssets().default}" />
|
<link rel="stylesheet" type="text/css" id="globcss" href="${styleassets.default}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app" class="popup">
|
<div id="app" class="popup">
|
||||||
</div>
|
</div>
|
||||||
${scripts.map((script) => `<script src="${script}"></script>`).join('')}
|
<script src="${script}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return { html, etag: popEtag };
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default generatePopUpPage;
|
export default generatePopUpPage;
|
||||||
|
|
53
src/utils/location.js
Normal file
53
src/utils/location.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* provide location and lang specific features
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gets preferred language out of localisation string
|
||||||
|
* @param location string (like from accept-language header)
|
||||||
|
* @return language code
|
||||||
|
*/
|
||||||
|
export function languageFromLocalisation(localisation) {
|
||||||
|
if (!localisation) {
|
||||||
|
return 'default';
|
||||||
|
}
|
||||||
|
let lang = localisation;
|
||||||
|
let i = lang.indexOf('-');
|
||||||
|
if (i !== -1) {
|
||||||
|
lang = lang.slice(0, i);
|
||||||
|
}
|
||||||
|
i = lang.indexOf(',');
|
||||||
|
if (i !== -1) {
|
||||||
|
lang = lang.slice(0, i);
|
||||||
|
}
|
||||||
|
i = lang.indexOf(';');
|
||||||
|
if (i !== -1) {
|
||||||
|
lang = lang.slice(0, i);
|
||||||
|
}
|
||||||
|
if (lang === 'en') {
|
||||||
|
lang = 'default';
|
||||||
|
}
|
||||||
|
return lang.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get country code to language code for displaying flags
|
||||||
|
* to languages
|
||||||
|
* @param lang 2-char lang code
|
||||||
|
* @return 2-char country code
|
||||||
|
*/
|
||||||
|
const lang2CC = {
|
||||||
|
en: 'gb',
|
||||||
|
dz: 'bt',
|
||||||
|
hy: 'am',
|
||||||
|
uk: 'ua',
|
||||||
|
ca: 'ct',
|
||||||
|
sr: 'rs',
|
||||||
|
be: 'by',
|
||||||
|
kk: 'kz',
|
||||||
|
da: 'dk',
|
||||||
|
fa: 'ir',
|
||||||
|
};
|
||||||
|
export function langCodeToCC(lang) {
|
||||||
|
return lang2CC[lang] || lang;
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const process = require('process');
|
const process = require('process');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
const AssetsPlugin = require('assets-webpack-plugin');
|
||||||
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -13,19 +14,29 @@ const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||||
*/
|
*/
|
||||||
process.chdir(__dirname);
|
process.chdir(__dirname);
|
||||||
|
|
||||||
module.exports = ({
|
/*
|
||||||
|
* Emit a file with assets paths
|
||||||
|
*/
|
||||||
|
const assetPlugin = new AssetsPlugin({
|
||||||
|
path: path.resolve('dist'),
|
||||||
|
filename: 'assets.json',
|
||||||
|
update: true,
|
||||||
|
entrypoints: true,
|
||||||
|
prettyPrint: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function buildWebpackClientConfig(
|
||||||
development,
|
development,
|
||||||
analyze,
|
analyze,
|
||||||
locale = 'en',
|
locale,
|
||||||
extract,
|
extract,
|
||||||
clean = true,
|
) {
|
||||||
readonly,
|
|
||||||
}) => {
|
|
||||||
const ttag = {
|
const ttag = {
|
||||||
resolve: {
|
resolve: {
|
||||||
translations: (locale !== 'en')
|
translations: (locale !== 'default')
|
||||||
? path.resolve('i18n', `${locale}.po`)
|
? path.resolve('i18n', `${locale}.po`)
|
||||||
: 'default',
|
: locale,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,31 +50,37 @@ module.exports = ({
|
||||||
['ttag', ttag],
|
['ttag', ttag],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// cache invalidates if .po file changed
|
||||||
|
const buildDependencies = {
|
||||||
|
config: [__filename],
|
||||||
|
}
|
||||||
|
if (locale !== 'default') {
|
||||||
|
buildDependencies.i18n = [ttag.resolve.translations];
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'client',
|
name: 'client',
|
||||||
target: 'web',
|
target: 'web',
|
||||||
|
|
||||||
mode: (development) ? 'development' : 'production',
|
mode: (development) ? 'development' : 'production',
|
||||||
devtool: (development) ? 'source-map' : false,
|
devtool: (development) ? 'inline-source-map' : false,
|
||||||
|
|
||||||
entry: {
|
entry: {
|
||||||
client:
|
[(locale !== 'default') ? `client-${locale}` : 'client']:
|
||||||
[path.resolve('src', 'client.js')],
|
[path.resolve('src', 'client.js')],
|
||||||
globe:
|
[(locale !== 'default') ? `globe-${locale}` : 'globe']:
|
||||||
[path.resolve('src', 'globe.js')],
|
[path.resolve('src', 'globe.js')],
|
||||||
popup:
|
[(locale !== 'default') ? `popup-${locale}` : 'popup']:
|
||||||
[path.resolve('src', 'popup.js')],
|
[path.resolve('src', 'popup.js')],
|
||||||
},
|
},
|
||||||
|
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve('dist', 'public', 'assets'),
|
path: path.resolve('dist', 'public', 'assets'),
|
||||||
publicPath: '/assets/',
|
publicPath: '/assets/',
|
||||||
// chunkReason is set if it is a split chunk like vendor or three
|
filename: '[name].[chunkhash:8].js',
|
||||||
filename: (pathData) => (pathData.chunk.chunkReason)
|
chunkFilename: (locale !== 'default')
|
||||||
? '[name].[chunkhash:8].js'
|
? `[name]-${locale}.[chunkhash:8].js`
|
||||||
: `[name].${locale}.[chunkhash:8].js`,
|
: '[name].[chunkhash:8].js',
|
||||||
chunkFilename: `[name].${locale}.[chunkhash:8].js`,
|
|
||||||
clean,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
|
@ -86,7 +103,9 @@ module.exports = ({
|
||||||
{
|
{
|
||||||
test: /\.svg$/,
|
test: /\.svg$/,
|
||||||
use: [
|
use: [
|
||||||
'babel-loader',
|
{
|
||||||
|
loader: 'babel-loader',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
loader: 'react-svg-loader',
|
loader: 'react-svg-loader',
|
||||||
options: {
|
options: {
|
||||||
|
@ -107,21 +126,16 @@ module.exports = ({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(js|jsx)$/,
|
test: /\.(js|jsx)$/,
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
options: {
|
|
||||||
plugins: babelPlugins,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
path.resolve('scripts/TtagNonCacheableLoader.js'),
|
|
||||||
],
|
|
||||||
include: [
|
include: [
|
||||||
path.resolve('src'),
|
path.resolve('src'),
|
||||||
...['image-q'].map((moduleName) => (
|
...['image-q'].map((moduleName) => (
|
||||||
path.resolve('node_modules', moduleName)
|
path.resolve('node_modules', moduleName)
|
||||||
)),
|
)),
|
||||||
],
|
],
|
||||||
|
options: {
|
||||||
|
plugins: babelPlugins,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -134,6 +148,8 @@ module.exports = ({
|
||||||
'process.env.BROWSER': true,
|
'process.env.BROWSER': true,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
assetPlugin,
|
||||||
|
|
||||||
// Webpack Bundle Analyzer
|
// Webpack Bundle Analyzer
|
||||||
// https://github.com/th0r/webpack-bundle-analyzer
|
// https://github.com/th0r/webpack-bundle-analyzer
|
||||||
...analyze ? [new BundleAnalyzerPlugin({ analyzerPort: 8889 })] : [],
|
...analyze ? [new BundleAnalyzerPlugin({ analyzerPort: 8889 })] : [],
|
||||||
|
@ -147,11 +163,6 @@ module.exports = ({
|
||||||
default: false,
|
default: false,
|
||||||
defaultVendors: false,
|
defaultVendors: false,
|
||||||
|
|
||||||
/*
|
|
||||||
* this layout of chunks is also assumed in src/core/assets.js
|
|
||||||
* client -> client.js + vendor.js
|
|
||||||
* globe -> globe.js + three.js
|
|
||||||
*/
|
|
||||||
vendor: {
|
vendor: {
|
||||||
name: 'vendor',
|
name: 'vendor',
|
||||||
chunks: (chunk) => chunk.name.startsWith('client'),
|
chunks: (chunk) => chunk.name.startsWith('client'),
|
||||||
|
@ -166,8 +177,6 @@ module.exports = ({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
recordsPath: path.resolve('records.json'),
|
|
||||||
|
|
||||||
stats: {
|
stats: {
|
||||||
colors: true,
|
colors: true,
|
||||||
reasons: false,
|
reasons: false,
|
||||||
|
@ -176,9 +185,11 @@ module.exports = ({
|
||||||
chunkModules: false,
|
chunkModules: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
cache: {
|
cache: (extract) ? false
|
||||||
|
: {
|
||||||
type: 'filesystem',
|
type: 'filesystem',
|
||||||
readonly,
|
name: (development) ? `${locale}-dev` : locale,
|
||||||
|
buildDependencies,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -188,8 +199,46 @@ function getAllAvailableLocals() {
|
||||||
const langs = fs.readdirSync(langDir)
|
const langs = fs.readdirSync(langDir)
|
||||||
.filter((e) => (e.endsWith('.po') && !e.startsWith('ssr')))
|
.filter((e) => (e.endsWith('.po') && !e.startsWith('ssr')))
|
||||||
.map((l) => l.slice(0, -3));
|
.map((l) => l.slice(0, -3));
|
||||||
langs.unshift('en');
|
langs.push('default');
|
||||||
return langs;
|
return langs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return array of webpack configuartions for all languages
|
||||||
|
*/
|
||||||
|
function buildWebpackClientConfigAllLangs() {
|
||||||
|
const langs = getAllAvailableLocals();
|
||||||
|
const webpackConfigClient = [];
|
||||||
|
for (let l = 0; l < langs.length; l += 1) {
|
||||||
|
const lang = langs[l];
|
||||||
|
const cfg = buildWebpackClientConfig(false, false, lang, false);
|
||||||
|
webpackConfigClient.push(cfg);
|
||||||
|
}
|
||||||
|
return webpackConfigClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Per default get configuration of all packages
|
||||||
|
* If any argument is given, it will only get one
|
||||||
|
* ('default' aka english if locale is unset)
|
||||||
|
*
|
||||||
|
* @param development If development mode
|
||||||
|
* @param extract if translatable strings get in i18n templates should
|
||||||
|
* get updated
|
||||||
|
* @param locale language get single configuration of specific locale
|
||||||
|
* @param analyze launch BundleAnalyzerPlugin after build
|
||||||
|
* @return webpack configuration
|
||||||
|
*/
|
||||||
|
module.exports = ({
|
||||||
|
development, analyze, extract, locale,
|
||||||
|
}) => {
|
||||||
|
if (extract || analyze || locale || development) {
|
||||||
|
return buildWebpackClientConfig(
|
||||||
|
development, analyze, locale || 'default', extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return buildWebpackClientConfigAllLangs(development);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.buildWebpackClientConfig = buildWebpackClientConfig;
|
||||||
module.exports.getAllAvailableLocals = getAllAvailableLocals;
|
module.exports.getAllAvailableLocals = getAllAvailableLocals;
|
||||||
|
|
|
@ -75,7 +75,7 @@ module.exports = ({
|
||||||
},
|
},
|
||||||
|
|
||||||
output: {
|
output: {
|
||||||
clean: false,
|
clean: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user