more translations

This commit is contained in:
HF 2021-01-30 13:32:46 +01:00
parent 8475ad0c9f
commit e7eafbf450
28 changed files with 1880 additions and 374 deletions

View File

@ -12,6 +12,102 @@ msgstr ""
"Plural-Forms: nplurals = 2; plural = (n != 1);\n" "Plural-Forms: nplurals = 2; plural = (n != 1);\n"
"X-Generator: Poedit 2.3\n" "X-Generator: Poedit 2.3\n"
#: src/components/CoordinatesBox.jsx:37 src/controls/keypress.js:59
msgid "Copied!"
msgstr "Kopiert!"
#: src/ui/placePixel.js:53
msgid "Error :("
msgstr "Fehler :("
#: src/ui/placePixel.js:54
msgid "Didn't get an answer from pixelplanet. Maybe try to refresh?"
msgstr ""
"Keine Antwort von pixelplanet erhalten. Vielleicht versuche die Seite neu zu "
"laden?"
#: src/ui/placePixel.js:56 src/ui/placePixel.js:265
msgid "OK"
msgstr "OK"
#: src/ui/placePixel.js:206
msgid "Invalid Canvas"
msgstr "Ungültige Leinwand"
#: src/ui/placePixel.js:207
msgid "This canvas doesn't exist"
msgstr "Diese Leinwand existiert nicht"
#: src/ui/placePixel.js:210 src/ui/placePixel.js:214 src/ui/placePixel.js:218
msgid "Invalid Coordinates"
msgstr "Ungültige Koordinaten"
#: src/ui/placePixel.js:211
msgid "x out of bounds"
msgstr "x außerhalb des Spielfelds"
#: src/ui/placePixel.js:215
msgid "y out of bounds"
msgstr "y außerhalb des Spielfelds"
#: src/ui/placePixel.js:219
msgid "z out of bounds"
msgstr "z außerhalb des Spielfelds"
#: src/ui/placePixel.js:222
msgid "Wrong Color"
msgstr "Falsche Farbe"
#: src/ui/placePixel.js:223
msgid "Invalid color selected"
msgstr "Ungültige Farbe ausgewählt"
#: src/ui/placePixel.js:226
msgid "Just for registered Users"
msgstr "Nur ür registrierte Spieler"
#: src/ui/placePixel.js:227
msgid "You have to be logged in to place on this canvas"
msgstr "Melde dich an um auf dieser Leinwand zu spielen"
#: src/ui/placePixel.js:230
msgid "Place more :)"
msgstr "Spiel mehr :)"
#: src/ui/placePixel.js:232
msgid "You can not access this canvas yet. You need to place more pixels"
msgstr "Mehr Pixel sind benötigt um auf dieser Leinwand zu spielen"
#: src/ui/placePixel.js:235
msgid "Pixel protected!"
msgstr "Pixel beschützt!"
#: src/ui/placePixel.js:251
msgid "No Proxies Allowed :("
msgstr "Kein Proxy erlaubt :("
#: src/ui/placePixel.js:252
msgid "You are using a Proxy."
msgstr "Du benutzt ein Proxy."
#: src/ui/placePixel.js:255
msgid "Weird"
msgstr "Komisch"
#: src/ui/placePixel.js:256
msgid "Couldn't set Pixel"
msgstr "Konnte ein Pixel setzen"
#: src/ui/placePixel.js:262
#, javascript-format
msgid "Error ${ retCode }"
msgstr "Fehler ${ retCode }"
#: src/components/Admintools.jsx:219 src/components/ChannelContextMenu.jsx:85
#: src/components/ModalRoot.jsx:60
msgid "Close"
msgstr "Schließen"
#: src/components/ExpandMenuButton.jsx:19 #: src/components/ExpandMenuButton.jsx:19
msgid "Close Menu" msgid "Close Menu"
msgstr "Schließe Menü" msgstr "Schließe Menü"
@ -28,6 +124,11 @@ msgstr "Schließe Chat"
msgid "Open Chat" msgid "Open Chat"
msgstr "Öffne Chat" msgstr "Öffne Chat"
#: src/components/CanvasSelectModal.jsx:67
#: src/components/CanvasSwitchButton.jsx:20
msgid "Canvas Selection"
msgstr "Leinwand auswahl"
#: src/components/OnlineBox.jsx:22 #: src/components/OnlineBox.jsx:22
msgid "User online" msgid "User online"
msgstr "Spieler anwesend" msgstr "Spieler anwesend"
@ -36,11 +137,7 @@ msgstr "Spieler anwesend"
msgid "Pixel gesetzt" msgid "Pixel gesetzt"
msgstr "Pixel plaziert" msgstr "Pixel plaziert"
#: src/components/CanvasSwitchButton.jsx:20 #: src/components/Converter.jsx:609 src/components/CoordinatesBox.jsx:26
msgid "Canvas Selection"
msgstr "Leinwand auswahl"
#: src/components/CoordinatesBox.jsx:26
msgid "Copy to Clipboard" msgid "Copy to Clipboard"
msgstr "Kopiere in die Zwischenablage" msgstr "Kopiere in die Zwischenablage"
@ -70,27 +167,104 @@ msgstr "maximieren"
#: src/components/Chat.jsx:168 #: src/components/Chat.jsx:168
msgid "Start chatting here" msgid "Start chatting here"
msgstr "Beginne hier zu chatten" msgstr "Beginne hier zu unterhalten"
#: src/components/Chat.jsx:200 #: src/components/Chat.jsx:200
msgid "Chat here" msgid "Chat here"
msgstr "Chatte hier" msgstr "Chatte hier"
#: src/components/Chat.jsx:219 #: src/components/Chat.jsx:220
msgid "You must be logged in to chat" msgid "You must be logged in to chat"
msgstr "Melde dich an um zu chatten" msgstr "Melde dich an um dich zu unterhalten"
#: src/components/GlobeButton.jsx:31 #: src/components/GlobeButton.jsx:31
msgid "Globe View" msgid "Globe View"
msgstr "Globus Ansicht" msgstr "Globus Ansicht"
#: src/components/PalselButton.jsx:25 #: src/components/SettingsModal.jsx:123
msgid "Close Palette" msgid "Show Grid"
msgstr "Schließe Palette" msgstr "Zeige Raster"
#: src/components/PalselButton.jsx:25 #: src/components/SettingsModal.jsx:124
msgid "Open Palette" msgid "Turn on grid to highlight pixel borders."
msgstr "Öffne Palette" msgstr "Aktiviere das Raster um Pixelgrenzen zu sehen."
#: src/components/SettingsModal.jsx:130
msgid "Show Pixel Activity"
msgstr "Zeige Pixelaktivität"
#: src/components/SettingsModal.jsx:131
msgid "Show circles where pixels are placed."
msgstr "Zeige Kreise wo Pixel von Spielern gesetzt werden."
#: src/components/SettingsModal.jsx:137
msgid "Disable Game Sounds"
msgstr "Deaktiviere Spiel Ton"
#: src/components/SettingsModal.jsx:139
msgid "All sound effects will be disabled."
msgstr "alle Toneffekte werden ausgeschaltet"
#: src/components/SettingsModal.jsx:145
msgid "Enable chat notifications"
msgstr "Aktiviere Chat Benachrichtigungen"
#: src/components/SettingsModal.jsx:146
msgid "Play a sound when new chat messages arrive"
msgstr "Spiele ein Geräusch wenn eine neue Chat Nachricht eintrifft"
#: src/components/SettingsModal.jsx:151
msgid "Auto Zoom In"
msgstr "Automaticher Zoom"
#: src/components/SettingsModal.jsx:153
msgid ""
"Zoom in instead of placing a pixel when you tap the canvas and your zoom is "
"small."
msgstr ""
"Zoome rein anstatt ein Pixel zu setzen wenn auf kleineren Zoomlevel geklickt "
"wird."
#: src/components/SettingsModal.jsx:158
msgid "Compact Palette"
msgstr "Kompakte Palette"
#: src/components/SettingsModal.jsx:160
msgid "Display Palette in a compact form that takes less screen space."
msgstr ""
"Zeige die Palette in einer kleineren Form an, welche weniger Platz benötigt"
#: src/components/SettingsModal.jsx:165
msgid "Potato Mode"
msgstr "Erdapfel Modus"
#: src/components/SettingsModal.jsx:166
msgid "For when you are playing on a potato."
msgstr "Wenn du auf einer Kartoffel spielst."
#: src/components/Converter.jsx:423 src/components/SettingsModal.jsx:171
msgid "Light Grid"
msgstr "Helles Raster"
#: src/components/SettingsModal.jsx:172
msgid "Show Grid in white instead of black."
msgstr "Zeige das Raster in weiß anstatt schwarz"
#: src/components/SettingsModal.jsx:179
msgid "Historical View"
msgstr "Historische Ansicht"
#: src/components/SettingsModal.jsx:180
msgid "Check out past versions of the canvas."
msgstr "Siehe vergangene Versionen der Leinwand"
#: src/components/SettingsModal.jsx:188
msgid "Themes"
msgstr "Themen"
#: src/components/SettingsModal.jsx:189
msgid "How pixelplanet should look like."
msgstr "Wähle aus wie pixelplanet aussehen soll"
#: src/components/HelpModal.jsx:34 src/components/HelpModal.jsx:35 #: src/components/HelpModal.jsx:34 src/components/HelpModal.jsx:35
msgid "Privacy Policy" msgid "Privacy Policy"
@ -321,9 +495,46 @@ msgstr ""
msgid "Welcome to PixelPlanet.fun" msgid "Welcome to PixelPlanet.fun"
msgstr "Willkommen auf PixelPlanet.fun" msgstr "Willkommen auf PixelPlanet.fun"
#: src/components/ChannelContextMenu.jsx:73
msgid "Mute"
msgstr ""
#: src/components/UserContextMenu.jsx:72
msgid "Ping"
msgstr ""
#: src/components/UserContextMenu.jsx:97
msgid "DM"
msgstr ""
#: src/components/UserContextMenu.jsx:107
msgid "Block"
msgstr ""
#: src/components/PalselButton.jsx:25
msgid "Close Palette"
msgstr "Schließe Palette"
#: src/components/PalselButton.jsx:25
msgid "Open Palette"
msgstr "Öffne Palette"
#: src/components/RegisterModal.jsx:18
msgid "Register new account here"
msgstr "Registriere ein neues Konto hier"
#: src/components/ForgotPasswordModal.jsx:20
#: src/components/RegisterModal.jsx:21 src/components/UserAreaModal.jsx:130
msgid "Consider joining us on Guilded:"
msgstr "Triff uns und andere Spieler auf guilded:"
#: src/components/RegisterModal.jsx:38
msgid "Register New Account"
msgstr "Registriere neues Konto"
#: src/components/UserAreaModal.jsx:33 #: src/components/UserAreaModal.jsx:33
msgid "Login to access more features and stats." msgid "Login to access more features and stats."
msgstr "Melde dich and um mehr Funktionen und Statistikan zu sehen" msgstr "Melde dich and um mehr Funktionen und Statistikan zu sehen."
#: src/components/UserAreaModal.jsx:35 #: src/components/UserAreaModal.jsx:35
msgid "Login with Mail:" msgid "Login with Mail:"
@ -333,6 +544,10 @@ msgstr "Mit Mail anmelden:"
msgid "I forgot my Password." msgid "I forgot my Password."
msgstr "Ich habe mein Passwort vergessen" msgstr "Ich habe mein Passwort vergessen"
#: src/components/UserAreaModal.jsx:43
msgid "or login with:"
msgstr "oder melde dich an mit:"
#: src/components/UserAreaModal.jsx:84 #: src/components/UserAreaModal.jsx:84
msgid "or register here:" msgid "or register here:"
msgstr "oder registriere dich hier:" msgstr "oder registriere dich hier:"
@ -341,107 +556,41 @@ msgstr "oder registriere dich hier:"
msgid "Register" msgid "Register"
msgstr "Registrieren" msgstr "Registrieren"
#: src/components/UserAreaModal.jsx:107
msgid "Profile"
msgstr "Profil"
#: src/components/UserAreaModal.jsx:113
msgid "Ranking"
msgstr "Rangliste"
#: src/components/UserAreaModal.jsx:116
msgid "Converter"
msgstr "Konverter"
#: src/components/UserAreaModal.jsx:122
msgid "Admintools"
msgstr "Admin Werkzeuge"
#: src/components/UserAreaModal.jsx:122
msgid "Modtools"
msgstr "Mod Werkzeuge"
#: src/components/UserAreaModal.jsx:123 #: src/components/UserAreaModal.jsx:123
msgid "Loading..." msgid "Loading..."
msgstr "Lade..." msgstr "Lade..."
#: src/components/ForgotPasswordModal.jsx:20 #: src/components/ForgotPasswordModal.jsx:16
#: src/components/RegisterModal.jsx:21 src/components/UserAreaModal.jsx:130 msgid "Enter your mail adress and we will send you a new password:"
msgid "Consider joining us on Guilded:" msgstr "Gib deine Mail Adresse an und wir senden dir ein neues Passwort."
msgstr "Triff uns und andere Spieler auf guilded:"
#: src/components/RegisterModal.jsx:18 #: src/components/ForgotPasswordModal.jsx:37
msgid "Register new account here" msgid "Restore my Password"
msgstr "Registriere ein neues Konto hier" msgstr "Passwort wiederherstellen"
#: src/components/RegisterModal.jsx:38 #: src/components/ChatModal.jsx:35
msgid "Register New Account" msgid "Chat"
msgstr "Registriere neues Konto" msgstr "Unterhaltung"
#: src/components/SettingsModal.jsx:123
msgid "Show Grid"
msgstr "Zeige Raster"
#: src/components/SettingsModal.jsx:124
msgid "Turn on grid to highlight pixel borders."
msgstr "Aktiviere das Raster um Pixelgrenzen zu sehen."
#: src/components/SettingsModal.jsx:130
msgid "Show Pixel Activity"
msgstr "Zeige Pixelaktivität"
#: src/components/SettingsModal.jsx:131
msgid "Show circles where pixels are placed."
msgstr "Zeige Kreise wo Pixel von Spielern gesetzt werden"
#: src/components/SettingsModal.jsx:137
msgid "Disable Game Sounds"
msgstr "Deaktiviere Spiel Ton"
#: src/components/SettingsModal.jsx:139
msgid "All sound effects will be disabled."
msgstr "alle Toneffekte werden ausgeschaltet"
#: src/components/SettingsModal.jsx:145
msgid "Enable chat notifications"
msgstr "Aktiviere Chat Benachrichtigungen"
#: src/components/SettingsModal.jsx:146
msgid "Play a sound when new chat messages arrive"
msgstr "Spiele ein Geräusch wenn eine neue Chat Nachricht eintrifft"
#: src/components/SettingsModal.jsx:151
msgid "Auto Zoom In"
msgstr "Automaticher Zoom"
#: src/components/SettingsModal.jsx:153
msgid ""
"Zoom in instead of placing a pixel when you tap the canvas and your zoom is "
"small."
msgstr ""
"Zoome rein anstatt ein Pixel zu setzen wenn auf kleineren Zoomlevel geklickt "
"wird."
#: src/components/SettingsModal.jsx:158
msgid "Compact Palette"
msgstr "Kompakte Palette"
#: src/components/SettingsModal.jsx:160
msgid "Display Palette in a compact form that takes less screen space."
msgstr ""
"Zeige die Palette in einer kleineren Form an, welche weniger Platz benötigt"
#: src/components/SettingsModal.jsx:165
msgid "Potato Mode"
msgstr "Erdapfel Modus"
#: src/components/SettingsModal.jsx:166
msgid "For when you are playing on a potato."
msgstr "Wenn du auf einer Kartoffel spielst."
#: src/components/SettingsModal.jsx:171
msgid "Light Grid"
msgstr "Helles Raster"
#: src/components/SettingsModal.jsx:172
msgid "Show Grid in white instead of black."
msgstr "Zeige das Raster in weiß anstatt schwarz"
#: src/components/SettingsModal.jsx:179
msgid "Historical View"
msgstr "Historische Ansicht"
#: src/components/SettingsModal.jsx:180
msgid "Check out past versions of the canvas."
msgstr "Siehe vergangene Versionen der Leinwand"
#: src/components/SettingsModal.jsx:188
msgid "Themes"
msgstr "Themen"
#: src/components/SettingsModal.jsx:189
msgid "How pixelplanet should look like."
msgstr "Wähle aus wie pixelplanet aussehen soll"
#: src/components/ArchiveModal.jsx:20 #: src/components/ArchiveModal.jsx:20
msgid "" msgid ""
@ -485,23 +634,23 @@ msgstr ""
msgid "Canvas Archive" msgid "Canvas Archive"
msgstr "Leinwand Archiv" msgstr "Leinwand Archiv"
#: src/components/ForgotPasswordModal.jsx:16 #: src/components/CanvasSelectModal.jsx:29
msgid "Enter your mail adress and we will send you a new password:" msgid ""
msgstr "Gib deine Mail Adresse an und wir senden dir ein neues Passwort." "Select the canvas you want to use. Every canvas is unique and has different "
"palettes, cooldown and requirements. Archive of closed canvases can be "
"accessed here:"
msgstr ""
#: src/components/ForgotPasswordModal.jsx:37 #: src/components/CanvasSelectModal.jsx:37
msgid "Restore my Password" msgid "Archive"
msgstr "Passwort wiederherstellen" msgstr "Archiv"
#: src/components/ChatModal.jsx:35
msgid "Chat"
msgstr "Unterhaltung"
#: src/components/LogInForm.jsx:104 #: src/components/LogInForm.jsx:104
msgid "Name or Email" msgid "Name or Email"
msgstr "Name oder Email" msgstr "Name oder Email"
#: src/components/LogInForm.jsx:111 #: src/components/ChangeMail.jsx:109 src/components/DeleteAccount.jsx:88
#: src/components/LogInForm.jsx:111 src/components/SignUpForm.jsx:139
msgid "Password" msgid "Password"
msgstr "Passwort" msgstr "Passwort"
@ -509,12 +658,363 @@ msgstr "Passwort"
msgid "LogIn" msgid "LogIn"
msgstr "Einloggen" msgstr "Einloggen"
#: src/components/UserArea.jsx:57
msgid "Todays Placed Pixels"
msgstr "Heutige Pixel"
#: src/components/UserArea.jsx:61
msgid "Daily Rank"
msgstr "Tägliche Rangliste"
#: src/components/UserArea.jsx:66
msgid "Placed Pixels"
msgstr "Plazierte Pixel"
#: src/components/UserArea.jsx:70
msgid "Total Rank"
msgstr "Gesamt Rang"
#: src/components/UserArea.jsx:75
#, javascript-format
msgid "Your name is: ${ name }"
msgstr "Dein Name ist: ${ name }"
#: src/components/UserArea.jsx:81
msgid "Log out"
msgstr "Abmelden"
#: src/components/UserArea.jsx:93
msgid "Change Username"
msgstr "Ändere Namen"
#: src/components/UserArea.jsx:108
msgid "Change Mail"
msgstr "Ändere Mail"
#: src/components/UserArea.jsx:122
msgid "Change Password"
msgstr "Passwort ändern"
#: src/components/UserArea.jsx:134
msgid "Delete Account"
msgstr "Lösche Konto"
#: src/components/UserArea.jsx:147
msgid "Social Settings"
msgstr "Soziale Einstellungen"
#: src/components/Rankings.jsx:37
msgid "Total"
msgstr "Gesamt"
#: src/components/Rankings.jsx:45
msgid "Daily"
msgstr "Täglich"
#: src/components/Rankings.jsx:49 #: src/components/Rankings.jsx:49
msgid "Ranking updates every 5 min. Daily rankings get reset at midnight UTC." msgid "Ranking updates every 5 min. Daily rankings get reset at midnight UTC."
msgstr "" msgstr ""
"Die Rangliste wird alle 5min aktualisiert. Die tägliche Liste wird um " "Die Rangliste wird alle 5min aktualisiert. Die tägliche Liste wird um "
"Mitternacht UTC zurückgestellt." "Mitternacht UTC zurückgestellt."
#: src/components/CanvasItem.jsx:46
msgid "Cooldown"
msgstr "Wartezeit"
#: src/components/CanvasItem.jsx:52
msgid "Stacking till"
msgstr "Gesamtzeit"
#: src/components/CanvasItem.jsx:54
msgid "Ranked"
msgstr ""
#: src/components/CanvasItem.jsx:56
msgid "Requirements"
msgstr "Vorraussetzungen"
#: src/components/CanvasItem.jsx:58
msgid "User Account"
msgstr "Konto"
#: src/components/CanvasItem.jsx:60
#, javascript-format
msgid "and ${ canvas.req } Pixels set"
msgstr "und ${ canvas.req } gesetzte Pixel"
#: src/components/CanvasItem.jsx:64
msgid "Dimensions"
msgstr "Dimensionen"
#: src/components/Admintools.jsx:179
msgid "Build image on canvas."
msgstr ""
#: src/components/Admintools.jsx:182
msgid "Build image and set it to protected."
msgstr ""
#: src/components/Admintools.jsx:185
msgid "Build image, but reset cooldown to unset-pixel cd."
msgstr ""
#: src/components/Admintools.jsx:248
msgid "Image Upload"
msgstr ""
#: src/components/Admintools.jsx:249
msgid "Upload images to canvas"
msgstr "Lade ein Bild zur Leinwand hoch"
#: src/components/Admintools.jsx:251
msgid "File"
msgstr ""
#: src/components/Admintools.jsx:271
msgid "Coordinates in X_Y format:"
msgstr ""
#: src/components/Admintools.jsx:306 src/components/Admintools.jsx:387
#: src/components/Admintools.jsx:461 src/components/Admintools.jsx:505
#: src/components/Admintools.jsx:589 src/components/SignUpForm.jsx:151
msgid "Submit"
msgstr ""
#: src/components/Admintools.jsx:311
msgid "Pixel Protection"
msgstr "Pixel beschützen"
#: src/components/Admintools.jsx:313
msgid ""
"Set protection of areas (if you need finer grained control, "
"use protect with image upload and alpha layers)"
msgstr ""
#: src/components/Admintools.jsx:392
msgid "Rollback to Date"
msgstr ""
#: src/components/Admintools.jsx:394
msgid "Rollback an area of the canvas to a set date (00:00 UTC)"
msgstr ""
#: src/components/Admintools.jsx:468
msgid "IP Actions"
msgstr ""
#: src/components/Admintools.jsx:470
msgid "Do stuff with IPs (one IP per line)"
msgstr ""
#: src/components/Admintools.jsx:510
msgid "Manage Moderators"
msgstr ""
#: src/components/Admintools.jsx:512
msgid "Remove Moderator"
msgstr ""
#: src/components/Admintools.jsx:544
msgid "There are no mods"
msgstr ""
#: src/components/Admintools.jsx:549
msgid "Assign new Mod"
msgstr ""
#: src/components/Admintools.jsx:552
msgid "Enter UserName of new Mod"
msgstr ""
#: src/components/SignUpForm.jsx:125
msgid "Name"
msgstr ""
#: src/components/SignUpForm.jsx:132
msgid "Email"
msgstr ""
#: src/components/SignUpForm.jsx:148
msgid "Confirm Password"
msgstr "Passwort bestätigen"
#: src/components/ChangeMail.jsx:122 src/components/ChangePassword.jsx:151
#: src/components/DeleteAccount.jsx:94 src/components/SignUpForm.jsx:157
msgid "Cancel"
msgstr "Abbrechen"
#: src/components/Converter.jsx:274
msgid "Choose Canvas"
msgstr "Wähle Leinwand"
#: src/components/Converter.jsx:300
msgid "Palette Download"
msgstr "Palette herunterladen"
#: src/components/Converter.jsx:302
#, javascript-format
msgid "Palette for ${ gimpLink }"
msgstr "Palette für ${ gimpLink }"
#: src/components/Converter.jsx:320
#, javascript-format
msgid "Credit for the Palette of the Moon goes to ${ starhouseLink }."
msgstr "Vielen Dank an ${ starhouseLink } für die Palette der Mond Leinwand."
#: src/components/Converter.jsx:323
msgid "Image Converter"
msgstr "Bild Konverter"
#: src/components/Converter.jsx:324
msgid "Convert an image to canvas colors"
msgstr "Konvertiere ein Bild zu Leinwand Farben"
#: src/components/Converter.jsx:335
msgid "Choose Strategy"
msgstr "Wähle Strategie"
#: src/components/Converter.jsx:362
msgid "Choose Color Mode"
msgstr "Wähle Farb Modus"
#: src/components/Converter.jsx:400
msgid "Add Grid (uncheck if you need a 1:1 template)"
msgstr "Zeichne Raster (deaktiviere falls du eine 1:1 Vorlage benötigst)"
#: src/components/Converter.jsx:425 src/components/Converter.jsx:441
msgid "Offset"
msgstr "Abweichung"
#: src/components/Converter.jsx:471
msgid "Scale Image"
msgstr "Skaliere Bild"
#: src/components/Converter.jsx:483
msgid "Width"
msgstr "Breite"
#: src/components/Converter.jsx:513
msgid "Height"
msgstr "Höhe"
#: src/components/Converter.jsx:551
msgid "Keep Ratio"
msgstr "Seitenverhältniss beibehalten"
#: src/components/Converter.jsx:564
msgid "Anti Aliasing"
msgstr "Kantenglättung"
#: src/components/Converter.jsx:578
msgid "Reset"
msgstr "Zurücksetzen"
#: src/components/Converter.jsx:597
msgid "Download Template"
msgstr "Bild herunterladen"
#: src/utils/validation.js:15
msgid "Email can't be empty."
msgstr ""
#: src/utils/validation.js:16
msgid "Email should be at least 5 characters long."
msgstr ""
#: src/utils/validation.js:17
msgid "Email can't be longer than 40 characters."
msgstr ""
#: src/utils/validation.js:18
msgid "Email should at least contain a dot"
msgstr ""
#: src/utils/validation.js:20
msgid "Email should contain a @"
msgstr ""
#: src/utils/validation.js:27
msgid "Name can't be empty."
msgstr ""
#: src/utils/validation.js:28
msgid "Name must be at least 4 characters long"
msgstr ""
#: src/utils/validation.js:29
msgid "Name must be shorter than 26 characters"
msgstr ""
#: src/utils/validation.js:36
msgid "Name contains invalid character like @, /, \\ or #"
msgstr ""
#: src/utils/validation.js:51
msgid "Password must be at least 6 characters long."
msgstr "Passwort muss mindestens 6 Zeichen lang sein"
#: src/utils/validation.js:54
msgid "Password must be shorter than 60 characters."
msgstr ""
#: src/utils/validation.js:68
msgid "Could not connect to server, please try again later :("
msgstr ""
#: src/utils/validation.js:74
msgid "I think we experienced some error :("
msgstr ""
#: src/components/DeleteAccount.jsx:92
msgid "Yes, Delete My Account!"
msgstr "Ja, löche mein Konto!"
#: src/components/ChangeMail.jsx:89
msgid ""
"Changed Mail successfully. We sent you a verification mail, "
"please verify your new mail adress."
msgstr ""
#: src/components/ChangeMail.jsx:116
msgid "New Mail"
msgstr "Neue Mail"
#: src/components/ChangeMail.jsx:120 src/components/ChangePassword.jsx:149
msgid "Save"
msgstr ""
#: src/components/ChangePassword.jsx:18
msgid "Passwords do not match."
msgstr ""
#: src/components/ChangePassword.jsx:103
msgid "Changed Password successfully."
msgstr "Passwort erfolgreich geändert"
#: src/components/ChangePassword.jsx:128
msgid "Old Password"
msgstr "Altes Passwort"
#: src/components/ChangePassword.jsx:136
msgid "New Password"
msgstr "Neues Passwort"
#: src/components/ChangePassword.jsx:145
msgid "Confirm New Password"
msgstr "Neues Passwort bestätigen"
#: src/components/SocialSettings.jsx:39
msgid "Block all Private Messages"
msgstr ""
#: src/components/SocialSettings.jsx:57
msgid "Unblock Users"
msgstr ""
#: src/components/SocialSettings.jsx:81
msgid "You have no users blocked"
msgstr ""
#: src/components/HelpModal.jsx:15 src/components/SettingsModal.jsx:125 #: src/components/HelpModal.jsx:15 src/components/SettingsModal.jsx:125
msgctxt "keybinds" msgctxt "keybinds"
msgid "G" msgid "G"
@ -525,6 +1025,11 @@ msgctxt "keybinds"
msgid "X" msgid "X"
msgstr "" msgstr ""
#: src/components/SettingsModal.jsx:140
msgctxt "keybinds"
msgid "M"
msgstr ""
#: src/components/HelpModal.jsx:17 src/components/SettingsModal.jsx:182 #: src/components/HelpModal.jsx:17 src/components/SettingsModal.jsx:182
msgctxt "keybinds" msgctxt "keybinds"
msgid "H" msgid "H"
@ -574,8 +1079,3 @@ msgstr ""
msgctxt "keybinds" msgctxt "keybinds"
msgid "C" msgid "C"
msgstr "" msgstr ""
#: src/components/SettingsModal.jsx:140
msgctxt "keybinds"
msgid "M"
msgstr ""

