Compare commits

..

No commits in common. "develop" and "v2.1.0" have entirely different histories.

272 changed files with 41287 additions and 25722 deletions

View file

@ -25,5 +25,3 @@ Dockerfile
settings.json settings.json
src/node_modules src/node_modules
admin/node_modules admin/node_modules
ui/node_modules
node_modules

View file

@ -24,7 +24,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
node: [20, 22, 23] node: [18, 20, 21]
steps: steps:
- -
name: Checkout repository name: Checkout repository
@ -53,7 +53,7 @@ jobs:
run: pnpm config set auto-install-peers false run: pnpm config set auto-install-peers false
- -
name: Install libreoffice name: Install libreoffice
uses: awalsh128/cache-apt-pkgs-action@v1.5.0 uses: awalsh128/cache-apt-pkgs-action@v1.4.2
with: with:
packages: libreoffice libreoffice-pdfimport packages: libreoffice libreoffice-pdfimport
version: 1.0 version: 1.0
@ -69,9 +69,6 @@ jobs:
- -
name: Run the backend tests name: Run the backend tests
run: pnpm test run: pnpm test
- name: Run the new vitest tests
working-directory: src
run: pnpm run test:vitest
withpluginsLinux: withpluginsLinux:
# run on pushes to any branch # run on pushes to any branch
@ -84,7 +81,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
node: [20, 22, 23] node: [18, 20, 21]
steps: steps:
- -
name: Checkout repository name: Checkout repository
@ -113,7 +110,7 @@ jobs:
run: pnpm config set auto-install-peers false run: pnpm config set auto-install-peers false
- -
name: Install libreoffice name: Install libreoffice
uses: awalsh128/cache-apt-pkgs-action@v1.5.0 uses: awalsh128/cache-apt-pkgs-action@v1.4.2
with: with:
packages: libreoffice libreoffice-pdfimport packages: libreoffice libreoffice-pdfimport
version: 1.0 version: 1.0
@ -145,9 +142,6 @@ jobs:
- -
name: Run the backend tests name: Run the backend tests
run: pnpm test run: pnpm test
- name: Run the new vitest tests
working-directory: src
run: pnpm run test:vitest
withoutpluginsWindows: withoutpluginsWindows:
# run on pushes to any branch # run on pushes to any branch
@ -199,11 +193,7 @@ jobs:
powershell -Command "(gc settings.json.holder) -replace '\"points\": 10', '\"points\": 1000' | Out-File -encoding ASCII settings.json" powershell -Command "(gc settings.json.holder) -replace '\"points\": 10', '\"points\": 1000' | Out-File -encoding ASCII settings.json"
- -
name: Run the backend tests name: Run the backend tests
working-directory: src run: cd src && pnpm test
run: pnpm test
- name: Run the new vitest tests
working-directory: src
run: pnpm run test:vitest
withpluginsWindows: withpluginsWindows:
# run on pushes to any branch # run on pushes to any branch
@ -221,7 +211,7 @@ jobs:
- -
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 21
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
name: Install pnpm name: Install pnpm
with: with:
@ -283,8 +273,4 @@ jobs:
powershell -Command "(gc settings.json.holder) -replace '\"points\": 10', '\"points\": 1000' | Out-File -encoding ASCII settings.json" powershell -Command "(gc settings.json.holder) -replace '\"points\": 10', '\"points\": 1000' | Out-File -encoding ASCII settings.json"
- -
name: Run the backend tests name: Run the backend tests
working-directory: src run: cd src && pnpm test
run: pnpm test
- name: Run the new vitest tests
working-directory: src
run: pnpm run test:vitest

View file

@ -22,9 +22,6 @@ jobs:
- -
name: Check out name: Check out
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
path: etherpad
- -
name: Set up QEMU name: Set up QEMU
if: github.event_name == 'push' if: github.event_name == 'push'
@ -34,9 +31,9 @@ jobs:
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- -
name: Build and export to Docker name: Build and export to Docker
uses: docker/build-push-action@v6 uses: docker/build-push-action@v5
with: with:
context: ./etherpad context: .
target: production target: production
load: true load: true
tags: ${{ env.TEST_TAG }} tags: ${{ env.TEST_TAG }}
@ -65,7 +62,6 @@ jobs:
${{ runner.os }}-pnpm-store- ${{ runner.os }}-pnpm-store-
- -
name: Test name: Test
working-directory: etherpad
run: | run: |
docker run --rm -d -p 9001:9001 --name test ${{ env.TEST_TAG }} docker run --rm -d -p 9001:9001 --name test ${{ env.TEST_TAG }}
./bin/installDeps.sh ./bin/installDeps.sh
@ -102,11 +98,10 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- -
name: Build and push name: Build and push
id: build-docker
if: github.event_name == 'push' if: github.event_name == 'push'
uses: docker/build-push-action@v6 uses: docker/build-push-action@v5
with: with:
context: ./etherpad context: .
target: production target: production
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
push: true push: true
@ -116,29 +111,7 @@ jobs:
uses: peter-evans/dockerhub-description@v4 uses: peter-evans/dockerhub-description@v4
if: github.ref == 'refs/heads/master' if: github.ref == 'refs/heads/master'
with: with:
readme-filepath: ./etherpad/README.md
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: etherpad/etherpad repository: etherpad/etherpad
enable-url-completion: true enable-url-completion: true
- name: Check out
if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
uses: actions/checkout@v4
with:
path: ether-charts
repository: ether/ether-charts
token: ${{ secrets.ETHER_CHART_TOKEN }}
- name: Update tag in values-dev.yaml
if: success() && github.ref == 'refs/heads/develop'
working-directory: ether-charts
run: |
sed -i 's/tag: ".*"/tag: "${{ steps.build-docker.outputs.digest }}"/' values-dev.yaml
- name: Commit and push changes
working-directory: ether-charts
if: success() && github.ref == 'refs/heads/develop'
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git add values-dev.yaml
git commit -m 'Update develop image tag'
git push

View file

