Merge branch 'release/1.8.5'
This commit is contained in:
commit
f3d950c664
208 changed files with 25420 additions and 9270 deletions
|
@ -1,4 +1,7 @@
|
|||
*~
|
||||
.dockerignore
|
||||
.hg
|
||||
Dockerfile
|
||||
|
||||
# Remove the git objects, logs, etc. to make final image smaller.
|
||||
# Some files still need to be in the .git directory, because Etherpad at
|
||||
|
|
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -1,12 +1,11 @@
|
|||
* * *
|
||||
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees:
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
* * *
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
@ -24,23 +23,16 @@ A clear and concise description of what you expected to happen.
|
|||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Environment (please complete the following information):**
|
||||
|
||||
- Etherpad Version: (e.g. 1.8.0)
|
||||
- Deployment (manual install, docker, ...)
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
|
||||
- OS: (e.g. iOS)
|
||||
- Browser (e.g. chrome, safari)
|
||||
- Version (e.g. 22)
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
|
||||
- Device: (e.g. iPhone6)
|
||||
- OS: (e.g. iOS8.1)
|
||||
- Browser (e.g. stock browser, safari)
|
||||
- Version (e.g. 22)
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
|
12
.github/ISSUE_TEMPLATE/feature_request.md
vendored
12
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
@ -1,3 +1,12 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: Feature Request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
* * *
|
||||
|
||||
name: Feature request
|
||||
|
@ -19,3 +28,6 @@ A clear and concise description of any alternative solutions or features you've
|
|||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
**Plugin?**
|
||||
Might this feature be better suited to being a plugin? Usually features that can be plugins, should be.
|
||||
|
|
30
.github/ISSUE_TEMPLATE/plugin-request-template.md
vendored
Normal file
30
.github/ISSUE_TEMPLATE/plugin-request-template.md
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
name: Plugin request template
|
||||
about: Suggest a plugin for Etherpad
|
||||
title: ''
|
||||
labels: Plugin Request
|
||||
assignees: JohnMcLear
|
||||
|
||||
---
|
||||
|
||||
* * *
|
||||
|
||||
name: Plugin request
|
||||
about: Suggest a plugin for this project
|
||||
title: ''
|
||||
labels: plugin request
|
||||
assignees:
|
||||
|
||||
* * *
|
||||
|
||||
**Is your plugin request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when (...)
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the plugin request here.
|
10
.github/ISSUE_TEMPLATE/security-issue.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/security-issue.md
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
name: Security issue
|
||||
about: Notify the Etherpad foundation of a Security issue
|
||||
title: ''
|
||||
labels: security
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please email contact@etherpad.org with details of the security issue prior to posting here.
|
13
.github/ISSUE_TEMPLATE/security.md
vendored
Normal file
13
.github/ISSUE_TEMPLATE/security.md
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
* * *
|
||||
|
||||
name: Security notification
|
||||
about: Disclose a security issue in Etherpad
|
||||
title: ''
|
||||
labels: security
|
||||
assignees:
|
||||
|
||||
* * *
|
||||
|
||||
**Our Security disclosure process**
|
||||
1. Please email contact@etherpad.org with detials of the exploit including steps to replicate.
|
||||
1. Once confirmed we will provide a confirmation, patch and CVE details.
|
23
.github/stale.yml
vendored
Normal file
23
.github/stale.yml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
- Bug
|
||||
- Serious Bug
|
||||
- Minor bug
|
||||
- Black hole bug
|
||||
- Special case Bug
|
||||
- Upstream bug
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: wontfix
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
54
.github/workflows/codeql-analysis.yml
vendored
Normal file
54
.github/workflows/codeql-analysis.yml
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop, master]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [develop]
|
||||
schedule:
|
||||
- cron: '0 13 * * 1'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
# languages: go, javascript, csharp, python, cpp, java
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
46
.travis.yml
46
.travis.yml
|
@ -6,13 +6,17 @@ node_js:
|
|||
services:
|
||||
- docker
|
||||
|
||||
cache: false
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:libreoffice/ppa
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y install libreoffice
|
||||
- sudo apt-get -y install libreoffice-pdfimport
|
||||
|
||||
install:
|
||||
- "bin/installDeps.sh"
|
||||
- "export GIT_HASH=$(git rev-parse --verify --short HEAD)"
|
||||
- "npm install ep_test_line_attrib"
|
||||
|
||||
before_script:
|
||||
- "tests/frontend/travis/sauce_tunnel.sh"
|
||||
|
||||
script:
|
||||
- "tests/frontend/travis/runner.sh"
|
||||
|
@ -24,25 +28,39 @@ env:
|
|||
|
||||
jobs:
|
||||
include:
|
||||
# we can only frontend tests from the ether/ organization and not from forks.
|
||||
# To request tests to be run ask a maintainer to fork your repo to ether/
|
||||
- if: fork = false
|
||||
name: "Test the Frontend"
|
||||
install:
|
||||
#FIXME
|
||||
- "sed 's/\"loglevel\": \"INFO\",/\"loglevel\": \"WARN\",/g' settings.json.template > settings.json"
|
||||
- "tests/frontend/travis/sauce_tunnel.sh"
|
||||
- "bin/installDeps.sh"
|
||||
- "export GIT_HASH=$(git rev-parse --verify --short HEAD)"
|
||||
script:
|
||||
- "tests/frontend/travis/runner.sh"
|
||||
- name: "Run the Backend tests"
|
||||
install:
|
||||
- "bin/installDeps.sh"
|
||||
- "cd src && npm install && cd -"
|
||||
script:
|
||||
- "tests/frontend/travis/runnerBackend.sh"
|
||||
- name: "Test the Frontend"
|
||||
## Temporarily commented out the Dockerfile tests
|
||||
# - name: "Test the Dockerfile"
|
||||
# install:
|
||||
# - "cd src && npm install && cd -"
|
||||
# script:
|
||||
# - "docker build -t etherpad:test ."
|
||||
# - "docker run -d -p 9001:9001 etherpad:test && sleep 3"
|
||||
# - "cd src && npm run test-container"
|
||||
- name: "Load test Etherpad"
|
||||
install:
|
||||
- "bin/installDeps.sh"
|
||||
- "export GIT_HASH=$(git rev-parse --verify --short HEAD)"
|
||||
- "npm install ep_test_line_attrib"
|
||||
script:
|
||||
- "tests/frontend/travis/runner.sh"
|
||||
- name: "Test the Dockerfile"
|
||||
install:
|
||||
- "cd src && npm install && cd -"
|
||||
- "npm install -g etherpad-load-test"
|
||||
script:
|
||||
- "docker build -t etherpad:test ."
|
||||
- "docker run -d -p 9001:9001 etherpad:test && sleep 3"
|
||||
- "cd src && npm run test-container"
|
||||
- "tests/frontend/travis/runnerLoadTest.sh"
|
||||
|
||||
notifications:
|
||||
irc:
|
||||
|
|
44
CHANGELOG.md
44
CHANGELOG.md
|
@ -1,3 +1,47 @@
|
|||
# Develop -- TODO Change to 1.8.x.
|
||||
* ...
|
||||
|
||||
# 1.8.5
|
||||
* IMPORTANT DROP OF SUPPORT: Drop support for IE. Browsers now need async/await.
|
||||
* IMPORTANT SECURITY: Rate limit Commits when env=production
|
||||
* SECURITY: Non completed uploads no longer crash Etherpad
|
||||
* SECURITY: Log authentication requests
|
||||
* FEATURE: Support ES6 (migrate from Uglify-JS to Terser)
|
||||
* FEATURE: Improve support for non-cookie enabled browsers
|
||||
* FEATURE: New hooks for ``index.html``
|
||||
* FEATURE: New script to delete sessions.
|
||||
* FEATURE: New setting to allow import withing an author session on a pad
|
||||
* FEATURE: Checks Etherpad version on startup and notifies if update is available. Also available in ``/admin`` interface.
|
||||
* FEATURE: Timeslider updates pad location to most recent edit
|
||||
* MINOR: Outdent UL/LI items on removal of list item
|
||||
* MINOR: Various UL/LI import/export bugs
|
||||
* MINOR: PDF export fix
|
||||
* MINOR: Front end tests no longer run (and subsequently error) on pull requests
|
||||
* MINOR: Fix issue with </li> closing a list before it opens
|
||||
* MINOR: Fix bug where large pads would fire a console error in timeslider
|
||||
* MINOR: Fix ?showChat URL param issue
|
||||
* MINOR: Issue where timeslider URI fails to be correct if padID is numeric
|
||||
* MINOR: Include prompt for clear authorship when entire document is selected
|
||||
* MINOR: Include full document aText every 100 revisions to make pad restoration on database curruption achievable
|
||||
* MINOR: Several Colibris CSS fixes
|
||||
* MINOR: Use mime library for mime types instead of hard-coded.
|
||||
* MINOR: Don't show "new pad button" if instance is read only
|
||||
* MINOR: Use latest NodeJS when doing Windows build
|
||||
* MINOR: Change disconnect logic to reconnect instead of silently failing
|
||||
* MINOR: Update SocketIO, async, jQuery and Mocha which were stuck due to stale code.
|
||||
* MINOR: Rewrite the majority of the ``bin`` scripts to use more modern syntax
|
||||
* MINOR: Improved CSS anomation through prefers-reduced-motion
|
||||
* PERFORMANCE: Use workers (where possible) to minify CSS/JS on first page request. This improves initial startup times.
|
||||
* PERFORMANCE: Cache EJS files improving page load speed when maxAge > 0.
|
||||
* PERFORMANCE: Fix performance for large pads
|
||||
* TESTS: Additional test coverage for OL/LI/Import/Export
|
||||
* TESTS: Include Simulated Load Testing in CI.
|
||||
* TESTS: Include content collector tests to test contentcollector.js logic external to pad dependents.
|
||||
* TESTS: Include fuzzing import test.
|
||||
* TESTS: Ensure CI is no longer using any cache
|
||||
* TESTS: Fix various tests...
|
||||
* TESTS: Various additional Travis testing including libreoffice import/export
|
||||
|
||||
# 1.8.4
|
||||
* FIX: fix a performance regression on MySQL introduced in 1.8.3
|
||||
* FIX: when running behind a reverse proxy and exposed in an inner directory, fonts and toolbar icons should now be visible. This is a regression introduced in 1.8.3
|
||||
|
|
|
@ -42,7 +42,7 @@ RUN bin/installDeps.sh && \
|
|||
#
|
||||
# Bash trick: in the for loop ${ETHERPAD_PLUGINS} is NOT quoted, in order to be
|
||||
# able to split at spaces.
|
||||
RUN for PLUGIN_NAME in ${ETHERPAD_PLUGINS}; do npm install "${PLUGIN_NAME}"; done
|
||||
RUN for PLUGIN_NAME in ${ETHERPAD_PLUGINS}; do npm install "${PLUGIN_NAME}" || exit 1; done
|
||||
|
||||
# Copy the configuration file.
|
||||
COPY --chown=etherpad:0 ./settings.json.docker /opt/etherpad-lite/settings.json
|
||||
|
|
17
README.md
17
README.md
|
@ -1,6 +1,8 @@
|
|||
# A real-time collaborative editor for the web
|
||||
<a href="https://hub.docker.com/r/etherpad/etherpad"><img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/etherpad/etherpad"></a>
|
||||
[![Travis (.org)](https://img.shields.io/travis/ether/etherpad-lite)](https://travis-ci.org/github/ether/etherpad-lite)
|
||||
|
||||
[![Travis (.org)](https://api.travis-ci.org/ether/etherpad-lite.svg?branch=develop)](https://travis-ci.org/github/ether/etherpad-lite)
|
||||
|
||||
![Demo Etherpad Animated Jif](doc/images/etherpad_demo.gif "Etherpad in action")
|
||||
|
||||
# About
|
||||
|
@ -92,6 +94,13 @@ If you prefer, `ep_hash_auth` also gives you the option of storing the users in
|
|||
|
||||
Etherpad is very customizable through plugins. Instructions for installing themes and plugins can be found in [the plugin wiki article](https://github.com/ether/etherpad-lite/wiki/Available-Plugins).
|
||||
|
||||
## Getting the full features
|
||||
Run the following command in your Etherpad folder to get all of the features visible in the demo gif:
|
||||
|
||||
```
|
||||
npm install ep_headings2 ep_markdown ep_comments_page ep_align ep_page_view ep_font_color ep_webrtc ep_embedded_hyperlinks2
|
||||
```
|
||||
|
||||
## Customize the style with skin variants
|
||||
|
||||
Open <http://127.0.0.1:9001/p/test#skinvariantsbuilder> in your browser and start playing !
|
||||
|
@ -130,10 +139,12 @@ OpenAPI (previously swagger) definitions for the API are exposed under `/api/ope
|
|||
There is a [jQuery plugin](https://github.com/ether/etherpad-lite-jquery-plugin) that helps you to embed Pads into your website.
|
||||
|
||||
# Plugin Framework
|
||||
Etherpad offers a plugin framework, allowing you to easily add your own features. By default your Etherpad is extremely light-weight and it's up to you to customize your experience. Once you have Etherpad installed you should visit the plugin page and take control.
|
||||
Etherpad offers a plugin framework, allowing you to easily add your own features. By default your Etherpad is extremely light-weight and it's up to you to customize your experience. Once you have Etherpad installed you should [visit the plugin page](https://static.etherpad.org/) and take control.
|
||||
|
||||
# Translations / Localizations (i18n / l10n)
|
||||
Etherpad comes with translations into all languages thanks to the team at TranslateWiki.
|
||||
Etherpad comes with translations into all languages thanks to the team at [TranslateWiki](https://translatewiki.net/).
|
||||
|
||||
If you require translations in [plugins](https://static.etherpad.org/) please send pull request to each plugin individually.
|
||||
|
||||
# FAQ
|
||||
Visit the **[FAQ](https://github.com/ether/etherpad-lite/wiki/FAQ)**.
|
||||
|
|
5
SECURITY.md
Normal file
5
SECURITY.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please email contact@etherpad.org to report security related issues.
|
|
@ -1,39 +1,29 @@
|
|||
#!/bin/sh
|
||||
|
||||
NODE_VERSION="10.20.1"
|
||||
pecho() { printf %s\\n "$*"; }
|
||||
log() { pecho "$@"; }
|
||||
error() { log "ERROR: $@" >&2; }
|
||||
fatal() { error "$@"; exit 1; }
|
||||
is_cmd() { command -v "$@" >/dev/null 2>&1; }
|
||||
|
||||
#Move to the folder where ep-lite is installed
|
||||
cd $(dirname $0)
|
||||
# Move to the folder where ep-lite is installed
|
||||
cd "$(dirname "$0")"/..
|
||||
|
||||
#Was this script started in the bin folder? if yes move out
|
||||
if [ -d "../bin" ]; then
|
||||
cd "../"
|
||||
fi
|
||||
# Is wget installed?
|
||||
is_cmd wget || fatal "Please install wget"
|
||||
|
||||
#Is wget installed?
|
||||
hash wget > /dev/null 2>&1 || {
|
||||
echo "Please install wget" >&2
|
||||
exit 1
|
||||
}
|
||||
# Is zip installed?
|
||||
is_cmd zip || fatal "Please install zip"
|
||||
|
||||
#Is zip installed?
|
||||
hash zip > /dev/null 2>&1 || {
|
||||
echo "Please install zip" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
#Is zip installed?
|
||||
hash unzip > /dev/null 2>&1 || {
|
||||
echo "Please install unzip" >&2
|
||||
exit 1
|
||||
}
|
||||
# Is zip installed?
|
||||
is_cmd unzip || fatal "Please install unzip"
|
||||
|
||||
START_FOLDER=$(pwd);
|
||||
TMP_FOLDER=$(mktemp -d)
|
||||
|
||||
echo "create a clean environment in $TMP_FOLDER..."
|
||||
cp -ar . $TMP_FOLDER
|
||||
cd $TMP_FOLDER
|
||||
log "create a clean environment in $TMP_FOLDER..."
|
||||
cp -ar . "$TMP_FOLDER"
|
||||
cd "$TMP_FOLDER"
|
||||
rm -rf node_modules
|
||||
rm -f etherpad-lite-win.zip
|
||||
|
||||
|
@ -41,33 +31,33 @@ rm -f etherpad-lite-win.zip
|
|||
# making the windows package smaller
|
||||
export NODE_ENV=production
|
||||
|
||||
echo "do a normal unix install first..."
|
||||
log "do a normal unix install first..."
|
||||
bin/installDeps.sh || exit 1
|
||||
|
||||
echo "copy the windows settings template..."
|
||||
log "copy the windows settings template..."
|
||||
cp settings.json.template settings.json
|
||||
|
||||
echo "resolve symbolic links..."
|
||||
log "resolve symbolic links..."
|
||||
cp -rL node_modules node_modules_resolved
|
||||
rm -rf node_modules
|
||||
mv node_modules_resolved node_modules
|
||||
|
||||
echo "download windows node..."
|
||||
log "download windows node..."
|
||||
cd bin
|
||||
wget "https://nodejs.org/dist/v$NODE_VERSION/win-x86/node.exe" -O ../node.exe
|
||||
wget "https://nodejs.org/dist/latest-erbium/win-x86/node.exe" -O ../node.exe
|
||||
|
||||
echo "remove git history to reduce folder size"
|
||||
log "remove git history to reduce folder size"
|
||||
rm -rf .git/objects
|
||||
|
||||
echo "remove windows jsdom-nocontextify/test folder"
|
||||
rm -rf $TMP_FOLDER/src/node_modules/wd/node_modules/request/node_modules/form-data/node_modules/combined-stream/test
|
||||
rm -rf $TMP_FOLDER/src/node_modules/nodemailer/node_modules/mailcomposer/node_modules/mimelib/node_modules/encoding/node_modules/iconv-lite/encodings/tables
|
||||
log "remove windows jsdom-nocontextify/test folder"
|
||||
rm -rf "$TMP_FOLDER"/src/node_modules/wd/node_modules/request/node_modules/form-data/node_modules/combined-stream/test
|
||||
rm -rf "$TMP_FOLDER"/src/node_modules/nodemailer/node_modules/mailcomposer/node_modules/mimelib/node_modules/encoding/node_modules/iconv-lite/encodings/tables
|
||||
|
||||
echo "create the zip..."
|
||||
cd $TMP_FOLDER
|
||||
zip -9 -r $START_FOLDER/etherpad-lite-win.zip ./*
|
||||
log "create the zip..."
|
||||
cd "$TMP_FOLDER"
|
||||
zip -9 -r "$START_FOLDER"/etherpad-lite-win.zip ./*
|
||||
|
||||
echo "clean up..."
|
||||
rm -rf $TMP_FOLDER
|
||||
log "clean up..."
|
||||
rm -rf "$TMP_FOLDER"
|
||||
|
||||
echo "Finished. You can find the zip in the Etherpad root folder, it's called etherpad-lite-win.zip"
|
||||
log "Finished. You can find the zip in the Etherpad root folder, it's called etherpad-lite-win.zip"
|
||||
|
|
|
@ -349,7 +349,7 @@ function convertPad(padId, callback)
|
|||
|
||||
//generate new author values
|
||||
var authorID = "a." + randomString(16);
|
||||
var authorColorID = authors[i].colorId || Math.floor(Math.random()*32);
|
||||
var authorColorID = authors[i].colorId || Math.floor(Math.random()*(exports.getColorPalette().length));
|
||||
var authorName = authors[i].name || null;
|
||||
|
||||
//overwrite the authorID of the attribute pool
|
||||
|
|
47
bin/createUserSession.js
Normal file
47
bin/createUserSession.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* A tool for generating a test user session which can be used for debugging configs
|
||||
* that require sessions.
|
||||
*/
|
||||
const m = (f) => __dirname + '/../' + f;
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const querystring = require('querystring');
|
||||
const request = require(m('src/node_modules/request'));
|
||||
const settings = require(m('src/node/utils/Settings'));
|
||||
const supertest = require(m('src/node_modules/supertest'));
|
||||
|
||||
(async () => {
|
||||
const api = supertest('http://'+settings.ip+':'+settings.port);
|
||||
|
||||
const filePath = path.join(__dirname, '../APIKEY.txt');
|
||||
const apikey = fs.readFileSync(filePath, {encoding: 'utf-8'});
|
||||
|
||||
let res;
|
||||
|
||||
res = await api.get('/api/');
|
||||
const apiVersion = res.body.currentVersion;
|
||||
if (!apiVersion) throw new Error('No version set in API');
|
||||
const uri = (cmd, args) => `/api/${apiVersion}/${cmd}?${querystring.stringify(args)}`;
|
||||
|
||||
res = await api.post(uri('createGroup', {apikey}));
|
||||
if (res.body.code === 1) throw new Error(`Error creating group: ${res.body}`);
|
||||
const groupID = res.body.data.groupID;
|
||||
console.log('groupID', groupID);
|
||||
|
||||
res = await api.post(uri('createGroupPad', {apikey, groupID}));
|
||||
if (res.body.code === 1) throw new Error(`Error creating group pad: ${res.body}`);
|
||||
console.log('Test Pad ID ====> ', res.body.data.padID);
|
||||
|
||||
res = await api.post(uri('createAuthor', {apikey}));
|
||||
if (res.body.code === 1) throw new Error(`Error creating author: ${res.body}`);
|
||||
const authorID = res.body.data.authorID;
|
||||
console.log('authorID', authorID);
|
||||
|
||||
const validUntil = Math.floor(new Date() / 1000) + 60000;
|
||||
console.log('validUntil', validUntil);
|
||||
res = await api.post(uri('createSession', {apikey, groupID, authorID, validUntil}));
|
||||
if (res.body.code === 1) throw new Error(`Error creating session: ${res.body}`);
|
||||
console.log('Session made: ====> create a cookie named sessionID and set the value to',
|
||||
res.body.data.sessionID);
|
||||
})();
|
|
@ -1,20 +1,15 @@
|
|||
#!/bin/sh
|
||||
|
||||
#Move to the folder where ep-lite is installed
|
||||
cd $(dirname $0)
|
||||
# Move to the folder where ep-lite is installed
|
||||
cd "$(dirname "$0")"/..
|
||||
|
||||
#Was this script started in the bin folder? if yes move out
|
||||
if [ -d "../bin" ]; then
|
||||
cd "../"
|
||||
fi
|
||||
|
||||
#Prepare the environment
|
||||
# Prepare the environment
|
||||
bin/installDeps.sh || exit 1
|
||||
|
||||
echo "If you are new to debugging Node.js with Chrome DevTools, take a look at this page:"
|
||||
echo "https://medium.com/@paul_irish/debugging-node-js-nightlies-with-chrome-devtools-7c4a1b95ae27"
|
||||
echo "Open 'chrome://inspect' on Chrome to start debugging."
|
||||
|
||||
#Use 0.0.0.0 to allow external connections to the debugger
|
||||
#(ex: running Etherpad on a docker container). Use default port # (9229)
|
||||
# Use 0.0.0.0 to allow external connections to the debugger
|
||||
# (ex: running Etherpad on a docker container). Use default port # (9229)
|
||||
node --inspect=0.0.0.0:9229 node_modules/ep_etherpad-lite/node/server.js "$@"
|
||||
|
|
51
bin/deleteAllGroupSessions.js
Normal file
51
bin/deleteAllGroupSessions.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* A tool for deleting ALL GROUP sessions Etherpad user sessions from the CLI,
|
||||
* because sometimes a brick is required to fix a face.
|
||||
*/
|
||||
|
||||
const request = require('../src/node_modules/request');
|
||||
const settings = require(__dirname+'/../tests/container/loadSettings').loadSettings();
|
||||
const supertest = require(__dirname+'/../src/node_modules/supertest');
|
||||
const api = supertest('http://'+settings.ip+":"+settings.port);
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
// get the API Key
|
||||
var filePath = path.join(__dirname, '../APIKEY.txt');
|
||||
var apikey = fs.readFileSync(filePath, {encoding: 'utf-8'});
|
||||
|
||||
// Set apiVersion to base value, we change this later.
|
||||
var apiVersion = 1;
|
||||
var guids;
|
||||
|
||||
// Update the apiVersion
|
||||
api.get('/api/')
|
||||
.expect(function(res){
|
||||
apiVersion = res.body.currentVersion;
|
||||
if (!res.body.currentVersion) throw new Error("No version set in API");
|
||||
return;
|
||||
})
|
||||
.then(function(){
|
||||
let guri = '/api/'+apiVersion+'/listAllGroups?apikey='+apikey;
|
||||
api.get(guri)
|
||||
.then(function(res){
|
||||
guids = res.body.data.groupIDs;
|
||||
guids.forEach(function(groupID){
|
||||
let luri = '/api/'+apiVersion+'/listSessionsOfGroup?apikey='+apikey + "&groupID="+groupID;
|
||||
api.get(luri)
|
||||
.then(function(res){
|
||||
if(res.body.data){
|
||||
Object.keys(res.body.data).forEach(function(sessionID){
|
||||
if(sessionID){
|
||||
console.log("Deleting", sessionID);
|
||||
let duri = '/api/'+apiVersion+'/deleteSession?apikey='+apikey + "&sessionID="+sessionID;
|
||||
api.post(duri); // deletes
|
||||
}
|
||||
})
|
||||
}else{
|
||||
// no session in this group.
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
|
||||
const request = require('../src/node_modules/request');
|
||||
const settings = require(__dirname+'/../tests/backend/loadSettings').loadSettings();
|
||||
const settings = require(__dirname+'/../tests/container/loadSettings').loadSettings();
|
||||
const supertest = require(__dirname+'/../src/node_modules/supertest');
|
||||
const api = supertest('http://'+settings.ip+":"+settings.port);
|
||||
const path = require('path');
|
||||
|
|
|
@ -8,6 +8,12 @@ REQUIRED_NODE_MINOR=13
|
|||
REQUIRED_NPM_MAJOR=5
|
||||
REQUIRED_NPM_MINOR=5
|
||||
|
||||
pecho() { printf %s\\n "$*"; }
|
||||
log() { pecho "$@"; }
|
||||
error() { log "ERROR: $@" >&2; }
|
||||
fatal() { error "$@"; exit 1; }
|
||||
is_cmd() { command -v "$@" >/dev/null 2>&1; }
|
||||
|
||||
require_minimal_version() {
|
||||
PROGRAM_LABEL="$1"
|
||||
VERSION_STRING="$2"
|
||||
|
@ -16,71 +22,50 @@ require_minimal_version() {
|
|||
|
||||
# Flag -s (--only-delimited on GNU cut) ensures no string is returned
|
||||
# when there is no match
|
||||
DETECTED_MAJOR=$(echo $VERSION_STRING | cut -s -d "." -f 1)
|
||||
DETECTED_MINOR=$(echo $VERSION_STRING | cut -s -d "." -f 2)
|
||||
DETECTED_MAJOR=$(pecho "$VERSION_STRING" | cut -s -d "." -f 1)
|
||||
DETECTED_MINOR=$(pecho "$VERSION_STRING" | cut -s -d "." -f 2)
|
||||
|
||||
if [ -z "$DETECTED_MAJOR" ]; then
|
||||
printf 'Cannot extract %s major version from version string "%s"\n' "$PROGRAM_LABEL" "$VERSION_STRING" >&2
|
||||
exit 1
|
||||
fi
|
||||
[ -n "$DETECTED_MAJOR" ] || fatal "Cannot extract $PROGRAM_LABEL major version from version string \"$VERSION_STRING\""
|
||||
|
||||
if [ -z "$DETECTED_MINOR" ]; then
|
||||
printf 'Cannot extract %s minor version from version string "%s"\n' "$PROGRAM_LABEL" "$VERSION_STRING" >&2
|
||||
exit 1
|
||||
fi
|
||||
[ -n "$DETECTED_MINOR" ] || fatal "Cannot extract $PROGRAM_LABEL minor version from version string \"$VERSION_STRING\""
|
||||
|
||||
case "$DETECTED_MAJOR" in
|
||||
''|*[!0-9]*)
|
||||
printf '%s major version from "%s" is not a number. Detected: "%s"\n' "$PROGRAM_LABEL" "$VERSION_STRING" "$DETECTED_MAJOR" >&2
|
||||
exit 1
|
||||
fatal "$PROGRAM_LABEL major version from \"$VERSION_STRING\" is not a number. Detected: \"$DETECTED_MAJOR\""
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$DETECTED_MINOR" in
|
||||
''|*[!0-9]*)
|
||||
printf '%s minor version from "%s" is not a number. Detected: "%s"\n' "$PROGRAM_LABEL" "$VERSION_STRING" "$DETECTED_MINOR" >&2
|
||||
exit 1
|
||||
fatal "$PROGRAM_LABEL minor version from \"$VERSION_STRING\" is not a number. Detected: \"$DETECTED_MINOR\""
|
||||
esac
|
||||
|
||||
if [ "$DETECTED_MAJOR" -lt "$REQUIRED_MAJOR" ] || ([ "$DETECTED_MAJOR" -eq "$REQUIRED_MAJOR" ] && [ "$DETECTED_MINOR" -lt "$REQUIRED_MINOR" ]); then
|
||||
printf 'Your %s version "%s" is too old. %s %d.%d.x or higher is required.\n' "$PROGRAM_LABEL" "$VERSION_STRING" "$PROGRAM_LABEL" "$REQUIRED_MAJOR" "$REQUIRED_MINOR" >&2
|
||||
exit 1
|
||||
fi
|
||||
[ "$DETECTED_MAJOR" -gt "$REQUIRED_MAJOR" ] || ([ "$DETECTED_MAJOR" -eq "$REQUIRED_MAJOR" ] && [ "$DETECTED_MINOR" -ge "$REQUIRED_MINOR" ]) \
|
||||
|| fatal "Your $PROGRAM_LABEL version \"$VERSION_STRING\" is too old. $PROGRAM_LABEL $REQUIRED_MAJOR.$REQUIRED_MINOR.x or higher is required."
|
||||
}
|
||||
|
||||
#Move to the folder where ep-lite is installed
|
||||
cd $(dirname $0)
|
||||
# Move to the folder where ep-lite is installed
|
||||
cd "$(dirname "$0")"/..
|
||||
|
||||
#Was this script started in the bin folder? if yes move out
|
||||
if [ -d "../bin" ]; then
|
||||
cd "../"
|
||||
fi
|
||||
# Is node installed?
|
||||
# Not checking io.js, default installation creates a symbolic link to node
|
||||
is_cmd node || fatal "Please install node.js ( https://nodejs.org )"
|
||||
|
||||
#Is node installed?
|
||||
#Not checking io.js, default installation creates a symbolic link to node
|
||||
hash node > /dev/null 2>&1 || {
|
||||
echo "Please install node.js ( https://nodejs.org )" >&2
|
||||
exit 1
|
||||
}
|
||||
# Is npm installed?
|
||||
is_cmd npm || fatal "Please install npm ( https://npmjs.org )"
|
||||
|
||||
#Is npm installed?
|
||||
hash npm > /dev/null 2>&1 || {
|
||||
echo "Please install npm ( https://npmjs.org )" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
#Check npm version
|
||||
# Check npm version
|
||||
NPM_VERSION_STRING=$(npm --version)
|
||||
|
||||
require_minimal_version "npm" "$NPM_VERSION_STRING" "$REQUIRED_NPM_MAJOR" "$REQUIRED_NPM_MINOR"
|
||||
|
||||
#Check node version
|
||||
# Check node version
|
||||
NODE_VERSION_STRING=$(node --version)
|
||||
NODE_VERSION_STRING=${NODE_VERSION_STRING#"v"}
|
||||
|
||||
require_minimal_version "nodejs" "$NODE_VERSION_STRING" "$REQUIRED_NODE_MAJOR" "$REQUIRED_NODE_MINOR"
|
||||
|
||||
#Get the name of the settings file
|
||||
# Get the name of the settings file
|
||||
settings="settings.json"
|
||||
a='';
|
||||
for arg in "$@"; do
|
||||
|
@ -88,26 +73,26 @@ for arg in "$@"; do
|
|||
a=$arg
|
||||
done
|
||||
|
||||
#Does a $settings exist? if not copy the template
|
||||
if [ ! -f $settings ]; then
|
||||
echo "Copy the settings template to $settings..."
|
||||
cp settings.json.template $settings || exit 1
|
||||
# Does a $settings exist? if not copy the template
|
||||
if [ ! -f "$settings" ]; then
|
||||
log "Copy the settings template to $settings..."
|
||||
cp settings.json.template "$settings" || exit 1
|
||||
fi
|
||||
|
||||
echo "Ensure that all dependencies are up to date... If this is the first time you have run Etherpad please be patient."
|
||||
log "Ensure that all dependencies are up to date... If this is the first time you have run Etherpad please be patient."
|
||||
(
|
||||
mkdir -p node_modules
|
||||
cd node_modules
|
||||
[ -e ep_etherpad-lite ] || ln -s ../src ep_etherpad-lite
|
||||
cd ep_etherpad-lite
|
||||
npm install --save --loglevel warn
|
||||
npm ci
|
||||
) || {
|
||||
rm -rf src/node_modules
|
||||
exit 1
|
||||
}
|
||||
|
||||
#Remove all minified data to force node creating it new
|
||||
echo "Clearing minified cache..."
|
||||
# Remove all minified data to force node creating it new
|
||||
log "Clearing minified cache..."
|
||||
rm -f var/minified*
|
||||
|
||||
exit 0
|
||||
|
|
|
@ -14,7 +14,7 @@ cd /D node_modules
|
|||
mklink /D "ep_etherpad-lite" "..\src"
|
||||
|
||||
cd /D "ep_etherpad-lite"
|
||||
cmd /C npm install --loglevel warn || exit /B 1
|
||||
cmd /C npm ci || exit /B 1
|
||||
|
||||
cd /D "%~dp0\.."
|
||||
|
||||
|
|
46
bin/plugins/README.md
Executable file
46
bin/plugins/README.md
Executable file
|
@ -0,0 +1,46 @@
|
|||
The files in this folder are for Plugin developers.
|
||||
|
||||
# Get suggestions to improve your Plugin
|
||||
|
||||
This code will check your plugin for known usual issues and some suggestions for improvements. No changes will be made to your project.
|
||||
|
||||
```
|
||||
node bin/plugins/checkPlugin.js $PLUGIN_NAME$
|
||||
```
|
||||
|
||||
# Basic Example:
|
||||
```
|
||||
node bin/plugins/checkPlugin.js ep_webrtc
|
||||
```
|
||||
|
||||
## Autofixing - will autofix any issues it can
|
||||
```
|
||||
node bin/plugins/checkPlugins.js ep_whatever autofix
|
||||
```
|
||||
|
||||
## Autocommitting, push, npm minor patch and npm publish (highly dangerous)
|
||||
```
|
||||
node bin/plugins/checkPlugins.js ep_whatever autofix autocommit
|
||||
```
|
||||
|
||||
# All the plugins
|
||||
Replace johnmclear with your github username
|
||||
|
||||
```
|
||||
# Clones
|
||||
cd node_modules
|
||||
GHUSER=johnmclear; curl "https://api.github.com/users/$GHUSER/repos?per_page=1000" | grep -o 'git@[^"]*' | grep /ep_ | xargs -L1 git clone
|
||||
cd ..
|
||||
|
||||
# autofixes and autocommits /pushes & npm publishes
|
||||
for dir in `ls node_modules`;
|
||||
do
|
||||
# echo $0
|
||||
if [[ $dir == *"ep_"* ]]; then
|
||||
if [[ $dir != "ep_etherpad-lite" ]]; then
|
||||
node bin/plugins/checkPlugin.js $dir autofix autocommit
|
||||
fi
|
||||
fi
|
||||
# echo $dir
|
||||
done
|
||||
```
|
246
bin/plugins/checkPlugin.js
Executable file
246
bin/plugins/checkPlugin.js
Executable file
|
@ -0,0 +1,246 @@
|
|||
// pro usage for all your plugins, replace johnmclear with your github username
|
||||
/*
|
||||
cd node_modules
|
||||
GHUSER=johnmclear; curl "https://api.github.com/users/$GHUSER/repos?per_page=1000" | grep -o 'git@[^"]*' | grep /ep_ | xargs -L1 git clone
|
||||
cd ..
|
||||
|
||||
for dir in `ls node_modules`;
|
||||
do
|
||||
# echo $0
|
||||
if [[ $dir == *"ep_"* ]]; then
|
||||
if [[ $dir != "ep_etherpad-lite" ]]; then
|
||||
node bin/plugins/checkPlugin.js $dir autofix autocommit
|
||||
fi
|
||||
fi
|
||||
# echo $dir
|
||||
done
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* Usage
|
||||
*
|
||||
* Normal usage: node bin/plugins/checkPlugins.js ep_whatever
|
||||
* Auto fix the things it can: node bin/plugins/checkPlugins.js ep_whatever autofix
|
||||
* Auto commit, push and publish(to npm) * highly dangerous:
|
||||
node bin/plugins/checkPlugins.js ep_whatever autofix autocommit
|
||||
|
||||
*/
|
||||
|
||||
const fs = require("fs");
|
||||
const { exec } = require("child_process");
|
||||
|
||||
// get plugin name & path from user input
|
||||
const pluginName = process.argv[2];
|
||||
const pluginPath = "node_modules/"+pluginName;
|
||||
|
||||
console.log("Checking the plugin: "+ pluginName)
|
||||
|
||||
// Should we autofix?
|
||||
if (process.argv[3] && process.argv[3] === "autofix") var autoFix = true;
|
||||
|
||||
// Should we update files where possible?
|
||||
if (process.argv[5] && process.argv[5] === "autoupdate") var autoUpdate = true;
|
||||
|
||||
// Should we automcommit and npm publish?!
|
||||
if (process.argv[4] && process.argv[4] === "autocommit") var autoCommit = true;
|
||||
|
||||
|
||||
if(autoCommit){
|
||||
console.warn("Auto commit is enabled, I hope you know what you are doing...")
|
||||
}
|
||||
|
||||
fs.readdir(pluginPath, function (err, rootFiles) {
|
||||
//handling error
|
||||
if (err) {
|
||||
return console.log('Unable to scan directory: ' + err);
|
||||
}
|
||||
|
||||
// rewriting files to lower case
|
||||
var files = [];
|
||||
|
||||
// some files we need to know the actual file name. Not compulsory but might help in the future.
|
||||
var readMeFileName;
|
||||
var repository;
|
||||
var hasAutofixed = false;
|
||||
|
||||
for (var i = 0; i < rootFiles.length; i++) {
|
||||
if(rootFiles[i].toLowerCase().indexOf("readme") !== -1) readMeFileName = rootFiles[i];
|
||||
files.push(rootFiles[i].toLowerCase());
|
||||
}
|
||||
|
||||
if(files.indexOf("package.json") === -1){
|
||||
console.warn("no package.json, please create");
|
||||
}
|
||||
|
||||
if(files.indexOf("package.json") !== -1){
|
||||
let packageJSON = fs.readFileSync(pluginPath+"/package.json", {encoding:'utf8', flag:'r'});
|
||||
|
||||
if(packageJSON.toLowerCase().indexOf("repository") === -1){
|
||||
console.warn("No repository in package.json");
|
||||
if(autoFix){
|
||||
console.warn("Repository not detected in package.json. Please add repository section manually.")
|
||||
}
|
||||
}else{
|
||||
// useful for creating README later.
|
||||
repository = JSON.parse(packageJSON).repository.url;
|
||||
}
|
||||
|
||||
}
|
||||
if(files.indexOf("readme") === -1 && files.indexOf("readme.md") === -1){
|
||||
console.warn("README.md file not found, please create");
|
||||
if(autoFix){
|
||||
console.log("Autofixing missing README.md file, please edit the README.md file further to include plugin specific details.");
|
||||
let readme = fs.readFileSync("bin/plugins/lib/README.md", {encoding:'utf8', flag:'r'})
|
||||
readme = readme.replace(/\[plugin_name\]/g, pluginName);
|
||||
if(repository){
|
||||
let org = repository.split("/")[3];
|
||||
let name = repository.split("/")[4];
|
||||
readme = readme.replace(/\[org_name\]/g, org);
|
||||
readme = readme.replace(/\[repo_url\]/g, name);
|
||||
fs.writeFileSync(pluginPath+"/README.md", readme);
|
||||
}else{
|
||||
console.warn("Unable to find repository in package.json, aborting.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(files.indexOf("readme") !== -1 && files.indexOf("readme.md") !== -1){
|
||||
let readme = fs.readFileSync(pluginPath+"/"+readMeFileName, {encoding:'utf8', flag:'r'});
|
||||
if(readme.toLowerCase().indexOf("license") === -1){
|
||||
console.warn("No license section in README");
|
||||
if(autoFix){
|
||||
console.warn("Please add License section to README manually.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(files.indexOf("license") === -1 && files.indexOf("license.md") === -1){
|
||||
console.warn("LICENSE.md file not found, please create");
|
||||
if(autoFix){
|
||||
hasAutofixed = true;
|
||||
console.log("Autofixing missing LICENSE.md file, including Apache 2 license.");
|
||||
exec("git config user.name", (error, name, stderr) => {
|
||||
if (error) {
|
||||
console.log(`error: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
if (stderr) {
|
||||
console.log(`stderr: ${stderr}`);
|
||||
return;
|
||||
}
|
||||
let license = fs.readFileSync("bin/plugins/lib/LICENSE.md", {encoding:'utf8', flag:'r'});
|
||||
license = license.replace("[yyyy]", new Date().getFullYear());
|
||||
license = license.replace("[name of copyright owner]", name)
|
||||
fs.writeFileSync(pluginPath+"/LICENSE.md", license);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var travisConfig = fs.readFileSync("bin/plugins/lib/travis.yml", {encoding:'utf8', flag:'r'});
|
||||
travisConfig = travisConfig.replace(/\[plugin_name\]/g, pluginName);
|
||||
|
||||
if(files.indexOf(".travis.yml") === -1){
|
||||
console.warn(".travis.yml file not found, please create. .travis.yml is used for automatically CI testing Etherpad. It is useful to know if your plugin breaks another feature for example.")
|
||||
// TODO: Make it check version of the .travis file to see if it needs an update.
|
||||
if(autoFix){
|
||||
hasAutofixed = true;
|
||||
console.log("Autofixing missing .travis.yml file");
|
||||
fs.writeFileSync(pluginPath+"/.travis.yml", travisConfig);
|
||||
console.log("Travis file created, please sign into travis and enable this repository")
|
||||
}
|
||||
}
|
||||
if(autoFix && autoUpdate){
|
||||
// checks the file versioning of .travis and updates it to the latest.
|
||||
let existingConfig = fs.readFileSync(pluginPath + "/.travis.yml", {encoding:'utf8', flag:'r'});
|
||||
let existingConfigLocation = existingConfig.indexOf("##ETHERPAD_TRAVIS_V=");
|
||||
let existingValue = existingConfig.substr(existingConfigLocation+20, existingConfig.length);
|
||||
|
||||
let newConfigLocation = travisConfig.indexOf("##ETHERPAD_TRAVIS_V=");
|
||||
let newValue = travisConfig.substr(newConfigLocation+20, travisConfig.length);
|
||||
|
||||
if(existingConfigLocation === -1){
|
||||
console.warn("no previous .travis.yml version found so writing new.")
|
||||
// we will write the newTravisConfig to the location.
|
||||
fs.writeFileSync(pluginPath + "/.travis.yml", travisConfig);
|
||||
}else{
|
||||
if(newValue > existingValue){
|
||||
console.log("updating .travis.yml");
|
||||
fs.writeFileSync(pluginPath + "/.travis.yml", travisConfig);
|
||||
hasAutofixed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(files.indexOf(".gitignore") === -1){
|
||||
console.warn(".gitignore file not found, please create. .gitignore files are useful to ensure files aren't incorrectly commited to a repository.")
|
||||
if(autoFix){
|
||||
hasAutofixed = true;
|
||||
console.log("Autofixing missing .gitignore file");
|
||||
let gitignore = fs.readFileSync("bin/plugins/lib/gitignore", {encoding:'utf8', flag:'r'});
|
||||
fs.writeFileSync(pluginPath+"/.gitignore", gitignore);
|
||||
}
|
||||
}
|
||||
|
||||
if(files.indexOf("locales") === -1){
|
||||
console.warn("Translations not found, please create. Translation files help with Etherpad accessibility.");
|
||||
}
|
||||
|
||||
|
||||
if(files.indexOf(".ep_initialized") !== -1){
|
||||
console.warn(".ep_initialized found, please remove. .ep_initialized should never be commited to git and should only exist once the plugin has been executed one time.")
|
||||
if(autoFix){
|
||||
hasAutofixed = true;
|
||||
console.log("Autofixing incorrectly existing .ep_initialized file");
|
||||
fs.unlinkSync(pluginPath+"/.ep_initialized");
|
||||
}
|
||||
}
|
||||
|
||||
if(files.indexOf("npm-debug.log") !== -1){
|
||||
console.warn("npm-debug.log found, please remove. npm-debug.log should never be commited to your repository.")
|
||||
if(autoFix){
|
||||
hasAutofixed = true;
|
||||
console.log("Autofixing incorrectly existing npm-debug.log file");
|
||||
fs.unlinkSync(pluginPath+"/npm-debug.log");
|
||||
}
|
||||
}
|
||||
|
||||
if(files.indexOf("static") !== -1){
|
||||
fs.readdir(pluginPath+"/static", function (errRead, staticFiles) {
|
||||
if(staticFiles.indexOf("tests") === -1){
|
||||
console.warn("Test files not found, please create tests. https://github.com/ether/etherpad-lite/wiki/Creating-a-plugin#writing-and-running-front-end-tests-for-your-plugin")
|
||||
}
|
||||
})
|
||||
}else{
|
||||
console.warn("Test files not found, please create tests. https://github.com/ether/etherpad-lite/wiki/Creating-a-plugin#writing-and-running-front-end-tests-for-your-plugin")
|
||||
}
|
||||
|
||||
if(hasAutofixed){
|
||||
console.log("Fixes applied, please check git diff then run the following command:\n\n")
|
||||
// bump npm Version
|
||||
if(autoCommit){
|
||||
// holy shit you brave.
|
||||
console.log("Attempting autocommit and auto publish to npm")
|
||||
exec("cd node_modules/"+ pluginName + " && git add -A && git commit --allow-empty -m 'autofixes from Etherpad checkPlugins.js' && npm version patch && git add package.json && git commit --allow-empty -m 'bump version' && git push && npm publish && cd ../..", (error, name, stderr) => {
|
||||
if (error) {
|
||||
console.log(`error: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
if (stderr) {
|
||||
console.log(`stderr: ${stderr}`);
|
||||
return;
|
||||
}
|
||||
console.log("I think she's got it! By George she's got it!")
|
||||
process.exit(0)
|
||||
});
|
||||
}else{
|
||||
console.log("cd node_modules/"+ pluginName + " && git add -A && git commit --allow-empty -m 'autofixes from Etherpad checkPlugins.js' && npm version patch && git add package.json && git commit --allow-empty -m 'bump version' && git push && npm publish && cd ../..")
|
||||
}
|
||||
}
|
||||
|
||||
//listing all files using forEach
|
||||
files.forEach(function (file) {
|
||||
// Do whatever you want to do with the file
|
||||
// console.log(file.toLowerCase());
|
||||
});
|
||||
});
|
13
bin/plugins/lib/LICENSE.md
Executable file
13
bin/plugins/lib/LICENSE.md
Executable file
|
@ -0,0 +1,13 @@
|
|||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
28
bin/plugins/lib/README.md
Executable file
28
bin/plugins/lib/README.md
Executable file
|
@ -0,0 +1,28 @@
|
|||
[![Travis (.org)](https://api.travis-ci.org/[org_name]/[repo_url].svg?branch=develop)](https://travis-ci.org/github/[org_name]/[repo_url])
|
||||
|
||||
# My awesome plugin README example
|
||||
Explain what your plugin does and who it's useful for.
|
||||
|
||||
## Example animated gif of usage if appropriate
|
||||
|
||||
## Installing
|
||||
npm install [plugin_name]
|
||||
|
||||
or Use the Etherpad ``/admin`` interface.
|
||||
|
||||
## Settings
|
||||
Document settings if any
|
||||
|
||||
## Testing
|
||||
Document how to run backend / frontend tests.
|
||||
|
||||
### Frontend
|
||||
|
||||
Visit http://whatever/tests/frontend/ to run the frontend tests.
|
||||
|
||||
### backend
|
||||
|
||||
Type ``cd src && npm run test`` to run the backend tests.
|
||||
|
||||
## LICENSE
|
||||
Apache 2.0
|
5
bin/plugins/lib/gitignore
Executable file
5
bin/plugins/lib/gitignore
Executable file
|
@ -0,0 +1,5 @@
|
|||
.ep_initialized
|
||||
.DS_Store
|
||||
node_modules/
|
||||
node_modules
|
||||
npm-debug.log
|
68
bin/plugins/lib/travis.yml
Executable file
68
bin/plugins/lib/travis.yml
Executable file
|
@ -0,0 +1,68 @@
|
|||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "lts/*"
|
||||
|
||||
cache: false
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:libreoffice/ppa
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y install libreoffice
|
||||
- sudo apt-get -y install libreoffice-pdfimport
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
install:
|
||||
- "bin/installDeps.sh"
|
||||
- "export GIT_HASH=$(git rev-parse --verify --short HEAD)"
|
||||
|
||||
before_script:
|
||||
- "tests/frontend/travis/sauce_tunnel.sh"
|
||||
|
||||
script:
|
||||
- "tests/frontend/travis/runner.sh"
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: "WMGxFkOeTTlhWB+ChMucRtIqVmMbwzYdNHuHQjKCcj8HBEPdZLfCuK/kf4rG\nVLcLQiIsyllqzNhBGVHG1nyqWr0/LTm8JRqSCDDVIhpyzp9KpCJQQJG2Uwjk\n6/HIJJh/wbxsEdLNV2crYU/EiVO3A4Bq0YTHUlbhUqG3mSCr5Ec="
|
||||
- secure: "gejXUAHYscbR6Bodw35XexpToqWkv2ifeECsbeEmjaLkYzXmUUNWJGknKSu7\nEUsSfQV8w+hxApr1Z+jNqk9aX3K1I4btL3cwk2trnNI8XRAvu1c1Iv60eerI\nkE82Rsd5lwUaMEh+/HoL8ztFCZamVndoNgX7HWp5J/NRZZMmh4g="
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- name: "Run the Backend tests"
|
||||
install:
|
||||
- "npm install"
|
||||
- "mkdir [plugin_name]"
|
||||
- "mv !([plugin_name]) [plugin_name]"
|
||||
- "git clone https://github.com/ether/etherpad-lite.git etherpad"
|
||||
- "cd etherpad"
|
||||
- "mkdir node_modules"
|
||||
- "mv ../[plugin_name] node_modules"
|
||||
- "bin/installDeps.sh"
|
||||
- "export GIT_HASH=$(git rev-parse --verify --short HEAD)"
|
||||
- "cd src && npm install && cd -"
|
||||
script:
|
||||
- "tests/frontend/travis/runnerBackend.sh"
|
||||
- name: "Test the Frontend"
|
||||
install:
|
||||
- "npm install"
|
||||
- "mkdir [plugin_name]"
|
||||
- "mv !([plugin_name]) [plugin_name]"
|
||||
- "git clone https://github.com/ether/etherpad-lite.git etherpad"
|
||||
- "cd etherpad"
|
||||
- "mkdir node_modules"
|
||||
- "mv ../[plugin_name] node_modules"
|
||||
- "bin/installDeps.sh"
|
||||
- "export GIT_HASH=$(git rev-parse --verify --short HEAD)"
|
||||
script:
|
||||
- "tests/frontend/travis/runner.sh"
|
||||
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "irc.freenode.org#etherpad-lite-dev"
|
||||
|
||||
##ETHERPAD_TRAVIS_V=3
|
||||
## Travis configuration automatically created using bin/plugins/updateAllPluginsScript.sh
|
14
bin/plugins/reTestAllPlugins.sh
Executable file
14
bin/plugins/reTestAllPlugins.sh
Executable file
|
@ -0,0 +1,14 @@
|
|||
echo "herp";
|
||||
for dir in `ls node_modules`;
|
||||
do
|
||||
echo $dir
|
||||
if [[ $dir == *"ep_"* ]]; then
|
||||
if [[ $dir != "ep_etherpad-lite" ]]; then
|
||||
# node bin/plugins/checkPlugin.js $dir autofix autocommit autoupdate
|
||||
cd node_modules/$dir
|
||||
git commit -m "Automatic update: bump update to re-run latest Etherpad tests" --allow-empty
|
||||
git push origin master
|
||||
cd ../..
|
||||
fi
|
||||
fi
|
||||
done
|
17
bin/plugins/updateAllPluginsScript.sh
Executable file
17
bin/plugins/updateAllPluginsScript.sh
Executable file
|
@ -0,0 +1,17 @@
|
|||
cd node_modules
|
||||
GHUSER=johnmclear; curl "https://api.github.com/users/$GHUSER/repos?per_page=1000" | grep -o 'git@[^"]*' | grep /ep_ | xargs -L1 git clone
|
||||
GHUSER=johnmclear; curl "https://api.github.com/users/$GHUSER/repos?per_page=1000&page=2" | grep -o 'git@[^"]*' | grep /ep_ | xargs -L1 git clone
|
||||
GHUSER=johnmclear; curl "https://api.github.com/users/$GHUSER/repos?per_page=1000&page=3" | grep -o 'git@[^"]*' | grep /ep_ | xargs -L1 git clone
|
||||
GHUSER=johnmclear; curl "https://api.github.com/users/$GHUSER/repos?per_page=1000&page=4" | grep -o 'git@[^"]*' | grep /ep_ | xargs -L1 git clone
|
||||
cd ..
|
||||
|
||||
for dir in `ls node_modules`;
|
||||
do
|
||||
# echo $0
|
||||
if [[ $dir == *"ep_"* ]]; then
|
||||
if [[ $dir != "ep_etherpad-lite" ]]; then
|
||||
node bin/plugins/checkPlugin.js $dir autofix autocommit autoupdate
|
||||
fi
|
||||
fi
|
||||
# echo $dir
|
||||
done
|
40
bin/run.sh
40
bin/run.sh
|
@ -1,39 +1,37 @@
|
|||
#!/bin/sh
|
||||
|
||||
#Move to the folder where ep-lite is installed
|
||||
cd $(dirname $0)
|
||||
pecho() { printf %s\\n "$*"; }
|
||||
log() { pecho "$@"; }
|
||||
error() { log "ERROR: $@" >&2; }
|
||||
fatal() { error "$@"; exit 1; }
|
||||
|
||||
#Was this script started in the bin folder? if yes move out
|
||||
if [ -d "../bin" ]; then
|
||||
cd "../"
|
||||
fi
|
||||
# Move to the folder where ep-lite is installed
|
||||
cd "$(dirname "$0")"/..
|
||||
|
||||
ignoreRoot=0
|
||||
for ARG in "$@"
|
||||
do
|
||||
for ARG in "$@"; do
|
||||
if [ "$ARG" = "--root" ]; then
|
||||
ignoreRoot=1
|
||||
fi
|
||||
done
|
||||
|
||||
#Stop the script if it's started as root
|
||||
if [ "$(id -u)" -eq 0 ] && [ $ignoreRoot -eq 0 ]; then
|
||||
echo "You shouldn't start Etherpad as root!"
|
||||
echo "Please type 'Etherpad rocks my socks' or supply the '--root' argument if you still want to start it as root"
|
||||
# Stop the script if it's started as root
|
||||
if [ "$(id -u)" -eq 0 ] && [ "$ignoreRoot" -eq 0 ]; then
|
||||
cat <<EOF >&2
|
||||
You shouldn't start Etherpad as root!
|
||||
Please type 'Etherpad rocks my socks' (or restart with the '--root'
|
||||
argument) if you still want to start it as root:
|
||||
EOF
|
||||
printf "> " >&2
|
||||
read rocks
|
||||
if [ ! "$rocks" == "Etherpad rocks my socks" ]
|
||||
then
|
||||
echo "Your input was incorrect"
|
||||
exit 1
|
||||
fi
|
||||
[ "$rocks" = "Etherpad rocks my socks" ] || fatal "Your input was incorrect"
|
||||
fi
|
||||
|
||||
#Prepare the environment
|
||||
# Prepare the environment
|
||||
bin/installDeps.sh "$@" || exit 1
|
||||
|
||||
#Move to the node folder and start
|
||||
echo "Started Etherpad..."
|
||||
# Move to the node folder and start
|
||||
log "Starting Etherpad..."
|
||||
|
||||
SCRIPTPATH=$(pwd -P)
|
||||
exec node "$SCRIPTPATH/node_modules/ep_etherpad-lite/node/server.js" "$@"
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
#This script ensures that ep-lite is automatically restarting after an error happens
|
||||
# This script ensures that ep-lite is automatically restarting after
|
||||
# an error happens
|
||||
|
||||
#Handling Errors
|
||||
# 0 silent
|
||||
# 1 email
|
||||
# Handling Errors
|
||||
# 0 silent
|
||||
# 1 email
|
||||
ERROR_HANDLING=0
|
||||
# Your email address which should receive the error messages
|
||||
EMAIL_ADDRESS="no-reply@example.com"
|
||||
|
@ -15,54 +16,54 @@ TIME_BETWEEN_EMAILS=600 # 10 minutes
|
|||
|
||||
# DON'T EDIT AFTER THIS LINE
|
||||
|
||||
pecho() { printf %s\\n "$*"; }
|
||||
log() { pecho "$@"; }
|
||||
error() { log "ERROR: $@" >&2; }
|
||||
fatal() { error "$@"; exit 1; }
|
||||
|
||||
LAST_EMAIL_SEND=0
|
||||
|
||||
# Move to the folder where ep-lite is installed
|
||||
cd "$(dirname "$0")"/..
|
||||
|
||||
# Check if a logfile parameter is set
|
||||
LOG="$1"
|
||||
|
||||
#Move to the folder where ep-lite is installed
|
||||
cd $(dirname $0)
|
||||
|
||||
#Was this script started in the bin folder? if yes move out
|
||||
if [ -d "../bin" ]; then
|
||||
cd "../"
|
||||
fi
|
||||
|
||||
#Check if a logfile parameter is set
|
||||
if [ -z "${LOG}" ]; then
|
||||
echo "Set a logfile as the first parameter"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -n "${LOG}" ] || fatal "Set a logfile as the first parameter"
|
||||
shift
|
||||
while [ 1 ]
|
||||
do
|
||||
#Try to touch the file if it doesn't exist
|
||||
if [ ! -f ${LOG} ]; then
|
||||
touch ${LOG} || ( echo "Logfile '${LOG}' is not writeable" && exit 1 )
|
||||
fi
|
||||
|
||||
#Check if the file is writeable
|
||||
if [ ! -w ${LOG} ]; then
|
||||
echo "Logfile '${LOG}' is not writeable"
|
||||
exit 1
|
||||
fi
|
||||
while true; do
|
||||
# Try to touch the file if it doesn't exist
|
||||
[ -f "${LOG}" ] || touch "${LOG}" || fatal "Logfile '${LOG}' is not writeable"
|
||||
|
||||
#Start the application
|
||||
bin/run.sh $@ >>${LOG} 2>>${LOG}
|
||||
# Check if the file is writeable
|
||||
[ -w "${LOG}" ] || fatal "Logfile '${LOG}' is not writeable"
|
||||
|
||||
#Send email
|
||||
if [ $ERROR_HANDLING = 1 ]; then
|
||||
# Start the application
|
||||
bin/run.sh "$@" >>${LOG} 2>>${LOG}
|
||||
|
||||
TIME_FMT=$(date +%Y-%m-%dT%H:%M:%S%z)
|
||||
|
||||
# Send email
|
||||
if [ "$ERROR_HANDLING" = 1 ]; then
|
||||
TIME_NOW=$(date +%s)
|
||||
TIME_SINCE_LAST_SEND=$(($TIME_NOW - $LAST_EMAIL_SEND))
|
||||
|
||||
if [ $TIME_SINCE_LAST_SEND -gt $TIME_BETWEEN_EMAILS ]; then
|
||||
printf "Server was restarted at: $(date)\nThe last 50 lines of the log before the error happens:\n $(tail -n 50 ${LOG})" | mail -s "Pad Server was restarted" $EMAIL_ADDRESS
|
||||
if [ "$TIME_SINCE_LAST_SEND" -gt "$TIME_BETWEEN_EMAILS" ]; then
|
||||
{
|
||||
cat <<EOF
|
||||
Server was restarted at: ${TIME_FMT}
|
||||
The last 50 lines of the log before the server exited:
|
||||
|
||||
EOF
|
||||
tail -n 50 "${LOG}"
|
||||
} | mail -s "Etherpad restarted" "$EMAIL_ADDRESS"
|
||||
|
||||
LAST_EMAIL_SEND=$TIME_NOW
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "RESTART!" >>${LOG}
|
||||
pecho "RESTART! ${TIME_FMT}" >>${LOG}
|
||||
|
||||
#Sleep 10 seconds before restart
|
||||
# Sleep 10 seconds before restart
|
||||
sleep 10
|
||||
done
|
||||
|
|
|
@ -1,11 +1,51 @@
|
|||
# Hooks
|
||||
All hooks are called with two arguments:
|
||||
|
||||
1. name - the name of the hook being called
|
||||
2. context - an object with some relevant information about the context of the call
|
||||
A hook function is registered with a hook via the plugin's `ep.json` file. See
|
||||
the Plugins section for details. A hook may have many registered functions from
|
||||
different plugins.
|
||||
|
||||
When a hook is invoked, its registered functions are called with three
|
||||
arguments:
|
||||
|
||||
1. hookName - The name of the hook being invoked.
|
||||
2. context - An object with some relevant information about the context of the
|
||||
call. See the hook-specific documentation for details.
|
||||
3. callback - Function to call when done. This callback takes a single argument,
|
||||
the meaning of which depends on the hook. See the "Return values" section for
|
||||
general information that applies to most hooks. The value returned by this
|
||||
callback must be returned by the hook function unless otherwise specified.
|
||||
|
||||
## Return values
|
||||
A hook should always return a list or undefined. Returning undefined is equivalent to returning an empty list.
|
||||
All the returned lists are appended to each other, so if the return values where `[1, 2]`, `undefined`, `[3, 4,]`, `undefined` and `[5]`, the value returned by callHook would be `[1, 2, 3, 4, 5]`.
|
||||
|
||||
This is, because it should never matter if you have one plugin or several plugins doing some work - a single plugin should be able to make callHook return the same value a set of plugins are able to return collectively. So, any plugin can return a list of values, of any length, not just one value.
|
||||
Note: This section applies to every hook unless the hook-specific documentation
|
||||
says otherwise.
|
||||
|
||||
Hook functions return zero or more values to Etherpad by passing an array to the
|
||||
provided callback. Hook functions typically provide a single value (array of
|
||||
length one). If the function does not want to or need to provide a value, it may
|
||||
pass an empty array or `undefined` (which is treated the same as an empty
|
||||
array). Hook functions may also provide more than one value (array of length two
|
||||
or more).
|
||||
|
||||
Some hooks concatenate the arrays provided by its registered functions. For
|
||||
example, if a hook's registered functions pass `[1, 2]`, `undefined`, `[3, 4]`,
|
||||
`[]`, and `[5]` to the provided callback, then the hook's return value is `[1,
|
||||
2, 3, 4, 5]`.
|
||||
|
||||
Other hooks only use the first non-empty array provided by a registered
|
||||
function. In this case, each of the hook's registered functions is called one at
|
||||
a time until one provides a non-empty array. The remaining functions are
|
||||
skipped. If none of the functions provide a non-empty array, or there are no
|
||||
registered functions, the hook's return value is `[]`.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
exports.abstractHook = (hookName, context, callback) => {
|
||||
if (notApplicableToThisPlugin(context)) {
|
||||
return callback();
|
||||
}
|
||||
const value = doSomeProcessing(context);
|
||||
return callback([value]);
|
||||
};
|
||||
```
|
||||
|
|
|
@ -93,7 +93,10 @@ Available blocks in `pad.html` are:
|
|||
|
||||
`index.html` blocks:
|
||||
|
||||
* `indexCustomStyles` - contains the `index.css` `<link>` tag, allows you to add your own or to customize the one provided by the active skin
|
||||
* `indexWrapper` - contains the form for creating new pads
|
||||
* `indexCustomScripts` - contains the `index.js` `<script>` tag, allows you to add your own or to customize the one provided by the active skin
|
||||
* `indexCustomInlineScripts` - contains the inline `<script>` of home page, allows you to customize `go2Name()`, `go2Random()` or `randomPadName()` functions
|
||||
|
||||
## padInitToolbar
|
||||
Called from: src/node/hooks/express/specialpages.js
|
||||
|
@ -197,7 +200,69 @@ Things in context:
|
|||
3. next - ?
|
||||
4. resource - the path being accessed
|
||||
|
||||
This is useful for modifying the way authentication is done, especially for specific paths.
|
||||
This hook is called to handle authorization. It is especially useful for
|
||||
controlling access to specific paths.
|
||||
|
||||
A plugin's authorize function is typically called twice for each access: once
|
||||
before authentication and again after. Specifically, it is called if all of the
|
||||
following are true:
|
||||
|
||||
* The request is not for static content or an API endpoint. (Requests for static
|
||||
content and API endpoints are always authorized, even if unauthenticated.)
|
||||
* Either authentication has not yet been performed (`context.req.session.user`
|
||||
is undefined) or the user has successfully authenticated
|
||||
(`context.req.session.user` is an object containing user-specific settings).
|
||||
* If the user has successfully authenticated, the user is not an admin. (Admin
|
||||
users are always authorized.)
|
||||
* Either the request is for an `/admin` page or the `requireAuthentication`
|
||||
setting is true.
|
||||
* Either the request is for an `/admin` page, or the user has not yet
|
||||
authenticated, or the user has authenticated and the `requireAuthorization`
|
||||
setting is true.
|
||||
* For pre-authentication invocations of a plugin's authorize function
|
||||
(`context.req.session.user` is undefined), an authorize function from a
|
||||
different plugin has not already caused the pre-authentication authorization
|
||||
to pass or fail.
|
||||
* For post-authentication invocations of a plugin's authorize function
|
||||
(`context.req.session.user` is an object), an authorize function from a
|
||||
different plugin has not already caused the post-authentication authorization
|
||||
to pass or fail.
|
||||
|
||||
For pre-authentication invocations of your authorize function, calling the
|
||||
provided callback with `[true]` will immediately grant access without requiring
|
||||
the user to authenticate. Calling the provided callback with `[false]` will
|
||||
trigger authentication unless authentication is not required. Calling the
|
||||
provided callback with `[]` or `undefined` will defer the decision to the next
|
||||
authorization plugin (if any, otherwise it is the same as calling with
|
||||
`[false]`).
|
||||
|
||||
**WARNING:** Your authorize function can be called for an `/admin` page even if
|
||||
the user has not yet authenticated. It is your responsibility to fail or defer
|
||||
authorization if you do not want to grant admin privileges to the general
|
||||
public.
|
||||
|
||||
For post-authentication invocations of your authorize function, calling the
|
||||
provided callback with `[true]` or `[false]` will cause access to be granted or
|
||||
denied, respectively. Calling the callback with `[]` or `undefined` will defer
|
||||
the authorization decision to the next authorization plugin (if any, otherwise
|
||||
deny).
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
exports.authorize = (hookName, context, cb) => {
|
||||
const user = context.req.session.user;
|
||||
if (!user) {
|
||||
// The user has not yet authenticated so defer the pre-authentication
|
||||
// authorization decision to the next plugin.
|
||||
return cb([]);
|
||||
}
|
||||
const path = context.req.path; // or context.resource
|
||||
if (isExplicitlyProhibited(user, path)) return cb([false]);
|
||||
if (isExplicitlyAllowed(user, path)) return cb([true]);
|
||||
return cb([]); // Let the next authorization plugin decide
|
||||
};
|
||||
```
|
||||
|
||||
## authenticate
|
||||
Called from: src/node/hooks/express/webaccess.js
|
||||
|
@ -210,7 +275,57 @@ Things in context:
|
|||
4. username - the username used (optional)
|
||||
5. password - the password used (optional)
|
||||
|
||||
This is useful for modifying the way authentication is done.
|
||||
This hook is called to handle authentication.
|
||||
|
||||
Plugins that supply an authenticate function should probably also supply an
|
||||
authFailure function unless falling back to HTTP basic authentication is
|
||||
appropriate upon authentication failure.
|
||||
|
||||
This hook is only called if either the `requireAuthentication` setting is true
|
||||
or the request is for an `/admin` page.
|
||||
|
||||
Calling the provided callback with `[true]` or `[false]` will cause
|
||||
authentication to succeed or fail, respectively. Calling the callback with `[]`
|
||||
or `undefined` will defer the authentication decision to the next authentication
|
||||
plugin (if any, otherwise fall back to HTTP basic authentication).
|
||||
|
||||
If you wish to provide a mix of restricted and anonymous access (e.g., some pads
|
||||
are private, others are public), you can "authenticate" (as a guest account)
|
||||
users that have not yet logged in, and rely on other hooks (e.g., authorize,
|
||||
onAccessCheck, handleMessageSecurity) to authorize specific privileged actions.
|
||||
|
||||
If authentication is successful, the authenticate function MUST set
|
||||
`context.req.session.user` to the user's settings object. The `username`
|
||||
property of this object should be set to the user's username. The settings
|
||||
object should come from global settings (`settings.users[username]`).
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
let global_settings;
|
||||
|
||||
exports.loadSettings = (hook_name, {settings}, cb) => {
|
||||
global_settings = settings;
|
||||
return cb();
|
||||
};
|
||||
|
||||
exports.authenticate = (hook_name, context, cb) => {
|
||||
if (notApplicableToThisPlugin(context)) {
|
||||
return cb([]); // Let the next authentication plugin decide
|
||||
}
|
||||
const username = authenticate(context);
|
||||
if (!username) {
|
||||
console.warn(`ep_myplugin.authenticate: Failed authentication from IP ${context.req.ip}`);
|
||||
return cb([false]);
|
||||
}
|
||||
console.info(`ep_myplugin.authenticate: Successful authentication from IP ${context.req.ip} for user ${username}`);
|
||||
const users = global_settings.users;
|
||||
if (!(username in users)) users[username] = {};
|
||||
users[username].username = username;
|
||||
context.req.session.user = users[username];
|
||||
return cb([true]);
|
||||
};
|
||||
```
|
||||
|
||||
## authFailure
|
||||
Called from: src/node/hooks/express/webaccess.js
|
||||
|
@ -221,7 +336,34 @@ Things in context:
|
|||
2. res - the response object
|
||||
3. next - ?
|
||||
|
||||
This is useful for modifying the way authentication is done.
|
||||
This hook is called to handle an authentication or authorization failure.
|
||||
|
||||
Plugins that supply an authenticate function should probably also supply an
|
||||
authFailure function unless falling back to HTTP basic authentication is
|
||||
appropriate upon authentication failure.
|
||||
|
||||
A plugin's authFailure function is only called if all of the following are true:
|
||||
|
||||
* There was an authentication or authorization failure.
|
||||
* The failure was not already handled by an authFailure function from another
|
||||
plugin.
|
||||
|
||||
Calling the provided callback with `[true]` tells Etherpad that the failure was
|
||||
handled and no further error handling is required. Calling the callback with
|
||||
`[]` or `undefined` defers error handling to the next authFailure plugin (if
|
||||
any, otherwise fall back to HTTP basic authentication).
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
exports.authFailure = (hookName, context, cb) => {
|
||||
if (notApplicableToThisPlugin(context)) {
|
||||
return cb([]); // Let the next plugin handle the error
|
||||
}
|
||||
context.res.redirect(makeLoginURL(context.req));
|
||||
return cb([true]);
|
||||
};
|
||||
```
|
||||
|
||||
## handleMessage
|
||||
Called from: src/node/handler/PadMessageHandler.js
|
||||
|
@ -275,7 +417,6 @@ function handleMessageSecurity ( hook, context, callback ) {
|
|||
};
|
||||
```
|
||||
|
||||
|
||||
## clientVars
|
||||
Called from: src/node/handler/PadMessageHandler.js
|
||||
|
||||
|
@ -283,16 +424,38 @@ Things in context:
|
|||
|
||||
1. clientVars - the basic `clientVars` built by the core
|
||||
2. pad - the pad this session is about
|
||||
3. socket - the socket.io Socket object
|
||||
|
||||
This hook will be called once a client connects and the `clientVars` are being sent. Plugins can use this hook to give the client an initial configuration, like the tracking-id of an external analytics-tool that is used on the client-side. You can also overwrite values from the original `clientVars`.
|
||||
This hook is called after a client connects but before the initial configuration
|
||||
is sent to the client. Plugins can use this hook to manipulate the
|
||||
configuration. (Example: Add a tracking ID for an external analytics tool that
|
||||
is used client-side.)
|
||||
|
||||
Example:
|
||||
The clientVars function must return a Promise that resolves to an object (or
|
||||
null/undefined) whose properties will be merged into `context.clientVars`.
|
||||
Returning `callback(value)` will return a Promise that is resolved to `value`.
|
||||
|
||||
You can modify `context.clientVars` to change the values sent to the client, but
|
||||
beware: async functions from other clientVars plugins might also be reading or
|
||||
manipulating the same `context.clientVars` object. For this reason it is
|
||||
recommended you return an object rather than modify `context.clientVars`.
|
||||
|
||||
If needed, you can access the user's account information (if authenticated) via
|
||||
`context.socket.client.request.session.user`.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
exports.clientVars = function(hook, context, callback)
|
||||
{
|
||||
// tell the client which year we are in
|
||||
return callback({ "currentYear": new Date().getFullYear() });
|
||||
// Using an async function
|
||||
exports.clientVars = async (hookName, context) => {
|
||||
const user = context.socket.client.request.session.user || {};
|
||||
return {'accountUsername': user.username || '<unknown>'}
|
||||
};
|
||||
|
||||
// Using a regular function
|
||||
exports.clientVars = (hookName, context, callback) => {
|
||||
const user = context.socket.client.request.session.user || {};
|
||||
return callback({'accountUsername': user.username || '<unknown>'});
|
||||
};
|
||||
```
|
||||
|
||||
|
|
|
@ -92,3 +92,23 @@ For example, if you want to replace `Chat` with `Notes`, simply add...
|
|||
, "pad.chat": "Notes"
|
||||
}
|
||||
```
|
||||
|
||||
## Customization for Administrators
|
||||
|
||||
As an Etherpad administrator, it is possible to overwrite core mesages as well as messages in plugins. These include error messages, labels, and user instructions. Whereas the localization in the source code is in separate files separated by locale, an administrator's custom localizations are in `settings.json` under the `customLocaleStrings` key, with each locale separated by a sub-key underneath.
|
||||
|
||||
For example, let's say you want to change the text on the "New Pad" button on Etherpad's home page. If you look in `locales/en.json` (or `locales/en-gb.json`) you'll see the key for this text is `"index.newPad"`. You could add the following to `settings.json`:
|
||||
|
||||
```
|
||||
"customLocaleStrings": {
|
||||
"fr": {
|
||||
"index.newPad": "Créer un document"
|
||||
},
|
||||
"en-gb": {
|
||||
"index.newPad": "Create a document"
|
||||
},
|
||||
"en": {
|
||||
"index.newPad": "Create a document"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -551,5 +551,8 @@
|
|||
*/
|
||||
|
||||
]
|
||||
} // logconfig
|
||||
}, // logconfig
|
||||
|
||||
/* Override any strings found in locale directories */
|
||||
"customLocaleStrings": {}
|
||||
}
|
||||
|
|
|
@ -467,6 +467,36 @@
|
|||
*/
|
||||
"importMaxFileSize": 52428800, // 50 * 1024 * 1024
|
||||
|
||||
|
||||
/*
|
||||
* From Etherpad 1.8.3 onwards import was restricted to authors who had
|
||||
* content within the pad.
|
||||
*
|
||||
* This setting will override that restriction and allow any user to import
|
||||
* without the requirement to add content to a pad.
|
||||
*
|
||||
* This setting is useful for when you use a plugin for authentication so you
|
||||
* can already trust each user.
|
||||
*/
|
||||
"allowAnyoneToImport": false,
|
||||
|
||||
/*
|
||||
* From Etherpad 1.9.0 onwards, when Etherpad is in production mode commits from individual users are rate limited
|
||||
*
|
||||
* The default is to allow at most 10 changes per IP in a 1 second window.
|
||||
* After that the change is rejected.
|
||||
*
|
||||
* See https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#websocket-single-connection-prevent-flooding for more options
|
||||
*/
|
||||
"commitRateLimiting": {
|
||||
// duration of the rate limit window (seconds)
|
||||
"duration": 1,
|
||||
|
||||
// maximum number of chanes per IP to allow during the rate limit window
|
||||
"points": 10
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* Toolbar buttons configuration.
|
||||
*
|
||||
|
@ -556,5 +586,8 @@
|
|||
*/
|
||||
|
||||
]
|
||||
} // logconfig
|
||||
}, // logconfig
|
||||
|
||||
/* Override any strings found in locale directories */
|
||||
"customLocaleStrings": {}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
},
|
||||
"index.newPad": "باد جديد",
|
||||
"index.createOpenPad": "أو صنع/فتح باد بوضع اسمه:",
|
||||
"index.openPad": "افتح باد موجودة بالاسم:",
|
||||
"pad.toolbar.bold.title": "سميك (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "مائل (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "تسطير (Ctrl+U)",
|
||||
|
@ -50,6 +51,8 @@
|
|||
"pad.settings.fontType": "نوع الخط:",
|
||||
"pad.settings.fontType.normal": "عادي",
|
||||
"pad.settings.language": "اللغة:",
|
||||
"pad.settings.about": "حول",
|
||||
"pad.settings.poweredBy": "مدعوم من",
|
||||
"pad.importExport.import_export": "استيراد/تصدير",
|
||||
"pad.importExport.import": "تحميل أي ملف نصي أو وثيقة",
|
||||
"pad.importExport.importSuccessful": "ناجح!",
|
||||
|
@ -60,7 +63,7 @@
|
|||
"pad.importExport.exportword": "مايكروسوفت وورد",
|
||||
"pad.importExport.exportpdf": "صيغة المستندات المحمولة",
|
||||
"pad.importExport.exportopen": "ODF (نسق المستند المفتوح)",
|
||||
"pad.importExport.abiword.innerHTML": "لا يمكنك الاستيراد إلا من نص عادي أو من تنسيقات HTML. للحصول على المزيد من ميزات الاستيراد المتقدمة، يرجى <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">تثبيت AbiWord</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "لا يمكنك الاستيراد إلا من نص عادي أو من تنسيقات HTML. للحصول على المزيد من ميزات الاستيراد المتقدمة، يرجى <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">تثبيت AbiWord أو LibreOffice</a>.",
|
||||
"pad.modals.connected": "متصل.",
|
||||
"pad.modals.reconnecting": "إعادة الاتصال ببادك..",
|
||||
"pad.modals.forcereconnect": "فرض إعادة الاتصال",
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
},
|
||||
"index.newPad": "Nuevu bloc",
|
||||
"index.createOpenPad": "o crear/abrir un bloc col nome:",
|
||||
"index.openPad": "abre un bloc qu'esiste col nome:",
|
||||
"pad.toolbar.bold.title": "Negrina (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Cursiva (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "Sorrayáu (Ctrl-U)",
|
||||
|
@ -26,7 +27,7 @@
|
|||
"pad.colorpicker.save": "Guardar",
|
||||
"pad.colorpicker.cancel": "Encaboxar",
|
||||
"pad.loading": "Cargando...",
|
||||
"pad.noCookie": "Nun pudo alcontrase la cookie. ¡Por favor, permite les cookies nel navegador!",
|
||||
"pad.noCookie": "Nun pudo alcontrase la cookie. ¡Por favor, permite les cookies nel navegador! La sesión y preferencies nun se guarden ente visites. Esto pué debese a qu'Etherpad inclúyese nun iFrame en dalgunos restoladores. Asegúrate de qu'Etherpad tea nel mesmu subdominiu/dominiu que la iFrame padre",
|
||||
"pad.passwordRequired": "Necesites una contraseña pa entrar a esti bloc",
|
||||
"pad.permissionDenied": "Nun tienes permisu pa entrar a esti bloc",
|
||||
"pad.wrongPassword": "La contraseña era incorreuta",
|
||||
|
@ -40,6 +41,8 @@
|
|||
"pad.settings.fontType": "Tipografía:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Llingua:",
|
||||
"pad.settings.about": "Tocante a",
|
||||
"pad.settings.poweredBy": "Col encontu de",
|
||||
"pad.importExport.import_export": "Importar/Esportar",
|
||||
"pad.importExport.import": "Xubir cualquier ficheru o documentu de testu",
|
||||
"pad.importExport.importSuccessful": "¡Correuto!",
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"Mastizada",
|
||||
"Mushviq Abdulla",
|
||||
"Neriman2003",
|
||||
"Vesely35",
|
||||
"Wertuose"
|
||||
]
|
||||
},
|
||||
|
@ -46,6 +47,8 @@
|
|||
"pad.settings.fontType": "Şriftin tipi:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Dil:",
|
||||
"pad.settings.about": "Haqqında",
|
||||
"pad.settings.poweredBy": "$1 ilə işləyir",
|
||||
"pad.importExport.import_export": "İdxal/İxrac",
|
||||
"pad.importExport.import": "Hər hansı bir mətn faylı və ya sənəd yüklə",
|
||||
"pad.importExport.importSuccessful": "Uğurlu!",
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
"authors": [
|
||||
"Jim-by",
|
||||
"Red Winged Duck",
|
||||
"Renessaince",
|
||||
"Wizardist"
|
||||
]
|
||||
},
|
||||
"index.newPad": "Стварыць",
|
||||
"index.createOpenPad": "ці тварыць/адкрыць дакумэнт з назвай:",
|
||||
"index.openPad": "адкрыць існы Нататнік з назваю:",
|
||||
"pad.toolbar.bold.title": "Тоўсты (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Курсіў (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "Падкрэсьліваньне (Ctrl-U)",
|
||||
|
@ -28,7 +30,7 @@
|
|||
"pad.colorpicker.save": "Захаваць",
|
||||
"pad.colorpicker.cancel": "Скасаваць",
|
||||
"pad.loading": "Загрузка...",
|
||||
"pad.noCookie": "Кукі ня знойдзеныя. Калі ласка, дазвольце кукі ў вашым браўзэры!",
|
||||
"pad.noCookie": "Кукі ня знойдзеныя. Калі ласка, дазвольце кукі ў вашым браўзэры! Паміж наведваньнямі вашая сэсія і налады ня будуць захаваныя. Гэта можа адбывацца таму, што ў некаторых броўзэрах Etherpad заключаны ўнутры iFrame. Праверце, калі ласка, што Etherpad знаходзіцца ў тым жа паддамэне/дамэне, што і бацькоўскі iFrame",
|
||||
"pad.passwordRequired": "Для доступу да гэтага дакумэнта патрэбны пароль",
|
||||
"pad.permissionDenied": "Вы ня маеце дазволу на доступ да гэтага дакумэнта",
|
||||
"pad.wrongPassword": "Вы ўвялі няслушны пароль",
|
||||
|
@ -52,7 +54,7 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "Вы можаце імпартаваць толькі з звычайнага тэксту або HTML. Дзеля больш пашыраных магчымасьцяў імпарту, калі ласка, <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">усталюйце AbiWord</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "Вы можаце імпартаваць толькі з звычайнага тэксту або HTML. Дзеля больш пашыраных магчымасьцяў імпарту, калі ласка, <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">усталюйце AbiWord альбо LibreOffice</a>.",
|
||||
"pad.modals.connected": "Падлучыліся.",
|
||||
"pad.modals.reconnecting": "Перападлучэньне да вашага дакумэнта...",
|
||||
"pad.modals.forcereconnect": "Прымусовае перападлучэньне",
|
||||
|
@ -120,7 +122,7 @@
|
|||
"pad.userlist.guest": "Госьць",
|
||||
"pad.userlist.deny": "Адхіліць",
|
||||
"pad.userlist.approve": "Зацьвердзіць",
|
||||
"pad.editbar.clearcolors": "Ачысьціць аўтарскія колеры ва ўсім дакумэнце?",
|
||||
"pad.editbar.clearcolors": "Ачысьціць аўтарскія колеры ва ўсім дакумэнце? Гэта немагчыма будзе скасаваць",
|
||||
"pad.impexp.importbutton": "Імпартаваць зараз",
|
||||
"pad.impexp.importing": "Імпартаваньне…",
|
||||
"pad.impexp.confirmimport": "Імпарт файла перазапіша цяперашні тэкст дакумэнту. Вы ўпэўненыя, што хочаце працягваць?",
|
||||
|
@ -129,5 +131,7 @@
|
|||
"pad.impexp.uploadFailed": "Загрузка не атрымалася, калі ласка, паспрабуйце яшчэ раз",
|
||||
"pad.impexp.importfailed": "Памылка імпарту",
|
||||
"pad.impexp.copypaste": "Калі ласка, скапіюйце і ўстаўце",
|
||||
"pad.impexp.exportdisabled": "Экспарт у фармаце {{type}} адключаны. Калі ласка, зьвярніцеся да вашага сыстэмнага адміністратара па падрабязнасьці."
|
||||
"pad.impexp.exportdisabled": "Экспарт у фармаце {{type}} адключаны. Калі ласка, зьвярніцеся да вашага сыстэмнага адміністратара па падрабязнасьці.",
|
||||
"pad.impexp.maxFileSize": "Файл завялікі. Зьвярніцеся да адміністратара сайту, каб павялічыць дазволены памер файлаў для імпарту",
|
||||
"pad.impexp.permission": "Імпарт адключаны, бо вы ніколі не працавалі з гэтым нататнікам. Калі ласка, перад імпартам зрабеце хоць бы адзін унёсак"
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"Bellayet",
|
||||
"Nasir8891",
|
||||
"Sankarshan",
|
||||
"Sibabrata Banerjee",
|
||||
"আফতাবুজ্জামান"
|
||||
]
|
||||
},
|
||||
|
@ -45,6 +46,8 @@
|
|||
"pad.settings.fontType": "ফন্টের প্রকার:",
|
||||
"pad.settings.fontType.normal": "সাধারণ",
|
||||
"pad.settings.language": "ভাষা:",
|
||||
"pad.settings.about": "পরিচিতি",
|
||||
"pad.settings.poweredBy": "$1 দ্বারা চালিত",
|
||||
"pad.importExport.import_export": "আমদানি/রপ্তানি",
|
||||
"pad.importExport.import": "কোন টেক্সট ফাইল বা নথি আপলোড করুন",
|
||||
"pad.importExport.importSuccessful": "সফল!",
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
"authors": [
|
||||
"Edinwiki",
|
||||
"Semina x",
|
||||
"Srdjan m"
|
||||
"Srdjan m",
|
||||
"Srđan"
|
||||
]
|
||||
},
|
||||
"index.newPad": "Novi Pad",
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"Jaumeortola",
|
||||
"Joan manel",
|
||||
"Macofe",
|
||||
"Mguix",
|
||||
"Pginer",
|
||||
"Pitort",
|
||||
"Ssola",
|
||||
|
@ -14,6 +15,7 @@
|
|||
},
|
||||
"index.newPad": "Nou pad",
|
||||
"index.createOpenPad": "o crea/obre un pad amb el nom:",
|
||||
"index.openPad": "obrir un Pad existint amb el nom:",
|
||||
"pad.toolbar.bold.title": "Negreta (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Cursiva (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "Subratllat (Ctrl-U)",
|
||||
|
@ -48,6 +50,8 @@
|
|||
"pad.settings.fontType": "Tipus de lletra:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Llengua:",
|
||||
"pad.settings.about": "Sobre",
|
||||
"pad.settings.poweredBy": "Funciona amb",
|
||||
"pad.importExport.import_export": "Importació/exportació",
|
||||
"pad.importExport.import": "Puja qualsevol fitxer de text o document",
|
||||
"pad.importExport.importSuccessful": "Hi ha hagut èxit!",
|
||||
|
@ -58,7 +62,7 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "Només podeu importar de text net o HTML. Per a opcions d'importació més avançades <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">instal·leu l'Abiword</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "Només podeu importar de text sense format o HTML. Per a opcions d'importació més avançades <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">instal·leu l'Abiword</a>.",
|
||||
"pad.modals.connected": "Connectat.",
|
||||
"pad.modals.reconnecting": "S'està tornant a connectar al vostre pad…",
|
||||
"pad.modals.forcereconnect": "Força tornar a connectar",
|
||||
|
@ -82,6 +86,8 @@
|
|||
"pad.modals.corruptPad.cause": "Això pot ser degut a una configuració errònia del servidor o a algun altre comportament inesperat. Si us plau, contacteu amb l'administrador del servei.",
|
||||
"pad.modals.deleted": "Suprimit.",
|
||||
"pad.modals.deleted.explanation": "S'ha suprimit el pad.",
|
||||
"pad.modals.rateLimited": "Tarifa limitada.",
|
||||
"pad.modals.rateLimited.explanation": "Heu enviat massa missatges a aquest pad per això us han desconnectat.",
|
||||
"pad.modals.disconnected": "Heu estat desconnectat.",
|
||||
"pad.modals.disconnected.explanation": "S'ha perdut la connexió amb el servidor",
|
||||
"pad.modals.disconnected.cause": "El servidor sembla que no està disponible. Notifiqueu a l'administrador del servei si continua passant.",
|
||||
|
@ -94,6 +100,7 @@
|
|||
"pad.chat.loadmessages": "Carrega més missatges",
|
||||
"pad.chat.stick.title": "Ancora el xat a la pantalla",
|
||||
"pad.chat.writeMessage.placeholder": "Escriviu el vostre missatge a continuació",
|
||||
"timeslider.followContents": "Fer seguiment de les actualitzacions de contingut del bloc",
|
||||
"timeslider.pageTitle": "Línia temporal — {{appTitle}}",
|
||||
"timeslider.toolbar.returnbutton": "Torna al pad",
|
||||
"timeslider.toolbar.authors": "Autors:",
|
||||
|
@ -126,7 +133,7 @@
|
|||
"pad.userlist.guest": "Convidat",
|
||||
"pad.userlist.deny": "Refusa",
|
||||
"pad.userlist.approve": "Aprova",
|
||||
"pad.editbar.clearcolors": "Voleu netejar els colors d'autor del document sencer?",
|
||||
"pad.editbar.clearcolors": "Netejar els colors d'autor del document sencer?",
|
||||
"pad.impexp.importbutton": "Importa ara",
|
||||
"pad.impexp.importing": "Important...",
|
||||
"pad.impexp.confirmimport": "En importar un fitxer se sobreescriurà el text actual del pad. Esteu segur que voleu continuar?",
|
||||
|
@ -135,5 +142,7 @@
|
|||
"pad.impexp.uploadFailed": "Ha fallat la càrrega. Torneu-ho a provar",
|
||||
"pad.impexp.importfailed": "Ha fallat la importació",
|
||||
"pad.impexp.copypaste": "Si us plau, copieu i enganxeu",
|
||||
"pad.impexp.exportdisabled": "Està inhabilitada l'exportació com a {{type}}. Contacteu amb el vostre administrador de sistemes per a més informació."
|
||||
"pad.impexp.exportdisabled": "Està inhabilitada l'exportació com a {{type}}. Contacteu amb el vostre administrador de sistemes per a més informació.",
|
||||
"pad.impexp.maxFileSize": "Arxiu massa gran. Poseu-vos en contacte amb l'administrador del vostre lloc per augmentar la mida màxima dels fitxers importats",
|
||||
"pad.impexp.permission": "La importació està desactivada perquè mai heu contribuït a aquest bloc. Si us plau, contribuïu almenys un cop abans d'importar"
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
"pad.settings.fontType": "Skrifttype:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Sprog:",
|
||||
"pad.settings.about": "Om",
|
||||
"pad.settings.poweredBy": "Drevet af",
|
||||
"pad.importExport.import_export": "Import/Eksport",
|
||||
"pad.importExport.import": "Uploade en tekstfil eller dokument",
|
||||
"pad.importExport.importSuccessful": "Vellykket!",
|
||||
|
|
|
@ -2,17 +2,20 @@
|
|||
"@metadata": {
|
||||
"authors": [
|
||||
"Bjarncraft",
|
||||
"Dom",
|
||||
"Metalhead64",
|
||||
"Mklehr",
|
||||
"Nipsky",
|
||||
"Predatorix",
|
||||
"Sebastian Wallroth",
|
||||
"Thargon",
|
||||
"Tim.krieger",
|
||||
"Wikinaut"
|
||||
]
|
||||
},
|
||||
"index.newPad": "Neues Pad",
|
||||
"index.createOpenPad": "oder ein Pad mit folgendem Namen erstellen/öffnen:",
|
||||
"index.openPad": "Öffne ein vorhandenes Pad mit folgendem Namen:",
|
||||
"pad.toolbar.bold.title": "Fett (Strg-B)",
|
||||
"pad.toolbar.italic.title": "Kursiv (Strg-I)",
|
||||
"pad.toolbar.underline.title": "Unterstrichen (Strg-U)",
|
||||
|
@ -33,10 +36,10 @@
|
|||
"pad.colorpicker.save": "Speichern",
|
||||
"pad.colorpicker.cancel": "Abbrechen",
|
||||
"pad.loading": "Lade …",
|
||||
"pad.noCookie": "Das Cookie konnte nicht gefunden werden. Bitte erlaube Cookies in deinem Browser!",
|
||||
"pad.passwordRequired": "Sie benötigen ein Kennwort, um auf dieses Pad zuzugreifen",
|
||||
"pad.permissionDenied": "Sie haben keine Berechtigung, um auf dieses Pad zuzugreifen",
|
||||
"pad.wrongPassword": "Ihr eingegebenes Kennwort war falsch",
|
||||
"pad.noCookie": "Das Cookie konnte nicht gefunden werden. Bitte erlaube Cookies in deinem Browser! Deine Sitzung und Einstellungen werden zwischen den Besuchen nicht gespeichert. Dies kann darauf zurückzuführen sein, dass Etherpad in einigen Browsern in einem iFrame enthalten ist. Bitte stelle sicher, dass sich Etherpad auf der gleichen Subdomain/Domain wie der übergeordnete iFrame befindet.",
|
||||
"pad.passwordRequired": "Du benötigst ein Kennwort, um auf dieses Pad zuzugreifen",
|
||||
"pad.permissionDenied": "Du hast keine Berechtigung, um auf dieses Pad zuzugreifen",
|
||||
"pad.wrongPassword": "Dein eingegebenes Kennwort war falsch",
|
||||
"pad.settings.padSettings": "Pad-Einstellungen",
|
||||
"pad.settings.myView": "Eigene Ansicht",
|
||||
"pad.settings.stickychat": "Unterhaltung immer anzeigen",
|
||||
|
@ -47,8 +50,10 @@
|
|||
"pad.settings.fontType": "Schriftart:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Sprache:",
|
||||
"pad.settings.about": "Über",
|
||||
"pad.settings.poweredBy": "Powered by $1",
|
||||
"pad.importExport.import_export": "Import/Export",
|
||||
"pad.importExport.import": "Text-Datei oder Dokument hochladen",
|
||||
"pad.importExport.import": "Textdatei oder Dokument hochladen",
|
||||
"pad.importExport.importSuccessful": "Erfolgreich!",
|
||||
"pad.importExport.export": "Aktuelles Pad exportieren als:",
|
||||
"pad.importExport.exportetherpad": "Etherpad",
|
||||
|
@ -57,7 +62,7 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "Sie können nur aus reinen Text- oder HTML-Formaten importieren. Für umfangreichere Importfunktionen <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">installieren Sie bitte AbiWord oder LibreOffice</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "Du kannst nur aus reinen Text- oder HTML-Formaten importieren. Für umfangreichere Importfunktionen <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">muss AbiWord oder LibreOffice auf dem Server installiert werden</a>.",
|
||||
"pad.modals.connected": "Verbunden.",
|
||||
"pad.modals.reconnecting": "Wiederherstellen der Verbindung …",
|
||||
"pad.modals.forcereconnect": "Erneutes Verbinden erzwingen",
|
||||
|
@ -65,25 +70,27 @@
|
|||
"pad.modals.cancel": "Abbrechen",
|
||||
"pad.modals.userdup": "In einem anderen Fenster geöffnet",
|
||||
"pad.modals.userdup.explanation": "Dieses Pad scheint in mehr als einem Browser-Fenster auf diesem Rechner geöffnet zu sein.",
|
||||
"pad.modals.userdup.advice": "Um stattdessen dieses Fenster zu verwenden, verbinden Sie sich bitte erneut.",
|
||||
"pad.modals.userdup.advice": "Verbinde dich erneut, um stattdessen dieses Fenster zu verwenden.",
|
||||
"pad.modals.unauth": "Nicht berechtigt",
|
||||
"pad.modals.unauth.explanation": "Ihre Zugriffsberechtigung für dieses Pad hat sich zwischenzeitlich geändert. Versuchen Sie sich erneut zu verbinden.",
|
||||
"pad.modals.unauth.explanation": "Deine Zugriffsberechtigung für dieses Pad hat sich zwischenzeitlich geändert. Versuche dich erneut zu verbinden.",
|
||||
"pad.modals.looping.explanation": "Es gibt Verbindungsprobleme mit dem Server.",
|
||||
"pad.modals.looping.cause": "Möglicherweise sind Sie durch eine inkompatible Firewall oder über einen inkompatiblen Proxy mit dem Server verbunden.",
|
||||
"pad.modals.looping.cause": "Möglicherweise bist du durch eine inkompatible Firewall oder über einen inkompatiblen Proxy mit dem Server verbunden.",
|
||||
"pad.modals.initsocketfail": "Der Server ist nicht erreichbar.",
|
||||
"pad.modals.initsocketfail.explanation": "Es konnte keine Verbindung zum Server hergestellt werden.",
|
||||
"pad.modals.initsocketfail.cause": "Dies könnte an Ihrem Browser oder Ihrer Internet-Verbindung liegen.",
|
||||
"pad.modals.initsocketfail.cause": "Dies könnte an deinem Browser oder deiner Internet-Verbindung liegen.",
|
||||
"pad.modals.slowcommit.explanation": "Der Server antwortet nicht.",
|
||||
"pad.modals.slowcommit.cause": "Dies könnte ein Netzwerkverbindungsproblem sein oder eine momentane Überlastung des Servers.",
|
||||
"pad.modals.badChangeset.explanation": "Eine von Ihnen gemachte Änderung wurde vom Server als ungültig eingestuft.",
|
||||
"pad.modals.badChangeset.explanation": "Eine von dir gemachte Änderung wurde vom Server als ungültig eingestuft.",
|
||||
"pad.modals.badChangeset.cause": "Dies könnte aufgrund einer falschen Serverkonfiguration oder eines anderen unerwarteten Verhaltens passiert sein. Bitte kontaktiere den Diensteadministrator, falls du glaubst, dass es sich um einen Fehler handelt. Versuche dich erneut zu verbinden, um mit dem Bearbeiten fortzufahren.",
|
||||
"pad.modals.corruptPad.explanation": "Das Pad, auf das Sie versuchen zuzugreifen, ist beschädigt.",
|
||||
"pad.modals.corruptPad.cause": "Dies könnte an einer falschen Serverkonfiguration oder eines anderen unerwarteten Verhaltens liegen. Bitte kontaktieren Sie den Administrator dieses Dienstes.",
|
||||
"pad.modals.corruptPad.explanation": "Das Pad, auf das du versuchst zuzugreifen, ist beschädigt.",
|
||||
"pad.modals.corruptPad.cause": "Dies könnte an einer falschen Serverkonfiguration oder einem anderen unerwarteten Verhalten liegen. Bitte kontaktiere den Administrator dieses Dienstes.",
|
||||
"pad.modals.deleted": "Gelöscht.",
|
||||
"pad.modals.deleted.explanation": "Dieses Pad wurde entfernt.",
|
||||
"pad.modals.rateLimited": "Begrenzte Rate.",
|
||||
"pad.modals.rateLimited.explanation": "Sie haben zu viele Nachrichten an dieses Pad gesendet, so dass die Verbindung unterbrochen wurde.",
|
||||
"pad.modals.disconnected": "Ihre Verbindung wurde getrennt.",
|
||||
"pad.modals.disconnected.explanation": "Die Verbindung zum Server wurde unterbrochen.",
|
||||
"pad.modals.disconnected.cause": "Möglicherweise ist der Server nicht erreichbar. Bitte benachrichtigen Sie den Dienstadministrator, falls dies weiterhin passiert.",
|
||||
"pad.modals.disconnected.cause": "Möglicherweise ist der Server nicht erreichbar. Bitte benachrichtige den Dienstadministrator, falls dies weiterhin passiert.",
|
||||
"pad.share": "Dieses Pad teilen",
|
||||
"pad.share.readonly": "Eingeschränkter Nur-Lese-Zugriff",
|
||||
"pad.share.link": "Verknüpfung",
|
||||
|
@ -93,6 +100,7 @@
|
|||
"pad.chat.loadmessages": "Weitere Nachrichten laden",
|
||||
"pad.chat.stick.title": "Chat an den Bildschirm anheften",
|
||||
"pad.chat.writeMessage.placeholder": "Schreibe hier deine Nachricht",
|
||||
"timeslider.followContents": "Aktualisierungen des Pad-Inhalts verfolgen",
|
||||
"timeslider.pageTitle": "{{appTitle}} Bearbeitungsverlauf",
|
||||
"timeslider.toolbar.returnbutton": "Zurück zum Pad",
|
||||
"timeslider.toolbar.authors": "Autoren:",
|
||||
|
@ -102,8 +110,8 @@
|
|||
"timeslider.version": "Version {{version}}",
|
||||
"timeslider.saved": "Gespeichert am {{day}}. {{month}} {{year}}",
|
||||
"timeslider.playPause": "Padbearbeitung abspielen/pausieren",
|
||||
"timeslider.backRevision": "Eine Version in diesem Pad zurück gehen",
|
||||
"timeslider.forwardRevision": "Eine Version in diesem Pad vorwärts gehen",
|
||||
"timeslider.backRevision": "Eine Version in diesem Pad zurückgehen",
|
||||
"timeslider.forwardRevision": "Eine Version in diesem Pad vorwärtsgehen",
|
||||
"timeslider.dateformat": "{{day}}.{{month}}.{{year}} {{hours}}:{{minutes}}:{{seconds}}",
|
||||
"timeslider.month.january": "Januar",
|
||||
"timeslider.month.february": "Februar",
|
||||
|
@ -119,22 +127,22 @@
|
|||
"timeslider.month.december": "Dezember",
|
||||
"timeslider.unnamedauthors": "{{num}} {[plural(num) one: unbenannter Autor, other: unbenannte Autoren ]}",
|
||||
"pad.savedrevs.marked": "Diese Version wurde jetzt als gespeicherte Version gekennzeichnet",
|
||||
"pad.savedrevs.timeslider": "Du kannst gespeicherte Versionen durch den Aufruf des Bearbeitungsverlaufes ansehen",
|
||||
"pad.userlist.entername": "Geben Sie Ihren Namen ein",
|
||||
"pad.savedrevs.timeslider": "Du kannst gespeicherte Versionen durch den Aufruf des Bearbeitungsverlaufes ansehen.",
|
||||
"pad.userlist.entername": "Dein Name?",
|
||||
"pad.userlist.unnamed": "unbenannt",
|
||||
"pad.userlist.guest": "Gast",
|
||||
"pad.userlist.deny": "Verweigern",
|
||||
"pad.userlist.approve": "Genehmigen",
|
||||
"pad.editbar.clearcolors": "Autorenfarben im gesamten Dokument zurücksetzen?",
|
||||
"pad.editbar.clearcolors": "Autorenfarben im gesamten Dokument zurücksetzen? Dies kann nicht rückgängig gemacht werden",
|
||||
"pad.impexp.importbutton": "Jetzt importieren",
|
||||
"pad.impexp.importing": "Importiere …",
|
||||
"pad.impexp.confirmimport": "Das Importieren einer Datei überschreibt den aktuellen Text des Pads. Wollen Sie wirklich fortfahren?",
|
||||
"pad.impexp.convertFailed": "Diese Datei konnte nicht importiert werden. Bitte verwenden Sie ein anderes Dokumentformat oder übertragen Sie den Text manuell.",
|
||||
"pad.impexp.padHasData": "Diese Datei konnte nicht importiert werden, da dieses Pad bereits Änderungen enthält. Bitte importieren Sie die Datei in ein neues Pad.",
|
||||
"pad.impexp.uploadFailed": "Das Hochladen ist fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
||||
"pad.impexp.confirmimport": "Das Importieren einer Datei überschreibt den aktuellen Text des Pads. Willst du wirklich fortfahren?",
|
||||
"pad.impexp.convertFailed": "Diese Datei konnte nicht importiert werden. Bitte verwende ein anderes Dokumentformat oder übertrage den Text manuell.",
|
||||
"pad.impexp.padHasData": "Diese Datei konnte nicht importiert werden, da dieses Pad bereits Änderungen enthält. Bitte importiere die Datei in ein neues Pad.",
|
||||
"pad.impexp.uploadFailed": "Das Hochladen ist fehlgeschlagen. Bitte versuche es erneut.",
|
||||
"pad.impexp.importfailed": "Import fehlgeschlagen",
|
||||
"pad.impexp.copypaste": "Bitte kopieren und einfügen",
|
||||
"pad.impexp.exportdisabled": "Der Export im {{type}}-Format ist deaktiviert. Für Einzelheiten kontaktieren Sie bitte Ihren Systemadministrator.",
|
||||
"pad.impexp.maxFileSize": "Datei zu groß.Kontaktiere deinen Administrator um das datei Limit für Imports zu erhöhen.",
|
||||
"pad.impexp.permission": "Importieren ist deaktiviert weil du nichts zu diesem Pad beigeteagen hast.Bitte trage etwas bei bevor du importierst."
|
||||
"pad.impexp.exportdisabled": "Der Export im {{type}}-Format ist deaktiviert. Für Einzelheiten kontaktiere bitte deinen Systemadministrator.",
|
||||
"pad.impexp.maxFileSize": "Die Datei ist zu groß. Kontaktiere bitte deinen Administrator, um das Limit für den Dateiimport zu erhöhen.",
|
||||
"pad.impexp.permission": "Die Importfunktion ist deaktiviert, da du noch nichts zu diesem Pad beigetragen hast. Bitte trage etwas zu diesem Pad bei, bevor du importierst."
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
},
|
||||
"index.newPad": "Bloknoto newe",
|
||||
"index.createOpenPad": "ya zi be nê nameyi ra yew bloknot vıraze/ake:",
|
||||
"index.openPad": "yew Padê biyayeyi be nê nameyi ra ake:",
|
||||
"pad.toolbar.bold.title": "Qalınd (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Namıte (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "Bınxetın (Ctrl-U)",
|
||||
|
@ -32,7 +33,7 @@
|
|||
"pad.colorpicker.save": "Qeyd ke",
|
||||
"pad.colorpicker.cancel": "Bıtexelne",
|
||||
"pad.loading": "Bar beno...",
|
||||
"pad.noCookie": "Çerez nêvibeya. Rovıter de çereza aktiv kerê",
|
||||
"pad.noCookie": "Çerez nêvineya. Rovıter de çereza aktiv kerê.Ronıştısê u eyarê şıma mabênê ziyareti qeyd nêbenê.Çıkı, Etherpad tay rovıteran de tewrê yew iFrame belka biyo. Kerem ke Etherpad corên iFrame ya wa eyni bınca/ca de zey pê bo.",
|
||||
"pad.passwordRequired": "Ena bloknot resayışi rê parola icab krna",
|
||||
"pad.permissionDenied": "Ena bloknot resayışi rê icazeta şıma çıni ya",
|
||||
"pad.wrongPassword": "Parola şıma ğeleta",
|
||||
|
@ -46,6 +47,8 @@
|
|||
"pad.settings.fontType": "Babeta nuşti:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Zıwan:",
|
||||
"pad.settings.about": "Heqa",
|
||||
"pad.settings.poweredBy": "Pheştidayoğ",
|
||||
"pad.importExport.import_export": "Zerredayış/Teberdayış",
|
||||
"pad.importExport.import": "Dosya ya zi dokumanê meqaleyê de tesadufi bar ke",
|
||||
"pad.importExport.importSuccessful": "Mıwafaq biye",
|
||||
|
@ -80,6 +83,8 @@
|
|||
"pad.modals.corruptPad.cause": "Eno, xırab vıraziyena rovıteri yana nezanaye xırab yew faktori ra amrya meydan. Ena şıma çımdı xeta yena se idarekaran de sisteniya irtibat kewê",
|
||||
"pad.modals.deleted": "Esteriya.",
|
||||
"pad.modals.deleted.explanation": "Ena ped wedariye",
|
||||
"pad.modals.rateLimited": "Nısbeto kemeyeyın",
|
||||
"pad.modals.rateLimited.explanation": "Na pad re ßıma vêşi mesac rışto, coki ra irtibat bıriyayo.",
|
||||
"pad.modals.disconnected": "İrtibata şıma reyê",
|
||||
"pad.modals.disconnected.explanation": "Rovıteri ya irtibata şıma reyyê",
|
||||
"pad.modals.disconnected.cause": "Qay rovıtero nêkarên o. Ena xerpey deqam kena se idarekaranê sistemiya irtibat kewê",
|
||||
|
@ -92,6 +97,7 @@
|
|||
"pad.chat.loadmessages": "Dehana zaf mesaci bar keri",
|
||||
"pad.chat.stick.title": "Mobet ekran de bıvındarne",
|
||||
"pad.chat.writeMessage.placeholder": "Mesacê xo tiya bınusne",
|
||||
"timeslider.followContents": "Rocaney zerrekê padi taqib bıkerê",
|
||||
"timeslider.pageTitle": "Ğızagê zemani {{appTitle}}",
|
||||
"timeslider.toolbar.returnbutton": "Peyser şo ped",
|
||||
"timeslider.toolbar.authors": "Nuştoği:",
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
"Geraki",
|
||||
"Glavkos",
|
||||
"Monopatis",
|
||||
"Norhorn",
|
||||
"Protnet"
|
||||
]
|
||||
},
|
||||
"index.newPad": "Νέο Pad",
|
||||
"index.createOpenPad": "ή δημιουργία/άνοιγμα ενός Pad με όνομα:",
|
||||
"index.openPad": "άνοιγμα υπάρχων Pad με όνομα:",
|
||||
"pad.toolbar.bold.title": "Έντονη (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Πλάγια (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "Υπογράμμιση (Ctrl-U)",
|
||||
|
@ -30,10 +32,10 @@
|
|||
"pad.colorpicker.save": "Αποθήκευση",
|
||||
"pad.colorpicker.cancel": "Άκυρο",
|
||||
"pad.loading": "Φόρτωση...",
|
||||
"pad.noCookie": "Το cookie δεν βρέθηκε. Παρακαλώ επιτρέψτε τα cookies στον περιηγητή σας!",
|
||||
"pad.passwordRequired": "Χρειάζεστε κωδικό πρόσβασης για πρόσβαση σε αυτό το pad",
|
||||
"pad.noCookie": "Το cookie δεν βρέθηκε. Παρακαλώ επιτρέψτε τα cookies στον περιηγητή σας! Η περίοδος σύνδεσης και οι ρυθμίσεις σας δεν θα αποθηκευτούν μεταξύ των επισκέψεων. Αυτό μπορεί να οφείλεται στο ότι το Etherpad περιλαμβάνεται σε ένα iFrame σε ορισμένα προγράμματα περιήγησης. Βεβαιωθείτε ότι το Etherpad βρίσκεται στον ίδιο υποτομέα/τομέα με το γονικό iFrame",
|
||||
"pad.passwordRequired": "Χρειάζεστε συνθηματικό για πρόσβαση σε αυτό το pad",
|
||||
"pad.permissionDenied": "Δεν έχετε δικαίωμα πρόσβασης σε αυτό το pad",
|
||||
"pad.wrongPassword": "Ο κωδικός σας ήταν λανθασμένος",
|
||||
"pad.wrongPassword": "Το συνθηματικό σας ήταν λανθασμένο",
|
||||
"pad.settings.padSettings": "Ρυθμίσεις Pad",
|
||||
"pad.settings.myView": "Η προβολή μου",
|
||||
"pad.settings.stickychat": "Να είναι πάντα ορατή η συνομιλία",
|
||||
|
@ -44,8 +46,10 @@
|
|||
"pad.settings.fontType": "Τύπος γραμματοσειράς:",
|
||||
"pad.settings.fontType.normal": "Κανονική",
|
||||
"pad.settings.language": "Γλώσσα:",
|
||||
"pad.settings.about": "Σχετικά",
|
||||
"pad.settings.poweredBy": "Υποστηρίζεται από",
|
||||
"pad.importExport.import_export": "Εισαγωγή/Εξαγωγή",
|
||||
"pad.importExport.import": "Αποστολή οποιουδήποτε αρχείου κειμένου ή εγγράφου",
|
||||
"pad.importExport.import": "Μεταφόρτωση οποιουδήποτε αρχείου κειμένου ή εγγράφου",
|
||||
"pad.importExport.importSuccessful": "Επιτυχής!",
|
||||
"pad.importExport.export": "Εξαγωγή τρέχοντος pad ως:",
|
||||
"pad.importExport.exportetherpad": "Etherpad",
|
||||
|
@ -53,12 +57,12 @@
|
|||
"pad.importExport.exportplain": "Απλό κείμενο",
|
||||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Μορφή Open Document)",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "Μπορείτε να εισάγετε απλό κείμενο ή HTML. Για προηγμένες δυνατότητες εισαγωγής παρακαλούμε <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">εγκαταστήστε το AbiWord ή το LibreOffice</a>.",
|
||||
"pad.modals.connected": "Συνδεμένοι.",
|
||||
"pad.modals.reconnecting": "Επανασύνδεση στο pad σας...",
|
||||
"pad.modals.forcereconnect": "Επιβολή επανασύνδεσης",
|
||||
"pad.modals.reconnecttimer": "Επαναπροσπάθεια σε",
|
||||
"pad.modals.reconnecttimer": "Προσπάθεια επανασύνδεσης σε",
|
||||
"pad.modals.cancel": "Ακύρωση",
|
||||
"pad.modals.userdup": "Ανοιγμένο σε άλλο παράθυρο",
|
||||
"pad.modals.userdup.explanation": "Αυτό το pad φαίνεται να είναι ανοιχτό σε περισσότερα από ένα παράθυρο του προγράμματος περιήγησης σε αυτόν τον υπολογιστή.",
|
||||
|
@ -123,13 +127,15 @@
|
|||
"pad.userlist.deny": "Άρνηση",
|
||||
"pad.userlist.approve": "Έγκριση",
|
||||
"pad.editbar.clearcolors": "Να γίνει εκκαθάριση χρωμάτων σύνταξης σε ολόκληρο το έγγραφο; Αυτό δεν μπορεί να αναιρεθεί",
|
||||
"pad.impexp.importbutton": "Εισαγωγή Τώρα",
|
||||
"pad.impexp.importbutton": "Εισαγωγή τώρα",
|
||||
"pad.impexp.importing": "Εισάγεται...",
|
||||
"pad.impexp.confirmimport": "Η εισαγωγή ενός αρχείου θα αντικαταστήσει το κείμενο του pad. Είστε βέβαιοι ότι θέλετε να συνεχίσετε;",
|
||||
"pad.impexp.convertFailed": "Δεν καταφέραμε να εισάγουμε αυτό το αρχείο. Παρακαλώ χρησιμοποιήστε διαφορετικό τύπο αρχείου ή αντιγράψτε και επικολλήστε χειροκίνητα",
|
||||
"pad.impexp.padHasData": "Δεν μπορέσαμε να εισάγουμε το αρχείο επειδή το Pad είχε ήδη αλλαγές. Παρακαλούμε εισαγάγετε το αρχείο σε νέο pad",
|
||||
"pad.impexp.uploadFailed": "Η αποστολή απέτυχε, παρακαλώ προσπαθήστε ξανά",
|
||||
"pad.impexp.uploadFailed": "Η μεταφόρτωση απέτυχε, παρακαλούμε προσπαθήστε ξανά",
|
||||
"pad.impexp.importfailed": "Η εισαγωγή απέτυχε",
|
||||
"pad.impexp.copypaste": "Παρακαλώ αντιγράψτε και επικολλήστε",
|
||||
"pad.impexp.exportdisabled": "Η εξαγωγή σε μορφή {{type}} έχει απενεργοποιηθεί. Επικοινωνήστε με τον διαχειριστή του συστήματός σας για λεπτομέρειες."
|
||||
"pad.impexp.exportdisabled": "Η εξαγωγή σε μορφή {{type}} έχει απενεργοποιηθεί. Επικοινωνήστε με τον διαχειριστή του συστήματός σας για λεπτομέρειες.",
|
||||
"pad.impexp.maxFileSize": "Πολύ μεγάλο αρχείο. Επικοινωνήστε με τον διαχειριστή για να αυξήσετε το επιτρεπόμενο μέγεθος αρχείου",
|
||||
"pad.impexp.permission": "Η εισαγωγή είναι απενεργοποιημένη επειδή δεν συνεισφέρατε ποτέ σε αυτό το pad. Συνεισφέρετε τουλάχιστον μία φορά πριν από την εισαγωγή"
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"@metadata": {
|
||||
"authors": [
|
||||
"Andibing",
|
||||
"Bjh21",
|
||||
"Cblair91",
|
||||
"Chase me ladies, I'm the Cavalry",
|
||||
"HairyFotr",
|
||||
|
@ -30,7 +31,7 @@
|
|||
"pad.colorpicker.save": "Save",
|
||||
"pad.colorpicker.cancel": "Cancel",
|
||||
"pad.loading": "Loading...",
|
||||
"pad.noCookie": "Cookie could not be found. Please allow cookies in your browser!",
|
||||
"pad.noCookie": "Cookie could not be found. Please allow cookies in your browser! Your session and settings will not be saved between visits. This may be due to Etherpad being included in an iFrame in some Browsers. Please ensure Etherpad is on the same subdomain/domain as the parent iFrame",
|
||||
"pad.passwordRequired": "You need a password to access this pad",
|
||||
"pad.permissionDenied": "You do not have permission to access this pad",
|
||||
"pad.wrongPassword": "Your password was wrong",
|
||||
|
@ -54,7 +55,7 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "You only can import from plain text or HTML formats. For more advanced import features please <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">install AbiWord</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "You only can import from plain text or HTML formats. For more advanced import features please <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">install AbiWord or LibreOffice</a>.",
|
||||
"pad.modals.connected": "Connected.",
|
||||
"pad.modals.reconnecting": "Reconnecting to your pad..",
|
||||
"pad.modals.forcereconnect": "Force reconnect",
|
||||
|
@ -122,7 +123,7 @@
|
|||
"pad.userlist.guest": "Guest",
|
||||
"pad.userlist.deny": "Deny",
|
||||
"pad.userlist.approve": "Approve",
|
||||
"pad.editbar.clearcolors": "Clear authorship colours on entire document?",
|
||||
"pad.editbar.clearcolors": "Clear authorship colours on entire document? This cannot be undone",
|
||||
"pad.impexp.importbutton": "Import Now",
|
||||
"pad.impexp.importing": "Importing...",
|
||||
"pad.impexp.confirmimport": "Importing a file will overwrite the current text of the pad. Are you sure you want to proceed?",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"index.newPad": "New Pad",
|
||||
"index.createOpenPad": "or create/open a Pad with the name:",
|
||||
"index.openPad": "open an existing Pad with the name:",
|
||||
|
||||
"pad.toolbar.bold.title": "Bold (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "Italic (Ctrl+I)",
|
||||
|
@ -24,7 +25,7 @@
|
|||
"pad.colorpicker.cancel": "Cancel",
|
||||
|
||||
"pad.loading": "Loading...",
|
||||
"pad.noCookie": "Cookie could not be found. Please allow cookies in your browser!",
|
||||
"pad.noCookie": "Cookie could not be found. Please allow cookies in your browser! Your session and settings will not be saved between visits. This may be due to Etherpad being included in an iFrame in some Browsers. Please ensure Etherpad is on the same subdomain/domain as the parent iFrame",
|
||||
"pad.passwordRequired": "You need a password to access this pad",
|
||||
"pad.permissionDenied": "You do not have permission to access this pad",
|
||||
"pad.wrongPassword": "Your password was wrong",
|
||||
|
@ -39,6 +40,8 @@
|
|||
"pad.settings.fontType": "Font type:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Language:",
|
||||
"pad.settings.about": "About",
|
||||
"pad.settings.poweredBy": "Powered by",
|
||||
|
||||
"pad.importExport.import_export": "Import/Export",
|
||||
"pad.importExport.import": "Upload any text file or document",
|
||||
|
@ -84,6 +87,9 @@
|
|||
"pad.modals.deleted": "Deleted.",
|
||||
"pad.modals.deleted.explanation": "This pad has been removed.",
|
||||
|
||||
"pad.modals.rateLimited": "Rate Limited.",
|
||||
"pad.modals.rateLimited.explanation": "You sent too many messages to this pad so it disconnected you.",
|
||||
|
||||
"pad.modals.disconnected": "You have been disconnected.",
|
||||
"pad.modals.disconnected.explanation": "The connection to the server was lost",
|
||||
"pad.modals.disconnected.cause": "The server may be unavailable. Please notify the service administrator if this continues to happen.",
|
||||
|
@ -98,6 +104,7 @@
|
|||
"pad.chat.stick.title": "Stick chat to screen",
|
||||
"pad.chat.writeMessage.placeholder": "Write your message here",
|
||||
|
||||
"timeslider.followContents": "Follow pad content updates",
|
||||
"timeslider.pageTitle": "{{appTitle}} Timeslider",
|
||||
"timeslider.toolbar.returnbutton": "Return to pad",
|
||||
"timeslider.toolbar.authors": "Authors:",
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
"pad.settings.fontType": "Tipografía:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Idioma:",
|
||||
"pad.settings.about": "Acerca de",
|
||||
"pad.settings.poweredBy": "Funciona con",
|
||||
"pad.importExport.import_export": "Importar/Exportar",
|
||||
"pad.importExport.import": "Subir cualquier texto o documento",
|
||||
"pad.importExport.importSuccessful": "¡Éxito!",
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
"pad.settings.fontType": "Fonttityyppi:",
|
||||
"pad.settings.fontType.normal": "normaali",
|
||||
"pad.settings.language": "Kieli:",
|
||||
"pad.settings.about": "Tietoja",
|
||||
"pad.settings.poweredBy": "Palvelun mahdollistaa",
|
||||
"pad.importExport.import_export": "Tuonti/vienti",
|
||||
"pad.importExport.import": "Lähetä mikä tahansa tekstitiedosto tai asiakirja",
|
||||
"pad.importExport.importSuccessful": "Onnistui!",
|
||||
|
@ -63,7 +65,7 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "Tuonti on tuettu vain HTML- ja raakatekstitiedostoista. Monipuoliset tuontiominaisuudet ovat käytettävissä <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">asentamalla AbiWord</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "Tuonti on tuettu vain HTML- ja raakatekstitiedostoista. Monipuoliset tuontiominaisuudet ovat käytettävissä <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">asentamalla AbiWordin tai LibreOfficen</a>.",
|
||||
"pad.modals.connected": "Yhdistetty.",
|
||||
"pad.modals.reconnecting": "Muodostetaan yhteyttä muistioon uudelleen...",
|
||||
"pad.modals.forcereconnect": "Pakota yhdistämään uudelleen",
|
||||
|
@ -131,7 +133,7 @@
|
|||
"pad.userlist.guest": "Vieras",
|
||||
"pad.userlist.deny": "Estä",
|
||||
"pad.userlist.approve": "Hyväksy",
|
||||
"pad.editbar.clearcolors": "Poistetaanko asiakirjasta tekijävärit?",
|
||||
"pad.editbar.clearcolors": "Poistetaanko asiakirjasta tekijävärit? Tätä ei voi perua",
|
||||
"pad.impexp.importbutton": "Tuo nyt",
|
||||
"pad.impexp.importing": "Tuodaan...",
|
||||
"pad.impexp.confirmimport": "Tiedoston tuonti korvaa kaiken muistiossa olevan tekstin. Haluatko varmasti jatkaa?",
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"Quenenni",
|
||||
"Rastus Vernon",
|
||||
"Stephane Cottin",
|
||||
"Thibaut120094",
|
||||
"Tux-tn",
|
||||
"Urhixidur",
|
||||
"Verdy p",
|
||||
|
@ -30,6 +31,7 @@
|
|||
},
|
||||
"index.newPad": "Nouveau bloc-notes",
|
||||
"index.createOpenPad": "ou créer/ouvrir un bloc-notes intitulé :",
|
||||
"index.openPad": "ouvrir un Pad existant avec le nom :",
|
||||
"pad.toolbar.bold.title": "Gras (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "Italique (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "Souligné (Ctrl+U)",
|
||||
|
@ -50,7 +52,7 @@
|
|||
"pad.colorpicker.save": "Enregistrer",
|
||||
"pad.colorpicker.cancel": "Annuler",
|
||||
"pad.loading": "Chargement...",
|
||||
"pad.noCookie": "Un cookie n’a pas pu être trouvé. Veuillez autoriser les fichiers témoins (ou cookies) dans votre navigateur !",
|
||||
"pad.noCookie": "Un cookie n’a pas pu être trouvé. Veuillez autoriser les fichiers témoins (ou cookies) dans votre navigateur ! Votre session et vos paramètres ne seront pas enregistrés entre les visites. Cela peut être dû au fait qu’Etehrpad est inclus dans un iFrame dans certains navigateurs. Veuillez vous assurer que Etherpad est dans le même sous-domaine/domaine que son iFrame parent",
|
||||
"pad.passwordRequired": "Vous avez besoin d'un mot de passe pour accéder à ce bloc-note",
|
||||
"pad.permissionDenied": "Vous n’êtes pas autorisé à accéder à ce bloc-notes",
|
||||
"pad.wrongPassword": "Votre mot de passe est incorrect",
|
||||
|
@ -64,6 +66,8 @@
|
|||
"pad.settings.fontType": "Police :",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Langue :",
|
||||
"pad.settings.about": "À propos",
|
||||
"pad.settings.poweredBy": "Fourni par",
|
||||
"pad.importExport.import_export": "Importer/Exporter",
|
||||
"pad.importExport.import": "Charger un texte ou un document",
|
||||
"pad.importExport.importSuccessful": "Réussi !",
|
||||
|
@ -98,6 +102,8 @@
|
|||
"pad.modals.corruptPad.cause": "Cela peut être dû à une mauvaise configuration du serveur ou à un autre comportement inattendu. Veuillez contacter l’administrateur du service.",
|
||||
"pad.modals.deleted": "Supprimé.",
|
||||
"pad.modals.deleted.explanation": "Ce bloc-notes a été supprimé.",
|
||||
"pad.modals.rateLimited": "Taux limité.",
|
||||
"pad.modals.rateLimited.explanation": "Vous avez envoyé trop de messages à ce bloc, il vous a donc déconnecté.",
|
||||
"pad.modals.disconnected": "Vous avez été déconnecté.",
|
||||
"pad.modals.disconnected.explanation": "La connexion au serveur a échoué.",
|
||||
"pad.modals.disconnected.cause": "Il se peut que le serveur soit indisponible. Si le problème persiste, veuillez en informer l’administrateur du service.",
|
||||
|
@ -110,6 +116,7 @@
|
|||
"pad.chat.loadmessages": "Charger davantage de messages",
|
||||
"pad.chat.stick.title": "Ancrer la discussion sur l’écran",
|
||||
"pad.chat.writeMessage.placeholder": "Entrez votre message ici",
|
||||
"timeslider.followContents": "Suivre les mises à jour de contenu du bloc",
|
||||
"timeslider.pageTitle": "Historique dynamique de {{appTitle}}",
|
||||
"timeslider.toolbar.returnbutton": "Retourner au bloc-notes",
|
||||
"timeslider.toolbar.authors": "Auteurs :",
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
"authors": [
|
||||
"Amire80",
|
||||
"Ofrahod",
|
||||
"Steeve815",
|
||||
"YaronSh",
|
||||
"תומר ט"
|
||||
]
|
||||
},
|
||||
"index.newPad": "פנקס חדש",
|
||||
"index.createOpenPad": "ליצור או לפתוח פנקס בשם:",
|
||||
"index.openPad": "פתיחת פנקס קיים עם השם:",
|
||||
"pad.toolbar.bold.title": "בולט (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "נטוי (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "קו תחתי (Ctrl-U)",
|
||||
|
@ -43,6 +45,7 @@
|
|||
"pad.settings.fontType": "סוג גופן:",
|
||||
"pad.settings.fontType.normal": "רגיל",
|
||||
"pad.settings.language": "שפה:",
|
||||
"pad.settings.about": "על אודות",
|
||||
"pad.importExport.import_export": "ייבוא/ייצוא",
|
||||
"pad.importExport.import": "העלאת כל קובץ טקסט או מסמך",
|
||||
"pad.importExport.importSuccessful": "זה עבד!",
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
},
|
||||
"index.newPad": "Novi blokić",
|
||||
"index.createOpenPad": "ili stvori/otvori blokić s imenom:",
|
||||
"index.openPad": "otvori postojeći blokić Etherpada s imenom:",
|
||||
"pad.toolbar.bold.title": "Masno (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "Ukošeno (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "Podcrtano (Ctrl+U)",
|
||||
|
@ -27,7 +28,7 @@
|
|||
"pad.colorpicker.save": "Spremi",
|
||||
"pad.colorpicker.cancel": "Otkaži",
|
||||
"pad.loading": "Učitavanje...",
|
||||
"pad.noCookie": "Kolačić nije pronađen. Molimo Vas da uključite kolačiće u Vašem pregledniku!",
|
||||
"pad.noCookie": "Kolačić nije pronađen. Molimo Vas, omogućite kolačiće u Vašem pregledniku! Sesija i postavke neće biti sačuvane između Vaših posjećivanja. Razlog može biti uključenost Etherpada u iFrame u nekim preglednicima. Molimo Vas, osigurajte da je Etherpad na istoj poddomeni/domeni kao i ''roditeljski'' iFrame.",
|
||||
"pad.passwordRequired": "Potrebna Vam je zaporka za pristup ovomu blokiću",
|
||||
"pad.permissionDenied": "Nemate dopuštenje za pristup ovome blokiću",
|
||||
"pad.wrongPassword": "Vaša zaporka nije valjana",
|
||||
|
@ -39,7 +40,10 @@
|
|||
"pad.settings.linenocheck": "Brojevi redaka",
|
||||
"pad.settings.rtlcheck": "Želite li prikaz sadržaja s desna na lijevo?",
|
||||
"pad.settings.fontType": "Vrsta fonta:",
|
||||
"pad.settings.fontType.normal": "Normalna",
|
||||
"pad.settings.language": "Jezik:",
|
||||
"pad.settings.about": "O projektu",
|
||||
"pad.settings.poweredBy": "Proizvod Vam pruža",
|
||||
"pad.importExport.import_export": "Uvoz/Izvoz",
|
||||
"pad.importExport.import": "Postavite bilo koju tekstualnu datoteku ili dokument",
|
||||
"pad.importExport.importSuccessful": "Uspješno!",
|
||||
|
@ -50,7 +54,7 @@
|
|||
"pad.importExport.exportword": "Datoteku programa Microsoft Word",
|
||||
"pad.importExport.exportpdf": "Datoteku Acrobatova PDF formata",
|
||||
"pad.importExport.exportopen": "Datoteku formata Open Document (ODF)",
|
||||
"pad.importExport.abiword.innerHTML": "Možete uvoziti datoteke formata za obični tekst (bez oblikovanja) te datoteke u HTML-u. Za naprednije mogućnosti uvoza molimo Vas, instalirajte <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">program AbiWord</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "Možete uvoziti samo datoteke formata za obični tekst (bez oblikovanja) te datoteke u formatima HTML-a. Za naprednije mogućnosti uvoza, molimo Vas, instalirajte <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">program AbiWord ili LibreOffice</a>.",
|
||||
"pad.modals.connected": "Povezano.",
|
||||
"pad.modals.reconnecting": "Ponovo Vas povezujemo s Vašim blokićem...",
|
||||
"pad.modals.forcereconnect": "Prisilno se ponovo poveži",
|
||||
|
@ -74,6 +78,8 @@
|
|||
"pad.modals.corruptPad.cause": "Moguće je došlo do pogrješne konfiguracije poslužitelja ili nekog drugog neočekivanog događaja ili postupka. Molimo Vas, kontaktirajte administratora usluge.",
|
||||
"pad.modals.deleted": "Pobrisano.",
|
||||
"pad.modals.deleted.explanation": "Blokić je bio uklonjen.",
|
||||
"pad.modals.rateLimited": "Brzina slanja poruka na blokić je ograničena.",
|
||||
"pad.modals.rateLimited.explanation": "Poslali ste previše poruka na ovaj blokić, te ste stoga odspojeni.",
|
||||
"pad.modals.disconnected": "Vaša je veza prekinuta.",
|
||||
"pad.modals.disconnected.explanation": "Veza s poslužiteljem je izgubljena.",
|
||||
"pad.modals.disconnected.cause": "Moguće je da poslužitelj nije dostupan. Molimo Vas, obavijestite administratora usluge ukoliko se to nastavi događati.",
|
||||
|
@ -86,6 +92,7 @@
|
|||
"pad.chat.loadmessages": "Učitaj više poruka",
|
||||
"pad.chat.stick.title": "Prilijepi razgovor na zaslon",
|
||||
"pad.chat.writeMessage.placeholder": "Napišite Vašu poruku ovdje",
|
||||
"timeslider.followContents": "Prati ažuriranja sadržaja blokića",
|
||||
"timeslider.pageTitle": "{{appTitle}} Vremenska lenta",
|
||||
"timeslider.toolbar.returnbutton": "Vrati se natrag na blokić",
|
||||
"timeslider.toolbar.authors": "Autori:",
|
||||
|
@ -127,5 +134,7 @@
|
|||
"pad.impexp.uploadFailed": "Postavljanje nije uspjelo. molimo Vas, pokušajte ponovo",
|
||||
"pad.impexp.importfailed": "Uvoz nije uspio",
|
||||
"pad.impexp.copypaste": "Molimo preslikajte/zalijepite",
|
||||
"pad.impexp.exportdisabled": "Izvoz u formatu {{type}} nije omogućen. Molimo Vas, kontaktirajte Vašega administratora sustava za više pojedinosti."
|
||||
"pad.impexp.exportdisabled": "Izvoz u formatu {{type}} nije omogućen. Molimo Vas, kontaktirajte Vašega administratora sustava za više pojedinosti.",
|
||||
"pad.impexp.maxFileSize": "Datoteka je prevelika. Kontaktirajte administratora Vašega mrežnoga sjedišta kako biste zatražili povećanje dopuštene veličine datoteke za uvoz",
|
||||
"pad.impexp.permission": "Uvoz je onemogućen jer niste doprinosili ovom blokiću Etherpada. Molimo Vas, doprinosite barem jednom prije radnje uvoza"
|
||||
}
|
||||
|
|
|
@ -7,18 +7,20 @@
|
|||
"Dj",
|
||||
"Misibacsi",
|
||||
"Notramo",
|
||||
"Ovari",
|
||||
"R-Joe",
|
||||
"Tgr"
|
||||
]
|
||||
},
|
||||
"index.newPad": "Új notesz",
|
||||
"index.createOpenPad": "vagy notesz létrehozása/megnyitása ezzel a névvel:",
|
||||
"index.newPad": "Új jegyzetfüzet",
|
||||
"index.createOpenPad": "vagy jegyzetfüzet létrehozása/megnyitása ezzel a névvel:",
|
||||
"index.openPad": "nyisson meg egy meglévő jegyzetfüzetet névvel:",
|
||||
"pad.toolbar.bold.title": "Félkövér (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "Dőlt (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "Aláhúzás (Ctrl+U)",
|
||||
"pad.toolbar.strikethrough.title": "Áthúzás (Ctrl+5)",
|
||||
"pad.toolbar.ol.title": "Számozott lista (Ctrl+Shift+N)",
|
||||
"pad.toolbar.ul.title": "Számozatlan lista (Ctrl+Shift+L)",
|
||||
"pad.toolbar.ol.title": "Rendezett lista (Ctrl+Shift+N)",
|
||||
"pad.toolbar.ul.title": "Rendezetlen lista (Ctrl+Shift+L)",
|
||||
"pad.toolbar.indent.title": "Behúzás növelése (TAB)",
|
||||
"pad.toolbar.unindent.title": "Behúzás csökkentése (Shift+TAB)",
|
||||
"pad.toolbar.undo.title": "Visszavonás (Ctrl-Z)",
|
||||
|
@ -28,16 +30,16 @@
|
|||
"pad.toolbar.timeslider.title": "Időcsúszka",
|
||||
"pad.toolbar.savedRevision.title": "Revízió mentése",
|
||||
"pad.toolbar.settings.title": "Beállítások",
|
||||
"pad.toolbar.embed.title": "Notesz beágyazása és megosztása",
|
||||
"pad.toolbar.showusers.title": "Notesz felhasználóinak megmutatása",
|
||||
"pad.toolbar.embed.title": "Jegyzetfüzet beágyazása és megosztása",
|
||||
"pad.toolbar.showusers.title": "Jegyzetfüzet felhasználóinak megmutatása",
|
||||
"pad.colorpicker.save": "Mentés",
|
||||
"pad.colorpicker.cancel": "Mégsem",
|
||||
"pad.loading": "Betöltés…",
|
||||
"pad.noCookie": "Nem található a süti. Engedélyezd a böngésződben a sütik használatát!",
|
||||
"pad.passwordRequired": "Jelszóra van szükséged ezen notesz eléréséhez",
|
||||
"pad.permissionDenied": "Nincs engedélyed ezen notesz eléréséhez",
|
||||
"pad.noCookie": "Nem található a süti. Engedélyezd a böngésződben a sütik használatát! A munkamenet és a beállítások nem kerülnek mentésre a látogatások között. Ennek oka lehet az, hogy az Etherpad egyes böngészőkben szerepel az iFrame-ben. Ellenőrizze, hogy az Etherpad ugyanabban az altartomány / tartományban van-e, mint a szülő iFrame",
|
||||
"pad.passwordRequired": "Jelszóra van szükséged ezen jegyzetfüzet eléréséhez",
|
||||
"pad.permissionDenied": "Nincs engedélyed ezen jegyzetfüzet eléréséhez",
|
||||
"pad.wrongPassword": "A jelszó rossz volt",
|
||||
"pad.settings.padSettings": "Notesz beállításai",
|
||||
"pad.settings.padSettings": "Jegyzetfüzet beállításai",
|
||||
"pad.settings.myView": "Az én nézetem",
|
||||
"pad.settings.stickychat": "Mindig mutasd a csevegés-dobozt",
|
||||
"pad.settings.chatandusers": "Csevegés és felhasználók mutatása",
|
||||
|
@ -47,24 +49,26 @@
|
|||
"pad.settings.fontType": "Betűtípus:",
|
||||
"pad.settings.fontType.normal": "Szokásos",
|
||||
"pad.settings.language": "Nyelv:",
|
||||
"pad.settings.about": "Névjegy",
|
||||
"pad.settings.poweredBy": "Működteti",
|
||||
"pad.importExport.import_export": "Import/export",
|
||||
"pad.importExport.import": "Tetszőleges szövegfájl vagy dokumentum feltöltése",
|
||||
"pad.importExport.importSuccessful": "Siker!",
|
||||
"pad.importExport.export": "Jelenlegi notesz exportálása így:",
|
||||
"pad.importExport.export": "Jelenlegi jegyzetfüzet exportálása így:",
|
||||
"pad.importExport.exportetherpad": "Etherpad",
|
||||
"pad.importExport.exporthtml": "HTML",
|
||||
"pad.importExport.exportplain": "Sima szöveg",
|
||||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document formátum)",
|
||||
"pad.importExport.abiword.innerHTML": "Csak szöveges, vagy HTML formátumokból importálhatsz. A speciális importálási funkciókért kérjük <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">telepítsd az AbiWord-öt</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "Csak szöveges, vagy HTML formátumokból importálhat. A haladó importálási szolgáltatásért kérjük <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">telepítse a AbiWord vagy a LibreOffice alkalmazást</a>.",
|
||||
"pad.modals.connected": "Kapcsolódva.",
|
||||
"pad.modals.reconnecting": "Újrakapcsolódás a noteszhez...",
|
||||
"pad.modals.reconnecting": "Újrakapcsolódás a jegyzetfüzethez…",
|
||||
"pad.modals.forcereconnect": "Újrakapcsolódás kényszerítése",
|
||||
"pad.modals.reconnecttimer": "Megpróbálok újracsatlakozni ennyi múlva:",
|
||||
"pad.modals.cancel": "Mégse",
|
||||
"pad.modals.userdup": "Új ablakban megnyitva",
|
||||
"pad.modals.userdup.explanation": "Úgy tűnik, ez a notesz több különböző böngészőablakban is meg van nyitva a számítógépeden.",
|
||||
"pad.modals.userdup.explanation": "Úgy tűnik, ez a jegyzetfüzet több különböző böngészőablakban is meg van nyitva a számítógépeden.",
|
||||
"pad.modals.userdup.advice": "Kapcsolódj újra, ha ezt az ablakot akarod használni.",
|
||||
"pad.modals.unauth": "Nincs rá jogosultságod",
|
||||
"pad.modals.unauth.explanation": "A jogosultságaid megváltoztak, miközben ezt az oldalt nézted. Próbálj meg újrakapcsolódni!",
|
||||
|
@ -77,34 +81,37 @@
|
|||
"pad.modals.slowcommit.cause": "Valószínűleg az internetkapcsolattal van probléma.",
|
||||
"pad.modals.badChangeset.explanation": "Szerkesztéseded a szinkronizációs szerver illegálisnak sorolta be.",
|
||||
"pad.modals.badChangeset.cause": "Ennek oka lehet egy rossz szerver konfiguráció, vagy más váratlan viselkedés. Ha úgy érzi, ez hiba eredménye, lépjen kapcsolatba a szolgáltatás adminisztrátorával. Próbáljon meg újrakapcsolódni a szerkesztés folytatásához.",
|
||||
"pad.modals.corruptPad.explanation": "A notesz, amit megpróbálsz elérni, sérült.",
|
||||
"pad.modals.corruptPad.explanation": "A jegyzetfüzet, amit megpróbálsz elérni, sérült.",
|
||||
"pad.modals.corruptPad.cause": "Ennek oka lehet egy rossz szerver konfiguráció, vagy más váratlan viselkedés. Kérjük, lépj kapcsolatba a szolgáltatás adminisztrátorával.",
|
||||
"pad.modals.deleted": "Törölve.",
|
||||
"pad.modals.deleted.explanation": "Ez a notesz el lett távolítva.",
|
||||
"pad.modals.deleted.explanation": "Ez a jegyzetfüzet el lett távolítva.",
|
||||
"pad.modals.rateLimited": "Korlátozott.",
|
||||
"pad.modals.rateLimited.explanation": "Túl sok üzenetet küldött erre a jegyzetfüzetre, így a kapcsolat bontva lett.",
|
||||
"pad.modals.disconnected": "Kapcsolat bontva.",
|
||||
"pad.modals.disconnected.explanation": "A szerverrel való kapcsolat megszűnt",
|
||||
"pad.modals.disconnected.cause": "Lehet, hogy a szerver nem elérhető. Kérlek, értesítsd a szolgáltatás adminisztrátorát, ha a probléma tartósan fennáll.",
|
||||
"pad.share": "Notesz megosztása",
|
||||
"pad.share": "Jegyzetfüzet megosztása",
|
||||
"pad.share.readonly": "Csak olvasható",
|
||||
"pad.share.link": "Hivatkozás",
|
||||
"pad.share.emebdcode": "URL beágyazása",
|
||||
"pad.chat": "Csevegés",
|
||||
"pad.chat.title": "A noteszhez tartozó csevegés megnyitása.",
|
||||
"pad.chat.title": "A jegyzetfüzethez tartozó csevegés megnyitása.",
|
||||
"pad.chat.loadmessages": "További üzenetek betöltése",
|
||||
"pad.chat.stick.title": "Csevegés a képernyőre",
|
||||
"pad.chat.writeMessage.placeholder": "Írja az üzenetét ide",
|
||||
"timeslider.followContents": "Kövesse a jegyzetfüzet tartalmának frissítéseit",
|
||||
"timeslider.pageTitle": "{{appTitle}} időcsúszka",
|
||||
"timeslider.toolbar.returnbutton": "Vissza a noteszhez",
|
||||
"timeslider.toolbar.returnbutton": "Vissza a jegyzetfüzethez",
|
||||
"timeslider.toolbar.authors": "Szerzők:",
|
||||
"timeslider.toolbar.authorsList": "Nincsenek szerzők",
|
||||
"timeslider.toolbar.exportlink.title": "Exportálás",
|
||||
"timeslider.exportCurrent": "Jelenlegi változat exportálása így:",
|
||||
"timeslider.version": "{{version}} verzió",
|
||||
"timeslider.saved": "{{year}}. {{month}} {{day}}-n elmentve",
|
||||
"timeslider.playPause": "Notesz tartalom visszajátszása / leállítása",
|
||||
"timeslider.backRevision": "Egy revízióval vissza a noteszben",
|
||||
"timeslider.forwardRevision": "Egy revízióval előre a noteszben",
|
||||
"timeslider.dateformat": "{{year}}/{{month}}/{{day}} {{hours}}:{{minutes}}:{{seconds}}",
|
||||
"timeslider.playPause": "Jegyzetfüzet tartalom visszajátszása/leállítása",
|
||||
"timeslider.backRevision": "Egy revízióval vissza a jegyzetfüzetben",
|
||||
"timeslider.forwardRevision": "Egy revízióval előre a jegyzetfüzetben",
|
||||
"timeslider.dateformat": "{{year}}.{{month}}.{{day}}. {{hours}}:{{minutes}}:{{seconds}}",
|
||||
"timeslider.month.january": "január",
|
||||
"timeslider.month.february": "február",
|
||||
"timeslider.month.march": "március",
|
||||
|
@ -125,14 +132,16 @@
|
|||
"pad.userlist.guest": "Vendég",
|
||||
"pad.userlist.deny": "Megtagad",
|
||||
"pad.userlist.approve": "Jóváhagy",
|
||||
"pad.editbar.clearcolors": "A szerzőséget jelző színeket törlöd a teljes dokumentumból?",
|
||||
"pad.editbar.clearcolors": "A szerzőséget jelző színeket törli a teljes dokumentumból? Ez nem vonható vissza.",
|
||||
"pad.impexp.importbutton": "Importálás most",
|
||||
"pad.impexp.importing": "Importálás…",
|
||||
"pad.impexp.confirmimport": "Egy fájl importálása felülírja a jelenlegi szöveget a noteszben. Biztos hogy folytatod?",
|
||||
"pad.impexp.confirmimport": "Egy fájl importálása felülírja a jelenlegi szöveget a jegyzetfüzetben. Biztosan folytatja?",
|
||||
"pad.impexp.convertFailed": "Nem tudtuk importálni ezt a fájlt. Kérjük, használj másik dokumentum formátumot, vagy kézzel másold és illeszd be a tartalmat",
|
||||
"pad.impexp.padHasData": "Nem tudjuk importálni ezt a fájlt, mert ez a notesz már megváltozott, kérjük, importálj egy új noteszba.",
|
||||
"pad.impexp.padHasData": "Nem tudjuk importálni ezt a fájlt, mert ez a jegyzetfüzet már megváltozott, kérjük, importálj egy új jegyzetfüzetbe.",
|
||||
"pad.impexp.uploadFailed": "A feltöltés sikertelen, próbáld meg újra",
|
||||
"pad.impexp.importfailed": "Az importálás nem sikerült",
|
||||
"pad.impexp.copypaste": "Kérjük másold be",
|
||||
"pad.impexp.exportdisabled": "{{type}} formátumba az exportálás nem engedélyezett. Kérjük, a részletekért fordulj a rendszeradminisztrátorhoz."
|
||||
"pad.impexp.exportdisabled": "{{type}} formátumba az exportálás nem engedélyezett. Kérjük, a részletekért fordulj a rendszeradminisztrátorhoz.",
|
||||
"pad.impexp.maxFileSize": "Túl nagy a fájl. Vegye fel a kapcsolatot a webhelygazdájával, hogy növelje az importálható fájl méretét",
|
||||
"pad.impexp.permission": "Az importálás le van tiltva, mert soha nem járult hozzá ehhez a jegyzetfüzethez. Kérjük, járuljon hozzá legalább egyszer az importálás előtt"
|
||||
}
|
||||
|
|
|
@ -3,25 +3,27 @@
|
|||
"authors": [
|
||||
"Beta16",
|
||||
"Gianfranco",
|
||||
"Jack",
|
||||
"Macofe",
|
||||
"Muxator",
|
||||
"Nivit",
|
||||
"Vituzzu"
|
||||
]
|
||||
},
|
||||
"index.newPad": "Nuovo Pad",
|
||||
"index.createOpenPad": "o creare o aprire un Pad con il nome:",
|
||||
"pad.toolbar.bold.title": "Grassetto (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Corsivo (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "Sottolineato (Ctrl-U)",
|
||||
"index.newPad": "Nuovo pad",
|
||||
"index.createOpenPad": "o crea/apre un pad con il nome:",
|
||||
"index.openPad": "apri un Pad esistente col nome:",
|
||||
"pad.toolbar.bold.title": "Grassetto (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "Corsivo (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "Sottolineato (Ctrl+U)",
|
||||
"pad.toolbar.strikethrough.title": "Barrato (Ctrl+5)",
|
||||
"pad.toolbar.ol.title": "Elenco numerato (Ctrl+Shift+N)",
|
||||
"pad.toolbar.ul.title": "Elenco puntato (Ctrl+Shift+L)",
|
||||
"pad.toolbar.indent.title": "Indentazione (TAB)",
|
||||
"pad.toolbar.unindent.title": "Riduci indentazione (Shift+TAB)",
|
||||
"pad.toolbar.undo.title": "Annulla (Ctrl-Z)",
|
||||
"pad.toolbar.redo.title": "Ripeti (Ctrl-Y)",
|
||||
"pad.toolbar.clearAuthorship.title": "Elimina i colori che indicano gli autori (Ctrl+Shift+C)",
|
||||
"pad.toolbar.undo.title": "Annulla (Ctrl+Z)",
|
||||
"pad.toolbar.redo.title": "Ripeti (Ctrl+Y)",
|
||||
"pad.toolbar.clearAuthorship.title": "Elimina i colori degli autori (Ctrl+Shift+C)",
|
||||
"pad.toolbar.import_export.title": "Importa/esporta da/a diversi formati di file",
|
||||
"pad.toolbar.timeslider.title": "Presentazione cronologia",
|
||||
"pad.toolbar.savedRevision.title": "Versione salvata",
|
||||
|
@ -31,7 +33,7 @@
|
|||
"pad.colorpicker.save": "Salva",
|
||||
"pad.colorpicker.cancel": "Annulla",
|
||||
"pad.loading": "Caricamento in corso…",
|
||||
"pad.noCookie": "Il cookie non è stato trovato. Consenti i cookie nel tuo browser!",
|
||||
"pad.noCookie": "Il cookie non è stato trovato. Consenti i cookie nel tuo browser! La sessione e le impostazioni non verranno salvate tra le diverse visite. Ciò può essere dovuto al fatto che Etherpad è stato incluso in un iFrame in alcuni browser. Assicurati che Etherpad si trovi sullo stesso sottodominio/dominio dell'iFrame principale",
|
||||
"pad.passwordRequired": "Per accedere a questo Pad è necessaria una password",
|
||||
"pad.permissionDenied": "Non si dispone dei permessi necessari per accedere a questo Pad",
|
||||
"pad.wrongPassword": "La password è sbagliata",
|
||||
|
@ -45,6 +47,8 @@
|
|||
"pad.settings.fontType": "Tipo di carattere:",
|
||||
"pad.settings.fontType.normal": "Normale",
|
||||
"pad.settings.language": "Lingua:",
|
||||
"pad.settings.about": "Informazioni",
|
||||
"pad.settings.poweredBy": "Realizzato con",
|
||||
"pad.importExport.import_export": "Importazione/esportazione",
|
||||
"pad.importExport.import": "Carica un file di testo o un documento",
|
||||
"pad.importExport.importSuccessful": "Riuscito!",
|
||||
|
@ -70,9 +74,9 @@
|
|||
"pad.modals.looping.cause": "Forse sei connesso attraverso un firewall o un server proxy non compatibili.",
|
||||
"pad.modals.initsocketfail": "Il server non è raggiungibile.",
|
||||
"pad.modals.initsocketfail.explanation": "Impossibile connettersi al server di sincronizzazione.",
|
||||
"pad.modals.initsocketfail.cause": "Questo probabilmente è dovuto a un problema con il tuo browser o con la tua connessione a internet.",
|
||||
"pad.modals.initsocketfail.cause": "Questo probabilmente è dovuto a un problema con il browser o con la tua connessione internet.",
|
||||
"pad.modals.slowcommit.explanation": "Il server non risponde.",
|
||||
"pad.modals.slowcommit.cause": "Questo potrebbe essere dovuto a problemi con la connettività di rete.",
|
||||
"pad.modals.slowcommit.cause": "Questo potrebbe essere dovuto a problemi di connettività di rete.",
|
||||
"pad.modals.badChangeset.explanation": "Una modifica che hai fatto è stata considerata illegale dal server di sincronizzazione.",
|
||||
"pad.modals.badChangeset.cause": "Ciò potrebbe essere causato da una errata configurazione del server o qualche altro comportamento imprevisto. Si prega di contattare l'amministratore del servizio, se si ritiene che questo sia un errore. Prova a riconnetterti per tentare di continuare a modificare.",
|
||||
"pad.modals.corruptPad.explanation": "Il pad a cui stai tentando di accedere è danneggiato.",
|
||||
|
@ -132,5 +136,7 @@
|
|||
"pad.impexp.uploadFailed": "Caricamento non riuscito, riprovare",
|
||||
"pad.impexp.importfailed": "Importazione fallita",
|
||||
"pad.impexp.copypaste": "Si prega di copiare e incollare",
|
||||
"pad.impexp.exportdisabled": "L'esportazione come {{type}} è disabilitata. Contattare l'amministratore per i dettagli."
|
||||
"pad.impexp.exportdisabled": "L'esportazione come {{type}} è disabilitata. Contattare l'amministratore per i dettagli.",
|
||||
"pad.impexp.maxFileSize": "File troppo grande. Contatta l'amministratore del sito per incrementare la dimensione consentita per l'importazione",
|
||||
"pad.impexp.permission": "L'importazione è disabilitata perché non hai mai contribuito a questo pad. Per favore, contribuisci almeno una volta, prima di fare importazioni"
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
},
|
||||
"index.newPad": "新規作成",
|
||||
"index.createOpenPad": "または作成/編集するパッド名を入力:",
|
||||
"index.openPad": "次の名称の既存の Pad を開く:",
|
||||
"pad.toolbar.bold.title": "太字 (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "斜体 (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "下線 (Ctrl+U)",
|
||||
|
@ -30,7 +31,7 @@
|
|||
"pad.colorpicker.save": "保存",
|
||||
"pad.colorpicker.cancel": "キャンセル",
|
||||
"pad.loading": "読み込み中...",
|
||||
"pad.noCookie": "クッキーが見つかりません。ブラウザの設定でクッキーの使用を許可してください。",
|
||||
"pad.noCookie": "Cookie could not be found. Please allow cookies in your browser! Your session and settings will not be saved between visits. \n\nクッキーが見つかりません。ブラウザの設定でクッキーの使用を許可するまで、アクセスの記録や設定は引き継がれません。原因はブラウザによって Etherpad が iFrame に組み込まれたからと考えられます。親ドメインの iFrame と同じドメイン/サブドメインに置かれているかどうか、Etherpad の設定を確認してください。",
|
||||
"pad.passwordRequired": "このパッドにアクセスするにはパスワードが必要です",
|
||||
"pad.permissionDenied": "あなたにはこのパッドへのアクセス許可がありません",
|
||||
"pad.wrongPassword": "パスワードが間違っています",
|
||||
|
@ -44,6 +45,8 @@
|
|||
"pad.settings.fontType": "フォントの種類:",
|
||||
"pad.settings.fontType.normal": "通常",
|
||||
"pad.settings.language": "言語:",
|
||||
"pad.settings.about": "このアプリについて",
|
||||
"pad.settings.poweredBy": "提供",
|
||||
"pad.importExport.import_export": "インポート/エクスポート",
|
||||
"pad.importExport.import": "あらゆるテキストファイルや文書をアップロードできます",
|
||||
"pad.importExport.importSuccessful": "完了しました。",
|
||||
|
@ -78,6 +81,8 @@
|
|||
"pad.modals.corruptPad.cause": "これはサーバーの構成不良か、予期せぬ挙動を見せたために発生した事象である可能性があります。当サービス管理者にお問い合わせください。",
|
||||
"pad.modals.deleted": "削除されました。",
|
||||
"pad.modals.deleted.explanation": "このパッドは削除されました。",
|
||||
"pad.modals.rateLimited": "速度制限中です。",
|
||||
"pad.modals.rateLimited.explanation": "パッドに送ったメッセージ件数が多すぎたため接続が解除されました。",
|
||||
"pad.modals.disconnected": "切断されました。",
|
||||
"pad.modals.disconnected.explanation": "サーバーとの接続が失われました",
|
||||
"pad.modals.disconnected.cause": "サーバーを利用できない可能性があります。この問題が解決しない場合はサービスの管理者にお知らせください。",
|
||||
|
@ -90,6 +95,7 @@
|
|||
"pad.chat.loadmessages": "その他のメッセージを読み込む",
|
||||
"pad.chat.stick.title": "チャットを画面に貼り付ける",
|
||||
"pad.chat.writeMessage.placeholder": "ここにメッセージを書き込んでください",
|
||||
"timeslider.followContents": "パッドの内容の更新をフォロー",
|
||||
"timeslider.pageTitle": "{{appTitle}} タイムスライダー",
|
||||
"timeslider.toolbar.returnbutton": "パッドに戻る",
|
||||
"timeslider.toolbar.authors": "作者:",
|
||||
|
@ -97,7 +103,7 @@
|
|||
"timeslider.toolbar.exportlink.title": "エクスポート",
|
||||
"timeslider.exportCurrent": "現在の版をエクスポートする形式:",
|
||||
"timeslider.version": "バージョン {{version}}",
|
||||
"timeslider.saved": "| {{year}}年{{month}}{{day}}日に保存",
|
||||
"timeslider.saved": "{{year}}年{{month}}{{day}}日に保存",
|
||||
"timeslider.playPause": "パッドの過去の内容を再生/一時停止",
|
||||
"timeslider.backRevision": "前の版に戻る",
|
||||
"timeslider.forwardRevision": "次の版に進む",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"@metadata": {
|
||||
"authors": [
|
||||
"Pichnat Thong",
|
||||
"Sovichet",
|
||||
"វ័ណថារិទ្ធ"
|
||||
]
|
||||
|
@ -36,6 +37,8 @@
|
|||
"pad.settings.fontType": "ប្រភេទពុម្ពអក្សរ៖",
|
||||
"pad.settings.fontType.normal": "ធម្មតា",
|
||||
"pad.settings.language": "ភាសា៖",
|
||||
"pad.settings.about": "អំពី",
|
||||
"pad.settings.poweredBy": "ពលុបត្ថម្ភដោយ",
|
||||
"pad.importExport.import_export": "នាំចូល/នាំចេញ",
|
||||
"pad.importExport.import": "ផ្ទុកឡើងឯកសារអត្ថបទណាមួយ",
|
||||
"pad.importExport.importSuccessful": "ដោយជោគជ័យ!",
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
"@metadata": {
|
||||
"authors": [
|
||||
"CYAN",
|
||||
"Codenstory",
|
||||
"Ellif",
|
||||
"Hym411",
|
||||
"Kurousagi",
|
||||
"Revi",
|
||||
|
@ -46,6 +48,8 @@
|
|||
"pad.settings.fontType": "글꼴 종류:",
|
||||
"pad.settings.fontType.normal": "보통",
|
||||
"pad.settings.language": "언어:",
|
||||
"pad.settings.about": "소개",
|
||||
"pad.settings.poweredBy": "제공:",
|
||||
"pad.importExport.import_export": "가져오기/내보내기",
|
||||
"pad.importExport.import": "텍스트 파일이나 문서 올리기",
|
||||
"pad.importExport.importSuccessful": "성공!",
|
||||
|
@ -129,9 +133,11 @@
|
|||
"pad.impexp.importing": "가져오는 중...",
|
||||
"pad.impexp.confirmimport": "파일을 가져오면 패드의 현재 텍스트를 덮어쓰게 됩니다. 진행하시겠습니까?",
|
||||
"pad.impexp.convertFailed": "이 파일을 가져올 수 없습니다. 다른 문서 형식을 사용하거나 수동으로 복사하여 붙여넣으세요",
|
||||
"pad.impexp.padHasData": "우리는 이 파일을 가져올 수 없었습니다. 이 패드는 이미 수정되었으니, 새 패드를 가져와 주십시오",
|
||||
"pad.impexp.padHasData": "이 파일을 가져올 수 없습니다. 이 패드는 이미 수정되었으니, 새 패드를 가져와 주십시오",
|
||||
"pad.impexp.uploadFailed": "올리기를 실패했습니다. 다시 시도하세요",
|
||||
"pad.impexp.importfailed": "가져오기를 실패했습니다",
|
||||
"pad.impexp.copypaste": "복사하여 붙여넣으세요",
|
||||
"pad.impexp.exportdisabled": "{{type}} 형식으로 내보내기가 비활성화되어 있습니다. 자세한 내용은 시스템 관리자에게 문의하시기 바랍니다."
|
||||
"pad.impexp.exportdisabled": "{{type}} 형식으로 내보내기가 비활성화되어 있습니다. 자세한 내용은 시스템 관리자에게 문의하시기 바랍니다.",
|
||||
"pad.impexp.maxFileSize": "파일의 용량이 너무 큽니다. 가져올 파일의 허용 크기를 늘리려면 사이트 관리자에게 문의하십시오",
|
||||
"pad.impexp.permission": "이 패드로 기여한 적이 없으므로 가져오기가 비활성화됩니다. 가져오기 전에 적어도 한 번은 기여해 주십시오"
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
"pad.settings.rtlcheck": "Bila naverok ji raste ber bi çepe be xwendin?",
|
||||
"pad.settings.fontType": "Tîpa nivîsê:",
|
||||
"pad.settings.language": "Ziman:",
|
||||
"pad.settings.about": "Derbar",
|
||||
"pad.importExport.importSuccessful": "Biserketî!",
|
||||
"pad.importExport.exportetherpad": "Etherpad",
|
||||
"pad.importExport.exporthtml": "HTML",
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
"pad.settings.fontType": "Schrëftart:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Sprooch:",
|
||||
"pad.settings.about": "Iwwer",
|
||||
"pad.settings.poweredBy": "Zur Verfügung gestallt vu(n)",
|
||||
"pad.importExport.import_export": "Import/Export",
|
||||
"pad.importExport.import": "Text-Fichier oder Dokument eroplueden",
|
||||
"pad.importExport.importSuccessful": "Erfollegräich",
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
},
|
||||
"index.newPad": "Нова тетратка",
|
||||
"index.createOpenPad": "или направете/отворете тетратка со името:",
|
||||
"index.openPad": "отвори постоечка тетратка наречена:",
|
||||
"pad.toolbar.bold.title": "Задебелено (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Косо (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "Подвлечено (Ctrl-U)",
|
||||
|
@ -28,7 +29,7 @@
|
|||
"pad.colorpicker.save": "Зачувај",
|
||||
"pad.colorpicker.cancel": "Откажи",
|
||||
"pad.loading": "Вчитувам...",
|
||||
"pad.noCookie": "Не можев да го најдам колачето. Овозможете колачиња во вашиот прелистувач!",
|
||||
"pad.noCookie": "Не можев да го најдам колачето. Овозможете колачиња во вашиот прелистувач! Вашата седница и нагодувања нема да бидат зачувани за следната посета. Ова можеби се должи на тоа што Etherpad е вклучен во iFrame во некои прелистувачи. Проверете дали Etherpad е на истиот поддомен/домен како матичниот iFrame",
|
||||
"pad.passwordRequired": "Потребна е лозинка за пристап",
|
||||
"pad.permissionDenied": "За овде не е потребна дозвола за пристап",
|
||||
"pad.wrongPassword": "Погрешна лозинка",
|
||||
|
@ -42,6 +43,8 @@
|
|||
"pad.settings.fontType": "Тип на фонт:",
|
||||
"pad.settings.fontType.normal": "Нормален",
|
||||
"pad.settings.language": "Јазик:",
|
||||
"pad.settings.about": "За додатоков",
|
||||
"pad.settings.poweredBy": "Овозможено од",
|
||||
"pad.importExport.import_export": "Увоз/Извоз",
|
||||
"pad.importExport.import": "Подигање на било каква текстуална податотека или документ",
|
||||
"pad.importExport.importSuccessful": "Успешно!",
|
||||
|
@ -76,6 +79,8 @@
|
|||
"pad.modals.corruptPad.cause": "Ова може да се должи на погрешна поставеност на опслужувачот или некое друго неочекувано поведение. Обратете се кај администраторот.",
|
||||
"pad.modals.deleted": "Избришано.",
|
||||
"pad.modals.deleted.explanation": "Оваа тетратка е отстранета.",
|
||||
"pad.modals.rateLimited": "Ограничено по стапка.",
|
||||
"pad.modals.rateLimited.explanation": "Испративте премногу пораки на тетраткава, па затоа таа ве исклучи.",
|
||||
"pad.modals.disconnected": "Врската е прекината.",
|
||||
"pad.modals.disconnected.explanation": "Врската со опслужувачот е прекината",
|
||||
"pad.modals.disconnected.cause": "Опслужувачот може да е недостапен. Известете го администраторот ако ова продолжи да ви се случува.",
|
||||
|
@ -88,6 +93,7 @@
|
|||
"pad.chat.loadmessages": "Вчитај уште пораки",
|
||||
"pad.chat.stick.title": "Залепи го разговорот на екранот",
|
||||
"pad.chat.writeMessage.placeholder": "Тука напишете порака",
|
||||
"timeslider.followContents": "Следи ги подновите во содржината на тетратката",
|
||||
"timeslider.pageTitle": "{{appTitle}} Историски преглед",
|
||||
"timeslider.toolbar.returnbutton": "Назад на тетратката",
|
||||
"timeslider.toolbar.authors": "Автори:",
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
"pad.colorpicker.save": "സേവ് ചെയ്യുക",
|
||||
"pad.colorpicker.cancel": "റദ്ദാക്കുക",
|
||||
"pad.loading": "ശേഖരിക്കുന്നു...",
|
||||
"pad.noCookie": "കുക്കി കണ്ടെത്താനായില്ല. ദയവായി താങ്കളുടെ ബ്രൗസറിൽ കുക്കികൾ അനുവദിക്കുക!",
|
||||
"pad.noCookie": "കുക്കി കണ്ടെത്താനായില്ല. ദയവായി താങ്കളുടെ ബ്രൗസറിൽ കുക്കികൾ അനുവദിക്കുക! തിരുത്തലുകൾക്കിടയിൽ താങ്കളുടെ സെഷനോ സജ്ജീകരണങ്ങളോ സേവ് ചെയ്യപ്പെടുകയില്ല. ചില ബ്രൗസറുകളിൽ ഈതർപാഡ് ഐഫ്രെയിമിന്റെ കൂടെ ഉൾപ്പെടുത്തിയത്കൊണ്ടാവാം ഈ പ്രശ്നം. പാരന്റ് ഐഫ്രെയിമിന്റെ അതെ ഡൊമെയ്നിൽ/ഉപഡൊമെയ്നിൽ തന്നെയാണ് ഈതർപാഡ് ഉള്ളത് എന്ന കാര്യം ഉറപ്പ് വരുത്തുക.",
|
||||
"pad.passwordRequired": "ഈ പാഡ് ഉപയോഗിക്കുന്നതിനായി ഒരു രഹസ്യവാക്ക് നൽകേണ്ടതാണ്",
|
||||
"pad.permissionDenied": "ഈ പാഡ് കാണുവാൻ താങ്കൾക്ക് അനുമതിയില്ല",
|
||||
"pad.wrongPassword": "താങ്കൾ നല്കിയ രഹസ്യവാക്ക് തെറ്റായിരുന്നു",
|
||||
|
@ -58,7 +58,7 @@
|
|||
"pad.importExport.exportword": "മൈക്രോസോഫ്റ്റ് വേഡ്",
|
||||
"pad.importExport.exportpdf": "പി.ഡി.എഫ്.",
|
||||
"pad.importExport.exportopen": "ഒ.ഡി.എഫ്. (ഓപ്പൺ ഡോക്യുമെന്റ് ഫോർമാറ്റ്)",
|
||||
"pad.importExport.abiword.innerHTML": "പ്ലെയിൻ ടെക്സ്റ്റോ എച്ച്.റ്റി.എം.എൽ. തരമോ മാത്രമേ താങ്കൾക്ക് ഇറക്കുമതി ചെയ്യാനാവൂ. കൂടുതൽ വിപുലീകൃത ഇറക്കുമതി സൗകര്യങ്ങൾക്കായി ദയവായി <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">അബിവേഡ് ഇൻസ്റ്റോൾ ചെയ്യുക</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "പ്ലെയിൻ ടെക്സ്റ്റോ എച്ച്.റ്റി.എം.എൽ. തരമോ മാത്രമേ താങ്കൾക്ക് ഇറക്കുമതി ചെയ്യാനാവൂ. കൂടുതൽ വിപുലീകൃത ഇറക്കുമതി സൗകര്യങ്ങൾക്കായി ദയവായി <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">അബിവേഡ് അല്ലെങ്കിൽ ലിബർഓഫീസ് ഇൻസ്റ്റോൾ ചെയ്യുക</a>.",
|
||||
"pad.modals.connected": "ബന്ധിപ്പിച്ചിരിക്കുന്നു.",
|
||||
"pad.modals.reconnecting": "താങ്കളുടെ പാഡിലേയ്ക്ക് വീണ്ടും ബന്ധിപ്പിക്കുന്നു...",
|
||||
"pad.modals.forcereconnect": "എന്തായാലും ബന്ധിപ്പിക്കുക",
|
||||
|
@ -125,7 +125,7 @@
|
|||
"pad.userlist.guest": "അതിഥി",
|
||||
"pad.userlist.deny": "നിരസിക്കുക",
|
||||
"pad.userlist.approve": "അംഗീകരിക്കുക",
|
||||
"pad.editbar.clearcolors": "ഡോക്യുമെന്റിൽ രചയിതാക്കളെ സൂചിപ്പിക്കാനായി നൽകിയിട്ടുള്ള നിറങ്ങൾ ഒഴിവാക്കട്ടെ?",
|
||||
"pad.editbar.clearcolors": "ഡോക്യുമെന്റിൽ രചയിതാക്കളെ സൂചിപ്പിക്കാനായി നൽകിയിട്ടുള്ള നിറങ്ങൾ ഒഴിവാക്കട്ടെ? ഈ തിരുത്തൽ പഴയപടി ആക്കുവാൻ സാധിക്കില്ല",
|
||||
"pad.impexp.importbutton": "ഇറക്കുമതി ചെയ്യുക",
|
||||
"pad.impexp.importing": "ഇറക്കുമതി ചെയ്യുന്നു...",
|
||||
"pad.impexp.confirmimport": "ഒരു പ്രമാണം ഇറക്കുമതി ചെയ്യുന്നത് നിലവിലുള്ള എഴുത്തുകൾ നഷ്ടപ്പെടാനിടയാക്കും, തുടരണമെന്ന് ഉറപ്പാണോ?",
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"pad.colorpicker.cancel": "Moxitiniz",
|
||||
"pad.settings.padSettings": "Pad Ītlatlālīliz",
|
||||
"pad.settings.myView": "Notlachiyaliz",
|
||||
"pad.settings.language": "Tlahtōlli:",
|
||||
"pad.settings.language": "Tlahtolli:",
|
||||
"pad.importExport.exportetherpad": "Etherpad",
|
||||
"pad.importExport.exporthtml": "HTML",
|
||||
"pad.importExport.exportword": "Microsoft Word",
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
"Cocu",
|
||||
"Jon Harald Søby",
|
||||
"Laaknor",
|
||||
"Orjanmen",
|
||||
"SuperPotato"
|
||||
]
|
||||
},
|
||||
"index.newPad": "Ny Pad",
|
||||
"index.createOpenPad": "eller opprette/åpne en ny Pad med dette navnet:",
|
||||
"index.newPad": "Ny pad",
|
||||
"index.createOpenPad": "eller opprett/åpne en pad med dette navnet:",
|
||||
"index.openPad": "åpne en eksisterende Pad med følgende navn:",
|
||||
"pad.toolbar.bold.title": "Fet (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "Kursiv (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "Understreking (Ctrl+U)",
|
||||
|
@ -19,35 +21,37 @@
|
|||
"pad.toolbar.indent.title": "Innrykk (TAB)",
|
||||
"pad.toolbar.unindent.title": "Rykk ut (Shift+TAB)",
|
||||
"pad.toolbar.undo.title": "Angre (Ctrl+Z)",
|
||||
"pad.toolbar.redo.title": "Gjør omigjen (Ctrl+Y)",
|
||||
"pad.toolbar.redo.title": "Gjør om igjen (Ctrl+Y)",
|
||||
"pad.toolbar.clearAuthorship.title": "Fjern forfatterfarger (Ctrl+Shift+C)",
|
||||
"pad.toolbar.import_export.title": "Importer/eksporter fra/til forskjellige filformater",
|
||||
"pad.toolbar.import_export.title": "Importer/eksporter fra/til ulike filformat",
|
||||
"pad.toolbar.timeslider.title": "Tidslinje",
|
||||
"pad.toolbar.savedRevision.title": "Lagre revisjoner",
|
||||
"pad.toolbar.savedRevision.title": "Lagre revisjon",
|
||||
"pad.toolbar.settings.title": "Innstillinger",
|
||||
"pad.toolbar.embed.title": "Del og sett inn denne Paden",
|
||||
"pad.toolbar.showusers.title": "Vis brukerne av denne Paden",
|
||||
"pad.toolbar.embed.title": "Del og sett inn denne pad-en",
|
||||
"pad.toolbar.showusers.title": "Vis brukerne av denne pad-en",
|
||||
"pad.colorpicker.save": "Lagre",
|
||||
"pad.colorpicker.cancel": "Avbryt",
|
||||
"pad.loading": "Laster...",
|
||||
"pad.noCookie": "Kunne ikke finne informasjonskapselen. Vennligst tillat informasjonskapsler (cookies) i din webleser!",
|
||||
"pad.passwordRequired": "Du trenger et passord for å få tilgang til denne Paden",
|
||||
"pad.permissionDenied": "Du har ikke tilgang til denne Paden",
|
||||
"pad.loading": "Laster …",
|
||||
"pad.noCookie": "Kunne ikke finne informasjonskapselen. Vennligst tillat informasjonskapsler (cookies) i din nettleser! Informasjonskapsler brukes til å lagre innstillinger o.l. Om feilen gjentar seg, kan det skyldes feil i nettsidens bruk av iFrame.",
|
||||
"pad.passwordRequired": "Pad-en er låst med et passord",
|
||||
"pad.permissionDenied": "Du har ikke tilgang til denne pad-en",
|
||||
"pad.wrongPassword": "Feil passord",
|
||||
"pad.settings.padSettings": "Padinnstillinger",
|
||||
"pad.settings.myView": "Min Visning",
|
||||
"pad.settings.myView": "Min visning",
|
||||
"pad.settings.stickychat": "Chat alltid synlig",
|
||||
"pad.settings.chatandusers": "Vis chat og brukere",
|
||||
"pad.settings.colorcheck": "Forfatterfarger",
|
||||
"pad.settings.linenocheck": "Linjenummer",
|
||||
"pad.settings.rtlcheck": "Les innhold fra høyre til venstre?",
|
||||
"pad.settings.rtlcheck": "Les innhold fra høyre til venstre",
|
||||
"pad.settings.fontType": "Skrifttype:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Språk:",
|
||||
"pad.settings.about": "Om",
|
||||
"pad.settings.poweredBy": "Drives av",
|
||||
"pad.importExport.import_export": "Importer/eksporter",
|
||||
"pad.importExport.import": "Last opp tekstfil eller dokument",
|
||||
"pad.importExport.importSuccessful": "Vellykket!",
|
||||
"pad.importExport.export": "Eksporter blokken som:",
|
||||
"pad.importExport.export": "Eksporter som:",
|
||||
"pad.importExport.exportetherpad": "Etherpad",
|
||||
"pad.importExport.exporthtml": "HTML",
|
||||
"pad.importExport.exportplain": "Ren tekst",
|
||||
|
@ -56,32 +60,32 @@
|
|||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "Du kan bare importere fra ren tekst eller HTML-formater. For mer avanserte importfunksjoner, <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">installer AbiWord eller LibreOffice</a>.",
|
||||
"pad.modals.connected": "Tilkoblet.",
|
||||
"pad.modals.reconnecting": "Kobler til din blokk på nytt...",
|
||||
"pad.modals.reconnecting": "Kobler til pad-en på nytt …",
|
||||
"pad.modals.forcereconnect": "Tving gjenoppkobling",
|
||||
"pad.modals.reconnecttimer": "Prøver å koble til igjen",
|
||||
"pad.modals.reconnecttimer": "Prøver å koble til på nytt",
|
||||
"pad.modals.cancel": "Avbryt",
|
||||
"pad.modals.userdup": "Åpnet i nytt vindu",
|
||||
"pad.modals.userdup.explanation": "Denne blokken ser ut til å være åpnet i mer enn et nettleservindu på denne maskinen.",
|
||||
"pad.modals.userdup.advice": "Koble til igjen for å bruke dette vinduet i stedenfor.",
|
||||
"pad.modals.userdup.explanation": "Denne pad-en ser ut til å være åpnet i flere vindu/faner i nettleseren din.",
|
||||
"pad.modals.userdup.advice": "Koble til igjen for å redigere fra dette vinduet.",
|
||||
"pad.modals.unauth": "Ikke tillatt",
|
||||
"pad.modals.unauth.explanation": "Dine rettigheter har blitt endret mens du så på denne siden. Prøv å koble til på nytt",
|
||||
"pad.modals.looping.explanation": "Det er kommunikasjonsproblemer med synkroniseringsserveren.",
|
||||
"pad.modals.looping.explanation": "Det er problemer med synkroniseringen av pad-en.",
|
||||
"pad.modals.looping.cause": "Kanskje du koblet til en inkompatibel brannmur eller mellomtjener",
|
||||
"pad.modals.initsocketfail": "Serveren er utilgjengelig",
|
||||
"pad.modals.initsocketfail.explanation": "Kunne ikke koble til synkroniseringsserveren.",
|
||||
"pad.modals.initsocketfail.cause": "Dette er sannsynligvis på grunn av et problem med nettleseren eller din internettoppkobling",
|
||||
"pad.modals.initsocketfail.cause": "Dette skyldes sannsynligvis et problem med internettoppkoblingen, eller nettleseren din.",
|
||||
"pad.modals.slowcommit.explanation": "Serveren svarer ikke.",
|
||||
"pad.modals.slowcommit.cause": "Dette kan være et problem med nettverkstilkoblingen",
|
||||
"pad.modals.badChangeset.explanation": "En redigering som du gjorde ble klassifisert som ulovlig av synkroniseringsserveren.",
|
||||
"pad.modals.slowcommit.cause": "Dette skyldes nettverksoppkoblingen din.",
|
||||
"pad.modals.badChangeset.explanation": "En redigering som du gjorde ble klassifisert som ugyldig av synkroniseringsserveren.",
|
||||
"pad.modals.badChangeset.cause": "Dette kan komme av feil serverkonfigurasjon eller en annen uventet adferd. Vennligst kontakt serviceadministratoren hvis du anser dette å være feil. Prøv å gjenopprette forbindelsen for å fortsette med redigeringen.",
|
||||
"pad.modals.corruptPad.explanation": "Blokken du forsøker å få tilgang til er skadet.",
|
||||
"pad.modals.corruptPad.explanation": "Pad-en du forsøker å få tilgang til, fungerer ikke.",
|
||||
"pad.modals.corruptPad.cause": "Dette kan komme av feil serverkonfigurasjon eller en annen uventet adferd. Vennligst kontakt serviceadministratoren hvis du anser dette å være feil.",
|
||||
"pad.modals.deleted": "Slettet.",
|
||||
"pad.modals.deleted.explanation": "Denne blokken har blitt fjernet",
|
||||
"pad.modals.deleted.explanation": "Denne pad-en har blitt fjernet.",
|
||||
"pad.modals.disconnected": "Du har blitt frakoblet.",
|
||||
"pad.modals.disconnected.explanation": "Mistet tilkobling til serveren.",
|
||||
"pad.modals.disconnected.cause": "Serveren kan være utilgjengelig. Vennligst si i fra til oss hvis dette fortsetter å skje.",
|
||||
"pad.share": "Del denne blokken",
|
||||
"pad.modals.disconnected.explanation": "Ingen tilkobling til serveren.",
|
||||
"pad.modals.disconnected.cause": "Serveren kan være utilgjengelig. Vennligst gi beskjed dersom dette gjentar seg.",
|
||||
"pad.share": "Del denne pad-en",
|
||||
"pad.share.readonly": "Skrivebeskyttet",
|
||||
"pad.share.link": "Lenke",
|
||||
"pad.share.emebdcode": "URL for innbygging",
|
||||
|
@ -90,17 +94,17 @@
|
|||
"pad.chat.loadmessages": "Last flere beskjeder",
|
||||
"pad.chat.stick.title": "Fest chatten til skjermen",
|
||||
"pad.chat.writeMessage.placeholder": "Skriv beskjeden din her",
|
||||
"timeslider.pageTitle": "{{appTitle}} Tidslinje",
|
||||
"timeslider.toolbar.returnbutton": "Gå tilbake til blokk",
|
||||
"timeslider.pageTitle": "{{appTitle}}-tidslinje",
|
||||
"timeslider.toolbar.returnbutton": "Gå tilbake til pad-en",
|
||||
"timeslider.toolbar.authors": "Forfattere:",
|
||||
"timeslider.toolbar.authorsList": "Ingen forfattere",
|
||||
"timeslider.toolbar.exportlink.title": "Eksporter",
|
||||
"timeslider.exportCurrent": "Eksporter nåværende versjon som:",
|
||||
"timeslider.version": "Versjon {{version}}",
|
||||
"timeslider.saved": "Lagret {{day}}. {{month}} {{year}}",
|
||||
"timeslider.playPause": "Spill av/Pause blokkinnholdet",
|
||||
"timeslider.backRevision": "Gå tilbake en revisjon i denne blokken",
|
||||
"timeslider.forwardRevision": "Gå fremover en revisjon i denne blokken",
|
||||
"timeslider.playPause": "Spill av/Pause pad-innholdet",
|
||||
"timeslider.backRevision": "Gå tilbake en revisjon i denne pad-en",
|
||||
"timeslider.forwardRevision": "Gå fremover en revisjon i denne pad-en",
|
||||
"timeslider.dateformat": "{{day}}. {{month}} {{year}} {{hours}}:{{minutes}}:{{seconds}}",
|
||||
"timeslider.month.january": "januar",
|
||||
"timeslider.month.february": "februar",
|
||||
|
@ -114,7 +118,7 @@
|
|||
"timeslider.month.october": "oktober",
|
||||
"timeslider.month.november": "november",
|
||||
"timeslider.month.december": "desember",
|
||||
"timeslider.unnamedauthors": "{{num}} navnløse {[plural(num) one: forfatter, other: forfattere ]}",
|
||||
"timeslider.unnamedauthors": "{{num}} {[plural(num) one: navnløs forfatter, other: navnløse forfattere ]}",
|
||||
"pad.savedrevs.marked": "Denne revisjonen er nå markert som en lagret revisjon",
|
||||
"pad.savedrevs.timeslider": "Du kan se lagrede revisjoner med tidslinjen",
|
||||
"pad.userlist.entername": "Skriv inn ditt navn",
|
||||
|
@ -124,14 +128,14 @@
|
|||
"pad.userlist.approve": "Godkjenn",
|
||||
"pad.editbar.clearcolors": "Fjern forfatterfarger på hele dokumentet? Dette kan ikke angres",
|
||||
"pad.impexp.importbutton": "Importer nå",
|
||||
"pad.impexp.importing": "Importerer...",
|
||||
"pad.impexp.importing": "Importerer …",
|
||||
"pad.impexp.confirmimport": "Importering av en fil vil overskrive den nåværende teksten på blokken. Er du sikker på at du vil fortsette?",
|
||||
"pad.impexp.convertFailed": "Vi greide ikke å importere denne filen. Bruk et annet dokumentformat eller kopier og lim inn teksten manuelt",
|
||||
"pad.impexp.padHasData": "Vi kunne ikke importere denne filen fordi blokken allerede hadde endringer. Importer til en ny blokk.",
|
||||
"pad.impexp.uploadFailed": "Opplastning feilet. Prøv igjen",
|
||||
"pad.impexp.importfailed": "Import feilet",
|
||||
"pad.impexp.copypaste": "Vennligst kopier og lim inn",
|
||||
"pad.impexp.exportdisabled": "Eksporterer som {{type}} er deaktivert. Vennligst kontakt din systemadministrator for detaljer.",
|
||||
"pad.impexp.exportdisabled": "Eksportering som {{type}} er deaktivert. Vennligst kontakt systemadministratoren din for detaljer.",
|
||||
"pad.impexp.maxFileSize": "Filen er for stor. Kontakt systemansvarlig for å øke filstørrelse for import",
|
||||
"pad.impexp.permission": "Import er deaktivert fordi du aldri har bidratt til denne padden. Vennligst bidra minst en gang før du importerer"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"@metadata": {
|
||||
"authors": [
|
||||
"Nirajan pant",
|
||||
"Nirjal stha",
|
||||
"राम प्रसाद जोशी",
|
||||
"सरोज कुमार ढकाल",
|
||||
|
@ -41,6 +42,8 @@
|
|||
"pad.settings.fontType": "लिपि प्रकार:",
|
||||
"pad.settings.fontType.normal": "सामान्य",
|
||||
"pad.settings.language": "भाषा:",
|
||||
"pad.settings.about": "बारेमा",
|
||||
"pad.settings.poweredBy": "प्रवर्धक",
|
||||
"pad.importExport.import_export": "आयात/निर्यात",
|
||||
"pad.importExport.import": "कुनै पनि पाठ रहेको फाइल या कागजात अपलोड गर्नुहोस्",
|
||||
"pad.importExport.importSuccessful": "सफल भयो!",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"@metadata": {
|
||||
"authors": [
|
||||
"Dutchy45",
|
||||
"Klaas van Buiten",
|
||||
"KlaasZ4usV",
|
||||
"Macofe",
|
||||
|
@ -49,6 +50,7 @@
|
|||
"pad.settings.fontType": "Lettertype:",
|
||||
"pad.settings.fontType.normal": "Normaal",
|
||||
"pad.settings.language": "Taal:",
|
||||
"pad.settings.about": "Over",
|
||||
"pad.importExport.import_export": "Importeren/exporteren",
|
||||
"pad.importExport.import": "Tekstbestand of document uploaden",
|
||||
"pad.importExport.importSuccessful": "Afgerond",
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
},
|
||||
"index.newPad": "Nowy dokument",
|
||||
"index.createOpenPad": "lub stwórz/otwórz dokument o nazwie:",
|
||||
"index.openPad": "otwórz istniejący dokument o nazwie:",
|
||||
"pad.toolbar.bold.title": "Pogrubienie (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Kursywa (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "Podkreślenie (Ctrl-U)",
|
||||
|
@ -35,7 +36,7 @@
|
|||
"pad.colorpicker.save": "Zapisz",
|
||||
"pad.colorpicker.cancel": "Anuluj",
|
||||
"pad.loading": "Ładowanie...",
|
||||
"pad.noCookie": "Nie znaleziono pliku cookie. Proszę zezwolić na pliki cookie w przeglądarce!",
|
||||
"pad.noCookie": "Nie można znaleźć pliku cookie. Proszę zezwolić na pliki cookie w przeglądarce! Twoja sesja i ustawienia nie zostaną zapisane między wizytami. Może to wynikać z włączenia Etherpad do ramki iFrame w niektórych przeglądarkach. Upewnij się, że Etherpad jest w tej samej subdomenie/domenie, co nadrzędna ramka iFrame",
|
||||
"pad.passwordRequired": "Musisz podać hasło aby uzyskać dostęp do tego dokumentu",
|
||||
"pad.permissionDenied": "Nie masz uprawnień dostępu do tego dokumentu",
|
||||
"pad.wrongPassword": "Nieprawidłowe hasło",
|
||||
|
@ -49,6 +50,7 @@
|
|||
"pad.settings.fontType": "Rodzaj czcionki:",
|
||||
"pad.settings.fontType.normal": "Normalna",
|
||||
"pad.settings.language": "Język:",
|
||||
"pad.settings.about": "O aplikacji",
|
||||
"pad.importExport.import_export": "Import/eksport",
|
||||
"pad.importExport.import": "Prześlij dowolny plik tekstowy lub dokument",
|
||||
"pad.importExport.importSuccessful": "Sukces!",
|
||||
|
@ -59,7 +61,7 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "Możesz importować pliki tylko w formacie zwykłego tekstu lub HTML. Aby umożliwić bardziej zaawansowane funkcje importu, <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-in-Ubuntu-or-OpenSuse-or-SLES-with-AbiWord\">zainstaluj AbiWord</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "Możesz importować pliki tylko w formacie zwykłego tekstu lub HTML. Aby umożliwić bardziej zaawansowane funkcje importu, <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-in-Ubuntu-or-OpenSuse-or-SLES-with-AbiWord\">zainstaluj AbiWord lub LibreOffice</a>.",
|
||||
"pad.modals.connected": "Połączony.",
|
||||
"pad.modals.reconnecting": "Ponowne łączenie z dokumentem...",
|
||||
"pad.modals.forcereconnect": "Wymuś ponowne połączenie",
|
||||
|
@ -127,7 +129,7 @@
|
|||
"pad.userlist.guest": "Gość",
|
||||
"pad.userlist.deny": "Zabroń",
|
||||
"pad.userlist.approve": "Zezwól",
|
||||
"pad.editbar.clearcolors": "Wyczyścić kolory autorstwa w całym dokumencie?",
|
||||
"pad.editbar.clearcolors": "Wyczyścić kolory autorstwa w całym dokumencie? Nie można będzie tego cofnąć!",
|
||||
"pad.impexp.importbutton": "Importuj teraz",
|
||||
"pad.impexp.importing": "Importowanie...",
|
||||
"pad.impexp.confirmimport": "Importowanie pliku spowoduje zastąpienie bieżącego tekstu. Czy na pewno chcesz kontynuować?",
|
||||
|
@ -136,5 +138,7 @@
|
|||
"pad.impexp.uploadFailed": "Przesyłanie nie powiodło się, proszę spróbować jeszcze raz",
|
||||
"pad.impexp.importfailed": "Importowanie nie powiodło się",
|
||||
"pad.impexp.copypaste": "Proszę skopiować i wkleić",
|
||||
"pad.impexp.exportdisabled": "Eksport do formatu {{type}} jest wyłączony. Proszę skontaktować się z administratorem aby uzyskać więcej szczegółów."
|
||||
"pad.impexp.exportdisabled": "Eksport do formatu {{type}} jest wyłączony. Proszę skontaktować się z administratorem aby uzyskać więcej szczegółów.",
|
||||
"pad.impexp.maxFileSize": "Plik jest zbyt duży. Skontaktuj się z administratorem aby zwiększył maksymalny dopuszczalny rozmiar importowanych plików",
|
||||
"pad.impexp.permission": "Importowanie jest zablokowane, ponieważ nie edytowałeś jeszcze tego dokumentu. Wykonaj przynajmniej jedną zmianę zanim zaczniesz importować"
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
},
|
||||
"index.newPad": "Feuj neuv",
|
||||
"index.createOpenPad": "o creé/duverté un feuj antitolà:",
|
||||
"index.openPad": "duverté un Pad esistent con ël nòm:",
|
||||
"pad.toolbar.bold.title": "Grassèt (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "Corsiv (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "Sotlignà (Ctrl+U)",
|
||||
|
@ -26,7 +27,7 @@
|
|||
"pad.colorpicker.save": "Argistré",
|
||||
"pad.colorpicker.cancel": "Anulé",
|
||||
"pad.loading": "Antramentr ch'as caria…",
|
||||
"pad.noCookie": "Ël bëscotin a l'é nen ëstàit trovà. Për piasì, ch'a autorisa ij bëscotin su sò navigador!",
|
||||
"pad.noCookie": "Ël bëscotin a l'é nen ëstàit trovà. Për piasì, ch'a autorisa ij bëscotin su sò navigador! Soa session e sò paràmeter a saran pa argistrà antra na vìsita e l'àutra. Sòn a peul esse dovù al fàit che Etherpad a l'é contnù an n'iFrame an chèich navigador. Ch'a contròla che Etherpad resta ant l'istess sot-domini/domini ëd sò ce iFrame",
|
||||
"pad.passwordRequired": "A l'ha da manca ëd na ciav për acede a cost feuj-sì",
|
||||
"pad.permissionDenied": "A l'ha nen ël përmess d'acede a 's feuj-sì",
|
||||
"pad.wrongPassword": "Soa ciav a l'era nen giusta",
|
||||
|
@ -39,6 +40,8 @@
|
|||
"pad.settings.rtlcheck": "Ël contnù, dev-lo esse lesù da drita a snistra?",
|
||||
"pad.settings.fontType": "Sòrt ëd caràter:",
|
||||
"pad.settings.language": "Lenga:",
|
||||
"pad.settings.about": "A propòsit",
|
||||
"pad.settings.poweredBy": "Potensià da",
|
||||
"pad.importExport.import_export": "Amporté/Esporté",
|
||||
"pad.importExport.import": "Carié n'archivi o document ëd test",
|
||||
"pad.importExport.importSuccessful": "Bele fàit!",
|
||||
|
@ -49,7 +52,7 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "A peul mach amporté dij formà ëd test sempi o HTML. Për dle fonsionalità d'amportassion pi avansà, ch'a <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">anstala AbiWord</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "A peul mach amporté dij formà ëd test sempi o HTML. Për dle fonsionalità d'amportassion pi avansà, ch'a <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">anstala AbiWord o LibreOffice</a>.",
|
||||
"pad.modals.connected": "Colegà.",
|
||||
"pad.modals.reconnecting": "Neuva conession a sò feuj...",
|
||||
"pad.modals.forcereconnect": "Forsé la neuva conession",
|
||||
|
@ -73,6 +76,8 @@
|
|||
"pad.modals.corruptPad.cause": "Sòn a podrìa esse dovù a na configurassion ësbalià dël servent o a chèich àutr comportament nen ëspetà. Për piasì, ch'a contata l'aministrator dël servissi.",
|
||||
"pad.modals.deleted": "Dëscancelà.",
|
||||
"pad.modals.deleted.explanation": "Ës feuj a l'é stàit eliminà.",
|
||||
"pad.modals.rateLimited": "Tass limità.",
|
||||
"pad.modals.rateLimited.explanation": "A l'ha mandà tròpi mëssagi a 's blòch-sì, antlora a l'ha dëscolegalo.",
|
||||
"pad.modals.disconnected": "A l'é stàit dëscolegà",
|
||||
"pad.modals.disconnected.explanation": "La conession al servent a l'é perdusse",
|
||||
"pad.modals.disconnected.cause": "Ël servent a podrìa esse indisponìbil. Për piasì, ch'a anforma l'aministrator dël servissi si ël problema a persist.",
|
||||
|
@ -85,6 +90,7 @@
|
|||
"pad.chat.loadmessages": "Carié pi 'd mëssagi",
|
||||
"pad.chat.stick.title": "Taché la ciaciarada an slë scren",
|
||||
"pad.chat.writeMessage.placeholder": "Ch'a scriva sò mëssage ambelessì",
|
||||
"timeslider.followContents": "Steje dapress a j'agiornament ëd contnù dël blòch",
|
||||
"timeslider.pageTitle": "Stòria dinàmica ëd {{appTitle}}",
|
||||
"timeslider.toolbar.returnbutton": "Torné al feuj",
|
||||
"timeslider.toolbar.authors": "Autor:",
|
||||
|
@ -126,5 +132,7 @@
|
|||
"pad.impexp.uploadFailed": "Ël cariament a l'ha falì, për piasì ch'a preuva torna",
|
||||
"pad.impexp.importfailed": "Amportassion falìa",
|
||||
"pad.impexp.copypaste": "Për piasì, ch'a còpia e ancòla",
|
||||
"pad.impexp.exportdisabled": "L'esportassion an formà {{type}} a l'é disativà. Për piasì, ch'a contata sò aministrator ëd sistema për ij detaj."
|
||||
"pad.impexp.exportdisabled": "L'esportassion an formà {{type}} a l'é disativà. Për piasì, ch'a contata sò aministrator ëd sistema për ij detaj.",
|
||||
"pad.impexp.maxFileSize": "Archivi tròp gròss. Ch'a contata sò aministrator ëd sit për sumenté la taja dj'archivi consentìa për j'amportassion",
|
||||
"pad.impexp.permission": "L'amportassion a l'é disativà përchè chiel a l'ha pa mai contribuì a cost blòch-sì. Për piasì, ch'a contribuissa almanch na vira prima d'amporté"
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
},
|
||||
"index.newPad": "Nova Nota",
|
||||
"index.createOpenPad": "ou criar-abrir uma Nota com o nome:",
|
||||
"index.openPad": "abra um bloco existente com o nome:",
|
||||
"pad.toolbar.bold.title": "Negrito (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Itálico (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "Sublinhado (Ctrl-U)",
|
||||
|
@ -41,7 +42,7 @@
|
|||
"pad.colorpicker.save": "Salvar",
|
||||
"pad.colorpicker.cancel": "Cancelar",
|
||||
"pad.loading": "Carregando...",
|
||||
"pad.noCookie": "Cookie não foi encontrado. Por favor, habilite cookies no seu navegador!",
|
||||
"pad.noCookie": "Não foi possível encontrar o cookie. Por favor, permita cookies no seu navegador! Sua sessão e configurações não serão salvas entre as visitas. Isso pode ser devido ao fato de o Etherpad ser incluído em um iFrame em alguns navegadores. Verifique se o Etherpad está no mesmo subdomínio/domínio que o iFrame pai",
|
||||
"pad.passwordRequired": "Você precisa de uma senha para acessar esta Nota",
|
||||
"pad.permissionDenied": "Você não tem permissão para acessar esta Nota",
|
||||
"pad.wrongPassword": "Senha incorreta",
|
||||
|
@ -55,6 +56,8 @@
|
|||
"pad.settings.fontType": "Tipo de fonte:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Idioma:",
|
||||
"pad.settings.about": "Sobre",
|
||||
"pad.settings.poweredBy": "Fornecido por",
|
||||
"pad.importExport.import_export": "Importar/Exportar",
|
||||
"pad.importExport.import": "Enviar um arquivo texto ou documento",
|
||||
"pad.importExport.importSuccessful": "Completo!",
|
||||
|
@ -89,6 +92,8 @@
|
|||
"pad.modals.corruptPad.cause": "Isto pode ocorrer devido a uma configuração errada do servidor ou algum outro comportamento inesperado. Por favor contate o administrador.",
|
||||
"pad.modals.deleted": "Excluído.",
|
||||
"pad.modals.deleted.explanation": "Esta nota foi removida.",
|
||||
"pad.modals.rateLimited": "Limitado.",
|
||||
"pad.modals.rateLimited.explanation": "Você enviou muitas mensagens para este pad por isso será desconectado.",
|
||||
"pad.modals.disconnected": "Você foi desconectado.",
|
||||
"pad.modals.disconnected.explanation": "A conexão com o servidor foi perdida",
|
||||
"pad.modals.disconnected.cause": "O servidor pode estar indisponível. Por favor, notifique o administrador caso isso continue.",
|
||||
|
@ -101,6 +106,7 @@
|
|||
"pad.chat.loadmessages": "Carregar mais mensagens",
|
||||
"pad.chat.stick.title": "Cole o bate-papo na tela",
|
||||
"pad.chat.writeMessage.placeholder": "Escreva sua mensagem aqui",
|
||||
"timeslider.followContents": "Siga as atualizações de conteúdo do pad",
|
||||
"timeslider.pageTitle": "Linha do tempo de {{appTitle}}",
|
||||
"timeslider.toolbar.returnbutton": "Retornar para a nota",
|
||||
"timeslider.toolbar.authors": "Autores:",
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"authors": [
|
||||
"Athena in Wonderland",
|
||||
"Cainamarques",
|
||||
"GoEThe",
|
||||
"Hamilton Abreu",
|
||||
"Imperadeiro98",
|
||||
"Luckas",
|
||||
|
@ -16,6 +17,7 @@
|
|||
},
|
||||
"index.newPad": "Nova Nota",
|
||||
"index.createOpenPad": "ou crie/abra uma nota com o nome:",
|
||||
"index.openPad": "abrir uma «Nota» existente com o nome:",
|
||||
"pad.toolbar.bold.title": "Negrito (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "Itálico (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "Sublinhado (Ctrl+U)",
|
||||
|
@ -36,7 +38,7 @@
|
|||
"pad.colorpicker.save": "Gravar",
|
||||
"pad.colorpicker.cancel": "Cancelar",
|
||||
"pad.loading": "A carregar…",
|
||||
"pad.noCookie": "O cookie não foi encontrado. Por favor, ative os cookies no seu navegador!",
|
||||
"pad.noCookie": "Não foi possível encontrar o ''cookie''. Por favor, permita ''cookies'' no seu navegador! A sua sessão e as definições não foram guardadas entre as visitas. Isto poderá ter ocorrido porque Etherpad foi incluído numa iFrame em alguns «Navegadores». Por favor, certifique-se que Etherpad está no mesmo subdomínio / domínio que a iFrame fonte",
|
||||
"pad.passwordRequired": "Precisa de uma palavra-passe para aceder a esta nota",
|
||||
"pad.permissionDenied": "Não tem permissão para aceder a esta nota",
|
||||
"pad.wrongPassword": "A sua palavra-passe estava errada",
|
||||
|
@ -50,6 +52,8 @@
|
|||
"pad.settings.fontType": "Tipo de letra:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Língua:",
|
||||
"pad.settings.about": "Sobre",
|
||||
"pad.settings.poweredBy": "Desenvolvido por",
|
||||
"pad.importExport.import_export": "Importar/Exportar",
|
||||
"pad.importExport.import": "Carregar qualquer ficheiro de texto ou documento",
|
||||
"pad.importExport.importSuccessful": "Completo!",
|
||||
|
@ -60,7 +64,7 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "Só pode importar texto sem formatação ou formatos HTML. Para funcionalidades de importação mais avançadas, por favor, <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">instale o AbiWord ou LibreOffice</a>.",
|
||||
"pad.importExport.abiword.innerHTML": "Só pode fazer importações de texto não formatado ou com formato HTML. Para funcionalidades de importação de texto mais avançadas, <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">instale AbiWord ou LibreOffice</a>, por favor.",
|
||||
"pad.modals.connected": "Ligado.",
|
||||
"pad.modals.reconnecting": "A restabelecer ligação ao seu bloco…",
|
||||
"pad.modals.forcereconnect": "Forçar restabelecimento de ligação",
|
||||
|
@ -84,6 +88,8 @@
|
|||
"pad.modals.corruptPad.cause": "Isto pode ocorrer devido a uma configuração errada do servidor ou algum outro comportamento inesperado. Por favor contacte o administrador.",
|
||||
"pad.modals.deleted": "Eliminado.",
|
||||
"pad.modals.deleted.explanation": "Esta nota foi removida.",
|
||||
"pad.modals.rateLimited": "Limitado.",
|
||||
"pad.modals.rateLimited.explanation": "Enviou demasiadas mensagens para este pad, por isso foi desligado.",
|
||||
"pad.modals.disconnected": "Você foi desligado.",
|
||||
"pad.modals.disconnected.explanation": "A ligação ao servidor foi perdida",
|
||||
"pad.modals.disconnected.cause": "O servidor pode estar indisponível. Por favor, notifique o administrador de serviço se isto continuar a acontecer.",
|
||||
|
@ -96,6 +102,7 @@
|
|||
"pad.chat.loadmessages": "Carregar mais mensagens",
|
||||
"pad.chat.stick.title": "Colar conversação no ecrã",
|
||||
"pad.chat.writeMessage.placeholder": "Escreva a sua mensagem aqui",
|
||||
"timeslider.followContents": "Siga as atualizações do conteúdo do pad",
|
||||
"timeslider.pageTitle": "Linha do tempo de {{appTitle}}",
|
||||
"timeslider.toolbar.returnbutton": "Voltar à nota",
|
||||
"timeslider.toolbar.authors": "Autores:",
|
||||
|
@ -128,7 +135,7 @@
|
|||
"pad.userlist.guest": "Convidado",
|
||||
"pad.userlist.deny": "Negar",
|
||||
"pad.userlist.approve": "Aprovar",
|
||||
"pad.editbar.clearcolors": "Limpar as cores de autoria em todo o documento? isto não pode ser anulado",
|
||||
"pad.editbar.clearcolors": "Limpar as cores de autoria do documento todo? Esta operação não pode ser desfeita",
|
||||
"pad.impexp.importbutton": "Importar agora",
|
||||
"pad.impexp.importing": "Importando...",
|
||||
"pad.impexp.confirmimport": "A importação de um ficheiro irá substituir o texto atual da nota. Tem certeza que deseja continuar?",
|
||||
|
@ -138,6 +145,6 @@
|
|||
"pad.impexp.importfailed": "A importação falhou",
|
||||
"pad.impexp.copypaste": "Copie e insira, por favor",
|
||||
"pad.impexp.exportdisabled": "A exportação no formato {{type}} está desativada. Por favor, contacte o administrador do sistema para mais informações.",
|
||||
"pad.impexp.maxFileSize": "Ficheiro muito grande. Contacte o administrador do ''site'' para aumentar o tamanho do ficheiro permitido para importar",
|
||||
"pad.impexp.permission": "A importação está desativada porque nunca contribuiu para este bloco. Por favor, contribua pelo menos uma vez antes de importar"
|
||||
"pad.impexp.maxFileSize": "Ficheiro demasiado grande. Contacte o administrador do ''site'' para aumentar o tamanho máximo dos ficheiros importados",
|
||||
"pad.impexp.permission": "A importação está desativada porque nunca contribuiu para esta nota. Contribua pelo menos uma vez antes de importar, por favor"
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
"Mklehr",
|
||||
"Nemo bis",
|
||||
"Shirayuki",
|
||||
"Siebrand"
|
||||
"Siebrand",
|
||||
"Tim.krieger"
|
||||
]
|
||||
},
|
||||
"index.newPad": "Used as button text.\nA pad, in the context of Etherpad, is a notepad, something to write on.",
|
||||
|
@ -106,7 +107,7 @@
|
|||
"timeslider.month.december": "Example usage: <samp>Saved on August 26, 2014</samp>.\n{{Identical|December}}",
|
||||
"timeslider.unnamedauthors": "See also:\n* {{msg-etherpadlite|Timeslider.unnamedauthor}}",
|
||||
"pad.savedrevs.marked": "more like bookmarked, or tagged/starred",
|
||||
"pad.userlist.entername": "Used as placeholder for the \"Name\" input box in the upper right corner of the screen.",
|
||||
"pad.userlist.entername": "Used as placeholder for the \"Name\" input box in the upper right corner of the screen. It's important to keep it short: Long sentences aren't displayed.",
|
||||
"pad.userlist.unnamed": "Displayed, if a user has not set a nick yet",
|
||||
"pad.userlist.guest": "Preceded by the link text which is labeled {{msg-etherpadlite|Pad.userlist.approve}}.\n{{Identical|Guest}}",
|
||||
"pad.userlist.deny": "Used as link text.\n\nFollowed by the link which is labeled {{msg-etherpadlite|Pad.userlist.approve}}.",
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
{
|
||||
"@metadata": {
|
||||
"authors": [
|
||||
"Carcassonne93",
|
||||
"Hedwig",
|
||||
"ImGelu",
|
||||
"MSClaudiu",
|
||||
"Minisarm",
|
||||
"Strainu",
|
||||
"Wintereu"
|
||||
|
@ -10,32 +12,41 @@
|
|||
},
|
||||
"index.newPad": "Pad nou",
|
||||
"index.createOpenPad": "sau creează/deschide un Pad cu numele:",
|
||||
"index.openPad": "deschide un Pad existent cu numele:",
|
||||
"pad.toolbar.bold.title": "Aldin (Ctrl + B)",
|
||||
"pad.toolbar.italic.title": "Cursiv (Ctrl + I)",
|
||||
"pad.toolbar.underline.title": "Subliniază (Ctrl+U)",
|
||||
"pad.toolbar.strikethrough.title": "Taie (Ctrl+5)",
|
||||
"pad.toolbar.ol.title": "Listă ordonată (Ctrl+Shift+N)",
|
||||
"pad.toolbar.ul.title": "Listă neordonată (Ctrl+Shift+L)",
|
||||
"pad.toolbar.indent.title": "Cursiv (TAB)",
|
||||
"pad.toolbar.unindent.title": "Fără cursiv (Shift+TAB)",
|
||||
"pad.toolbar.undo.title": "Anulează (Ctrl+Z)",
|
||||
"pad.toolbar.redo.title": "Refă (Ctrl+Y)",
|
||||
"pad.toolbar.clearAuthorship.title": "Curăță culorile autorilor (Ctrl+Shift+C)",
|
||||
"pad.toolbar.import_export.title": "Importă/Exportă din/în diferite formate",
|
||||
"pad.toolbar.timeslider.title": "Glisor de timp",
|
||||
"pad.toolbar.savedRevision.title": "Salvează revizia",
|
||||
"pad.toolbar.settings.title": "Setări",
|
||||
"pad.toolbar.embed.title": "Partajați și încorporați acest pad",
|
||||
"pad.toolbar.showusers.title": "Arată utilizatorii de pe acest pad",
|
||||
"pad.colorpicker.save": "Salvează",
|
||||
"pad.colorpicker.cancel": "Anulează",
|
||||
"pad.loading": "Se încarcă...",
|
||||
"pad.noCookie": "Cookie-ul nu a putut fi găsit. Vă rugăm să permiteți cookie-urile în browser! Sesiunea și setările nu vor fi salvate între vizite. Aceasta se poate datora faptului că Etherpad este inclus într-un iFrame în unele browsere. Vă rugăm să vă asigurați că Etherpad este pe același subdomeniu/domeniu ca iFrame părinte",
|
||||
"pad.passwordRequired": "Ai nevoie de o parolă pentru a accesa acest pad",
|
||||
"pad.permissionDenied": "Nu ai permisiunea să accesezi acest pad",
|
||||
"pad.wrongPassword": "Parola ta este greșită",
|
||||
"pad.settings.padSettings": "Setări pentru Pad",
|
||||
"pad.settings.myView": "Perspectiva mea",
|
||||
"pad.settings.stickychat": "Chat-ul întotdeauna pe ecran",
|
||||
"pad.settings.chatandusers": "Afișează Chat-ul și Utilizatorii",
|
||||
"pad.settings.colorcheck": "Culorile autorilor",
|
||||
"pad.settings.linenocheck": "Numere de linie",
|
||||
"pad.settings.rtlcheck": "Citiți conținut de la dreapta la stânga?",
|
||||
"pad.settings.fontType": "Tipul fontului:",
|
||||
"pad.settings.language": "Limbă:",
|
||||
"pad.settings.about": "Despre",
|
||||
"pad.importExport.import_export": "Import/Export",
|
||||
"pad.importExport.import": "Încarcă orice fișier text sau document",
|
||||
"pad.importExport.importSuccessful": "Succes!",
|
||||
|
@ -46,19 +57,33 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "Puteți importa doar din format simplu sau HTML. Pentru funcții de import mai avansate, vă rugăm <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">instalați AbiWord sau LibreOffice</a>.",
|
||||
"pad.modals.connected": "Conectat.",
|
||||
"pad.modals.reconnecting": "Se reconectează la pad-ul dumneavoastră..",
|
||||
"pad.modals.forcereconnect": "Forțează reconectarea",
|
||||
"pad.modals.reconnecttimer": "Încercați să vă reconectați în",
|
||||
"pad.modals.cancel": "Anulează",
|
||||
"pad.modals.userdup": "Deschis în altă fereastră",
|
||||
"pad.modals.userdup.explanation": "Acest pad pare a fi deschis în mai multe ferestre de browser de pe acest computer.",
|
||||
"pad.modals.userdup.advice": "Reconectați-vă dacă doriți să utilizați această fereastră.",
|
||||
"pad.modals.unauth": "Nu ești autorizat",
|
||||
"pad.modals.unauth.explanation": "Permisiunile dvs. s-au schimbat în timpul vizualizării acestei pagini. Încercați să vă reconectați.",
|
||||
"pad.modals.looping.explanation": "Există probleme de comunicare cu serverul de sincronizare.",
|
||||
"pad.modals.looping.cause": "Poate că v-ați conectat printr-un firewall sau proxy incompatibil.",
|
||||
"pad.modals.initsocketfail": "Serverul nu este disponibil.",
|
||||
"pad.modals.initsocketfail.explanation": "Nu s-a putut conecta la serverul de sincronizare.",
|
||||
"pad.modals.initsocketfail.cause": "Acest lucru se datorează probabil unei probleme cu browserul sau conexiunea la internet.",
|
||||
"pad.modals.slowcommit.explanation": "Serverul nu răspunde.",
|
||||
"pad.modals.slowcommit.cause": "Aceasta poate fi cauzată de probleme cu conexiunea la rețea.",
|
||||
"pad.modals.badChangeset.explanation": "O editare pe care ai făcut-o a fost clasificată ilegal de serverul de sincronizare.",
|
||||
"pad.modals.badChangeset.cause": "Aceasta s-ar putea datora unei configurații greșite a serverului sau a unui alt comportament neașteptat. Vă rugăm să contactați administratorul de serviciu, dacă considerați că aceasta este o eroare. Încercați să vă reconectați pentru a continua editarea.",
|
||||
"pad.modals.corruptPad.explanation": "Pad-ul pe care încercați să îl accesați este corupt.",
|
||||
"pad.modals.corruptPad.cause": "Aceasta se poate datora unei configurații greșite a serverului sau a unui alt comportament neașteptat. Vă rugăm să contactați administratorul de servicii.",
|
||||
"pad.modals.deleted": "Șters.",
|
||||
"pad.modals.deleted.explanation": "Acest pad a fost șters.",
|
||||
"pad.modals.disconnected": "Ai fost deconectat.",
|
||||
"pad.modals.disconnected.explanation": "S-a pierdut conexiunea la server",
|
||||
"pad.modals.disconnected.cause": "Este posibil ca serverul să nu fie disponibil. Vă rugăm să anunțați administratorul de servicii dacă acest lucru se întâmplă în continuare.",
|
||||
"pad.share": "Distribuie acest pad",
|
||||
"pad.share.readonly": "Doar în citire",
|
||||
"pad.share.link": "Legătură",
|
||||
|
@ -66,6 +91,9 @@
|
|||
"pad.chat": "Chat",
|
||||
"pad.chat.title": "Deschide chat-ul pentru acest pad.",
|
||||
"pad.chat.loadmessages": "Încarcă mai multe mesaje",
|
||||
"pad.chat.stick.title": "Lipiți chatul pe ecran",
|
||||
"pad.chat.writeMessage.placeholder": "Scrie-ți mesajul aici",
|
||||
"timeslider.pageTitle": "{{appTitle}} Glisor de timp",
|
||||
"timeslider.toolbar.returnbutton": "Înapoi la pad",
|
||||
"timeslider.toolbar.authors": "Autori:",
|
||||
"timeslider.toolbar.authorsList": "Niciun autor",
|
||||
|
@ -73,6 +101,9 @@
|
|||
"timeslider.exportCurrent": "Exportă versiunea curentă ca:",
|
||||
"timeslider.version": "Versiunea {{version}}",
|
||||
"timeslider.saved": "Salvat pe {{day}} {{month}} {{year}}",
|
||||
"timeslider.playPause": "Redare / Pauză conținut Pad",
|
||||
"timeslider.backRevision": "Reveniți la o revizuire în acest Pad",
|
||||
"timeslider.forwardRevision": "Continuați o revizuire în acest Pad",
|
||||
"timeslider.dateformat": "{{day}}/{{month}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}",
|
||||
"timeslider.month.january": "ianuarie",
|
||||
"timeslider.month.february": "februarie",
|
||||
|
@ -86,12 +117,24 @@
|
|||
"timeslider.month.october": "octombrie",
|
||||
"timeslider.month.november": "noiembrie",
|
||||
"timeslider.month.december": "decembrie",
|
||||
"timeslider.unnamedauthors": "{{num}} anonim {[plural (num) unul: autor, altul: autori ]}",
|
||||
"pad.savedrevs.marked": "Această revizie este marcată acum ca o revizuire salvată",
|
||||
"pad.savedrevs.timeslider": "Puteți vedea reviziile salvate accesând cursorul de timp",
|
||||
"pad.userlist.entername": "Introduceți numele dumneavoastră",
|
||||
"pad.userlist.unnamed": "fără nume",
|
||||
"pad.userlist.guest": "Oaspete",
|
||||
"pad.userlist.deny": "Respinge",
|
||||
"pad.userlist.approve": "Aprobă",
|
||||
"pad.editbar.clearcolors": "Ștergeți culorile de autor pe întreg documentul? Acest lucru nu poate fi anulat",
|
||||
"pad.impexp.importbutton": "Importă acum",
|
||||
"pad.impexp.importing": "Importare...",
|
||||
"pad.impexp.importfailed": "Import eșuat"
|
||||
"pad.impexp.confirmimport": "Importarea unui fișier va suprascrie textul curent al padului. Ești sigur că vrei să continui?",
|
||||
"pad.impexp.convertFailed": "Nu am putut importa acest fișier. Vă rugăm să utilizați un alt format de document sau să copiați pasta manual",
|
||||
"pad.impexp.padHasData": "Nu am putut importa acest fișier, deoarece acest Pad a avut deja modificări, vă rugăm să importați pe un nou pad",
|
||||
"pad.impexp.uploadFailed": "Încărcarea a eșuat. Încercați din nou",
|
||||
"pad.impexp.importfailed": "Import eșuat",
|
||||
"pad.impexp.copypaste": "Vă rugăm să copiați și să lipiți",
|
||||
"pad.impexp.exportdisabled": "Exportul ca format {{type}} este dezactivat. Vă rugăm să contactați administratorul de sistem pentru detalii.",
|
||||
"pad.impexp.maxFileSize": "Fișier prea mare. Contactați administratorul site-ului pentru a crește dimensiunea permisă a fișierului pentru import",
|
||||
"pad.impexp.permission": "Importul este dezactivat deoarece nu ați contribuit niciodată la această placă. Vă rugăm să contribuiți cel puțin o dată înainte de import"
|
||||
}
|
||||
|
|
|
@ -6,17 +6,20 @@
|
|||
"Diralik",
|
||||
"Eleferen",
|
||||
"Facenapalm",
|
||||
"MSClaudiu",
|
||||
"Movses",
|
||||
"Nzeemin",
|
||||
"Okras",
|
||||
"Patrick Star",
|
||||
"Teretalexev",
|
||||
"Volkov"
|
||||
]
|
||||
},
|
||||
"index.newPad": "Создать",
|
||||
"index.createOpenPad": "или создать/открыть документ с именем:",
|
||||
"pad.toolbar.bold.title": "полужирный (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "курсив (Ctrl-I)",
|
||||
"index.openPad": "откройте существующий документ с именем:",
|
||||
"pad.toolbar.bold.title": "Полужирный (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Курсив (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "подчёркивание (Ctrl-U)",
|
||||
"pad.toolbar.strikethrough.title": "Зачёркивание (Ctrl+5)",
|
||||
"pad.toolbar.ol.title": "Упорядоченный список (Ctrl+Shift+N)",
|
||||
|
@ -26,7 +29,7 @@
|
|||
"pad.toolbar.undo.title": "Отменить (Ctrl-Z)",
|
||||
"pad.toolbar.redo.title": "Вернуть (Ctrl-Y)",
|
||||
"pad.toolbar.clearAuthorship.title": "Очистить цвета документа (Ctrl+Shift+C)",
|
||||
"pad.toolbar.import_export.title": "Импорт/экспорт с использованием различных форматов файлов",
|
||||
"pad.toolbar.import_export.title": "Импорт/экспорт из/в другие форматы файлов",
|
||||
"pad.toolbar.timeslider.title": "Шкала времени",
|
||||
"pad.toolbar.savedRevision.title": "Сохранить версию",
|
||||
"pad.toolbar.settings.title": "Настройки",
|
||||
|
@ -35,7 +38,7 @@
|
|||
"pad.colorpicker.save": "Сохранить",
|
||||
"pad.colorpicker.cancel": "Отмена",
|
||||
"pad.loading": "Загрузка...",
|
||||
"pad.noCookie": "Куки не найдены. Пожалуйста, включите куки в вашем браузере!",
|
||||
"pad.noCookie": "Куки не найдены. Пожалуйста, включите куки в вашем браузере! Ваш сеанс и настройки не будут сохранены между посещениями. Это может быть связано с тем, что Etherpad включен в iFrame в некоторых браузерах. Убедитесь, что Etherpad находится в том же поддомене/домене, что и родительский iFrame.",
|
||||
"pad.passwordRequired": "Вам нужен пароль для доступа",
|
||||
"pad.permissionDenied": "У вас нет разрешения на доступ",
|
||||
"pad.wrongPassword": "Неправильный пароль",
|
||||
|
@ -49,6 +52,8 @@
|
|||
"pad.settings.fontType": "Тип шрифта:",
|
||||
"pad.settings.fontType.normal": "Обычный",
|
||||
"pad.settings.language": "Язык:",
|
||||
"pad.settings.about": "О проекте",
|
||||
"pad.settings.poweredBy": "Проект основан на",
|
||||
"pad.importExport.import_export": "Импорт/экспорт",
|
||||
"pad.importExport.import": "Загрузить любой текстовый файл или документ",
|
||||
"pad.importExport.importSuccessful": "Успешно!",
|
||||
|
@ -83,6 +88,8 @@
|
|||
"pad.modals.corruptPad.cause": "Это может быть из-за неправильной конфигурации сервера или некоторых других неожиданных действий. Пожалуйста, свяжитесь с администратором службы.",
|
||||
"pad.modals.deleted": "Удалён.",
|
||||
"pad.modals.deleted.explanation": "Этот документ был удалён.",
|
||||
"pad.modals.rateLimited": "Скорость ограничена.",
|
||||
"pad.modals.rateLimited.explanation": "Вы отправили слишком много сообщений в этот документ, поэтому вы были отключены.",
|
||||
"pad.modals.disconnected": "Соединение разорвано.",
|
||||
"pad.modals.disconnected.explanation": "Подключение к серверу потеряно",
|
||||
"pad.modals.disconnected.cause": "Сервер, возможно, недоступен. Пожалуйста, сообщите администратору службы, если проблема будет повторятся.",
|
||||
|
@ -95,8 +102,9 @@
|
|||
"pad.chat.loadmessages": "Ещё сообщения",
|
||||
"pad.chat.stick.title": "Закрепить чат на экране",
|
||||
"pad.chat.writeMessage.placeholder": "Напишите своё сообщение сюда",
|
||||
"timeslider.followContents": "Следить за обновлениями содержимого документа",
|
||||
"timeslider.pageTitle": "Временная шкала {{appTitle}}",
|
||||
"timeslider.toolbar.returnbutton": "К документу",
|
||||
"timeslider.toolbar.returnbutton": "Вернуться к документу",
|
||||
"timeslider.toolbar.authors": "Авторы:",
|
||||
"timeslider.toolbar.authorsList": "Нет авторов",
|
||||
"timeslider.toolbar.exportlink.title": "Экспорт",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"@metadata": {
|
||||
"authors": [
|
||||
"BaRaN6161 TURK",
|
||||
"Mehtab ahmed",
|
||||
"Tweety"
|
||||
]
|
||||
|
@ -66,7 +67,7 @@
|
|||
"timeslider.toolbar.exportlink.title": "برآمد ڪريو",
|
||||
"timeslider.version": "ورزن {{version}}",
|
||||
"timeslider.saved": "سانڍيل {{month}} {{day}}، {{year}}",
|
||||
"timeslider.dateformat": "{{مهينو}}/{{ڏينهن}}/{{سال}} {{ڪلاڪ}}:{{منٽ}}:{{سيڪنڊ}}",
|
||||
"timeslider.dateformat": "{{month}}/{{day}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}",
|
||||
"timeslider.month.january": "جنوري",
|
||||
"timeslider.month.february": "فيبروري",
|
||||
"timeslider.month.march": "مارچ",
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"Milicevic01",
|
||||
"Obsuser",
|
||||
"Srdjan m",
|
||||
"Srđan",
|
||||
"Милан Јелисавчић"
|
||||
]
|
||||
},
|
||||
|
@ -46,6 +47,8 @@
|
|||
"pad.settings.fontType": "Врста фонта:",
|
||||
"pad.settings.fontType.normal": "Нормално",
|
||||
"pad.settings.language": "Језик:",
|
||||
"pad.settings.about": "О пројекту",
|
||||
"pad.settings.poweredBy": "Покреће",
|
||||
"pad.importExport.import_export": "Увоз/извоз",
|
||||
"pad.importExport.import": "Отпремите било коју текстуалну датотеку или документ",
|
||||
"pad.importExport.importSuccessful": "Успешно!",
|
||||
|
|
|
@ -3,21 +3,23 @@
|
|||
"authors": [
|
||||
"Jopparn",
|
||||
"Lokal Profil",
|
||||
"Sabelöga",
|
||||
"WikiPhoenix"
|
||||
]
|
||||
},
|
||||
"index.newPad": "Nytt block",
|
||||
"index.createOpenPad": "eller skapa/öppna ett block med namnet:",
|
||||
"pad.toolbar.bold.title": "Fet (Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "Kursiv (Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "Understruken (Ctrl-U)",
|
||||
"index.openPad": "öppna ett befintligt block med namnet:",
|
||||
"pad.toolbar.bold.title": "Fet (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "Kursiv (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "Understruken (Ctrl+U)",
|
||||
"pad.toolbar.strikethrough.title": "Genomstruken (Ctrl+5)",
|
||||
"pad.toolbar.ol.title": "Numrerad lista (Ctrl+Shift+N)",
|
||||
"pad.toolbar.ul.title": "Onumrerad lista (Ctrl+Shift+L)",
|
||||
"pad.toolbar.indent.title": "Öka indrag (TABB)",
|
||||
"pad.toolbar.unindent.title": "Minska indrag (Shift+TABB)",
|
||||
"pad.toolbar.undo.title": "Ångra (Ctrl-Z)",
|
||||
"pad.toolbar.redo.title": "Gör om (Ctrl-Y)",
|
||||
"pad.toolbar.undo.title": "Ångra (Ctrl+Z)",
|
||||
"pad.toolbar.redo.title": "Gör om (Ctrl+Y)",
|
||||
"pad.toolbar.clearAuthorship.title": "Rensa författarfärger (Ctrl+Shift+C)",
|
||||
"pad.toolbar.import_export.title": "Importera/exportera från/till olika filformat",
|
||||
"pad.toolbar.timeslider.title": "Tidsreglage",
|
||||
|
@ -28,7 +30,7 @@
|
|||
"pad.colorpicker.save": "Spara",
|
||||
"pad.colorpicker.cancel": "Avbryt",
|
||||
"pad.loading": "Läser in...",
|
||||
"pad.noCookie": "Kunde inte hitta några kakor. Var god tillåt kakor i din webbläsare!",
|
||||
"pad.noCookie": "Kunde inte hitta några kakor. Var god tillåt kakor i din webbläsare! Din session och inställningar kommer inte sparas mellan dina besök. Detta kan bero på att Etherpad inte ligger inuti en iFrame i vissa webbläsare. Se till att Etherpad är i samma underdomän/domän som det överordnade iFrame-elementet.",
|
||||
"pad.passwordRequired": "Du behöver ett lösenord för att få tillgång till detta block",
|
||||
"pad.permissionDenied": "Du har inte åtkomstbehörighet för detta block",
|
||||
"pad.wrongPassword": "Ditt lösenord var fel",
|
||||
|
@ -42,10 +44,12 @@
|
|||
"pad.settings.fontType": "Typsnitt:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Språk:",
|
||||
"pad.settings.about": "Om",
|
||||
"pad.settings.poweredBy": "Drivs av",
|
||||
"pad.importExport.import_export": "Importera/Exportera",
|
||||
"pad.importExport.import": "Ladda upp textfiler eller dokument",
|
||||
"pad.importExport.importSuccessful": "Åtgärden slutfördes!",
|
||||
"pad.importExport.export": "Export aktuellt block som:",
|
||||
"pad.importExport.export": "Exportera aktuellt block som:",
|
||||
"pad.importExport.exportetherpad": "Etherpad",
|
||||
"pad.importExport.exporthtml": "HTML",
|
||||
"pad.importExport.exportplain": "Oformaterad text",
|
||||
|
@ -76,6 +80,8 @@
|
|||
"pad.modals.corruptPad.cause": "Detta kan bero på en felaktig konfiguration av servern eller något annat oväntad beteende. Var god kontakta tjänstadministratören.",
|
||||
"pad.modals.deleted": "Raderad.",
|
||||
"pad.modals.deleted.explanation": "Detta block har tagits bort.",
|
||||
"pad.modals.rateLimited": "Begränsad frekvens.",
|
||||
"pad.modals.rateLimited.explanation": "Du skickade för många meddelanden till detta block så du blev frånkopplad.",
|
||||
"pad.modals.disconnected": "Du har blivit frånkopplad.",
|
||||
"pad.modals.disconnected.explanation": "Anslutningen till servern avbröts",
|
||||
"pad.modals.disconnected.cause": "Servern kanske är otillgänglig. Var god meddela tjänstadministratören om detta fortsätter att hända.",
|
||||
|
@ -88,6 +94,7 @@
|
|||
"pad.chat.loadmessages": "Läs in fler meddelanden",
|
||||
"pad.chat.stick.title": "Fäst chatten på skärmen",
|
||||
"pad.chat.writeMessage.placeholder": "Skriv ditt meddelande här",
|
||||
"timeslider.followContents": "Följ uppdateringar om blockets innehåll",
|
||||
"timeslider.pageTitle": "{{appTitle}} tidsreglage",
|
||||
"timeslider.toolbar.returnbutton": "Återvänd till blocket",
|
||||
"timeslider.toolbar.authors": "Författare:",
|
||||
|
@ -131,5 +138,5 @@
|
|||
"pad.impexp.copypaste": "Var god kopiera och klistra in",
|
||||
"pad.impexp.exportdisabled": "Exportering av formatet {{type}} är inaktiverad. Var god kontakta din systemadministratör för mer information.",
|
||||
"pad.impexp.maxFileSize": "Filen är för stor. Kontakta din systemadministratör för att öka den tillåtna filstorleken för importering",
|
||||
"pad.impexp.permission": "Import är inaktiverat eftersom du aldrig har bidragit detta block. var god bidra minst en gång innan du importerar"
|
||||
"pad.impexp.permission": "Importering är inaktiverat eftersom du aldrig har bidragit till detta block. Var god bidra minst en gång innan du importerar"
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
"pad.settings.fontType": "అక్షరశైలి రకం:",
|
||||
"pad.settings.fontType.normal": "సాధారణ",
|
||||
"pad.settings.language": "భాష",
|
||||
"pad.settings.about": "గురించి",
|
||||
"pad.importExport.import_export": "దిగుమతి/ఎగుమతి",
|
||||
"pad.importExport.import": "పాఠము దస్త్రము లేదా పత్రమును దిగుమతి చేయుము",
|
||||
"pad.importExport.importSuccessful": "విజయవంతం!",
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
{
|
||||
"@metadata": {
|
||||
"authors": [
|
||||
"Aefgh39622"
|
||||
"Aefgh39622",
|
||||
"Patsagorn Y."
|
||||
]
|
||||
},
|
||||
"index.newPad": "สร้างแผ่นจดบันทึกใหม่",
|
||||
"index.createOpenPad": "หรือสร้าง/เปิดแผ่นจดบันทึกที่มีชื่อ:",
|
||||
"index.openPad": "เปิดแพดที่มีอยู่แล้วด้วยชื่อ:",
|
||||
"pad.toolbar.bold.title": "ตัวหนา (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "ตัวเอียง (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "ขีดเส้นใต้ (Ctrl+U)",
|
||||
|
@ -26,10 +28,10 @@
|
|||
"pad.colorpicker.save": "บันทึก",
|
||||
"pad.colorpicker.cancel": "ยกเลิก",
|
||||
"pad.loading": "กำลังโหลด...",
|
||||
"pad.noCookie": "ไม่พบคุกกี้ โปรดเปิดใช้งานคุกกี้ในเบราว์เซอร์ของคุณ!",
|
||||
"pad.noCookie": "ไม่พบคุกกี้ กรุณาอนุญาติคุกกี้บนเบราว์เซอร์ของคุณ การเข้าสู่ระบบและการตั้งค่าจะไม่ถูกบันทึกขณะเยี่ยมชม อาจเกิดปัญหาจากอีเทอร์แพดถูกฝังไว้ในหน้าผ่าน iFrame ในบางเบราว์เซอร์ กรุณาตรวจสอบว่าอีเทอร์แพดอยู่ในโดเมนหรือโดเมนรองเดียวกันกับหน้าที่ฝัง iFrame",
|
||||
"pad.passwordRequired": "คุณต้องใช้รหัสผ่านเพื่อเข้าถึงแผ่นจดบันทึกนี้",
|
||||
"pad.permissionDenied": "คุณไม่มีสิทธิ์เข้าถึงแผ่นจดบันทึกนี้",
|
||||
"pad.wrongPassword": "รหัสผ่านของคุณผิด",
|
||||
"pad.wrongPassword": "รหัสผ่านไม่ถูกต้อง",
|
||||
"pad.settings.padSettings": "การตั้งค่าแผ่นจดบันทึก",
|
||||
"pad.settings.myView": "มุมมองของฉัน",
|
||||
"pad.settings.stickychat": "แสดงการแชทบนหน้าจอเสมอ",
|
||||
|
@ -39,6 +41,8 @@
|
|||
"pad.settings.rtlcheck": "อ่านเนื้อหาจากขวาไปซ้ายหรือไม่?",
|
||||
"pad.settings.fontType": "ชนิดแบบอักษร:",
|
||||
"pad.settings.language": "ภาษา:",
|
||||
"pad.settings.about": "เกี่ยวกับ",
|
||||
"pad.settings.poweredBy": "ขับเคลื่อนโดย $1",
|
||||
"pad.importExport.import_export": "นำเข้า/ส่งออก",
|
||||
"pad.importExport.import": "อัปโหลดไฟล์ข้อความหรือเอกสารใดๆ",
|
||||
"pad.importExport.importSuccessful": "สำเร็จ!",
|
||||
|
@ -49,7 +53,7 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||
"pad.importExport.abiword.innerHTML": "คุณสามารถนำเข้าได้จากรูปแบบ HTML หรือข้อความธรรมดาเท่านั้น สำหรับคุณสมบัติการนำเข้าขั้นสูงเพิ่มเติม โปรด<a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">ติดตั้ง AbiWord</a>",
|
||||
"pad.importExport.abiword.innerHTML": "คุณสามารถนำเข้าได้จากรูปแบบ HTML หรือข้อความธรรมดาเท่านั้น สำหรับคุณสมบัติการนำเข้าขั้นสูงเพิ่มเติม โปรด<a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">ติดตั้ง AbiWord หรือ LibraOffice</a>",
|
||||
"pad.modals.connected": "เชื่อมต่อแล้ว",
|
||||
"pad.modals.reconnecting": "กำลังเชื่อมต่อกับแผ่นจดบันทึกของคุณใหม่..",
|
||||
"pad.modals.forcereconnect": "บังคับเชื่อมต่อใหม่",
|
||||
|
@ -73,6 +77,8 @@
|
|||
"pad.modals.corruptPad.cause": "อาจเป็นเนื่องจากการกำหนดค่าเซิร์ฟเวอร์ไม่ถูกต้องหรือมีลักษณะการทำงานอื่นๆ บางอย่างที่ไม่คาดคิด โปรดติดต่อผู้ดูแลการให้บริการ",
|
||||
"pad.modals.deleted": "ลบแล้ว",
|
||||
"pad.modals.deleted.explanation": "แผ่นจดบันทึกนี้ได้ถูกลบออกแล้ว",
|
||||
"pad.modals.rateLimited": "ถึงขีดจำกัด",
|
||||
"pad.modals.rateLimited.explanation": "คณส่งข้อความถึงแพดนี้มากเกินไปจึงถูกตัดการเชื่อมโดยโปรแกรมอัตโนมัติ",
|
||||
"pad.modals.disconnected": "คุณได้ตัดการเชื่อมต่อแล้ว",
|
||||
"pad.modals.disconnected.explanation": "การเชื่อมต่อกับเซิร์ฟเวอร์ถูกตัด",
|
||||
"pad.modals.disconnected.cause": "เซิร์ฟเวอร์อาจใช้ไม่ได้ชั่วคราว โปรดแจ้งให้ผู้ดูแลการให้บริการทราบถ้าปัญหานี้ยังคงเกิดขึ้น",
|
||||
|
@ -83,6 +89,9 @@
|
|||
"pad.chat": "แชท",
|
||||
"pad.chat.title": "เปิดการแชทสำหรับแผ่นจดบันทึกนี้",
|
||||
"pad.chat.loadmessages": "โหลดข้อความเพิ่มเติม",
|
||||
"pad.chat.stick.title": "ปักการสนทนาไว้บนหน้าจอ",
|
||||
"pad.chat.writeMessage.placeholder": "เขียนข้อความ...",
|
||||
"timeslider.followContents": "ติดตามการอัพเดตเนื้อหาแพด",
|
||||
"timeslider.pageTitle": "ตัวเลื่อนเวลา {{appTitle}}",
|
||||
"timeslider.toolbar.returnbutton": "กลับไปแผ่นจดบันทึก",
|
||||
"timeslider.toolbar.authors": "ผู้เขียน:",
|
||||
|
@ -112,11 +121,11 @@
|
|||
"pad.savedrevs.timeslider": "คุณสามารถดูรุ่นแก้ไขที่บันทึกแล้วโดยเยี่ยมชมตัวเลื่อนเวลา",
|
||||
"pad.userlist.entername": "กรอกชื่อของคุณ",
|
||||
"pad.userlist.unnamed": "ไม่มีชื่อ",
|
||||
"pad.userlist.guest": "ผู้เยี่ยมชม",
|
||||
"pad.userlist.guest": "นิรนาม",
|
||||
"pad.userlist.deny": "ปฏิเสธ",
|
||||
"pad.userlist.approve": "อนุมัติ",
|
||||
"pad.editbar.clearcolors": "ล้างสีผู้เขียนบนทั้งเอกสารหรือไม่?",
|
||||
"pad.impexp.importbutton": "นำเข้าเดี๋ยวนี้",
|
||||
"pad.userlist.approve": "อนุญาต",
|
||||
"pad.editbar.clearcolors": "ลบการเน้นความเป็นเจ้าของข้อความหรือไม่? การกระทำนี่ไม่สามารถย้อนได้",
|
||||
"pad.impexp.importbutton": "นำเข้าตอนนี้",
|
||||
"pad.impexp.importing": "กำลังนำเข้า...",
|
||||
"pad.impexp.confirmimport": "การนำเข้าไฟล์จะเป็นการเขียนทับข้อความปัจจุบันบนแผ่นจดบันทึก คุณแน่ใจหรือว่าคุณต้องการดำเนินการต่อ?",
|
||||
"pad.impexp.convertFailed": "เราไม่สามารถนำเข้าไฟล์นี้ได้ โปรดใช้รูปแบบเอกสารอื่นหรือคัดลอกแล้ววางด้วยตนเอง",
|
||||
|
@ -124,5 +133,7 @@
|
|||
"pad.impexp.uploadFailed": "การอัปโหลดล้มเหลว โปรดลองอีกครั้ง",
|
||||
"pad.impexp.importfailed": "การนำเข้าล้มเหลว",
|
||||
"pad.impexp.copypaste": "โปรดคัดลอกแล้ววาง",
|
||||
"pad.impexp.exportdisabled": "การส่งออกเป็นรูปแบบ {{type}} ถูกปิดใช้งาน โปรดติดต่อผู้ดูแลระบบของคุณสำหรับรายละเอียดเพิ่มเติม"
|
||||
"pad.impexp.exportdisabled": "การส่งออกเป็นรูปแบบ {{type}} ถูกปิดใช้งาน โปรดติดต่อผู้ดูแลระบบของคุณสำหรับรายละเอียดเพิ่มเติม",
|
||||
"pad.impexp.maxFileSize": "ไฟล์ใหญ่เกินไป ติดต่อผู้ดูแลไซต์เพื่อให้ขยายขนาดไฟล์ที่นำเข้าได้",
|
||||
"pad.impexp.permission": "การนำเข้าถูกปิดเนื่องจากคุณไม่เคยมีส่วนร่วมในแพดนี้ กรุณามีส่วนร่วมซักครั้งหนึ่งก่อนนำเข้า"
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
},
|
||||
"index.newPad": "Yeni Bloknot",
|
||||
"index.createOpenPad": "veya şu adla bir Bloknot oluşturun/açın:",
|
||||
"index.openPad": "şu adla varolan bir Pad'i açın:",
|
||||
"pad.toolbar.bold.title": "Kalın (Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "Eğik (Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "Altı Çizili (Ctrl+U)",
|
||||
|
@ -35,7 +36,7 @@
|
|||
"pad.colorpicker.save": "Kaydet",
|
||||
"pad.colorpicker.cancel": "İptal",
|
||||
"pad.loading": "Yükleniyor...",
|
||||
"pad.noCookie": "Çerez bulunamadı. Lütfen tarayıcınızda çerezlere izin veriniz!",
|
||||
"pad.noCookie": "Çerez bulunamadı. Lütfen tarayıcınızda çerezlere izin veriniz! Lütfen tarayıcınızda çerezlere izin verin! Oturumunuz ve ayarlarınız ziyaretler arasında kaydedilmez. Bunun nedeni, Etherpad'in bazı Tarayıcılarda bir iFrame'e dahil edilmiş olması olabilir. Lütfen Etherpad'in üst iFrame ile aynı alt alanda/alanda olduğundan emin olun",
|
||||
"pad.passwordRequired": "Bu bloknota erişebilmeniz için parolaya ihtiyacınız var",
|
||||
"pad.permissionDenied": "Bu bloknota erişmeye izniniz yok",
|
||||
"pad.wrongPassword": "Parolanız yanlış",
|
||||
|
@ -49,6 +50,8 @@
|
|||
"pad.settings.fontType": "Yazı tipi:",
|
||||
"pad.settings.fontType.normal": "Olağan",
|
||||
"pad.settings.language": "Dil:",
|
||||
"pad.settings.about": "Hakkında",
|
||||
"pad.settings.poweredBy": "Destekleyen",
|
||||
"pad.importExport.import_export": "İçe/Dışa aktar",
|
||||
"pad.importExport.import": "Herhangi bir metin dosyası ya da belgesi yükle",
|
||||
"pad.importExport.importSuccessful": "Başarılı!",
|
||||
|
@ -83,11 +86,13 @@
|
|||
"pad.modals.corruptPad.cause": "Bunun nedeni yanlış bir sunucu yapılandırması veya beklenmeyen başka bir davranış olabilir. Lütfen servis yöneticisine başvurun.",
|
||||
"pad.modals.deleted": "Silindi.",
|
||||
"pad.modals.deleted.explanation": "Bu bloknot kaldırılmış.",
|
||||
"pad.modals.rateLimited": "Oran Sınırlı.",
|
||||
"pad.modals.rateLimited.explanation": "Bu pad'e çok fazla mesaj gönderdiniz, böylece bağlantı kesildi.",
|
||||
"pad.modals.disconnected": "Bağlantınız koptu.",
|
||||
"pad.modals.disconnected.explanation": "Sunucu bağlantısı kaybedildi",
|
||||
"pad.modals.disconnected.cause": "Sunucu kullanılamıyor olabilir. Bunun devam etmesi durumunda servis yöneticisine bildirin.",
|
||||
"pad.share": "Bu bloknotu paylaş",
|
||||
"pad.share.readonly": "Sadece oku",
|
||||
"pad.share.readonly": "Yalnızca oku",
|
||||
"pad.share.link": "Bağlantı",
|
||||
"pad.share.emebdcode": "URL'yi göm",
|
||||
"pad.chat": "Sohbet",
|
||||
|
@ -95,6 +100,7 @@
|
|||
"pad.chat.loadmessages": "Daha fazla mesaj yükle",
|
||||
"pad.chat.stick.title": "Sohbeti ekrana yapıştır",
|
||||
"pad.chat.writeMessage.placeholder": "Mesajını buraya yaz",
|
||||
"timeslider.followContents": "Pad içerik güncellemelerini takip edin",
|
||||
"timeslider.pageTitle": "{{appTitle}} Zaman Çizelgesi",
|
||||
"timeslider.toolbar.returnbutton": "Bloknota geri dön",
|
||||
"timeslider.toolbar.authors": "Yazarlar:",
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
"pad.toolbar.timeslider.title": "Prexentasion storego",
|
||||
"pad.toolbar.savedRevision.title": "Version salvada",
|
||||
"pad.toolbar.settings.title": "Inpostasion",
|
||||
"pad.toolbar.embed.title": "Spartisi e incorpora sto Pad",
|
||||
"pad.toolbar.embed.title": "Spartisi o incastra sto Pad",
|
||||
"pad.toolbar.showusers.title": "Varda i utenti so sto Pad",
|
||||
"pad.colorpicker.save": "Salva",
|
||||
"pad.colorpicker.cancel": "Descançełare",
|
||||
|
|
|
@ -13,11 +13,14 @@
|
|||
"VulpesVulpes825",
|
||||
"Yfdyh000",
|
||||
"乌拉跨氪",
|
||||
"列维劳德",
|
||||
"沈澄心",
|
||||
"燃玉"
|
||||
]
|
||||
},
|
||||
"index.newPad": "新记事本",
|
||||
"index.createOpenPad": "或者创建/打开带名字的记事本:",
|
||||
"index.openPad": "打开一个现有的记事本,名称为:",
|
||||
"pad.toolbar.bold.title": "粗体(Ctrl-B)",
|
||||
"pad.toolbar.italic.title": "斜体(Ctrl-I)",
|
||||
"pad.toolbar.underline.title": "下划线(Ctrl-U)",
|
||||
|
@ -38,7 +41,7 @@
|
|||
"pad.colorpicker.save": "保存",
|
||||
"pad.colorpicker.cancel": "取消",
|
||||
"pad.loading": "载入中……",
|
||||
"pad.noCookie": "无法找到Cookie。请在您的浏览器中允许Cookie!",
|
||||
"pad.noCookie": "无法找到Cookie。请在您的浏览器中允许Cookie!您的会话和设置不会在访问时保存。这可能是由于Etherpad包含在某些浏览器中的iFrame中。请确保Etherpad与父iFrame位于同一子域/域上",
|
||||
"pad.passwordRequired": "您需要密码才能访问这个记事本",
|
||||
"pad.permissionDenied": "您没有访问这个记事本的权限",
|
||||
"pad.wrongPassword": "您的密码错了",
|
||||
|
@ -52,6 +55,8 @@
|
|||
"pad.settings.fontType": "字体类型:",
|
||||
"pad.settings.fontType.normal": "正常",
|
||||
"pad.settings.language": "语言:",
|
||||
"pad.settings.about": "关于",
|
||||
"pad.settings.poweredBy": "技术支持来自",
|
||||
"pad.importExport.import_export": "导入/导出",
|
||||
"pad.importExport.import": "上载任何文本文件或档案",
|
||||
"pad.importExport.importSuccessful": "成功!",
|
||||
|
@ -62,7 +67,7 @@
|
|||
"pad.importExport.exportword": "Microsoft Word",
|
||||
"pad.importExport.exportpdf": "PDF",
|
||||
"pad.importExport.exportopen": "ODF(开放文档格式)",
|
||||
"pad.importExport.abiword.innerHTML": "您只可以导入纯文本或HTML格式。要获取更高级的导入功能,请<a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">安装AbiWord</a>。",
|
||||
"pad.importExport.abiword.innerHTML": "您只可以导入纯文本或HTML格式。要获取更高级的导入功能,请<a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">安装 AbiWord 或是 LibreOffice</a>。",
|
||||
"pad.modals.connected": "已连接。",
|
||||
"pad.modals.reconnecting": "重新连接到您的记事本...",
|
||||
"pad.modals.forcereconnect": "强制重新连接",
|
||||
|
@ -86,6 +91,8 @@
|
|||
"pad.modals.corruptPad.cause": "这可能是因为服务器配置的错误或者其他未预料到的行为。请联系服务管理员。",
|
||||
"pad.modals.deleted": "已删除。",
|
||||
"pad.modals.deleted.explanation": "此记事本已被移除。",
|
||||
"pad.modals.rateLimited": "速率限制",
|
||||
"pad.modals.rateLimited.explanation": "您向此记事本发送了太多消息,因此中断了与您的连接。",
|
||||
"pad.modals.disconnected": "您已断开连接。",
|
||||
"pad.modals.disconnected.explanation": "到服务器的连接已丢失",
|
||||
"pad.modals.disconnected.cause": "服务器可能无法使用。若此情况持续发生,请通知服务器管理员。",
|
||||
|
@ -98,6 +105,7 @@
|
|||
"pad.chat.loadmessages": "加载更多信息",
|
||||
"pad.chat.stick.title": "在屏幕上固定聊天界面",
|
||||
"pad.chat.writeMessage.placeholder": "在此写下您的消息",
|
||||
"timeslider.followContents": "跟随记事本的内容更新",
|
||||
"timeslider.pageTitle": "{{appTitle}} 时间轴",
|
||||
"timeslider.toolbar.returnbutton": "返回记事本",
|
||||
"timeslider.toolbar.authors": "作者:",
|
||||
|
@ -130,7 +138,7 @@
|
|||
"pad.userlist.guest": "访客",
|
||||
"pad.userlist.deny": "拒绝",
|
||||
"pad.userlist.approve": "批准",
|
||||
"pad.editbar.clearcolors": "清除整个文档的作者颜色吗?",
|
||||
"pad.editbar.clearcolors": "清除整个文档的作者颜色吗?此操作无法撤消",
|
||||
"pad.impexp.importbutton": "现在导入",
|
||||
"pad.impexp.importing": "正在导入...",
|
||||
"pad.impexp.confirmimport": "导入的文件将覆盖记事本的当前文本。你确定要继续吗?",
|
||||
|
@ -139,5 +147,7 @@
|
|||
"pad.impexp.uploadFailed": "上载失败,请重试",
|
||||
"pad.impexp.importfailed": "导入失败",
|
||||
"pad.impexp.copypaste": "请复制粘贴",
|
||||
"pad.impexp.exportdisabled": "{{type}} 格式的导出被禁用。有关详情,请与您的系统管理员联系。"
|
||||
"pad.impexp.exportdisabled": "{{type}} 格式的导出被禁用。有关详情,请与您的系统管理员联系。",
|
||||
"pad.impexp.maxFileSize": "文件太大。 请与您的站点管理员联系以增加允许导入的文件大小",
|
||||
"pad.impexp.permission": "因为你从未为在此记事本做出任何贡献,导入已被禁用。在导入之前,请至少贡献一次"
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
},
|
||||
"index.newPad": "新記事本",
|
||||
"index.createOpenPad": "或建立/開啟以下名稱的記事本:",
|
||||
"index.openPad": "開啟一個現有的記事本,名稱為:",
|
||||
"pad.toolbar.bold.title": "粗體(Ctrl+B)",
|
||||
"pad.toolbar.italic.title": "斜體(Ctrl+I)",
|
||||
"pad.toolbar.underline.title": "底線(Ctrl+U)",
|
||||
|
@ -34,7 +35,7 @@
|
|||
"pad.colorpicker.save": "儲存",
|
||||
"pad.colorpicker.cancel": "取消",
|
||||
"pad.loading": "載入中...",
|
||||
"pad.noCookie": "找不到 Cookie。請允許瀏覽器使用 Cookie!",
|
||||
"pad.noCookie": "找不到 Cookie。請允許瀏覽器使用 Cookie!您的 session 與設定沒有在訪問期間被儲存下來,這可能是因為在某些瀏覽器裡 Etherpad 被包在 iFrame 中,請確認 Etherpad 是在父層級的 iFrame 相同的網域/子網域。",
|
||||
"pad.passwordRequired": "您需要密碼才能存取這個記事本",
|
||||
"pad.permissionDenied": "你沒有存取這個記事本的權限",
|
||||
"pad.wrongPassword": "密碼錯誤",
|
||||
|
@ -48,6 +49,8 @@
|
|||
"pad.settings.fontType": "字型類型:",
|
||||
"pad.settings.fontType.normal": "正常",
|
||||
"pad.settings.language": "語言:",
|
||||
"pad.settings.about": "關於",
|
||||
"pad.settings.poweredBy": "技術提供來自",
|
||||
"pad.importExport.import_export": "匯入/匯出",
|
||||
"pad.importExport.import": "上載任何文字檔或文件",
|
||||
"pad.importExport.importSuccessful": "完成!",
|
||||
|
@ -82,6 +85,8 @@
|
|||
"pad.modals.corruptPad.cause": "這可能由於伺服器的配置錯誤或遇到意外問題。請聯繫伺服器管理員。",
|
||||
"pad.modals.deleted": "已刪除。",
|
||||
"pad.modals.deleted.explanation": "此記事本已被移除。",
|
||||
"pad.modals.rateLimited": "比例限制。",
|
||||
"pad.modals.rateLimited.explanation": "您發送太多訊息到此記事本,因此中斷了您的連結。",
|
||||
"pad.modals.disconnected": "您已中斷連線。",
|
||||
"pad.modals.disconnected.explanation": "伺服器連接曾中斷",
|
||||
"pad.modals.disconnected.cause": "伺服器可能無法使用。若此情況持續發生,請通知伺服器管理員。",
|
||||
|
@ -94,6 +99,7 @@
|
|||
"pad.chat.loadmessages": "載入更多訊息",
|
||||
"pad.chat.stick.title": "釘住聊天在螢幕上",
|
||||
"pad.chat.writeMessage.placeholder": "在此編寫您的訊息",
|
||||
"timeslider.followContents": "關注記事本內容更新",
|
||||
"timeslider.pageTitle": "{{appTitle}}時間軸",
|
||||
"timeslider.toolbar.returnbutton": "返回到記事本",
|
||||
"timeslider.toolbar.authors": "協作者:",
|
||||
|
|
|
@ -50,7 +50,7 @@ exports.deleteGroup = async function(groupID)
|
|||
|
||||
// iterate through group2sessions and delete all sessions
|
||||
let group2sessions = await db.get("group2sessions:" + groupID);
|
||||
let sessions = group2sessions ? group2sessions.sessionsIDs : {};
|
||||
let sessions = group2sessions ? group2sessions.sessionIDs : {};
|
||||
|
||||
// loop through all sessions and delete them (in parallel)
|
||||
await Promise.all(Object.keys(sessions).map(session => {
|
||||
|
|
|
@ -93,6 +93,7 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
|||
}
|
||||
|
||||
if (newRev % 100 == 0) {
|
||||
newRevData.meta.pool = this.pool;
|
||||
newRevData.meta.atext = this.atext;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,30 +26,41 @@ var settings = require("../utils/Settings");
|
|||
var log4js = require('log4js');
|
||||
var authLogger = log4js.getLogger("auth");
|
||||
|
||||
const DENY = Object.freeze({accessStatus: 'deny'});
|
||||
const WRONG_PASSWORD = Object.freeze({accessStatus: 'wrongPassword'});
|
||||
const NEED_PASSWORD = Object.freeze({accessStatus: 'needPassword'});
|
||||
|
||||
/**
|
||||
* This function controlls the access to a pad, it checks if the user can access a pad.
|
||||
* @param padID the pad the user wants to access
|
||||
* @param sessionCookie the session the user has (set via api)
|
||||
* @param token a random token representing the author, of the form
|
||||
* t.randomstring_of_lenght_20. The random string is generated by
|
||||
* the client.
|
||||
* Used for every pad in the web UI. Not used for the HTTP API.
|
||||
* @param password the password the user has given to access this pad, can be null
|
||||
* @return {accessStatus: grant|deny|wrongPassword|needPassword, authorID: a.xxxxxx})
|
||||
* Determines whether the user can access a pad.
|
||||
*
|
||||
* @param padID identifies the pad the user wants to access.
|
||||
* @param sessionCookie identifies the sessions the user created via the HTTP API, if any.
|
||||
* Note: The term "session" used here is unrelated to express-session.
|
||||
* @param token is a random token of the form t.randomstring_of_length_20 generated by the client
|
||||
* when using the web UI (not the HTTP API). This token is only used if settings.requireSession
|
||||
* is false and the user is accessing a public pad. If there is not an author already associated
|
||||
* with this token then a new author object is created (including generating an author ID) and
|
||||
* associated with this token.
|
||||
* @param password is the password the user has given to access this pad. It can be null.
|
||||
* @return {accessStatus: grant|deny|wrongPassword|needPassword, authorID: a.xxxxxx}. The caller
|
||||
* must use the author ID returned in this object when making any changes associated with the
|
||||
* author.
|
||||
*
|
||||
* WARNING: Tokens and session IDs MUST be kept secret, otherwise users will be able to impersonate
|
||||
* each other (which might allow them to gain privileges).
|
||||
*
|
||||
* TODO: Add a hook so that plugins can make access decisions.
|
||||
*/
|
||||
exports.checkAccess = async function(padID, sessionCookie, token, password)
|
||||
{
|
||||
// immutable object
|
||||
let deny = Object.freeze({ accessStatus: "deny" });
|
||||
|
||||
if (!padID) {
|
||||
return deny;
|
||||
return DENY;
|
||||
}
|
||||
|
||||
// allow plugins to deny access
|
||||
var deniedByHook = hooks.callAll("onAccessCheck", {'padID': padID, 'password': password, 'token': token, 'sessionCookie': sessionCookie}).indexOf(false) > -1;
|
||||
if (deniedByHook) {
|
||||
return deny;
|
||||
return DENY;
|
||||
}
|
||||
|
||||
// start to get author for this token
|
||||
|
@ -62,31 +73,14 @@ exports.checkAccess = async function(padID, sessionCookie, token, password)
|
|||
// a valid session is required (api-only mode)
|
||||
if (!sessionCookie) {
|
||||
// without sessionCookie, access is denied
|
||||
return deny;
|
||||
return DENY;
|
||||
}
|
||||
} else {
|
||||
// a session is not required, so we'll check if it's a public pad
|
||||
if (padID.indexOf("$") === -1) {
|
||||
// it's not a group pad, means we can grant access
|
||||
|
||||
// assume user has access
|
||||
let authorID = await p_tokenAuthor;
|
||||
let statusObject = { accessStatus: "grant", authorID };
|
||||
|
||||
if (settings.editOnly) {
|
||||
// user can't create pads
|
||||
|
||||
let padExists = await p_padExists;
|
||||
|
||||
if (!padExists) {
|
||||
// pad doesn't exist - user can't have access
|
||||
statusObject.accessStatus = "deny";
|
||||
}
|
||||
}
|
||||
|
||||
// user may create new pads - no need to check anything
|
||||
// grant access, with author of token
|
||||
return statusObject;
|
||||
if (settings.editOnly && !(await p_padExists)) return DENY;
|
||||
return {accessStatus: 'grant', authorID: await p_tokenAuthor};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,14 +201,14 @@ exports.checkAccess = async function(padID, sessionCookie, token, password)
|
|||
// - the pad is password protected but wrong password given
|
||||
|
||||
// --> deny access, ask for new password and tell them that the password is wrong
|
||||
return { accessStatus: "wrongPassword" };
|
||||
return WRONG_PASSWORD;
|
||||
}
|
||||
|
||||
if (isPasswordProtected && passwordStatus === "notGiven") {
|
||||
// - the pad is password protected but no password given
|
||||
|
||||
// --> ask for password
|
||||
return { accessStatus: "needPassword" };
|
||||
return NEED_PASSWORD;
|
||||
}
|
||||
|
||||
throw new Error("Oops, something wrong happend");
|
||||
|
@ -230,7 +224,7 @@ exports.checkAccess = async function(padID, sessionCookie, token, password)
|
|||
// --> deny access if user isn't allowed to create the pad
|
||||
if (settings.editOnly) {
|
||||
authLogger.debug("Auth failed: valid session & pad does not exist");
|
||||
accessStatus = "deny";
|
||||
return DENY;
|
||||
}
|
||||
|
||||
return { accessStatus, authorID };
|
||||
|
@ -260,14 +254,14 @@ exports.checkAccess = async function(padID, sessionCookie, token, password)
|
|||
// - it's public and the pad is password protected but wrong password given
|
||||
|
||||
// --> deny access, ask for new password and tell them that the password is wrong
|
||||
return { accessStatus: "wrongPassword" };
|
||||
return WRONG_PASSWORD;
|
||||
}
|
||||
|
||||
if (isPublic && isPasswordProtected && passwordStatus === "notGiven") {
|
||||
// - it's public and the pad is password protected but no password given
|
||||
|
||||
// --> ask for password
|
||||
return { accessStatus: "needPassword" };
|
||||
return NEED_PASSWORD;
|
||||
}
|
||||
|
||||
if (!isPublic) {
|
||||
|
@ -275,7 +269,7 @@ exports.checkAccess = async function(padID, sessionCookie, token, password)
|
|||
|
||||
authLogger.debug("Auth failed: invalid session & pad is not public");
|
||||
// --> deny access
|
||||
return { accessStatus: "deny" };
|
||||
return DENY;
|
||||
}
|
||||
|
||||
throw new Error("Oops, something wrong happend");
|
||||
|
@ -283,5 +277,5 @@ exports.checkAccess = async function(padID, sessionCookie, token, password)
|
|||
|
||||
// there is no valid session avaiable AND pad doesn't exist
|
||||
authLogger.debug("Auth failed: invalid session & pad does not exist");
|
||||
return { accessStatus: "deny" };
|
||||
return DENY;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ var fs = require("fs");
|
|||
var path = require("path");
|
||||
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks.js");
|
||||
var resolve = require("resolve");
|
||||
var settings = require('../utils/Settings');
|
||||
|
||||
const templateCache = new Map()
|
||||
|
||||
exports.info = {
|
||||
__output_stack: [],
|
||||
|
@ -114,12 +117,26 @@ exports.require = function (name, args, mod) {
|
|||
|
||||
args.e = exports;
|
||||
args.require = require;
|
||||
var template = '<% e._init(__output); %>' + fs.readFileSync(ejspath).toString() + '<% e._exit(); %>';
|
||||
|
||||
|
||||
let template
|
||||
if (settings.maxAge !== 0){ // don't cache if maxAge is 0
|
||||
if (!templateCache.has(ejspath)) {
|
||||
template = '<% e._init(__output); %>' + fs.readFileSync(ejspath).toString() + '<% e._exit(); %>';
|
||||
templateCache.set(ejspath, template)
|
||||
} else {
|
||||
template = templateCache.get(ejspath)
|
||||
}
|
||||
}else{
|
||||
template = '<% e._init(__output); %>' + fs.readFileSync(ejspath).toString() + '<% e._exit(); %>';
|
||||
}
|
||||
|
||||
exports.info.args.push(args);
|
||||
exports.info.file_stack.push({path: ejspath, inherit: []});
|
||||
|
||||
var res = ejs.render(template, args);
|
||||
if(settings.maxAge !== 0){
|
||||
var res = ejs.render(template, args, { cache: true, filename: ejspath });
|
||||
}else{
|
||||
var res = ejs.render(template, args, { cache: false, filename: ejspath });
|
||||
}
|
||||
exports.info.file_stack.pop();
|
||||
exports.info.args.pop();
|
||||
|
||||
|
|
|
@ -73,6 +73,18 @@ async function doImport(req, res, padId)
|
|||
form.keepExtensions = true;
|
||||
form.uploadDir = tmpDirectory;
|
||||
form.maxFileSize = settings.importMaxFileSize;
|
||||
|
||||
// Ref: https://github.com/node-formidable/formidable/issues/469
|
||||
// Crash in Etherpad was Uploading Error: Error: Request aborted
|
||||
// [ERR_STREAM_DESTROYED]: Cannot call write after a stream was destroyed
|
||||
form.onPart = part => {
|
||||
form.handlePart(part);
|
||||
if (part.filename !== undefined) {
|
||||
form.openedFiles[form.openedFiles.length - 1]._writeStream.on('error', err => {
|
||||
form.emit('error', err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// locally wrapped Promise, since form.parse requires a callback
|
||||
let srcFile = await new Promise((resolve, reject) => {
|
||||
|
@ -84,7 +96,7 @@ async function doImport(req, res, padId)
|
|||
}
|
||||
|
||||
// I hate doing indexOf here but I can't see anything to use...
|
||||
if (err.stack.indexOf("maxFileSize") !== -1) {
|
||||
if (err && err.stack && err.stack.indexOf("maxFileSize") !== -1) {
|
||||
reject("maxFileSize");
|
||||
}
|
||||
|
||||
|
@ -274,15 +286,6 @@ exports.doImport = function (req, res, padId)
|
|||
}
|
||||
}).then(() => {
|
||||
// close the connection
|
||||
res.send(
|
||||
"<head> \
|
||||
<script type='text/javascript' src='../../static/js/jquery.js'></script> \
|
||||
</head> \
|
||||
<script> \
|
||||
$(window).load(function(){ \
|
||||
var impexp = window.parent.padimpexp.handleFrameCall('" + req.directDatabaseAccess +"', '" + status + "'); \
|
||||
}) \
|
||||
</script>"
|
||||
);
|
||||
res.send("<script>document.addEventListener('DOMContentLoaded', function(){ var impexp = window.parent.padimpexp.handleFrameCall('" + req.directDatabaseAccess +"', '" + status + "'); })</script>");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ var authorManager = require("../db/AuthorManager");
|
|||
var readOnlyManager = require("../db/ReadOnlyManager");
|
||||
var settings = require('../utils/Settings');
|
||||
var securityManager = require("../db/SecurityManager");
|
||||
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins.js");
|
||||
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugin_defs.js");
|
||||
var log4js = require('log4js');
|
||||
var messageLogger = log4js.getLogger("message");
|
||||
var accessLogger = log4js.getLogger("access");
|
||||
|
@ -36,7 +36,14 @@ var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks.js");
|
|||
var channels = require("channels");
|
||||
var stats = require('../stats');
|
||||
var remoteAddress = require("../utils/RemoteAddress").remoteAddress;
|
||||
const assert = require('assert').strict;
|
||||
const nodeify = require("nodeify");
|
||||
const { RateLimiterMemory } = require('rate-limiter-flexible');
|
||||
|
||||
const rateLimiter = new RateLimiterMemory({
|
||||
points: settings.commitRateLimiting.points,
|
||||
duration: settings.commitRateLimiting.duration
|
||||
});
|
||||
|
||||
/**
|
||||
* A associative array that saves informations about a session
|
||||
|
@ -164,6 +171,19 @@ exports.handleDisconnect = async function(client)
|
|||
*/
|
||||
exports.handleMessage = async function(client, message)
|
||||
{
|
||||
var env = process.env.NODE_ENV || 'development';
|
||||
|
||||
if (env === 'production') {
|
||||
try {
|
||||
await rateLimiter.consume(client.handshake.address); // consume 1 point per event from IP
|
||||
}catch(e){
|
||||
console.warn("Rate limited: ", client.handshake.address, " to reduce the amount of rate limiting that happens edit the rateLimit values in settings.json");
|
||||
stats.meter('rateLimited').mark();
|
||||
client.json.send({disconnect:"rateLimited"});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (message == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -239,35 +259,13 @@ exports.handleMessage = async function(client, message)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* In a previous version of this code, an "if (message)" wrapped the
|
||||
* following series of async calls [now replaced with await calls]
|
||||
* This ugly "!Boolean(message)" is a lame way to exactly negate the truthy
|
||||
* condition and replace it with an early return, while being sure to leave
|
||||
* the original behaviour unchanged.
|
||||
*
|
||||
* A shallower code could maybe make more evident latent logic errors.
|
||||
*/
|
||||
if (!Boolean(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let dropMessage = await handleMessageHook();
|
||||
if (!dropMessage) {
|
||||
|
||||
// check permissions
|
||||
|
||||
if (message.type == "CLIENT_READY") {
|
||||
// client tried to auth for the first time (first msg from the client)
|
||||
createSessionInfo(client, message);
|
||||
}
|
||||
|
||||
// Note: message.sessionID is an entirely different kind of
|
||||
// session from the sessions we use here! Beware!
|
||||
// FIXME: Call our "sessions" "connections".
|
||||
// FIXME: Use a hook instead
|
||||
// FIXME: Allow to override readwrite access with readonly
|
||||
|
||||
// the session may have been dropped during earlier processing
|
||||
if (!sessioninfos[client.id]) {
|
||||
messageLogger.warn("Dropping message from a connection that has gone away.")
|
||||
|
@ -895,12 +893,6 @@ async function handleClientReady(client, message)
|
|||
// Get ro/rw id:s
|
||||
let padIds = await readOnlyManager.getIds(message.padId);
|
||||
|
||||
// check permissions
|
||||
|
||||
// Note: message.sessionID is an entierly different kind of
|
||||
// session from the sessions we use here! Beware!
|
||||
// FIXME: Call our "sessions" "connections".
|
||||
// FIXME: Use a hook instead
|
||||
// FIXME: Allow to override readwrite access with readonly
|
||||
let statusObject = await securityManager.checkAccess(padIds.padId, message.sessionID, message.token, message.password);
|
||||
let accessStatus = statusObject.accessStatus;
|
||||
|
@ -914,6 +906,7 @@ async function handleClientReady(client, message)
|
|||
let author = statusObject.authorID;
|
||||
|
||||
// get all authordata of this new user
|
||||
assert(author);
|
||||
let value = await authorManager.getAuthor(author);
|
||||
let authorColorId = value.colorId;
|
||||
let authorName = value.name;
|
||||
|
@ -1131,6 +1124,7 @@ async function handleClientReady(client, message)
|
|||
},
|
||||
"initialChangesets": [], // FIXME: REMOVE THIS SHIT
|
||||
"thisUserHasEditedThisPad": thisUserHasEditedThisPad,
|
||||
"allowAnyoneToImport": settings.allowAnyoneToImport
|
||||
}
|
||||
|
||||
// Add a username to the clientVars if one avaiable
|
||||
|
@ -1139,7 +1133,7 @@ async function handleClientReady(client, message)
|
|||
}
|
||||
|
||||
// call the clientVars-hook so plugins can modify them before they get sent to the client
|
||||
let messages = await hooks.aCallAll("clientVars", { clientVars: clientVars, pad: pad });
|
||||
let messages = await hooks.aCallAll('clientVars', {clientVars, pad, socket: client});
|
||||
|
||||
// combine our old object with the new attributes from the hook
|
||||
for (let msg of messages) {
|
||||
|
@ -1294,7 +1288,7 @@ async function handleChangesetRequest(client, message)
|
|||
data.requestID = message.data.requestID;
|
||||
client.json.send({ type: "CHANGESET_REQ", data });
|
||||
} catch (err) {
|
||||
console.error('Error while handling a changeset request for ' + padIds.padId, err, message.data);
|
||||
console.error('Error while handling a changeset request for ' + padIds.padId, err.toString(), message.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1495,8 +1489,12 @@ exports.padUsers = async function(padID) {
|
|||
let s = sessioninfos[roomClient.id];
|
||||
if (s) {
|
||||
return authorManager.getAuthor(s.author).then(author => {
|
||||
author.id = s.author;
|
||||
padUsers.push(author);
|
||||
// Fixes: https://github.com/ether/etherpad-lite/issues/4120
|
||||
// On restart author might not be populated?
|
||||
if(author){
|
||||
author.id = s.author;
|
||||
padUsers.push(author);
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
var eejs = require('ep_etherpad-lite/node/eejs');
|
||||
var settings = require('ep_etherpad-lite/node/utils/Settings');
|
||||
var installer = require('ep_etherpad-lite/static/js/pluginfw/installer');
|
||||
var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins');
|
||||
var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs');
|
||||
var _ = require('underscore');
|
||||
var semver = require('semver');
|
||||
const UpdateCheck = require('ep_etherpad-lite/node/utils/UpdateCheck');
|
||||
|
||||
exports.expressCreateServer = function(hook_name, args, cb) {
|
||||
args.app.get('/admin/plugins', function(req, res) {
|
||||
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
|
||||
var render_args = {
|
||||
plugins: plugins.plugins,
|
||||
search_results: {},
|
||||
|
@ -23,7 +23,8 @@ exports.expressCreateServer = function(hook_name, args, cb) {
|
|||
|
||||
res.send(eejs.require("ep_etherpad-lite/templates/admin/plugins-info.html", {
|
||||
gitCommit: gitCommit,
|
||||
epVersion: epVersion
|
||||
epVersion: epVersion,
|
||||
latestVersion: UpdateCheck.getLatestVersion()
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ exports.socketio = function (hook_name, args, cb) {
|
|||
return console.log(err);
|
||||
}
|
||||
|
||||
//if showSettingsInAdminPage is set to false, then return NOT_ALLOWED in the result
|
||||
// if showSettingsInAdminPage is set to false, then return NOT_ALLOWED in the result
|
||||
if(settings.showSettingsInAdminPage === false) {
|
||||
socket.emit("settings", {results:'NOT_ALLOWED'});
|
||||
socket.emit("settings", {results: 'NOT_ALLOWED'});
|
||||
}
|
||||
else {
|
||||
socket.emit("settings", {results: data});
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
const assert = require('assert').strict;
|
||||
var hasPadAccess = require("../../padaccess");
|
||||
var settings = require('../../utils/Settings');
|
||||
var exportHandler = require('../../handler/ExportHandler');
|
||||
|
@ -5,6 +6,7 @@ var importHandler = require('../../handler/ImportHandler');
|
|||
var padManager = require("../../db/PadManager");
|
||||
var authorManager = require("../../db/AuthorManager");
|
||||
const rateLimit = require("express-rate-limit");
|
||||
const securityManager = require("../../db/SecurityManager");
|
||||
|
||||
settings.importExportRateLimiting.onLimitReached = function(req, res, options) {
|
||||
// when the rate limiter triggers, write a warning in the logs
|
||||
|
@ -51,57 +53,41 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
// handle import requests
|
||||
args.app.use('/p/:pad/import', limiter);
|
||||
args.app.post('/p/:pad/import', async function(req, res, next) {
|
||||
if (await hasPadAccess(req, res)) {
|
||||
let exists = await padManager.doesPadExists(req.params.pad);
|
||||
if (!exists) {
|
||||
console.warn(`Someone tried to import into a pad that doesn't exist (${req.params.pad})`);
|
||||
return next();
|
||||
}
|
||||
|
||||
/*
|
||||
* Starting from Etherpad 1.8.3 onwards, importing into a pad is allowed
|
||||
* only if a user has his browser opened and connected to the pad (i.e. a
|
||||
* Socket.IO session is estabilished for him) and he has already
|
||||
* contributed to that specific pad.
|
||||
*
|
||||
* Note that this does not have anything to do with the "session", used
|
||||
* for logging into "group pads". That kind of session is not needed here.
|
||||
*
|
||||
* This behaviour does not apply to API requests, only to /p/$PAD$/import
|
||||
*
|
||||
* See: https://github.com/ether/etherpad-lite/pull/3833#discussion_r407490205
|
||||
*/
|
||||
if (!req.cookies) {
|
||||
console.warn(`Unable to import file into "${req.params.pad}". No cookies included in request`);
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!req.cookies.token) {
|
||||
console.warn(`Unable to import file into "${req.params.pad}". No token in the cookies`);
|
||||
return next();
|
||||
}
|
||||
|
||||
let author = await authorManager.getAuthor4Token(req.cookies.token);
|
||||
// author is of the form: "a.g2droBYw1prY7HW9"
|
||||
if (!author) {
|
||||
console.warn(`Unable to import file into "${req.params.pad}". No Author found for token ${req.cookies.token}`);
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
let authorsPads = await authorManager.listPadsOfAuthor(author);
|
||||
if (!authorsPads) {
|
||||
console.warn(`Unable to import file into "${req.params.pad}". Author "${author}" exists but he never contributed to any pad`);
|
||||
return next();
|
||||
}
|
||||
|
||||
let authorsPadIDs = authorsPads.padIDs;
|
||||
if (authorsPadIDs.indexOf(req.params.pad) === -1) {
|
||||
console.warn(`Unable to import file into "${req.params.pad}". Author "${author}" exists but he never contributed to this pad`);
|
||||
return next();
|
||||
}
|
||||
|
||||
importHandler.doImport(req, res, req.params.pad);
|
||||
if (!(await padManager.doesPadExists(req.params.pad))) {
|
||||
console.warn(`Someone tried to import into a pad that doesn't exist (${req.params.pad})`);
|
||||
return next();
|
||||
}
|
||||
|
||||
const {accessStatus, authorID} = await securityManager.checkAccess(
|
||||
req.params.pad, req.cookies.sessionID, req.cookies.token, req.cookies.password);
|
||||
if (accessStatus !== 'grant') return res.status(403).send('Forbidden');
|
||||
assert(authorID);
|
||||
|
||||
/*
|
||||
* Starting from Etherpad 1.8.3 onwards, importing into a pad is allowed
|
||||
* only if a user has his browser opened and connected to the pad (i.e. a
|
||||
* Socket.IO session is estabilished for him) and he has already
|
||||
* contributed to that specific pad.
|
||||
*
|
||||
* Note that this does not have anything to do with the "session", used
|
||||
* for logging into "group pads". That kind of session is not needed here.
|
||||
*
|
||||
* This behaviour does not apply to API requests, only to /p/$PAD$/import
|
||||
*
|
||||
* See: https://github.com/ether/etherpad-lite/pull/3833#discussion_r407490205
|
||||
*/
|
||||
if (!settings.allowAnyoneToImport) {
|
||||
const authorsPads = await authorManager.listPadsOfAuthor(authorID);
|
||||
if (!authorsPads) {
|
||||
console.warn(`Unable to import file into "${req.params.pad}". Author "${authorID}" exists but he never contributed to any pad`);
|
||||
return next();
|
||||
}
|
||||
if (authorsPads.padIDs.indexOf(req.params.pad) === -1) {
|
||||
console.warn(`Unable to import file into "${req.params.pad}". Author "${authorID}" exists but he never contributed to this pad`);
|
||||
return next();
|
||||
}
|
||||
}
|
||||
|
||||
importHandler.doImport(req, res, req.params.pad);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -688,7 +688,7 @@ exports.expressCreateServer = async (_, args) => {
|
|||
// support jsonp response format
|
||||
if (req.query.jsonp && isValidJSONPName.check(req.query.jsonp)) {
|
||||
res.header('Content-Type', 'application/javascript');
|
||||
response = `${req.query.jsonp}(${JSON.stringify(response)}`;
|
||||
response = `${req.query.jsonp}(${JSON.stringify(response)})`;
|
||||
}
|
||||
|
||||
// send response
|
||||
|
|
|
@ -47,25 +47,35 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
io.use(function(socket, accept) {
|
||||
var data = socket.request;
|
||||
// Use a setting if we want to allow load Testing
|
||||
if(!data.headers.cookie && settings.loadTest){
|
||||
|
||||
// Sometimes browsers might not have cookies at all, for example Safari in iFrames Cross domain
|
||||
// https://github.com/ether/etherpad-lite/issues/4031
|
||||
// if requireSession is false we can allow them to still get on the pad.
|
||||
// Note that this does make security less tight because any socketIO connection can be established without
|
||||
// any logic on the client to do any handshaking.. I am not concerned about this though, the real solution
|
||||
// here is to implement rateLimiting on SocketIO ACCEPT_COMMIT messages.
|
||||
|
||||
if(!data.headers.cookie && (settings.loadTest || !settings.requireSession)){
|
||||
accept(null, true);
|
||||
}else{
|
||||
if (!data.headers.cookie) return accept('No session cookie transmitted.', false);
|
||||
}
|
||||
cookieParserFn(data, {}, function(err){
|
||||
if(err) {
|
||||
console.error(err);
|
||||
accept("Couldn't parse request cookies. ", false);
|
||||
return;
|
||||
}
|
||||
if(data.headers.cookie){
|
||||
cookieParserFn(data, {}, function(err){
|
||||
if(err) {
|
||||
console.error(err);
|
||||
accept("Couldn't parse request cookies. ", false);
|
||||
return;
|
||||
}
|
||||
|
||||
data.sessionID = data.signedCookies.express_sid;
|
||||
args.app.sessionStore.get(data.sessionID, function (err, session) {
|
||||
if (err || !session) return accept('Bad session / session has expired', false);
|
||||
data.session = new sessionModule.Session(data, session);
|
||||
accept(null, true);
|
||||
data.sessionID = data.signedCookies.express_sid;
|
||||
args.app.sessionStore.get(data.sessionID, function (err, session) {
|
||||
if (err || !session) return accept('Bad session / session has expired', false);
|
||||
data.session = new sessionModule.Session(data, session);
|
||||
accept(null, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// var socketIOLogger = log4js.getLogger("socket.io");
|
||||
|
|
|
@ -29,7 +29,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
var filePath = path.join(settings.root, "src", "static", "skins", settings.skinName, "robots.txt");
|
||||
res.sendFile(filePath, function(err)
|
||||
{
|
||||
//there is no custom favicon, send the default robots.txt which dissallows all
|
||||
//there is no custom robots.txt, send the default robots.txt which dissallows all
|
||||
if(err)
|
||||
{
|
||||
filePath = path.join(settings.root, "src", "static", "robots.txt");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
var minify = require('../../utils/Minify');
|
||||
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
|
||||
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugin_defs");
|
||||
var CachingMiddleware = require('../../utils/caching_middleware');
|
||||
var settings = require("../../utils/Settings");
|
||||
var Yajsml = require('etherpad-yajsml');
|
||||
|
|
|
@ -17,7 +17,8 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
files = files.filter(el => !/\.swp$/.test(el))
|
||||
|
||||
console.debug("Sent browser the following test specs:", files);
|
||||
res.send("var specs_list = " + JSON.stringify(files) + ";\n");
|
||||
res.setHeader('content-type', 'text/javascript');
|
||||
res.end("var specs_list = " + JSON.stringify(files) + ";\n");
|
||||
});
|
||||
|
||||
// path.join seems to normalize by default, but we'll just be explicit
|
||||
|
|
|
@ -1,116 +1,131 @@
|
|||
var express = require('express');
|
||||
var log4js = require('log4js');
|
||||
var httpLogger = log4js.getLogger("http");
|
||||
var settings = require('../../utils/Settings');
|
||||
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
||||
var ueberStore = require('../../db/SessionStore');
|
||||
var stats = require('ep_etherpad-lite/node/stats');
|
||||
var sessionModule = require('express-session');
|
||||
var cookieParser = require('cookie-parser');
|
||||
const express = require('express');
|
||||
const log4js = require('log4js');
|
||||
const httpLogger = log4js.getLogger('http');
|
||||
const settings = require('../../utils/Settings');
|
||||
const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
||||
const ueberStore = require('../../db/SessionStore');
|
||||
const stats = require('ep_etherpad-lite/node/stats');
|
||||
const sessionModule = require('express-session');
|
||||
const cookieParser = require('cookie-parser');
|
||||
|
||||
//checks for basic http auth
|
||||
exports.basicAuth = function (req, res, next) {
|
||||
var hookResultMangle = function (cb) {
|
||||
return function (err, data) {
|
||||
exports.checkAccess = (req, res, next) => {
|
||||
const hookResultMangle = (cb) => {
|
||||
return (err, data) => {
|
||||
return cb(!err && data.length && data[0]);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var authorize = function (cb) {
|
||||
// This may be called twice per access: once before authentication is checked and once after (if
|
||||
// settings.requireAuthorization is true).
|
||||
const authorize = (cb) => {
|
||||
// Do not require auth for static paths and the API...this could be a bit brittle
|
||||
if (req.path.match(/^\/(static|javascripts|pluginfw|api)/)) return cb(true);
|
||||
|
||||
if (req.path.toLowerCase().indexOf('/admin') != 0) {
|
||||
if (req.path.toLowerCase().indexOf('/admin') !== 0) {
|
||||
if (!settings.requireAuthentication) return cb(true);
|
||||
if (!settings.requireAuthorization && req.session && req.session.user) return cb(true);
|
||||
}
|
||||
|
||||
if (req.session && req.session.user && req.session.user.is_admin) return cb(true);
|
||||
|
||||
hooks.aCallFirst("authorize", {req: req, res:res, next:next, resource: req.path}, hookResultMangle(cb));
|
||||
}
|
||||
|
||||
var authenticate = function (cb) {
|
||||
// If auth headers are present use them to authenticate...
|
||||
if (req.headers.authorization && req.headers.authorization.search('Basic ') === 0) {
|
||||
var userpass = Buffer.from(req.headers.authorization.split(' ')[1], 'base64').toString().split(":")
|
||||
var username = userpass.shift();
|
||||
var password = userpass.join(':');
|
||||
var fallback = function(success) {
|
||||
if (success) return cb(true);
|
||||
if (settings.users[username] != undefined && settings.users[username].password === password) {
|
||||
settings.users[username].username = username;
|
||||
req.session.user = settings.users[username];
|
||||
return cb(true);
|
||||
}
|
||||
return cb(false);
|
||||
};
|
||||
return hooks.aCallFirst("authenticate", {req: req, res:res, next:next, username: username, password: password}, hookResultMangle(fallback));
|
||||
}
|
||||
hooks.aCallFirst("authenticate", {req: req, res:res, next:next}, hookResultMangle(cb));
|
||||
}
|
||||
|
||||
hooks.aCallFirst('authorize', {req, res, next, resource: req.path}, hookResultMangle(cb));
|
||||
};
|
||||
|
||||
/* Authentication OR authorization failed. */
|
||||
var failure = function () {
|
||||
return hooks.aCallFirst("authFailure", {req: req, res:res, next:next}, hookResultMangle(function (ok) {
|
||||
if (ok) return;
|
||||
/* No plugin handler for invalid auth. Return Auth required
|
||||
* Headers, delayed for 1 second, if authentication failed
|
||||
* before. */
|
||||
const failure = () => {
|
||||
return hooks.aCallFirst('authFailure', {req, res, next}, hookResultMangle((ok) => {
|
||||
if (ok) return;
|
||||
// No plugin handled the authn/authz failure. Fall back to basic authentication.
|
||||
res.header('WWW-Authenticate', 'Basic realm="Protected Area"');
|
||||
if (req.headers.authorization) {
|
||||
setTimeout(function () {
|
||||
res.status(401).send('Authentication required');
|
||||
}, 1000);
|
||||
} else {
|
||||
res.status(401).send('Authentication required');
|
||||
}
|
||||
// Delay the error response for 1s to slow down brute force attacks.
|
||||
setTimeout(() => {
|
||||
res.status(401).send('Authentication Required');
|
||||
}, 1000);
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// Access checking is done in three steps:
|
||||
//
|
||||
// 1) Try to just access the thing. If access fails (perhaps authentication has not yet completed,
|
||||
// or maybe different credentials are required), go to the next step.
|
||||
// 2) Try to authenticate. (Or, if already logged in, reauthenticate with different credentials if
|
||||
// supported by the authn scheme.) If authentication fails, give the user a 401 error to
|
||||
// request new credentials. Otherwise, go to the next step.
|
||||
// 3) Try to access the thing again. If this fails, give the user a 401 error.
|
||||
//
|
||||
// Plugins can use the 'next' callback (from the hook's context) to break out at any point (e.g.,
|
||||
// to process an OAuth callback). Plugins can use the authFailure hook to override the default
|
||||
// error handling behavior (e.g., to redirect to a login page).
|
||||
|
||||
/* This is the actual authentication/authorization hoop. It is done in four steps:
|
||||
let step1PreAuthenticate, step2Authenticate, step3Authorize;
|
||||
|
||||
1) Try to just access the thing
|
||||
2) If not allowed using whatever creds are in the current session already, try to authenticate
|
||||
3) If authentication using already supplied credentials succeeds, try to access the thing again
|
||||
4) If all els fails, give the user a 401 to request new credentials
|
||||
|
||||
Note that the process could stop already in step 3 with a redirect to login page.
|
||||
|
||||
*/
|
||||
|
||||
authorize(function (ok) {
|
||||
if (ok) return next();
|
||||
authenticate(function (ok) {
|
||||
if (!ok) return failure();
|
||||
authorize(function (ok) {
|
||||
if (ok) return next();
|
||||
failure();
|
||||
});
|
||||
step1PreAuthenticate = () => {
|
||||
authorize((ok) => {
|
||||
if (ok) return next();
|
||||
step2Authenticate();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
step2Authenticate = () => {
|
||||
const ctx = {req, res, next};
|
||||
// If the HTTP basic auth header is present, extract the username and password so it can be
|
||||
// given to authn plugins.
|
||||
const httpBasicAuth =
|
||||
req.headers.authorization && req.headers.authorization.search('Basic ') === 0;
|
||||
if (httpBasicAuth) {
|
||||
const userpass =
|
||||
Buffer.from(req.headers.authorization.split(' ')[1], 'base64').toString().split(':');
|
||||
ctx.username = userpass.shift();
|
||||
ctx.password = userpass.join(':');
|
||||
}
|
||||
hooks.aCallFirst('authenticate', ctx, hookResultMangle((ok) => {
|
||||
if (!ok) {
|
||||
// Fall back to HTTP basic auth.
|
||||
if (!httpBasicAuth) return failure();
|
||||
if (!(ctx.username in settings.users)) {
|
||||
httpLogger.info(`Failed authentication from IP ${req.ip} - no such user`);
|
||||
return failure();
|
||||
}
|
||||
if (settings.users[ctx.username].password !== ctx.password) {
|
||||
httpLogger.info(`Failed authentication from IP ${req.ip} for user ${ctx.username} - incorrect password`);
|
||||
return failure();
|
||||
}
|
||||
httpLogger.info(`Successful authentication from IP ${req.ip} for user ${ctx.username}`);
|
||||
settings.users[ctx.username].username = ctx.username;
|
||||
req.session.user = settings.users[ctx.username];
|
||||
}
|
||||
step3Authorize();
|
||||
}));
|
||||
};
|
||||
|
||||
step3Authorize = () => {
|
||||
authorize((ok) => {
|
||||
if (ok) return next();
|
||||
failure();
|
||||
});
|
||||
};
|
||||
|
||||
step1PreAuthenticate();
|
||||
};
|
||||
|
||||
exports.secret = null;
|
||||
|
||||
exports.expressConfigure = function (hook_name, args, cb) {
|
||||
exports.expressConfigure = (hook_name, args, cb) => {
|
||||
// Measure response time
|
||||
args.app.use(function(req, res, next) {
|
||||
var stopWatch = stats.timer('httpRequests').start();
|
||||
var sendFn = res.send
|
||||
res.send = function() {
|
||||
stopWatch.end()
|
||||
sendFn.apply(res, arguments)
|
||||
}
|
||||
next()
|
||||
})
|
||||
args.app.use((req, res, next) => {
|
||||
const stopWatch = stats.timer('httpRequests').start();
|
||||
const sendFn = res.send;
|
||||
res.send = function() { // function, not arrow, due to use of 'arguments'
|
||||
stopWatch.end();
|
||||
sendFn.apply(res, arguments);
|
||||
};
|
||||
next();
|
||||
});
|
||||
|
||||
// If the log level specified in the config file is WARN or ERROR the application server never starts listening to requests as reported in issue #158.
|
||||
// Not installing the log4js connect logger when the log level has a higher severity than INFO since it would not log at that level anyway.
|
||||
if (!(settings.loglevel === "WARN" || settings.loglevel == "ERROR"))
|
||||
args.app.use(log4js.connectLogger(httpLogger, { level: log4js.levels.DEBUG, format: ':status, :method :url'}));
|
||||
if (!(settings.loglevel === 'WARN' || settings.loglevel === 'ERROR'))
|
||||
args.app.use(log4js.connectLogger(httpLogger, {level: log4js.levels.DEBUG, format: ':status, :method :url'}));
|
||||
|
||||
/* Do not let express create the session, so that we can retain a
|
||||
* reference to it for socket.io to use. Also, set the key (cookie
|
||||
|
@ -122,6 +137,8 @@ exports.expressConfigure = function (hook_name, args, cb) {
|
|||
exports.secret = settings.sessionKey;
|
||||
}
|
||||
|
||||
const sameSite = settings.ssl ? 'Strict' : 'Lax';
|
||||
|
||||
args.app.sessionStore = exports.sessionStore;
|
||||
args.app.use(sessionModule({
|
||||
secret: exports.secret,
|
||||
|
@ -131,6 +148,12 @@ exports.expressConfigure = function (hook_name, args, cb) {
|
|||
name: 'express_sid',
|
||||
proxy: true,
|
||||
cookie: {
|
||||
/*
|
||||
* Firefox started enforcing sameSite, see https://github.com/ether/etherpad-lite/issues/3989
|
||||
* for details. In response we set it based on if SSL certs are set in Etherpad. Note that if
|
||||
* You use Nginx or so for reverse proxy this may cause problems. Use Certificate pinning to remedy.
|
||||
*/
|
||||
sameSite: sameSite,
|
||||
/*
|
||||
* The automatic express-session mechanism for determining if the
|
||||
* application is being served over ssl is similar to the one used for
|
||||
|
@ -157,5 +180,5 @@ exports.expressConfigure = function (hook_name, args, cb) {
|
|||
|
||||
args.app.use(cookieParser(settings.sessionKey, {}));
|
||||
|
||||
args.app.use(exports.basicAuth);
|
||||
}
|
||||
args.app.use(exports.checkAccess);
|
||||
};
|
||||
|
|
|
@ -3,9 +3,10 @@ var languages = require('languages4translatewiki')
|
|||
, path = require('path')
|
||||
, _ = require('underscore')
|
||||
, npm = require('npm')
|
||||
, plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins.js').plugins
|
||||
, plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs.js').plugins
|
||||
, semver = require('semver')
|
||||
, existsSync = require('../utils/path_exists')
|
||||
, settings = require('../utils/Settings')
|
||||
;
|
||||
|
||||
|
||||
|
@ -43,7 +44,7 @@ function getAllLocales() {
|
|||
//add plugins languages (if any)
|
||||
for(var pluginName in plugins) extractLangs(path.join(npm.root, pluginName, 'locales'));
|
||||
|
||||
// Build a locale index (merge all locale data)
|
||||
// Build a locale index (merge all locale data other than user-supplied overrides)
|
||||
var locales = {}
|
||||
_.each (locales2paths, function(files, langcode) {
|
||||
locales[langcode]={};
|
||||
|
@ -54,6 +55,22 @@ function getAllLocales() {
|
|||
});
|
||||
});
|
||||
|
||||
// Add custom strings from settings.json
|
||||
// Since this is user-supplied, we'll do some extra sanity checks
|
||||
const wrongFormatErr = Error(
|
||||
"customLocaleStrings in wrong format. See documentation " +
|
||||
"for Customization for Administrators, under Localization.")
|
||||
if (settings.customLocaleStrings) {
|
||||
if (typeof settings.customLocaleStrings !== "object") throw wrongFormatErr
|
||||
_.each(settings.customLocaleStrings, function(overrides, langcode) {
|
||||
if (typeof overrides !== "object") throw wrongFormatErr
|
||||
_.each(overrides, function(localeString, key) {
|
||||
if (typeof localeString !== "string") throw wrongFormatErr
|
||||
locales[langcode][key] = localeString
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return locales;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var log4js = require('log4js')
|
||||
const log4js = require('log4js')
|
||||
, NodeVersion = require('./utils/NodeVersion')
|
||||
, UpdateCheck = require('./utils/UpdateCheck')
|
||||
;
|
||||
|
||||
log4js.replaceConsole();
|
||||
|
@ -38,6 +39,9 @@ NodeVersion.enforceMinNodeVersion('10.13.0');
|
|||
*/
|
||||
NodeVersion.checkDeprecationStatus('10.13.0', '1.8.3');
|
||||
|
||||
// Check if Etherpad version is up-to-date
|
||||
UpdateCheck.check();
|
||||
|
||||
/*
|
||||
* start up stats counting system
|
||||
*/
|
||||
|
@ -57,7 +61,6 @@ npm.load({}, function() {
|
|||
var db = require('./db/DB');
|
||||
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
|
||||
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
|
||||
hooks.plugins = plugins;
|
||||
|
||||
db.init()
|
||||
.then(plugins.update)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue