diff --git a/.vscode/launch.json b/.vscode/launch.json index 156b175..030faa4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,11 +4,26 @@ { "type": "node", "request": "launch", - "name": "Nodemon", + "name": "Launch debug", "runtimeExecutable": "${workspaceFolder}/node_modules/nodemon/bin/nodemon.js", "skipFiles": ["/**"], "program": "${workspaceFolder}/spacedeck.js", - "cwd": "${workspaceFolder}" + "cwd": "${workspaceFolder}", + "env": { + "NODE_APP_INSTANCE" :"dev" + } + }, + { + "type": "node", + "request": "launch", + "name": "Launch ldap", + "runtimeExecutable": "${workspaceFolder}/node_modules/nodemon/bin/nodemon.js", + "skipFiles": ["/**"], + "program": "${workspaceFolder}/spacedeck.js", + "cwd": "${workspaceFolder}", + "env": { + "NODE_APP_INSTANCE" :"ldap" + } } ] } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c7d5f2b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +## [X.X.X] - 2021-03-23 + +### Changes + +- Replaced phantomjs with puppeteer #169 +- Create Hungarian language pack #174 diff --git a/Dockerfile b/Dockerfile index 2c486ff..4893a0c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,20 @@ RUN cd audiowaveform/build/ && cmake -D ENABLE_TESTS=0 -D BUILD_STATIC=1 .. RUN cd audiowaveform/build/ && make RUN cd audiowaveform/build/ && make install +# install chromium +RUN apk add --no-cache \ + chromium \ + nss \ + freetype \ + freetype-dev \ + harfbuzz \ + ca-certificates \ + ttf-freefont + +# Tell Puppeteer to skip installing Chrome. We'll be using the installed package. +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ + PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser + # install other requirements RUN apk add graphicsmagick ffmpeg ffmpeg-dev ghostscript diff --git a/README.md b/README.md index c8f46cf..4578be3 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ We appreciate filed issues, pull requests and general discussion. # Features -- Create virtual whiteboards called *Spaces* with virtually unlimited size +- Create virtual whiteboards called _Spaces_ with virtually unlimited size - Drag & drop images, videos and audio from your computer or the web - Write and format text with full control over fonts, colors and style - Draw, annotate and highlight with included graphical shapes @@ -37,7 +37,7 @@ Spacedeck requires: To run Spacedeck, you only need Node.JS 10.x. -To install all node dependencies, run (do this once): +To install all node dependencies, run (do this once) after cloning the repository: npm install @@ -45,7 +45,6 @@ To install all node dependencies, run (do this once): See [config/default.json](config/default.json). Set `storage_local_path` for a local sqlite database or `storage_region`, `storage_bucket`, `storage_cdn` and `storage_endpoint` for AWS S3. `mail_provider` may be one of `console` or `smtp`. Also, omit a trailing `/` for the `endpoint`. - ## Disable DB logs ```json @@ -61,7 +60,8 @@ Add a custom array of swatches to your config/default.json. **You should include the swatch transparent (rgba(0,0,0,0)) so users can remove the color applied.** ## Configure default colors -You can define text, stroke and fill color in your config/default.json. + +You can define text, stroke and fill color in your config/default.json. **You also should include the default colors in your custom swatches palette.** @@ -107,8 +107,8 @@ For advanced media conversion: # Data Storage -By default, media files are uploaded to the ```storage``` folder. -The database is stored in ```database.sqlite``` by default. +By default, media files are uploaded to the `storage` folder. +The database is stored in `database.sqlite` by default. # Other databases (Not officially supported) @@ -129,16 +129,12 @@ Adapt the other values as needed "storage_password": "password", ``` - # Run with Docker - configure `config/default.json` -- configure `volumes` section inside `docker-compose.yml` - - point to `database.sqlite` on the host system - - `touch database.sqlite` if it not exists - - point to `storage/` on the host system - - `mkdir storage/` if it not exists -- start the container with `sudo docker-compose up -f docker-compose.yml -d --build` +- adapt your `docker-compose.yml` if needed. +- start the container with `docker-compose up` + (use `-d` for background process and `--build` for rebuilding the image) # Hacking @@ -155,7 +151,7 @@ Spacedeck Open source code is released under the GNU Affero General Public Licen Spacedeck Open - Web-based Collaborative Whiteboard For Rich Media Copyright (C) 2011-2018 Lukas F. Hartmann, Martin Güther Icons and original CSS design copyright by Thomas Helbig - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the diff --git a/config/default.json b/config/default.json index d47d223..db52b31 100644 --- a/config/default.json +++ b/config/default.json @@ -25,7 +25,7 @@ "redis_mock": true, "redis_host": "localhost", - "phantom_api_secret": "very_secret_phantom_password", + "export_api_secret": "very_secret_export_password", "mail_provider": "smtp", "mail_smtp_host": "your.smtp.host", diff --git a/docker-compose.yml b/docker-compose.yml index 4823997..8835b96 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,4 @@ version: "2.0" - services: spacedeck: build: . @@ -7,6 +6,5 @@ services: ports: - "9666:9666" volumes: - - /absolute/path/to/storage:/app/storage - - /absolute/path/to/database.sqlite:/app/database.sqlite - + - ./storage:/app/storage + - ./database.sqlite:/app/database.sqlite diff --git a/docs/nginx_setup.md b/docs/nginx_setup.md index 5ce36e2..1f8d4c4 100644 --- a/docs/nginx_setup.md +++ b/docs/nginx_setup.md @@ -12,7 +12,7 @@ server { listen 80; listen [::]:80; - servername spacedeck.domain.de + server_name spacedeck.domain.de return 301 https://$server_name$request_uri; } diff --git a/helpers/exporter.js b/helpers/exporter.js new file mode 100644 index 0000000..8f923f4 --- /dev/null +++ b/helpers/exporter.js @@ -0,0 +1,58 @@ +'use strict'; + +const db = require('../models/db'); +const config = require('config'); +const puppeteer = require('puppeteer'); +const os = require('os'); + +module.exports = { + // type = "pdf" or "png" + takeScreenshot: function(space,type,on_success,on_error) { + var spaceId = space._id; + var space_url = config.get("endpoint")+"/api/spaces/"+spaceId+"/html"; + + var export_path = os.tmpdir()+"/"+spaceId+"."+type; + + var timeout = 5000; + if (type=="pdf") timeout = 30000; + + space_url += "?api_token="+config.get("export_api_secret"); + + console.log("[space-screenshot] url: "+space_url); + console.log("[space-screenshot] export_path: "+export_path); + + (async () => { + let browser; + let page; + try { + browser = await puppeteer.launch( + { + headless: true, + args: ['--disable-dev-shm-usage', '--no-sandbox'] + } + ); + page = await browser.newPage(); + + page.setDefaultTimeout(timeout); + await page.setJavaScriptEnabled(false); + await page.goto(space_url, {waitUntil: 'networkidle2'}); + await page.emulateMediaType('screen'); + + if (type=="pdf") { + let margin = 2; + await page.pdf({path: export_path, printBackground: true, width: space.width+margin+'px', height: space.height+margin+'px' }); + }else{ + await page.screenshot({path: export_path, printBackground: true}); + } + + await browser.close(); + on_success(export_path); + } catch (error) { + console.error(error); + console.error("[space-screenshot] puppeteer abnormal exit for url "+space_url); + on_error(); + } + + })(); + } +}; diff --git a/helpers/phantom.js b/helpers/phantom.js deleted file mode 100644 index 197b9a2..0000000 --- a/helpers/phantom.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -const db = require('../models/db'); -const config = require('config'); -const phantom = require('node-phantom-simple'); -const os = require('os'); - -module.exports = { - // type = "pdf" or "png" - takeScreenshot: function(space,type,on_success,on_error) { - var spaceId = space._id; - var space_url = config.get("endpoint")+"/api/spaces/"+spaceId+"/html"; - - var export_path = os.tmpdir()+"/"+spaceId+"."+type; - - var timeout = 5000; - if (type=="pdf") timeout = 30000; - - space_url += "?api_token="+config.get("phantom_api_secret"); - - console.log("[space-screenshot] url: "+space_url); - console.log("[space-screenshot] export_path: "+export_path); - - var on_success_called = false; - - var on_exit = function(exit_code) { - if (exit_code>0) { - console.error("phantom abnormal exit for url "+space_url); - if (!on_success_called && on_error) { - on_error(); - } - } - }; - - phantom.create({ path: require('phantomjs-prebuilt').path }, function (err, browser) { - if (err) { - console.error(err); - } else { - return browser.createPage(function (err, page) { - console.log("page created, opening ",space_url); - - if (type=="pdf") { - var psz = { - width: space.width+"px", - height: space.height+"px" - }; - page.set('paperSize', psz); - } - - page.set('settings.resourceTimeout',timeout); - page.set('settings.javascriptEnabled',false); - - return page.open(space_url, function (err,status) { - page.render(export_path, function() { - on_success_called = true; - if (on_success) { - on_success(export_path); - } - page.close(); - browser.exit(); - }); - }); - }); - } - - }, { - onExit: on_exit - }); - } -}; diff --git a/locales/de.js b/locales/de.js index b41e542..fe0a36f 100644 --- a/locales/de.js +++ b/locales/de.js @@ -320,5 +320,6 @@ "follow_present": "Folgen", "mute_present": "Entfolgen", "follow_present_help": "Wenn jemand den Space präsentiert, folgen die anderen Mitglieder automatisch der Präsentation. Mit diesem Knopf lässt sich das an- oder ausschalten.", - "media": "Media" -} + "media": "Media", + "tool_edit_text": "Text bearbeiten" +} \ No newline at end of file diff --git a/locales/hu.js b/locales/hu.js new file mode 100644 index 0000000..0cb2986 --- /dev/null +++ b/locales/hu.js @@ -0,0 +1,328 @@ +{ + "ok": "Rendben", + "cancel": "Mégse", + "close": "Bezárás", + "open": "Megnyitás", + "folder": "Mappa", + "save": "Mentés", + "saved": "Mentve", + "created": "létrehozva", + "duplicate": "Másolás", + "delete": "Törlés", + "remove": "Eltávolítás", + "set": "készlet", + "reset": "alaphelyzet", + "thanks": "Köszönöm", + "share": "Megosztás", + "signup": "Feliratkozás", + "login": "Bejelentkezés", + "logout": "Kijelentkezés", + "email": "E-mail-cím", + "password": "Jelszó", + "width": "Szélesség", + "height": "Magasság", + "nick": "Név", + "role": "Szerepkör", + "members": "Tagok", + "actions": "Műveletek", + "or": "vagy", + "you": "Ön", + "via": "ezen keresztül:", + "by": "szerző:", + "zero": "Nulla", + "page": "Oldal:", + "new": "Új", + "copy": "Másolás", + "home": "Kezdőoldal", + "owner": "Tulajdonos", + "space": "Hely", + "second": "másodperc", + "not_found": "Nem található.", + "untitled_space": "Névtelen hely", + "untitled_folder": "Névtelen mappa", + "untitled": "névtelen", + "sure": "Biztos vagy benne?", + "specify": "Kérjük, részletezze", + "confirm": "Erősítse meg a műveletet", + "error_unknown_email": "Ez az e-mail/jelszó kombináció ismeretlen.", + "error_password_confirmation": "A megadott jelszavak nem egyeznek.", + "error_domain_blocked": "Tartománya letiltva.", + "error_user_email_already_used": "Ez az e-mail cím már használatban van.", + "support": "Spacedeck támogatás", + "offline": "Kapcsolat nélküli üzemmód. Kattintson további információkért.", + "error": "Sajnálom, de valami rosszul ment. Kérjük, lépjen kapcsolatba a support@spacedeck.com-al", + "welcome": "Üdvözöljük", + "claim": "A digitális rajztáblája.", + "trynow": "Próbálja most.", + "about": "Rólunk", + "terms": "Feltételek", + "contact": "Kapcsolat", + "privacy": "Adatvédelem", + "business_adress": "Üzleti cím", + "post_adress": "Posta cím", + "phone": "Telefon", + "ceo": "Ügyvezető igazgató", + "name": "Név", + "confirm_subject": "Spacedeck e-mail megerősítés", + "confirm_body": "Köszönjük, hogy feliratkozott a Spacedeck-re.\nKérjük, hogy kattintson az alábbi linkre az e-mail cím megerősítéséhez.\n", + "confirm_action": "Erősítse meg most", + "team_invite_membership_subject": "Csapat meghívó %-s számára", + "team_invite_membership_body": "Meghívták a(z) %s oldalra a Spacedeck-en. Kattintson a következő hivatkozásra a meghívás elfogadásához.", + "team_invite_user_body": "Meghívták a(z)%s oldalra a Spacedeck-en.\nAz ideiglenes jelszó \"%s\".\n Kérjük, kattintson a következő hivatkozásra a meghívás elfogadásához.", + "team_invite_admin_body": "%s meghívást kapott a csapatodba: %s. Az ideiglenes jelszó \"%s\".", + "team_invite_membership_acction": "Elfogad", + "team_new_member_subject": "A(z) %s új csapattagja feliratkozott", + "team_new_member_body": "%s most csatlakozott a(z) %s csoporthoz a Spacedeck-en.", + "space_invite_membership_subject": "%s meghívott %s helyre", + "space_invite_membership_body": "%s meghívta, hogy csatlakozzon a(z) %s helyre a Spacedecken. Kattintson a következő linkre a meghívás elfogadásához.", + "space_invite_membership_action": "Elfogad", + "folder_invite_membership_subject": "Hely", + "folder_invite_membership_body": "Meghívták a Spacedeck csoportjába. Kérjük, hogy kattintson a következő linkre a meghívás elfogadásához.", + "folder_invite_membership_acction": "Elfogad", + "login_google": "Bejelentkezés a Google-al", + "save_changes": "Változtatások mentése", + "upgrade": "Frissítés", + "upgrade_now": "Frissítés most", + "create_space": "Hely létrehozása", + "create_folder": "Mappa létrehozása", + "email_unconfirmed": "E-mail nincs megerősítve", + "confirmation_sent": "E-mail elküldve", + "folder_filter": "Szűrő", + "sort_by": "Rendezés", + "last_modified": "Utoljára módosítva", + "last_opened": "Utoljára nyitva", + "title": "Cím", + "edit_team": "Csapat szerkesztése", + "edit_account": "Fiók szerkesztése", + "log_out": "Kijelentkezés", + "no_spaces_yet": "Isten hozta! Itt létrehozhat helyeket és mappákat a bal felső sarokban található gombokkal.", + "new_folder_title": "Új cím a mappához", + "folder_settings": "Mappa beállításai", + "upload_cover_image": "Borító kép feltöltése", + "spacedeck_pro_ad_folders": "A Spacedeck Pro segítségével korlátlan mennyiségű helyet foglalhat el a mappákban és kezelheti az egyes mappák hozzáférési vezérléseit. Szeretne többet megtudni a Pro funkcióiról?", + "spacedeck_pro_ad_versions": "A Spacedeck Pro segítségével korlátlan verziókat menthet az egyes helyekről, hogy nyomon kövesse az előrehaladást vagy biztonságban tartsa a pillanatképeket. Szeretne többet megtudni a Pro funkcióiról?", + "spacedeck_pro_ad_pdf": "A Spacedeck Pro segítségével a helyeket éles PDF-fájlokként exportálhatja archiváláshoz, postázáshoz vagy nyomtatáshoz. Szeretne többet megtudni a Pro funkcióiról?", + "spacedeck_pro_ad_zip": "A Spacedeck Pro segítségével exportálhatja a hely tartalmát ZIP-csomagként. Szeretne többet megtudni a Pro funkcióiról?", + "spacedeck_pro_ad_colors": "A Spacedeck Pro segítségével professzionális színválasztóval keverheti össze saját színeit.", + "profile_caption": "Profil", + "upload_avatar": "Avatar feltöltése", + "uploading_avatar": "Avatar feltöltése…", + "avatar_dimensions": "Ajánlott méretek: 200 × 200 képpont.", + "profile_name": "Név", + "profile_email": "E-mail cím", + "send_again": "Küldje újra", + "confirmation_sent_long": "E-mail megerősítő hivatkozáds elküldve.Kérjük, ellenőrizze a beérkező leveleket.", + "confirmation_sent_another": "Egy másik megerősítő link elküldve.", + "confirmation_sent_dialog_text": "E-mailt küldtünk Önnek, amelyben elmagyaráztuk, hogyan erősítse meg e-mail címét.", + "payment_caption": "Fizetés", + "language_caption": "Nyelv", + "notifications_caption": "Értesítések", + "notifications_option_chat": "E-mailben értesítsen az új megjegyzésekről", + "notifications_option_spaces": "Küldjön napi összefoglalót arról, hogy mi történt a helyeim és mappáim között", + "password_caption": "Jelszó", + "current_password": "Jelenlegi jelszó", + "new_password": "Új jelszó", + "verify_password": "Jelszó megerősítése", + "change_password": "Jelszó módosítása", + "reset_password": "Jelszó visszaállítása", + "terminate_caption": "Fiók törlése", + "terminate_warning": "Ha törli a fiókját, akkor az összes hely, mappa és üzenet, beleértve az Ön összes tartalmát és a helyeiben létrehozott más embereket megsemmisül.", + "terminate_warning2": "Ezt nem lehet visszavonni.", + "terminate_reason": "Üzenet", + "terminate_reason_caption": "Segítsen nekünk a fejlesztésben, ha megosztja a lemondás okait.", + "terminate_terminate": "Leállít", + "space_blank1": "Üdvözöljük egy friss, új helyen!", + "space_blank2": "Húzza ide a fájlokat, hivatkozások beillesztése", + "space_blank3": "vagy használja az alábbi eszközöket", + "space_blank4": "hogy ezt a helyet tartalommal töltse meg.", + "draft": "Piszkozat", + "publish": "Közzététel", + "published": "Közzétett", + "save_version": "Verzió mentése", + "version_saved": "Verzió mentve", + "post": "Üzenet küldése", + "chat_invite_cta1": "Az együttműködés szórakoztató!", + "chat_invite_cta2": "Miért ne", + "chat_invite_cta3": "hívjon meg néhány embert", + "chat_invite_cta4": "Önnel dolgozni?", + "chat_message_placeholder": "Írja meg az üzenetét…", + "view": "Nézet", + "edit": "Szerkesztés", + "present": "Jelen van", + "chat": "Csevegés", + "meta": "Meta", + "tool_search": "Keresés", + "tool_upload": "Feltöltés", + "tool_text": "Szöveg", + "tool_shape": "Forma", + "tool_zones": "Zónák", + "tool_canvas": "Vászon", + "search_media": "Keresés a médiában…", + "type_here": "Írja ide", + "text_formats": "Formátumok", + "format_p": "Bekezdés", + "format_bullets": "Listajeles lista", + "format_numbers": "Számozott lista", + "format_h1": "1. címsor", + "format_h2": "2. címsor", + "format_h3": "3. címsor", + "font_size": "Betűméret", + "line_height": "Sormagasság", + "tool_align": "Igazítás", + "tool_styles": "Stílusok", + "tool_bullets": "Felsorolás", + "tool_numbers": "Számok", + "tool_font": "Betűtípus", + "color_fill": "Kitöltés", + "color_stroke": "Vonás", + "color_text": "Szöveg", + "tool_type": "Típus", + "tool_box": "Doboz", + "tool_link": "Hivatkozás", + "tool_layout": "Elrendezés", + "tool_options": "Lehetőségek", + "tool_stroke": "Vonás ", + "tool_delete": "Törlés", + "tool_lock": "Lezár", + "tool_copy": "Másol", + "stack": "Halom", + "tool_circle": "Kör", + "tool_hexagon": "Hatszög", + "tool_square": "Négyzet", + "tool_diamond": "Gyémánt", + "tool_bubble": "Buborék", + "tool_cloud": "Felhő", + "tool_burst": "Sorozatfelvétel", + "tool_star": "Csillag", + "tool_heart": "Szív", + "tool_scribble": "Irkál", + "tool_line": "Vonal", + "tool_arrow": "Nyíl", + "search_media_placeholder": "Keresés az internetes médiában…", + "add_zone": "Új zóna", + "palette": "Paletta", + "picker": "Választó", + "background_image_caption": "Kép", + "background_color_caption": "Szín", + "upload_background_caption": "Kattintson egy háttérkép feltöltéséhez", + "upload_background": "Háttér feltöltése", + "access_caption": "Hozzáférés", + "versions_caption": "Verziók", + "info_caption": "Információ", + "mode_private": "Magán: Csak a tagok tekinthetik meg és szerkeszthetik", + "mode_public": "Nyilvános: A hivatkozás birtokában bárki megtekintheti", + "invite_collaborators": "Hívjon meg együttműködőket", + "revoke_access": "Hozzáférés visszavonása", + "invite": "Meghívók küldése", + "invitee_email_address": "Az új tag e-mail címe", + "optional_message": "Választható üzenet", + "role_viewer": "Néző", + "role_editor": "Szerkesztő", + "role_admin": "Adminisztrátor", + "new_space_title": "Új cím a helynek", + "team": "Csoport", + "search": "Keresés", + "search_no_results": "keresés_nincsenek_eredmények", + "search_clear": "keresés_törlés", + "rename": "Átnevezés", + "mobile": "mobil", + "image": "kép", + "tool_filter": "szűrő", + "canel": "mégse", + "invite_membership_action": "meghívni_tagságot", + "viewer": "néző", + "editor": "szerkesztő", + "admin": "adminisztrátor ", + "logging_in": "bejelentkezés", + "password_confirmation": "Jelszó megerősítése", + "confirm_again": "E-mailt küldtünk Önnek, amelyben elmagyaráztuk, hogyan erősítse meg e-mail címét.", + "confirmed": "Fiókját sikeresen megerősítettük. Köszönjük.", + "signing_up": "Feliratkozás", + "password_check_inbox": "Kérjük, ellenőrizze a beérkező leveleket", + "new_space": "Új hely", + "tool_more": "Több", + "what_is_your_name": "Üdvözöljük a %s oldalon! Kérjük, hogy válasszon egy felhasználónevet.", + "lang": "hu", + "landing_title": "Rajztáblája az interneten.", + "landing_claim": "A Spacedeck segítségével könnyedén kombinálhat mindenféle típusú médiát a virtuális rajztáblákon: szöveges jegyzeteket, fotókat, internetes linkeket, sőt videókat és hangfelvételeket.", + "landing_example": "Az emberek a Spacedeck segítségével szervezik ötleteiket, csoportokban, hogy egy pillantással teljes projekteket láthassanak vagy iskolákban és egyetemeken gazdagabb, összekapcsolt tanulási tapasztalatokkal.", + "spaces": "Saját helyek", + "access_editor_link": "Azonnali hivatkozás szerkesztése", + "access_editor_link_desc": "Adja meg ezt a hivatkozást mindenkinek, akinek képesnek kell lennie a hely azonnali szerkesztésére, nincs szükség fiókra:", + "access_editor_link_desc_slug": "Ez a hivatkozás tartalmazza a hely nevét is.", + "access_anonymous_edit_blocking": "Névtelen szerkesztők csak a saját tételeiket változtathatják meg", + "access_current_members": "Current Members", + "access_new_members": "Új tagok meghívása", + "access_no_members": "A Hely tagjai itt jelennek meg.", + "comments": "hozzászólások", + "landing_customers": "Ezrek bíznak benne.", + "landing_features_title": "Gyerekjáték használni.", + "landing_features_text": "Az új Spacedeck 5 korszerű, gyönyörű felhasználói felülettel rendelkezik, amely minden eddiginél könnyebbé és szórakoztatóbbá teszi munkáját - miközben még erőteljesebb funkciókat kínál:", + "landing_features_1": "Fogd és vidd képeket, videókat és hangokat a számítógépről vagy az internetről", + "landing_features_2": "Szöveg írása és formázása de a betűtípusok, a színek és a stílus teljes ellenőrzésével", + "landing_features_3": "Rajzoljon, kommentáljon és jelöljön ki a mellékelt grafikus alakzatokkal", + "landing_features_4": "Kapcsolja tábláját nagyító prezentációvá", + "landing_features_5": "Együttműködés és csevegés valós időben csoport társaival, diákjaival vagy barátaival. ", + "landing_features_6": "Helyek megosztása az interneten vagy e-mailben", + "landing_features_7": "Exportálja munkáját nyomtatható PDF vagy ZIP formátumban", + "landing_pricing": "Hihetetlenül megfizethető.", + "landing_pricing_lite": "Ingyenes/személyes használat", + "landing_pricing_lite_text": "Az alap, átfogó verzió a képek gyűjtésére és a jegyzetek vezetésére.", + "landing_pricing_pro_features_list": "