@ -11,13 +11,14 @@ permissions:
jobs: jobs:
withplugins: withplugins:
if: ${{ github.actor != 'dependabot[bot]' }}
name: with plugins name: with plugins
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
node: [20, 22, 23] node: [20, 21]
steps: steps:
- -
@ -49,13 +50,6 @@ jobs:
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: | restore-keys: |
${{ runner.os }}-pnpm-store- ${{ runner.os }}-pnpm-store-
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Only install direct dependencies - name: Only install direct dependencies
run: pnpm config set auto-install-peers false run: pnpm config set auto-install-peers false
#- #-
@ -75,7 +69,7 @@ jobs:
# rules. # rules.
- -
name: Install all dependencies and symlink for ep_etherpad-lite name: Install all dependencies and symlink for ep_etherpad-lite
run: pnpm i run: bin/installDeps.sh
#- #-
# name: Install etherpad plugins # name: Install etherpad plugins
# run: rm -Rf node_modules/ep_align/static/tests/* # run: rm -Rf node_modules/ep_align/static/tests/*
@ -99,6 +93,7 @@ jobs:
- name: Build admin frontend - name: Build admin frontend
working-directory: admin working-directory: admin
run: | run: |
pnpm install
pnpm run build pnpm run build
# name: Run the frontend admin tests # name: Run the frontend admin tests
# shell: bash # shell: bash
@ -130,7 +125,7 @@ jobs:
- name: Run the frontend admin tests - name: Run the frontend admin tests
shell: bash shell: bash
run: | run: |
pnpm run prod & pnpm run dev &
connected=false connected=false
can_connect() { can_connect() {
curl -sSfo /dev/null http://localhost:9001/ || return 1 curl -sSfo /dev/null http://localhost:9001/ || return 1

View file

@ -26,7 +26,7 @@ jobs:
- -
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 21
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
name: Install pnpm name: Install pnpm
with: with:
@ -56,17 +56,10 @@ jobs:
- -
name: Create settings.json name: Create settings.json
run: cp ./src/tests/settings.json settings.json run: cp ./src/tests/settings.json settings.json
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Run the frontend tests - name: Run the frontend tests
shell: bash shell: bash
run: | run: |
pnpm run prod & pnpm run dev &
connected=false connected=false
can_connect() { can_connect() {
curl -sSfo /dev/null http://localhost:9001/ || return 1 curl -sSfo /dev/null http://localhost:9001/ || return 1
@ -99,7 +92,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 21
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
name: Install pnpm name: Install pnpm
with: with:
@ -126,17 +119,10 @@ jobs:
run: echo "::set-output name=sha_short::$(git rev-parse --short ${{ github.sha }})" run: echo "::set-output name=sha_short::$(git rev-parse --short ${{ github.sha }})"
- name: Create settings.json - name: Create settings.json
run: cp ./src/tests/settings.json settings.json run: cp ./src/tests/settings.json settings.json
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Run the frontend tests - name: Run the frontend tests
shell: bash shell: bash
run: | run: |
pnpm run prod & pnpm run dev &
connected=false connected=false
can_connect() { can_connect() {
curl -sSfo /dev/null http://localhost:9001/ || return 1 curl -sSfo /dev/null http://localhost:9001/ || return 1
@ -173,14 +159,7 @@ jobs:
- -
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 21
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
name: Install pnpm name: Install pnpm
with: with:
@ -213,7 +192,7 @@ jobs:
- name: Run the frontend tests - name: Run the frontend tests
shell: bash shell: bash
run: | run: |
pnpm run prod & pnpm run dev &
connected=false connected=false
can_connect() { can_connect() {
curl -sSfo /dev/null http://localhost:9001/ || return 1 curl -sSfo /dev/null http://localhost:9001/ || return 1

View file

@ -48,7 +48,7 @@ jobs:
- -
name: docker network name: docker network
run: docker network create --subnet=172.23.0.0/16 ep_net run: docker network create --subnet=172.23.42.0/16 ep_net
- -
name: build docker image name: build docker image
run: | run: |

View file

@ -24,13 +24,13 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
node: [20, 22, 23] node: [18, 20, 21]
steps: steps:
- -
name: Check out latest release name: Check out latest release
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
ref: develop #FIXME change to master when doing release ref: master
- -
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
@ -43,7 +43,7 @@ jobs:
- name: Only install direct dependencies - name: Only install direct dependencies
run: pnpm config set auto-install-peers false run: pnpm config set auto-install-peers false
- name: Install libreoffice - name: Install libreoffice
uses: awalsh128/cache-apt-pkgs-action@v1.5.0 uses: awalsh128/cache-apt-pkgs-action@v1.4.2
with: with:
packages: libreoffice libreoffice-pdfimport packages: libreoffice libreoffice-pdfimport
version: 1.0 version: 1.0
@ -62,7 +62,7 @@ jobs:
run: pnpm config set auto-install-peers false run: pnpm config set auto-install-peers false
- -
name: Install libreoffice name: Install libreoffice
uses: awalsh128/cache-apt-pkgs-action@v1.5.0 uses: awalsh128/cache-apt-pkgs-action@v1.4.2
with: with:
packages: libreoffice libreoffice-pdfimport packages: libreoffice libreoffice-pdfimport
version: 1.0 version: 1.0

View file

@ -14,7 +14,6 @@ permissions:
jobs: jobs:
build-zip: build-zip:
permissions: write-all
# run on pushes to any branch # run on pushes to any branch
# run on PRs from external forks # run on PRs from external forks
if: | if: |
@ -35,7 +34,7 @@ jobs:
- -
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 21
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
name: Install pnpm name: Install pnpm
with: with:
@ -61,26 +60,112 @@ jobs:
- -
name: Run the backend tests name: Run the backend tests
shell: msys2 {0} shell: msys2 {0}
working-directory: src run: cd src && pnpm test
run: pnpm test -
name: Build the .zip
shell: msys2 {0}
run: bin/buildForWindows.sh
-
name: Archive production artifacts
uses: actions/upload-artifact@v4
with:
name: etherpad-win.zip
path: etherpad-win.zip
build-exe:
if: |
(github.event_name != 'pull_request')
|| (github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id)
name: Build .exe
needs: build-zip
runs-on: windows-latest
steps:
-
name: Checkout repository
uses: actions/checkout@v4
-
name: Download .zip
uses: actions/download-artifact@v4
with:
name: etherpad-win.zip
path: ..
-
name: Extract .zip
working-directory: ..
run: 7z x etherpad-win.zip -oetherpad-zip
-
name: Create installer
uses: joncloud/makensis-action@v4.1
with:
script-file: 'bin/nsis/etherpad.nsi'
-
name: Archive production artifacts
uses: actions/upload-artifact@v4
with:
name: etherpad-win.exe
path: etherpad-win.exe
deploy-zip:
# run on pushes to any branch
# run on PRs from external forks
permissions:
contents: write
if: |
(github.event_name != 'pull_request')
|| (github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id)
name: Deploy
needs: build-zip
runs-on: windows-latest
steps:
-
name: Download zip
uses: actions/download-artifact@v4
with:
name: etherpad-win.zip
-
name: Extract Etherpad
run: 7z x etherpad-win.zip -oetherpad
-
uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 9.0.4
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
- name: Install all dependencies and symlink for ep_etherpad-lite
run: .\bin\installOnWindows.bat
working-directory: etherpad
- -
name: Run Etherpad name: Run Etherpad
working-directory: src working-directory: etherpad/src
run: | run: |
pnpm i pnpm install cypress
pnpm exec playwright install --with-deps .\node_modules\.bin\cypress.cmd install --force
pnpm run prod & pnpm run prod &
curl --connect-timeout 10 --max-time 20 --retry 5 --retry-delay 10 --retry-max-time 60 --retry-connrefused http://127.0.0.1:9001/p/test curl --connect-timeout 10 --max-time 20 --retry 5 --retry-delay 10 --retry-max-time 60 --retry-connrefused http://127.0.0.1:9001/p/test
pnpm exec playwright install chromium --with-deps pnpm exec cypress run --config-file ./tests/frontend/cypress/cypress.config.js
pnpm run test-ui --project=chromium # On release, upload windows zip to GitHub release tab
# On release, create release -
- name: Generate Changelog name: Rename to etherpad-lite-win.zip
if: ${{startsWith(github.ref, 'refs/tags/v') }} shell: powershell
working-directory: bin run: mv etherpad-win.zip etherpad-lite-win.zip
run: pnpm run generateChangelog ${{ github.ref }} > ${{ github.workspace }}-CHANGELOG.txt - name: upload binaries to release
- name: Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
if: ${{startsWith(github.ref, 'refs/tags/v') }} if: ${{startsWith(github.ref, 'refs/tags/v') }}
with: with:
body_path: ${{ github.workspace }}-CHANGELOG.txt files: etherpad-lite-win.zip
make_latest: true

View file

@ -1,85 +1,3 @@
# 2.3.0
### Notable enhancements and fixes
- Added possibility to cluster Etherpads behind reverse proxy. There is now a new reverse proxy designed for Etherpads that handles multiple Etherpads and the created pads in them. It will assign the pad assignement to an Etherpad at random but once the choice was made it will always reverse proxy the same backend. This allows to host multiple concurrent Etherpads and benefit from multi core systems even though one Etherpad is singlethreaded.
- Added reverse proxy configuration for replacing Nginx. In the past there were some issues with nginx and its configuration. This reverse proxy allows you to handle your configuration with ease.
If you want to find out more about the reverse proxy method check out the repository https://github.com/ether/etherpad-proxy . It also contains a sample docker-compose file with three Etherpads and one etherpad-proxy. Of course you need to adapt the settings.json.template to your liking and map it into the reverse proxy image before you are ready :).
- Added client authorization to work with Etherpad. Before it would get blocked because it doesn't have the required claim. As this is now fixed etherpad-proxy can also work with your new OAuth2 configuration and retrieve a token via client credentials flow.
# 2.2.7
### Notable enhancements and fixes
- We migrated all important pages to React 19 and React Router v7
Besides that only dependency updates.
-> Have a merry Christmas and a happy new year. 🎄 🎁
# 2.2.6
### Notable enhancements and fixes
- Added option to delete a pad by the creator. This option can be found in the settings menu. When you click on it you get a confirm dialog and after that you have the chance to completely erase the pad.
# 2.2.5
### Notable enhancements and fixes
- Fixed timeslider not scrolling when the revision count is a multiple of 100
- Added new Restful API for version 2 of Etherpad. It is available at /api-docs
# 2.2.4
### Notable enhancements and fixes
- Switched to new SQLite backend
- Fixed rusty-store-kv module not found
# 2.2.3
### Notable enhancements and fixes
- Introduced a new in process database `rustydb` that represents a fast key value store written in Rust.
- Readded window._ as a shortcut for getting text
- Added support for migrating any ueberdb database to another. You can now switch as you please. See here: https://docs.etherpad.org/cli.html
- Further Typescript movements
- A lot of security issues fixed and reviewed in this release. Please update.
# 2.2.2
### Notable enhancements and fixes
- Removal of Etherpad require kernel: We finally managed to include esbuild to bundle our frontend code together. So no matter how many plugins your server has it is always one JavaScript file. This boosts performance dramatically.
- Added log layoutType: This lets you print the log in either colored or basic (black and white text)
- Introduced esbuild for bundling CSS files
- Cache all files to be bundled in memory for faster load speed
# 2.1.1
### Notable enhancements and fixes
- Fixed failing Docker build when checked out as git submodule. Thanks to @neurolabs
- Fixed: Fallback to websocket and polling when unknown(old) config is present for socket io
- Fixed: Next page disabled if zero page by @samyakj023
- On CTRL+CLICK bring the window back to focus by Helder Sepulveda
# 2.1.0 # 2.1.0
### Notable enhancements and fixes ### Notable enhancements and fixes

View file

@ -3,17 +3,16 @@
# https://github.com/ether/etherpad-lite # https://github.com/ether/etherpad-lite
# #
# Author: muxator # Author: muxator
ARG BUILD_ENV=git
FROM node:alpine AS adminbuild FROM node:alpine as adminBuild
RUN npm install -g pnpm@latest
WORKDIR /opt/etherpad-lite WORKDIR /opt/etherpad-lite
COPY . . COPY ./ ./
RUN pnpm install RUN cd ./admin && npm install -g pnpm@9.0.4 && pnpm install && pnpm run build --outDir ./dist
RUN pnpm run build:ui RUN cd ./ui && pnpm install && pnpm run build --outDir ./dist
FROM node:alpine AS build FROM node:alpine as build
LABEL maintainer="Etherpad team, https://github.com/ether/etherpad-lite" LABEL maintainer="Etherpad team, https://github.com/ether/etherpad-lite"
# Set these arguments when building the image from behind a proxy # Set these arguments when building the image from behind a proxy
@ -50,14 +49,6 @@ ARG ETHERPAD_PLUGINS=
# ETHERPAD_LOCAL_PLUGINS="../ep_my_plugin ../ep_another_plugin" # ETHERPAD_LOCAL_PLUGINS="../ep_my_plugin ../ep_another_plugin"
ARG ETHERPAD_LOCAL_PLUGINS= ARG ETHERPAD_LOCAL_PLUGINS=
# github plugins to install while building the container. By default no plugins are
# installed.
# If given a value, it has to be a space-separated, quoted list of plugin names.
#
# EXAMPLE:
# ETHERPAD_GITHUB_PLUGINS="ether/ep_plugin"
ARG ETHERPAD_GITHUB_PLUGINS=
# Control whether abiword will be installed, enabling exports to DOC/PDF/ODT formats. # Control whether abiword will be installed, enabling exports to DOC/PDF/ODT formats.
# By default, it is not installed. # By default, it is not installed.
# If given any value, abiword will be installed. # If given any value, abiword will be installed.
@ -100,7 +91,7 @@ RUN mkdir -p "${EP_DIR}" && chown etherpad:etherpad "${EP_DIR}"
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199 # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
RUN \ RUN \
mkdir -p /usr/share/man/man1 && \ mkdir -p /usr/share/man/man1 && \
npm install pnpm@latest -g && \ npm install pnpm@9.0.4 -g && \
apk update && apk upgrade && \ apk update && apk upgrade && \
apk add --no-cache \ apk add --no-cache \
ca-certificates \ ca-certificates \
@ -114,66 +105,40 @@ USER etherpad
WORKDIR "${EP_DIR}" WORKDIR "${EP_DIR}"
# etherpads version feature requires this. Only copy what is really needed # etherpads version feature requires this. Only copy what is really needed
COPY --chown=etherpad:etherpad ./.git/HEAD ./.git/HEAD
COPY --chown=etherpad:etherpad ./.git/refs ./.git/refs
COPY --chown=etherpad:etherpad ${SETTINGS} ./settings.json COPY --chown=etherpad:etherpad ${SETTINGS} ./settings.json
COPY --chown=etherpad:etherpad ./var ./var COPY --chown=etherpad:etherpad ./var ./var
COPY --chown=etherpad:etherpad ./bin ./bin COPY --chown=etherpad:etherpad ./bin ./bin
COPY --chown=etherpad:etherpad ./pnpm-workspace.yaml ./package.json ./ COPY --chown=etherpad:etherpad ./pnpm-workspace.yaml ./package.json ./
FROM build as development
COPY --chown=etherpad:etherpad ./src/package.json .npmrc ./src/
FROM build AS build_git COPY --chown=etherpad:etherpad --from=adminBuild /opt/etherpad-lite/admin/dist ./src/templates/admin
ONBUILD COPY --chown=etherpad:etherpad ./.git/HEA[D] ./.git/HEAD COPY --chown=etherpad:etherpad --from=adminBuild /opt/etherpad-lite/ui/dist ./src/static/oidc
ONBUILD COPY --chown=etherpad:etherpad ./.git/ref[s] ./.git/refs
FROM build AS build_copy
FROM build_${BUILD_ENV} AS development
ARG ETHERPAD_PLUGINS=
ARG ETHERPAD_LOCAL_PLUGINS=
ARG ETHERPAD_LOCAL_PLUGINS_ENV=
ARG ETHERPAD_GITHUB_PLUGINS=
COPY --chown=etherpad:etherpad ./src/ ./src/
COPY --chown=etherpad:etherpad --from=adminbuild /opt/etherpad-lite/src/ templates/admin./src/templates/admin
COPY --chown=etherpad:etherpad --from=adminbuild /opt/etherpad-lite/src/static/oidc ./src/static/oidc
COPY --chown=etherpad:etherpad ./local_plugin[s] ./local_plugins/
RUN bash -c ./bin/installLocalPlugins.sh
RUN bin/installDeps.sh && \ RUN bin/installDeps.sh && \
if [ ! -z "${ETHERPAD_PLUGINS}" ] || [ ! -z "${ETHERPAD_GITHUB_PLUGINS}" ]; then \ if [ ! -z "${ETHERPAD_PLUGINS}" ] || [ ! -z "${ETHERPAD_LOCAL_PLUGINS}" ]; then \
pnpm run plugins i ${ETHERPAD_PLUGINS} ${ETHERPAD_GITHUB_PLUGINS:+--github ${ETHERPAD_GITHUB_PLUGINS}}; \ pnpm run plugins i ${ETHERPAD_PLUGINS} ${ETHERPAD_LOCAL_PLUGINS:+--path ${ETHERPAD_LOCAL_PLUGINS}}; \
fi fi
FROM build_${BUILD_ENV} AS production FROM build as production
ARG ETHERPAD_PLUGINS=
ARG ETHERPAD_LOCAL_PLUGINS=
ARG ETHERPAD_LOCAL_PLUGINS_ENV=
ARG ETHERPAD_GITHUB_PLUGINS=
ENV NODE_ENV=production ENV NODE_ENV=production
ENV ETHERPAD_PRODUCTION=true ENV ETHERPAD_PRODUCTION=true
COPY --chown=etherpad:etherpad ./src ./src COPY --chown=etherpad:etherpad ./src ./src
COPY --chown=etherpad:etherpad --from=adminbuild /opt/etherpad-lite/src/templates/admin ./src/templates/admin COPY --chown=etherpad:etherpad --from=adminBuild /opt/etherpad-lite/admin/dist ./src/templates/admin
COPY --chown=etherpad:etherpad --from=adminbuild /opt/etherpad-lite/src/static/oidc ./src/static/oidc COPY --chown=etherpad:etherpad --from=adminBuild /opt/etherpad-lite/ui/dist ./src/static/oidc
COPY --chown=etherpad:etherpad ./local_plugin[s] ./local_plugins/ RUN bin/installDeps.sh && rm -rf ~/.npm && rm -rf ~/.local && rm -rf ~/.cache && \
if [ ! -z "${ETHERPAD_PLUGINS}" ] || [ ! -z "${ETHERPAD_LOCAL_PLUGINS}" ]; then \
RUN bash -c ./bin/installLocalPlugins.sh pnpm run plugins i ${ETHERPAD_PLUGINS} ${ETHERPAD_LOCAL_PLUGINS:+--path ${ETHERPAD_LOCAL_PLUGINS}}; \
RUN bin/installDeps.sh && \
if [ ! -z "${ETHERPAD_PLUGINS}" ] || [ ! -z "${ETHERPAD_GITHUB_PLUGINS}" ]; then \
pnpm run plugins i ${ETHERPAD_PLUGINS} ${ETHERPAD_GITHUB_PLUGINS:+--github ${ETHERPAD_GITHUB_PLUGINS}}; \
fi fi
# Copy the configuration file. # Copy the configuration file.
COPY --chown=etherpad:etherpad ${SETTINGS} "${EP_DIR}"/settings.json COPY --chown=etherpad:etherpad ${SETTINGS} "${EP_DIR}"/settings.json

100
README.md
View file

@ -90,7 +90,7 @@ services:
# ports: # ports:
# - "5432:5432" # - "5432:5432"
volumes: volumes:
- postgres_data:/var/lib/postgresql/data - postgres_data:/var/lib/postgresql/data/pgdata
volumes: volumes:
postgres_data: postgres_data:
@ -98,19 +98,76 @@ volumes:
etherpad-var: etherpad-var:
``` ```
### Requirements ### Requirements
[Node.js](https://nodejs.org/) >= **18.18.2**. [Node.js](https://nodejs.org/) >= **18.18.2**.
### Windows, macOS, Linux ### GNU/Linux and other UNIX-like systems
1. Download the latest Node.js runtime from [nodejs.org](https://nodejs.org/). #### Quick install on Debian/Ubuntu
2. Install pnpm: `npm install -g pnpm` (Administrator privileges may be required).
3. Clone the repository: `git clone -b master` Install the latest Node.js LTS per [official install instructions](https://github.com/nodesource/distributions#installation-instructions), then:
4. Run `pnpm i` ```sh
5. Run `pnpm run build:etherpad` git clone --branch master https://github.com/ether/etherpad-lite.git &&
6. Run `pnpm run prod` cd etherpad-lite &&
7. Visit `http://localhost:9001` in your browser. bin/run.sh
```
#### Manual install
You'll need Git and [Node.js](https://nodejs.org/) installed.
**As any user (we recommend creating a separate user called etherpad):**
1. Move to a folder where you want to install Etherpad.
2. Clone the Git repository: `git clone --branch master
https://github.com/ether/etherpad-lite.git`
3. Change into the new directory containing the cloned source code: `cd
etherpad-lite`
4. Run `bin/run.sh` and open http://127.0.0.1:9001 in your browser.
To update to the latest released version, execute `git pull origin`. The next
start with `bin/run.sh` will update the dependencies.
### Windows
#### Prebuilt Windows package
This package runs on any Windows machine. You can perform a manual installation
via git for development purposes, but as this uses symlinks which performs
unreliably on Windows, please stick to the prebuilt package if possible.
1. [Download the latest Windows package](https://etherpad.org/#download)
2. Extract the folder
Run `start.bat` and open <http://localhost:9001> in your browser.
#### Manually install on Windows
You'll need [Node.js](https://nodejs.org) and (optionally, though recommended)
git.
1. Grab the source, either:
* download <https://github.com/ether/etherpad-lite/zipball/master>
* or `git clone --branch master
https://github.com/ether/etherpad-lite.git`
2. With a "Run as administrator" command prompt execute
`bin\installOnWindows.bat`
Now, run `start.bat` and open http://localhost:9001 in your browser.
Update to the latest version with `git pull origin`, then run
`bin\installOnWindows.bat`, again.
If cloning to a subdirectory within another project, you may need to do the
following:
1. Start the server manually (e.g. `node src/node/server.ts`)
2. Edit the db `filename` in `settings.json` to the relative directory with
the file (e.g. `application/lib/etherpad-lite/var/dirty.db`)
3. Add auto-generated files to the main project `.gitignore`
### Docker container ### Docker container
@ -174,31 +231,6 @@ following plugins:
that each user's chosen color, display name, comment ownership, etc. is that each user's chosen color, display name, comment ownership, etc. is
strongly linked to their account. strongly linked to their account.
### Upgrade Etherpad
Run the following command in your Etherpad folder to upgrade
1. Stop any running Etherpad (manual, systemd ...)
2. Get present version
```sh
git -P tag --contains
```
3. List versions available
```sh
git -P tag --list "v*" --merged
```
4. Select the version
```sh
git checkout v2.2.5
git switch -c v2.2.5
```
5. Upgrade Etherpad
```sh
./bin/run.sh
```
6. Stop with [CTRL-C]
7. Restart your Etherpad service
## Next Steps ## Next Steps
### Tweak the settings ### Tweak the settings

View file

@ -1,7 +1,7 @@
{ {
"name": "admin", "name": "admin",
"private": true, "private": true,
"version": "2.3.0", "version": "2.1.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@ -11,32 +11,32 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@radix-ui/react-switch": "^1.2.5" "@radix-ui/react-switch": "^1.0.3"
}, },
"devDependencies": { "devDependencies": {
"@radix-ui/react-dialog": "^1.1.14", "@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-toast": "^1.2.14", "@radix-ui/react-toast": "^1.1.5",
"@types/react": "^19.1.8", "@types/react": "^18.3.2",
"@types/react-dom": "^19.1.6", "@types/react-dom": "^18.2.25",
"@typescript-eslint/eslint-plugin": "^8.34.0", "@typescript-eslint/eslint-plugin": "^7.11.0",
"@typescript-eslint/parser": "^8.34.0", "@typescript-eslint/parser": "^7.11.0",
"@vitejs/plugin-react-swc": "^3.10.2", "@vitejs/plugin-react-swc": "^3.5.0",
"eslint": "^9.28.0", "eslint": "^9.2.0",
"eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.20", "eslint-plugin-react-refresh": "^0.4.7",
"i18next": "^25.2.1", "i18next": "^23.11.5",
"i18next-browser-languagedetector": "^8.2.0", "i18next-browser-languagedetector": "^8.0.0",
"lucide-react": "^0.515.0", "lucide-react": "^0.381.0",
"react": "^19.1.0", "react": "^18.2.0",
"react-dom": "^19.1.0", "react-dom": "^18.2.0",
"react-hook-form": "^7.57.0", "react-hook-form": "^7.51.5",
"react-i18next": "^15.5.3", "react-i18next": "^14.1.0",
"react-router-dom": "^7.6.2", "react-router-dom": "^6.23.1",
"socket.io-client": "^4.8.1", "socket.io-client": "^4.7.5",
"typescript": "^5.8.2", "typescript": "^5.4.5",
"vite": "^6.3.5", "vite": "^5.2.12",
"vite-plugin-static-copy": "^3.0.0", "vite-plugin-static-copy": "^1.0.3",
"vite-plugin-svgr": "^4.3.0", "vite-plugin-svgr": "^4.2.0",
"zustand": "^5.0.5" "zustand": "^4.5.2"
} }
} }

View file

@ -14,7 +14,6 @@
"ep_adminpads2_autoupdate.title": "Aktiviert oder deaktiviert automatische Aktualisierungen für die aktuelle Abfrage.", "ep_adminpads2_autoupdate.title": "Aktiviert oder deaktiviert automatische Aktualisierungen für die aktuelle Abfrage.",
"ep_adminpads2_confirm": "Willst du das Pad {{padID}} wirklich löschen?", "ep_adminpads2_confirm": "Willst du das Pad {{padID}} wirklich löschen?",
"ep_adminpads2_delete.value": "Löschen", "ep_adminpads2_delete.value": "Löschen",
"ep_adminpads2_cleanup": "Historie aufräumen",
"ep_adminpads2_last-edited": "Zuletzt bearbeitet", "ep_adminpads2_last-edited": "Zuletzt bearbeitet",
"ep_adminpads2_loading": "Lädt...", "ep_adminpads2_loading": "Lädt...",
"ep_adminpads2_manage-pads": "Pads verwalten", "ep_adminpads2_manage-pads": "Pads verwalten",

View file

@ -4,7 +4,6 @@
"ep_adminpads2_autoupdate.title": "Enables or disables automatic updates for the current query.", "ep_adminpads2_autoupdate.title": "Enables or disables automatic updates for the current query.",
"ep_adminpads2_confirm": "Do you really want to delete the pad {{padID}}?", "ep_adminpads2_confirm": "Do you really want to delete the pad {{padID}}?",
"ep_adminpads2_delete.value": "Delete", "ep_adminpads2_delete.value": "Delete",
"ep_adminpads2_cleanup": "Cleanup revisions",
"ep_adminpads2_last-edited": "Last edited", "ep_adminpads2_last-edited": "Last edited",
"ep_adminpads2_loading": "Loading…", "ep_adminpads2_loading": "Loading…",
"ep_adminpads2_manage-pads": "Manage pads", "ep_adminpads2_manage-pads": "Manage pads",

View file

@ -1,4 +1,4 @@
import {useEffect, useState} from 'react' import {useEffect} from 'react'
import './App.css' import './App.css'
import {connect} from 'socket.io-client' import {connect} from 'socket.io-client'
import {isJSONClean} from './utils/utils.ts' import {isJSONClean} from './utils/utils.ts'
@ -6,23 +6,22 @@ import {NavLink, Outlet, useNavigate} from "react-router-dom";
import {useStore} from "./store/store.ts"; import {useStore} from "./store/store.ts";
import {LoadingScreen} from "./utils/LoadingScreen.tsx"; import {LoadingScreen} from "./utils/LoadingScreen.tsx";
import {Trans, useTranslation} from "react-i18next"; import {Trans, useTranslation} from "react-i18next";
import {Cable, Construction, Crown, NotepadText, Wrench, PhoneCall, LucideMenu} from "lucide-react"; import {Cable, Construction, Crown, NotepadText, Wrench, PhoneCall} from "lucide-react";
const WS_URL = import.meta.env.DEV ? 'http://localhost:9001' : '' const WS_URL = import.meta.env.DEV? 'http://localhost:9001' : ''
export const App = () => { export const App = ()=> {
const setSettings = useStore(state => state.setSettings); const setSettings = useStore(state => state.setSettings);
const {t} = useTranslation() const {t} = useTranslation()
const navigate = useNavigate() const navigate = useNavigate()
const [sidebarOpen, setSidebarOpen] = useState<boolean>(true)
useEffect(() => { useEffect(() => {
fetch('/admin-auth/', { fetch('/admin-auth/', {
method: 'POST' method: 'POST'
}).then((value) => { }).then((value)=>{
if (!value.ok) { if(!value.ok){
navigate('/login') navigate('/login')
} }
}).catch(() => { }).catch(()=>{
navigate('/login') navigate('/login')
}) })
}, []); }, []);
@ -76,7 +75,7 @@ export const App = () => {
useStore.getState().setShowLoading(false); useStore.getState().setShowLoading(false);
}); });
settingSocket.on('saveprogress', (status) => { settingSocket.on('saveprogress', (status)=>{
console.log(status) console.log(status)
}) })
@ -86,7 +85,7 @@ export const App = () => {
} }
}, []); }, []);
return <div id="wrapper" className={`${sidebarOpen ? '': 'closed' }`}> return <div id="wrapper">
<LoadingScreen/> <LoadingScreen/>
<div className="menu"> <div className="menu">
<div className="inner-menu"> <div className="inner-menu">
@ -94,11 +93,7 @@ export const App = () => {
<Crown width={40} height={40}/> <Crown width={40} height={40}/>
<h1>Etherpad</h1> <h1>Etherpad</h1>
</span> </span>
<ul onClick={()=>{ <ul>
if (window.innerWidth < 768) {
setSidebarOpen(false)
}
}}>
<li><NavLink to="/plugins"><Cable/><Trans i18nKey="admin_plugins"/></NavLink></li> <li><NavLink to="/plugins"><Cable/><Trans i18nKey="admin_plugins"/></NavLink></li>
<li><NavLink to={"/settings"}><Wrench/><Trans i18nKey="admin_settings"/></NavLink></li> <li><NavLink to={"/settings"}><Wrench/><Trans i18nKey="admin_settings"/></NavLink></li>
<li><NavLink to={"/help"}> <Construction/> <Trans i18nKey="admin_plugins_info"/></NavLink></li> <li><NavLink to={"/help"}> <Construction/> <Trans i18nKey="admin_plugins_info"/></NavLink></li>
@ -108,9 +103,6 @@ export const App = () => {
</ul> </ul>
</div> </div>
</div> </div>
<button id="icon-button" onClick={() => {
setSidebarOpen(!sidebarOpen)
}}><LucideMenu/></button>
<div className="innerwrapper"> <div className="innerwrapper">
<Outlet/> <Outlet/>
</div> </div>

View file

@ -1,4 +1,4 @@
import {FC, JSX, ReactElement} from "react"; import {FC, ReactElement} from "react";
export type IconButtonProps = { export type IconButtonProps = {
icon: JSX.Element, icon: JSX.Element,

View file

@ -2,7 +2,6 @@
--etherpad-color: #0f775b; --etherpad-color: #0f775b;
--etherpad-comp: #9C8840; --etherpad-comp: #9C8840;
--etherpad-light: #99FF99; --etherpad-light: #99FF99;
--sidebar-width: 20em;
} }
@font-face { @font-face {
@ -29,21 +28,17 @@ body {
} }
div.menu { div.menu {
left: 0;
transition: left .3s;
height: 100vh; height: 100vh;
font-size: 16px; font-size: 16px;
font-weight: bolder; font-weight: bolder;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: var(--sidebar-width); max-width: 20%;
z-index: 99; min-width: 20%;
position: fixed;
} }
.icon-button{
.icon-button {
display: flex; display: flex;
gap: 10px; gap: 10px;
background-color: var(--etherpad-color); background-color: var(--etherpad-color);
@ -113,7 +108,7 @@ div.menu li {
div.menu li:has(.active) { div.menu li:has(.active) {
background-color: #9C885C; background-color: #9C885C ;
} }
div.menu li a { div.menu li a {
@ -121,15 +116,13 @@ div.menu li a {
} }
div.innerwrapper { div.innerwrapper {
transition: margin-left .3s;
isolation: isolate;
background-color: #F0F0F0; background-color: #F0F0F0;
overflow: auto; overflow: auto;
height: 100vh; height: 100vh;
flex-grow: 100; flex-grow: 100;
margin-left: var(--sidebar-width); padding: 20px;
padding: 20px 20px 20px;
} }
div.innerwrapper-err { div.innerwrapper-err {
@ -137,9 +130,11 @@ div.innerwrapper-err {
} }
#wrapper { #wrapper {
display: flex;
background: none repeat scroll 0px 0px #FFFFFF; background: none repeat scroll 0px 0px #FFFFFF;
box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.2); box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.2);
min-height: 100%; /*always display a scrollbar*/ min-height: 100%;/*always display a scrollbar*/
} }
h1 { h1 {
@ -178,17 +173,14 @@ input {
.sort { .sort {
cursor: pointer; cursor: pointer;
} }
.sort:after { .sort:after {
content: '▲▼' content: '▲▼'
} }
.sort.up:after { .sort.up:after {
content: '▲' content:'▲'
} }
.sort.down:after { .sort.down:after {
content: '▼' content:'▼'
} }
@ -204,14 +196,11 @@ table {
margin: 20px 0; margin: 20px 0;
} }
.table-container {
width: 100%;
overflow: auto;
max-height: 90vh;
}
#available-plugins th:first-child, #available-plugins th:nth-child(2) {
#available-plugins th:first-child, #available-plugins th:nth-child(2){
text-align: center; text-align: center;
} }
@ -223,40 +212,35 @@ td, th {
display: none; display: none;
} }
#installed-plugins td > div { #installed-plugins td>div {
position: relative; /* Allows us to position the loading indicator relative to this row */ position: relative;/* Allows us to position the loading indicator relative to this row */
display: inline-block; /*make this fill the whole cell*/ display: inline-block; /*make this fill the whole cell*/
width: 100%; width:100%;
} }
.messages { .messages {
height: 5em; height: 5em;
} }
.messages * { .messages * {
display: none; display: none;
text-align: center; text-align: center;
} }
.messages .fetching { .messages .fetching {
display: block; display: block;
} }
.progress { .progress {
position: absolute; position: absolute;
top: 0; top: 0; left: 0; bottom:0; right:0;
left: 0;
bottom: 0;
right: 0;
padding: auto; padding: auto;
background: rgb(255, 255, 255); background: rgb(255,255,255);
display: none; display: none;
} }
#search-progress.progress { #search-progress.progress {
padding-top: 20%; padding-top: 20%;
background: rgba(255, 255, 255, 0.3); background: rgba(255,255,255,0.3);
} }
.progress * { .progress * {
@ -279,7 +263,6 @@ td, th {
outline: none; outline: none;
width: 100%; width: 100%;
resize: none; resize: none;
font-family: monospace;
} }
#response { #response {
@ -318,45 +301,17 @@ pre {
word-wrap: break-word; word-wrap: break-word;
} }
#icon-button {
color: var(--etherpad-color);
top: 10px;
background-color: transparent;
border: none;
z-index: 99;
position: absolute;
left: 10px;
}
.inner-menu span:nth-child(2) {
display: flex;
margin-top: 30px;
}
#wrapper.closed .menu {
left: calc(-1 * var(--sidebar-width));
}
#wrapper.closed .innerwrapper {
margin-left: 0;
}
@media (max-width: 800px) { @media (max-width: 800px) {
div.innerwrapper { div.innerwrapper {
margin-left: 0; padding: 0 15px 15px 15px;
}
.inner-menu {
border-radius: 0;
} }
div.menu { div.menu {
padding: 1px 15px 0 15px;
position: static;
height: auto; height: auto;
border-right: none; border-right: none;
--sidebar-width: 100%; width: auto;
float: left; float: left;
} }
@ -420,7 +375,6 @@ pre {
.login-background { .login-background {
background-image: url("/fond.jpg"); background-image: url("/fond.jpg");
background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: cover; background-size: cover;
display: flex; display: flex;
@ -434,11 +388,12 @@ pre {
margin-top: 1rem; margin-top: 1rem;
} }
.login-inner-box [type=submit] { .login-inner-box [type=submit]{
margin-top: 2rem; margin-top: 2rem;
} }
.login-textinput { .login-textinput {
width: 100%; width: 100%;
padding: 10px; padding: 10px;
@ -449,20 +404,14 @@ pre {
} }
.login-box { .login-box {
width: 20%;
padding: 20px; padding: 20px;
border-radius: 40px; border-radius: 40px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
background-color: #fff; background-color: #fff;
} }
.login-inner-box{
@media (max-width: 900px) {
.login-box {
width: 90%
}
}
.login-inner-box {
position: relative; position: relative;
padding: 20px; padding: 20px;
} }
@ -530,6 +479,7 @@ pre {
} }
.ToastViewport { .ToastViewport {
position: fixed; position: fixed;
top: 10px; top: 10px;
@ -567,24 +517,19 @@ pre {
column-gap: 15px; column-gap: 15px;
align-items: center; align-items: center;
} }
.ToastRoot[data-state='open'] { .ToastRoot[data-state='open'] {
animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1); animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1);
} }
.ToastRoot[data-state='closed'] { .ToastRoot[data-state='closed'] {
animation: hide 100ms ease-in; animation: hide 100ms ease-in;
} }
.ToastRoot[data-swipe='move'] { .ToastRoot[data-swipe='move'] {
transform: translateX(var(--radix-toast-swipe-move-x)); transform: translateX(var(--radix-toast-swipe-move-x));
} }
.ToastRoot[data-swipe='cancel'] { .ToastRoot[data-swipe='cancel'] {
transform: translateX(0); transform: translateX(0);
transition: transform 200ms ease-out; transition: transform 200ms ease-out;
} }
.ToastRoot[data-swipe='end'] { .ToastRoot[data-swipe='end'] {
animation: swipeOut 100ms ease-out; animation: swipeOut 100ms ease-out;
} }
@ -651,7 +596,7 @@ pre {
border-color: transparent; border-color: transparent;
border-radius: 20px; border-radius: 20px;
height: 2.5rem; height: 2.5rem;
width: 100%; width: 100vh;
padding: 5px 5px 5px 30px; padding: 5px 5px 5px 30px;
} }
@ -738,7 +683,7 @@ table tbody tr.active-row {
} }
.pad-pagination { .pad-pagination{
display: flex; display: flex;
justify-content: center; justify-content: center;
gap: 10px; gap: 10px;
@ -765,7 +710,7 @@ table tbody tr.active-row {
align-self: center; align-self: center;
} }
.pad-pagination > span { .pad-pagination >span {
font-size: 20px; font-size: 20px;
} }
@ -819,11 +764,9 @@ input, button, select, optgroup, textarea {
box-shadow: 0 2px 10px var(--black-a7); box-shadow: 0 2px 10px var(--black-a7);
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
} }
.SwitchRoot:focus { .SwitchRoot:focus {
box-shadow: 0 0 0 2px black; box-shadow: 0 0 0 2px black;
} }
.SwitchRoot[data-state='checked'] { .SwitchRoot[data-state='checked'] {
background-color: var(--etherpad-color); background-color: var(--etherpad-color);
} }
@ -839,7 +782,6 @@ input, button, select, optgroup, textarea {
transform: translateX(2px); transform: translateX(2px);
will-change: transform; will-change: transform;
} }
.SwitchThumb[data-state='checked'] { .SwitchThumb[data-state='checked'] {
transform: translateX(25px); transform: translateX(25px);
} }
@ -859,12 +801,3 @@ input, button, select, optgroup, textarea {
background-color: var(--etherpad-color); background-color: var(--etherpad-color);
color: white color: white
} }
.search-pads {
text-align: center;
}
.search-pads-body tr td:last-child {
display: flex;
justify-content: center;
}

View file