View File

@ -1,15 +1,237 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Project-Id-Version: \n"
"Plural-Forms: nplurals = 2; plural = (n != 1);\n" "POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de\n" "Language: de\n"
"mime-version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals = 2; plural = (n != 1);\n"
"X-Generator: Poedit 2.3\n"
#: src/ssr-components/Globe.jsx:23 #: src/ssr-components/Globe.jsx:44
msgid "Double click on globe to go back." msgid "Double click on globe to go back."
msgstr "Doppelklick um zurück zu gehen" msgstr "Doppelklick um zurück zu gehen"
#: src/ssr-components/Globe.jsx:24 #: src/ssr-components/Globe.jsx:45
msgid "Loading..." msgid "Loading..."
msgstr "Lade..." msgstr "Lade..."
#: src/ssr-components/Globe.jsx:51
msgid "PixelPlanet.Fun 3DGlobe"
msgstr "PixelPlanet.Fun 3D Globus"
#: src/ssr-components/Globe.jsx:52
msgid "A 3D globe of our whole map"
msgstr "Ein interaktvier 3D Globus unserer gesamten Karte"
#: src/routes/reset_password.js:63
msgid "You sent an empty password or invalid data :("
msgstr ""
#: src/routes/reset_password.js:74
msgid "This password-reset link isn't valid anymore :("
msgstr ""
#: src/routes/reset_password.js:84
msgid "Your passwords do not match :("
msgstr ""
#: src/routes/reset_password.js:98
msgid "User doesn't exist in our database :("
msgstr ""
#: src/routes/reset_password.js:109
msgid "Passowrd successfully changed."
msgstr ""
#: src/routes/reset_password.js:126
msgid "Invalid url :( Please check your mail again."
msgstr ""
#: src/routes/reset_password.js:138
msgid ""
"This passwort reset link is wrong or already expired, please request a new "
"one (Note: you can use those links just once)"
msgstr ""
#: src/core/mail.js:65
#, javascript-format
msgid ""
"We already sent you a verification mail, you can request another one in "
"${ minLeft } minutes."
msgstr ""
#: src/core/mail.js:75
msgid "Welcome ${ name } to PixelPlanet, plese verify your mail"
msgstr ""
#: src/core/mail.js:77
#, javascript-format
msgid "Hello ${ name }"
msgstr ""
#: src/core/mail.js:78
msgid ""
"welcome to our little community of pixelplacers, to use your account, you "
"have to verify your mail. You can do that here: "
msgstr ""
#: src/core/mail.js:78
msgid "Click to Verify"
msgstr ""
#: src/core/mail.js:78 src/core/mail.js:128
msgid "Or by copying following url:"
msgstr ""
#: src/core/mail.js:79
msgid ""
"Have fun and don't hesitate to contact us if you encouter any problems :)"
msgstr ""
#: src/core/mail.js:80 src/core/mail.js:130
msgid "Thanks"
msgstr ""
#: src/core/mail.js:98
msgid ""
"We already sent you a mail with instructions. Please wait before requesting "
"another mail."
msgstr ""
#: src/core/mail.js:106
msgid "Couldn't find this mail in our database"
msgstr ""
#: src/core/mail.js:125
msgid "You forgot your password for PixelPlanet? Get a new one here"
msgstr ""
#: src/core/mail.js:127
msgid "Hello"
msgstr ""
#: src/core/mail.js:128
msgid ""
"You requested to get a new password. You can change your password within the "
"next 30min here: "
msgstr ""
#: src/core/mail.js:128
msgid "Reset Password"
msgstr ""
#: src/core/mail.js:129
#, javascript-format
msgid ""
"If you did not request this mail, please just ignore it (the ip that "
"requested this mail was ${ ip })."
msgstr ""
#: src/utils/validation.js:15
msgid "Email can't be empty."
msgstr ""
#: src/utils/validation.js:16
msgid "Email should be at least 5 characters long."
msgstr ""
#: src/utils/validation.js:17
msgid "Email can't be longer than 40 characters."
msgstr ""
#: src/utils/validation.js:18
msgid "Email should at least contain a dot"
msgstr ""
#: src/utils/validation.js:20
msgid "Email should contain a @"
msgstr ""
#: src/utils/validation.js:27
msgid "Name can't be empty."
msgstr ""
#: src/utils/validation.js:28
msgid "Name must be at least 4 characters long"
msgstr ""
#: src/utils/validation.js:29
msgid "Name must be shorter than 26 characters"
msgstr ""
#: src/utils/validation.js:36
msgid "Name contains invalid character like @, /, \\ or #"
msgstr ""
#: src/utils/validation.js:51
msgid "Password must be at least 6 characters long."
msgstr "Passwort muss mindestens 6 Zeichen lang sein."
#: src/utils/validation.js:54
msgid "Password must be shorter than 60 characters."
msgstr ""
#: src/utils/validation.js:68
msgid "Could not connect to server, please try again later :("
msgstr ""
#: src/utils/validation.js:74
msgid "I think we experienced some error :("
msgstr ""
#: src/routes/api/auth/change_mail.js:41
#: src/routes/api/auth/change_passwd.js:37
#: src/routes/api/auth/delete_account.js:38
msgid "You are not authenticated."
msgstr ""
#: src/routes/api/auth/change_mail.js:50
#: src/routes/api/auth/change_passwd.js:46
#: src/routes/api/auth/delete_account.js:48
msgid "Incorrect password!"
msgstr ""
#: src/routes/api/auth/register.js:61
msgid "Failed to create new user :("
msgstr ""
#: src/routes/api/auth/register.js:77
msgid "Failed to establish session after register :("
msgstr ""
#: src/canvasesDesc.js:19
msgid "Our main canvas, a huge map of the world. Place everywhere you like"
msgstr ""
"Unsere Hauptleinwand, eine große Weltkarte. Zeichnen ist überall möglich."
#: src/canvasesDesc.js:20
msgid ""
"Moon canvas. Safe space for art. No flags or large text (unless part of art)"
msgstr ""
"Mond Leinwand. Kunst erwünscht. Keine Flaggen oder großer Text außer als "
"Teil von Kunst."
#: src/canvasesDesc.js:21
msgid "Place Voxels on a 3D canvas with others"
msgstr "Zeichne mit Voxeln in einer 3D Umgebung."
#: src/canvasesDesc.js:22
msgid "Special canvas to spread awareness of SARS-CoV2"
msgstr "Kleine Leinwand im SARS-CoV2 Thema"
#: src/canvasesDesc.js:23
msgid "Mirror of PixelZone"
msgstr "Kopie von PixelZone"
#: src/canvasesDesc.js:24
msgid "Mirror of PixelCanvas"
msgstr "Kopie von PixelCanvas"
#: src/canvasesDesc.js:25
msgid "Black and White canvas"
msgstr "Schwarz/Weiß Leinwand"

View File

@ -3,10 +3,223 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n"
#: src/ssr-components/Globe.jsx:46 #: src/ssr-components/Globe.jsx:44
msgid "Double click on globe to go back." msgid "Double click on globe to go back."
msgstr "" msgstr ""
#: src/ssr-components/Globe.jsx:47 #: src/ssr-components/Globe.jsx:45
msgid "Loading..." msgid "Loading..."
msgstr ""
#: src/ssr-components/Globe.jsx:51
msgid "PixelPlanet.Fun 3DGlobe"
msgstr ""
#: src/ssr-components/Globe.jsx:52
msgid "A 3D globe of our whole map"
msgstr ""
#: src/routes/reset_password.js:63
msgid "You sent an empty password or invalid data :("
msgstr ""
#: src/routes/reset_password.js:74
msgid "This password-reset link isn't valid anymore :("
msgstr ""
#: src/routes/reset_password.js:84
msgid "Your passwords do not match :("
msgstr ""
#: src/routes/reset_password.js:98
msgid "User doesn't exist in our database :("
msgstr ""
#: src/routes/reset_password.js:109
msgid "Passowrd successfully changed."
msgstr ""
#: src/routes/reset_password.js:126
msgid "Invalid url :( Please check your mail again."
msgstr ""
#: src/routes/reset_password.js:138
msgid ""
"This passwort reset link is wrong or already expired, please request a new "
"one (Note: you can use those links just once)"
msgstr ""
#: src/core/mail.js:65
#, javascript-format
msgid ""
"We already sent you a verification mail, you can request another one in ${ "
"minLeft } minutes."
msgstr ""
#: src/core/mail.js:75
msgid "Welcome ${ name } to PixelPlanet, plese verify your mail"
msgstr ""
#: src/core/mail.js:77
#, javascript-format
msgid "Hello ${ name }"
msgstr ""
#: src/core/mail.js:78
msgid ""
"welcome to our little community of pixelplacers, to use your account, you "
"have to verify your mail. You can do that here: "
msgstr ""
#: src/core/mail.js:78
msgid "Click to Verify"
msgstr ""
#: src/core/mail.js:78
#: src/core/mail.js:128
msgid "Or by copying following url:"
msgstr ""
#: src/core/mail.js:79
msgid "Have fun and don't hesitate to contact us if you encouter any problems :)"
msgstr ""
#: src/core/mail.js:80
#: src/core/mail.js:130
msgid "Thanks"
msgstr ""
#: src/core/mail.js:98
msgid ""
"We already sent you a mail with instructions. Please wait before requesting "
"another mail."
msgstr ""
#: src/core/mail.js:106
msgid "Couldn't find this mail in our database"
msgstr ""
#: src/core/mail.js:125
msgid "You forgot your password for PixelPlanet? Get a new one here"
msgstr ""
#: src/core/mail.js:127
msgid "Hello"
msgstr ""
#: src/core/mail.js:128
msgid ""
"You requested to get a new password. You can change your password within "
"the next 30min here: "
msgstr ""
#: src/core/mail.js:128
msgid "Reset Password"
msgstr ""
#: src/core/mail.js:129
#, javascript-format
msgid ""
"If you did not request this mail, please just ignore it (the ip that "
"requested this mail was ${ ip })."
msgstr ""
#: src/utils/validation.js:15
msgid "Email can't be empty."
msgstr ""
#: src/utils/validation.js:16
msgid "Email should be at least 5 characters long."
msgstr ""
#: src/utils/validation.js:17
msgid "Email can't be longer than 40 characters."
msgstr ""
#: src/utils/validation.js:18
msgid "Email should at least contain a dot"
msgstr ""
#: src/utils/validation.js:20
msgid "Email should contain a @"
msgstr ""
#: src/utils/validation.js:27
msgid "Name can't be empty."
msgstr ""
#: src/utils/validation.js:28
msgid "Name must be at least 4 characters long"
msgstr ""
#: src/utils/validation.js:29
msgid "Name must be shorter than 26 characters"
msgstr ""
#: src/utils/validation.js:36
msgid "Name contains invalid character like @, /, \\ or #"
msgstr ""
#: src/utils/validation.js:51
msgid "Password must be at least 6 characters long."
msgstr ""
#: src/utils/validation.js:54
msgid "Password must be shorter than 60 characters."
msgstr ""
#: src/utils/validation.js:68
msgid "Could not connect to server, please try again later :("
msgstr ""
#: src/utils/validation.js:74
msgid "I think we experienced some error :("
msgstr ""
#: src/routes/api/auth/change_mail.js:41
#: src/routes/api/auth/change_passwd.js:37
#: src/routes/api/auth/delete_account.js:38
msgid "You are not authenticated."
msgstr ""
#: src/routes/api/auth/change_mail.js:50
#: src/routes/api/auth/change_passwd.js:46
#: src/routes/api/auth/delete_account.js:48
msgid "Incorrect password!"
msgstr ""
#: src/routes/api/auth/register.js:61
msgid "Failed to create new user :("
msgstr ""
#: src/routes/api/auth/register.js:77
msgid "Failed to establish session after register :("
msgstr ""
#: src/canvasesDesc.js:19
msgid "Our main canvas, a huge map of the world. Place everywhere you like"
msgstr ""
#: src/canvasesDesc.js:20
msgid "Moon canvas. Safe space for art. No flags or large text (unless part of art)"
msgstr ""
#: src/canvasesDesc.js:21
msgid "Place Voxels on a 3D canvas with others"
msgstr ""
#: src/canvasesDesc.js:22
msgid "Special canvas to spread awareness of SARS-CoV2"
msgstr ""
#: src/canvasesDesc.js:23
msgid "Mirror of PixelZone"
msgstr ""
#: src/canvasesDesc.js:24
msgid "Mirror of PixelCanvas"
msgstr ""
#: src/canvasesDesc.js:25
msgid "Black and White canvas"
msgstr "" msgstr ""