@ -4,54 +4,16 @@ import {InstalledPlugin, PluginDef, SearchParams} from "./Plugin.ts";
import {useDebounce} from "../utils/useDebounce.ts"; import {useDebounce} from "../utils/useDebounce.ts";
import {Trans, useTranslation} from "react-i18next"; import {Trans, useTranslation} from "react-i18next";
import {SearchField} from "../components/SearchField.tsx"; import {SearchField} from "../components/SearchField.tsx";
import {ArrowUpFromDot, Download, Trash} from "lucide-react"; import {Download, Trash} from "lucide-react";
import {IconButton} from "../components/IconButton.tsx"; import {IconButton} from "../components/IconButton.tsx";
import {determineSorting} from "../utils/sorting.ts";
export const HomePage = () => { export const HomePage = () => {
const pluginsSocket = useStore(state=>state.pluginsSocket) const pluginsSocket = useStore(state=>state.pluginsSocket)
const [plugins,setPlugins] = useState<PluginDef[]>([]) const [plugins,setPlugins] = useState<PluginDef[]>([])
const installedPlugins = useStore(state=>state.installedPlugins) const [installedPlugins, setInstalledPlugins] = useState<InstalledPlugin[]>([])
const setInstalledPlugins = useStore(state=>state.setInstalledPlugins)
const [searchParams, setSearchParams] = useState<SearchParams>({
offset: 0,
limit: 99999,
sortBy: 'name',
sortDir: 'asc',
searchTerm: ''
})
const filteredInstallablePlugins = useMemo(()=>{
return plugins.sort((a, b)=>{
if(searchParams.sortBy === "version"){
if(searchParams.sortDir === "asc"){
return a.version.localeCompare(b.version)
}
return b.version.localeCompare(a.version)
}
if(searchParams.sortBy === "last-updated"){
if(searchParams.sortDir === "asc"){
return a.time.localeCompare(b.time)
}
return b.time.localeCompare(a.time)
}
if (searchParams.sortBy === "name") {
if(searchParams.sortDir === "asc"){
return a.name.localeCompare(b.name)
}
return b.name.localeCompare(a.name)
}
return 0
})
}, [plugins, searchParams])
const sortedInstalledPlugins = useMemo(()=>{ const sortedInstalledPlugins = useMemo(()=>{
return useStore.getState().installedPlugins.sort((a, b)=>{ return installedPlugins.sort((a, b)=>{
if(a.name < b.name){ if(a.name < b.name){
return -1 return -1
} }
@ -61,8 +23,14 @@ export const HomePage = () => {
return 0 return 0
}) })
} ,[installedPlugins, searchParams]) } ,[installedPlugins])
const [searchParams, setSearchParams] = useState<SearchParams>({
offset: 0,
limit: 99999,
sortBy: 'name',
sortDir: 'asc',
searchTerm: ''
})
const [searchTerm, setSearchTerm] = useState<string>('') const [searchTerm, setSearchTerm] = useState<string>('')
const {t} = useTranslation() const {t} = useTranslation()
@ -79,16 +47,17 @@ export const HomePage = () => {
}) })
pluginsSocket.on('results:updatable', (data) => { pluginsSocket.on('results:updatable', (data) => {
const newInstalledPlugins = useStore.getState().installedPlugins.map(plugin => { data.updatable.forEach((pluginName: string) => {
if (data.updatable.includes(plugin.name)) { setInstalledPlugins(installedPlugins.map(plugin => {
if (plugin.name === pluginName) {
return { return {
...plugin, ...plugin,
updatable: true updatable: true
} }
} }
return plugin return plugin
}))
}) })
setInstalledPlugins(newInstalledPlugins)
}) })
pluginsSocket.on('finished:install', () => { pluginsSocket.on('finished:install', () => {
@ -124,20 +93,25 @@ export const HomePage = () => {
if (!pluginsSocket) { if (!pluginsSocket) {
return return
} }
pluginsSocket?.emit('search', searchParams) pluginsSocket?.emit('search', searchParams)
pluginsSocket!.on('results:search', (data: { pluginsSocket!.on('results:search', (data: {
results: PluginDef[] results: PluginDef[]
}) => { }) => {
if (Array.isArray(data.results) && data.results.length > 0) {
setPlugins(data.results) setPlugins(data.results)
}) } else {
pluginsSocket!.on('results:searcherror', (data: {error: string}) => {
console.log(data.error)
useStore.getState().setToastState({ useStore.getState().setToastState({
open: true, open: true,
title: "Error retrieving plugins", title: "Error retrieving plugins",
success: false success: false
}) })
}
}) })
}, [searchParams, pluginsSocket]); }, [searchParams, pluginsSocket]);
const uninstallPlugin = (pluginName: string)=>{ const uninstallPlugin = (pluginName: string)=>{
@ -151,6 +125,7 @@ export const HomePage = () => {
setPlugins(plugins.filter(plugin=>plugin.name !== pluginName)) setPlugins(plugins.filter(plugin=>plugin.name !== pluginName))
} }
useDebounce(()=>{ useDebounce(()=>{
setSearchParams({ setSearchParams({
...searchParams, ...searchParams,
@ -159,7 +134,6 @@ export const HomePage = () => {
}) })
}, 500, [searchTerm]) }, 500, [searchTerm])
return <div> return <div>
<h1><Trans i18nKey="admin_plugins"/></h1> <h1><Trans i18nKey="admin_plugins"/></h1>
@ -181,7 +155,7 @@ export const HomePage = () => {
<td> <td>
{ {
plugin.updatable ? plugin.updatable ?
<IconButton onClick={() => installPlugin(plugin.name)} icon={<ArrowUpFromDot/>} title="Update"></IconButton> <button onClick={() => installPlugin(plugin.name)}>Update</button>
: <IconButton disabled={plugin.name == "ep_etherpad-lite"} icon={<Trash/>} title={<Trans i18nKey="admin_plugins.installed_uninstall.value"/>} onClick={() => uninstallPlugin(plugin.name)}/> : <IconButton disabled={plugin.name == "ep_etherpad-lite"} icon={<Trash/>} title={<Trans i18nKey="admin_plugins.installed_uninstall.value"/>} onClick={() => uninstallPlugin(plugin.name)}/>
} }
</td> </td>
@ -194,39 +168,18 @@ export const HomePage = () => {
<h2><Trans i18nKey="admin_plugins.available"/></h2> <h2><Trans i18nKey="admin_plugins.available"/></h2>
<SearchField onChange={v=>{setSearchTerm(v.target.value)}} placeholder={t('admin_plugins.available_search.placeholder')} value={searchTerm}/> <SearchField onChange={v=>{setSearchTerm(v.target.value)}} placeholder={t('admin_plugins.available_search.placeholder')} value={searchTerm}/>
<div className="table-container">
<table id="available-plugins"> <table id="available-plugins">
<thead> <thead>
<tr> <tr>
<th className={determineSorting(searchParams.sortBy, searchParams.sortDir == "asc", 'name')} onClick={()=>{ <th><Trans i18nKey="admin_plugins.name"/></th>
setSearchParams({
...searchParams,
sortBy: 'name',
sortDir: searchParams.sortDir === "asc"? "desc": "asc"
})
}}>
<Trans i18nKey="admin_plugins.name" /></th>
<th style={{width: '30%'}}><Trans i18nKey="admin_plugins.description"/></th> <th style={{width: '30%'}}><Trans i18nKey="admin_plugins.description"/></th>
<th className={determineSorting(searchParams.sortBy, searchParams.sortDir == "asc", 'version')} onClick={()=>{ <th><Trans i18nKey="admin_plugins.version"/></th>
setSearchParams({ <th><Trans i18nKey="admin_plugins.last-update"/></th>
...searchParams,
sortBy: 'version',
sortDir: searchParams.sortDir === "asc"? "desc": "asc"
})
}}><Trans i18nKey="admin_plugins.version"/></th>
<th className={determineSorting(searchParams.sortBy, searchParams.sortDir == "asc", 'last-updated')} onClick={()=>{
setSearchParams({
...searchParams,
sortBy: 'last-updated',
sortDir: searchParams.sortDir === "asc"? "desc": "asc"
})
}}><Trans i18nKey="admin_plugins.last-update"/></th>
<th><Trans i18nKey="ep_admin_pads:ep_adminpads2_action"/></th> <th><Trans i18nKey="ep_admin_pads:ep_adminpads2_action"/></th>
</tr> </tr>
</thead> </thead>
<tbody style={{overflow: 'auto'}}> <tbody style={{overflow: 'auto'}}>
{(filteredInstallablePlugins.length > 0) ? {plugins.map((plugin) => {
filteredInstallablePlugins.map((plugin) => {
return <tr key={plugin.name}> return <tr key={plugin.name}>
<td><a rel="noopener noreferrer" href={`https://npmjs.com/${plugin.name}`} target="_blank">{plugin.name}</a></td> <td><a rel="noopener noreferrer" href={`https://npmjs.com/${plugin.name}`} target="_blank">{plugin.name}</a></td>
<td>{plugin.description}</td> <td>{plugin.description}</td>
@ -236,12 +189,8 @@ export const HomePage = () => {
<IconButton icon={<Download/>} onClick={() => installPlugin(plugin.name)} title={<Trans i18nKey="admin_plugins.available_install.value"/>}/> <IconButton icon={<Download/>} onClick={() => installPlugin(plugin.name)} title={<Trans i18nKey="admin_plugins.available_install.value"/>}/>
</td> </td>
</tr> </tr>
}) })}
:
<tr><td colSpan={5}>{searchTerm == '' ? <Trans i18nKey="pad.loading"/>: <Trans i18nKey="admin_plugins.available_not-found"/>}</td></tr>
}
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
} }

View file

@ -6,7 +6,7 @@ import {useDebounce} from "../utils/useDebounce.ts";
import {determineSorting} from "../utils/sorting.ts"; import {determineSorting} from "../utils/sorting.ts";
import * as Dialog from "@radix-ui/react-dialog"; import * as Dialog from "@radix-ui/react-dialog";
import {IconButton} from "../components/IconButton.tsx"; import {IconButton} from "../components/IconButton.tsx";
import {ChevronLeft, ChevronRight, Eye, Trash2, FileStack} from "lucide-react"; import {ChevronLeft, ChevronRight, Eye, Trash2} from "lucide-react";
import {SearchField} from "../components/SearchField.tsx"; import {SearchField} from "../components/SearchField.tsx";
export const PadPage = ()=>{ export const PadPage = ()=>{
@ -23,11 +23,10 @@ export const PadPage = ()=>{
const pads = useStore(state=>state.pads) const pads = useStore(state=>state.pads)
const [currentPage, setCurrentPage] = useState<number>(0) const [currentPage, setCurrentPage] = useState<number>(0)
const [deleteDialog, setDeleteDialog] = useState<boolean>(false) const [deleteDialog, setDeleteDialog] = useState<boolean>(false)
const [errorText, setErrorText] = useState<string|null>(null)
const [padToDelete, setPadToDelete] = useState<string>('') const [padToDelete, setPadToDelete] = useState<string>('')
const pages = useMemo(()=>{ const pages = useMemo(()=>{
if(!pads){ if(!pads){
return 0; return [0]
} }
return Math.ceil(pads!.total / searchParams.limit) return Math.ceil(pads!.total / searchParams.limit)
@ -69,35 +68,12 @@ export const PadPage = ()=>{
results: newPads results: newPads
}) })
}) })
settingsSocket.on('results:cleanupPadRevisions', (data)=>{
let newPads = useStore.getState().pads?.results ?? []
if (data.error) {
setErrorText(data.error)
return
}
newPads.forEach((pad)=>{
if (pad.padName === data.padId) {
pad.revisionNumber = data.keepRevisions
}
})
useStore.getState().setPads({
results: newPads,
total: useStore.getState().pads!.total
})
})
}, [settingsSocket, pads]); }, [settingsSocket, pads]);
const deletePad = (padID: string)=>{ const deletePad = (padID: string)=>{
settingsSocket?.emit('deletePad', padID) settingsSocket?.emit('deletePad', padID)
} }
const cleanupPad = (padID: string)=>{
settingsSocket?.emit('cleanupPadRevisions', padID)
}
return <div> return <div>
@ -124,26 +100,11 @@ export const PadPage = ()=>{
</Dialog.Content> </Dialog.Content>
</Dialog.Portal> </Dialog.Portal>
</Dialog.Root> </Dialog.Root>
<Dialog.Root open={errorText !== null}>
<Dialog.Portal>
<Dialog.Overlay className="dialog-confirm-overlay"/>
<Dialog.Content className="dialog-confirm-content">
<div>
<div>Error occured: {errorText}</div>
<div className="settings-button-bar">
<button onClick={() => {
setErrorText(null)
}}>OK</button>
</div>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
<h1><Trans i18nKey="ep_admin_pads:ep_adminpads2_manage-pads"/></h1> <h1><Trans i18nKey="ep_admin_pads:ep_adminpads2_manage-pads"/></h1>
<SearchField value={searchTerm} onChange={v=>setSearchTerm(v.target.value)} placeholder={t('ep_admin_pads:ep_adminpads2_search-heading')}/> <SearchField value={searchTerm} onChange={v=>setSearchTerm(v.target.value)} placeholder={t('ep_admin_pads:ep_adminpads2_search-heading')}/>
<table> <table>
<thead> <thead>
<tr className="search-pads"> <tr>
<th className={determineSorting(searchParams.sortBy, searchParams.ascending, 'padName')} onClick={()=>{ <th className={determineSorting(searchParams.sortBy, searchParams.ascending, 'padName')} onClick={()=>{
setSearchParams({ setSearchParams({
...searchParams, ...searchParams,
@ -151,19 +112,19 @@ export const PadPage = ()=>{
ascending: !searchParams.ascending ascending: !searchParams.ascending
}) })
}}><Trans i18nKey="ep_admin_pads:ep_adminpads2_padname"/></th> }}><Trans i18nKey="ep_admin_pads:ep_adminpads2_padname"/></th>
<th className={determineSorting(searchParams.sortBy, searchParams.ascending, 'userCount')} onClick={()=>{
setSearchParams({
...searchParams,
sortBy: 'userCount',
ascending: !searchParams.ascending
})
}}><Trans i18nKey="ep_admin_pads:ep_adminpads2_pad-user-count"/></th>
<th className={determineSorting(searchParams.sortBy, searchParams.ascending, 'lastEdited')} onClick={()=>{ <th className={determineSorting(searchParams.sortBy, searchParams.ascending, 'lastEdited')} onClick={()=>{
setSearchParams({ setSearchParams({
...searchParams, ...searchParams,
sortBy: 'lastEdited', sortBy: 'lastEdited',
ascending: !searchParams.ascending ascending: !searchParams.ascending
}) })
}}><Trans i18nKey="ep_admin_pads:ep_adminpads2_pad-user-count"/></th>
<th className={determineSorting(searchParams.sortBy, searchParams.ascending, 'userCount')} onClick={()=>{
setSearchParams({
...searchParams,
sortBy: 'userCount',
ascending: !searchParams.ascending
})
}}><Trans i18nKey="ep_admin_pads:ep_adminpads2_last-edited"/></th> }}><Trans i18nKey="ep_admin_pads:ep_adminpads2_last-edited"/></th>
<th className={determineSorting(searchParams.sortBy, searchParams.ascending, 'revisionNumber')} onClick={()=>{ <th className={determineSorting(searchParams.sortBy, searchParams.ascending, 'revisionNumber')} onClick={()=>{
setSearchParams({ setSearchParams({
@ -175,7 +136,7 @@ export const PadPage = ()=>{
<th><Trans i18nKey="ep_admin_pads:ep_adminpads2_action"/></th> <th><Trans i18nKey="ep_admin_pads:ep_adminpads2_action"/></th>
</tr> </tr>
</thead> </thead>
<tbody className="search-pads-body"> <tbody>
{ {
pads?.results?.map((pad)=>{ pads?.results?.map((pad)=>{
return <tr key={pad.padName}> return <tr key={pad.padName}>
@ -189,9 +150,6 @@ export const PadPage = ()=>{
setPadToDelete(pad.padName) setPadToDelete(pad.padName)
setDeleteDialog(true) setDeleteDialog(true)
}}/> }}/>
<IconButton icon={<FileStack/>} title={<Trans i18nKey="ep_admin_pads:ep_adminpads2_cleanup"/>} onClick={()=>{
cleanupPad(pad.padName)
}}/>
<IconButton icon={<Eye/>} title="view" onClick={()=>window.open(`/p/${pad.padName}`, '_blank')}/> <IconButton icon={<Eye/>} title="view" onClick={()=>window.open(`/p/${pad.padName}`, '_blank')}/>
</div> </div>
</td> </td>
@ -208,7 +166,7 @@ export const PadPage = ()=>{
offset: (Number(currentPage)-1)*searchParams.limit}) offset: (Number(currentPage)-1)*searchParams.limit})
}}><ChevronLeft/><span>Previous Page</span></button> }}><ChevronLeft/><span>Previous Page</span></button>
<span>{currentPage+1} out of {pages}</span> <span>{currentPage+1} out of {pages}</span>
<button disabled={pages == 0 || pages == currentPage+1} onClick={()=>{ <button disabled={pages == currentPage+1} onClick={()=>{
const newCurrentPage = currentPage+1 const newCurrentPage = currentPage+1
setCurrentPage(newCurrentPage) setCurrentPage(newCurrentPage)
setSearchParams({ setSearchParams({

View file

@ -20,7 +20,7 @@ export type SearchParams = {
searchTerm: string, searchTerm: string,
offset: number, offset: number,
limit: number, limit: number,
sortBy: 'name'|'version'|'last-updated', sortBy: 'name'|'version',
sortDir: 'asc'|'desc' sortDir: 'asc'|'desc'
} }

View file

@ -1,12 +1,12 @@
import {useStore} from "../store/store.ts"; import {useStore} from "../store/store.ts";
import {isJSONClean, cleanComments} from "../utils/utils.ts"; import {isJSONClean} from "../utils/utils.ts";
import {Trans} from "react-i18next"; import {Trans} from "react-i18next";
import {IconButton} from "../components/IconButton.tsx"; import {IconButton} from "../components/IconButton.tsx";
import {RotateCw, Save} from "lucide-react"; import {RotateCw, Save} from "lucide-react";
export const SettingsPage = ()=>{ export const SettingsPage = ()=>{
const settingsSocket = useStore(state=>state.settingsSocket) const settingsSocket = useStore(state=>state.settingsSocket)
const settings = cleanComments(useStore(state=>state.settings)) const settings = useStore(state=>state.settings)
return <div className="settings-page"> return <div className="settings-page">
<h1><Trans i18nKey="admin_settings.current"/></h1> <h1><Trans i18nKey="admin_settings.current"/></h1>

View file

@ -1,7 +1,6 @@
import {create} from "zustand"; import {create} from "zustand";
import {Socket} from "socket.io-client"; import {Socket} from "socket.io-client";
import {PadSearchResult} from "../utils/PadSearch.ts"; import {PadSearchResult} from "../utils/PadSearch.ts";
import {InstalledPlugin} from "../pages/Plugin.ts";
type ToastState = { type ToastState = {
description?:string, description?:string,
@ -23,9 +22,7 @@ type StoreState = {
toastState: ToastState, toastState: ToastState,
setToastState: (val: ToastState)=>void, setToastState: (val: ToastState)=>void,
pads: PadSearchResult|undefined, pads: PadSearchResult|undefined,
setPads: (pads: PadSearchResult)=>void, setPads: (pads: PadSearchResult)=>void
installedPlugins: InstalledPlugin[],
setInstalledPlugins: (plugins: InstalledPlugin[])=>void
} }
@ -46,7 +43,5 @@ export const useStore = create<StoreState>()((set) => ({
success: false success: false
}, },
pads: undefined, pads: undefined,
setPads: (pads)=>set({pads}), setPads: (pads)=>set({pads})
installedPlugins: [],
setInstalledPlugins: (plugins)=>set({installedPlugins: plugins})
})); }));

View file

@ -1,14 +1,5 @@
export const cleanComments = (json: string|undefined)=>{ const minify = (json: string)=>{
if (json !== undefined){
json = json.replace(/\/\*.*?\*\//g, ""); // remove single line comments
json = json.replace(/ *\/\*.*(.|\n)*?\*\//g, ""); // remove multi line comments
json = json.replace(/[ \t]+$/gm, ""); // trim trailing spaces
json = json.replace(/^(\n)/gm, ""); // remove empty lines
}
return json;
}
export const minify = (json: string)=>{
let tokenizer = /"|(\/\*)|(\*\/)|(\/\/)|\n|\r/g, let tokenizer = /"|(\/\*)|(\*\/)|(\/\/)|\n|\r/g,
in_string = false, in_string = false,
in_multiline_comment = false, in_multiline_comment = false,
@ -58,6 +49,9 @@ export const minify = (json: string)=>{
return new_str.join(""); return new_str.join("");
} }
export const isJSONClean = (data: string) => { export const isJSONClean = (data: string) => {
let cleanSettings = minify(data); let cleanSettings = minify(data);
// this is a bit naive. In theory some key/value might contain the sequences ',]' or ',}' // this is a bit naive. In theory some key/value might contain the sequences ',]' or ',}'

View file

@ -50,13 +50,21 @@ rm -rf src/node_modules || true
#$(try cd ./bin/installDeps.sh) #$(try cd ./bin/installDeps.sh)
# Install admin frontend # Install admin frontend
cd admin
try pnpm install try pnpm install
try pnpm run build:etherpad try pnpm run build
cd ..
# Nuke the admin folder as it is not needed anymore :D # Nuke the admin folder as it is not needed anymore :D
rm -rf admin rm -rf admin
rm -rf oidc
rm -rf src/node_modules export NODE_ENV=production
try pnpm install --production
log "copy the windows settings template..." log "copy the windows settings template..."
try cp settings.json.template settings.json try cp settings.json.template settings.json

View file

@ -25,5 +25,4 @@ if (process.argv.length !== 2) throw new Error('Use: node bin/checkAllPads.js');
console.log(`Pad ${padId}: OK`); console.log(`Pad ${padId}: OK`);
})); }));
console.log('Finished.'); console.log('Finished.');
process.exit(0)
})(); })();

View file

@ -11,19 +11,12 @@ process.on('unhandledRejection', (err) => { throw err; });
if (process.argv.length !== 3) throw new Error('Use: node bin/checkPad.js $PADID'); if (process.argv.length !== 3) throw new Error('Use: node bin/checkPad.js $PADID');
// @ts-ignore // @ts-ignore
const padId = process.argv[2]; const padId = process.argv[2];
(async () => {
const performCheck = async () => {
const db = require('ep_etherpad-lite/node/db/DB'); const db = require('ep_etherpad-lite/node/db/DB');
await db.init(); await db.init();
console.log("Checking if " + padId + " exists")
const padManager = require('ep_etherpad-lite/node/db/PadManager'); const padManager = require('ep_etherpad-lite/node/db/PadManager');
if (!await padManager.doesPadExists(padId)) throw new Error('Pad does not exist'); if (!await padManager.doesPadExists(padId)) throw new Error('Pad does not exist');
const pad = await padManager.getPad(padId); const pad = await padManager.getPad(padId);
await pad.check(); await pad.check();
console.log('Finished checking pad.'); console.log('Finished.');
process.exit(0) })();
}
performCheck()
.then(e=>console.log("Finished"))
.catch(e=>console.log("Finished with errors"))

View file

@ -14,7 +14,6 @@ import path from "node:path";
import querystring from "node:querystring"; import querystring from "node:querystring";
import axios from 'axios' import axios from 'axios'
import process from "node:process";
process.on('unhandledRejection', (err) => { throw err; }); process.on('unhandledRejection', (err) => { throw err; });
@ -54,5 +53,4 @@ const settings = require('ep_etherpad-lite/node/utils/Settings');
if (res.data.code === 1) throw new Error(`Error creating session: ${JSON.stringify(res.data)}`); if (res.data.code === 1) throw new Error(`Error creating session: ${JSON.stringify(res.data)}`);
console.log('Session made: ====> create a cookie named sessionID and set the value to', console.log('Session made: ====> create a cookie named sessionID and set the value to',
res.data.data.sessionID); res.data.data.sessionID);
process.exit(0)
})(); })();

View file

@ -49,5 +49,4 @@ const settings = require('ep_etherpad-lite/tests/container/loadSettings').loadSe
} }
} }
console.log(`Deleted ${deleteCount} sessions`); console.log(`Deleted ${deleteCount} sessions`);
process.exit(0)
})(); })();

View file

@ -38,5 +38,4 @@ const apikey = fs.readFileSync(filePath, {encoding: 'utf-8'});
const deleteAttempt = await axios.post(uri); const deleteAttempt = await axios.post(uri);
if (deleteAttempt.data.code === 1) throw new Error(`Error deleting pad ${deleteAttempt.data}`); if (deleteAttempt.data.code === 1) throw new Error(`Error deleting pad ${deleteAttempt.data}`);
console.log('Deleted pad', deleteAttempt.data); console.log('Deleted pad', deleteAttempt.data);
process.exit(0)
})(); })();

View file

@ -60,5 +60,4 @@ const padId = process.argv[2];
} }
console.log('finished'); console.log('finished');
process.exit(0)
})(); })();

View file

@ -1,39 +0,0 @@
import {readFileSync} from "node:fs";
const changelog = readFileSync('../changelog.md')
const changelogText = changelog.toString()
const changelogLines = changelogText.split('\n')
let cliArgs = process.argv.slice(2)
let tagVar = cliArgs[0]
if (!tagVar) {
console.error("No tag provided")
process.exit(1)
}
tagVar = tagVar.replace("refs/tags/v", "")
let startNum = -1
let endline = 0
let counter = 0
for (const line of changelogLines) {
if (line.trim().startsWith("#") && (line.match(new RegExp("#", "g"))||[]).length === 1) {
if (startNum !== -1) {
endline = counter-1
break
}
const sanitizedLine = line.replace("#","").trim()
if(sanitizedLine.includes(tagVar)) {
startNum = counter
}
}
counter++
}
let currentReleaseNotes = changelogLines.slice(startNum, endline).join('\n')
console.log(currentReleaseNotes)

View file

@ -6,8 +6,7 @@ import util from "node:util";
const fs = require('fs'); const fs = require('fs');
import log4js from 'log4js'; import log4js from 'log4js';
import readline from 'readline'; import readline from 'readline';
import {Database} from "ueberdb2"; import ueberDB from "ueberdb2";
import process from "node:process";
const settings = require('ep_etherpad-lite/node/utils/Settings'); const settings = require('ep_etherpad-lite/node/utils/Settings');
process.on('unhandledRejection', (err) => { throw err; }); process.on('unhandledRejection', (err) => { throw err; });
@ -57,7 +56,7 @@ const unescape = (val: string) => {
writeInterval: 100, writeInterval: 100,
json: false, // data is already json encoded json: false, // data is already json encoded
}; };
const db = new Database( // eslint-disable-line new-cap const db = new ueberDB.Database( // eslint-disable-line new-cap
settings.dbType, settings.dbType,
settings.dbSettings, settings.dbSettings,
dbWrapperSettings, dbWrapperSettings,
@ -97,8 +96,6 @@ const unescape = (val: string) => {
'depended on dbms this may take some time..\n'); 'depended on dbms this may take some time..\n');
const closeDB = util.promisify(db.close.bind(db)); const closeDB = util.promisify(db.close.bind(db));
// @ts-ignore
await closeDB(null); await closeDB(null);
log(`finished, imported ${keyNo} keys.`); log(`finished, imported ${keyNo} keys.`);
process.exit(0)
})(); })();

View file

@ -1,51 +0,0 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
trim() {
local var="$*"
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
printf '%s' "$var"
}
# Move to the Etherpad base directory.
MY_DIR=$(cd "${0%/*}" && pwd -P) || exit 1
cd "${MY_DIR}/.." || exit 1
# Source constants and useful functions
. bin/functions.sh
PNPM_OPTIONS=
if [ ! -z "${NODE_ENV-}" ]; then
if [ "$NODE_ENV" == 'production' ]; then
PNPM_OPTIONS='--prod'
fi
fi
if [ ! -z "${ETHERPAD_LOCAL_PLUGINS_ENV-}" ]; then
if [ "$ETHERPAD_LOCAL_PLUGINS_ENV" == 'production' ]; then
PNPM_OPTIONS='--prod'
elif [ "$ETHERPAD_LOCAL_PLUGINS_ENV" == 'development' ]; then
PNPM_OPTIONS='-D'
fi
fi
if [ ! -z "${ETHERPAD_LOCAL_PLUGINS}" ]; then
readarray -d ' ' plugins <<< "${ETHERPAD_LOCAL_PLUGINS}"
for plugin in "${plugins[@]}"; do
plugin=$(trim "$plugin")
if [ -d "local_plugins/${plugin}" ]; then
echo "Installing plugin: '${plugin}'"
pnpm install -w ${PNPM_OPTIONS:-} "local_plugins/${plugin}/"
else
( echo "Error. Directory 'local_plugins/${plugin}' for local plugin " \
"'${plugin}' missing" >&2 )
exit 1
fi
done
else
echo 'No local plugings to install.'
fi

View file

@ -1,63 +0,0 @@
import {exec} from 'child_process'
import fs from 'fs'
import path from 'path'
import pjson from '../src/package.json'
const VERSION=pjson.version
console.log(`Building docs for version ${VERSION}`)
const createDirIfNotExists = (dir: fs.PathLike) => {
if (!fs.existsSync(dir)){
fs.mkdirSync(dir)
}
}
function copyFolderSync(from: fs.PathLike, to: fs.PathLike) {
if(fs.existsSync(to)){
const stat = fs.lstatSync(to)
if (stat.isDirectory()){
fs.rmSync(to, { recursive: true })
}
else{
fs.rmSync(to)
}
}
fs.mkdirSync(to);
fs.readdirSync(from).forEach(element => {
if (fs.lstatSync(path.join(<string>from, element)).isFile()) {
if (typeof from === "string") {
if (typeof to === "string") {
fs.copyFileSync(path.join(from, element), path.join(to, element))
}
}
} else {
if (typeof from === "string") {
if (typeof to === "string") {
copyFolderSync(path.join(from, element), path.join(to, element))
}
}
}
});
}
exec('asciidoctor -v', (err,stdout)=>{
if (err){
console.log('Please install asciidoctor')
console.log('https://asciidoctor.org/docs/install-toolchain/')
process.exit(1)
}
});
createDirIfNotExists('../out')
createDirIfNotExists('../out/doc')
createDirIfNotExists('../out/doc/api')
exec(`asciidoctor -D ../out/doc ../doc/index.adoc ../*/**.adoc -a VERSION=${VERSION}`)
exec(`asciidoctor -D ../out/doc/api ../doc/api/*.adoc -a VERSION=${VERSION}`)
copyFolderSync('../doc/public/', '../out/doc/')

View file

@ -1,83 +0,0 @@
// DB migration
import {readFileSync} from 'node:fs'
import {Database, DatabaseType} from "ueberdb2";
import path from "node:path";
const settings = require('ep_etherpad-lite/node/utils/Settings');
// file1 = source, file2 = target
// pnpm run migrateDB --file1 <db1.json> --file2 <db2.json>
const arg = process.argv.slice(2);
if (arg.length != 4) {
console.error('Wrong number of arguments!. Call with pnpm run migrateDB --file1 source.json target.json')
process.exit(1)
}
type SettingsConfig = {
dbType: string,
dbSettings: any
}
/*
{
"dbType": "<your-db-type>",
"dbSettings": {
<your-db-settings>
}
}
*/
let firstDBSettingsFile: string
let secondDBSettingsFile: string
if (arg[0] == "--file1") {
firstDBSettingsFile = arg[1]
} else if (arg[0] === "--file2") {
secondDBSettingsFile = arg[1]
}
if (arg[2] == "--file1") {
firstDBSettingsFile = arg[3]
} else if (arg[2] === "--file2") {
secondDBSettingsFile = arg[3]
}
const settingsfile = JSON.parse(readFileSync(path.join(settings.root,firstDBSettingsFile!)).toString()) as SettingsConfig
const settingsfile2 = JSON.parse(readFileSync(path.join(settings.root,secondDBSettingsFile!)).toString()) as SettingsConfig
console.log(settingsfile2)
if ("filename" in settingsfile.dbSettings) {
settingsfile.dbSettings.filename = path.join(settings.root, settingsfile.dbSettings.filename)
console.log(settingsfile.dbType + " location is "+ settingsfile.dbSettings.filename)
}
if ("filename" in settingsfile2.dbSettings) {
settingsfile2.dbSettings.filename = path.join(settings.root, settingsfile2.dbSettings.filename)
console.log(settingsfile2.dbType + " location is "+ settingsfile2.dbSettings.filename)
}
const ueberdb1 = new Database(settingsfile.dbType as DatabaseType, settingsfile.dbSettings)
const ueberdb2 = new Database(settingsfile2.dbType as DatabaseType, settingsfile2.dbSettings)
const handleSync = async ()=>{
await ueberdb1.init()
await ueberdb2.init()
const allKeys = await ueberdb1.findKeys('*','')
for (const key of allKeys) {
const foundVal = await ueberdb1.get(key)!
await ueberdb2.set(key, foundVal)
}
}
handleSync().then(()=>{
console.log("Done syncing dbs")
}).catch(e=>{
console.log(`Error syncing db ${e}`)
})

View file

@ -1,7 +1,7 @@
'use strict'; 'use strict';
import process from 'node:process'; import process from 'node:process';
import {Database} from "ueberdb2"; import ueberDB from "ueberdb2";
import log4js from 'log4js'; import log4js from 'log4js';
import util from 'util'; import util from 'util';
const settings = require('ep_etherpad-lite/node/utils/Settings'); const settings = require('ep_etherpad-lite/node/utils/Settings');
@ -23,7 +23,7 @@ process.on('unhandledRejection', (err) => { throw err; });
cache: '0', // The cache slows things down when you're mostly writing. cache: '0', // The cache slows things down when you're mostly writing.
writeInterval: 0, // Write directly to the database, don't buffer writeInterval: 0, // Write directly to the database, don't buffer
}; };
const db = new Database( // eslint-disable-line new-cap const db = new ueberDB.Database( // eslint-disable-line new-cap
settings.dbType, settings.dbType,
settings.dbSettings, settings.dbSettings,
dbWrapperSettings, dbWrapperSettings,
@ -31,7 +31,7 @@ process.on('unhandledRejection', (err) => { throw err; });
await db.init(); await db.init();
console.log('Waiting for dirtyDB to parse its file.'); console.log('Waiting for dirtyDB to parse its file.');
const dirty = new Database('dirty', `${__dirname}/../var/dirty.db`); const dirty = await new ueberDB.Database('dirty',`${__dirname}/../var/dirty.db`);
await dirty.init(); await dirty.init();
const keys = await dirty.findKeys('*', '') const keys = await dirty.findKeys('*', '')
@ -57,5 +57,4 @@ process.on('unhandledRejection', (err) => { throw err; });
await db.close(null); await db.close(null);
await dirty.close(null); await dirty.close(null);
console.log('Finished.'); console.log('Finished.');
process.exit(0)
})(); })();

View file

@ -1,26 +1,25 @@
{ {
"name": "bin", "name": "bin",
"version": "2.3.0", "version": "2.1.0",
"description": "", "description": "",
"main": "checkAllPads.js", "main": "checkAllPads.js",
"directories": { "directories": {
"doc": "doc" "doc": "doc"
}, },
"dependencies": { "dependencies": {
"axios": "^1.8.4", "axios": "^1.7.2",
"ep_etherpad-lite": "workspace:../src", "ep_etherpad-lite": "workspace:../src",
"log4js": "^6.9.1", "log4js": "^6.9.1",
"semver": "^7.7.2", "semver": "^7.6.2",
"tsx": "^4.20.3", "tsx": "^4.10.5",
"ueberdb2": "^5.0.14" "ueberdb2": "^4.2.63"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^24.0.1", "@types/node": "^20.12.13",
"@types/semver": "^7.7.0", "@types/semver": "^7.5.8",
"typescript": "^5.8.2" "typescript": "^5.4.5"
}, },
"scripts": { "scripts": {
"makeDocs": "node --import tsx make_docs.ts",
"checkPad": "node --import tsx checkPad.ts", "checkPad": "node --import tsx checkPad.ts",
"checkAllPads": "node --import tsx checkAllPads.ts", "checkAllPads": "node --import tsx checkAllPads.ts",
"createUserSession": "node --import tsx createUserSession.ts", "createUserSession": "node --import tsx createUserSession.ts",
@ -33,9 +32,7 @@
"rebuildPad": "node --import tsx rebuildPad.ts", "rebuildPad": "node --import tsx rebuildPad.ts",
"stalePlugins": "node --import tsx ./plugins/stalePlugins.ts", "stalePlugins": "node --import tsx ./plugins/stalePlugins.ts",
"checkPlugin": "node --import tsx ./plugins/checkPlugin.ts", "checkPlugin": "node --import tsx ./plugins/checkPlugin.ts",
"plugins": "node --import tsx ./plugins.ts", "plugins": "node --import tsx ./plugins.ts"
"generateChangelog": "node --import tsx generateReleaseNotes.ts",
"migrateDB": "node --import tsx migrateDB.ts"
}, },
"author": "", "author": "",
"license": "ISC" "license": "ISC"

View file

@ -23,13 +23,17 @@ const possibleActions = [
] ]
const install = ()=> { const install = ()=> {
const argsAsString: string = args.join(" ");
const regexRegistryPlugins = /(?<=i\s)(.*?)(?=--github|--path|$)/; let registryPlugins: string[] = [];
const regexLocalPlugins = /(?<=--path\s)(.*?)(?=--github|$)/; let localPlugins: string[] = [];
const regexGithubPlugins = /(?<=--github\s)(.*?)(?=--path|$)/;
const registryPlugins = argsAsString.match(regexRegistryPlugins)?.[0]?.split(" ")?.filter(s => s) || []; if (args.indexOf('--path') !== -1) {
const localPlugins = argsAsString.match(regexLocalPlugins)?.[0]?.split(" ")?.filter(s => s) || []; const indexToSplit = args.indexOf('--path');
const githubPlugins = argsAsString.match(regexGithubPlugins)?.[0]?.split(" ")?.filter(s => s) || []; registryPlugins = args.slice(1, indexToSplit);
localPlugins = args.slice(indexToSplit + 1);
} else {
registryPlugins = args;
}
async function run() { async function run() {
for (const plugin of registryPlugins) { for (const plugin of registryPlugins) {
@ -49,11 +53,6 @@ const install = ()=> {
console.log(`Installing plugin from path: ${plugin}`); console.log(`Installing plugin from path: ${plugin}`);
await linkInstaller.installFromPath(plugin); await linkInstaller.installFromPath(plugin);
} }
for (const plugin of githubPlugins) {
console.log(`Installing plugin from github: ${plugin}`);
await linkInstaller.installFromGitHub(plugin);
}
} }
(async () => { (async () => {

View file

@ -474,6 +474,6 @@ log4js.configure({
logger.info('No changes.'); logger.info('No changes.');
} }
} }
logger.info('Finished'); logger.info('Finished');
process.exit(0)
})(); })();

View file

@ -78,7 +78,7 @@ jobs:
- name: Run the frontend tests - name: Run the frontend tests
shell: bash shell: bash
run: | run: |
pnpm run prod & pnpm run dev &
connected=false connected=false
can_connect() { can_connect() {
curl -sSfo /dev/null http://localhost:9001/ || return 1 curl -sSfo /dev/null http://localhost:9001/ || return 1

View file

@ -3,7 +3,6 @@
// Returns a list of stale plugins and their authors email // Returns a list of stale plugins and their authors email
import axios from 'axios' import axios from 'axios'
import process from "node:process";
const currentTime = new Date(); const currentTime = new Date();
(async () => { (async () => {
@ -20,5 +19,4 @@ const currentTime = new Date();
console.log(`${name}, ${res.data[plugin].data.maintainers[0].email}`); console.log(`${name}, ${res.data[plugin].data.maintainers[0].email}`);
} }
} }
process.exit(0)
})(); })();

View file

@ -7,8 +7,6 @@
// As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an // As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an
// unhandled rejection into an uncaught exception, which does cause Node.js to exit. // unhandled rejection into an uncaught exception, which does cause Node.js to exit.
import process from "node:process";
process.on('unhandledRejection', (err) => { throw err; }); process.on('unhandledRejection', (err) => { throw err; });
if (process.argv.length !== 4 && process.argv.length !== 5) { if (process.argv.length !== 4 && process.argv.length !== 5) {
@ -84,5 +82,4 @@ const newPadId = process.argv[4] || `${padId}-rebuilt`;
await db.shutdown(); await db.shutdown();
console.info('finished'); console.info('finished');
process.exit(0)
})(); })();

View file

@ -197,7 +197,7 @@ try {
try { try {
console.log('Building documentation...'); console.log('Building documentation...');
run('pnpm run makeDocs'); run('node ./make_docs.js');
console.log('Updating ether.github.com master branch...'); console.log('Updating ether.github.com master branch...');
run('git pull --ff-only', {cwd: '../ether.github.com/'}); run('git pull --ff-only', {cwd: '../ether.github.com/'});
console.log('Committing documentation...'); console.log('Committing documentation...');

View file

@ -57,5 +57,4 @@ let valueCount = 0;
} }
console.info(`Finished: Replaced ${valueCount} values in the database`); console.info(`Finished: Replaced ${valueCount} values in the database`);
process.exit(0)
})(); })();

View file

@ -45,4 +45,4 @@ fi
log "Starting Etherpad..." log "Starting Etherpad..."
# cd src # cd src
exec pnpm run prod "$@" exec pnpm run dev "$@"

View file

@ -39,7 +39,7 @@
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
"resolveJsonModule": true, /* Enable importing .json files. */ // "resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */ // "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */

View file