View File

@ -3,6 +3,105 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n"
#: src/components/CoordinatesBox.jsx:37
#: src/controls/keypress.js:59
msgid "Copied!"
msgstr ""
#: src/ui/placePixel.js:53
msgid "Error :("
msgstr ""
#: src/ui/placePixel.js:54
msgid "Didn't get an answer from pixelplanet. Maybe try to refresh?"
msgstr ""
#: src/ui/placePixel.js:56
#: src/ui/placePixel.js:265
msgid "OK"
msgstr ""
#: src/ui/placePixel.js:206
msgid "Invalid Canvas"
msgstr ""
#: src/ui/placePixel.js:207
msgid "This canvas doesn't exist"
msgstr ""
#: src/ui/placePixel.js:210
#: src/ui/placePixel.js:214
#: src/ui/placePixel.js:218
msgid "Invalid Coordinates"
msgstr ""
#: src/ui/placePixel.js:211
msgid "x out of bounds"
msgstr ""
#: src/ui/placePixel.js:215
msgid "y out of bounds"
msgstr ""
#: src/ui/placePixel.js:219
msgid "z out of bounds"
msgstr ""
#: src/ui/placePixel.js:222
msgid "Wrong Color"
msgstr ""
#: src/ui/placePixel.js:223
msgid "Invalid color selected"
msgstr ""
#: src/ui/placePixel.js:226
msgid "Just for registered Users"
msgstr ""
#: src/ui/placePixel.js:227
msgid "You have to be logged in to place on this canvas"
msgstr ""
#: src/ui/placePixel.js:230
msgid "Place more :)"
msgstr ""
#: src/ui/placePixel.js:232
msgid "You can not access this canvas yet. You need to place more pixels"
msgstr ""
#: src/ui/placePixel.js:235
msgid "Pixel protected!"
msgstr ""
#: src/ui/placePixel.js:251
msgid "No Proxies Allowed :("
msgstr ""
#: src/ui/placePixel.js:252
msgid "You are using a Proxy."
msgstr ""
#: src/ui/placePixel.js:255
msgid "Weird"
msgstr ""
#: src/ui/placePixel.js:256
msgid "Couldn't set Pixel"
msgstr ""
#: src/ui/placePixel.js:262
#, javascript-format
msgid "Error ${ retCode }"
msgstr ""
#: src/components/Admintools.jsx:219
#: src/components/ChannelContextMenu.jsx:85
#: src/components/ModalRoot.jsx:60
msgid "Close"
msgstr ""
#: src/components/ExpandMenuButton.jsx:19 #: src/components/ExpandMenuButton.jsx:19
msgid "Close Menu" msgid "Close Menu"
msgstr "" msgstr ""
@ -19,6 +118,11 @@ msgstr ""
msgid "Open Chat" msgid "Open Chat"
msgstr "" msgstr ""
#: src/components/CanvasSelectModal.jsx:67
#: src/components/CanvasSwitchButton.jsx:20
msgid "Canvas Selection"
msgstr ""
#: src/components/OnlineBox.jsx:22 #: src/components/OnlineBox.jsx:22
msgid "User online" msgid "User online"
msgstr "" msgstr ""
@ -27,10 +131,7 @@ msgstr ""
msgid "Pixel gesetzt" msgid "Pixel gesetzt"
msgstr "" msgstr ""
#: src/components/CanvasSwitchButton.jsx:20 #: src/components/Converter.jsx:609
msgid "Canvas Selection"
msgstr ""
#: src/components/CoordinatesBox.jsx:26 #: src/components/CoordinatesBox.jsx:26
msgid "Copy to Clipboard" msgid "Copy to Clipboard"
msgstr "" msgstr ""
@ -69,7 +170,7 @@ msgstr ""
msgid "Chat here" msgid "Chat here"
msgstr "" msgstr ""
#: src/components/Chat.jsx:219 #: src/components/Chat.jsx:220
msgid "You must be logged in to chat" msgid "You must be logged in to chat"
msgstr "" msgstr ""
@ -77,12 +178,87 @@ msgstr ""
msgid "Globe View" msgid "Globe View"
msgstr "" msgstr ""
#: src/components/PalselButton.jsx:25 #: src/components/SettingsModal.jsx:123
msgid "Close Palette" msgid "Show Grid"
msgstr "" msgstr ""
#: src/components/PalselButton.jsx:25 #: src/components/SettingsModal.jsx:124
msgid "Open Palette" msgid "Turn on grid to highlight pixel borders."
msgstr ""
#: src/components/SettingsModal.jsx:130
msgid "Show Pixel Activity"
msgstr ""
#: src/components/SettingsModal.jsx:131
msgid "Show circles where pixels are placed."
msgstr ""
#: src/components/SettingsModal.jsx:137
msgid "Disable Game Sounds"
msgstr ""
#: src/components/SettingsModal.jsx:139
msgid "All sound effects will be disabled."
msgstr ""
#: src/components/SettingsModal.jsx:145
msgid "Enable chat notifications"
msgstr ""
#: src/components/SettingsModal.jsx:146
msgid "Play a sound when new chat messages arrive"
msgstr ""
#: src/components/SettingsModal.jsx:151
msgid "Auto Zoom In"
msgstr ""
#: src/components/SettingsModal.jsx:153
msgid ""
"Zoom in instead of placing a pixel when you tap the canvas and your zoom is "
"small."
msgstr ""
#: src/components/SettingsModal.jsx:158
msgid "Compact Palette"
msgstr ""
#: src/components/SettingsModal.jsx:160
msgid "Display Palette in a compact form that takes less screen space."
msgstr ""
#: src/components/SettingsModal.jsx:165
msgid "Potato Mode"
msgstr ""
#: src/components/SettingsModal.jsx:166
msgid "For when you are playing on a potato."
msgstr ""
#: src/components/Converter.jsx:423
#: src/components/SettingsModal.jsx:171
msgid "Light Grid"
msgstr ""
#: src/components/SettingsModal.jsx:172
msgid "Show Grid in white instead of black."
msgstr ""
#: src/components/SettingsModal.jsx:179
msgid "Historical View"
msgstr ""
#: src/components/SettingsModal.jsx:180
msgid "Check out past versions of the canvas."
msgstr ""
#: src/components/SettingsModal.jsx:188
msgid "Themes"
msgstr ""
#: src/components/SettingsModal.jsx:189
msgid "How pixelplanet should look like."
msgstr "" msgstr ""
#: src/components/HelpModal.jsx:34 #: src/components/HelpModal.jsx:34
@ -278,6 +454,44 @@ msgstr ""
msgid "Welcome to PixelPlanet.fun" msgid "Welcome to PixelPlanet.fun"
msgstr "" msgstr ""
#: src/components/ChannelContextMenu.jsx:73
msgid "Mute"
msgstr ""
#: src/components/UserContextMenu.jsx:72
msgid "Ping"
msgstr ""
#: src/components/UserContextMenu.jsx:97
msgid "DM"
msgstr ""
#: src/components/UserContextMenu.jsx:107
msgid "Block"
msgstr ""
#: src/components/PalselButton.jsx:25
msgid "Close Palette"
msgstr ""
#: src/components/PalselButton.jsx:25
msgid "Open Palette"
msgstr ""
#: src/components/RegisterModal.jsx:18
msgid "Register new account here"
msgstr ""
#: src/components/ForgotPasswordModal.jsx:20
#: src/components/RegisterModal.jsx:21
#: src/components/UserAreaModal.jsx:130
msgid "Consider joining us on Guilded:"
msgstr ""
#: src/components/RegisterModal.jsx:38
msgid "Register New Account"
msgstr ""
#: src/components/UserAreaModal.jsx:33 #: src/components/UserAreaModal.jsx:33
msgid "Login to access more features and stats." msgid "Login to access more features and stats."
msgstr "" msgstr ""
@ -290,6 +504,10 @@ msgstr ""
msgid "I forgot my Password." msgid "I forgot my Password."
msgstr "" msgstr ""
#: src/components/UserAreaModal.jsx:43
msgid "or login with:"
msgstr ""
#: src/components/UserAreaModal.jsx:84 #: src/components/UserAreaModal.jsx:84
msgid "or register here:" msgid "or register here:"
msgstr "" msgstr ""
@ -298,104 +516,40 @@ msgstr ""
msgid "Register" msgid "Register"
msgstr "" msgstr ""
#: src/components/UserAreaModal.jsx:107
msgid "Profile"
msgstr ""
#: src/components/UserAreaModal.jsx:113
msgid "Ranking"
msgstr ""
#: src/components/UserAreaModal.jsx:116
msgid "Converter"
msgstr ""
#: src/components/UserAreaModal.jsx:122
msgid "Admintools"
msgstr ""
#: src/components/UserAreaModal.jsx:122
msgid "Modtools"
msgstr ""
#: src/components/UserAreaModal.jsx:123 #: src/components/UserAreaModal.jsx:123
msgid "Loading..." msgid "Loading..."
msgstr "" msgstr ""
#: src/components/ForgotPasswordModal.jsx:20 #: src/components/ForgotPasswordModal.jsx:16
#: src/components/RegisterModal.jsx:21 msgid "Enter your mail adress and we will send you a new password:"
#: src/components/UserAreaModal.jsx:130
msgid "Consider joining us on Guilded:"
msgstr "" msgstr ""
#: src/components/RegisterModal.jsx:18 #: src/components/ForgotPasswordModal.jsx:37
msgid "Register new account here" msgid "Restore my Password"
msgstr "" msgstr ""
#: src/components/RegisterModal.jsx:38 #: src/components/ChatModal.jsx:35
msgid "Register New Account" msgid "Chat"
msgstr ""
#: src/components/SettingsModal.jsx:123
msgid "Show Grid"
msgstr ""
#: src/components/SettingsModal.jsx:124
msgid "Turn on grid to highlight pixel borders."
msgstr ""
#: src/components/SettingsModal.jsx:130
msgid "Show Pixel Activity"
msgstr ""
#: src/components/SettingsModal.jsx:131
msgid "Show circles where pixels are placed."
msgstr ""
#: src/components/SettingsModal.jsx:137
msgid "Disable Game Sounds"
msgstr ""
#: src/components/SettingsModal.jsx:139
msgid "All sound effects will be disabled."
msgstr ""
#: src/components/SettingsModal.jsx:145
msgid "Enable chat notifications"
msgstr ""
#: src/components/SettingsModal.jsx:146
msgid "Play a sound when new chat messages arrive"
msgstr ""
#: src/components/SettingsModal.jsx:151
msgid "Auto Zoom In"
msgstr ""
#: src/components/SettingsModal.jsx:153
msgid ""
"Zoom in instead of placing a pixel when you tap the canvas and your zoom is "
"small."
msgstr ""
#: src/components/SettingsModal.jsx:158
msgid "Compact Palette"
msgstr ""
#: src/components/SettingsModal.jsx:160
msgid "Display Palette in a compact form that takes less screen space."
msgstr ""
#: src/components/SettingsModal.jsx:165
msgid "Potato Mode"
msgstr ""
#: src/components/SettingsModal.jsx:166
msgid "For when you are playing on a potato."
msgstr ""
#: src/components/SettingsModal.jsx:171
msgid "Light Grid"
msgstr ""
#: src/components/SettingsModal.jsx:172
msgid "Show Grid in white instead of black."
msgstr ""
#: src/components/SettingsModal.jsx:179
msgid "Historical View"
msgstr ""
#: src/components/SettingsModal.jsx:180
msgid "Check out past versions of the canvas."
msgstr ""
#: src/components/SettingsModal.jsx:188
msgid "Themes"
msgstr ""
#: src/components/SettingsModal.jsx:189
msgid "How pixelplanet should look like."
msgstr "" msgstr ""
#: src/components/ArchiveModal.jsx:20 #: src/components/ArchiveModal.jsx:20
@ -435,23 +589,25 @@ msgstr ""
msgid "Canvas Archive" msgid "Canvas Archive"
msgstr "" msgstr ""
#: src/components/ForgotPasswordModal.jsx:16 #: src/components/CanvasSelectModal.jsx:29
msgid "Enter your mail adress and we will send you a new password:" msgid ""
"Select the canvas you want to use. Every canvas is unique and has different "
"palettes, cooldown and requirements. Archive of closed canvases can be "
"accessed here:"
msgstr "" msgstr ""
#: src/components/ForgotPasswordModal.jsx:37 #: src/components/CanvasSelectModal.jsx:37
msgid "Restore my Password" msgid "Archive"
msgstr ""
#: src/components/ChatModal.jsx:35
msgid "Chat"
msgstr "" msgstr ""
#: src/components/LogInForm.jsx:104 #: src/components/LogInForm.jsx:104
msgid "Name or Email" msgid "Name or Email"
msgstr "" msgstr ""
#: src/components/ChangeMail.jsx:109
#: src/components/DeleteAccount.jsx:88
#: src/components/LogInForm.jsx:111 #: src/components/LogInForm.jsx:111
#: src/components/SignUpForm.jsx:139
msgid "Password" msgid "Password"
msgstr "" msgstr ""
@ -459,10 +615,368 @@ msgstr ""
msgid "LogIn" msgid "LogIn"
msgstr "" msgstr ""
#: src/components/UserArea.jsx:57
msgid "Todays Placed Pixels"
msgstr ""
#: src/components/UserArea.jsx:61
msgid "Daily Rank"
msgstr ""
#: src/components/UserArea.jsx:66
msgid "Placed Pixels"
msgstr ""
#: src/components/UserArea.jsx:70
msgid "Total Rank"
msgstr ""
#: src/components/UserArea.jsx:75
#, javascript-format
msgid "Your name is: ${ name }"
msgstr ""
#: src/components/UserArea.jsx:81
msgid "Log out"
msgstr ""
#: src/components/UserArea.jsx:93
msgid "Change Username"
msgstr ""
#: src/components/UserArea.jsx:108
msgid "Change Mail"
msgstr ""
#: src/components/UserArea.jsx:122
msgid "Change Password"
msgstr ""
#: src/components/UserArea.jsx:134
msgid "Delete Account"
msgstr ""
#: src/components/UserArea.jsx:147
msgid "Social Settings"
msgstr ""
#: src/components/Rankings.jsx:37
msgid "Total"
msgstr ""
#: src/components/Rankings.jsx:45
msgid "Daily"
msgstr ""
#: src/components/Rankings.jsx:49 #: src/components/Rankings.jsx:49
msgid "Ranking updates every 5 min. Daily rankings get reset at midnight UTC." msgid "Ranking updates every 5 min. Daily rankings get reset at midnight UTC."
msgstr "" msgstr ""
#: src/components/CanvasItem.jsx:46
msgid "Cooldown"
msgstr ""
#: src/components/CanvasItem.jsx:52
msgid "Stacking till"
msgstr ""
#: src/components/CanvasItem.jsx:54
msgid "Ranked"
msgstr ""
#: src/components/CanvasItem.jsx:56
msgid "Requirements"
msgstr ""
#: src/components/CanvasItem.jsx:58
msgid "User Account"
msgstr ""
#: src/components/CanvasItem.jsx:60
#, javascript-format
msgid "and ${ canvas.req } Pixels set"
msgstr ""
#: src/components/CanvasItem.jsx:64
msgid "Dimensions"
msgstr ""
#: src/components/Admintools.jsx:179
msgid "Build image on canvas."
msgstr ""
#: src/components/Admintools.jsx:182
msgid "Build image and set it to protected."
msgstr ""
#: src/components/Admintools.jsx:185
msgid "Build image, but reset cooldown to unset-pixel cd."
msgstr ""
#: src/components/Admintools.jsx:248
msgid "Image Upload"
msgstr ""
#: src/components/Admintools.jsx:249
msgid "Upload images to canvas"
msgstr ""
#: src/components/Admintools.jsx:251
msgid "File"
msgstr ""
#: src/components/Admintools.jsx:271
msgid "Coordinates in X_Y format:"
msgstr ""
#: src/components/Admintools.jsx:306
#: src/components/Admintools.jsx:387
#: src/components/Admintools.jsx:461
#: src/components/Admintools.jsx:505
#: src/components/Admintools.jsx:589
#: src/components/SignUpForm.jsx:151
msgid "Submit"
msgstr ""
#: src/components/Admintools.jsx:311
msgid "Pixel Protection"
msgstr ""
#: src/components/Admintools.jsx:313
msgid ""
"Set protection of areas (if you need finer grained control, "
"use protect with image upload and alpha layers)"
msgstr ""
#: src/components/Admintools.jsx:392
msgid "Rollback to Date"
msgstr ""
#: src/components/Admintools.jsx:394
msgid "Rollback an area of the canvas to a set date (00:00 UTC)"
msgstr ""
#: src/components/Admintools.jsx:468
msgid "IP Actions"
msgstr ""
#: src/components/Admintools.jsx:470
msgid "Do stuff with IPs (one IP per line)"
msgstr ""
#: src/components/Admintools.jsx:510
msgid "Manage Moderators"
msgstr ""
#: src/components/Admintools.jsx:512
msgid "Remove Moderator"
msgstr ""
#: src/components/Admintools.jsx:544
msgid "There are no mods"
msgstr ""
#: src/components/Admintools.jsx:549
msgid "Assign new Mod"
msgstr ""
#: src/components/Admintools.jsx:552
msgid "Enter UserName of new Mod"
msgstr ""
#: src/components/SignUpForm.jsx:125
msgid "Name"
msgstr ""
#: src/components/SignUpForm.jsx:132
msgid "Email"
msgstr ""
#: src/components/SignUpForm.jsx:148
msgid "Confirm Password"
msgstr ""
#: src/components/ChangeMail.jsx:122
#: src/components/ChangePassword.jsx:151
#: src/components/DeleteAccount.jsx:94
#: src/components/SignUpForm.jsx:157
msgid "Cancel"
msgstr ""
#: src/components/Converter.jsx:274
msgid "Choose Canvas"
msgstr ""
#: src/components/Converter.jsx:300
msgid "Palette Download"
msgstr ""
#: src/components/Converter.jsx:302
#, javascript-format
msgid "Palette for ${ gimpLink }"
msgstr ""
#: src/components/Converter.jsx:320
#, javascript-format
msgid "Credit for the Palette of the Moon goes to ${ starhouseLink }."
msgstr ""
#: src/components/Converter.jsx:323
msgid "Image Converter"
msgstr ""
#: src/components/Converter.jsx:324
msgid "Convert an image to canvas colors"
msgstr ""
#: src/components/Converter.jsx:335
msgid "Choose Strategy"
msgstr ""
#: src/components/Converter.jsx:362
msgid "Choose Color Mode"
msgstr ""
#: src/components/Converter.jsx:400
msgid "Add Grid (uncheck if you need a 1:1 template)"
msgstr ""
#: src/components/Converter.jsx:425
#: src/components/Converter.jsx:441
msgid "Offset"
msgstr ""
#: src/components/Converter.jsx:471
msgid "Scale Image"
msgstr ""
#: src/components/Converter.jsx:483
msgid "Width"
msgstr ""
#: src/components/Converter.jsx:513
msgid "Height"
msgstr ""
#: src/components/Converter.jsx:551
msgid "Keep Ratio"
msgstr ""
#: src/components/Converter.jsx:564
msgid "Anti Aliasing"
msgstr ""
#: src/components/Converter.jsx:578
msgid "Reset"
msgstr ""
#: src/components/Converter.jsx:597
msgid "Download Template"
msgstr ""
#: src/utils/validation.js:15
msgid "Email can't be empty."
msgstr ""
#: src/utils/validation.js:16
msgid "Email should be at least 5 characters long."
msgstr ""
#: src/utils/validation.js:17
msgid "Email can't be longer than 40 characters."
msgstr ""
#: src/utils/validation.js:18
msgid "Email should at least contain a dot"
msgstr ""
#: src/utils/validation.js:20
msgid "Email should contain a @"
msgstr ""
#: src/utils/validation.js:27
msgid "Name can't be empty."
msgstr ""
#: src/utils/validation.js:28
msgid "Name must be at least 4 characters long"
msgstr ""
#: src/utils/validation.js:29
msgid "Name must be shorter than 26 characters"
msgstr ""
#: src/utils/validation.js:36
msgid "Name contains invalid character like @, /, \\ or #"
msgstr ""
#: src/utils/validation.js:51
msgid "Password must be at least 6 characters long."
msgstr ""
#: src/utils/validation.js:54
msgid "Password must be shorter than 60 characters."
msgstr ""
#: src/utils/validation.js:68
msgid "Could not connect to server, please try again later :("
msgstr ""
#: src/utils/validation.js:74
msgid "I think we experienced some error :("
msgstr ""
#: src/components/DeleteAccount.jsx:92
msgid "Yes, Delete My Account!"
msgstr ""
#: src/components/ChangeMail.jsx:89
msgid ""
"Changed Mail successfully. We sent you a verification mail, "
"please verify your new mail adress."
msgstr ""
#: src/components/ChangeMail.jsx:116
msgid "New Mail"
msgstr ""
#: src/components/ChangeMail.jsx:120
#: src/components/ChangePassword.jsx:149
msgid "Save"
msgstr ""
#: src/components/ChangePassword.jsx:18
msgid "Passwords do not match."
msgstr ""
#: src/components/ChangePassword.jsx:103
msgid "Changed Password successfully."
msgstr ""
#: src/components/ChangePassword.jsx:128
msgid "Old Password"
msgstr ""
#: src/components/ChangePassword.jsx:136
msgid "New Password"
msgstr ""
#: src/components/ChangePassword.jsx:145
msgid "Confirm New Password"
msgstr ""
#: src/components/SocialSettings.jsx:39
msgid "Block all Private Messages"
msgstr ""
#: src/components/SocialSettings.jsx:57
msgid "Unblock Users"
msgstr ""
#: src/components/SocialSettings.jsx:81
msgid "You have no users blocked"
msgstr ""
#: src/components/HelpModal.jsx:15 #: src/components/HelpModal.jsx:15
#: src/components/SettingsModal.jsx:125 #: src/components/SettingsModal.jsx:125
msgctxt "keybinds" msgctxt "keybinds"
@ -475,6 +989,11 @@ msgctxt "keybinds"
msgid "X" msgid "X"
msgstr "" msgstr ""
#: src/components/SettingsModal.jsx:140
msgctxt "keybinds"
msgid "M"
msgstr ""
#: src/components/HelpModal.jsx:17 #: src/components/HelpModal.jsx:17
#: src/components/SettingsModal.jsx:182 #: src/components/SettingsModal.jsx:182
msgctxt "keybinds" msgctxt "keybinds"
@ -524,9 +1043,4 @@ msgstr ""
#: src/components/HelpModal.jsx:32 #: src/components/HelpModal.jsx:32
msgctxt "keybinds" msgctxt "keybinds"
msgid "C" msgid "C"
msgstr ""
#: src/components/SettingsModal.jsx:140
msgctxt "keybinds"
msgid "M"
msgstr "" msgstr ""

View File

@ -35,6 +35,8 @@ function getCanvases(t) {
const key = canvasKeys[i]; const key = canvasKeys[i];
localicedCanvases[key].desc = canvasDesc[key] || `Canvas ${key}`; localicedCanvases[key].desc = canvasDesc[key] || `Canvas ${key}`;
} }
return localicedCanvases;
} }

View File

@ -5,6 +5,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { t } from 'ttag';
import type { State } from '../reducers'; import type { State } from '../reducers';
@ -175,13 +176,13 @@ function Admintools({
let descAction; let descAction;
switch (imageAction) { switch (imageAction) {
case 'build': case 'build':
descAction = 'Build image on canvas.'; descAction = t`Build image on canvas.`;
break; break;
case 'protect': case 'protect':
descAction = 'Build image and set it to protected.'; descAction = t`Build image and set it to protected.`;
break; break;
case 'wipe': case 'wipe':
descAction = 'Build image, but reset cooldown to unset-pixel cd.'; descAction = t`Build image, but reset cooldown to unset-pixel cd.`;
break; break;
default: default:
// nothing // nothing
@ -215,7 +216,7 @@ function Admintools({
className="modallink" className="modallink"
onClick={() => setResp(null)} onClick={() => setResp(null)}
> >
Close {t`Close`}
</span> </span>
</div> </div>
)} )}
@ -244,10 +245,10 @@ function Admintools({
</p> </p>
<br /> <br />
<div className="modaldivider" /> <div className="modaldivider" />
<h3 className="modaltitle">Image Upload</h3> <h3 className="modaltitle">{t`Image Upload`}</h3>
<p className="modalcotext">Upload images to canvas</p> <p className="modalcotext">{t`Upload images to canvas`}</p>
<p className="modalcotext"> <p className="modalcotext">
File:&nbsp; {t`File`}:&nbsp;
<input type="file" name="image" id="imgfile" /> <input type="file" name="image" id="imgfile" />
</p> </p>
<select <select
@ -267,7 +268,7 @@ function Admintools({
</select> </select>
<p className="modalcotext">{descAction}</p> <p className="modalcotext">{descAction}</p>
<p className="modalcotext"> <p className="modalcotext">
Coordinates in X_Y format:&nbsp; {t`Coordinates in X_Y format:`}&nbsp;
<input <input
value={coords} value={coords}
style={{ style={{
@ -302,16 +303,16 @@ function Admintools({
); );
}} }}
> >
{(submitting) ? '...' : 'Submit'} {(submitting) ? '...' : t`Submit`}
</button> </button>
<br /> <br />
<div className="modaldivider" /> <div className="modaldivider" />
<h3 className="modaltitle">Pixel Protection</h3> <h3 className="modaltitle">{t`Pixel Protection`}</h3>
<p className="modalcotext"> <p className="modalcotext">
Set protection of areas&nbsp; {t`Set protection of areas \
(if you need finer grained control,&nbsp; (if you need finer grained control, \
use protect with image upload and alpha layers) use protect with image upload and alpha layers)`}
</p> </p>
<select <select
onChange={(e) => { onChange={(e) => {
@ -383,14 +384,14 @@ function Admintools({
); );
}} }}
> >
{(submitting) ? '...' : 'Submit'} {(submitting) ? '...' : t`Submit`}
</button> </button>
<br /> <br />
<div className="modaldivider" /> <div className="modaldivider" />
<h3 className="modaltitle">Rollback to Date</h3> <h3 className="modaltitle">{t`Rollback to Date`}</h3>
<p className="modalcotext"> <p className="modalcotext">
Rollback an area of the canvas to a set date (00:00 UTC) {t`Rollback an area of the canvas to a set date (00:00 UTC)`}
</p> </p>
<input <input
type="date" type="date"
@ -457,15 +458,17 @@ function Admintools({
); );
}} }}
> >
{(submitting) ? '...' : 'Submit'} {(submitting) ? '...' : t`Submit`}
</button> </button>
{(userlvl === 1) && ( {(userlvl === 1) && (
<div> <div>
<br /> <br />
<div className="modaldivider" /> <div className="modaldivider" />
<h3 className="modaltitle">IP Actions</h3> <h3 className="modaltitle">{t`IP Actions`}</h3>
<p className="modalcotext">Do stuff with IPs (one IP per line)</p> <p className="modalcotext">
{t`Do stuff with IPs (one IP per line)`}
</p>
<select <select
onChange={(e) => { onChange={(e) => {
const sel = e.target; const sel = e.target;
@ -499,14 +502,14 @@ function Admintools({
); );
}} }}
> >
{(submitting) ? '...' : 'Submit'} {(submitting) ? '...' : t`Submit`}
</button> </button>
<br /> <br />
<div className="modaldivider" /> <div className="modaldivider" />
<h3 className="modaltitle">Manage Moderators</h3> <h3 className="modaltitle">{t`Manage Moderators`}</h3>
<p className="modalcotext"> <p className="modalcotext">
Remove Moderator {t`Remove Moderator`}
</p> </p>
{(modlist.length) ? ( {(modlist.length) ? (
<span <span
@ -538,15 +541,15 @@ function Admintools({
</span> </span>
) )
: ( : (
<p className="modaltext">There are no mods</p> <p className="modaltext">{t`There are no mods`}</p>
)} )}
<br /> <br />
<p className="modalcotext"> <p className="modalcotext">
Assign new Mod {t`Assign new Mod`}
</p> </p>
<p className="modalcotext"> <p className="modalcotext">
Enter UserName of new Mod:&nbsp; {t`Enter UserName of new Mod`}:&nbsp;
<input <input
value={modName} value={modName}
style={{ style={{
@ -583,7 +586,7 @@ function Admintools({
); );
}} }}
> >
{(submitting) ? '...' : 'Submit'} {(submitting) ? '...' : t`Submit`}
</button> </button>
<br /> <br />
<div className="modaldivider" /> <div className="modaldivider" />

View File

@ -4,6 +4,7 @@
*/ */
import React from 'react'; import React from 'react';
import { t } from 'ttag';
import { import {
validateEMail, validatePassword, parseAPIresponse, validateEMail, validatePassword, parseAPIresponse,
} from '../utils/validation'; } from '../utils/validation';
@ -85,8 +86,8 @@ class ChangeMail extends React.Component {
<p <p
className="modalmessage" className="modalmessage"
> >
Changed Mail successfully. {t`Changed Mail successfully. We sent you a verification mail, \
We sent you a verification mail, please verify your new mail adress. please verify your new mail adress.`}
</p> </p>
<button type="button" onClick={done}>Close</button> <button type="button" onClick={done}>Close</button>
</div> </div>
@ -105,20 +106,20 @@ class ChangeMail extends React.Component {
value={password} value={password}
onChange={(evt) => this.setState({ password: evt.target.value })} onChange={(evt) => this.setState({ password: evt.target.value })}
type="password" type="password"
placeholder="Password" placeholder={t`Password`}
/> />
<br /> <br />
<input <input
value={email} value={email}
onChange={(evt) => this.setState({ email: evt.target.value })} onChange={(evt) => this.setState({ email: evt.target.value })}
type="text" type="text"
placeholder="New Mail" placeholder={t`New Mail`}
/> />
<br /> <br />
<button type="submit"> <button type="submit">
{(submitting) ? '...' : 'Save'} {(submitting) ? '...' : t`Save`}
</button> </button>
<button type="button" onClick={done}>Cancel</button> <button type="button" onClick={done}>{t`Cancel`}</button>
</form> </form>
</div> </div>
); );

View File

@ -4,6 +4,7 @@
*/ */
import React from 'react'; import React from 'react';
import { t } from 'ttag';
import { validatePassword, parseAPIresponse } from '../utils/validation'; import { validatePassword, parseAPIresponse } from '../utils/validation';
function validate(mailreg, password, newPassword, confirmPassword) { function validate(mailreg, password, newPassword, confirmPassword) {
@ -14,7 +15,7 @@ function validate(mailreg, password, newPassword, confirmPassword) {
if (oldpasserror) errors.push(oldpasserror); if (oldpasserror) errors.push(oldpasserror);
} }
if (newPassword !== confirmPassword) { if (newPassword !== confirmPassword) {
errors.push('Passwords do not match.'); errors.push(t`Passwords do not match.`);
return errors; return errors;
} }
const passerror = validatePassword(newPassword); const passerror = validatePassword(newPassword);
@ -99,7 +100,7 @@ class ChangePassword extends React.Component {
const { done } = this.props; const { done } = this.props;
return ( return (
<div className="inarea"> <div className="inarea">
<p className="modalmessage">Changed Password successfully.</p> <p className="modalmessage">{t`Changed Password successfully.`}</p>
<button type="button" onClick={done}>Close</button> <button type="button" onClick={done}>Close</button>
</div> </div>
); );
@ -124,7 +125,7 @@ class ChangePassword extends React.Component {
value={password} value={password}
onChange={(evt) => this.setState({ password: evt.target.value })} onChange={(evt) => this.setState({ password: evt.target.value })}
type="password" type="password"
placeholder="Old Password" placeholder={t`Old Password`}
/> />
)} )}
<br /> <br />
@ -132,7 +133,7 @@ class ChangePassword extends React.Component {
value={newPassword} value={newPassword}
onChange={(evt) => this.setState({ newPassword: evt.target.value })} onChange={(evt) => this.setState({ newPassword: evt.target.value })}
type="password" type="password"
placeholder="New Password" placeholder={t`New Password`}
/> />
<br /> <br />
<input <input
@ -141,13 +142,13 @@ class ChangePassword extends React.Component {
confirmPassword: evt.target.value, confirmPassword: evt.target.value,
})} })}
type="password" type="password"
placeholder="Confirm New Password" placeholder={t`Confirm New Password`}
/> />
<br /> <br />
<button type="submit"> <button type="submit">
{(submitting) ? '...' : 'Save'} {(submitting) ? '...' : t`Save`}
</button> </button>
<button type="button" onClick={cancel}>Cancel</button> <button type="button" onClick={cancel}>{t`Cancel`}</button>
</form> </form>
</div> </div>
); );

View File

@ -7,6 +7,7 @@ import React, {
useRef, useEffect, useRef, useEffect,
} from 'react'; } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { t } from 'ttag';
import { import {
hideContextMenu, hideContextMenu,
@ -69,7 +70,7 @@ const UserContextMenu = ({
tabIndex={0} tabIndex={0}
style={{ borderTop: 'none' }} style={{ borderTop: 'none' }}
> >
{`${(isMuted) ? '✔' : '✘'} Mute`} {`${(isMuted) ? '✔' : '✘'} ${t`Mute`}`}
</div> </div>
{(channels[cid][1] !== 0) {(channels[cid][1] !== 0)
&& ( && (
@ -81,7 +82,7 @@ const UserContextMenu = ({
}} }}
tabIndex={0} tabIndex={0}
> >
Close {t`Close`}
</div> </div>
)} )}
</div> </div>

View File

@ -5,8 +5,9 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { validatePassword, parseAPIresponse } from '../utils/validation'; import { t } from 'ttag';
import { validatePassword, parseAPIresponse } from '../utils/validation';
import { logoutUser } from '../actions'; import { logoutUser } from '../actions';
function validate(password) { function validate(password) {
@ -84,13 +85,13 @@ class DeleteAccount extends React.Component {
value={password} value={password}
onChange={(evt) => this.setState({ password: evt.target.value })} onChange={(evt) => this.setState({ password: evt.target.value })}
type="password" type="password"
placeholder="Password" placeholder={t`Password`}
/> />
<br /> <br />
<button type="submit"> <button type="submit">
{(submitting) ? '...' : 'Yes, Delete My Account!'} {(submitting) ? '...' : t`Yes, Delete My Account!`}
</button> </button>
<button type="button" onClick={done}>Cancel</button> <button type="button" onClick={done}>{t`Cancel`}</button>
</form> </form>
</div> </div>
); );

View File

@ -18,8 +18,10 @@ function validate(nameoremail, password) {
? validateEMail(nameoremail) ? validateEMail(nameoremail)
: validateName(nameoremail); : validateName(nameoremail);
if (mailerror) errors.push(mailerror); if (mailerror) errors.push(mailerror);
/*
const passworderror = validatePassword(password); const passworderror = validatePassword(password);
if (passworderror) errors.push(passworderror); if (passworderror) errors.push(passworderror);
*/
return errors; return errors;
} }

View File

@ -5,6 +5,7 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { t } from 'ttag';
import { import {
validateEMail, validateName, validatePassword, parseAPIresponse, validateEMail, validateName, validatePassword, parseAPIresponse,
} from '../utils/validation'; } from '../utils/validation';
@ -121,21 +122,21 @@ class SignUpForm extends React.Component {
value={name} value={name}
onChange={(evt) => this.setState({ name: evt.target.value })} onChange={(evt) => this.setState({ name: evt.target.value })}
type="text" type="text"
placeholder="Name" placeholder={t`Name`}
/><br /> /><br />
<input <input
style={inputStyles} style={inputStyles}
value={email} value={email}
onChange={(evt) => this.setState({ email: evt.target.value })} onChange={(evt) => this.setState({ email: evt.target.value })}
type="text" type="text"
placeholder="Email" placeholder={t`Email`}
/><br /> /><br />
<input <input
style={inputStyles} style={inputStyles}
value={password} value={password}
onChange={(evt) => this.setState({ password: evt.target.value })} onChange={(evt) => this.setState({ password: evt.target.value })}
type="password" type="password"
placeholder="Password" placeholder={t`Password`}
/><br /> /><br />
<input <input
style={inputStyles} style={inputStyles}
@ -144,16 +145,16 @@ class SignUpForm extends React.Component {
confirmPassword: evt.target.value, confirmPassword: evt.target.value,
})} })}
type="password" type="password"
placeholder="Confirm Password" placeholder={t`Confirm Password`}
/><br /> /><br />
<button type="submit"> <button type="submit">
{(submitting) ? '...' : 'Submit'} {(submitting) ? '...' : t`Submit`}
</button> </button>
<button <button
type="button" type="button"
onClick={back} onClick={back}
> >
Cancel {t`Cancel`}
</button> </button>
</form> </form>
); );