@ -32,7 +32,6 @@ export default defineConfig({
{ text: 'Stats', link: '/stats.md' }, { text: 'Stats', link: '/stats.md' },
{text: 'Skins', link: '/skins.md' }, {text: 'Skins', link: '/skins.md' },
{text: 'Demo', link: '/demo.md' }, {text: 'Demo', link: '/demo.md' },
{text: 'CLI', link: '/cli.md'},
] ]
}, },
{ {

View file

@ -1,7 +1,7 @@
# Changeset Library # Changeset Library
The [changeset The [changeset
library](https://github.com/ether/etherpad-lite/blob/develop/src/static/js/Changeset.ts) library](https://github.com/ether/etherpad-lite/blob/develop/src/static/js/Changeset.js)
provides tools to create, read, and apply changesets. provides tools to create, read, and apply changesets.
## Changeset ## Changeset

View file

@ -1,29 +0,0 @@
# CLI
You can find different tools for migrating things, checking your Etherpad health in the bin directory.
One of these is the migrateDB command. It takes two settings.json files and copies data from one source to another one.
In this example we migrate from the old dirty db to the new rustydb engine. So we copy these files to the root of the etherpad-directory.
````json
{
"dbType": "dirty",
"dbSettings": {
"filename": "./var/rusty.db"
}
}
````
````json
{
"dbType": "rustydb",
"dbSettings": {
"filename": "./var/rusty2.db"
}
}
````
After that we need to move the data from dirty to rustydb.
Therefore, we call `pnpm run migrateDB --file1 test1.json --file2 test2.json` with these two files in our root directories. After some time the data should be copied over to the new database.

View file

@ -1,6 +1,6 @@
{ {
"devDependencies": { "devDependencies": {
"vitepress": "^1.6.3" "vitepress": "^1.2.2"
}, },
"scripts": { "scripts": {
"docs:dev": "vitepress dev", "docs:dev": "vitepress dev",

View file

@ -9,7 +9,6 @@ services:
build: build:
context: . context: .
args: args:
# Attention: installed plugins in the node_modules folder get overwritten during volume mount in dev
ETHERPAD_PLUGINS: ETHERPAD_PLUGINS:
# change from development to production if needed # change from development to production if needed
target: development target: development
@ -58,7 +57,7 @@ services:
# ports: # ports:
# - "5432:5432" # - "5432:5432"
volumes: volumes:
- postgres_data:/var/lib/postgresql/data - postgres_data:/var/lib/postgresql/data/pgdata
volumes: volumes:
postgres_data: postgres_data:

View file

@ -42,7 +42,7 @@ services:
# ports: # ports:
# - "5432:5432" # - "5432:5432"
volumes: volumes:
- postgres_data:/var/lib/postgresql/data - postgres_data:/var/lib/postgresql/data/pgdata
volumes: volumes:
postgres_data: postgres_data:

View file

@ -1,3 +0,0 @@
# ignore everything
*
!.gitignore

55
make_docs.js Normal file
View file

@ -0,0 +1,55 @@
import {exec} from 'child_process'
import fs from 'fs'
import path from 'path'
import pjson from './src/package.json' assert {type: "json"}
const VERSION=pjson.version
console.log(`Building docs for version ${VERSION}`)
const createDirIfNotExists = (dir) => {
if (!fs.existsSync(dir)){
fs.mkdirSync(dir)
}
}
function copyFolderSync(from, to) {
if(fs.existsSync(to)){
const stat = fs.lstatSync(to)
if (stat.isDirectory()){
fs.rmSync(to, { recursive: true })
}
else{
fs.rmSync(to)
}
}
fs.mkdirSync(to);
fs.readdirSync(from).forEach(element => {
if (fs.lstatSync(path.join(from, element)).isFile()) {
fs.copyFileSync(path.join(from, element), path.join(to, element))
} else {
copyFolderSync(path.join(from, element), path.join(to, element))
}
});
}
exec('asciidoctor -v', (err,stdout)=>{
if (err){
console.log('Please install asciidoctor')
console.log('https://asciidoctor.org/docs/install-toolchain/')
process.exit(1)
}
});
createDirIfNotExists('./out')
createDirIfNotExists('./out/doc')
createDirIfNotExists('./out/doc/api')
exec(`asciidoctor -D out/doc doc/index.adoc */**.adoc -a VERSION=${VERSION}`)
exec(`asciidoctor -D out/doc/api ./doc/api/*.adoc -a VERSION=${VERSION}`)
copyFolderSync('./doc/public/', './out/doc/')

View file

@ -15,7 +15,6 @@
"scripts": { "scripts": {
"lint": "pnpm --filter ep_etherpad-lite run lint", "lint": "pnpm --filter ep_etherpad-lite run lint",
"test": "pnpm --filter ep_etherpad-lite run test", "test": "pnpm --filter ep_etherpad-lite run test",
"test-utils": "pnpm --filter ep_etherpad-lite run test-utils",
"test-container": "pnpm --filter ep_etherpad-lite run test-container", "test-container": "pnpm --filter ep_etherpad-lite run test-container",
"dev": "pnpm --filter ep_etherpad-lite run dev", "dev": "pnpm --filter ep_etherpad-lite run dev",
"prod": "pnpm --filter ep_etherpad-lite run prod", "prod": "pnpm --filter ep_etherpad-lite run prod",
@ -28,10 +27,7 @@
"plugins": "pnpm --filter bin run plugins", "plugins": "pnpm --filter bin run plugins",
"install-plugins": "pnpm --filter bin run plugins i", "install-plugins": "pnpm --filter bin run plugins i",
"remove-plugins": "pnpm --filter bin run remove-plugins", "remove-plugins": "pnpm --filter bin run remove-plugins",
"list-plugins": "pnpm --filter bin run list-plugins", "list-plugins": "pnpm --filter bin run list-plugins"
"build:etherpad": "pnpm --filter admin run build-copy && pnpm --filter ui run build-copy",
"build:ui": "pnpm --filter ui run build-copy && pnpm --filter admin run build-copy",
"makeDocs": "pnpm --filter bin run makeDocs"
}, },
"dependencies": { "dependencies": {
"ep_etherpad-lite": "workspace:./src" "ep_etherpad-lite": "workspace:./src"
@ -50,6 +46,6 @@
"type": "git", "type": "git",
"url": "https://github.com/ether/etherpad-lite.git" "url": "https://github.com/ether/etherpad-lite.git"
}, },
"version": "2.3.0", "version": "2.1.0",
"license": "Apache-2.0" "license": "Apache-2.0"
} }

8146
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,3 @@ packages:
- bin - bin
- doc - doc
- ui - ui
onlyBuiltDependencies:
- '@scarf/scarf'
- '@swc/core'
- esbuild

View file

@ -96,7 +96,7 @@
* 3) if you want to use newlines in the default value of a string parameter, * 3) if you want to use newlines in the default value of a string parameter,
* use "\n" as usual. * use "\n" as usual.
* *
* "defaultPadText" : "${DEFAULT_PAD_TEXT:Line 1\nLine 2}" * "defaultPadText" : "${DEFAULT_PAD_TEXT}Line 1\nLine 2"
*/ */
{ {
/* /*
@ -171,14 +171,6 @@
*/ */
"showSettingsInAdminPage": "${SHOW_SETTINGS_IN_ADMIN_PAGE:true}", "showSettingsInAdminPage": "${SHOW_SETTINGS_IN_ADMIN_PAGE:true}",
/*
* Settings for cleanup of pads
*/
"cleanup": {
"enabled": false,
"keepRevisions": 5
},
/* /*
The authentication method used by the server. The authentication method used by the server.
The default value is sso The default value is sso
@ -202,15 +194,6 @@
}, },
*/ */
/*
* Enables the use of a different server. We have a different one that syncs changes from the original server.
* It is hosted on GitHub and should not be blocked by many firewalls.
* https://etherpad.org/ep_infos
*/
"updateServer": "https://etherpad.org/ep_infos",
/* /*
* The type of the database. * The type of the database.
* *

View file

@ -87,7 +87,7 @@
* 3) if you want to use newlines in the default value of a string parameter, * 3) if you want to use newlines in the default value of a string parameter,
* use "\n" as usual. * use "\n" as usual.
* *
* "defaultPadText" : "${DEFAULT_PAD_TEXT:Line 1\nLine 2}" * "defaultPadText" : "${DEFAULT_PAD_TEXT}Line 1\nLine 2"
*/ */
{ {
/* /*
@ -162,14 +162,6 @@
*/ */
"showSettingsInAdminPage": true, "showSettingsInAdminPage": true,
/*
* Settings for cleanup of pads
*/
"cleanup": {
"enabled": false,
"keepRevisions": 5
},
/* /*
* Node native SSL support * Node native SSL support
* *
@ -279,14 +271,6 @@
"pageDown": true "pageDown": true
}, },
/*
* Enables the use of a different server. We have a different one that syncs changes from the original server.
* It is hosted on GitHub and should not be blocked by many firewalls.
* https://etherpad.org/ep_infos
*/
"updateServer": "https://etherpad.org/ep_infos",
/* /*
* Should we suppress errors from being visible in the default Pad Text? * Should we suppress errors from being visible in the default Pad Text?
*/ */
@ -664,13 +648,6 @@
*/ */
"loglevel": "INFO", "loglevel": "INFO",
/*
* The log layout type to use.
*
* Valid values: basic, colored
*/
"logLayoutType": "colored",
/* Override any strings found in locale directories */ /* Override any strings found in locale directories */
"customLocaleStrings": {}, "customLocaleStrings": {},

View file

@ -42,8 +42,7 @@
"name": "specialpages", "name": "specialpages",
"hooks": { "hooks": {
"expressCreateServer": "ep_etherpad-lite/node/hooks/express/specialpages", "expressCreateServer": "ep_etherpad-lite/node/hooks/express/specialpages",
"expressPreSession": "ep_etherpad-lite/node/hooks/express/specialpages", "expressPreSession": "ep_etherpad-lite/node/hooks/express/specialpages"
"socketio": "ep_etherpad-lite/node/hooks/express/specialpages"
} }
}, },
{ {
@ -82,12 +81,6 @@
"expressCreateServer": "ep_etherpad-lite/node/hooks/express/errorhandling" "expressCreateServer": "ep_etherpad-lite/node/hooks/express/errorhandling"
} }
}, },
{
"name": "restApi",
"hooks": {
"expressCreateServer": "ep_etherpad-lite/node/handler/RestAPI"
}
},
{ {
"name": "socketio", "name": "socketio",
"hooks": { "hooks": {

View file

@ -16,18 +16,10 @@
] ]
}, },
"admin.page-title": "لوحة تحكم المسؤول - Etherpad", "admin.page-title": "لوحة تحكم المسؤول - Etherpad",
"admin_plugins": "مدير المكونات الإضافية",
"admin_plugins.available": "المكونات الإضافية المتاحة",
"admin_plugins.available_not-found": "لم يتم العثور على أي مكونات إضافية.",
"admin_plugins.available_fetching": "جاري الجلب…",
"admin_plugins.available_install.value": "تنصيب",
"admin_plugins.available_search.placeholder": "ابحث عن المكونات الإضافية للتثبيت",
"admin_plugins.description": "الوصف", "admin_plugins.description": "الوصف",
"admin_plugins.installed": "الإضافات المثبتة", "admin_plugins.installed": "الإضافات المثبتة",
"admin_plugins.installed_fetching": "جارٍ إحضار المكونات الإضافية المثبتة ...", "admin_plugins.installed_fetching": "جارٍ إحضار المكونات الإضافية المثبتة ...",
"admin_plugins.installed_nothing": "لم تقم بتثبيت أي مكونات إضافية حتى الآن.", "admin_plugins.installed_nothing": "لم تقم بتثبيت أي مكونات إضافية حتى الآن.",
"admin_plugins.installed_uninstall.value": "إلغاء التثبيت",
"admin_plugins.last-update": "آخر تحديث",
"admin_plugins.name": "الاسم", "admin_plugins.name": "الاسم",
"admin_plugins.page-title": "مدير البرنامج المساعد - Etherpad", "admin_plugins.page-title": "مدير البرنامج المساعد - Etherpad",
"admin_plugins.version": "الإصدار", "admin_plugins.version": "الإصدار",
@ -39,10 +31,8 @@
"admin_plugins_info.plugins": "الإضافات المثبتة", "admin_plugins_info.plugins": "الإضافات المثبتة",
"admin_plugins_info.page-title": "معلومات البرنامج المساعد - Etherpad", "admin_plugins_info.page-title": "معلومات البرنامج المساعد - Etherpad",
"admin_plugins_info.version": "إصدار Etherpad", "admin_plugins_info.version": "إصدار Etherpad",
"admin_plugins_info.version_latest": "أحدث إصدار متاح",
"admin_plugins_info.version_number": "رقم الإصدار", "admin_plugins_info.version_number": "رقم الإصدار",
"admin_settings": "إعدادات", "admin_settings": "إعدادات",
"admin_settings.current": "التكوين الحالي",
"admin_settings.current_example-devel": "مثال على قالب إعدادات التطوير", "admin_settings.current_example-devel": "مثال على قالب إعدادات التطوير",
"admin_settings.current_example-prod": "مثال على قالب إعدادات الإنتاج", "admin_settings.current_example-prod": "مثال على قالب إعدادات الإنتاج",
"admin_settings.current_restart.value": "أعد تشغيل Etherpad", "admin_settings.current_restart.value": "أعد تشغيل Etherpad",
@ -83,8 +73,6 @@
"pad.settings.fontType": "نوع الخط:", "pad.settings.fontType": "نوع الخط:",
"pad.settings.fontType.normal": "عادي", "pad.settings.fontType.normal": "عادي",
"pad.settings.language": "اللغة:", "pad.settings.language": "اللغة:",
"pad.settings.deletePad": "حذف الوسادة",
"pad.delete.confirm": "هل تريد حقا حذف هذه الوسادة؟",
"pad.settings.about": "حول", "pad.settings.about": "حول",
"pad.settings.poweredBy": "مدعوم من", "pad.settings.poweredBy": "مدعوم من",
"pad.importExport.import_export": "استيراد/تصدير", "pad.importExport.import_export": "استيراد/تصدير",
@ -122,8 +110,6 @@
"pad.modals.deleted": "محذوف.", "pad.modals.deleted": "محذوف.",
"pad.modals.deleted.explanation": "تمت إزالة هذا الباد.", "pad.modals.deleted.explanation": "تمت إزالة هذا الباد.",
"pad.modals.rateLimited": "معدل محدود.", "pad.modals.rateLimited": "معدل محدود.",
"pad.modals.rateLimited.explanation": "لقد أرسلت الكثير من الرسائل إلى هذه اللوحة مما أدى إلى قطع الاتصال بك.",
"pad.modals.rejected.explanation": "رفض الخادم الرسالة التي أرسلها متصفحك.",
"pad.modals.rejected.cause": "ربما تم تحديث الخادم أثناء عرض اللوحة ، أو ربما كان هناك خطأ في Etherpad. حاول إعادة تحميل الصفحة.", "pad.modals.rejected.cause": "ربما تم تحديث الخادم أثناء عرض اللوحة ، أو ربما كان هناك خطأ في Etherpad. حاول إعادة تحميل الصفحة.",
"pad.modals.disconnected": "لم تعد متصلا.", "pad.modals.disconnected": "لم تعد متصلا.",
"pad.modals.disconnected.explanation": "تم فقدان الاتصال بالخادم", "pad.modals.disconnected.explanation": "تم فقدان الاتصال بالخادم",

View file

@ -35,10 +35,6 @@
"admin_plugins_info.version_number": "Нумар вэрсіі", "admin_plugins_info.version_number": "Нумар вэрсіі",
"admin_settings": "Налады", "admin_settings": "Налады",
"admin_settings.current": "Цяперашняя канфігурацыя", "admin_settings.current": "Цяперашняя канфігурацыя",
"admin_settings.current_example-devel": "Прыклад шаблёну наладаў распрацоўкі",
"admin_settings.current_example-prod": "Прыклад шаблёну наладаў вытворчасьці",
"admin_settings.current_restart.value": "Перазапуск Etherpad",
"admin_settings.current_save.value": "Захаваць налады",
"admin_settings.page-title": "Налады — Etherpad", "admin_settings.page-title": "Налады — Etherpad",
"index.newPad": "Стварыць", "index.newPad": "Стварыць",
"index.createOpenPad": "ці тварыць/адкрыць дакумэнт з назвай:", "index.createOpenPad": "ці тварыць/адкрыць дакумэнт з назвай:",
@ -76,7 +72,6 @@
"pad.settings.fontType.normal": "Звычайны", "pad.settings.fontType.normal": "Звычайны",
"pad.settings.language": "Мова:", "pad.settings.language": "Мова:",
"pad.settings.about": "Пра", "pad.settings.about": "Пра",
"pad.settings.poweredBy": "Працуе на",
"pad.importExport.import_export": "Імпарт/Экспарт", "pad.importExport.import_export": "Імпарт/Экспарт",
"pad.importExport.import": "Загрузіжайце любыя тэкставыя файлы або дакумэнты", "pad.importExport.import": "Загрузіжайце любыя тэкставыя файлы або дакумэнты",
"pad.importExport.importSuccessful": "Пасьпяхова!", "pad.importExport.importSuccessful": "Пасьпяхова!",
@ -111,9 +106,6 @@
"pad.modals.corruptPad.cause": "Гэта можа быць выклікана няправільнай канфігурацыяй сэрвэру або іншымі нечаканымі дзеяньнямі. Калі ласка, скантактуйцеся з адміністратарам службы.", "pad.modals.corruptPad.cause": "Гэта можа быць выклікана няправільнай канфігурацыяй сэрвэру або іншымі нечаканымі дзеяньнямі. Калі ласка, скантактуйцеся з адміністратарам службы.",
"pad.modals.deleted": "Выдалены.", "pad.modals.deleted": "Выдалены.",
"pad.modals.deleted.explanation": "Гэты дакумэнт быў выдалены.", "pad.modals.deleted.explanation": "Гэты дакумэнт быў выдалены.",
"pad.modals.rateLimited": "Хуткасьць абмежаваная.",
"pad.modals.rateLimited.explanation": "Вы адаслалі так шмат паведамленьняў, што гэты дакумэнт вас адключыў.",
"pad.modals.rejected.explanation": "Сэрвэр адхіліў паведамленьне, адасланае вашым броўзэрам.",
"pad.modals.disconnected": "Вы былі адключаныя.", "pad.modals.disconnected": "Вы былі адключаныя.",
"pad.modals.disconnected.explanation": "Злучэньне з сэрвэрам было страчанае", "pad.modals.disconnected.explanation": "Злучэньне з сэрвэрам было страчанае",
"pad.modals.disconnected.cause": "Магчыма, сэрвэр недаступны. Калі ласка, паведаміце адміністратару службы, калі праблема будзе паўтарацца.", "pad.modals.disconnected.cause": "Магчыма, сэрвэр недаступны. Калі ласка, паведаміце адміністратару службы, калі праблема будзе паўтарацца.",

View file

@ -1,49 +0,0 @@
{
"@metadata": {
"authors": [
"Умар"
]
},
"admin.page-title": "Администраторан панель — Etherpad",
"admin_plugins": "Плагинийн менеджер",
"admin_plugins.available": "ТӀекхочуш йолу плагинаш",
"admin_plugins.available_not-found": "Плагинаш ца карийна.",
"admin_plugins.available_fetching": "Схьаоьцуш...",
"admin_plugins.available_install.value": "ДӀахӀоттайе",
"admin_plugins.installed_uninstall.value": "ДӀайаккха",
"admin_plugins.last-update": "ТӀаьххьара карлайаккхар",
"admin_plugins.name": "ЦӀе",
"admin_plugins.page-title": "Плагинийн менеджер — Etherpad",
"admin_plugins.version": "Верси",
"admin_plugins_info.version_number": "Версин лоьмар",
"admin_settings": "Нисдаран гӀирс",
"admin_settings.current": "Карара конфигураци",
"pad.colorpicker.save": "Ӏалашйан",
"pad.colorpicker.cancel": "Йухайаккхар",
"pad.loading": "Чуйолуш…",
"pad.permissionDenied": "Хьан бакъонаш йац тӀекхача",
"pad.settings.padSettings": "Документан нисдаран гӀирс",
"pad.settings.myView": "Сан васт",
"pad.settings.stickychat": "Гуттара а гайта чат",
"pad.settings.language": "Мотт:",
"pad.settings.about": "Проектах лаьцна",
"pad.importExport.importSuccessful": "Кхиамца!",
"pad.modals.cancel": "Йухайаккхар",
"pad.share.link": "Хьажорг",
"pad.chat": "Чат",
"timeslider.toolbar.authors": "Авторш:",
"timeslider.toolbar.exportlink.title": "Экспорт",
"timeslider.month.january": "январь",
"timeslider.month.february": "февраль",
"timeslider.month.march": "март",
"timeslider.month.april": "апрель",
"timeslider.month.may": "май",
"timeslider.month.june": "июнь",
"timeslider.month.july": "июль",
"timeslider.month.august": "август",
"timeslider.month.september": "сентябрь",
"timeslider.month.october": "октябрь",
"timeslider.month.november": "ноябрь",
"timeslider.month.december": "декабрь",
"pad.impexp.importing": "Импорт йар..."
}

View file

@ -11,8 +11,7 @@
"Mormegil", "Mormegil",
"Peldrjan", "Peldrjan",
"Quinn", "Quinn",
"Spotter", "Spotter"
"The astrea"
] ]
}, },
"admin.page-title": "Ovládací panel Správce - Etherpad", "admin.page-title": "Ovládací panel Správce - Etherpad",
@ -83,8 +82,6 @@
"pad.settings.fontType": "Typ písma:", "pad.settings.fontType": "Typ písma:",
"pad.settings.fontType.normal": "Normální", "pad.settings.fontType.normal": "Normální",
"pad.settings.language": "Jazyk:", "pad.settings.language": "Jazyk:",
"pad.settings.deletePad": "Smazat pad",
"pad.delete.confirm": "Opravdu chcete tento pad smazat?",
"pad.settings.about": "O projektu", "pad.settings.about": "O projektu",
"pad.settings.poweredBy": "Běží na", "pad.settings.poweredBy": "Běží na",
"pad.importExport.import_export": "Import/Export", "pad.importExport.import_export": "Import/Export",

View file

@ -11,7 +11,6 @@
"Predatorix", "Predatorix",
"SamTV", "SamTV",
"Sebastian Wallroth", "Sebastian Wallroth",
"Ssgl",
"Thargon", "Thargon",
"Tim.krieger", "Tim.krieger",
"Wikinaut", "Wikinaut",
@ -86,8 +85,6 @@
"pad.settings.fontType": "Schriftart:", "pad.settings.fontType": "Schriftart:",
"pad.settings.fontType.normal": "Normal", "pad.settings.fontType.normal": "Normal",
"pad.settings.language": "Sprache:", "pad.settings.language": "Sprache:",
"pad.settings.deletePad": "Pad löschen",
"pad.delete.confirm": "Möchtest du dieses Pad wirklich löschen?",
"pad.settings.about": "Über", "pad.settings.about": "Über",
"pad.settings.poweredBy": "Betrieben von", "pad.settings.poweredBy": "Betrieben von",
"pad.importExport.import_export": "Import/Export", "pad.importExport.import_export": "Import/Export",

View file