View File

@ -5,6 +5,7 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { t } from 'ttag';
import { import {
setBlockingDm, setBlockingDm,
@ -35,7 +36,7 @@ const SocialSettings = ({
}} }}
className="modaltitle" className="modaltitle"
> >
Block all Private Messages {t`Block all Private Messages`}
</span> </span>
<MdToggleButtonHover <MdToggleButtonHover
value={blockDm} value={blockDm}
@ -53,7 +54,7 @@ const SocialSettings = ({
marginLeft: 10, marginLeft: 10,
}} }}
className="modaltitle" className="modaltitle"
>Unblock Users</p> >{t`Unblock Users`}</p>
{ {
(blocked.length) ? ( (blocked.length) ? (
<span <span
@ -77,7 +78,7 @@ const SocialSettings = ({
</span> </span>
) )
: ( : (
<p className="modaltext">You have no users blocked</p> <p className="modaltext">{t`You have no users blocked`}</p>
) )
} }
<div className="modaldivider" /> <div className="modaldivider" />

View File

@ -7,6 +7,7 @@ import React, {
useRef, useEffect, useRef, useEffect,
} from 'react'; } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { t } from 'ttag';
import { import {
hideContextMenu, hideContextMenu,
@ -68,7 +69,7 @@ const UserContextMenu = ({
}} }}
style={{ borderTop: 'none' }} style={{ borderTop: 'none' }}
> >
Ping {t`Ping`}
</div> </div>
<div <div
role="button" role="button"
@ -93,7 +94,7 @@ const UserContextMenu = ({
close(); close();
}} }}
> >
DM {t`DM`}
</div> </div>
<div <div
onClick={() => { onClick={() => {
@ -103,7 +104,7 @@ const UserContextMenu = ({
role="button" role="button"
tabIndex={-1} tabIndex={-1}
> >
Block {t`Block`}
</div> </div>
</div> </div>
); );

View File

@ -3,12 +3,14 @@
* @flow * @flow
*/ */
// import Sequelize from 'sequelize'; /* eslint-disable max-len */
import nodemailer from 'nodemailer'; import nodemailer from 'nodemailer';
import logger from './logger'; import logger from './logger';
import { HOUR, MINUTE } from './constants'; import { HOUR, MINUTE } from './constants';
import { DailyCron, HourlyCron } from '../utils/cron'; import { DailyCron, HourlyCron } from '../utils/cron';
import { getTTag } from './ttag';
import { GMAIL_USER, GMAIL_PW } from './config'; import { GMAIL_USER, GMAIL_PW } from './config';
import RegUser from '../data/models/RegUser'; import RegUser from '../data/models/RegUser';
@ -48,7 +50,9 @@ class MailProvider {
DailyCron.hook(MailProvider.cleanUsers); DailyCron.hook(MailProvider.cleanUsers);
} }
sendVerifyMail(to, name, host) { sendVerifyMail(to, name, host, lang) {
const { t } = getTTag(lang);
const pastMail = this.verifyCodes[to]; const pastMail = this.verifyCodes[to];
if (pastMail) { if (pastMail) {
const minLeft = Math.floor( const minLeft = Math.floor(
@ -58,8 +62,7 @@ class MailProvider {
logger.info( logger.info(
`Verify mail for ${to} - already sent, ${minLeft} minutes left`, `Verify mail for ${to} - already sent, ${minLeft} minutes left`,
); );
// eslint-disable-next-line max-len return t`We already sent you a verification mail, you can request another one in ${minLeft} minutes.`;
return `We already sent you a verification mail, you can request another one in ${minLeft} minutes.`;
} }
} }
logger.info(`Sending verification mail to ${to} / ${name}`); logger.info(`Sending verification mail to ${to} / ${name}`);
@ -69,12 +72,13 @@ class MailProvider {
from, from,
to, to,
replyTo: 'donotreply@pixelplanet.fun', replyTo: 'donotreply@pixelplanet.fun',
// eslint-disable-next-line max-len subject: t`Welcome ${name} to PixelPlanet, plese verify your mail`,
subject: `Welcome ${name} to PixelPlanet, plese verify your mail`,
// eslint-disable-next-line max-len
// text: `Hello,\nwelcome to our little community of pixelplacers, to use your account, you have to verify your mail. You can do that here:\n ${verifyUrl} \nHave fun and don't hesitate to contact us if you encouter any problems :)\nThanks`, // text: `Hello,\nwelcome to our little community of pixelplacers, to use your account, you have to verify your mail. You can do that here:\n ${verifyUrl} \nHave fun and don't hesitate to contact us if you encouter any problems :)\nThanks`,
// eslint-disable-next-line max-len html: `<em>${t`Hello ${name}`}</em>,<br />
html: `<em>Hello ${name}</em>,<br />\nwelcome to our little community of pixelplacers, to use your account, you have to verify your mail. You can do that <a href="${verifyUrl}">here</a>. Or by copying following url:<br />${verifyUrl}\n<br />\nHave fun and don&#39;t hesitate to contact us if you encouter any problems :)<br />\nThanks<br /><br />\n<img alt="" src="https://assets.pixelplanet.fun/tile.png" style="height:64px; width:64px" />`, ${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 encouter any problems :)`}<br />
${t`Thanks`}<br /><br />
<img alt="" src="https://assets.pixelplanet.fun/tile.png" style="height:64px; width:64px" />`,
}, (err) => { }, (err) => {
if (err) { if (err) {
logger.error(err); logger.error(err);
@ -83,15 +87,15 @@ class MailProvider {
return null; return null;
} }
async sendPasswdResetMail(to, ip, host) { async sendPasswdResetMail(to, ip, host, lang) {
const { t } = getTTag(lang);
const pastMail = this.verifyCodes[to]; const pastMail = this.verifyCodes[to];
if (pastMail) { if (pastMail) {
if (Date.now() < pastMail.timestamp + 15 * MINUTE) { if (Date.now() < pastMail.timestamp + 15 * MINUTE) {
logger.info( logger.info(
`Password reset mail for ${to} requested by ${ip} - already sent`, `Password reset mail for ${to} requested by ${ip} - already sent`,
); );
// eslint-disable-next-line max-len return t`We already sent you a mail with instructions. Please wait before requesting another mail.`;
return 'We already sent you a mail with instructions. Please wait before requesting another mail.';
} }
} }
const reguser = await RegUser.findOne({ where: { email: to } }); const reguser = await RegUser.findOne({ where: { email: to } });
@ -99,7 +103,7 @@ class MailProvider {
logger.info( logger.info(
`Password reset mail for ${to} requested by ${ip} - mail not found`, `Password reset mail for ${to} requested by ${ip} - mail not found`,
); );
return "Couldn't find this mail in our database"; return t`Couldn't find this mail in our database`;
} }
/* /*
* not sure if this is needed yet * not sure if this is needed yet
@ -118,11 +122,12 @@ class MailProvider {
from, from,
to, to,
replyTo: 'donotreply@pixelplanet.fun', replyTo: 'donotreply@pixelplanet.fun',
subject: 'You forgot your password for PixelPlanet? Get a new one here', subject: t`You forgot your password for PixelPlanet? Get a new one here`,
// eslint-disable-next-line max-len
// text: `Hello,\nYou requested to get a new password. You can change your password within the next 30min here:\n ${restoreUrl} \nHave fun and don't hesitate to contact us if you encouter any problems :)\nIf you did not request this mail, please just ignore it (the ip that requested this mail was ${ip}).\nThanks`, // text: `Hello,\nYou requested to get a new password. You can change your password within the next 30min here:\n ${restoreUrl} \nHave fun and don't hesitate to contact us if you encouter any problems :)\nIf you did not request this mail, please just ignore it (the ip that requested this mail was ${ip}).\nThanks`,
// eslint-disable-next-line max-len html: `<em>${t`Hello`}</em>,<br />
html: `<em>Hello</em>,<br />\nYou requested to get a new password. You can change your password within the next 30min <a href="${restoreUrl}">here</a>. Or by copying following url:<br />${restoreUrl}\n<br />\nIf you did not request this mail, please just ignore it (the ip that requested this mail was ${ip}).<br />\nThanks<br /><br />\n<img alt="" src="https://assets.pixelplanet.fun/tile.png" style="height:64px; width:64px" />`, ${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`Thanks`}<br /><br />\n<img alt="" src="https://assets.pixelplanet.fun/tile.png" style="height:64px; width:64px" />`,
}, (err) => { }, (err) => {
if (err) { if (err) {
logger.error(err & err.stack); logger.error(err & err.stack);

View File

@ -4,6 +4,7 @@
*/ */
import { TTag } from 'ttag'; import { TTag } from 'ttag';
import deLocale from '../../i18n/ssr-de.po'; import deLocale from '../../i18n/ssr-de.po';
import { languageFromLocalisation } from '../utils/location';
const LOCALES = { const LOCALES = {
de: deLocale, de: deLocale,
@ -27,4 +28,11 @@ export function getTTag(lang) {
return ttags[lang] || ttags.default; return ttags[lang] || ttags.default;
} }
export function expressTTag(req, res, next) {
const language = req.headers['accept-language'];
req.lang = (language) ? languageFromLocalisation(language) : 'en';
req.ttag = getTTag(req.lang);
next();
}
export default ttags; export default ttags;

View File

@ -11,10 +11,10 @@ import { validatePassword, validateEMail } from '../../../utils/validation';
import { getHostFromRequest } from '../../../utils/ip'; import { getHostFromRequest } from '../../../utils/ip';
import { compareToHash } from '../../../utils/hash'; import { compareToHash } from '../../../utils/hash';
function validate(email, password) { function validate(email, password, gettext) {
const errors = []; const errors = [];
const passerror = validatePassword(password); const passerror = gettext(validatePassword(password));
if (passerror) errors.push(passerror); if (passerror) errors.push(passerror);
const mailerror = validateEMail(email); const mailerror = validateEMail(email);
if (mailerror) errors.push(mailerror); if (mailerror) errors.push(mailerror);
@ -24,7 +24,8 @@ function validate(email, password) {
export default async (req: Request, res: Response) => { export default async (req: Request, res: Response) => {
const { email, password } = req.body; const { email, password } = req.body;
const errors = validate(email, password); const { t, gettext } = req.ttag;
const errors = validate(email, password, gettext);
if (errors.length > 0) { if (errors.length > 0) {
res.status(400); res.status(400);
res.json({ res.json({
@ -33,11 +34,11 @@ export default async (req: Request, res: Response) => {
return; return;
} }
const { user } = req; const { user, lang } = req;
if (!user) { if (!user) {
res.status(401); res.status(401);
res.json({ res.json({
errors: ['You are not authenticated.'], errors: [t`You are not authenticated.`],
}); });
return; return;
} }
@ -46,7 +47,7 @@ export default async (req: Request, res: Response) => {
if (!compareToHash(password, currentPassword)) { if (!compareToHash(password, currentPassword)) {
res.status(400); res.status(400);
res.json({ res.json({
errors: ['Incorrect password!'], errors: [t`Incorrect password!`],
}); });
return; return;
} }
@ -57,7 +58,7 @@ export default async (req: Request, res: Response) => {
}); });
const host = getHostFromRequest(req); const host = getHostFromRequest(req);
mailProvider.sendVerifyMail(email, user.regUser.name, host); mailProvider.sendVerifyMail(email, user.regUser.name, host, lang);
res.json({ res.json({
success: true, success: true,

View File

@ -9,10 +9,10 @@ import type { Request, Response } from 'express';
import { validatePassword } from '../../../utils/validation'; import { validatePassword } from '../../../utils/validation';
import { compareToHash } from '../../../utils/hash'; import { compareToHash } from '../../../utils/hash';
function validate(newPassword) { function validate(newPassword, gettext) {
const errors = []; const errors = [];
const newpassworderror = validatePassword(newPassword); const newpassworderror = gettext(validatePassword(newPassword));
if (newpassworderror) errors.push(newpassworderror); if (newpassworderror) errors.push(newpassworderror);
return errors; return errors;
@ -20,7 +20,8 @@ function validate(newPassword) {
export default async (req: Request, res: Response) => { export default async (req: Request, res: Response) => {
const { newPassword, password } = req.body; const { newPassword, password } = req.body;
const errors = validate(newPassword); const { t, gettext } = req.ttag;
const errors = validate(newPassword, gettext);
if (errors.length > 0) { if (errors.length > 0) {
res.status(400); res.status(400);
res.json({ res.json({
@ -33,7 +34,7 @@ export default async (req: Request, res: Response) => {
if (!user) { if (!user) {
res.status(401); res.status(401);
res.json({ res.json({
errors: ['You are not authenticated.'], errors: [t`You are not authenticated.`],
}); });
return; return;
} }
@ -42,7 +43,7 @@ export default async (req: Request, res: Response) => {
if (currentPassword && !compareToHash(password, currentPassword)) { if (currentPassword && !compareToHash(password, currentPassword)) {
res.status(400); res.status(400);
res.json({ res.json({
errors: ['Incorrect password!'], errors: [t`Incorrect password!`],
}); });
return; return;
} }

View File

@ -10,10 +10,10 @@ import { RegUser } from '../../../data/models';
import { validatePassword } from '../../../utils/validation'; import { validatePassword } from '../../../utils/validation';
import { compareToHash } from '../../../utils/hash'; import { compareToHash } from '../../../utils/hash';
function validate(password) { function validate(password, gettext) {
const errors = []; const errors = [];
const passworderror = validatePassword(password); const passworderror = gettext(validatePassword(password));
if (passworderror) errors.push(passworderror); if (passworderror) errors.push(passworderror);
return errors; return errors;
@ -21,7 +21,8 @@ function validate(password) {
export default async (req: Request, res: Response) => { export default async (req: Request, res: Response) => {
const { password } = req.body; const { password } = req.body;
const errors = await validate(password); const { t, gettext } = req.ttag;
const errors = await validate(password, gettext);
if (errors.length > 0) { if (errors.length > 0) {
res.status(400); res.status(400);
res.json({ res.json({
@ -34,7 +35,7 @@ export default async (req: Request, res: Response) => {
if (!user) { if (!user) {
res.status(401); res.status(401);
res.json({ res.json({
errors: ['You are not authenticated.'], errors: [t`You are not authenticated.`],
}); });
return; return;
} }
@ -44,7 +45,7 @@ export default async (req: Request, res: Response) => {
if (!currentPassword || !compareToHash(password, currentPassword)) { if (!currentPassword || !compareToHash(password, currentPassword)) {
res.status(400); res.status(400);
res.json({ res.json({
errors: ['Incorrect password!'], errors: [t`Incorrect password!`],
}); });
return; return;
} }

View File

@ -156,7 +156,7 @@ export default (passport) => {
} }
user.ip = req.user.ip; user.ip = req.user.ip;
const me = await getMe(user); const me = await getMe(user, req.lang);
res.json({ res.json({
success: true, success: true,
me, me,

View File

@ -18,13 +18,13 @@ import {
validatePassword, validatePassword,
} from '../../../utils/validation'; } from '../../../utils/validation';
async function validate(email, name, password) { async function validate(email, name, password, gettext) {
const errors = []; const errors = [];
const emailerror = validateEMail(email); const emailerror = validateEMail(email);
if (emailerror) errors.push(emailerror); if (emailerror) errors.push(emailerror);
const nameerror = validateName(name); const nameerror = validateName(name);
if (nameerror) errors.push(nameerror); if (nameerror) errors.push(nameerror);
const passworderror = validatePassword(password); const passworderror = gettext(validatePassword(password));
if (passworderror) errors.push(passworderror); if (passworderror) errors.push(passworderror);
let reguser = await RegUser.findOne({ where: { email } }); let reguser = await RegUser.findOne({ where: { email } });
@ -37,7 +37,8 @@ async function validate(email, name, password) {
export default async (req: Request, res: Response) => { export default async (req: Request, res: Response) => {
const { email, name, password } = req.body; const { email, name, password } = req.body;
const errors = await validate(email, name, password); const { t, gettext } = req.ttag;
const errors = await validate(email, name, password, gettext);
if (errors.length > 0) { if (errors.length > 0) {
res.status(400); res.status(400);
res.json({ res.json({
@ -57,7 +58,7 @@ export default async (req: Request, res: Response) => {
if (!newuser) { if (!newuser) {
res.status(500); res.status(500);
res.json({ res.json({
errors: ['Failed to create new user :('], errors: [t`Failed to create new user :(`],
}); });
return; return;
} }
@ -65,20 +66,20 @@ export default async (req: Request, res: Response) => {
const ip = getIPFromRequest(req); const ip = getIPFromRequest(req);
logger.info(`Created new user ${name} ${email} ${ip}`); logger.info(`Created new user ${name} ${email} ${ip}`);
const { user } = req; const { user, lang } = req;
user.setRegUser(newuser); user.setRegUser(newuser);
const me = await getMe(user); const me = await getMe(user, lang);
await req.logIn(user, (err) => { await req.logIn(user, (err) => {
if (err) { if (err) {
res.status(500); res.status(500);
res.json({ res.json({
errors: ['Failed to establish session after register :('], errors: [t`Failed to establish session after register :(`],
}); });
return; return;
} }
const host = getHostFromRequest(req); const host = getHostFromRequest(req);
mailProvider.sendVerifyMail(email, name, host); mailProvider.sendVerifyMail(email, name, host, lang);
res.status(200); res.status(200);
res.json({ res.json({
success: true, success: true,

View File

@ -10,7 +10,7 @@ import mailProvider from '../../../core/mail';
import { getHostFromRequest } from '../../../utils/ip'; import { getHostFromRequest } from '../../../utils/ip';
export default async (req: Request, res: Response) => { export default async (req: Request, res: Response) => {
const { user } = req; const { user, lang } = req;
if (!user) { if (!user) {
res.status(401); res.status(401);
res.json({ res.json({
@ -30,7 +30,7 @@ export default async (req: Request, res: Response) => {
const host = getHostFromRequest(req); const host = getHostFromRequest(req);
const error = mailProvider.sendVerifyMail(email, name, host); const error = mailProvider.sendVerifyMail(email, name, host, lang);
if (error) { if (error) {
res.status(400); res.status(400);
res.json({ res.json({

View File

@ -31,7 +31,8 @@ export default async (req: Request, res: Response) => {
return; return;
} }
const host = getHostFromRequest(req); const host = getHostFromRequest(req);
const error = await mailProvider.sendPasswdResetMail(email, ip, host); const { lang } = req;
const error = await mailProvider.sendPasswdResetMail(email, ip, host, lang);
if (error) { if (error) {
res.status(400); res.status(400);
res.json({ res.json({

View File

@ -7,6 +7,7 @@ import bodyParser from 'body-parser';
import session from '../../core/session'; import session from '../../core/session';
import passport from '../../core/passport'; import passport from '../../core/passport';
import { expressTTag } from '../../core/ttag';
import logger from '../../core/logger'; import logger from '../../core/logger';
import User from '../../data/models/User'; import User from '../../data/models/User';
import { getIPFromRequest } from '../../utils/ip'; import { getIPFromRequest } from '../../utils/ip';
@ -78,8 +79,6 @@ router.use((req, res, next) => {
next(); next();
}); });
router.get('/me', me);
router.post('/mctp', mctp); router.post('/mctp', mctp);
router.get('/chathistory', chatHistory); router.get('/chathistory', chatHistory);
@ -92,6 +91,10 @@ router.post('/block', block);
router.post('/blockdm', blockdm); router.post('/blockdm', blockdm);
router.use(expressTTag);
router.get('/me', me);
router.use('/auth', auth(passport)); router.use('/auth', auth(passport));
export default router; export default router;

View File

@ -14,8 +14,8 @@ import { cheapDetector } from '../../core/isProxy';
export default async (req: Request, res: Response) => { export default async (req: Request, res: Response) => {
const { user } = req; const { user, lang } = req;
const userdata = await getMe(user); const userdata = await getMe(user, lang);
user.updateLogInTimestamp(); user.updateLogInTimestamp();
const { trueIp: ip } = req; const { trueIp: ip } = req;

View File

@ -13,6 +13,7 @@ import type { Request, Response } from 'express';
import redis from '../data/redis'; import redis from '../data/redis';
import logger from '../core/logger'; import logger from '../core/logger';
import getPasswordResetHtml from '../ssr-components/PasswordReset'; import getPasswordResetHtml from '../ssr-components/PasswordReset';
import { expressTTag } from '../core/ttag';
import { MINUTE } from '../core/constants'; import { MINUTE } from '../core/constants';
import mailProvider from '../core/mail'; import mailProvider from '../core/mail';
@ -41,17 +42,25 @@ router.use('/',
router.use(bodyParser.urlencoded({ extended: true })); router.use(bodyParser.urlencoded({ extended: true }));
/*
* use translation
*/
router.use(expressTTag);
/* /*
* Check for POST parameters, * Check for POST parameters,
* if invalid password is given, ignore it and go to next * if invalid password is given, ignore it and go to next
*/ */
router.post('/', async (req: Request, res: Response) => { router.post('/', async (req: Request, res: Response) => {
const { pass, passconf, code } = req.body; const { pass, passconf, code } = req.body;
const { t } = req.ttag;
if (!pass || !passconf || !code) { if (!pass || !passconf || !code) {
const html = getPasswordResetHtml( const html = getPasswordResetHtml(
null, null,
null, null,
'You sent an empty password or invalid data :(', t`You sent an empty password or invalid data :(`,
); );
res.status(400).send(html); res.status(400).send(html);
return; return;
@ -62,7 +71,7 @@ router.post('/', async (req: Request, res: Response) => {
const html = getPasswordResetHtml( const html = getPasswordResetHtml(
null, null,
null, null,
"This password-reset link isn't valid anymore :(", t`This password-reset link isn't valid anymore :(`,
); );
res.status(401).send(html); res.status(401).send(html);
return; return;
@ -72,7 +81,7 @@ router.post('/', async (req: Request, res: Response) => {
const html = getPasswordResetHtml( const html = getPasswordResetHtml(
null, null,
null, null,
'Your passwords do not match :(', t`Your passwords do not match :(`,
); );
res.status(400).send(html); res.status(400).send(html);
return; return;
@ -86,7 +95,7 @@ router.post('/', async (req: Request, res: Response) => {
const html = getPasswordResetHtml( const html = getPasswordResetHtml(
null, null,
null, null,
"User doesn't exist in our database :(", t`User doesn't exist in our database :(`,
); );
res.status(400).send(html); res.status(400).send(html);
return; return;
@ -97,7 +106,7 @@ router.post('/', async (req: Request, res: Response) => {
const html = getPasswordResetHtml( const html = getPasswordResetHtml(
null, null,
null, null,
'Passowrd successfully changed.', t`Passowrd successfully changed.`,
); );
res.status(200).send(html); res.status(200).send(html);
}); });
@ -108,11 +117,13 @@ router.post('/', async (req: Request, res: Response) => {
*/ */
router.get('/', async (req: Request, res: Response) => { router.get('/', async (req: Request, res: Response) => {
const { token } = req.query; const { token } = req.query;
const { t } = req.ttag;
if (!token) { if (!token) {
const html = getPasswordResetHtml( const html = getPasswordResetHtml(
null, null,
null, null,
'Invalid url :( Please check your mail again.', t`Invalid url :( Please check your mail again.`,
); );
res.status(400).send(html); res.status(400).send(html);
return; return;
@ -124,7 +135,7 @@ router.get('/', async (req: Request, res: Response) => {
null, null,
null, null,
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
'This passwort reset link is wrong or already expired, please request a new one (Note: you can use those links just once)', t`This passwort reset link is wrong or already expired, please request a new one (Note: you can use those links just once)`,
); );
res.status(401).send(html); res.status(401).send(html);
return; return;

View File

@ -1,34 +1,42 @@
/* /*
* functionf for validation of user input * Functions for validation of user input
* This gets used on server and on the client.
*
* On the server the return values will be again translated with gettext
* which could be a bit questionable, but it is preferable to write this file
* two times imho.
*
* @flow * @flow
*/ */
import { t } from 'ttag/dist/mock';
// eslint-disable-next-line no-useless-escape, max-len // eslint-disable-next-line no-useless-escape, max-len
const mailTester = /^[-!#$%&'*+\/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/; const mailTester = /^[-!#$%&'*+\/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;
export function validateEMail(email) { export function validateEMail(email) {
if (!email) return "Email can't be empty."; if (!email) return t`Email can't be empty.`;
if (email.length < 5) return 'Email should be at least 5 characters long.'; if (email.length < 5) return t`Email should be at least 5 characters long.`;
if (email.length > 40) return "Email can't be longer than 40 characters."; if (email.length > 40) return t`Email can't be longer than 40 characters.`;
if (email.indexOf('.') === -1) return 'Email should at least contain a dot'; if (email.indexOf('.') === -1) return t`Email should at least contain a dot`;
if (email.split('').filter((x) => x === '@').length !== 1) { if (email.split('').filter((x) => x === '@').length !== 1) {
return 'Email should contain a @'; return t`Email should contain a @`;
} }
if (!mailTester.test(email)) return 'Your Email looks shady'; if (!mailTester.test(email)) return 'Your Email looks shady';
return false; return false;
} }
export function validateName(name) { export function validateName(name) {
if (!name) return "Name can't be empty."; if (!name) return t`Name can't be empty.`;
if (name.length < 4) return 'Name must be at least 4 characters long'; if (name.length < 4) return t`Name must be at least 4 characters long`;
if (name.length > 26) return 'Name must be shorter than 26 characters'; if (name.length > 26) return t`Name must be shorter than 26 characters`;
if (name.indexOf('@') !== -1 if (name.indexOf('@') !== -1
|| name.indexOf('/') !== -1 || name.indexOf('/') !== -1
|| name.indexOf('\\') !== -1 || name.indexOf('\\') !== -1
|| name.indexOf('>') !== -1 || name.indexOf('>') !== -1
|| name.indexOf('<') !== -1 || name.indexOf('<') !== -1
|| name.indexOf('#') !== -1) { || name.indexOf('#') !== -1) {
return 'Name contains invalid character like @, /, \\ or #'; return t`Name contains invalid character like @, /, \\ or #`;
} }
return false; return false;
} }
@ -42,11 +50,14 @@ export function sanitizeName(name) {
} }
export function validatePassword(password) { export function validatePassword(password) {
if (!password) {
return t`No password given.`;
}
if (password.length < 6) { if (password.length < 6) {
return 'Password must be at least 6 characters long.'; return t`Password must be at least 6 characters long.`;
} }
if (password.length > 60) { if (password.length > 60) {
return 'Password must be shorter than 60 characters.'; return t`Password must be shorter than 60 characters.`;
} }
return false; return false;
} }
@ -60,13 +71,13 @@ export async function parseAPIresponse(response) {
const resp = await response.json(); const resp = await response.json();
if (!response.ok && !resp.errors) { if (!response.ok && !resp.errors) {
return { return {
errors: ['Could not connect to server, please try again later :('], errors: [t`Could not connect to server, please try again later :(`],
}; };
} }
return resp; return resp;
} catch (e) { } catch (e) {
return { return {
errors: ['I think we experienced some error :('], errors: [t`I think we experienced some error :(`],
}; };
} }
} }

View File

@ -55,7 +55,7 @@ const babelPlugins = [
extract: { extract: {
output: path.resolve(__dirname, 'i18n', 'template-ssr.pot'), output: path.resolve(__dirname, 'i18n', 'template-ssr.pot'),
}, },
discover: ['t', 'jt', 'gettext'], discover: ['t', 'jt'],
}], }],
]; ];