@ -3,7 +3,6 @@
"authors": [ "authors": [
"1917 Ekim Devrimi", "1917 Ekim Devrimi",
"Erdemaslancan", "Erdemaslancan",
"GolyatGeri",
"Gorizon", "Gorizon",
"Gırd", "Gırd",
"Kumkumuk", "Kumkumuk",
@ -79,8 +78,6 @@
"pad.settings.fontType": "Babeta nuşti:", "pad.settings.fontType": "Babeta nuşti:",
"pad.settings.fontType.normal": "Normal", "pad.settings.fontType.normal": "Normal",
"pad.settings.language": "Zıwan:", "pad.settings.language": "Zıwan:",
"pad.settings.deletePad": "Defteri bıesterê",
"pad.delete.confirm": ıma raşti wazenê ke nê defteri bıesterên?",
"pad.settings.about": "Heqa", "pad.settings.about": "Heqa",
"pad.settings.poweredBy": "Pheştidayoğ", "pad.settings.poweredBy": "Pheştidayoğ",
"pad.importExport.import_export": "Zerredayış/Teberdayış", "pad.importExport.import_export": "Zerredayış/Teberdayış",

View file

@ -72,8 +72,6 @@
"pad.settings.fontType": "Pismowa družyna:", "pad.settings.fontType": "Pismowa družyna:",
"pad.settings.fontType.normal": "Normalny", "pad.settings.fontType.normal": "Normalny",
"pad.settings.language": "Rěc:", "pad.settings.language": "Rěc:",
"pad.settings.deletePad": "Zapisnik lašowaś",
"pad.delete.confirm": "Cośo napšawdu toś ten zapisnik lašowaś?",
"pad.settings.about": "Wó", "pad.settings.about": "Wó",
"pad.settings.poweredBy": "Pódpěrany wót", "pad.settings.poweredBy": "Pódpěrany wót",
"pad.importExport.import_export": "Import/Eksport", "pad.importExport.import_export": "Import/Eksport",

View file

@ -14,12 +14,10 @@
"admin_plugins": "Διαχειριστής πρόσθετων", "admin_plugins": "Διαχειριστής πρόσθετων",
"admin_plugins.available": "Διαθέσιμα πρόσθετα", "admin_plugins.available": "Διαθέσιμα πρόσθετα",
"admin_plugins.available_not-found": "Δεν βρέθηκαν πρόσθετα.", "admin_plugins.available_not-found": "Δεν βρέθηκαν πρόσθετα.",
"admin_plugins.available_fetching": "Ανακτάται...",
"admin_plugins.available_install.value": "Εγκατάσταση", "admin_plugins.available_install.value": "Εγκατάσταση",
"admin_plugins.available_search.placeholder": "Αναζητήστε πρόσθετα για εγκατάσταση", "admin_plugins.available_search.placeholder": "Αναζητήστε πρόσθετα για εγκατάσταση",
"admin_plugins.description": "Περιγραφή", "admin_plugins.description": "Περιγραφή",
"admin_plugins.installed": "Εγκατεστημένα πρόσθετα", "admin_plugins.installed": "Εγκατεστημένα πρόσθετα",
"admin_plugins.installed_fetching": "Ανάκτηση εγκατεστημένων προσθηκών…",
"admin_plugins.installed_nothing": "Δεν έχετε εγκαταστήσει πρόσθετα ακόμη.", "admin_plugins.installed_nothing": "Δεν έχετε εγκαταστήσει πρόσθετα ακόμη.",
"admin_plugins.installed_uninstall.value": "Απεγκατάσταση", "admin_plugins.installed_uninstall.value": "Απεγκατάσταση",
"admin_plugins.last-update": "Τελευταία ενημέρωση", "admin_plugins.last-update": "Τελευταία ενημέρωση",
@ -77,8 +75,6 @@
"pad.settings.fontType": "Τύπος γραμματοσειράς:", "pad.settings.fontType": "Τύπος γραμματοσειράς:",
"pad.settings.fontType.normal": "Κανονική", "pad.settings.fontType.normal": "Κανονική",
"pad.settings.language": "Γλώσσα:", "pad.settings.language": "Γλώσσα:",
"pad.settings.deletePad": "Διαγραφή Pad",
"pad.delete.confirm": "Θέλετε πραγματικά να διαγράψετε αυτό το pad;",
"pad.settings.about": "Σχετικά", "pad.settings.about": "Σχετικά",
"pad.settings.poweredBy": "Υποστηρίζεται από", "pad.settings.poweredBy": "Υποστηρίζεται από",
"pad.importExport.import_export": "Εισαγωγή/Εξαγωγή", "pad.importExport.import_export": "Εισαγωγή/Εξαγωγή",
@ -93,7 +89,7 @@
"pad.importExport.exportopen": "ODF (Open Document Format)", "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.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.connected": "Συνδεμένοι.",
"pad.modals.reconnecting": "Επανασύνδεση στο pad σας", "pad.modals.reconnecting": "Επανασύνδεση στο pad σας...",
"pad.modals.forcereconnect": "Επιβολή επανασύνδεσης", "pad.modals.forcereconnect": "Επιβολή επανασύνδεσης",
"pad.modals.reconnecttimer": "Προσπάθεια επανασύνδεσης σε", "pad.modals.reconnecttimer": "Προσπάθεια επανασύνδεσης σε",
"pad.modals.cancel": "Ακύρωση", "pad.modals.cancel": "Ακύρωση",
@ -115,9 +111,7 @@
"pad.modals.corruptPad.cause": "Αυτό μπορεί να οφείλεται σε ένα λάθος στη ρύθμιση του διακομιστή ή κάποια άλλη απρόβλεπτη συμπεριφορά. Παρακαλώ επικοινωνήστε με τον διαχειριστή της υπηρεσίας.", "pad.modals.corruptPad.cause": "Αυτό μπορεί να οφείλεται σε ένα λάθος στη ρύθμιση του διακομιστή ή κάποια άλλη απρόβλεπτη συμπεριφορά. Παρακαλώ επικοινωνήστε με τον διαχειριστή της υπηρεσίας.",
"pad.modals.deleted": "Διεγράφη.", "pad.modals.deleted": "Διεγράφη.",
"pad.modals.deleted.explanation": "Αυτό το pad έχει καταργηθεί.", "pad.modals.deleted.explanation": "Αυτό το pad έχει καταργηθεί.",
"pad.modals.rateLimited.explanation": "Στείλατε πάρα πολλά μηνύματα σε αυτό το pad, επομένως σας αποσύνδεσε.",
"pad.modals.rejected.explanation": "Ο διακομιστής απέρριψε ένα μήνυμα που στάλθηκε από το πρόγραμμα περιήγησής σας.", "pad.modals.rejected.explanation": "Ο διακομιστής απέρριψε ένα μήνυμα που στάλθηκε από το πρόγραμμα περιήγησής σας.",
"pad.modals.rejected.cause": "Ο διακομιστής μπορεί να έχει ενημερωθεί ενώ προβάλλατε το pad ή ίσως υπάρχει σφάλμα στο Etherpad. Δοκιμάστε να φορτώσετε ξανά τη σελίδα.",
"pad.modals.disconnected": "Είστε αποσυνδεδεμένοι.", "pad.modals.disconnected": "Είστε αποσυνδεδεμένοι.",
"pad.modals.disconnected.explanation": "Χάθηκε η σύνδεση με τον διακομιστή", "pad.modals.disconnected.explanation": "Χάθηκε η σύνδεση με τον διακομιστή",
"pad.modals.disconnected.cause": "Ο διακομιστής μπορεί να μην είναι διαθέσιμος. Παρακαλούμε ειδοποιήστε τον διαχειριστή της υπηρεσίας εάν εξακολουθεί να συμβαίνει αυτό.", "pad.modals.disconnected.cause": "Ο διακομιστής μπορεί να μην είναι διαθέσιμος. Παρακαλούμε ειδοποιήστε τον διαχειριστή της υπηρεσίας εάν εξακολουθεί να συμβαίνει αυτό.",
@ -130,7 +124,6 @@
"pad.chat.loadmessages": "Φόρτωση περισσότερων μηνυμάτων", "pad.chat.loadmessages": "Φόρτωση περισσότερων μηνυμάτων",
"pad.chat.stick.title": "Κρατήστε τη συνομιλία στην οθόνη", "pad.chat.stick.title": "Κρατήστε τη συνομιλία στην οθόνη",
"pad.chat.writeMessage.placeholder": "Γράψτε το μήνυμα σας εδώ", "pad.chat.writeMessage.placeholder": "Γράψτε το μήνυμα σας εδώ",
"timeslider.followContents": "Ακολουθήστε τις ενημερώσεις περιεχομένου του pad",
"timeslider.pageTitle": "{{appTitle}} Χρονοδιάγραμμα", "timeslider.pageTitle": "{{appTitle}} Χρονοδιάγραμμα",
"timeslider.toolbar.returnbutton": "Επιστροφή στο pad", "timeslider.toolbar.returnbutton": "Επιστροφή στο pad",
"timeslider.toolbar.authors": "Συντάκτες:", "timeslider.toolbar.authors": "Συντάκτες:",

View file

@ -72,8 +72,6 @@
"pad.settings.fontType": "Font type:", "pad.settings.fontType": "Font type:",
"pad.settings.fontType.normal": "Normal", "pad.settings.fontType.normal": "Normal",
"pad.settings.language": "Language:", "pad.settings.language": "Language:",
"pad.settings.deletePad": "Delete Pad",
"pad.delete.confirm": "Do you really want to delete this pad?",
"pad.settings.about": "About", "pad.settings.about": "About",
"pad.settings.poweredBy": "Powered by", "pad.settings.poweredBy": "Powered by",

View file

@ -4,7 +4,6 @@
"BMRG14", "BMRG14",
"Beginneruser", "Beginneruser",
"Dalba", "Dalba",
"Ebrahim",
"Ebraminio", "Ebraminio",
"FarsiNevis", "FarsiNevis",
"Jeeputer", "Jeeputer",

View file

@ -87,8 +87,6 @@
"pad.settings.fontType": "Fonttityyppi:", "pad.settings.fontType": "Fonttityyppi:",
"pad.settings.fontType.normal": "normaali", "pad.settings.fontType.normal": "normaali",
"pad.settings.language": "Kieli:", "pad.settings.language": "Kieli:",
"pad.settings.deletePad": "Poista muistio",
"pad.delete.confirm": "Haluatko todella poistaa tämän muistion?",
"pad.settings.about": "Tietoja", "pad.settings.about": "Tietoja",
"pad.settings.poweredBy": "Palvelun mahdollistaa", "pad.settings.poweredBy": "Palvelun mahdollistaa",
"pad.importExport.import_export": "Tuonti/vienti", "pad.importExport.import_export": "Tuonti/vienti",

View file

@ -14,7 +14,6 @@
"Jean-Frédéric", "Jean-Frédéric",
"Leviathan", "Leviathan",
"Macofe", "Macofe",
"Mahabarata",
"Maxim21", "Maxim21",
"McDutchie", "McDutchie",
"Metroitendo", "Metroitendo",
@ -22,7 +21,6 @@
"Peter17", "Peter17",
"Quenenni", "Quenenni",
"Rastus Vernon", "Rastus Vernon",
"Spf",
"Stephane Cottin", "Stephane Cottin",
"Thibaut120094", "Thibaut120094",
"Tux-tn", "Tux-tn",
@ -99,8 +97,6 @@
"pad.settings.fontType": "Type de police:", "pad.settings.fontType": "Type de police:",
"pad.settings.fontType.normal": "Normal", "pad.settings.fontType.normal": "Normal",
"pad.settings.language": "Langue:", "pad.settings.language": "Langue:",
"pad.settings.deletePad": "Supprimer le bloc-notes",
"pad.delete.confirm": "Voulez-vous vraiment supprimer ce bloc-notes ?",
"pad.settings.about": "À propos", "pad.settings.about": "À propos",
"pad.settings.poweredBy": "Propulsé par", "pad.settings.poweredBy": "Propulsé par",
"pad.importExport.import_export": "Importer/Exporter", "pad.importExport.import_export": "Importer/Exporter",
@ -161,7 +157,7 @@
"timeslider.toolbar.exportlink.title": "Exporter", "timeslider.toolbar.exportlink.title": "Exporter",
"timeslider.exportCurrent": "Exporter la version actuelle sous:", "timeslider.exportCurrent": "Exporter la version actuelle sous:",
"timeslider.version": "Version {{version}}", "timeslider.version": "Version {{version}}",
"timeslider.saved": "Enregistrée le {{day}} {{month}} {{year}}", "timeslider.saved": "Enregistré le {{day}} {{month}} {{year}}",
"timeslider.playPause": "Lecture/Pause des contenus du bloc-notes", "timeslider.playPause": "Lecture/Pause des contenus du bloc-notes",
"timeslider.backRevision": "Reculer dune révision dans ce bloc-notes", "timeslider.backRevision": "Reculer dune révision dans ce bloc-notes",
"timeslider.forwardRevision": "Avancer dune révision dans ce bloc-notes", "timeslider.forwardRevision": "Avancer dune révision dans ce bloc-notes",

View file

@ -42,9 +42,9 @@
"index.newPad": "Novo documento", "index.newPad": "Novo documento",
"index.createOpenPad": "ou crea/abre un documento co nome:", "index.createOpenPad": "ou crea/abre un documento co nome:",
"index.openPad": "abrir un Pad existente co nome:", "index.openPad": "abrir un Pad existente co nome:",
"pad.toolbar.bold.title": "Grosa (Ctrl+B)", "pad.toolbar.bold.title": "Resaltado (Ctrl-B)",
"pad.toolbar.italic.title": "Cursiva (Ctrl+I)", "pad.toolbar.italic.title": "Cursiva (Ctrl-I)",
"pad.toolbar.underline.title": "Subliñar (Ctrl+U)", "pad.toolbar.underline.title": "Subliñar (Ctrl-U)",
"pad.toolbar.strikethrough.title": "Riscar (Ctrl+5)", "pad.toolbar.strikethrough.title": "Riscar (Ctrl+5)",
"pad.toolbar.ol.title": "Lista ordenada (Ctrl+Shift+N)", "pad.toolbar.ol.title": "Lista ordenada (Ctrl+Shift+N)",
"pad.toolbar.ul.title": "Lista sen ordenar (Ctrl+Shift+L)", "pad.toolbar.ul.title": "Lista sen ordenar (Ctrl+Shift+L)",
@ -74,8 +74,6 @@
"pad.settings.fontType": "Tipo de letra:", "pad.settings.fontType": "Tipo de letra:",
"pad.settings.fontType.normal": "Normal", "pad.settings.fontType.normal": "Normal",
"pad.settings.language": "Lingua:", "pad.settings.language": "Lingua:",
"pad.settings.deletePad": "Borrar o documento",
"pad.delete.confirm": "Queres borrar este documento?",
"pad.settings.about": "Acerca de", "pad.settings.about": "Acerca de",
"pad.settings.poweredBy": "Grazas a", "pad.settings.poweredBy": "Grazas a",
"pad.importExport.import_export": "Importar/Exportar", "pad.importExport.import_export": "Importar/Exportar",
@ -90,7 +88,7 @@
"pad.importExport.exportopen": "ODF (Open Document Format)", "pad.importExport.exportopen": "ODF (Open Document Format)",
"pad.importExport.abiword.innerHTML": "Só podes importar texto simple ou formatos HTML. Para obter máis información sobre as características de importación avanzadas <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">instala AbiWord</a>.", "pad.importExport.abiword.innerHTML": "Só podes importar texto simple ou formatos HTML. Para obter máis información sobre as características de importación avanzadas <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">instala AbiWord</a>.",
"pad.modals.connected": "Conectado.", "pad.modals.connected": "Conectado.",
"pad.modals.reconnecting": "Reconectando co teu documento...", "pad.modals.reconnecting": "Reconectando co seu documento...",
"pad.modals.forcereconnect": "Forzar a reconexión", "pad.modals.forcereconnect": "Forzar a reconexión",
"pad.modals.reconnecttimer": "Intentarase reconectar en", "pad.modals.reconnecttimer": "Intentarase reconectar en",
"pad.modals.cancel": "Cancelar", "pad.modals.cancel": "Cancelar",

View file

@ -76,8 +76,6 @@
"pad.settings.fontType": "סוג גופן:", "pad.settings.fontType": "סוג גופן:",
"pad.settings.fontType.normal": "רגיל", "pad.settings.fontType.normal": "רגיל",
"pad.settings.language": "שפה:", "pad.settings.language": "שפה:",
"pad.settings.deletePad": "מחיקת פנקס",
"pad.delete.confirm": "למחוק את הפנקס הזה?",
"pad.settings.about": "על אודות", "pad.settings.about": "על אודות",
"pad.settings.poweredBy": "מופעל על גבי", "pad.settings.poweredBy": "מופעל על גבי",
"pad.importExport.import_export": "יבוא/יצוא", "pad.importExport.import_export": "יבוא/יצוא",

View file

@ -72,8 +72,6 @@
"pad.settings.fontType": "Pismowa družina:", "pad.settings.fontType": "Pismowa družina:",
"pad.settings.fontType.normal": "Normalny", "pad.settings.fontType.normal": "Normalny",
"pad.settings.language": "Rěč:", "pad.settings.language": "Rěč:",
"pad.settings.deletePad": "Zapisnik zhašeć",
"pad.delete.confirm": "Chceće woprawdźe tutón zapisnik zhašeć?",
"pad.settings.about": "Wo", "pad.settings.about": "Wo",
"pad.settings.poweredBy": "Spěchowany wot", "pad.settings.poweredBy": "Spěchowany wot",
"pad.importExport.import_export": "Import/Eksport", "pad.importExport.import_export": "Import/Eksport",

View file

@ -72,8 +72,6 @@
"pad.settings.fontType": "Typo de litteras:", "pad.settings.fontType": "Typo de litteras:",
"pad.settings.fontType.normal": "Normal", "pad.settings.fontType.normal": "Normal",
"pad.settings.language": "Lingua:", "pad.settings.language": "Lingua:",
"pad.settings.deletePad": "Deler pad",
"pad.delete.confirm": "Es tu secur de voler deler iste pad?",
"pad.settings.about": "A proposito", "pad.settings.about": "A proposito",
"pad.settings.poweredBy": "Actionate per", "pad.settings.poweredBy": "Actionate per",
"pad.importExport.import_export": "Importar/Exportar", "pad.importExport.import_export": "Importar/Exportar",

View file

@ -1,8 +1,6 @@
{ {
"@metadata": { "@metadata": {
"authors": [ "authors": [
"Akmaie Ajam",
"Atriwidada",
"Bennylin", "Bennylin",
"IvanLanin", "IvanLanin",
"Marwan Mohamad", "Marwan Mohamad",
@ -12,39 +10,13 @@
"admin.page-title": "Dasbor Pengurus - Etherpad", "admin.page-title": "Dasbor Pengurus - Etherpad",
"admin_plugins": "Manajer plugin", "admin_plugins": "Manajer plugin",
"admin_plugins.available": "Plugin yang tersedia", "admin_plugins.available": "Plugin yang tersedia",
"admin_plugins.available_not-found": "Tidak ada plugin yang ditemukan.",
"admin_plugins.available_fetching": "Mengambil…",
"admin_plugins.available_install.value": "Instal", "admin_plugins.available_install.value": "Instal",
"admin_plugins.available_search.placeholder": "Cari plugin yang akan dipasang",
"admin_plugins.description": "Deskripsi",
"admin_plugins.installed": "Plugin terpasang",
"admin_plugins.installed_fetching": "Mengambil plugin yang terpasang…",
"admin_plugins.installed_nothing": "Anda belum memasang plugin apa pun.",
"admin_plugins.installed_uninstall.value": "Uninstal",
"admin_plugins.last-update": "Pembaruan terakhir",
"admin_plugins.name": "Nama",
"admin_plugins.page-title": "Manajer plugin - Etherpad",
"admin_plugins.version": "Versi", "admin_plugins.version": "Versi",
"admin_plugins_info": "Informasi penelusuran masalah",
"admin_plugins_info.hooks": "Kait terpasang",
"admin_plugins_info.hooks_client": "Kait sisi klien",
"admin_plugins_info.hooks_server": "Kait sisi server",
"admin_plugins_info.parts": "Bagian terpasang",
"admin_plugins_info.plugins": "Plugin terpasang",
"admin_plugins_info.page-title": "Informasi plugin - Etherpad",
"admin_plugins_info.version": "Versi Etherpad",
"admin_plugins_info.version_latest": "Versi terakhir yang tersedia",
"admin_plugins_info.version_number": "Nomor versi",
"admin_settings": "Pengaturan", "admin_settings": "Pengaturan",
"admin_settings.current": "Konfigurasi kini",
"admin_settings.current_example-devel": "Contoh templat pengaturan pengembangan",
"admin_settings.current_example-prod": "Contoh templat pengaturan produksi",
"admin_settings.current_restart.value": "Jalankan ulang Etherpad",
"admin_settings.current_save.value": "Simpan pengaturan", "admin_settings.current_save.value": "Simpan pengaturan",
"admin_settings.page-title": "Pengaturan - Etherpad", "admin_settings.page-title": "Pengaturan - Etherpad",
"index.newPad": "Pad baru", "index.newPad": "Pad baru",
"index.createOpenPad": "atau buat/buka Pad dengan nama:", "index.createOpenPad": "atau buat/buka Pad dengan nama:",
"index.openPad": "buka Pad yang ada dengan nama:",
"pad.toolbar.bold.title": "Tebal (Ctrl-B)", "pad.toolbar.bold.title": "Tebal (Ctrl-B)",
"pad.toolbar.italic.title": "Miring (Ctrl-I)", "pad.toolbar.italic.title": "Miring (Ctrl-I)",
"pad.toolbar.underline.title": "Garis bawah (Ctrl-U)", "pad.toolbar.underline.title": "Garis bawah (Ctrl-U)",
@ -65,7 +37,7 @@
"pad.colorpicker.save": "Simpan", "pad.colorpicker.save": "Simpan",
"pad.colorpicker.cancel": "Batalkan", "pad.colorpicker.cancel": "Batalkan",
"pad.loading": "Memuat...", "pad.loading": "Memuat...",
"pad.noCookie": "Kuki tidak dapat ditemukan. Izinkan kuki di peramban Anda! Sesi dan pengaturan Anda tidak akan disimpan antar kunjungan. Ini mungkin karena Etherpad disertakan dalam suatu iFrame dalam beberapa Peramban. Harap pastikan Etherpad ada pada sub domain/domain dengan iFrame induk", "pad.noCookie": "Kuki tidak dapat ditemukan. Izinkan kuki di peramban Anda!",
"pad.permissionDenied": "Anda tidak memiliki izin untuk mengakses pad ini", "pad.permissionDenied": "Anda tidak memiliki izin untuk mengakses pad ini",
"pad.settings.padSettings": "Pengaturan Pad", "pad.settings.padSettings": "Pengaturan Pad",
"pad.settings.myView": "Tampilan Saya", "pad.settings.myView": "Tampilan Saya",
@ -76,10 +48,7 @@
"pad.settings.rtlcheck": "Membaca dari kanan ke kiri?", "pad.settings.rtlcheck": "Membaca dari kanan ke kiri?",
"pad.settings.fontType": "Jenis fonta:", "pad.settings.fontType": "Jenis fonta:",
"pad.settings.language": "Bahasa:", "pad.settings.language": "Bahasa:",
"pad.settings.deletePad": "Hapus Pad",
"pad.delete.confirm": "Apakah Anda benar-benar ingin menghapus pad ini?",
"pad.settings.about": "Tentang", "pad.settings.about": "Tentang",
"pad.settings.poweredBy": "Ditenagai oleh",
"pad.importExport.import_export": "Impor/Ekspor", "pad.importExport.import_export": "Impor/Ekspor",
"pad.importExport.import": "Unggah setiap berkas teks atau dokumen", "pad.importExport.import": "Unggah setiap berkas teks atau dokumen",
"pad.importExport.importSuccessful": "Berhasil!", "pad.importExport.importSuccessful": "Berhasil!",
@ -90,9 +59,9 @@
"pad.importExport.exportword": "Microsoft Word", "pad.importExport.exportword": "Microsoft Word",
"pad.importExport.exportpdf": "PDF", "pad.importExport.exportpdf": "PDF",
"pad.importExport.exportopen": "ODF (Open Document Format)", "pad.importExport.exportopen": "ODF (Open Document Format)",
"pad.importExport.abiword.innerHTML": "Anda hanya dapat mengimpor dari format teks polos atau HTML. Untuk fitur impor yang lebih canggih, <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">pasanglah AbiWord atau LibreOffice</a>.", "pad.importExport.abiword.innerHTML": "Anda hanya dapat mengimpor dari format teks biasa atau HTML. Untuk fitur impor yang lebih canggih, <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">pasanglah AbiWord</a>.",
"pad.modals.connected": "Tersambung.", "pad.modals.connected": "Tersambung.",
"pad.modals.reconnecting": "Menyambungkan kembali ke pad Anda", "pad.modals.reconnecting": "Menyambungkan kembali ke pad Anda...",
"pad.modals.forcereconnect": "Sambung kembali secara paksa", "pad.modals.forcereconnect": "Sambung kembali secara paksa",
"pad.modals.reconnecttimer": "Mencoba menghubungkan ulang", "pad.modals.reconnecttimer": "Mencoba menghubungkan ulang",
"pad.modals.cancel": "Batalkan", "pad.modals.cancel": "Batalkan",
@ -114,10 +83,6 @@
"pad.modals.corruptPad.cause": "Hal ini mungkin disebabkan oleh konfigurasi peladen salah atau sesuatu perilaku yang tidak diperkirakan. Silahkan hubungi administrator Anda jika Anda merasakan ini adalah satu kesalahan.", "pad.modals.corruptPad.cause": "Hal ini mungkin disebabkan oleh konfigurasi peladen salah atau sesuatu perilaku yang tidak diperkirakan. Silahkan hubungi administrator Anda jika Anda merasakan ini adalah satu kesalahan.",
"pad.modals.deleted": "Dihapus", "pad.modals.deleted": "Dihapus",
"pad.modals.deleted.explanation": "Pad ini telah dibuang.", "pad.modals.deleted.explanation": "Pad ini telah dibuang.",
"pad.modals.rateLimited": "Laju Dibatasi.",
"pad.modals.rateLimited.explanation": "Anda mengirim terlalu banyak pesan ke pad ini sehingga itu memutus Anda.",
"pad.modals.rejected.explanation": "Server menolak suatu pesan yang dikirim oleh peramban Anda.",
"pad.modals.rejected.cause": "Server mungkin telah diperbarui ketika Anda sedang melihat pad, atau mungkin ada bug dalam Etherpad. Cobalah memuat ulang halaman.",
"pad.modals.disconnected": "Sambungan Anda telah diputuskan.", "pad.modals.disconnected": "Sambungan Anda telah diputuskan.",
"pad.modals.disconnected.explanation": "Sambungan ke peladen terputus", "pad.modals.disconnected.explanation": "Sambungan ke peladen terputus",
"pad.modals.disconnected.cause": "Peladen ini mungkin tidak tersedia. Silakan beritahu administrator jika masalah ini berkelanjutan.", "pad.modals.disconnected.cause": "Peladen ini mungkin tidak tersedia. Silakan beritahu administrator jika masalah ini berkelanjutan.",
@ -130,7 +95,6 @@
"pad.chat.loadmessages": "Muatkan lebih banyak pesan", "pad.chat.loadmessages": "Muatkan lebih banyak pesan",
"pad.chat.stick.title": "Tempelkan chat ke layar", "pad.chat.stick.title": "Tempelkan chat ke layar",
"pad.chat.writeMessage.placeholder": "Tuliskan pesan Anda di sini", "pad.chat.writeMessage.placeholder": "Tuliskan pesan Anda di sini",
"timeslider.followContents": "Ikuti pembaruan isi pad",
"timeslider.pageTitle": "{{appTitle}} Timeslider", "timeslider.pageTitle": "{{appTitle}} Timeslider",
"timeslider.toolbar.returnbutton": "Kembali ke pad", "timeslider.toolbar.returnbutton": "Kembali ke pad",
"timeslider.toolbar.authors": "Pembuat:", "timeslider.toolbar.authors": "Pembuat:",
@ -160,7 +124,7 @@
"pad.savedrevs.timeslider": "Anda bisa melihat revisi yang tersimpan dengan mengunjungi timeslider", "pad.savedrevs.timeslider": "Anda bisa melihat revisi yang tersimpan dengan mengunjungi timeslider",
"pad.userlist.entername": "Masukkan nama Anda", "pad.userlist.entername": "Masukkan nama Anda",
"pad.userlist.unnamed": "tanpa nama", "pad.userlist.unnamed": "tanpa nama",
"pad.editbar.clearcolors": "Bersihkan warna penulis pada seluruh dokumen? Ini tidak dapat dibatalkan", "pad.editbar.clearcolors": "Padamkan warna penulis pada seluruh dokumen?",
"pad.impexp.importbutton": "Impor Sekarang", "pad.impexp.importbutton": "Impor Sekarang",
"pad.impexp.importing": "Mengimpor...", "pad.impexp.importing": "Mengimpor...",
"pad.impexp.confirmimport": "Mengimpor berkas akan menimpa teks saat ini di pad ini. Apakah Anda benar-benar ingin melakukannya?", "pad.impexp.confirmimport": "Mengimpor berkas akan menimpa teks saat ini di pad ini. Apakah Anda benar-benar ingin melakukannya?",
@ -169,6 +133,5 @@
"pad.impexp.uploadFailed": "Penunggahan gagal, silakan mencoba lagi", "pad.impexp.uploadFailed": "Penunggahan gagal, silakan mencoba lagi",
"pad.impexp.importfailed": "Impor gagal", "pad.impexp.importfailed": "Impor gagal",
"pad.impexp.copypaste": "Silahkan salin tempel", "pad.impexp.copypaste": "Silahkan salin tempel",
"pad.impexp.exportdisabled": "Mengekspor dalam format {{type}} dilarang. Silakan hubungi administrator untuk detilnya.", "pad.impexp.exportdisabled": "Mengekspor dalam format {{type}} dilarang. Silakan hubungi administrator untuk detilnya."
"pad.impexp.maxFileSize": "Berkas terlalu besar. Hubungi administrator situs Anda untuk menaikkan ukuran berkas yang diizinkan untuk impor"
} }

View file

@ -8,7 +8,6 @@
"Kurousagi", "Kurousagi",
"Revi", "Revi",
"SeoJeongHo", "SeoJeongHo",
"Suleiman the Magnificent Television",
"Ykhwong", "Ykhwong",
"그냥기여자", "그냥기여자",
"아라" "아라"
@ -20,13 +19,13 @@
"admin_plugins.available_not-found": "플러그인이 없습니다.", "admin_plugins.available_not-found": "플러그인이 없습니다.",
"admin_plugins.available_fetching": "검색 중...", "admin_plugins.available_fetching": "검색 중...",
"admin_plugins.available_install.value": "설치", "admin_plugins.available_install.value": "설치",
"admin_plugins.available_search.placeholder": "설치할 플러그인을 검색", "admin_plugins.available_search.placeholder": "설치할 플러그인을 검색합니다",
"admin_plugins.description": "설명", "admin_plugins.description": "설명",
"admin_plugins.installed": "설치된 플러그인", "admin_plugins.installed": "설치된 플러그인",
"admin_plugins.installed_fetching": "설치된 플러그인을 검색하는 중...", "admin_plugins.installed_fetching": "설치된 플러그인을 검색하는 중...",
"admin_plugins.installed_nothing": "아직 플러인을 설치하지 않으셨습니다.", "admin_plugins.installed_nothing": "아직 플러인을 설치하지 않으셨습니다.",
"admin_plugins.installed_uninstall.value": "제거", "admin_plugins.installed_uninstall.value": "설치 제거",
"admin_plugins.last-update": "마지막 업데이트", "admin_plugins.last-update": "최근 업데이트",
"admin_plugins.name": "이름", "admin_plugins.name": "이름",
"admin_plugins.page-title": "플러그인 관리자 - 이더패드", "admin_plugins.page-title": "플러그인 관리자 - 이더패드",
"admin_plugins.version": "버전", "admin_plugins.version": "버전",
@ -82,8 +81,6 @@
"pad.settings.fontType": "글꼴 종류:", "pad.settings.fontType": "글꼴 종류:",
"pad.settings.fontType.normal": "보통", "pad.settings.fontType.normal": "보통",
"pad.settings.language": "언어:", "pad.settings.language": "언어:",
"pad.settings.deletePad": "패드 삭제",
"pad.delete.confirm": "이 패드를 삭제하시겠습니까?",
"pad.settings.about": "소개", "pad.settings.about": "소개",
"pad.settings.poweredBy": "제공:", "pad.settings.poweredBy": "제공:",
"pad.importExport.import_export": "가져오기/내보내기", "pad.importExport.import_export": "가져오기/내보내기",

View file

@ -82,7 +82,7 @@
"timeslider.toolbar.exportlink.title": "Exportéieren", "timeslider.toolbar.exportlink.title": "Exportéieren",
"timeslider.exportCurrent": "Exportéiert déi aktuell Versioun als:", "timeslider.exportCurrent": "Exportéiert déi aktuell Versioun als:",
"timeslider.version": "Versioun {{version}}", "timeslider.version": "Versioun {{version}}",
"timeslider.saved": "Gespäichert de(n) {{day}}. {{month}} {{year}}", "timeslider.saved": "Gespäichert de(n) {{day}} {{month}} {{year}}",
"timeslider.dateformat": "{{day}}/{{month}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}", "timeslider.dateformat": "{{day}}/{{month}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}",
"timeslider.month.january": "Januar", "timeslider.month.january": "Januar",
"timeslider.month.february": "Februar", "timeslider.month.february": "Februar",

View file

@ -1,61 +0,0 @@
{
"@metadata": {
"authors": [
"BOKOBA VEROLY"
]
},
"admin.page-title": "Admin Dashboard - Etherpad",
"admin_plugins": "Mokambi ya plug-in",
"admin_plugins.available": "Ba plugins oyo ezali",
"admin_plugins.available_not-found": "Ba plugins ezwamaki te.",
"admin_plugins.available_fetching": "Kozwa...",
"admin_plugins.available_install.value": "Kotya",
"admin_plugins.available_search.placeholder": "Bolukiluki ya ba plugins mpo na kotya",
"admin_plugins.description": "Ndimbola",
"admin_plugins.installed": "Ba plugins oyo etyamaki",
"admin_plugins.installed_fetching": "Kozwa ba plugins oyo etyamaki...",
"admin_plugins.installed_nothing": "Otikaki naino ba plugins te.",
"admin_plugins.installed_uninstall.value": "Kofungola esika",
"admin_plugins.last-update": "Makambo ya sika ya suka",
"admin_plugins.name": "Nkombo na yango",
"admin_plugins.page-title": "Gestionnaire de greffons — Etherpad",
"admin_plugins.version": "Libongoli",
"admin_plugins_info": "Informations de résolution de problème",
"admin_plugins_info.hooks": "Crochets installés",
"admin_plugins_info.hooks_client": "Crochets côté client",
"admin_plugins_info.hooks_server": "Crochets côté serveur",
"admin_plugins_info.parts": "Biteni oyo batye",
"admin_plugins_info.plugins": "Ba plugins oyo etyamaki",
"admin_plugins_info.page-title": "Makambo etali ordinatɛrɛ - Etherpad",
"admin_plugins_info.version": "Libongoli ya Etherpad",
"admin_plugins_info.version_latest": "Libongoli ya sika",
"admin_plugins_info.version_number": "Numero ya version",
"admin_settings": "Ndenge ya kobongisa yango",
"admin_settings.current": "Configuration ya lelo",
"admin_settings.current_example-devel": "Ndakisa modèle ya paramètres ya développement",
"admin_settings.current_example-prod": "Ndakisa modèle ya paramètres ya production",
"admin_settings.current_restart.value": "Bobandi lisusu Etherpad",
"admin_settings.current_save.value": "Bomba ba Paramètres",
"admin_settings.page-title": "Paramètres - Etherpad ya kosala",
"index.newPad": "Pad ya sika",
"index.createOpenPad": "to kosala/kofungola Pad na nkombo:",
"index.openPad": "kofungola Pad oyo ezali na nkombo:",
"pad.toolbar.bold.title": "Makomi ya moindo makasi (Ctrl+B)",
"pad.toolbar.underline.title": "Mokanda ya nse (Ctrl+U)",
"pad.toolbar.strikethrough.title": "Strikethrough (Ctrl+5)",
"pad.toolbar.ol.title": "Liste oyo esɛngami (Ctrl+Shift+N)",
"pad.toolbar.ul.title": "Liste oyo etyami na molongo te (Ctrl+Shift+L)",
"pad.toolbar.indent.title": "Indent (TAB)",
"pad.toolbar.unindent.title": "Mikuwa ya libándá (Shift+TAB)",
"pad.toolbar.undo.title": "Undo (Ctrl+Z)",
"pad.toolbar.redo.title": "Redo (Ctrl+Y)",
"pad.toolbar.clearAuthorship.title": "Langi ya polele ya mokomi (Ctrl+Shift+C)",
"pad.toolbar.import_export.title": "Kokotisa/kobimisa na/na ba formats ya ba fichiers ndenge na ndenge",
"pad.toolbar.timeslider.title": "Mokambi ya ntango",
"pad.toolbar.savedRevision.title": "Kobomba lisusu",
"pad.toolbar.settings.title": "Ndenge ya kobongisa yango",
"pad.toolbar.embed.title": "Kopesa mpe kobakisa yango",
"pad.toolbar.showusers.title": "Tyá bato oyo basalelaka yango",
"pad.colorpicker.save": "Kobikisa",
"pad.colorpicker.cancel": "Kolongola"
}

View file

@ -63,7 +63,7 @@
"pad.colorpicker.save": "Išsaugoti", "pad.colorpicker.save": "Išsaugoti",
"pad.colorpicker.cancel": "Atšaukti", "pad.colorpicker.cancel": "Atšaukti",
"pad.loading": "Įkraunama...", "pad.loading": "Įkraunama...",
"pad.noCookie": "Slapuko rasti nepavyko. Prašome leisti slapukus savo naršyklėje! Jūsų sesija ir nustatymai nebus išsaugoti tarp apsilankymų. Taip gali būti dėl to, kad kai kuriose naršyklėse Etherpad yra įtrauktas į iFrame. Įsitikinkite, kad Etherpad yra tame pačiame padomenyje / domene kaip ir pirminis iFrame.", "pad.noCookie": "Slapuko nepavyko rasti. Prašome leisti slapukus interneto naršyklėje!",
"pad.permissionDenied": "Jūs neturite leidimo patekti į šį bloknotą", "pad.permissionDenied": "Jūs neturite leidimo patekti į šį bloknotą",
"pad.settings.padSettings": "Bloknoto nustatymai", "pad.settings.padSettings": "Bloknoto nustatymai",
"pad.settings.myView": "Mano Vaizdas", "pad.settings.myView": "Mano Vaizdas",
@ -75,8 +75,6 @@
"pad.settings.fontType": "Šrifto tipas:", "pad.settings.fontType": "Šrifto tipas:",
"pad.settings.fontType.normal": "Normalus", "pad.settings.fontType.normal": "Normalus",
"pad.settings.language": "Kalba:", "pad.settings.language": "Kalba:",
"pad.settings.deletePad": "Ištrinti bloką",
"pad.delete.confirm": "Ar tikrai norite ištrinti šį bloką?",
"pad.settings.about": "Apie", "pad.settings.about": "Apie",
"pad.settings.poweredBy": "Palaiko", "pad.settings.poweredBy": "Palaiko",
"pad.importExport.import_export": "Importuoti/Eksportuoti", "pad.importExport.import_export": "Importuoti/Eksportuoti",

View file

@ -74,8 +74,6 @@
"pad.settings.fontType": "Тип на фонт:", "pad.settings.fontType": "Тип на фонт:",
"pad.settings.fontType.normal": "Нормален", "pad.settings.fontType.normal": "Нормален",
"pad.settings.language": "Јазик:", "pad.settings.language": "Јазик:",
"pad.settings.deletePad": "Избриши тетратка",
"pad.delete.confirm": "Дали навистина сакате да ја избришете тетраткава?",
"pad.settings.about": "За додатоков", "pad.settings.about": "За додатоков",
"pad.settings.poweredBy": "Овозможено од", "pad.settings.poweredBy": "Овозможено од",
"pad.importExport.import_export": "Увоз/Извоз", "pad.importExport.import_export": "Увоз/Извоз",

View file

@ -41,7 +41,6 @@
"pad.settings.fontType": "Jenis fon:", "pad.settings.fontType": "Jenis fon:",
"pad.settings.fontType.normal": "Normal", "pad.settings.fontType.normal": "Normal",
"pad.settings.language": "Bahasa:", "pad.settings.language": "Bahasa:",
"pad.settings.poweredBy": "Dikuasakan oleh",
"pad.importExport.import_export": "Import/Eksport", "pad.importExport.import_export": "Import/Eksport",
"pad.importExport.import": "Muat naik sebarang fail teks atau dokumen", "pad.importExport.import": "Muat naik sebarang fail teks atau dokumen",
"pad.importExport.importSuccessful": "Berjaya!", "pad.importExport.importSuccessful": "Berjaya!",

View file

@ -4,14 +4,12 @@
"Bada Kaji", "Bada Kaji",
"Nirajan pant", "Nirajan pant",
"Nirjal stha", "Nirjal stha",
"पर्वत सुबेदी",
"बडा काजी", "बडा काजी",
"राम प्रसाद जोशी", "राम प्रसाद जोशी",
"सरोज कुमार ढकाल", "सरोज कुमार ढकाल",
"हिमाल सुबेदी" "हिमाल सुबेदी"
] ]
}, },
"admin_plugins.description": "विवरण",
"index.newPad": "नयाँ प्याड", "index.newPad": "नयाँ प्याड",
"index.createOpenPad": "नाम सहितको नयाँ प्याड सिर्जना गर्ने / खोल्ने :", "index.createOpenPad": "नाम सहितको नयाँ प्याड सिर्जना गर्ने / खोल्ने :",
"pad.toolbar.bold.title": "मोटो (Ctrl-B)", "pad.toolbar.bold.title": "मोटो (Ctrl-B)",
@ -59,7 +57,6 @@
"pad.modals.connected": "जोडीएको।", "pad.modals.connected": "जोडीएको।",
"pad.modals.reconnecting": "तपाईंको प्याडमा पुन: जडान गर्दै", "pad.modals.reconnecting": "तपाईंको प्याडमा पुन: जडान गर्दै",
"pad.modals.forcereconnect": "जडानको लागि जोडगर्ने", "pad.modals.forcereconnect": "जडानको लागि जोडगर्ने",
"pad.modals.cancel": "रद्द गर्नुहोस्",
"pad.modals.userdup": "अर्को सन्झ्यालमा खोल्ने", "pad.modals.userdup": "अर्को सन्झ्यालमा खोल्ने",
"pad.modals.unauth": "अनुमती नदिइएको", "pad.modals.unauth": "अनुमती नदिइएको",
"pad.modals.initsocketfail": "सर्भरमा पहुँच पुर्‍याउन सकिएन ।", "pad.modals.initsocketfail": "सर्भरमा पहुँच पुर्‍याउन सकिएन ।",

View file

@ -85,8 +85,6 @@
"pad.settings.fontType": "Lettertype:", "pad.settings.fontType": "Lettertype:",
"pad.settings.fontType.normal": "Normaal", "pad.settings.fontType.normal": "Normaal",
"pad.settings.language": "Taal:", "pad.settings.language": "Taal:",
"pad.settings.deletePad": "Pad verwijderen",
"pad.delete.confirm": "Wilt u dit pad echt verwijderen?",
"pad.settings.about": "Over", "pad.settings.about": "Over",
"pad.settings.poweredBy": "Aangedreven door", "pad.settings.poweredBy": "Aangedreven door",
"pad.importExport.import_export": "Importeren/exporteren", "pad.importExport.import_export": "Importeren/exporteren",

View file

@ -9,16 +9,6 @@
"ਪ੍ਰਚਾਰਕ" "ਪ੍ਰਚਾਰਕ"
] ]
}, },
"admin_plugins.available_fetching": "ਲਿਆਉਣਾ ਪਿਆਂ...",
"admin_plugins.available_install.value": "ਜੜੋ",
"admin_plugins.description": "ਵੇਰਵਾ",
"admin_plugins.last-update": "ਆਖਰੀ ਵਾਰ ਨਵਿਆਈਆ ਗਿਆ",
"admin_plugins.name": "ਨਾਂ",
"admin_plugins_info": "ਸਮੱਸਿਆ ਨਿਵਾਰਣ ਜਾਣਕਾਰੀ",
"admin_settings": "ਤਰਜੀਹਾਂ",
"admin_settings.current": "ਮੌਜੂਦਾ ਬਣਤਰ",
"admin_settings.current_save.value": "ਤਰਜੀਹਾਂ ਸੰਭਾਲੋ",
"admin_settings.page-title": "ਤਰਜੀਹਾਂ - ਈਥਰਪੈਡ",
"index.newPad": "ਨਵਾਂ ਪੈਡ", "index.newPad": "ਨਵਾਂ ਪੈਡ",
"index.createOpenPad": "ਜਾਂ ਨਾਂ ਨਾਲ ਨਵਾਂ ਪੈਡ ਬਣਾਓ/ਖੋਲ੍ਹੋ:", "index.createOpenPad": "ਜਾਂ ਨਾਂ ਨਾਲ ਨਵਾਂ ਪੈਡ ਬਣਾਓ/ਖੋਲ੍ਹੋ:",
"pad.toolbar.bold.title": "ਗੂੜ੍ਹਾ (Ctrl-B)", "pad.toolbar.bold.title": "ਗੂੜ੍ਹਾ (Ctrl-B)",
@ -35,9 +25,9 @@
"pad.toolbar.import_export.title": "ਵੱਖ-ਵੱਖ ਫਾਇਲ ਫਾਰਮੈਟ ਤੋਂ/ਵਿੱਚ ਇੰਪੋਰਟ/ਐਕਸਪੋਰਟ ਕਰੋ", "pad.toolbar.import_export.title": "ਵੱਖ-ਵੱਖ ਫਾਇਲ ਫਾਰਮੈਟ ਤੋਂ/ਵਿੱਚ ਇੰਪੋਰਟ/ਐਕਸਪੋਰਟ ਕਰੋ",
"pad.toolbar.timeslider.title": "ਸਮਾਂ-ਲਕੀਰ", "pad.toolbar.timeslider.title": "ਸਮਾਂ-ਲਕੀਰ",
"pad.toolbar.savedRevision.title": "ਦੁਹਰਾਅ ਸਾਂਭੋ", "pad.toolbar.savedRevision.title": "ਦੁਹਰਾਅ ਸਾਂਭੋ",
"pad.toolbar.settings.title": "ਪਸੰਦਾਂ", "pad.toolbar.settings.title": "ਸੈਟਿੰਗ",
"pad.toolbar.embed.title": "ਇਹ ਪੈਡ ਸਾਂਝਾ ਤੇ ਇੰਬੈੱਡ ਕਰੋ", "pad.toolbar.embed.title": "ਇਹ ਪੈਡ ਸਾਂਝਾ ਤੇ ਇੰਬੈੱਡ ਕਰੋ",
"pad.toolbar.showusers.title": "ਇਸ ਫੱਟੀ ਉੱਤੇ ਵਰਤੋਂਕਾਰ ਵਿਖਾਓ", "pad.toolbar.showusers.title": "ਇਹ ਪੈਡ ਉੱਤੇ ਯੂਜ਼ਰ ਵੇਖਾਓ",
"pad.colorpicker.save": "ਸੰਭਾਲੋ", "pad.colorpicker.save": "ਸੰਭਾਲੋ",
"pad.colorpicker.cancel": "ਰੱਦ ਕਰੋ", "pad.colorpicker.cancel": "ਰੱਦ ਕਰੋ",
"pad.loading": "…ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ", "pad.loading": "…ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ",
@ -50,11 +40,10 @@
"pad.settings.colorcheck": "ਲੇਖਕੀ ਰੰਗ", "pad.settings.colorcheck": "ਲੇਖਕੀ ਰੰਗ",
"pad.settings.linenocheck": "ਲਕੀਰ ਨੰਬਰ", "pad.settings.linenocheck": "ਲਕੀਰ ਨੰਬਰ",
"pad.settings.rtlcheck": "ਸਮੱਗਰੀ ਸੱਜੇ ਤੋਂ ਖੱਬੇ ਪੜ੍ਹਨੀ ਹੈ?", "pad.settings.rtlcheck": "ਸਮੱਗਰੀ ਸੱਜੇ ਤੋਂ ਖੱਬੇ ਪੜ੍ਹਨੀ ਹੈ?",
"pad.settings.fontType": "ਅੱਖਰ ਦੀ ਕਿਸਮ:", "pad.settings.fontType": "ਫੋਂਟ ਕਿਸਮ:",
"pad.settings.fontType.normal": "ਆਮ", "pad.settings.fontType.normal": "ਸਧਾਰਨ",
"pad.settings.language": "ਭਾਸ਼ਾ:", "pad.settings.language": "ਭਾਸ਼ਾ:",
"pad.settings.about": "ਬਾਬਤ", "pad.importExport.import_export": "ਇੰਪੋਰਟ/ਐਕਸਪੋਰਟ",
"pad.importExport.import_export": "ਦਰਾਮਦ/ਬਰਾਮਦ",
"pad.importExport.import": "ਕੋਈ ਵੀ ਟੈਕਸਟ ਫਾਇਲ ਜਾਂ ਦਸਤਾਵੇਜ਼ ਅੱਪਲੋਡ ਕਰੋ", "pad.importExport.import": "ਕੋਈ ਵੀ ਟੈਕਸਟ ਫਾਇਲ ਜਾਂ ਦਸਤਾਵੇਜ਼ ਅੱਪਲੋਡ ਕਰੋ",
"pad.importExport.importSuccessful": "ਸਫ਼ਲ!", "pad.importExport.importSuccessful": "ਸਫ਼ਲ!",
"pad.importExport.export": "ਮੌਜੂਦਾ ਪੈਡ ਨੂੰ ਐਕਸਪੋਰਟ ਕਰੋ:", "pad.importExport.export": "ਮੌਜੂਦਾ ਪੈਡ ਨੂੰ ਐਕਸਪੋਰਟ ਕਰੋ:",
@ -68,7 +57,6 @@
"pad.modals.connected": "ਕੁਨੈਕਟ ਹੈ।", "pad.modals.connected": "ਕੁਨੈਕਟ ਹੈ।",
"pad.modals.reconnecting": "..ਤੁਹਾਡੇ ਪੈਡ ਨਾਲ ਮੁੜ-ਕੁਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ", "pad.modals.reconnecting": "..ਤੁਹਾਡੇ ਪੈਡ ਨਾਲ ਮੁੜ-ਕੁਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ",
"pad.modals.forcereconnect": "ਧੱਕੇ ਨਾਲ ਮੁੜ-ਕੁਨੈਕਟ ਕਰੋ", "pad.modals.forcereconnect": "ਧੱਕੇ ਨਾਲ ਮੁੜ-ਕੁਨੈਕਟ ਕਰੋ",
"pad.modals.cancel": "ਰੱਦ ਕਰੋ",
"pad.modals.userdup": "ਹੋਰ ਵਿੰਡੋ ਵਿੱਚ ਖੁੱਲ੍ਹਿਆ ਹੈ", "pad.modals.userdup": "ਹੋਰ ਵਿੰਡੋ ਵਿੱਚ ਖੁੱਲ੍ਹਿਆ ਹੈ",
"pad.modals.userdup.explanation": "ਇਹ ਪੈਡ ਇਸ ਕੰਪਿਊਟਰ 'ਤੇ ਇੱਕ ਤੋਂ ਵੱਧ ਫਰੋਲੂ ਬਾਰੀ ਵਿੱਚ ਖੁੱਲ੍ਹਿਆ ਜਾਪਦਾ ਹੈ।", "pad.modals.userdup.explanation": "ਇਹ ਪੈਡ ਇਸ ਕੰਪਿਊਟਰ 'ਤੇ ਇੱਕ ਤੋਂ ਵੱਧ ਫਰੋਲੂ ਬਾਰੀ ਵਿੱਚ ਖੁੱਲ੍ਹਿਆ ਜਾਪਦਾ ਹੈ।",
"pad.modals.userdup.advice": "ਸਗੋਂ ਇਹ ਬਾਰੀ ਵਰਤਣ ਵਾਸਤੇ ਮੁੜ ਜੁੜੋ।", "pad.modals.userdup.advice": "ਸਗੋਂ ਇਹ ਬਾਰੀ ਵਰਤਣ ਵਾਸਤੇ ਮੁੜ ਜੁੜੋ।",
@ -92,17 +80,16 @@
"pad.modals.disconnected.cause": "ਸਰਵਰ ਨਾਮੌਜੂਦ ਹੋ ਸਕਦਾ ਹੈ। ਜੇਕਰ ਇਹ ਹੁੰਦਾ ਰਹੇ ਤਾਂ ਮਿਹਰਬਾਨੀ ਕਰਕੇ ਸੇਵਾ ਪ੍ਰਬੰਧਕ ਨੂੰ ਖ਼ਬਰ ਕਰੋ।", "pad.modals.disconnected.cause": "ਸਰਵਰ ਨਾਮੌਜੂਦ ਹੋ ਸਕਦਾ ਹੈ। ਜੇਕਰ ਇਹ ਹੁੰਦਾ ਰਹੇ ਤਾਂ ਮਿਹਰਬਾਨੀ ਕਰਕੇ ਸੇਵਾ ਪ੍ਰਬੰਧਕ ਨੂੰ ਖ਼ਬਰ ਕਰੋ।",
"pad.share": "ਇਹ ਪੈਡ ਸਾਂਝਾ ਕਰੋ", "pad.share": "ਇਹ ਪੈਡ ਸਾਂਝਾ ਕਰੋ",
"pad.share.readonly": "ਕੇਵਲ ਪੜ੍ਹਨ ਲਈ", "pad.share.readonly": "ਕੇਵਲ ਪੜ੍ਹਨ ਲਈ",
"pad.share.link": "ੜੀ", "pad.share.link": "ਲਿੰਕ",
"pad.share.emebdcode": "ਇੰਬੈੱਡ URL", "pad.share.emebdcode": "ਇੰਬੈੱਡ URL",
"pad.chat": "ਗੱਲਬਾਤ", "pad.chat": "ਗੱਲਬਾਤ",
"pad.chat.title": "ਇਹ ਪੈਡ ਲਈ ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ।", "pad.chat.title": "ਇਹ ਪੈਡ ਲਈ ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ।",
"pad.chat.loadmessages": "ਹੋਰ ਸੁਨੇਹੇ ਲੱਦੋ", "pad.chat.loadmessages": "ਹੋਰ ਸੁਨੇਹੇ ਲੋਡ ਕਰੋ",
"pad.chat.writeMessage.placeholder": "ਆਪਣਾ ਸੁਨੇਹਾ ਇੱਥੇ ਲਿਖੋ",
"timeslider.pageTitle": "{{appTitle}} ਸਮਾਂ-ਲਕੀਰ", "timeslider.pageTitle": "{{appTitle}} ਸਮਾਂ-ਲਕੀਰ",
"timeslider.toolbar.returnbutton": "ਪੈਡ ਉੱਤੇ ਵਾਪਸ", "timeslider.toolbar.returnbutton": "ਪੈਡ ਉੱਤੇ ਵਾਪਸ",
"timeslider.toolbar.authors": "ਲੇਖਕ:", "timeslider.toolbar.authors": "ਲੇਖਕ:",
"timeslider.toolbar.authorsList": "ਕੋਈ ਲੇਖਕ ਨਹੀਂ", "timeslider.toolbar.authorsList": "ਕੋਈ ਲੇਖਕ ਨਹੀਂ",
"timeslider.toolbar.exportlink.title": "ਬਰਾਮਦ", "timeslider.toolbar.exportlink.title": "ਐਕਸਪੋਰਟ",
"timeslider.exportCurrent": "ਮੌਜੂਦਾ ਵਰਜਨ ਇੰਝ ਐਕਸਪੋਰਟ ਕਰੋ:", "timeslider.exportCurrent": "ਮੌਜੂਦਾ ਵਰਜਨ ਇੰਝ ਐਕਸਪੋਰਟ ਕਰੋ:",
"timeslider.version": "ਵਰਜ਼ਨ {{version}}", "timeslider.version": "ਵਰਜ਼ਨ {{version}}",
"timeslider.saved": "{{day}} {{month}} {{year}} ਨੂੰ ਸੰਭਾਲਿਆ", "timeslider.saved": "{{day}} {{month}} {{year}} ਨੂੰ ਸੰਭਾਲਿਆ",
@ -123,18 +110,18 @@
"timeslider.month.november": "ਨਵੰਬਰ", "timeslider.month.november": "ਨਵੰਬਰ",
"timeslider.month.december": "ਦਸੰਬਰ", "timeslider.month.december": "ਦਸੰਬਰ",
"timeslider.unnamedauthors": "{{num}} ਬੇਨਾਮ {[plural(num) one: ਲੇਖਕ, other: ਲੇਖਕ ]}", "timeslider.unnamedauthors": "{{num}} ਬੇਨਾਮ {[plural(num) one: ਲੇਖਕ, other: ਲੇਖਕ ]}",
"pad.savedrevs.marked": "ਇਹ ਦੁਹਰਾਅ ਨੂੰ ਹੁਣ ਸੰਭਾਲੇ ਹੋਏ ਦੁਹਰਾਅ ਵਜੋਂ ਮੰਨਿਆ ਗਿਆ ਹੈ", "pad.savedrevs.marked": "ਇਹ ਰੀਵਿਜ਼ਨ ਨੂੰ ਹੁਣ ਸੰਭਾਲੇ ਹੋਏ ਰੀਵਿਜ਼ਨ ਵਜੋਂ ਮੰਨਿਆ ਗਿਆ ਹੈ",
"pad.savedrevs.timeslider": "ਤੁਸੀੰ ਸਾੰਭੀਆੰ ਹੋਈਆੰ ਵਰਜਨਾੰ ਸਮਾੰਸਲਾਈਡਰ ਤੇ ਜਾ ਕੇ ਵੇਖ ਸਕਦੇ ਹੋ", "pad.savedrevs.timeslider": "ਤੁਸੀੰ ਸਾੰਭੀਆੰ ਹੋਈਆੰ ਵਰਜਨਾੰ ਸਮਾੰਸਲਾਈਡਰ ਤੇ ਜਾ ਕੇ ਵੇਖ ਸਕਦੇ ਹੋ",
"pad.userlist.entername": "ਆਪਣਾ ਨਾਂ ਦਿਉ", "pad.userlist.entername": "ਆਪਣਾ ਨਾਂ ਦਿਉ",
"pad.userlist.unnamed": "ਬੇਨਾਮ", "pad.userlist.unnamed": "ਬੇਨਾਮ",
"pad.editbar.clearcolors": "ਪੂਰੇ ਦਸਾਤਵੇਜ਼ ਉੱਤੇ ਪਰਮਾਣਕਿਤਾ ਰੰਗ ਸਾਫ਼ ਕਰਨੇ ਹਨ?", "pad.editbar.clearcolors": "ਪੂਰੇ ਦਸਾਤਵੇਜ਼ ਉੱਤੇ ਪਰਮਾਣਕਿਤਾ ਰੰਗ ਸਾਫ਼ ਕਰਨੇ ਹਨ?",
"pad.impexp.importbutton": "ਹੁਣੇ ਦਰਾਮਦ ਕਰੋ", "pad.impexp.importbutton": "ਹੁਣੇ ਇੰਪੋਰਟ ਕਰੋ",
"pad.impexp.importing": "...ਇੰਪੋਰਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ", "pad.impexp.importing": "...ਇੰਪੋਰਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ",
"pad.impexp.confirmimport": "ਕੋਈ ਫ਼ਾਈਲ ਦਰਾਮਦ ਕਾਰਨ ਨਾਲ਼ ਪੈਡ ਦੀ ਮੌਜੂਦਾ ਲਿਖਤ ਉੱਤੇ ਲਿਖਿਆ ਜਾਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਸੱਚੀਂ ਇਹ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", "pad.impexp.confirmimport": "ਕੋਈ ਫ਼ਾਈਲ ਦਰਾਮਦ ਕਾਰਨ ਨਾਲ਼ ਪੈਡ ਦੀ ਮੌਜੂਦਾ ਲਿਖਤ ਉੱਤੇ ਲਿਖਿਆ ਜਾਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਸੱਚੀਂ ਇਹ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?",
"pad.impexp.convertFailed": "ਅਸੀਂ ਇਸ ਫ਼ਾਈਲ ਦੀ ਦਰਾਮਦ ਨਹੀਂ ਕਰ ਸਕੇ। ਮਿਹਰਬਾਨੀ ਕਰਕੇ ਕੋਈ ਵੱਖਰੀ ਦਸਤਾਵੇਜ਼ੀ ਰੂਪ-ਰੇਖਾ ਵਰਤੋ ਜਾਂ ਹੱਥੀਂ ਨਕਲ-ਚੇਪੀ ਕਰੋ।", "pad.impexp.convertFailed": "ਅਸੀਂ ਇਸ ਫ਼ਾਈਲ ਦੀ ਦਰਾਮਦ ਨਹੀਂ ਕਰ ਸਕੇ। ਮਿਹਰਬਾਨੀ ਕਰਕੇ ਕੋਈ ਵੱਖਰੀ ਦਸਤਾਵੇਜ਼ੀ ਰੂਪ-ਰੇਖਾ ਵਰਤੋ ਜਾਂ ਹੱਥੀਂ ਨਕਲ-ਚੇਪੀ ਕਰੋ।",
"pad.impexp.padHasData": "ਅਸੀ ਇਸ ਫਾਈਲ ਨੂੰ ਦਰਾਮਦ ਨਹੀੰ ਕਰ ਸਕੇ ਕਿਉੰਕਿ ਇਸ ਕਾਗਜ਼ ਉੱਤੇ ਪਹਿਲਾਂ ਹੀ ਤਬਦੀਲੀਆਂ ਕੀਤੀਆਂ ਜਾ ਚੁਕੀਆਂ ਹਨ, ਕਿਰਪਾ ਕਰਕੇ ਨਵੇਂ ਕਾਗਜ਼ ਵਿਚ ਦਰਾਮਦ ਕਰੋ", "pad.impexp.padHasData": "ਅਸੀ ਇਸ ਫਾਈਲ ਨੂੰ ਆਯਾਤ ਨਹੀੰ ਕਰ ਸਕੇ ਕਿਉੰਕਿ ਇਸ ਪੈਡ ਉੱਤੇ ਪਹਿਲਾੰ ਹੀ ਤਬਦੀਲੀਆੰ ਕੀਤੀਆੰ ਜਾ ਚੁਕੀਆੰ ਹਨ, ਕਿਰਪਾ ਕਰਕੇ ਨਵੇੰ ਪੈਡ ਵਿਚ ਆਯਾਤ ਕਰੋ",
"pad.impexp.uploadFailed": "ਅੱਪਲੋਡ ਲਈ ਫੇਲ੍ਹ ਹੈ, ਫੇਰ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜੀ।", "pad.impexp.uploadFailed": "ਅੱਪਲੋਡ ਲਈ ਫੇਲ੍ਹ ਹੈ, ਫੇਰ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜੀ।",
"pad.impexp.importfailed": "ਦਰਾਮਦ ਨਾਕਾਮ", "pad.impexp.importfailed": "ਇੰਪੋਰਟ ਫੇਲ੍ਹ ਹੈ",
"pad.impexp.copypaste": "ਕਾਪੀ ਕਰੋ ਚੇਪੋ ਜੀ", "pad.impexp.copypaste": "ਕਾਪੀ ਕਰੋ ਚੇਪੋ ਜੀ",
"pad.impexp.exportdisabled": "{{type}} ਫਾਰਮੈਟ ਵਜੋਂ ਬਰਾਮਦ ਕਰਨਾ ਬੰਦ ਹੈ। ਵੇਰਵੇ ਵਾਸਤੇ ਆਪਣੇ ਸਿਸਟਮ ਦੇ ਪਰਬੰਧਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।" "pad.impexp.exportdisabled": "{{type}} ਫਾਰਮੈਟ ਵਜੋਂ ਬਰਾਮਦ ਕਰਨਾ ਬੰਦ ਹੈ। ਵੇਰਵੇ ਵਾਸਤੇ ਆਪਣੇ ਸਿਸਟਮ ਦੇ ਪਰਬੰਧਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"
} }

View file

@ -71,8 +71,6 @@
"pad.settings.rtlcheck": "Ël contnù, dev-lo esse lesù da drita a snistra?", "pad.settings.rtlcheck": "Ël contnù, dev-lo esse lesù da drita a snistra?",
"pad.settings.fontType": "Sòrt ëd caràter:", "pad.settings.fontType": "Sòrt ëd caràter:",
"pad.settings.language": "Lenga:", "pad.settings.language": "Lenga:",
"pad.settings.deletePad": "Eliminé ël blochet",
"pad.delete.confirm": "Veul-lo për da bon eliminé cost blochet?",
"pad.settings.about": "A propòsit", "pad.settings.about": "A propòsit",
"pad.settings.poweredBy": "Potensià da", "pad.settings.poweredBy": "Potensià da",
"pad.importExport.import_export": "Amporté/Esporté", "pad.importExport.import_export": "Amporté/Esporté",

View file

@ -23,22 +23,22 @@
] ]
}, },
"admin.page-title": "Painel administrativo - Etherpad", "admin.page-title": "Painel administrativo - Etherpad",
"admin_plugins": "Gerenciador de complementos", "admin_plugins": "Gerente de complementos",
"admin_plugins.available": "Plugins disponíveis", "admin_plugins.available": "Plugins disponíveis",
"admin_plugins.available_not-found": "Nenhum plugin encontrado.", "admin_plugins.available_not-found": "Nenhuma complementos encontrado.",
"admin_plugins.available_fetching": "Buscando…", "admin_plugins.available_fetching": "Buscando…",
"admin_plugins.available_install.value": "Instalar", "admin_plugins.available_install.value": "Instalar",
"admin_plugins.available_search.placeholder": "Procure plugins para instalar", "admin_plugins.available_search.placeholder": "Procure por plug-ins para instalar",
"admin_plugins.description": "Descrição", "admin_plugins.description": "Descrição",
"admin_plugins.installed": "Plugins instalados", "admin_plugins.installed": "Complementos instalados",
"admin_plugins.installed_fetching": "Buscando plugins instalados…", "admin_plugins.installed_fetching": "Buscando plug-ins instalados…",
"admin_plugins.installed_nothing": "Você ainda não instalou nenhum plugin.", "admin_plugins.installed_nothing": "Você ainda não instalou nenhum plug-in.",
"admin_plugins.installed_uninstall.value": "Desinstalar", "admin_plugins.installed_uninstall.value": "Desinstalar",
"admin_plugins.last-update": "Última atualização", "admin_plugins.last-update": "Última atualização",
"admin_plugins.name": "Nome", "admin_plugins.name": "Nome",
"admin_plugins.page-title": "Gerenciador de plugins - Etherpad", "admin_plugins.page-title": "Gerenciador de plug-ins - Etherpad",
"admin_plugins.version": "Versão", "admin_plugins.version": "Versão",
"admin_plugins_info": "Resolução de problemas", "admin_plugins_info": "Informações sobre solução",
"admin_plugins_info.hooks": "Ganchos instalados", "admin_plugins_info.hooks": "Ganchos instalados",
"admin_plugins_info.hooks_client": "Ganchos do lado do cliente", "admin_plugins_info.hooks_client": "Ganchos do lado do cliente",
"admin_plugins_info.hooks_server": "Ganchos do lado do servidor", "admin_plugins_info.hooks_server": "Ganchos do lado do servidor",
@ -90,8 +90,6 @@
"pad.settings.fontType": "Tipo de fonte:", "pad.settings.fontType": "Tipo de fonte:",
"pad.settings.fontType.normal": "Normal", "pad.settings.fontType.normal": "Normal",
"pad.settings.language": "Idioma:", "pad.settings.language": "Idioma:",
"pad.settings.deletePad": "Apagar Pad",
"pad.delete.confirm": "Tem certeza de que quer deletar este pad?",
"pad.settings.about": "Sobre", "pad.settings.about": "Sobre",
"pad.settings.poweredBy": "Fornecido por", "pad.settings.poweredBy": "Fornecido por",
"pad.importExport.import_export": "Importar/Exportar", "pad.importExport.import_export": "Importar/Exportar",
@ -129,7 +127,7 @@
"pad.modals.deleted": "Excluído.", "pad.modals.deleted": "Excluído.",
"pad.modals.deleted.explanation": "Esta nota foi removida.", "pad.modals.deleted.explanation": "Esta nota foi removida.",
"pad.modals.rateLimited": "Limitado.", "pad.modals.rateLimited": "Limitado.",
"pad.modals.rateLimited.explanation": "Você enviou muitas mensagens para esta nota por isso será desconectado.", "pad.modals.rateLimited.explanation": "Você enviou muitas mensagens para este pad por isso será desconectado.",
"pad.modals.rejected.explanation": "O servidor rejeitou uma mensagem que foi enviada pelo seu navegador.", "pad.modals.rejected.explanation": "O servidor rejeitou uma mensagem que foi enviada pelo seu navegador.",
"pad.modals.rejected.cause": "O server pode ter sido atualizado enquanto visualizava esta nota, ou talvez seja apenas um bug do Etherpad. Tenta recarregar a página.", "pad.modals.rejected.cause": "O server pode ter sido atualizado enquanto visualizava esta nota, ou talvez seja apenas um bug do Etherpad. Tenta recarregar a página.",
"pad.modals.disconnected": "Você foi desconectado.", "pad.modals.disconnected": "Você foi desconectado.",
@ -144,7 +142,7 @@
"pad.chat.loadmessages": "Carregar mais mensagens", "pad.chat.loadmessages": "Carregar mais mensagens",
"pad.chat.stick.title": "Cole o bate-papo na tela", "pad.chat.stick.title": "Cole o bate-papo na tela",
"pad.chat.writeMessage.placeholder": "Escreva sua mensagem aqui", "pad.chat.writeMessage.placeholder": "Escreva sua mensagem aqui",
"timeslider.followContents": "Siga as atualizações de conteúdo da nota", "timeslider.followContents": "Siga as atualizações de conteúdo do pad",
"timeslider.pageTitle": "Linha do tempo de {{appTitle}}", "timeslider.pageTitle": "Linha do tempo de {{appTitle}}",
"timeslider.toolbar.returnbutton": "Retornar para a nota", "timeslider.toolbar.returnbutton": "Retornar para a nota",
"timeslider.toolbar.authors": "Autores:", "timeslider.toolbar.authors": "Autores:",
@ -153,9 +151,9 @@
"timeslider.exportCurrent": "Exportar a versão atual em formato:", "timeslider.exportCurrent": "Exportar a versão atual em formato:",
"timeslider.version": "Versão {{version}}", "timeslider.version": "Versão {{version}}",
"timeslider.saved": "Salvo em {{day}} de {{month}} de {{year}}", "timeslider.saved": "Salvo em {{day}} de {{month}} de {{year}}",
"timeslider.playPause": "Reproduzir / Pausar conteúdos da Nota", "timeslider.playPause": "Reproduzir / Pausar conteúdo no Pad",
"timeslider.backRevision": "Voltar a uma revisão anterior nesta Nota", "timeslider.backRevision": "Voltar a uma revisão anterior neste Pad",
"timeslider.forwardRevision": "Ir a uma revisão posterior nesta Nota", "timeslider.forwardRevision": "Ir a uma revisão posterior neste Pad",
"timeslider.dateformat": "{{day}}/{{month}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}", "timeslider.dateformat": "{{day}}/{{month}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}",
"timeslider.month.january": "Janeiro", "timeslider.month.january": "Janeiro",
"timeslider.month.february": "Fevereiro", "timeslider.month.february": "Fevereiro",

View file

@ -87,8 +87,6 @@
"pad.settings.fontType": "Тип шрифта:", "pad.settings.fontType": "Тип шрифта:",
"pad.settings.fontType.normal": "Обычный", "pad.settings.fontType.normal": "Обычный",
"pad.settings.language": "Язык:", "pad.settings.language": "Язык:",
"pad.settings.deletePad": "Удалить документ",
"pad.delete.confirm": "Вы действительно хотите удалить этот документ?",
"pad.settings.about": "О проекте", "pad.settings.about": "О проекте",
"pad.settings.poweredBy": "Проект основан на", "pad.settings.poweredBy": "Проект основан на",
"pad.importExport.import_export": "Импорт/экспорт", "pad.importExport.import_export": "Импорт/экспорт",

View file

@ -77,8 +77,6 @@
"pad.settings.fontType": "Vrsta pisave:", "pad.settings.fontType": "Vrsta pisave:",
"pad.settings.fontType.normal": "Normalno", "pad.settings.fontType.normal": "Normalno",
"pad.settings.language": "Jezik:", "pad.settings.language": "Jezik:",
"pad.settings.deletePad": "Izbriši ploščico",
"pad.delete.confirm": "Res želite izbrisati to ploščico?",
"pad.settings.about": "Kolofon", "pad.settings.about": "Kolofon",
"pad.settings.poweredBy": "Omogoča", "pad.settings.poweredBy": "Omogoča",
"pad.importExport.import_export": "Uvoz/Izvoz", "pad.importExport.import_export": "Uvoz/Izvoz",

View file

@ -1,7 +1,6 @@
{ {
"@metadata": { "@metadata": {
"authors": [ "authors": [
"Aca",
"Acamicamacaraca", "Acamicamacaraca",
"Aktron", "Aktron",
"BadDog", "BadDog",

View file

@ -76,8 +76,6 @@
"pad.settings.fontType": "Typsnitt:", "pad.settings.fontType": "Typsnitt:",
"pad.settings.fontType.normal": "Normal", "pad.settings.fontType.normal": "Normal",
"pad.settings.language": "Språk:", "pad.settings.language": "Språk:",
"pad.settings.deletePad": "Radera block",
"pad.delete.confirm": "Vill du verkligen radera detta block?",
"pad.settings.about": "Om", "pad.settings.about": "Om",
"pad.settings.poweredBy": "Drivs av", "pad.settings.poweredBy": "Drivs av",
"pad.importExport.import_export": "Importera/Exportera", "pad.importExport.import_export": "Importera/Exportera",

View file

@ -3,7 +3,6 @@
"authors": [ "authors": [
"Aefgh39622", "Aefgh39622",
"Andibecker", "Andibecker",
"Ekminarin",
"Patsagorn Y.", "Patsagorn Y.",
"Trisorn Triboon" "Trisorn Triboon"
] ]
@ -122,7 +121,7 @@
"pad.share.readonly": "อ่านเท่านั้น", "pad.share.readonly": "อ่านเท่านั้น",
"pad.share.link": "ลิงก์", "pad.share.link": "ลิงก์",
"pad.share.emebdcode": "URL แบบฝังตัว", "pad.share.emebdcode": "URL แบบฝังตัว",
"pad.chat": "แช", "pad.chat": "แช",
"pad.chat.title": "เปิดการแชทสำหรับแผ่นจดบันทึกนี้", "pad.chat.title": "เปิดการแชทสำหรับแผ่นจดบันทึกนี้",
"pad.chat.loadmessages": "โหลดข้อความเพิ่มเติม", "pad.chat.loadmessages": "โหลดข้อความเพิ่มเติม",
"pad.chat.stick.title": "ปักการสนทนาไว้บนหน้าจอ", "pad.chat.stick.title": "ปักการสนทนาไว้บนหน้าจอ",

View file

@ -7,7 +7,6 @@
"Grkn gll", "Grkn gll",
"Hedda", "Hedda",
"Joseph", "Joseph",
"Leo",
"McAang", "McAang",
"Meelo", "Meelo",
"MuratTheTurkish", "MuratTheTurkish",
@ -83,8 +82,6 @@
"pad.settings.fontType": "Yazı tipi:", "pad.settings.fontType": "Yazı tipi:",
"pad.settings.fontType.normal": "Olağan", "pad.settings.fontType.normal": "Olağan",
"pad.settings.language": "Dil:", "pad.settings.language": "Dil:",
"pad.settings.deletePad": "Silme Defteri",
"pad.delete.confirm": "Bu defteri gerçekten silmek istiyor musunuz?",
"pad.settings.about": "Hakkında", "pad.settings.about": "Hakkında",
"pad.settings.poweredBy": "Destekleyen:", "pad.settings.poweredBy": "Destekleyen:",
"pad.importExport.import_export": "İçe/Dışa aktar", "pad.importExport.import_export": "İçe/Dışa aktar",

View file

@ -1,14 +1,13 @@
{ {
"@metadata": { "@metadata": {
"authors": [ "authors": [
"Candalua",
"Fierodelveneto" "Fierodelveneto"
] ]
}, },
"index.newPad": "Novo Pad", "index.newPad": "Novo Pad",
"index.createOpenPad": "O creare o verxare on Pad co'l nome:", "index.createOpenPad": "O creare o verxare on Pad co'l nome:",
"pad.toolbar.bold.title": "Groseto (Ctrl-B)", "pad.toolbar.bold.title": "Groseto (Ctrl-B)",
"pad.toolbar.italic.title": "Corsivo (Ctrl-I)", "pad.toolbar.italic.title": "Corivo (Ctrl-I)",
"pad.toolbar.underline.title": "Sotolineà (Ctrl-U)", "pad.toolbar.underline.title": "Sotolineà (Ctrl-U)",
"pad.toolbar.strikethrough.title": "Barà (Ctrl+5)", "pad.toolbar.strikethrough.title": "Barà (Ctrl+5)",
"pad.toolbar.ol.title": "Ełenco numarà (Ctrl+Shift+N)", "pad.toolbar.ol.title": "Ełenco numarà (Ctrl+Shift+N)",

View file

@ -16,7 +16,6 @@
"Shangkuanlc", "Shangkuanlc",
"Shizhao", "Shizhao",
"Stang", "Stang",
"TFX202X",
"VulpesVulpes825", "VulpesVulpes825",
"Yfdyh000", "Yfdyh000",
"乌拉跨氪", "乌拉跨氪",
@ -93,8 +92,6 @@
"pad.settings.fontType": "字体类型:", "pad.settings.fontType": "字体类型:",
"pad.settings.fontType.normal": "正常", "pad.settings.fontType.normal": "正常",
"pad.settings.language": "语言:", "pad.settings.language": "语言:",
"pad.settings.deletePad": "删除记事本",
"pad.delete.confirm": "您确定要删除此记事本吗?",
"pad.settings.about": "关于", "pad.settings.about": "关于",
"pad.settings.poweredBy": "技术支持来自", "pad.settings.poweredBy": "技术支持来自",
"pad.importExport.import_export": "导入/导出", "pad.importExport.import_export": "导入/导出",

View file

@ -82,8 +82,6 @@
"pad.settings.fontType": "字型類型:", "pad.settings.fontType": "字型類型:",
"pad.settings.fontType.normal": "正常", "pad.settings.fontType.normal": "正常",
"pad.settings.language": "語言:", "pad.settings.language": "語言:",
"pad.settings.deletePad": "刪除記事本",
"pad.delete.confirm": "您確定要刪除此記事本?",
"pad.settings.about": "關於", "pad.settings.about": "關於",
"pad.settings.poweredBy": "技術支援來自", "pad.settings.poweredBy": "技術支援來自",
"pad.importExport.import_export": "導入/匯出", "pad.importExport.import_export": "導入/匯出",

View file

@ -19,10 +19,8 @@
* limitations under the License. * limitations under the License.
*/ */
import {deserializeOps} from '../../static/js/Changeset'; const Changeset = require('../../static/js/Changeset');
import ChatMessage from '../../static/js/ChatMessage'; const ChatMessage = require('../../static/js/ChatMessage');
import {Builder} from "../../static/js/Builder";
import {Attribute} from "../../static/js/types/Attribute";
const CustomError = require('../utils/customError'); const CustomError = require('../utils/customError');
const padManager = require('./PadManager'); const padManager = require('./PadManager');
const padMessageHandler = require('../handler/PadMessageHandler'); const padMessageHandler = require('../handler/PadMessageHandler');
@ -565,11 +563,11 @@ exports.restoreRevision = async (padID: string, rev: number, authorId = '') => {
const oldText = pad.text(); const oldText = pad.text();
atext.text += '\n'; atext.text += '\n';
const eachAttribRun = (attribs: string, func:Function) => { const eachAttribRun = (attribs: string[], func:Function) => {
let textIndex = 0; let textIndex = 0;
const newTextStart = 0; const newTextStart = 0;
const newTextEnd = atext.text.length; const newTextEnd = atext.text.length;
for (const op of deserializeOps(attribs)) { for (const op of Changeset.deserializeOps(attribs)) {
const nextIndex = textIndex + op.chars; const nextIndex = textIndex + op.chars;
if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) { if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) {
func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs);
@ -579,10 +577,10 @@ exports.restoreRevision = async (padID: string, rev: number, authorId = '') => {
}; };
// create a new changeset with a helper builder object // create a new changeset with a helper builder object
const builder = new Builder(oldText.length); const builder = Changeset.builder(oldText.length);
// assemble each line into the builder // assemble each line into the builder
eachAttribRun(atext.attribs, (start: number, end: number, attribs:Attribute[]) => { eachAttribRun(atext.attribs, (start: number, end: number, attribs:string[]) => {
builder.insert(atext.text.substring(start, end), attribs); builder.insert(atext.text.substring(start, end), attribs);
}); });

View file

@ -21,8 +21,8 @@
const db = require('./DB'); const db = require('./DB');
const CustomError = require('../utils/customError'); const CustomError = require('../utils/customError');
const hooks = require('../../static/js/pluginfw/hooks'); const hooks = require('../../static/js/pluginfw/hooks.js');
import padutils, {randomString} from "../../static/js/pad_utils"; const {randomString, padutils: {warnDeprecated}} = require('../../static/js/pad_utils');
exports.getColorPalette = () => [ exports.getColorPalette = () => [
'#ffc7c7', '#ffc7c7',
@ -169,7 +169,7 @@ exports.getAuthorId = async (token: string, user: object) => {
* @param {String} token The token * @param {String} token The token
*/ */
exports.getAuthor4Token = async (token: string) => { exports.getAuthor4Token = async (token: string) => {
padutils.warnDeprecated( warnDeprecated(
'AuthorManager.getAuthor4Token() is deprecated; use AuthorManager.getAuthorId() instead'); 'AuthorManager.getAuthor4Token() is deprecated; use AuthorManager.getAuthorId() instead');
return await getAuthor4Token(token); return await getAuthor4Token(token);
}; };

View file

@ -21,7 +21,7 @@
* limitations under the License. * limitations under the License.
*/ */
import {Database} from 'ueberdb2'; import ueberDB from 'ueberdb2';
const settings = require('../utils/Settings'); const settings = require('../utils/Settings');
import log4js from 'log4js'; import log4js from 'log4js';
const stats = require('../stats') const stats = require('../stats')
@ -37,7 +37,7 @@ exports.db = null;
* Initializes the database with the settings provided by the settings module * Initializes the database with the settings provided by the settings module
*/ */
exports.init = async () => { exports.init = async () => {
exports.db = new Database(settings.dbType, settings.dbSettings, null, logger); exports.db = new ueberDB.Database(settings.dbType, settings.dbSettings, null, logger);
await exports.db.init(); await exports.db.init();
if (exports.db.metrics != null) { if (exports.db.metrics != null) {
for (const [metric, value] of Object.entries(exports.db.metrics)) { for (const [metric, value] of Object.entries(exports.db.metrics)) {

Some files were not shown because too many files have changed in this diff Show more