Compare commits

..

3 Commits

Author SHA1 Message Date
Michael Telatynski
4bc6f4dafa Make sonar happier 2023-05-24 12:36:20 +01:00
Michael Telatynski
84ffc7e2e6 Iterate 2023-05-24 12:01:56 +01:00
Michael Telatynski
344d473e9b Don't double up app badge on Windows 2023-05-24 11:35:09 +01:00
121 changed files with 9705 additions and 9989 deletions

View File

@@ -2,11 +2,11 @@ module.exports = {
plugins: ["matrix-org"],
extends: [".eslintrc.js"],
parserOptions: {
project: ["playwright/tsconfig.json"],
project: ["test/tsconfig.json"],
},
overrides: [
{
files: ["playwright/**/*.ts"],
files: ["test/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
rules: {
// Things we do that break the ideal style

9
.github/CODEOWNERS vendored
View File

@@ -1,5 +1,4 @@
* @element-hq/element-web-reviewers
/.github/workflows/** @element-hq/element-web-team
/package.json @element-hq/element-web-team
/yarn.lock @element-hq/element-web-team
/src/i18n/strings
* @vector-im/element-web
/.github/workflows/** @vector-im/element-web-app-team
/package.json @vector-im/element-web-app-team
/yarn.lock @vector-im/element-web-app-team

View File

@@ -5,3 +5,9 @@
- [ ] Ensure your code works with manual testing
- [ ] Linter and other CI checks pass
- [ ] Sign-off given on the changes (see [CONTRIBUTING.md](https://github.com/vector-im/element-desktop/blob/develop/CONTRIBUTING.md))
<!--
If you would like to specify text for the changelog entry other than your PR title, add the following:
Notes: Add super cool feature
-->

31
.github/labels.yml vendored
View File

@@ -1,31 +0,0 @@
- name: "A-Install"
color: "72A447"
- name: "A-Seshat"
color: "8262BE"
- name: "A-Update"
color: "17BE67"
- name: "Story"
description: "A change to the product that generates user value on its own. Unit of delivery."
color: "0BAC47"
- name: "X-Breaking-Change"
color: "ff7979"
- name: "Z-Arch"
color: "D601BE"
- name: "Z-ARM"
color: "5DEC5B"
- name: "Z-Flatpak"
color: "0CA856"
- name: "Z-Linux"
color: "7B4A9C"
- name: "Z-macOS"
color: "500605"
- name: "Z-Official"
color: "1D2B20"
- name: "Z-Snap"
color: "29CD95"
- name: "Z-Suse"
color: "79D07B"
- name: "Z-Wayland"
color: "94C519"
- name: "Z-Windows"
color: "0632DE"

View File

@@ -1 +0,0 @@
_extends: element-hq/element-web

View File

@@ -23,7 +23,7 @@ jobs:
)
)
steps:
- uses: tibdex/backport@9565281eda0731b1d20c4025c43339fb0a23812e # v2
- uses: tibdex/backport@2e217641d82d02ba0603f46b1aeedefb258890ac
with:
labels_template: "<%= JSON.stringify([...labels, 'X-Release-Blocker']) %>"
# We can't use GITHUB_TOKEN here or CI won't run on the new PR

View File

@@ -3,9 +3,6 @@ on:
# Nightly build
schedule:
- cron: "0 9 * * *"
# Release build
release:
types: [published]
# Manual nightly & release
workflow_dispatch:
inputs:
@@ -22,8 +19,13 @@ on:
required: true
type: boolean
default: true
windows:
description: Build Windows
windows_32bit:
description: Build Windows 32-bit
required: true
type: boolean
default: true
windows_64bit:
description: Build Windows 64-bit
required: true
type: boolean
default: true
@@ -37,7 +39,7 @@ on:
required: true
type: boolean
default: true
run-name: Element ${{ inputs.mode != 'release' && github.event_name != 'release' && 'Nightly' || 'Desktop' }}
run-name: Element ${{ inputs.mode == 'release' && 'Desktop' || 'Nightly' }}
concurrency: ${{ github.workflow }}
env:
R2_BUCKET: ${{ vars.R2_BUCKET }}
@@ -45,27 +47,36 @@ jobs:
prepare:
uses: ./.github/workflows/build_prepare.yaml
with:
config: element.io/${{ inputs.mode || (github.event_name == 'release' && 'release') || 'nightly' }}
version: ${{ (inputs.mode != 'release' && github.event_name != 'release') && 'develop' || '' }}
nightly: ${{ inputs.mode != 'release' && github.event_name != 'release' }}
deploy: ${{ inputs.deploy || (github.event_name != 'workflow_dispatch' && github.event.release.prerelease != true) }}
config: element.io/${{ inputs.mode || 'nightly' }}
version: ${{ inputs.mode != 'release' && 'develop' || '' }}
nightly: ${{ inputs.mode != 'release' }}
secrets:
CF_R2_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
CF_R2_TOKEN: ${{ secrets.CF_R2_TOKEN }}
windows:
if: github.event_name != 'workflow_dispatch' || inputs.windows
windows_32bit:
if: github.event_name != 'workflow_dispatch' || inputs.windows_32bit
needs: prepare
name: Windows ${{ matrix.arch }}
strategy:
matrix:
arch: [ia32, x64]
name: Windows 32-bit
uses: ./.github/workflows/build_windows.yaml
secrets: inherit
with:
sign: true
arch: ${{ matrix.arch }}
version: ${{ needs.prepare.outputs.nightly-version }}
deploy-mode: true
arch: x86
version: ${{ needs.prepare.outputs.win32-x86-version }}
windows_64bit:
if: github.event_name != 'workflow_dispatch' || inputs.windows_64bit
needs: prepare
name: Windows 64-bit
uses: ./.github/workflows/build_windows.yaml
secrets: inherit
with:
sign: true
deploy-mode: true
arch: x64
version: ${{ needs.prepare.outputs.win32-x64-version }}
macos:
if: github.event_name != 'workflow_dispatch' || inputs.macos
@@ -75,170 +86,86 @@ jobs:
secrets: inherit
with:
sign: true
base-url: https://packages.element.io/${{ needs.prepare.outputs.packages-dir }}
version: ${{ needs.prepare.outputs.nightly-version }}
deploy-mode: true
base-url: https://packages.element.io/${{ inputs.mode == 'release' && 'desktop' || 'nightly' }}
version: ${{ needs.prepare.outputs.macos-version }}
# We do not put these calls into deploy-mode as we do not want it to add to the packages.element.io artifact
# We ship this build via reprepro only
linux:
if: github.event_name != 'workflow_dispatch' || inputs.linux
needs: prepare
name: Linux ${{ matrix.arch }} (sqlcipher ${{ matrix.sqlcipher }})
name: Linux ${{ matrix.arch }} (sqlcipher system)
strategy:
matrix:
arch: [amd64, arm64]
sqlcipher: [system, static]
exclude:
- arch: arm64
sqlcipher: static
uses: ./.github/workflows/build_linux.yaml
with:
arch: ${{ matrix.arch }}
config: ${{ needs.prepare.outputs.config }}
sqlcipher: ${{ matrix.sqlcipher }}
version: ${{ needs.prepare.outputs.nightly-version }}
config: element.io/${{ inputs.mode || 'nightly' }}
sqlcipher: system
version: ${{ needs.prepare.outputs.linux-version }}
# We ship the static build via static tarball only
linux_static:
if: github.event_name != 'workflow_dispatch' || inputs.linux
needs: prepare
name: Linux (sqlcipher static)
uses: ./.github/workflows/build_linux.yaml
with:
arch: amd64
deploy-mode: true
config: element.io/${{ inputs.mode || 'nightly' }}
sqlcipher: static
version: ${{ needs.prepare.outputs.linux-version }}
# This deploy job only handles Windows, macOS & linux_static as those are stateless and static.
# Linux will be deployed via reprepro after it, but we list it as a dependency to abort if it fails.
deploy:
needs:
- prepare
- macos
- linux
- windows
- linux_static
- windows_32bit
- windows_64bit
runs-on: ubuntu-latest
name: ${{ needs.prepare.outputs.deploy == 'true' && 'Deploy' || 'Deploy (dry-run)' }}
if: always() && !failure() && !cancelled()
environment: ${{ needs.prepare.outputs.deploy == 'true' && 'packages.element.io' || '' }}
name: Deploy
if: github.event_name != 'workflow_dispatch' || (inputs.deploy && (inputs.macos || inputs.windows_32bit || inputs.windows_64bit))
environment: packages.element.io
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Prepare artifacts for deployment
run: |
# Windows
for arch in x64 ia32 arm64
do
if [ -d "win-$arch" ]; then
mkdir -p packages.element.io/{install,update}/win32/$arch
mv win-$arch/squirrel-windows*/*.exe "packages.element.io/install/win32/$arch/"
mv win-$arch/squirrel-windows*/*.nupkg "packages.element.io/update/win32/$arch/"
mv win-$arch/squirrel-windows*/RELEASES "packages.element.io/update/win32/$arch/"
fi
done
# macOS
if [ -d macos ]; then
mkdir -p packages.element.io/{install,update}/macos
mv macos/*.dmg packages.element.io/install/macos/
mv macos/*-mac.zip packages.element.io/update/macos/
mv macos/*.json packages.element.io/update/macos/
fi
# Linux
if [ -d linux-amd64-sqlcipher-static ]; then
mkdir -p packages.element.io/install/linux/glibc-x86-64
mv linux-amd64-sqlcipher-static/*.tar.gz packages.element.io/install/linux/glibc-x86-64
fi
# We don't wish to store the installer for every nightly ever, so we only keep the latest
- name: "[Nightly] Strip version from installer file"
if: needs.prepare.outputs.nightly-version != ''
run: |
# Windows
for arch in x64 ia32 arm64
do
[ -d "win-$arch" ] && mv packages.element.io/install/win32/$arch/{*,"Element Nightly Setup"}.exe
done
# macOS
[ -d macos ] && mv packages.element.io/install/macos/{*,"Element Nightly"}.dmg
# Linux
[ -d linux-amd64-sqlcipher-static ] && mv packages.element.io/install/linux/glibc-x86-64/{*,element-desktop-nightly}.tar.gz
- name: "[Release] Prepare release latest symlink"
if: needs.prepare.outputs.nightly-version == ''
run: |
# Windows
for arch in x64 ia32 arm64
do
if [ -d "win-$arch" ]; then
pushd packages.element.io/install/win32/$arch
ln -s "$(find . -type f -iname "*.exe" | xargs -0 -n1 -- basename)" "Element Setup.exe"
popd
fi
done
# macOS
if [ -d macos ]; then
pushd packages.element.io/install/macos
ln -s "$(find . -type f -iname "*.dmg" | xargs -0 -n1 -- basename)" "Element.dmg"
popd
fi
# Linux
if [ -d linux-amd64-sqlcipher-static ]; then
pushd packages.element.io/install/linux/glibc-x86-64
ln -s "$(find . -type f -iname "*.tar.gz" | xargs -0 -n1 -- basename)" "element-desktop.tar.gz"
popd
fi
- name: Stash packages.element.io
if: needs.prepare.outputs.deploy == 'false'
uses: actions/upload-artifact@v4
uses: actions/download-artifact@v3
with:
name: packages.element.io
path: packages.element.io
- name: Deploy artifacts
if: needs.prepare.outputs.deploy == 'true'
run: |
aws s3 cp --recursive packages.element.io/ s3://$R2_BUCKET/$DEPLOYMENT_DIR --endpoint-url $R2_URL --region auto
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
R2_URL: ${{ vars.CF_R2_S3_API }}
DEPLOYMENT_DIR: ${{ needs.prepare.outputs.packages-dir }}
DEPLOYMENT_DIR: ${{ inputs.mode == 'release' && 'desktop' || 'nightly' }}
- name: Notify packages.element.io of new files
if: needs.prepare.outputs.deploy == 'true'
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3
uses: peter-evans/repository-dispatch@26b39ed245ab8f31526069329e112ab2fb224588 # v2
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
repository: element-hq/packages.element.io
repository: vector-im/packages.element.io
event-type: packages-index
- name: Find debs
id: deb
if: needs.linux.result == 'success'
run: |
for arch in amd64 arm64
do
echo "$arch=$(ls linux-$arch-sqlcipher-system/*.deb | tail -n1)" >> $GITHUB_OUTPUT
done
- name: Stash debs
if: needs.prepare.outputs.deploy == 'false' && needs.linux.result == 'success'
uses: actions/upload-artifact@v4
with:
name: debs
path: |
${{ steps.deb.outputs.amd64 }}
${{ steps.deb.outputs.arm64 }}
- name: Publish amd64 deb to packages.element.io
uses: element-hq/packages.element.io@master
if: needs.prepare.outputs.deploy == 'true' && needs.linux.result == 'success'
with:
file: ${{ steps.deb.outputs.amd64 }}
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
bucket-api: ${{ vars.CF_R2_S3_API }}
bucket-key-id: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
bucket-access-key: ${{ secrets.CF_R2_TOKEN }}
- name: Publish arm64 deb to packages.element.io
uses: element-hq/packages.element.io@master
if: needs.prepare.outputs.deploy == 'true' && needs.linux.result == 'success'
with:
file: ${{ steps.deb.outputs.arm64 }}
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
bucket-api: ${{ vars.CF_R2_S3_API }}
bucket-key-id: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
bucket-access-key: ${{ secrets.CF_R2_TOKEN }}
reprepro:
needs:
- linux
# We queue this after the other deploy stage as we want to abort if that fails
- deploy
name: Run reprepro ${{ matrix.arch }}
strategy:
matrix:
arch: [amd64, arm64]
if: github.event_name != 'workflow_dispatch' || (inputs.deploy && inputs.linux)
uses: ./.github/workflows/reprepro.yaml
secrets: inherit
with:
artifact-name: linux-${{ matrix.arch }}-sqlcipher-system

View File

@@ -19,7 +19,7 @@ jobs:
uses: ./.github/workflows/build_windows.yaml
strategy:
matrix:
arch: [x64, ia32]
arch: [x64, x86]
with:
arch: ${{ matrix.arch }}
@@ -37,17 +37,17 @@ jobs:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}-dockerbuild-pr
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: "Get modified files"
id: changed_files
uses: tj-actions/changed-files@ae82ed4ae04587b665efad2f206578aa6f0e8539 # v42
uses: tj-actions/changed-files@b2d17f51244a144849c6b37a3a6791b98a51d86f # v35
with:
files: |
dockerbuild/**
dockerbuild/*
- name: Log in to the Container registry
if: steps.changed_files.outputs.any_modified == 'true'
uses: docker/login-action@3d58c274f17dffee475a5520cbe67f0a882c4dbb
uses: docker/login-action@40891eba8c2bcd1309b07ba8b11232f313e86779
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -63,7 +63,7 @@ jobs:
- name: Build and push Docker image
if: steps.changed_files.outputs.any_modified == 'true'
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5
uses: docker/build-push-action@91df6b874e498451163feb47610c87c4a218c1ee
with:
context: dockerbuild
push: true
@@ -106,26 +106,21 @@ jobs:
- name: macOS Universal
os: macos
artifact: macos
executable: "/Users/runner/Applications/Element.app/Contents/MacOS/Element"
# We need to mount the DMG and copy the app to the Applications folder as a mounted DMG is
# read-only and thus would not allow us to override the fuses as is required for Playwright.
prepare_cmd: |
hdiutil attach ./dist/*.dmg -mountpoint /Volumes/Element &&
rsync -a /Volumes/Element/Element.app ~/Applications/ &&
hdiutil detach /Volumes/Element
executable: "/Volumes/Element/Element.app/Contents/MacOS/Element"
prepare_cmd: "hdiutil attach ./dist/*.dmg -mountpoint /Volumes/Element"
- name: "Linux (amd64) (sqlcipher: system)"
os: ubuntu
artifact: linux-amd64-sqlcipher-system
executable: "/opt/Element/element-desktop"
executable: "element-desktop"
prepare_cmd: "sudo apt install ./dist/*.deb"
- name: "Linux (amd64) (sqlcipher: static)"
os: ubuntu
artifact: linux-amd64-sqlcipher-static
executable: "/opt/Element/element-desktop"
executable: "element-desktop"
prepare_cmd: "sudo apt install ./dist/*.deb"
- name: Windows (x86)
os: windows
artifact: win-ia32
artifact: win-x86
executable: "./dist/win-ia32-unpacked/Element.exe"
- name: Windows (x64)
os: windows
@@ -134,17 +129,16 @@ jobs:
name: Test ${{ matrix.name }}
runs-on: ${{ matrix.os }}-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version-file: package.json
cache: "yarn"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v3
with:
name: ${{ matrix.artifact }}
path: dist
@@ -153,26 +147,18 @@ jobs:
run: ${{ matrix.prepare_cmd }}
if: matrix.prepare_cmd
# We previously disabled the `EnableNodeCliInspectArguments` fuse, but Playwright requires
# it to be enabled to test Electron apps, so turn it back on.
- name: Set EnableNodeCliInspectArguments fuse enabled
run: $RUN_AS npx @electron/fuses write --app ${{ matrix.executable }} EnableNodeCliInspectArguments=on
shell: bash
env:
# We need sudo on Linux as it is installed in /opt/
RUN_AS: ${{ runner.os == 'Linux' && 'sudo' || '' }}
- name: Run tests
uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a
uses: coactions/setup-xvfb@b6b4fcfb9f5a895edadc3bc76318fae0ac17c8b3 # v1
timeout-minutes: 5
with:
run: "yarn test ${{ runner.os != 'Linux' && '--ignore-snapshots' || '' }}"
run: "yarn test"
env:
ELEMENT_DESKTOP_EXECUTABLE: ${{ matrix.executable }}
- name: Upload HTML report
uses: actions/upload-artifact@v4
- name: Upload Artifacts
uses: actions/upload-artifact@v3
if: always()
with:
name: ${{ matrix.artifact }}-test
path: playwright-report
retention-days: 14
name: ${{ matrix.artifact }}
path: test_artifacts
retention-days: 1

View File

@@ -20,20 +20,24 @@ on:
type: string
required: true
description: "How to link sqlcipher, one of 'system' | 'static'"
deploy-mode:
type: boolean
required: false
description: "Whether to arrange artifacts in the arrangement needed for deployment, skipping unrelated ones"
docker-image:
type: string
required: false
description: "The docker image to use for the build, defaults to ghcr.io/element-hq/element-desktop-dockerbuild"
description: "The docker image to use for the build, defaults to ghcr.io/vector-im/element-desktop-dockerbuild"
jobs:
build:
runs-on: ubuntu-latest
container:
image: ${{ inputs.docker-image || format('ghcr.io/element-hq/element-desktop-dockerbuild:{0}', github.ref_name == 'master' && 'master' || 'develop') }}
image: ${{ inputs.docker-image || format('ghcr.io/vector-im/element-desktop-dockerbuild:{0}', github.ref_name == 'master' && 'master' || 'develop') }}
defaults:
run:
shell: bash
steps:
- uses: nbucic/variable-mapper@0673f6891a0619ba7c002ecfed0f9f4f39017b6f
- uses: kanga333/variable-mapper@master
id: config
with:
key: "${{ inputs.arch }}"
@@ -51,23 +55,22 @@ jobs:
}
}
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v3
with:
name: webapp
- name: Cache .hak
id: cache
uses: actions/cache@v4
uses: actions/cache@v3
with:
key: ${{ runner.os }}-${{ inputs.docker-image || github.ref_name }}-${{ inputs.sqlcipher }}-${{ inputs.arch }}-${{ hashFiles('hakHash', 'electronVersion') }}
path: |
./.hak
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version-file: package.json
cache: "yarn"
env:
# Workaround for https://github.com/actions/setup-node/issues/317
@@ -88,9 +91,12 @@ jobs:
if: steps.cache.outputs.cache-hit != 'true' && inputs.arch == 'arm64'
run: |
set -x
sed -i 's/deb http/deb [arch=amd64] http/g' /etc/apt/sources.list
echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ bionic main multiverse restricted universe" | tee -a /etc/apt/sources.list
echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main multiverse restricted universe" | tee -a /etc/apt/sources.list
dpkg --add-architecture arm64
apt-get -qq update
apt-get -qq install --no-install-recommends crossbuild-essential-arm64 libsqlcipher-dev:arm64 libssl-dev:arm64 libsecret-1-dev:arm64
apt-get -qq install --no-install-recommends crossbuild-essential-arm64 libsqlcipher-dev:arm64 libssl-dev:arm64 libsecret-1-dev:arm64 libgnome-keyring-dev:arm64
rustup target add aarch64-unknown-linux-gnu
mv dockerbuild/aarch64/.cargo .
cat dockerbuild/aarch64/.env >> $GITHUB_ENV
@@ -100,19 +106,24 @@ jobs:
run: "yarn build:native --target ${{ steps.config.outputs.target }}"
- name: "[Nightly] Resolve version"
id: nightly
if: inputs.version != ''
run: |
echo "ED_NIGHTLY=${{ inputs.version }}" >> $GITHUB_ENV
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
- name: Generate debian files and arguments
id: debian
run: |
if [ -f changelog.Debian ]; then
echo "ED_DEBIAN_CHANGELOG=changelog.Debian" >> $GITHUB_ENV
echo "config-args=--deb-changelog changelog.Debian" >> $GITHUB_OUTPUT
fi
- name: Build App
run: |
yarn build --publish never -l ${{ steps.config.outputs.build-args }}
npx ts-node scripts/generate-builder-config.ts \
${{ steps.nightly.outputs.config-args }} \
${{ steps.debian.outputs.config-args }}
yarn build --publish never -l --config electron-builder.json ${{ steps.config.outputs.build-args }}
- name: Check native libraries
run: |
@@ -140,11 +151,39 @@ jobs:
env:
ARCH: ${{ steps.config.outputs.arch }}
- name: Stash deb package
if: inputs.deploy-mode
uses: actions/upload-artifact@v3
with:
name: linux-sqlcipher-${{ inputs.sqlcipher }}-deb
path: dist/*.deb
retention-days: 1
- name: Prepare artifacts for deployment
if: inputs.deploy-mode
run: |
mv dist _dist
mkdir -p "dist/install/linux/glibc-x86-64/"
mv _dist/*.tar.gz "dist/install/linux/glibc-x86-64"
# We don't wish to store the tarball for every nightly ever, so we only keep the latest
- name: "[Nightly] Strip version from tarball"
if: inputs.deploy-mode && inputs.version != ''
run: |
mv dist/install/linux/glibc-x86-64/*.tar.gz "dist/install/linux/glibc-x86-64/element-desktop-nightly.tar.gz"
- name: "[Release] Prepare release latest symlink"
if: inputs.deploy-mode && inputs.version == ''
shell: bash
run: |
ln -s "$(find . -type f -iname "*.tar.gz" | xargs -0 -n1 -- basename)" "element-desktop.tar.gz"
working-directory: "dist/install/linux/glibc-x86-64"
# We exclude *-unpacked as it loses permissions and the tarball contains it with correct permissions
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: linux-${{ inputs.arch }}-sqlcipher-${{ inputs.sqlcipher }}
name: ${{ inputs.deploy-mode && 'packages.element.io' || format('linux-{0}-sqlcipher-{1}', inputs.arch, inputs.sqlcipher) }}
path: |
dist
!dist/*-unpacked/**

View File

@@ -23,24 +23,28 @@ on:
type: string
required: false
description: "Whether to sign & notarise the build, requires 'packages.element.io' environment"
deploy-mode:
type: boolean
required: false
description: "Whether to arrange artifacts in the arrangement needed for deployment, skipping unrelated ones"
base-url:
type: string
required: false
description: "The URL to which the output will be deployed."
description: "The URL to which the output will be deployed, required if deploy-mode is enabled."
jobs:
build:
runs-on: macos-14 # M1
runs-on: macos-latest
environment: ${{ inputs.sign && 'packages.element.io' || '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v3
with:
name: webapp
- name: Cache .hak
id: cache
uses: actions/cache@v4
uses: actions/cache@v3
with:
key: ${{ runner.os }}-${{ hashFiles('hakHash', 'electronVersion') }}
path: |
@@ -48,20 +52,14 @@ jobs:
- name: Install Rust
if: steps.cache.outputs.cache-hit != 'true'
run: |
rustup toolchain install stable --profile minimal --no-self-update
rustup default stable
rustup target add aarch64-apple-darwin
rustup target add x86_64-apple-darwin
# M1 macos-14 comes without Python preinstalled
- uses: actions/setup-python@v5
uses: actions-rs/toolchain@88dc2356392166efad76775c878094f4e83ff746
with:
python-version: "3.12"
default: true
toolchain: stable
target: aarch64-apple-darwin
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version-file: package.json
cache: "yarn"
# Does not need branch matching as only analyses this layer
@@ -70,23 +68,21 @@ jobs:
- name: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: |
# Python 3.12 drops distutils which keytar relies on
pip3 install setuptools
yarn build:native:universal
run: "yarn build:native:universal"
- name: "[Nightly] Resolve version"
id: nightly
if: inputs.version != ''
run: |
echo "ED_NIGHTLY=${{ inputs.version }}" >> $GITHUB_ENV
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
# We split these because electron-builder gets upset if we set CSC_LINK even to an empty string
- name: "[Signed] Build App"
if: inputs.sign != ''
run: |
yarn build:universal --publish never
scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }} --notarytool-team-id='${{ secrets.APPLE_TEAM_ID }}'
yarn build:universal --publish never --config electron-builder.json
env:
ED_NOTARYTOOL_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
@@ -95,21 +91,27 @@ jobs:
- name: Check app was signed & notarised successfully
if: inputs.sign != ''
run: |
hdiutil attach dist/*.dmg -mountpoint /Volumes/Element
codesign -dv --verbose=4 /Volumes/Element/*.app
spctl -a -vvv -t install /Volumes/Element/*.app
hdiutil detach /Volumes/Element
hdiutil attach dist/*.dmg
codesign -dv --verbose=4 /Volumes/Element*/*.app
spctl -a -vvv -t install /Volumes/Element*/*.app
hdiutil detach /Volumes/Element*
- name: "[Unsigned] Build App"
if: inputs.sign == ''
run: |
yarn build:universal --publish never
scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }}
yarn build:universal --publish never --config electron-builder.json
env:
CSC_IDENTITY_AUTO_DISCOVERY: false
- name: Generate releases.json
if: inputs.base-url
- name: Prepare artifacts for deployment
if: inputs.deploy-mode
run: |
mv dist _dist
mkdir -p dist/install/macos dist/update/macos
mv _dist/*-mac.zip dist/update/macos/
mv _dist/*.dmg dist/install/macos/
PKG_JSON_VERSION=$(cat package.json | jq -r .version)
LATEST=$(find dist -type f -iname "*-mac.zip" | xargs -0 -n1 -- basename)
# Encode spaces in the URL as Squirrel.Mac complains about bad JSON otherwise
@@ -126,18 +128,30 @@ jobs:
},
}],
}
' > dist/releases.json
' > dist/update/macos/releases.json
jq -n --arg url "$URL" '
{ url: $url }
' > dist/releases-legacy.json
' > dist/update/macos/releases-legacy.json
env:
VERSION: ${{ inputs.version }}
# We exclude mac-universal as the unpacked app takes forever to upload and zip and dmg already contains it
# We don't wish to store the installer for every nightly ever, so we only keep the latest
- name: "[Nightly] Strip version from installer file"
if: inputs.deploy-mode && inputs.version != ''
run: |
mv dist/install/macos/*.dmg "dist/install/macos/Element Nightly.dmg"
- name: "[Release] Prepare release latest symlink"
if: inputs.deploy-mode && inputs.version == ''
run: |
ln -s "$(find . -type f -iname "*.dmg" | xargs -0 -n1 -- basename)" "Element.dmg"
working-directory: "dist/install/macos"
# We exclude mac-universal as the unpacked app takes forever to upload and zip and dmg already contain it
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: macos
name: ${{ inputs.deploy-mode && 'packages.element.io' || 'macos' }}
path: |
dist
!dist/mac-universal/**

View File

@@ -15,11 +15,6 @@ on:
required: false
default: false
description: "Whether the build is a Nightly and to calculate the version strings new builds should use"
deploy:
type: boolean
required: false
default: false
description: "Whether the build should be deployed to production"
secrets:
# Required if `nightly` is set
CF_R2_ACCESS_KEY_ID:
@@ -28,32 +23,33 @@ on:
CF_R2_TOKEN:
required: false
outputs:
nightly-version:
description: "The version string the next Nightly should use, only output for nightly"
value: ${{ jobs.prepare.outputs.nightly-version }}
packages-dir:
description: "The directory non-deb packages for this run should live in within packages.element.io"
value: ${{ inputs.nightly && 'nightly' || 'desktop' }}
# These are just simple pass-throughs of the input to simplify reuse of complex inline conditions
config:
description: "The relative path to the config file for this run"
value: ${{ inputs.config }}
deploy:
description: "The relative path to the config file for this run"
value: ${{ inputs.deploy }}
macos-version:
description: "The version string the next macOS Nightly should use, only output for nightly"
value: ${{ jobs.prepare.outputs.macos-version }}
linux-version:
description: "The version string the next Linux Nightly should use, only output for nightly"
value: ${{ jobs.prepare.outputs.linux-version }}
win32-x64-version:
description: "The version string the next Windows x64 Nightly should use, only output for nightly"
value: ${{ jobs.prepare.outputs.win32-x64-version }}
win32-x86-version:
description: "The version string the next Windows x86 Nightly should use, only output for nightly"
value: ${{ jobs.prepare.outputs.win32-x86-version }}
jobs:
prepare:
name: Prepare
environment: ${{ inputs.nightly && 'packages.element.io' || '' }}
runs-on: ubuntu-latest
outputs:
nightly-version: ${{ steps.versions.outputs.nightly }}
macos-version: ${{ steps.versions.outputs.macos }}
linux-version: ${{ steps.versions.outputs.linux }}
win32-x64-version: ${{ steps.versions.outputs.win_x64 }}
win32-x86-version: ${{ steps.versions.outputs.win_x86 }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version-file: package.json
cache: "yarn"
- name: Install Deps
@@ -70,22 +66,20 @@ jobs:
find hak -type f -print0 | xargs -0 sha1sum >> hakHash
find scripts/hak -type f -print0 | xargs -0 sha1sum >> hakHash
- name: "[Nightly] Calculate version"
- name: "[Nightly] Calculate versions"
id: versions
if: inputs.nightly
run: |
# Find all latest Nightly versions
aws s3 cp s3://$R2_BUCKET/nightly/update/macos/releases.json - --endpoint-url $R2_URL --region auto | jq -r .currentRelease >> VERSIONS
aws s3 cp s3://$R2_BUCKET/debian/dists/default/main/binary-amd64/Packages - --endpoint-url $R2_URL --region auto | grep "Package: element-nightly" -A 50 | grep Version -m1 | sed -n 's/Version: //p' >> VERSIONS
aws s3 cp s3://$R2_BUCKET/debian/dists/default/main/binary-arm64/Packages - --endpoint-url $R2_URL --region auto | grep "Package: element-nightly" -A 50 | grep Version -m1 | sed -n 's/Version: //p' >> VERSIONS
aws s3 cp s3://$R2_BUCKET/nightly/update/win32/x64/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8- >> VERSIONS
aws s3 cp s3://$R2_BUCKET/nightly/update/win32/ia32/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8- >> VERSIONS
MACOS=$(aws s3 cp s3://$R2_BUCKET/nightly/update/macos/releases.json - --endpoint-url $R2_URL --region auto | jq -r .currentRelease)
echo "macos=$(scripts/generate-nightly-version.ts --latest $MACOS)" >> $GITHUB_OUTPUT
# Pick the greatest one
VERSION=$(cat VERSIONS | sort -uf | tail -n1)
echo "Found latest nightly version $VERSION"
# Increment it
echo "nightly=$(scripts/generate-nightly-version.ts --latest $VERSION)" >> $GITHUB_OUTPUT
LINUX=$(aws s3 cp s3://$R2_BUCKET/debian/dists/default/main/binary-amd64/Packages - --endpoint-url $R2_URL --region auto | grep "Package: element-nightly" -A 50 | grep Version -m1 | sed -n 's/Version: //p')
echo "linux=$(scripts/generate-nightly-version.ts --latest $LINUX)" >> $GITHUB_OUTPUT
WINx64=$(aws s3 cp s3://$R2_BUCKET/nightly/update/win32/x64/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8-)
echo "win_x64=$(scripts/generate-nightly-version.ts --latest $WINx64)" >> $GITHUB_OUTPUT
WINx86=$(aws s3 cp s3://$R2_BUCKET/nightly/update/win32/ia32/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8-)
echo "win_x86=$(scripts/generate-nightly-version.ts --latest $WINx86)" >> $GITHUB_OUTPUT
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
@@ -129,16 +123,20 @@ jobs:
REACT_VERSION=${WEBAPP_VERSION:19:12}
JS_VERSION=${WEBAPP_VERSION:35:12}
echo "### Nightly build ${{ steps.versions.outputs.nightly }}" >> $GITHUB_STEP_SUMMARY
echo "### Nightly build" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Component | Version |" >> $GITHUB_STEP_SUMMARY
echo "| ----------- | ------- |" >> $GITHUB_STEP_SUMMARY
echo "| macOS | ${{ steps.versions.outputs.macos }} |" >> $GITHUB_STEP_SUMMARY
echo "| Linux | ${{ steps.versions.outputs.linux }} |" >> $GITHUB_STEP_SUMMARY
echo "| Windows x64 | ${{ steps.versions.outputs.win_x64 }} |" >> $GITHUB_STEP_SUMMARY
echo "| Windows x86 | ${{ steps.versions.outputs.win_x86 }} |" >> $GITHUB_STEP_SUMMARY
echo "| Bundle Hash | $BUNDLE_HASH |" >> $GITHUB_STEP_SUMMARY
echo "| Element Web | [$WEB_VERSION](https://github.com/element-hq/element-web/commit/$WEB_VERSION) |" >> $GITHUB_STEP_SUMMARY
echo "| Element Web | [$WEB_VERSION](https://github.com/vector-im/element-web/commit/$WEB_VERSION) |" >> $GITHUB_STEP_SUMMARY
echo "| React SDK | [$REACT_VERSION](https://github.com/matrix-org/matrix-react-sdk/commit/$REACT_VERSION) |" >> $GITHUB_STEP_SUMMARY
echo "| JS SDK | [$JS_VERSION](https://github.com/matrix-org/matrix-js-sdk/commit/$JS_VERSION) |" >> $GITHUB_STEP_SUMMARY
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
name: webapp
retention-days: 1

View File

@@ -1,11 +1,6 @@
# This workflow relies on actions/cache to store the hak dependency artifacts as they take a long time to build
# Due to this extra care must be taken to only ever run all build_* scripts against the same branch to ensure
# the correct cache scoping, and additional care must be taken to not run untrusted actions on the develop branch.
# window-latest by default uses the pwsh shell which breaks codeSigningCert in the workflow
defaults:
run:
shell: powershell
on:
workflow_call:
secrets:
@@ -19,7 +14,7 @@ on:
arch:
type: string
required: true
description: "The architecture to build for, one of 'x64' | 'ia32' | 'arm64'"
description: "The architecture to build for, one of 'x64' | 'x86' | 'arm64'"
version:
type: string
required: false
@@ -28,6 +23,10 @@ on:
type: string
required: false
description: "Whether to sign & notarise the build, requires 'packages.element.io' environment"
deploy-mode:
type: boolean
required: false
description: "Whether to arrange artifacts in the arrangement needed for deployment, skipping unrelated ones"
jobs:
build:
runs-on: windows-latest
@@ -35,7 +34,7 @@ jobs:
env:
SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.22000.0/x86/signtool.exe"
steps:
- uses: nbucic/variable-mapper@0673f6891a0619ba7c002ecfed0f9f4f39017b6f
- uses: kanga333/variable-mapper@3681b75f5c6c00162721168fb91ab74925eaebcb
id: config
with:
key: "${{ inputs.arch }}"
@@ -43,36 +42,38 @@ jobs:
map: |
{
"x64": {
"target": "x86_64-pc-windows-msvc"
"target": "x86_64-pc-windows-msvc",
"dir": "x64"
},
"arm64": {
"target": "aarch64-pc-windows-msvc",
"build-args": "--arm64",
"arch": "amd64_arm64"
"arch": "amd64_arm64",
"dir": "arm64"
},
"ia32": {
"x86": {
"target": "i686-pc-windows-msvc",
"build-args": "--ia32",
"arch": "x86"
"dir": "ia32"
}
}
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v3
with:
name: webapp
- name: Cache .hak
id: cache
uses: actions/cache@v4
uses: actions/cache@v3
with:
key: ${{ runner.os }}-${{ inputs.arch }}-${{ hashFiles('hakHash', 'electronVersion') }}
path: |
./.hak
- name: Set up build tools
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89
with:
arch: ${{ steps.config.outputs.arch || inputs.arch }}
@@ -94,14 +95,14 @@ jobs:
- name: Install Rust
if: steps.cache.outputs.cache-hit != 'true'
run: |
rustup toolchain install stable --profile minimal --no-self-update
rustup default stable
rustup target add ${{ steps.config.outputs.target }}
- uses: actions/setup-node@v4
uses: actions-rs/toolchain@88dc2356392166efad76775c878094f4e83ff746
with:
default: true
toolchain: stable
target: ${{ steps.config.outputs.target }}
- uses: actions/setup-node@v3
with:
node-version-file: package.json
cache: "yarn"
# Does not need branch matching as only analyses this layer
@@ -115,14 +116,13 @@ jobs:
yarn build:native --target ${{ steps.config.outputs.target }}
- name: Install and configure eSigner CKA
id: esigner
if: inputs.sign
run: |
Set-StrictMode -Version 'Latest'
# Download, extract, and rename
Invoke-WebRequest -OutFile eSigner_CKA.zip "$env:ESIGNER_URL"
Expand-Archive -Path eSigner_CKA.zip -DestinationPath .
Get-ChildItem -Path * -Include "*_build_*.exe" | Rename-Item -NewName eSigner_CKA.exe
# Download
Invoke-WebRequest -OutFile eSigner_CKA.exe "https://packages.element.io/tools/SSL.COM%20eSigner%20CKA_1.0.4-build-20230221_signed.exe"
# Install
New-Item -ItemType Directory -Force -Path "$env:INSTALL_DIR"
@@ -145,37 +145,61 @@ jobs:
# Extract thumbprint and subject name
$Thumbprint = $CodeSigningCert.Thumbprint
$SubjectName = ($CodeSigningCert.Subject -replace ", ?", "`n" | ConvertFrom-StringData).CN
echo "ED_SIGNTOOL_THUMBPRINT=$Thumbprint" >> $env:GITHUB_ENV
echo "ED_SIGNTOOL_SUBJECT_NAME=$SubjectName" >> $env:GITHUB_ENV
echo "config-args=--signtool-thumbprint '$Thumbprint' --signtool-subject-name '$SubjectName'" >> $env:GITHUB_OUTPUT
env:
ESIGNER_URL: https://github.com/SSLcom/eSignerCKA/releases/download/v1.0.6/SSL.COM-eSigner-CKA_1.0.6.zip
INSTALL_DIR: C:\Users\runneradmin\eSignerCKA
MASTER_KEY_FILE: C:\Users\runneradmin\eSignerCKA\master.key
- name: "[Nightly] Resolve version"
id: nightly
if: inputs.version != ''
shell: bash
run: |
echo "ED_NIGHTLY=${{ inputs.version }}" >> $GITHUB_ENV
# XXX: For whatever reason if we use `yarn build ...` it freezes, but splitting it into parts it is fine
- run: yarn run build:ts
- run: yarn run build:res
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
- name: Build App
run: |
yarn electron-builder --publish never -w ${{ steps.config.outputs.build-args }}
yarn ts-node scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }} ${{ steps.esigner.outputs.config-args }}
yarn build --publish never -w --config electron-builder.json ${{ steps.config.outputs.build-args }}
- name: Check app was signed successfully
if: inputs.sign != ''
run: |
. "$env:SIGNTOOL_PATH" verify /pa (get-item ./dist/squirrel-windows*/*.exe)
- name: Prepare artifacts for deployment
if: inputs.deploy-mode
shell: bash
run: |
mv dist _dist
mkdir -p "dist/install/win32/$DIR/msi" "dist/update/win32/$DIR"
mv _dist/squirrel-windows*/*.exe "dist/install/win32/$DIR"
mv _dist/squirrel-windows*/*.nupkg "dist/update/win32/$DIR/"
mv _dist/squirrel-windows*/RELEASES "dist/update/win32/$DIR/"
# mv _dist/*.msi "dist/install/win32/$DIR/msi/"
env:
DIR: ${{ steps.config.outputs.dir }}
# We don't wish to store the installer for every nightly ever, so we only keep the latest
- name: "[Nightly] Strip version from installer file"
if: inputs.deploy-mode && inputs.version != ''
shell: bash
run: |
mv dist/install/win32/$DIR/*.exe "dist/install/win32/$DIR/Element Nightly Setup.exe"
# mv dist/install/win32/$DIR/msi/*.msi "dist/install/win32/$DIR/msi/Element Nightly Setup.msi"
env:
DIR: ${{ steps.config.outputs.dir }}
- name: "[Release] Prepare release latest symlink"
if: inputs.deploy-mode && inputs.version == ''
shell: bash
run: |
ln -s "$(find . -type f -iname "*.exe" | xargs -0 -n1 -- basename)" "Element Setup.exe"
working-directory: "dist/install/win32/${{ steps.config.outputs.dir }}"
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: win-${{ inputs.arch }}
path: |
dist
name: ${{ inputs.deploy-mode && 'packages.element.io' || format('win-{0}', inputs.arch) }}
path: dist
retention-days: 1

View File

@@ -17,10 +17,10 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@3d58c274f17dffee475a5520cbe67f0a882c4dbb
uses: docker/login-action@40891eba8c2bcd1309b07ba8b11232f313e86779
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -28,14 +28,14 @@ jobs:
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@dbef88086f6cef02e264edb7dbf63250c17cef6c # v5
uses: docker/metadata-action@c4ee3adeed93b1fa6a762f209fb01608c1a22f1e
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
- name: Build and push Docker image
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5
uses: docker/build-push-action@91df6b874e498451163feb47610c87c4a218c1ee
with:
context: dockerbuild
push: true

View File

@@ -1,10 +0,0 @@
name: Localazy Download
on:
workflow_dispatch: {}
schedule:
- cron: "0 6 * * 1,3,5" # Every Monday, Wednesday and Friday at 6am UTC
jobs:
download:
uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_download.yaml@main
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@@ -1,11 +0,0 @@
name: Localazy Upload
on:
push:
branches: [develop]
paths:
- "src/i18n/strings/en_EN.json"
jobs:
upload:
uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_upload.yaml@main
secrets:
LOCALAZY_WRITE_KEY: ${{ secrets.LOCALAZY_WRITE_KEY }}

View File

@@ -1,11 +0,0 @@
name: Release Drafter
on:
push:
branches: [staging]
workflow_dispatch: {}
concurrency: ${{ github.workflow }}
jobs:
draft:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-drafter-workflow.yml@develop
with:
include-changes: element-hq/element-web@$VERSION

View File

@@ -1,11 +0,0 @@
# Gitflow merge-back master->develop
name: Merge master -> develop
on:
push:
branches: [master]
concurrency: ${{ github.repository }}-${{ github.workflow }}
jobs:
merge:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-gitflow.yml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@@ -1,39 +0,0 @@
name: Release Process
on:
workflow_dispatch:
inputs:
mode:
description: What type of release
required: true
default: rc
type: choice
options:
- rc
- final
concurrency: ${{ github.workflow }}
jobs:
release:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
with:
final: ${{ inputs.mode == 'final' }}
include-changes: element-hq/element-web@$VERSION
gpg-fingerprint: ${{ vars.GPG_FINGERPRINT }}
expected-asset-count: 1
check:
name: Post release checks
needs: release
runs-on: ubuntu-latest
steps:
- name: Wait for desktop packaging
uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork
with:
ref: master
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10
check-name: Deploy
allowed-conclusions: success

49
.github/workflows/reprepro.yaml vendored Normal file
View File

@@ -0,0 +1,49 @@
on:
workflow_call:
inputs:
artifact-name:
type: string
required: true
description: "The name of the artifact containing the deb to include"
secrets:
ELEMENT_BOT_TOKEN:
required: true
CF_R2_ACCESS_KEY_ID:
required: true
CF_R2_TOKEN:
required: true
# Protect reprepro database using concurrency
concurrency: reprepro
jobs:
reprepro:
name: Deploy debian package
environment: packages.element.io
runs-on: ubuntu-latest
env:
R2_INCOMING_BUCKET: ${{ vars.R2_INCOMING_BUCKET }}
R2_URL: ${{ vars.CF_R2_S3_API }}
steps:
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: ${{ inputs.artifact-name }}
path: dist
- name: Upload incoming deb
id: upload
run: |
deb="$(ls *.deb | tail -n1)"
echo "incoming=$deb" >> $GITHUB_OUTPUT
aws s3 cp "$deb" "s3://$R2_INCOMING_BUCKET" --endpoint-url "$R2_URL" --region auto
working-directory: dist
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
- name: Notify packages.element.io of incoming deb
uses: peter-evans/repository-dispatch@26b39ed245ab8f31526069329e112ab2fb224588 # v2
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
repository: vector-im/packages.element.io
event-type: reprepro-incoming
client-payload: '{"incoming": "${{ steps.upload.outputs.incoming }}"}'

View File

@@ -8,11 +8,10 @@ jobs:
name: "Typescript Syntax Check"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version-file: package.json
cache: "yarn"
# Does not need branch matching as only analyses this layer
@@ -24,17 +23,16 @@ jobs:
i18n_lint:
name: "i18n Check"
uses: matrix-org/matrix-web-i18n/.github/workflows/i18n_check.yml@main
uses: matrix-org/matrix-react-sdk/.github/workflows/i18n_check.yml@develop
js_lint:
name: "ESLint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version-file: package.json
cache: "yarn"
# Does not need branch matching as only analyses this layer
@@ -43,38 +41,3 @@ jobs:
- name: Run Linter
run: "yarn run lint:js"
workflow_lint:
name: "Workflow Lint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "yarn"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Run Linter
run: "yarn lint:workflows"
analyse_dead_code:
name: "Analyse Dead Code"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "yarn"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Run linter
run: "yarn run lint:knip"

View File

@@ -1,21 +0,0 @@
name: Sync labels
on:
workflow_dispatch: {}
schedule:
- cron: "0 2 * * *" # 2am every day
push:
branches:
- develop
paths:
- .github/labels.yml
jobs:
sync-labels:
uses: element-hq/element-meta/.github/workflows/sync-labels.yml@develop
with:
LABELS: |
element-hq/element-web
.github/labels.yml
DELETE: true
WET: true
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@@ -1,10 +0,0 @@
name: Move labelled issues to correct projects
on:
issues:
types: [labeled]
jobs:
call-triage-labelled:
uses: element-hq/element-web/.github/workflows/triage-labelled.yml@develop
secrets: inherit

View File

@@ -0,0 +1,8 @@
name: Upgrade Dependencies
on:
workflow_dispatch: {}
jobs:
upgrade:
uses: matrix-org/matrix-js-sdk/.github/workflows/upgrade_dependencies.yml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@@ -8,8 +8,6 @@
/CHANGELOG.md
/package-lock.json
/yarn.lock
/playwright/html-report
/playwright/test-results
**/.idea
.vscode

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
![Build](https://github.com/vector-im/element-desktop/actions/workflows/build.yaml/badge.svg)
![Static Analysis](https://github.com/vector-im/element-desktop/actions/workflows/static_analysis.yaml/badge.svg)
[![Localazy](https://img.shields.io/endpoint?url=https%3A%2F%2Fconnect.localazy.com%2Fstatus%2Felement-web%2Fdata%3Fcontent%3Dall%26title%3Dlocalazy%26logo%3Dtrue)](https://localazy.com/p/element-web)
[![Weblate](https://translate.element.io/widgets/element-desktop/-/element-desktop/svg-badge.svg)](https://translate.element.io/engage/element-desktop/)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=element-desktop&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=element-desktop)
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=element-desktop&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=element-desktop)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=element-desktop&metric=bugs)](https://sonarcloud.io/summary/new_code?id=element-desktop)
@@ -149,6 +149,8 @@ To add a new translation, head to the [translating doc](https://github.com/vecto
For a developer guide, see the [translating dev doc](https://github.com/vector-im/element-web/blob/develop/docs/translating-dev.md).
[<img src="https://translate.element.io/widgets/element-desktop/-/multi-auto.svg" alt="translationsstatus" width="340">](https://translate.element.io/engage/element-desktop/?utm_source=widget)
# Report bugs & give feedback
If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.

View File

@@ -1,5 +1,5 @@
# Docker image to facilitate building Element Desktop with native bits using a glibc version with broader compatibility
FROM buildpack-deps:buster-curl
FROM buildpack-deps:bionic-curl
ENV DEBIAN_FRONTEND noninteractive
@@ -11,9 +11,9 @@ RUN apt-get -qq update && apt-get -qq dist-upgrade && \
# python for node-gyp
# rpm is required for FPM to build rpm package
# tclsh is required for building SQLite as part of SQLCipher
# libsecret-1-dev is required even for prebuild keytar
# libsecret-1-dev and libgnome-keyring-dev are required even for prebuild keytar
apt-get -qq install --no-install-recommends qtbase5-dev bsdtar build-essential autoconf libssl-dev gcc-multilib g++-multilib lzip rpm python libcurl4 git git-lfs ssh unzip tcl \
libsecret-1-dev \
libsecret-1-dev libgnome-keyring-dev \
libopenjp2-tools \
# Used by github actions \
jq grep file \
@@ -34,11 +34,13 @@ ENV LC_ALL C.UTF-8
ENV DEBUG_COLORS true
ENV FORCE_COLOR true
ENV NODE_VERSION 18.19.0
ENV NODE_VERSION 16.18.1
# this package is used for snapcraft and we should not clear apt list - to avoid apt-get update during snap build
RUN curl --proto "=https" -L https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz | tar xz -C /usr/local --strip-components=1 && \
unlink /usr/local/CHANGELOG.md && unlink /usr/local/LICENSE && unlink /usr/local/README.md
unlink /usr/local/CHANGELOG.md && unlink /usr/local/LICENSE && unlink /usr/local/README.md && \
# https://github.com/npm/npm/issues/4531
npm config set unsafe-perm true
ENV RUSTUP_HOME=/usr/local/rustup \
CARGO_HOME=/usr/local/cargo \

View File

@@ -1,17 +0,0 @@
# Summary
- [Introduction](../README.md)
# Build
- [Native Node modules](native-node-modules.md)
- [Windows requirements](windows-requirements.md)
# Distribution
- [Updates](updates.md)
- [Packaging](packaging.md)
# Setup
- [Config](config.md)

View File

@@ -1,15 +0,0 @@
# Configuration
All Element Web options documented [here](https://github.com/vector-im/element-web/blob/develop/docs/config.md) can be used as well as the following:
---
The app contains a configuration file specified at build time using [these instructions](https://github.com/vector-im/element-desktop/#config).
This config can be overwritten by the end using by creating a `config.json` file at the paths described [here](https://github.com/vector-im/element-desktop/#user-specified-configjson).
After changing the config, the app will need to be exited fully (including via the task tray) and re-started.
---
1. `update_base_url`: Specifies the URL of the update server, see [document](https://github.com/vector-im/element-desktop/blob/develop/docs/updates.md).
2. `web_base_url`: Specifies the Element Web URL when performing actions such as popout widget. Defaults to `https://app.element.io/`.

View File

@@ -1,55 +0,0 @@
## Packaging nightlies
Element Desktop nightly builds are build automatically by the [Github Actions workflow](https://github.com/vector-im/element-desktop/blob/develop/.github/workflows/build_and_deploy.yaml).
The schedule is currently set for once a day at 9am UTC. It will deploy to packages.element.io upon completion.
## Triggering a manual nightly build
Simply go to https://github.com/vector-im/element-desktop/actions/workflows/build_and_deploy.yaml
1. Click `Run workflow`
1. Feel free to make changes to the checkboxes depending on the circumstances
1. Click the green `Run workflow`
## Packaging releases
**Don't do this for RCs! We don't build Element Desktop for RCs.**
For releasing Element Desktop, we assume the following prerequisites:
- a tag of `element-desktop` repo with the Element Desktop version to be released set in `package.json`.
- an Element Web tarball published to GitHub with a matching version number.
**Both of these are done automatically when you run the release automation.**
The packaging is kicked off automagically for you when a Github Release for Element Desktop is published.
### More detail on the github actions
We moved to Github Actions for the following reasons:
1. Removing single point of failure
2. Improving reliability
3. Unblocking the packaging on a single individual
4. Improving parallelism
The Windows builds are signed by SSL.com using their Cloud Key Adapter for eSigner.
This allows us to use Microsoft's signtool to interface with eSigner and send them a hash of the exe along with
credentials in exchange for a signed certificate which we attach onto all the relevant files.
The Apple builds are signed using standard code signing means and then notarised to appease GateKeeper.
The Linux builds are distributed via a signed reprepro repository.
The packages.element.io site is a public Cloudflare R2 bucket which is deployed to solely from Github Actions.
The main bucket in R2 is `packages-element-io` which is a direct mapping of packages.element.io,
we have a workflow which generates the index.html files there to imitate a public index which Cloudflare does not currently support.
The reprepro database lives in `packages-element-io-db`.
There is an additional pair of buckets of same name but appended with `-test` which can be used for testing,
these land on https://packages-element-io-test.element.io/.
### Debian/Ubuntu Distributions
We used to add a new distribution to match each Debian and Ubuntu release. As of April 2020, we have created a `default` distribution that everyone can use (since the packages have never differed by distribution anyway).
The distribution configuration lives in https://github.com/vector-im/packages.element.io/blob/master/debian/conf/distributions as a canonical source.

View File

@@ -1,5 +1,6 @@
# Windows
## Requirements to build native modules
We rely on Github Actions `windows-latest` plus a few extra utilities as per [the workflow](https://github.com/vector-im/element-desktop/blob/develop/.github/workflows/build_windows.yaml).

View File

@@ -1,215 +0,0 @@
const os = require("os");
const fs = require("fs");
const path = require("path");
const Arch = require("electron-builder").Arch;
const { flipFuses, FuseVersion, FuseV1Options } = require("@electron/fuses");
// Typescript conversion blocked on https://github.com/electron-userland/electron-builder/issues/7775
/**
* This script has different outputs depending on your os platform.
*
* On Windows:
* Prefixes the nightly version with `0.0.1-nightly.` as it breaks if it is not semver
* Passes $ED_SIGNTOOL_THUMBPRINT and $ED_SIGNTOOL_SUBJECT_NAME to
* build.win.signingHashAlgorithms and build.win.certificateSubjectName respectively if specified.
*
* On macOS:
* Passes $ED_NOTARYTOOL_TEAM_ID to build.mac.notarize.notarize if specified
*
* On Linux:
* Replaces spaces in the product name with dashes as spaces in paths can cause issues
* Removes libsqlcipher0 recommended dependency if env SQLCIPHER_BUNDLED is asserted.
* Passes $ED_DEBIAN_CHANGELOG to build.deb.fpm if specified
*/
const NIGHTLY_APP_ID = "im.riot.nightly";
const NIGHTLY_DEB_NAME = "element-nightly";
const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
/**
* @type {import('electron-builder').Configuration}
* @see https://www.electron.build/configuration/configuration
*/
const config = {
appId: "im.riot.app",
asarUnpack: "**/*.node",
afterPack: async (context) => {
if (context.electronPlatformName !== "darwin" || context.arch === Arch.universal) {
// Burn in electron fuses for proactive security hardening.
// On macOS, we only do this for the universal package, as the constituent arm64 and amd64 packages are embedded within.
const ext = {
darwin: ".app",
win32: ".exe",
linux: "",
}[context.electronPlatformName];
let executableName = context.packager.appInfo.productFilename;
if (context.electronPlatformName === "linux") {
// Linux uses the package name as the executable name
executableName = context.packager.appInfo.name;
}
const electronBinaryPath = path.join(context.appOutDir, `${executableName}${ext}`);
console.log(`Flipping fuses for: ${electronBinaryPath}`);
await flipFuses(electronBinaryPath, {
version: FuseVersion.V1,
resetAdHocDarwinSignature: context.electronPlatformName === "darwin" && context.arch === Arch.universal,
[FuseV1Options.EnableCookieEncryption]: true,
[FuseV1Options.OnlyLoadAppFromAsar]: true,
[FuseV1Options.RunAsNode]: false,
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
[FuseV1Options.EnableNodeCliInspectArguments]: false,
// Mac app crashes on arm for us when `LoadBrowserProcessSpecificV8Snapshot` is enabled
[FuseV1Options.LoadBrowserProcessSpecificV8Snapshot]: false,
// https://github.com/electron/fuses/issues/7
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: false,
});
}
},
files: [
"package.json",
{
from: ".hak/hakModules",
to: "node_modules",
},
"lib/**",
],
extraResources: [
{
from: "res/img",
to: "img",
},
"webapp.asar",
],
extraMetadata: {
name: pkg.name,
productName: pkg.productName,
description: pkg.description,
},
linux: {
target: ["tar.gz", "deb"],
category: "Network;InstantMessaging;Chat",
maintainer: "support@element.io",
icon: "build/icons",
desktop: {
MimeType: "x-scheme-handler/element",
},
},
deb: {
packageCategory: "net",
depends: [
"libgtk-3-0",
"libnotify4",
"libnss3",
"libxss1",
"libxtst6",
"xdg-utils",
"libatspi2.0-0",
"libuuid1",
"libsecret-1-0",
"libasound2",
"libgbm1",
],
recommends: ["libsqlcipher0", "element-io-archive-keyring"],
fpm: [
"--deb-field",
"Replaces: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)",
"--deb-field",
"Breaks: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)",
],
},
mac: {
category: "public.app-category.social-networking",
darkModeSupport: true,
hardenedRuntime: true,
gatekeeperAssess: true,
entitlements: "./build/entitlements.mac.plist",
icon: "build/icons/icon.icns",
},
win: {
target: ["squirrel"],
signingHashAlgorithms: ["sha256"],
icon: "build/icons/icon.ico",
},
directories: {
output: "dist",
},
protocols: [
{
name: "element",
schemes: ["element"],
},
],
};
/**
* Allow specifying windows signing cert via env vars
* @param {string} process.env.ED_SIGNTOOL_SUBJECT_NAME
* @param {string} process.env.ED_SIGNTOOL_THUMBPRINT
*/
if (process.env.ED_SIGNTOOL_SUBJECT_NAME && process.env.ED_SIGNTOOL_THUMBPRINT) {
config.win.certificateSubjectName = process.env.ED_SIGNTOOL_SUBJECT_NAME;
config.win.certificateSha1 = process.env.ED_SIGNTOOL_THUMBPRINT;
}
/**
* Allow specifying macOS notary team id via env var
* @param {string} process.env.ED_NOTARYTOOL_TEAM_ID
*/
if (process.env.ED_NOTARYTOOL_TEAM_ID) {
config.mac.notarize = {
teamId: process.env.ED_NOTARYTOOL_TEAM_ID,
};
}
/**
* Allow specifying nightly version via env var
* @param {string} process.env.ED_NIGHTLY
*/
if (process.env.ED_NIGHTLY) {
config.deb.fpm = []; // Clear the fpm as the breaks deb fields don't apply to nightly
config.appId = NIGHTLY_APP_ID;
config.extraMetadata.productName += " Nightly";
config.extraMetadata.name += "-nightly";
config.extraMetadata.description += " (nightly unstable build)";
config.deb.fpm.push("--name", NIGHTLY_DEB_NAME);
let version = process.env.ED_NIGHTLY;
if (os.platform() === "win32") {
// The windows packager relies on parsing this as semver, so we have to make it look like one.
// This will give our update packages really stupid names, but we probably can't change that either
// because squirrel windows parses them for the version too. We don't really care: nobody sees them.
// We just give the installer a static name, so you'll just see this in the 'about' dialog.
// Turns out if you use 0.0.0 here it makes Squirrel windows crash, so we use 0.0.1.
version = "0.0.1-nightly." + version;
}
config.extraMetadata.version = version;
}
if (os.platform() === "linux") {
// Electron crashes on debian if there's a space in the path.
// https://github.com/vector-im/element-web/issues/13171
config.extraMetadata.productName = config.extraMetadata.productName.replace(/ /g, "-");
/**
* Allow specifying deb changelog via env var
* @param {string} process.env.ED_DEB_CHANGELOG
*/
if (process.env.ED_DEBIAN_CHANGELOG) {
config.deb.fpm.push(`--deb-changelog=${process.env.ED_DEBIAN_CHANGELOG}`);
}
if (process.env.SQLCIPHER_BUNDLED) {
// Remove sqlcipher dependency when using bundled
config.deb.recommends = config.deb.recommends?.filter((d) => d !== "libsqlcipher0");
}
}
exports.default = config;

View File

@@ -1,14 +1,6 @@
{
"update_base_url": "https://packages.element.io/nightly/update/",
"default_server_name": "matrix.org",
"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix-client.matrix.org"
},
"m.identity_server": {
"base_url": "https://vector.im"
}
},
"brand": "Element Nightly",
"integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api",
@@ -21,8 +13,8 @@
],
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
"uisi_autorageshake_app": "element-auto-uisi",
"show_labs_settings": true,
"room_directory": {
"showLabsSettings": true,
"roomDirectory": {
"servers": ["matrix.org", "gitter.im", "libera.chat"]
},
"enable_presence_by_hs_url": {
@@ -44,17 +36,16 @@
"environment": "nightly"
},
"posthog": {
"project_api_key": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
"api_host": "https://posthog.element.io"
"projectApiKey": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
"apiHost": "https://posthog.element.io"
},
"privacy_policy_url": "https://element.io/cookie-policy",
"features": {
"feature_spotlight": true,
"feature_video_rooms": true,
"feature_element_call_video_rooms": true
"feature_video_rooms": true
},
"element_call": {
"url": "https://call.element.dev"
"url": "https://element-call.netlify.app"
},
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}

View File

@@ -1,14 +1,6 @@
{
"update_base_url": "https://packages.element.io/desktop/update/",
"default_server_name": "matrix.org",
"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix-client.matrix.org"
},
"m.identity_server": {
"base_url": "https://vector.im"
}
},
"brand": "Element",
"integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api",
@@ -21,10 +13,10 @@
],
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
"uisi_autorageshake_app": "element-auto-uisi",
"room_directory": {
"roomDirectory": {
"servers": ["matrix.org", "gitter.im", "libera.chat"]
},
"show_labs_settings": false,
"showLabsSettings": false,
"enable_presence_by_hs_url": {
"https://matrix.org": false,
"https://matrix-client.matrix.org": false
@@ -40,8 +32,8 @@
}
],
"posthog": {
"project_api_key": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
"api_host": "https://posthog.element.io"
"projectApiKey": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
"apiHost": "https://posthog.element.io"
},
"privacy_policy_url": "https://element.io/cookie-policy",
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"

View File

@@ -28,12 +28,16 @@ export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Prom
console.log("Running yarn install");
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn("yarn" + (hakEnv.isWin() ? ".cmd" : ""), ["install"], {
cwd: moduleInfo.moduleBuildDir,
env,
shell: true,
stdio: "inherit",
});
const proc = childProcess.spawn(
"yarn" + (hakEnv.isWin() ? ".cmd" : ""),
["install"],
{
cwd: moduleInfo.moduleBuildDir,
env,
shell: true,
stdio: "inherit",
},
);
proc.on("exit", (code) => {
code ? reject(code) : resolve();
});
@@ -43,12 +47,16 @@ export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Prom
console.log("Running yarn build");
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn("yarn" + (hakEnv.isWin() ? ".cmd" : ""), ["run", buildTarget], {
cwd: moduleInfo.moduleBuildDir,
env,
shell: true,
stdio: "inherit",
});
const proc = childProcess.spawn(
"yarn" + (hakEnv.isWin() ? ".cmd" : ""),
["run", buildTarget],
{
cwd: moduleInfo.moduleBuildDir,
env,
shell: true,
stdio: "inherit",
},
);
proc.on("exit", (code) => {
code ? reject(code) : resolve();
});

View File

@@ -5,10 +5,10 @@
"target": "es2016",
"sourceMap": false,
"strict": true,
"lib": ["es2020"],
"lib": ["es2020"]
},
"include": ["../scripts/@types/*.d.ts", "./**/*.ts"],
"ts-node": {
"transpileOnly": true,
},
"transpileOnly": true
}
}

16
knip.ts
View File

@@ -1,16 +0,0 @@
import { KnipConfig } from "knip";
export default {
entry: ["src/electron-main.ts", "src/preload.ts", "electron-builder.js", ".eslintrc-*.js", "scripts/**", "hak/**"],
project: ["**/*.{js,ts}"],
ignoreDependencies: [
// Brought in via hak scripts
"keytar",
"matrix-seshat",
// Needed by `electron-builder`
"electron-builder-squirrel-windows",
// Required for `action-validator`
"@action-validator/*",
],
ignoreBinaries: ["jq", "scripts/in-docker.sh"],
} satisfies KnipConfig;

View File

@@ -1,37 +0,0 @@
{
"readKey": "a7688614897667993891-866e2615b0a22e6ccef56aea9b10e815efa3e1296752a7a30bd9925f1a8f33e7",
"upload": {
"type": "json",
"keySeparator": "|",
"deprecate": "file",
"features": ["plural_object", "filter_untranslated"],
"files": [
{
"pattern": "src/i18n/strings/en_EN.json",
"file": "element-desktop.json",
"lang": "inherited"
},
{
"group": "existing",
"pattern": "src/i18n/strings/*.json",
"file": "element-desktop.json",
"excludes": ["src/i18n/strings/en_EN.json"],
"lang": "${autodetectLang}"
}
]
},
"download": {
"files": [
{
"conditions": "equals: ${file}, element-desktop.json",
"output": "src/i18n/strings/${langLsrUnderscore}.json"
}
],
"includeSourceLang": "${includeSourceLang|false}",
"langAliases": {
"en": "en-EN"
}
}
}

View File

@@ -2,7 +2,7 @@
"name": "element-desktop",
"productName": "Element",
"main": "lib/electron-main.js",
"version": "1.11.59",
"version": "1.11.31",
"description": "A feature-rich client for Matrix.org",
"author": "Element",
"homepage": "https://element.io",
@@ -13,35 +13,32 @@
"license": "Apache-2.0",
"files": [],
"engines": {
"node": ">=18.0.0"
"node": ">=16.0.0"
},
"scripts": {
"i18n": "matrix-gen-i18n && yarn i18n:sort && yarn i18n:lint",
"i18n:sort": "jq --sort-keys '.' src/i18n/strings/en_EN.json > src/i18n/strings/en_EN.json.tmp && mv src/i18n/strings/en_EN.json.tmp src/i18n/strings/en_EN.json",
"i18n:lint": "prettier --log-level=silent --write src/i18n/strings/ --ignore-path /dev/null",
"i18n:diff": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && yarn i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json",
"i18n": "matrix-gen-i18n",
"prunei18n": "matrix-prune-i18n",
"diff-i18n": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && matrix-gen-i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json",
"mkdirs": "mkdirp packages deploys",
"fetch": "yarn run mkdirs && ts-node scripts/fetch-package.ts",
"asar-webapp": "asar p webapp webapp.asar",
"start": "yarn run build:ts && yarn run build:res && electron .",
"lint": "yarn lint:types && yarn lint:js && yarn lint:workflows",
"lint:js": "yarn lint:js:src && yarn lint:js:test && yarn lint:js:scripts && yarn lint:js:hak && prettier --check .",
"lint": "yarn lint:types && yarn lint:js",
"lint:js": "yarn lint:js:src && yarn lint:js:test && yarn lint:js:scripts && yarn lint:js:hak",
"lint:js:src": "eslint --max-warnings 0 src",
"lint:js:test": "eslint --max-warnings 0 --config .eslintrc-test.js playwright",
"lint:js:test": "eslint --max-warnings 0 --config .eslintrc-test.js test",
"lint:js:scripts": "eslint --max-warnings 0 --config .eslintrc-scripts.js scripts",
"lint:js:hak": "eslint --max-warnings 0 --config .eslintrc-hak.js hak",
"lint:js-fix": "yarn lint:js-fix:src &&yarn lint:js-fix:test && yarn lint:js-fix:scripts && yarn lint:js-fix:hak && prettier --log-level=warn --write .",
"lint:js-fix": "yarn lint:js-fix:src &&yarn lint:js-fix:test && yarn lint:js-fix:scripts && yarn lint:js-fix:hak",
"lint:js-fix:src": "eslint --fix --max-warnings 0 src",
"lint:js-fix:test": "eslint --fix --max-warnings 0 --config .eslintrc-test.js playwright",
"lint:js-fix:test": "eslint --fix --max-warnings 0 --config .eslintrc-test.js test",
"lint:js-fix:scripts": "eslint --fix --max-warnings 0 --config .eslintrc-scripts.js scripts",
"lint:js-fix:hak": "eslint --fix --max-warnings 0 --config .eslintrc-hak.js hak",
"lint:types": "yarn lint:types:src && yarn lint:types:test && yarn lint:types:scripts && yarn lint:types:hak",
"lint:types:src": "tsc --noEmit",
"lint:types:test": "tsc --noEmit -p playwright/tsconfig.json",
"lint:types:test": "tsc --noEmit -p test/tsconfig.json",
"lint:types:scripts": "tsc --noEmit -p scripts/tsconfig.json",
"lint:types:hak": "tsc --noEmit -p hak/tsconfig.json",
"lint:workflows": "find .github/workflows -type f \\( -iname '*.yaml' -o -iname '*.yml' \\) | xargs -I {} sh -c 'echo \"Linting {}\"; action-validator \"{}\"'",
"lint:knip": "knip",
"build:native": "yarn run hak",
"build:native:universal": "yarn run hak --target x86_64-apple-darwin fetchandbuild && yarn run hak --target aarch64-apple-darwin fetchandbuild && yarn run hak --target x86_64-apple-darwin --target aarch64-apple-darwin copyandlink",
"build:32": "yarn run build:ts && yarn run build:res && electron-builder --ia32",
@@ -50,16 +47,13 @@
"build": "yarn run build:ts && yarn run build:res && electron-builder",
"build:ts": "tsc",
"build:res": "ts-node scripts/copy-res.ts",
"docker:setup": "docker build --platform linux/amd64 -t element-desktop-dockerbuild dockerbuild",
"docker:setup": "docker build -t element-desktop-dockerbuild dockerbuild",
"docker:build:native": "scripts/in-docker.sh yarn run hak",
"docker:build": "scripts/in-docker.sh yarn run build",
"docker:install": "scripts/in-docker.sh yarn install",
"clean": "rimraf webapp.asar dist packages deploys lib",
"hak": "ts-node scripts/hak/index.ts",
"test": "playwright test",
"test:open": "yarn test --ui",
"test:screenshots:build": "docker build playwright -t element-desktop-playwright --platform linux/amd64",
"test:screenshots:run": "docker run --rm --network host -v $(pwd):/work/element-desktop -v /var/run/docker.sock:/var/run/docker.sock --platform linux/amd64 -it element-desktop-playwright"
"test": "jest"
},
"dependencies": {
"@sentry/electron": "^4.3.0",
@@ -70,59 +64,147 @@
"electron-window-state": "^5.0.3",
"minimist": "^1.2.6",
"node-fetch": "^2",
"png-to-ico": "^2.1.1",
"uuid": "^9.0.0"
"png-to-ico": "^2.1.1"
},
"devDependencies": {
"@action-validator/cli": "^0.5.3",
"@action-validator/core": "^0.5.3",
"@babel/core": "^7.18.10",
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@electron/asar": "^3.2.3",
"@electron/fuses": "^1.7.0",
"@playwright/test": "1.41.2",
"@electron/notarize": "^1.2.3",
"@types/auto-launch": "^5.0.1",
"@types/counterpart": "^0.18.1",
"@types/detect-libc": "^1.0.0",
"@types/jest": "^29.0.0",
"@types/minimist": "^1.2.1",
"@types/mkdirp": "^1.0.2",
"@types/node": "18.19.8",
"@types/node": "16.18.30",
"@types/pacote": "^11.1.1",
"@types/tar": "^6.1.3",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"app-builder-lib": "24.12.0",
"@typescript-eslint/eslint-plugin": "^5.42.0",
"@typescript-eslint/parser": "^5.42.0",
"allchange": "^1.0.6",
"app-builder-lib": "24.4.0",
"babel-jest": "^29.0.0",
"chokidar": "^3.5.2",
"detect-libc": "^2.0.0",
"electron": "^28.0.0",
"electron-builder": "24.9.1",
"electron-builder-squirrel-windows": "24.12.0",
"detect-libc": "^1.0.3",
"electron": "^24.0.0",
"electron-builder": "24.4.0",
"electron-builder-squirrel-windows": "24.4.0",
"electron-devtools-installer": "^3.2.0",
"eslint": "^8.26.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^9.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-matrix-org": "^1.0.0",
"eslint-plugin-unicorn": "^50.0.0",
"eslint-plugin-unicorn": "^47.0.0",
"expect-playwright": "^0.8.0",
"find-npm-prefix": "^1.0.2",
"fs-extra": "^11.0.0",
"glob": "^10.0.0",
"knip": "^4.0.1",
"matrix-web-i18n": "^3.1.3",
"jest": "^29.0.0",
"matrix-web-i18n": "^1.3.0",
"mkdirp": "^3.0.0",
"node-pre-gyp": "^0.17.0",
"pacote": "^17.0.0",
"prettier": "^3.0.0",
"pacote": "^15.0.0",
"playwright": "^1.25.0",
"prettier": "^2.8.1",
"rimraf": "^5.0.0",
"tar": "^6.1.2",
"ts-jest": "^29.0.0",
"ts-node": "^10.9.1",
"typescript": "5.3.3"
"typescript": "5.0.4"
},
"hakDependencies": {
"matrix-seshat": "^3.0.1",
"keytar": "^7.9.0"
},
"resolutions": {
"@types/node": "18.19.8"
"@types/node": "16.18.30"
},
"build": {
"appId": "im.riot.app",
"asarUnpack": "**/*.node",
"files": [
"package.json",
{
"from": ".hak/hakModules",
"to": "node_modules"
},
"lib/**"
],
"extraResources": [
{
"from": "res/img",
"to": "img"
},
"webapp.asar"
],
"linux": {
"target": [
"tar.gz",
"deb"
],
"category": "Network;InstantMessaging;Chat",
"maintainer": "support@element.io",
"icon": "build/icons"
},
"deb": {
"packageCategory": "net",
"depends": [
"libgtk-3-0",
"libnotify4",
"libnss3",
"libxss1",
"libxtst6",
"xdg-utils",
"libatspi2.0-0",
"libuuid1",
"libsecret-1-0",
"libasound2",
"libgbm1"
],
"recommends": [
"libsqlcipher0",
"element-io-archive-keyring"
]
},
"mac": {
"category": "public.app-category.social-networking",
"darkModeSupport": true,
"hardenedRuntime": true,
"gatekeeperAssess": true,
"entitlements": "./build/entitlements.mac.plist",
"icon": "build/icons/icon.icns"
},
"win": {
"target": [
"squirrel"
],
"signingHashAlgorithms": [
"sha256"
],
"icon": "build/icons/icon.ico"
},
"directories": {
"output": "dist"
},
"protocols": [
{
"name": "element",
"schemes": [
"element"
]
}
]
},
"jest": {
"testEnvironment": "node",
"testMatch": [
"<rootDir>/test/**/*-test.[jt]s?(x)"
],
"setupFilesAfterEnv": [
"expect-playwright"
]
}
}

View File

@@ -1,33 +0,0 @@
/*
Copyright 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { defineConfig } from "@playwright/test";
export default defineConfig({
use: {
viewport: { width: 1280, height: 720 },
video: "retain-on-failure",
trace: "on-first-retry",
},
testDir: "playwright/e2e",
outputDir: "playwright/test-results",
workers: 1,
retries: process.env.CI ? 2 : 0,
reporter: [["html", { outputFolder: "playwright/html-report" }]],
snapshotDir: "playwright/snapshots",
snapshotPathTemplate: "{snapshotDir}/{testFilePath}/{arg}-{platform}{ext}",
timeout: 10 * 1000,
});

View File

@@ -1,5 +0,0 @@
/test-results/
/html-report/
# Only commit snapshots from Linux
/snapshots/**/*.png
!/snapshots/**/*-linux.png

View File

@@ -1,10 +0,0 @@
FROM mcr.microsoft.com/playwright:v1.41.1-jammy
WORKDIR /work/element-desktop
RUN apt-get update && apt-get -y install xvfb
USER 1000:1000
COPY docker-entrypoint.sh /opt/docker-entrypoint.sh
ENTRYPOINT ["bash", "/opt/docker-entrypoint.sh"]

View File

@@ -1,11 +0,0 @@
#!/bin/bash
set -e
echo "Starting Xvfb"
Xvfb :99 -ac &
sleep 2
export DISPLAY=:99
npx playwright test --update-snapshots --reporter line $1

View File

@@ -1,26 +0,0 @@
/*
Copyright 2022 - 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { test, expect } from "../../element-desktop-test";
test.describe("App launch", () => {
test("should launch and render the welcome view successfully", async ({ page }) => {
await page.locator("#matrixchat").waitFor();
await page.locator(".mx_Welcome").waitFor();
await expect(page).toHaveURL("vector://vector/webapp/#/welcome");
await expect(page).toHaveScreenshot();
});
});

View File

@@ -1,57 +0,0 @@
/*
Copyright 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { _electron as electron, test as base, expect as baseExpect, type ElectronApplication } from "@playwright/test";
import fs from "node:fs/promises";
import path from "node:path";
import os from "node:os";
export const test = base.extend<{ app: ElectronApplication; tmpDir: string }>({
// eslint-disable-next-line no-empty-pattern
tmpDir: async ({}, use) => {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "element-desktop-tests-"));
console.log("Using temp profile directory: ", tmpDir);
await use(tmpDir);
await fs.rm(tmpDir, { recursive: true });
},
app: async ({ tmpDir }, use) => {
const args = ["--profile-dir", tmpDir];
const executablePath = process.env["ELEMENT_DESKTOP_EXECUTABLE"];
if (!executablePath) {
// Unpackaged mode testing
args.unshift("./lib/electron-main.js");
}
const app = await electron.launch({
env: process.env,
executablePath,
args,
});
await app.firstWindow();
await use(app);
},
page: async ({ app }, use) => {
const window = await app.firstWindow();
await use(window);
await app.close().catch((e) => {
console.error(e);
});
},
});
export const expect = baseExpect;

View File

@@ -1,11 +0,0 @@
{
"compilerOptions": {
"resolveJsonModule": true,
"moduleResolution": "node",
"esModuleInterop": true,
"target": "es2017",
"module": "es2022",
"lib": ["ESNext", "es2021", "dom"],
},
"include": ["**/*.ts"],
}

9
release.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
#
# Script to perform a release of element-desktop.
set -e
cd "$(dirname "$0")"
./node_modules/matrix-js-sdk/release.sh "$@"

View File

@@ -28,11 +28,11 @@ fs.mkdirSync("lib/i18n/strings", { recursive: true });
type Translations = Record<string, Record<string, string> | string>;
function genLangFile(file: string, dest: string): void {
const translations: Translations = {};
const inTrs: Record<string, string> = {};
[file].forEach(function (f) {
if (fs.existsSync(f)) {
try {
Object.assign(translations, JSON.parse(fs.readFileSync(f).toString()));
Object.assign(inTrs, JSON.parse(fs.readFileSync(f).toString()));
} catch (e) {
console.error("Failed: " + f, e);
throw e;
@@ -40,6 +40,7 @@ function genLangFile(file: string, dest: string): void {
}
});
const translations = weblateToCounterpart(inTrs);
const json = JSON.stringify(translations, null, 4);
const filename = path.basename(file);
@@ -49,6 +50,46 @@ function genLangFile(file: string, dest: string): void {
}
}
/*
* Convert translation key from weblate format
* (which only supports a single level) to counterpart
* which requires object values for 'count' translations.
*
* eg.
* "there are %(count)s badgers|one": "a badger",
* "there are %(count)s badgers|other": "%(count)s badgers"
* becomes
* "there are %(count)s badgers": {
* "one": "a badger",
* "other": "%(count)s badgers"
* }
*/
function weblateToCounterpart(inTrs: Record<string, string>): Translations {
const outTrs: Translations = {};
for (const key of Object.keys(inTrs)) {
const keyParts = key.split("|", 2);
if (keyParts.length === 2) {
let obj = outTrs[keyParts[0]];
if (obj === undefined) {
obj = outTrs[keyParts[0]] = {};
} else if (typeof obj === "string") {
// This is a transitional edge case if a string went from singular to pluralised and both still remain
// in the translation json file. Use the singular translation as `other` and merge pluralisation atop.
obj = outTrs[keyParts[0]] = {
other: inTrs[key],
};
console.warn("Found entry in i18n file in both singular and pluralised form", keyParts[0]);
}
obj[keyParts[1]] = inTrs[key];
} else {
outTrs[key] = inTrs[key];
}
}
return outTrs;
}
/*
watch the input files for a given language,
regenerate the file, and regenerating languages.json with the new filename

View File

@@ -12,7 +12,7 @@ import riotDesktopPackageJson from "../package.json";
import { setPackageVersion } from "./set-version";
const PUB_KEY_URL = "https://packages.riot.im/element-release-key.asc";
const PACKAGE_URL_PREFIX = "https://github.com/element-hq/element-web/releases/download/";
const PACKAGE_URL_PREFIX = "https://github.com/vector-im/element-web/releases/download/";
const DEVELOP_TGZ_URL = "https://develop.element.io/develop.tar.gz";
const ASAR_PATH = "webapp.asar";

View File

@@ -0,0 +1,129 @@
#!/usr/bin/env -S npx ts-node
/**
* Script to generate electron-builder.json config files for builds which don't match package.json, e.g. nightlies
* This script has different outputs depending on your os platform.
*
* On Windows:
* Prefixes the nightly version with `0.0.1-nightly.` as it breaks if it is not semver
*
* On macOS:
* Passes --notarytool-team-id to build.mac.notarize.notarize if specified
*
* On Linux:
* Replaces spaces in the product name with dashes as spaces in paths can cause issues
* Passes --deb-custom-control to build.deb.fpm if specified
* Removes libsqlcipher0 recommended dependency if env SQLCIPHER_BUNDLED is asserted.
*/
import parseArgs from "minimist";
import fsProm from "fs/promises";
import * as os from "os";
import { Configuration } from "app-builder-lib";
const ELECTRON_BUILDER_CFG_FILE = "electron-builder.json";
const NIGHTLY_APP_ID = "im.riot.nightly";
const NIGHTLY_APP_NAME = "element-desktop-nightly";
const NIGHTLY_DEB_NAME = "element-nightly";
const argv = parseArgs<{
"nightly"?: string;
"signtool-thumbprint"?: string;
"signtool-subject-name"?: string;
"notarytool-team-id"?: string;
"deb-changelog"?: string;
}>(process.argv.slice(2), {
string: ["nightly", "deb-changelog", "signtool-thumbprint", "signtool-subject-name", "notarytool-team-id"],
});
type DeepWriteable<T> = { -readonly [P in keyof T]: DeepWriteable<T[P]> };
interface PackageBuild extends DeepWriteable<Omit<Configuration, "extraMetadata">> {
extraMetadata?: {
productName?: string;
name?: string;
version?: string;
description?: string;
};
}
interface Package {
build: PackageBuild;
productName: string;
description: string;
}
async function main(): Promise<number | void> {
// Electron builder doesn't overlay with the config in package.json, so load it here
const pkg: Package = JSON.parse(await fsProm.readFile("package.json", "utf8"));
const cfg: PackageBuild = {
...pkg.build,
extraMetadata: {
productName: pkg.productName,
description: pkg.description,
},
};
if (!cfg.deb!.fpm) cfg.deb!.fpm = [];
if (argv.nightly) {
cfg.appId = NIGHTLY_APP_ID;
cfg.extraMetadata!.productName += " Nightly";
cfg.extraMetadata!.name = NIGHTLY_APP_NAME;
cfg.extraMetadata!.description += " (nightly unstable build)";
cfg.deb!.fpm!.push("--name", NIGHTLY_DEB_NAME);
let version = argv.nightly;
if (os.platform() === "win32") {
// The windows packager relies on parsing this as semver, so we have to make it look like one.
// This will give our update packages really stupid names, but we probably can't change that either
// because squirrel windows parses them for the version too. We don't really care: nobody sees them.
// We just give the installer a static name, so you'll just see this in the 'about' dialog.
// Turns out if you use 0.0.0 here it makes Squirrel windows crash, so we use 0.0.1.
version = "0.0.1-nightly." + version;
}
cfg.extraMetadata!.version = version;
} else {
cfg.deb!.fpm!.push("--deb-field", "Replaces: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)");
cfg.deb!.fpm!.push("--deb-field", "Breaks: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)");
}
if (argv["signtool-thumbprint"] && argv["signtool-subject-name"]) {
cfg.win!.certificateSubjectName = argv["signtool-subject-name"];
cfg.win!.certificateSha1 = argv["signtool-thumbprint"];
}
if (argv["notarytool-team-id"]) {
cfg.mac!.notarize = {
teamId: argv["notarytool-team-id"],
};
}
if (os.platform() === "linux") {
// Electron crashes on debian if there's a space in the path.
// https://github.com/vector-im/element-web/issues/13171
cfg.extraMetadata!.productName = cfg.extraMetadata!.productName!.replace(/ /g, "-");
if (argv["deb-changelog"]) {
cfg.deb!.fpm!.push(`--deb-changelog=${argv["deb-changelog"]}`);
}
if (process.env.SQLCIPHER_BUNDLED) {
// Remove sqlcipher dependency when using bundled
cfg.deb!.recommends = cfg.deb!.recommends?.filter((d) => d !== "libsqlcipher0");
}
}
await fsProm.writeFile(ELECTRON_BUILDER_CFG_FILE, JSON.stringify(cfg, null, 4));
}
main()
.then((ret) => {
process.exit(ret!);
})
.catch((e) => {
console.error(e);
process.exit(1);
});

View File

@@ -41,10 +41,7 @@ export default class HakEnv {
public runtimeVersion?: string;
public dotHakDir: string;
public constructor(
public readonly projectRoot: string,
targetId: TargetId | null,
) {
public constructor(public readonly projectRoot: string, targetId: TargetId | null) {
const target = targetId ? TARGETS[targetId] : getHost();
if (!target) {
@@ -84,10 +81,6 @@ export default class HakEnv {
return this.target.platform === "linux";
}
public isFreeBSD(): boolean {
return this.target.platform === "freebsd";
}
public getTargetArch(): Arch {
return this.target.arch;
}
@@ -109,6 +102,6 @@ export default class HakEnv {
}
public wantsStaticSqlCipher(): boolean {
return !(this.isLinux() || this.isFreeBSD()) || process.env.SQLCIPHER_BUNDLED == "1";
return !this.isLinux() || process.env.SQLCIPHER_BUNDLED == "1";
}
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { GLIBC, MUSL, familySync as processLibC } from "detect-libc";
import { GLIBC, MUSL, family as processLibC } from "detect-libc";
// We borrow Rust's target naming scheme as a way of expressing all target
// details in a single string.
@@ -26,9 +26,6 @@ export type TargetId =
| "i686-pc-windows-msvc"
| "x86_64-pc-windows-msvc"
| "aarch64-pc-windows-msvc"
| "i686-unknown-freebsd"
| "x86_64-unknown-freebsd"
| "aarch64-unknown-freebsd"
| "i686-unknown-linux-musl"
| "i686-unknown-linux-gnu"
| "x86_64-unknown-linux-musl"
@@ -39,7 +36,7 @@ export type TargetId =
| "powerpc64le-unknown-linux-gnu";
// Values are expected to match those used in `process.platform`.
export type Platform = "darwin" | "freebsd" | "linux" | "win32";
export type Platform = "darwin" | "linux" | "win32";
// Values are expected to match those used in `process.arch`.
export type Arch = "arm64" | "ia32" | "x64" | "ppc64" | "universal";
@@ -61,7 +58,7 @@ export type WindowsTarget = Target & {
export type LinuxTarget = Target & {
platform: "linux";
libC: typeof GLIBC | typeof MUSL;
libC: typeof processLibC;
};
export type UniversalTarget = Target & {
@@ -109,24 +106,6 @@ const aarch64WindowsMsvc: WindowsTarget = {
vcVarsArch: "arm64",
};
const i686UnknownFreebsd: Target = {
id: "i686-unknown-freebsd",
platform: "freebsd",
arch: "ia32",
};
const x8664UnknownFreebsd: Target = {
id: "x86_64-unknown-freebsd",
platform: "freebsd",
arch: "x64",
};
const aarch64UnknownFreebsd: Target = {
id: "aarch64-unknown-freebsd",
platform: "freebsd",
arch: "arm64",
};
const x8664UnknownLinuxGnu: LinuxTarget = {
id: "x86_64-unknown-linux-gnu",
platform: "linux",
@@ -192,10 +171,6 @@ export const TARGETS: Record<TargetId, Target> = {
"i686-pc-windows-msvc": i686PcWindowsMsvc,
"x86_64-pc-windows-msvc": x8664PcWindowsMsvc,
"aarch64-pc-windows-msvc": aarch64WindowsMsvc,
// FreeBSD
"i686-unknown-freebsd": i686UnknownFreebsd,
"x86_64-unknown-freebsd": x8664UnknownFreebsd,
"aarch64-unknown-freebsd": aarch64UnknownFreebsd,
// Linux
"i686-unknown-linux-musl": i686UnknownLinuxMusl,
"i686-unknown-linux-gnu": i686UnknownLinuxGnu,
@@ -212,7 +187,7 @@ export function getHost(): Target | undefined {
(target) =>
target.platform === process.platform &&
target.arch === process.arch &&
(process.platform !== "linux" || (target as LinuxTarget).libC === processLibC()),
(process.platform !== "linux" || (target as LinuxTarget).libC === processLibC),
);
}

View File

@@ -11,7 +11,6 @@ fi
# Taken from https://www.electron.build/multi-platform-build#docker
# Pass through any vars prefixed with INDOCKER_, removing the prefix
docker run --rm -ti \
--platform linux/amd64 \
--env-file <(env | grep -E '^INDOCKER_' | sed -e 's/^INDOCKER_//') \
--env ELECTRON_CACHE="/root/.cache/electron" \
--env ELECTRON_BUILDER_CACHE="/root/.cache/electron-builder" \

View File

@@ -7,10 +7,10 @@
"module": "commonjs",
"sourceMap": false,
"strict": true,
"lib": ["es2020", "dom"],
"lib": ["es2020", "dom"]
},
"include": ["../src/@types", "./**/*.ts"],
"ts-node": {
"transpileOnly": true,
},
"transpileOnly": true
}
}

View File

@@ -1,29 +0,0 @@
/*
Copyright 2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { Streams } from "electron";
type DisplayMediaCallback = (streams: Streams) => void;
let displayMediaCallback: DisplayMediaCallback | null;
export const getDisplayMediaCallback = (): DisplayMediaCallback | null => {
return displayMediaCallback;
};
export const setDisplayMediaCallback = (callback: DisplayMediaCallback | null): void => {
displayMediaCallback = callback;
};

View File

@@ -19,7 +19,7 @@ limitations under the License.
// Squirrel on windows starts the app with various flags as hooks to tell us when we've been installed/uninstalled etc.
import "./squirrelhooks";
import { app, BrowserWindow, Menu, autoUpdater, protocol, dialog, Input, Event, session } from "electron";
import { app, BrowserWindow, Menu, autoUpdater, protocol, dialog, Input } from "electron";
import * as Sentry from "@sentry/electron/main";
import AutoLaunch from "auto-launch";
import path from "path";
@@ -39,9 +39,6 @@ import webContentsHandler from "./webcontents-handler";
import * as updater from "./updater";
import { getProfileFromDeeplink, protocolInit } from "./protocol";
import { _t, AppLocalization } from "./language-helper";
import { setDisplayMediaCallback } from "./displayMediaCallback";
import { setupMacosTitleBar } from "./macos-titlebar";
import { loadJsonFile } from "./utils";
const argv = minimist(process.argv, {
alias: { help: "h" },
@@ -144,7 +141,8 @@ async function loadConfig(): Promise<void> {
const asarPath = await getAsarPath();
try {
global.vectorConfig = loadJsonFile(asarPath, "config.json");
// eslint-disable-next-line @typescript-eslint/no-var-requires
global.vectorConfig = require(asarPath + "config.json");
} catch (e) {
// it would be nice to check the error code here and bail if the config
// is unparsable, but we get MODULE_NOT_FOUND in the case of a missing
@@ -155,7 +153,8 @@ async function loadConfig(): Promise<void> {
try {
// Load local config and use it to override values from the one baked with the build
const localConfig = loadJsonFile(app.getPath("userData"), "config.json");
// eslint-disable-next-line @typescript-eslint/no-var-requires
const localConfig = require(path.join(app.getPath("userData"), "config.json"));
// If the local config has a homeserver defined, don't use the homeserver from the build
// config. This is to avoid a problem where Riot thinks there are multiple homeservers
@@ -164,13 +163,10 @@ async function loadConfig(): Promise<void> {
// Rip out all the homeserver options from the vector config
global.vectorConfig = Object.keys(global.vectorConfig)
.filter((k) => !homeserverProps.includes(<any>k))
.reduce(
(obj, key) => {
obj[key] = global.vectorConfig[key];
return obj;
},
{} as Omit<Partial<(typeof global)["vectorConfig"]>, keyof typeof homeserverProps>,
);
.reduce((obj, key) => {
obj[key] = global.vectorConfig[key];
return obj;
}, {} as Omit<Partial<(typeof global)["vectorConfig"]>, keyof typeof homeserverProps>);
}
global.vectorConfig = Object.assign(global.vectorConfig, localConfig);
@@ -262,8 +258,7 @@ global.appQuitting = false;
const exitShortcuts: Array<(input: Input, platform: string) => boolean> = [
(input, platform): boolean => platform !== "darwin" && input.alt && input.key.toUpperCase() === "F4",
(input, platform): boolean => platform !== "darwin" && input.control && input.key.toUpperCase() === "Q",
(input, platform): boolean =>
platform === "darwin" && input.meta && !input.control && input.key.toUpperCase() === "Q",
(input, platform): boolean => platform === "darwin" && input.meta && input.key.toUpperCase() === "Q",
];
const warnBeforeExit = (event: Event, input: Input): void => {
@@ -276,12 +271,12 @@ const warnBeforeExit = (event: Event, input: Input): void => {
dialog.showMessageBoxSync(global.mainWindow, {
type: "question",
buttons: [
_t("action|cancel"),
_t("action|close_brand", {
_t("Cancel"),
_t("Close %(brand)s", {
brand: global.vectorConfig.brand || "Element",
}),
],
message: _t("confirm_quit"),
message: _t("Are you sure you want to quit?"),
defaultId: 1,
cancelId: 0,
}) === 0;
@@ -458,9 +453,6 @@ app.on("ready", async () => {
// https://www.electronjs.org/docs/faq#the-font-looks-blurry-what-is-this-and-what-can-i-do
backgroundColor: "#fff",
titleBarStyle: process.platform === "darwin" ? "hidden" : "default",
trafficLightPosition: { x: 9, y: 8 },
icon: global.trayConfig.icon_path,
show: false,
autoHideMenuBar: global.store.get("autoHideMenuBar", true),
@@ -479,10 +471,6 @@ app.on("ready", async () => {
});
global.mainWindow.loadURL("vector://vector/webapp/");
if (process.platform === "darwin") {
setupMacosTitleBar(global.mainWindow);
}
// Handle spellchecker
// For some reason spellCheckerEnabled isn't persisted, so we have to use the store here
global.mainWindow.webContents.session.setSpellCheckerEnabled(global.store.get("spellCheckerEnabled", true));
@@ -544,11 +532,6 @@ app.on("ready", async () => {
store: global.store,
components: [(): void => tray.initApplicationMenu(), (): void => Menu.setApplicationMenu(buildMenuTemplate())],
});
session.defaultSession.setDisplayMediaRequestHandler((_, callback) => {
global.mainWindow?.webContents.send("openDesktopCapturerSourcePicker");
setDisplayMediaCallback(callback);
});
});
app.on("window-all-closed", () => {

47
src/i18n/strings/ar.json Normal file
View File

@@ -0,0 +1,47 @@
{
"File": "ملف",
"Close": "أغلِق",
"Actual Size": "المقاس الفعلي",
"View": "منظور",
"Select All": "حدّد الكل",
"Delete": "احذف",
"Copy": "انسخ",
"Edit": "تحرير",
"Cancel": "ألغِ",
"Bring All to Front": "ضَع الكل في المقدّمة",
"Speech": "نطق",
"Add to dictionary": "أضِف إلى القاموس",
"The image failed to save": "فشل حفظ الصورة",
"Failed to save image": "فشل حفظ الصورة",
"Save image as...": "احفظ الصورة كَ‍...",
"Copy link address": "انسخ عنوان الرابط",
"Copy email address": "انسخ عنوان البريد الإلكتروني",
"Copy image": "انسخ الصورة",
"Zoom": "تقريب",
"Stop Speaking": "أوقِف النطق",
"Start Speaking": "ابدأ النطق",
"Unhide": "اعرض",
"Hide Others": "أخفِ البقية",
"Hide": "أخفِ",
"Services": "الخدمات",
"About": "عن",
"Element Help": "مساعدة Element",
"Help": "مساعدة",
"Minimize": "صغّر",
"Window": "نافذة",
"Toggle Developer Tools": "فعّل/عطّل أدوات المطوّرين",
"Toggle Full Screen": "فعّل/عطّل ملء الشاشة",
"Preferences": "التفضيلات",
"Zoom In": "قرّب",
"Zoom Out": "بعّد",
"Paste and Match Style": "ألصِق وطابِق النمط",
"Paste": "ألصِق",
"Cut": "قصّ",
"Redo": "أعِد",
"Undo": "تراجَع",
"Quit": "غادِر",
"Show/Hide": "اعرض/أخفِ",
"Are you sure you want to quit?": "أمتأكّد من الإغلاق؟",
"Copy image address": "انسخ عنوان (رابط) الصورة",
"Close %(brand)s": "اغلاق %(brand)s"
}

View File

@@ -0,0 +1 @@
{}

45
src/i18n/strings/be.json Normal file
View File

@@ -0,0 +1,45 @@
{
"Add to dictionary": "Дадаць у слоўнік",
"The image failed to save": "Не атрымалася захаваць малюнак",
"Failed to save image": "Не атрымалася захаваць малюнак",
"Save image as...": "Захаваць малюнак як...",
"Copy link address": "Скапіраваць спасылку",
"Copy email address": "Скапіраваць адрас пошты",
"Copy image": "Скапіраваць малюнак",
"File": "Файл",
"Bring All to Front": "Вынесці ўсё наперад",
"Zoom": "Маштаб",
"Stop Speaking": "Перастаць гаварыць",
"Start Speaking": "Гаварыць",
"Speech": "Голас",
"Unhide": "Паказаць",
"Hide Others": "Схаваць іншыя",
"Hide": "Схаваць",
"Services": "Сервісы",
"About": "Аб праграме",
"Element Help": "Даведка Element",
"Help": "Даведка",
"Close": "Зачыніць",
"Minimize": "Згарнуць",
"Window": "Акно",
"Toggle Developer Tools": "Пераключэнне інструментаў распрацоўніка",
"Toggle Full Screen": "Пераключэнне на ўвесь экран",
"Preferences": "Параметры",
"Zoom Out": "Паменшыць",
"Zoom In": "Павялічыць",
"Actual Size": "Фактычны Памер",
"View": "Прагляд",
"Select All": "Выбраць усё",
"Delete": "Выдаліць",
"Paste and Match Style": "Уставіць і супаставіць стыль",
"Paste": "Уставіць",
"Copy": "Капіяваць",
"Cut": "Выразаць",
"Redo": "Паўтарыць",
"Undo": "Адмяніць",
"Edit": "Змяніць",
"Quit": "Выйсці",
"Show/Hide": "Паказаць / схаваць",
"Are you sure you want to quit?": "Вы ўпэўненыя, што хочаце выйсці?",
"Cancel": "Адмена"
}

46
src/i18n/strings/bg.json Normal file
View File

@@ -0,0 +1,46 @@
{
"Add to dictionary": "Добави към речника",
"The image failed to save": "Изображението не успя да се запази",
"Failed to save image": "Неуспешно запазване на изображението",
"Save image as...": "Запази изображението като...",
"Copy link address": "Копирай линка",
"Copy image address": "Копирай адреса на изображението",
"Copy email address": "Копирай имейл адрес",
"Copy image": "Копирай изображение",
"File": "Файл",
"Bring All to Front": "Покажи всички най-отгоре",
"Zoom": "Мащабирай",
"Stop Speaking": "Спри да говориш",
"Start Speaking": "Започни да говориш",
"Speech": "Говор",
"Unhide": "Покажи",
"Hide Others": "Скрий Останалите",
"Hide": "Скрий",
"Services": "Услуги",
"About": "Относно",
"Element Help": "Помощ за Елемент",
"Help": "Помощ",
"Close": "Затвори",
"Minimize": "Минимизирай",
"Window": "Прозорец",
"Toggle Developer Tools": "Превключи инструментите за разработчици",
"Toggle Full Screen": "Превключи на Цял екран",
"Preferences": "Предпочитания",
"Zoom Out": "Намали",
"Zoom In": "Увеличи",
"Actual Size": "Действителен Размер",
"View": "Преглед",
"Select All": "Избери Всичко",
"Delete": "Изтрий",
"Paste and Match Style": "Постави и Използвай текущия стил",
"Paste": "Постави",
"Copy": "Копирай",
"Cut": "Изрежи",
"Redo": "Върни",
"Undo": "Отмени",
"Edit": "Редактирай",
"Quit": "Напусни",
"Show/Hide": "Покажи/Скрий",
"Are you sure you want to quit?": "Сигурен ли си че искаш да напуснеш?",
"Cancel": "Отказ"
}

46
src/i18n/strings/bn.json Normal file
View File

@@ -0,0 +1,46 @@
{
"Are you sure you want to quit?": "তুমি কি আসলেই বের হতে চাও?",
"Cancel": "বাতিল",
"Save image as...": "ছবি সংরক্ষণের ধরন...",
"Failed to save image": "ছবি সংরক্ষণ ব্যর্থ",
"The image failed to save": "ছবি সংরক্ষণ ব্যর্থ",
"Add to dictionary": "অভিধানে যোগ করি",
"Copy link address": "সংযোগের ঠিকানা অনুলিপি করো",
"Copy image address": "ছবির ঠিকানা অনুলিপি করো",
"Copy email address": "ইমেইল ঠিকানা অনুলিপি করো",
"Copy image": "ছবি অনুলিপি করো",
"File": "নথি",
"Bring All to Front": "সবকিছু সামনে আনো",
"Zoom": "বড় করা",
"Stop Speaking": "কথা বন্ধ করো",
"Start Speaking": "কথা শুরু করো",
"Speech": "বাচন",
"Unhide": "দেখাও",
"Hide Others": "অন্যগুলো লুকাও",
"Hide": "লুকাও",
"Services": "সেবা",
"About": "আমাদের সম্পর্কে",
"Element Help": "এলিমেন্ট সাহায্য",
"Help": "সাহায্য",
"Close": "বন্ধ",
"Minimize": "সংকোচন",
"Window": "জানালা",
"Toggle Developer Tools": "ডেভেলপার সরঞ্জামাদি",
"Toggle Full Screen": "পূর্ণ পর্দা করো/বের হও",
"Preferences": "পছন্দসমূহ",
"Zoom Out": "ছোট করো",
"Zoom In": "বড়ো করো",
"Actual Size": "আসল আকার",
"View": "দেখো",
"Select All": "সব নির্বাচন",
"Delete": "অপসারণ",
"Paste and Match Style": "লেপন ও একই ধরনে",
"Paste": "লেপন",
"Copy": "অনুলিপি",
"Cut": "কাটো",
"Redo": "পুন",
"Undo": "ফিরত",
"Edit": "সম্পাদনা",
"Quit": "প্রস্থান",
"Show/Hide": "দেখাও/লুকাও"
}

45
src/i18n/strings/ca.json Normal file
View File

@@ -0,0 +1,45 @@
{
"Add to dictionary": "Afegeix al diccionari",
"The image failed to save": "S'ha fallat en desar la imatge",
"Failed to save image": "S'ha fallat en desar la imatge",
"Save image as...": "Anomena i desa la imatge...",
"Copy link address": "Copia l'adreça de l'enllaç",
"Copy email address": "Copia l'adreça de correu electrònic",
"Copy image": "Copia la imatge",
"File": "Fitxer",
"Bring All to Front": "Porta-ho tot al davant",
"Zoom": "Escala",
"Stop Speaking": "Para la veu",
"Start Speaking": "Comença la veu",
"Speech": "Veu",
"Unhide": "Deixa d'amagar",
"Hide Others": "Amaga les altres",
"Hide": "Amaga",
"Services": "Serveis",
"About": "Quant a",
"Element Help": "Ajuda sobre l'Element",
"Help": "Ajuda",
"Close": "Tanca",
"Minimize": "Minimitza",
"Window": "Finestra",
"Toggle Developer Tools": "Commuta les eines per a desenvolupadors",
"Toggle Full Screen": "Commuta la pantalla completa",
"Preferences": "Preferències",
"Zoom Out": "Allunya",
"Zoom In": "Apropia",
"Actual Size": "Mida real",
"View": "Visualitza",
"Select All": "Selecciona-ho tot",
"Delete": "Suprimeix",
"Paste and Match Style": "Enganxa i fes coincidir l'estil",
"Paste": "Enganxa",
"Copy": "Copia",
"Cut": "Retalla",
"Redo": "Refés",
"Undo": "Desfés",
"Edit": "Edita",
"Quit": "Surt",
"Show/Hide": "Mostra/Amaga",
"Are you sure you want to quit?": "Esteu segur que voleu sortir?",
"Cancel": "Cancel·la"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Storno",
"close": "Zavřít",
"close_brand": "Zavřít %(brand)s",
"copy": "Zkopírovat",
"cut": "Vyjmout",
"delete": "Smazat",
"edit": "Upravit",
"minimise": "Minimalizovat",
"paste": "Vložit",
"paste_match_style": "Vložit a přizpůsobit styl",
"quit": "Ukončit",
"redo": "Znovu",
"select_all": "Vybrat vše",
"show_hide": "Zobrazit/Skrýt",
"undo": "Zpět",
"zoom_in": "Přiblížit",
"zoom_out": "Oddálit"
},
"common": {
"about": "O",
"brand_help": "%(brand)s nápověda",
"help": "Nápověda",
"preferences": "Předvolby"
},
"confirm_quit": "Opravdu chcete ukončit aplikaci?",
"edit_menu": {
"speech": "Řeč",
"speech_start_speaking": "Spustit nahrávání hlasu",
"speech_stop_speaking": "Zastavit nahrávání hlasu"
},
"file_menu": {
"label": "Soubor"
},
"menu": {
"hide": "Skrýt",
"hide_others": "Skrýt ostatní",
"services": "Služby",
"unhide": "Zrušit skrytí"
},
"right_click_menu": {
"add_to_dictionary": "Přidat do slovníku",
"copy_email": "Kopírovat e-mailovou adresu",
"copy_image": "Kopírovat obrázek",
"copy_image_url": "Kopírovat adresu obrázku",
"copy_link_url": "Kopírovat adresu odkazu",
"save_image_as": "Uložit obrázek jako...",
"save_image_as_error_description": "Obrázek se nepodařilo uložit",
"save_image_as_error_title": "Chyba při ukládání obrázku"
},
"view_menu": {
"actual_size": "Aktuální velikost",
"toggle_developer_tools": "Přepnout zobrazení nástrojů pro vývojáře",
"toggle_full_screen": "Přepnout zobrazení celé obrazovky",
"view": "Zobrazit"
},
"window_menu": {
"bring_all_to_front": "Přenést vše do popředí",
"label": "Okno",
"zoom": "Lupa"
}
"Add to dictionary": "Přidat do slovníku",
"Failed to save image": "Chyba při ukládání obrázku",
"The image failed to save": "Obrázek se nepodařilo uložit",
"Save image as...": "Uložit obrázek jako...",
"Copy link address": "Kopírovat adresu odkazu",
"Copy image address": "Kopírovat adresu obrázku",
"Copy email address": "Kopírovat e-mailovou adresu",
"Copy image": "Kopírovat obrázek",
"File": "Soubor",
"Bring All to Front": "Přenést vše do popředí",
"Zoom": "Lupa",
"Stop Speaking": "Zastavit nahrávání hlasu",
"Start Speaking": "Spustit nahrávání hlasu",
"Speech": "Řeč",
"Unhide": "Zrušit skrytí",
"Hide Others": "Skrýt ostatní",
"Hide": "Skrýt",
"Services": "Služby",
"About": "O aplikaci",
"Element Help": "Nápověda aplikace Element",
"Help": "Nápověda",
"Close": "Zavřít",
"Minimize": "Minimalizovat",
"Window": "Okno",
"Toggle Developer Tools": "Přepnout zobrazení nástrojů pro vývojáře",
"Toggle Full Screen": "Přepnout zobrazení celé obrazovky",
"Preferences": "Předvolby",
"Zoom Out": "Oddálit",
"Zoom In": "Přiblížit",
"Actual Size": "Aktuální velikost",
"View": "Zobrazit",
"Select All": "Vybrat vše",
"Delete": "Smazat",
"Paste and Match Style": "Vložit a přizpůsobit styl",
"Paste": "Vložit",
"Copy": "Kopírovat",
"Cut": "Vyjmout",
"Redo": "Znovu",
"Undo": "Zpět",
"Edit": "Úpravy",
"Quit": "Ukončit",
"Show/Hide": "Zobrazit/Skrýt",
"Are you sure you want to quit?": "Opravdu chcete ukončit aplikaci?",
"Close %(brand)s": "Zavřít %(brand)s",
"Cancel": "Zrušit"
}

47
src/i18n/strings/de.json Normal file
View File

@@ -0,0 +1,47 @@
{
"Speech": "Sprache",
"Paste and Match Style": "Einfügen und Formatierung beibehalten",
"Stop Speaking": "Aufnahme beenden",
"Start Speaking": "Aufnahme starten",
"Services": "Dienste",
"Are you sure you want to quit?": "Wirklich beenden?",
"Add to dictionary": "Wörterbuch hinzufügen",
"The image failed to save": "Das Bild konnte nicht gespeichert werden",
"Failed to save image": "Bild kann nicht gespeichert werden",
"Save image as...": "Bild speichern unter...",
"Copy link address": "Link-Adresse kopieren",
"Copy email address": "Email-Adresse kopieren",
"Copy image": "Bild kopieren",
"File": "Datei",
"Bring All to Front": "Alles in den Vordergrund",
"Zoom": "Zoom",
"Unhide": "Wieder anzeigen",
"Hide Others": "Andere verstecken",
"Hide": "Verstecken",
"About": "Über",
"Element Help": "Hilfe zu Element",
"Help": "Hilfe",
"Close": "Schließen",
"Minimize": "Minimieren",
"Window": "Fenster",
"Toggle Developer Tools": "Developer-Tools an/aus",
"Toggle Full Screen": "Vollbildschirm an/aus",
"Preferences": "Einstellungen",
"Zoom Out": "Verkleinern",
"Zoom In": "Vergrößern",
"Actual Size": "Tatsächliche Größe",
"View": "Ansicht",
"Select All": "Alles auswählen",
"Delete": "Löschen",
"Paste": "Einfügen",
"Copy": "Kopieren",
"Cut": "Ausschneiden",
"Redo": "Wiederherstellen",
"Undo": "Rückgängig",
"Edit": "Bearbeiten",
"Quit": "Beenden",
"Show/Hide": "Anzeigen/Ausblenden",
"Cancel": "Abbrechen",
"Copy image address": "Bild-Adresse kopieren",
"Close %(brand)s": "%(brand)s schließen"
}

View File

@@ -1,63 +0,0 @@
{
"action": {
"cancel": "Abbrechen",
"close": "Schließen",
"close_brand": "%(brand)s schließen",
"copy": "Kopieren",
"cut": "Ausschneiden",
"delete": "Löschen",
"edit": "Bearbeiten",
"minimise": "Minimieren",
"paste": "Einfügen",
"paste_match_style": "Einfügen und Formatierung beibehalten",
"quit": "Beenden",
"redo": "Wiederherstellen",
"select_all": "Alles auswählen",
"show_hide": "Anzeigen/Ausblenden",
"undo": "Rückgängig",
"zoom_in": "Vergrößern",
"zoom_out": "Verkleinern"
},
"common": {
"about": "Über",
"brand_help": "%(brand)s Hilfe",
"help": "Hilfe",
"preferences": "Einstellungen"
},
"confirm_quit": "Wirklich beenden?",
"edit_menu": {
"speech": "Sprache",
"speech_start_speaking": "Aufnahme starten",
"speech_stop_speaking": "Aufnahme beenden"
},
"file_menu": {
"label": "Datei"
},
"menu": {
"hide": "Verstecken",
"hide_others": "Andere verstecken",
"services": "Dienste",
"unhide": "Wieder anzeigen"
},
"right_click_menu": {
"add_to_dictionary": "Wörterbuch hinzufügen",
"copy_email": "Email-Adresse kopieren",
"copy_image": "Bild kopieren",
"copy_image_url": "Bild-Adresse kopieren",
"copy_link_url": "Link-Adresse kopieren",
"save_image_as": "Bild speichern unter...",
"save_image_as_error_description": "Das Bild konnte nicht gespeichert werden",
"save_image_as_error_title": "Bild kann nicht gespeichert werden"
},
"view_menu": {
"actual_size": "Tatsächliche Größe",
"toggle_developer_tools": "Developer-Tools an/aus",
"toggle_full_screen": "Vollbildschirm an/aus",
"view": "Ansicht"
},
"window_menu": {
"bring_all_to_front": "Alles in den Vordergrund",
"label": "Fenster",
"zoom": "Zoomen"
}
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Ακύρωση",
"close": "Κλείσιμο",
"close_brand": "Κλείσιμο %(brand)s",
"copy": "Αντιγραφή",
"cut": "Αποκοπή",
"delete": "Διαγραφή",
"edit": "Επεξεργασία",
"minimise": "Ελαχιστοποίηση",
"paste": "Επικόλληση",
"paste_match_style": "Επικόλληση και Ταίριασμα Στυλ",
"quit": "Κλείσιμο",
"redo": "Επανάληψη",
"select_all": "Επιλογή Όλων",
"show_hide": "Eμφάνιση/Απόκρυψη",
"undo": "Αναίρεση",
"zoom_in": "Μεγέθυνση",
"zoom_out": "Σμίκρυνση"
},
"common": {
"about": "Σχετικά με",
"brand_help": "%(brand)s Υποστήριξη",
"help": "Βοήθεια",
"preferences": "Προτιμήσεις"
},
"confirm_quit": "Είστε βέβαιος ότι θέλετε να εγκαταλείψετε;",
"edit_menu": {
"speech": "Ομιλία",
"speech_start_speaking": "Ξεκινήστε να μιλάτε",
"speech_stop_speaking": "Τερματίστε να μιλάτε"
},
"file_menu": {
"label": "Αρχείο"
},
"menu": {
"hide": "Απόκρυψη",
"hide_others": "Απόκρυψη Άλλων",
"services": "Υπηρεσίες",
"unhide": "Εμφάνιση"
},
"right_click_menu": {
"add_to_dictionary": "Προσθήκη στο λεξικό",
"copy_email": "Αντιγραφή διεύθυνσης email",
"copy_image": "Αντιγραφή εικόνας",
"copy_image_url": "Αντιγραφή διεύθυνσης εικόνας",
"copy_link_url": "Αντιγραφή διεύθυνσης συνδέσμου",
"save_image_as": "Αποθήκευση εικόνας ως...",
"save_image_as_error_description": "Η αποθήκευση της εικόνας απέτυχε",
"save_image_as_error_title": "Αποτυχία αποθήκευσης εικόνας"
},
"view_menu": {
"actual_size": "Πραγματικό Μέγεθος",
"toggle_developer_tools": "Άνοιγμα Εργαλείων Προγραμματιστή",
"toggle_full_screen": "Εναλλαγή σε Πλήρη Οθόνη",
"view": "Προβολή"
},
"window_menu": {
"bring_all_to_front": "Μεταφορά Όλων στο Προσκήνιο",
"label": "Παράθυρο",
"zoom": "Ζουμ"
}
"Are you sure you want to quit?": "Είστε βέβαιος ότι θέλετε να εγκαταλείψετε;",
"Zoom": "Ζουμ",
"Unhide": "Εμφάνιση",
"Window": "Παράθυρο",
"Toggle Developer Tools": "Άνοιγμα Εργαλείων Προγραμματιστή",
"Toggle Full Screen": "Εναλλαγή σε Πλήρη Οθόνη",
"Copy email address": "Αντιγραφή διεύθυνσης email",
"File": "Αρχείο",
"Bring All to Front": "Μεταφορά Όλων στο Προσκήνιο",
"Stop Speaking": "Τερματίστε να μιλάτε",
"Start Speaking": "Ξεκινήστε να μιλάτε",
"Speech": "Ομιλία",
"Hide Others": "Απόκρυψη Άλλων",
"Hide": "Απόκρυψη",
"Services": "Υπηρεσίες",
"About": "Σχετικά με",
"Element Help": "Βοήθεια για το Element",
"Help": "Βοήθεια",
"Close": "Κλείσιμο",
"Minimize": "Ελαχιστοποίηση",
"Preferences": "Προτιμήσεις",
"Zoom Out": "Σμίκρυνση",
"Zoom In": "Μεγέθυνση",
"Actual Size": "Πραγματικό Μέγεθος",
"View": "Προβολή",
"Select All": "Επιλογή Όλων",
"Delete": "Διαγραφή",
"Paste and Match Style": "Επικόλληση και Ταίριασμα Στυλ",
"Paste": "Επικόλληση",
"Copy": "Αντιγραφή",
"Cut": "Αποκοπή",
"Redo": "Επανάληψη",
"Undo": "Αναίρεση",
"Edit": "Επεξεργασία",
"Quit": "Κλείσιμο",
"Show/Hide": "Eμφάνιση/Απόκρυψη",
"Cancel": "Ακύρωση",
"Add to dictionary": "Προσθήκη στο λεξικό",
"The image failed to save": "Η αποθήκευση της εικόνας απέτυχε",
"Failed to save image": "Αποτυχία αποθήκευσης εικόνας",
"Save image as...": "Αποθήκευση εικόνας ως...",
"Copy link address": "Αντιγραφή διεύθυνσης συνδέσμου",
"Copy image address": "Αντιγραφή διεύθυνσης εικόνας",
"Copy image": "Αντιγραφή εικόνας",
"Close %(brand)s": "Κλείσιμο %(brand)s"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Cancel",
"close": "Close",
"close_brand": "Close %(brand)s",
"copy": "Copy",
"cut": "Cut",
"delete": "Delete",
"edit": "Edit",
"minimise": "Minimize",
"paste": "Paste",
"paste_match_style": "Paste and Match Style",
"quit": "Quit",
"redo": "Redo",
"select_all": "Select All",
"show_hide": "Show/Hide",
"undo": "Undo",
"zoom_in": "Zoom In",
"zoom_out": "Zoom Out"
},
"common": {
"about": "About",
"brand_help": "%(brand)s Help",
"help": "Help",
"preferences": "Preferences"
},
"confirm_quit": "Are you sure you want to quit?",
"edit_menu": {
"speech": "Speech",
"speech_start_speaking": "Start Speaking",
"speech_stop_speaking": "Stop Speaking"
},
"file_menu": {
"label": "File"
},
"menu": {
"hide": "Hide",
"hide_others": "Hide Others",
"services": "Services",
"unhide": "Unhide"
},
"right_click_menu": {
"add_to_dictionary": "Add to dictionary",
"copy_email": "Copy email address",
"copy_image": "Copy image",
"copy_image_url": "Copy image address",
"copy_link_url": "Copy link address",
"save_image_as": "Save image as...",
"save_image_as_error_description": "The image failed to save",
"save_image_as_error_title": "Failed to save image"
},
"view_menu": {
"actual_size": "Actual Size",
"toggle_developer_tools": "Toggle Developer Tools",
"toggle_full_screen": "Toggle Full Screen",
"view": "View"
},
"window_menu": {
"bring_all_to_front": "Bring All to Front",
"label": "Window",
"zoom": "Zoom"
}
"Cancel": "Cancel",
"Close %(brand)s": "Close %(brand)s",
"Are you sure you want to quit?": "Are you sure you want to quit?",
"Show/Hide": "Show/Hide",
"Quit": "Quit",
"Edit": "Edit",
"Undo": "Undo",
"Redo": "Redo",
"Cut": "Cut",
"Copy": "Copy",
"Paste": "Paste",
"Paste and Match Style": "Paste and Match Style",
"Delete": "Delete",
"Select All": "Select All",
"View": "View",
"Actual Size": "Actual Size",
"Zoom In": "Zoom In",
"Zoom Out": "Zoom Out",
"Preferences": "Preferences",
"Toggle Full Screen": "Toggle Full Screen",
"Toggle Developer Tools": "Toggle Developer Tools",
"Window": "Window",
"Minimize": "Minimize",
"Close": "Close",
"Help": "Help",
"Element Help": "Element Help",
"About": "About",
"Services": "Services",
"Hide": "Hide",
"Hide Others": "Hide Others",
"Unhide": "Unhide",
"Speech": "Speech",
"Start Speaking": "Start Speaking",
"Stop Speaking": "Stop Speaking",
"Zoom": "Zoom",
"Bring All to Front": "Bring All to Front",
"File": "File",
"Copy image": "Copy image",
"Copy email address": "Copy email address",
"Copy image address": "Copy image address",
"Copy link address": "Copy link address",
"Save image as...": "Save image as...",
"Failed to save image": "Failed to save image",
"The image failed to save": "The image failed to save",
"Add to dictionary": "Add to dictionary"
}

View File

@@ -0,0 +1,45 @@
{
"Close": "Close",
"Add to dictionary": "Add to dictionary",
"The image failed to save": "The image failed to save",
"Failed to save image": "Failed to save image",
"Save image as...": "Save image as...",
"Copy link address": "Copy link address",
"Copy email address": "Copy email address",
"Copy image": "Copy image",
"File": "File",
"Bring All to Front": "Bring All to Front",
"Zoom": "Zoom",
"Stop Speaking": "Stop Speaking",
"Start Speaking": "Start Speaking",
"Speech": "Speech",
"Unhide": "Unhide",
"Hide Others": "Hide Others",
"Hide": "Hide",
"Services": "Services",
"About": "About",
"Element Help": "Element Help",
"Help": "Help",
"Minimize": "Minimize",
"Window": "Window",
"Toggle Developer Tools": "Toggle Developer Tools",
"Toggle Full Screen": "Toggle Full Screen",
"Preferences": "Preferences",
"Zoom Out": "Zoom Out",
"Zoom In": "Zoom In",
"Actual Size": "Actual Size",
"View": "View",
"Select All": "Select All",
"Delete": "Delete",
"Paste and Match Style": "Paste and Match Style",
"Paste": "Paste",
"Copy": "Copy",
"Cut": "Cut",
"Redo": "Redo",
"Undo": "Undo",
"Edit": "Edit",
"Quit": "Quit",
"Show/Hide": "Show/Hide",
"Are you sure you want to quit?": "Are you sure you want to quit?",
"Cancel": "Cancel"
}

View File

@@ -1,50 +1,34 @@
{
"action": {
"cancel": "Nuligi",
"close": "Fermi",
"close_brand": "Fermu %(brand)s",
"copy": "Kopii",
"cut": "Tranĉi",
"delete": "Forigi",
"edit": "Redakti",
"minimise": "Minimumigi",
"paste": "Enmeti",
"redo": "Refari",
"select_all": "Elekti Ĉiujn",
"show_hide": "Montri/Kaŝi",
"undo": "Malfari"
},
"common": {
"about": "Prio",
"help": "Helpo",
"preferences": "Agordoj"
},
"confirm_quit": "Ĉu vi certas, ke vi volas ĉesi?",
"edit_menu": {
"speech_start_speaking": "Ekparoli",
"speech_stop_speaking": "Ĉesi Paroli"
},
"file_menu": {
"label": "Dosiero"
},
"menu": {
"hide": "Kaŝi",
"hide_others": "Kaŝi Aliajn",
"unhide": "Malkaŝi"
},
"right_click_menu": {
"copy_email": "Kopiu retadreson",
"copy_image": "Kopiu bildon",
"copy_image_url": "Kopiu adreson de la bildo",
"copy_link_url": "Kopiu ligilon de la bildo",
"save_image_as_error_description": "La bildo malsukcesis elŝutiĝi",
"save_image_as_error_title": "Malsukcesis elŝuti bildon"
},
"view_menu": {
"toggle_developer_tools": "Baskuligi Programistajn Ilojn",
"view": "Vidi"
},
"window_menu": {
"label": "Fenestro"
}
"The image failed to save": "La bildo malsukcesis elŝutiĝi",
"Failed to save image": "Malsukcesis elŝuti bildon",
"Stop Speaking": "Ĉesi Paroli",
"Start Speaking": "Ekparoli",
"Unhide": "Malkaŝi",
"Hide Others": "Kaŝi Aliajn",
"Hide": "Kaŝi",
"About": "Informilo",
"Element Help": "Element-a Helpo",
"Help": "Helpo",
"Toggle Developer Tools": "Baskuligi Programistajn Ilojn",
"Preferences": "Preferoj",
"View": "Vidi",
"Delete": "Forigi",
"Redo": "Refari",
"Undo": "Malfari",
"Edit": "Redakti",
"Show/Hide": "Montri/Kaŝi",
"Cancel": "Nuligi",
"Copy link address": "Kopiu ligilon de la bildo",
"Copy image address": "Kopiu adreson de la bildo",
"Copy email address": "Kopiu retadreson",
"Copy image": "Kopiu bildon",
"File": "Dosiero",
"Minimize": "Minimumigi",
"Window": "Fenestro",
"Select All": "Elekti Ĉiujn",
"Paste": "Enmeti",
"Copy": "Kopiu",
"Cut": "Tranĉi",
"Are you sure you want to quit?": "Ĉu vi certas, ke vi volas ĉesi?",
"Close %(brand)s": "Fermu %(brand)s"
}

View File

@@ -1,62 +1,47 @@
{
"action": {
"cancel": "Cancelar",
"close": "Cerrar",
"close_brand": "Cerrar %(brand)s",
"copy": "Copiar",
"cut": "Cortar",
"delete": "Borrar",
"edit": "Editar",
"minimise": "Minimizar",
"paste": "Pegar",
"paste_match_style": "Pegar manteniendo estilo",
"quit": "Salir",
"redo": "Rehacer",
"select_all": "Seleccionar todo",
"show_hide": "Ver/Ocultar",
"undo": "Deshacer",
"zoom_in": "Acercar",
"zoom_out": "Alejar"
},
"common": {
"about": "Acerca de",
"brand_help": "Ayuda sobre %(brand)s",
"help": "Ayuda",
"preferences": "Preferencias"
},
"confirm_quit": "¿Quieres salir?",
"edit_menu": {
"speech": "Dictado",
"speech_start_speaking": "Empezar a hablar",
"speech_stop_speaking": "Parar de hablar"
},
"file_menu": {
"label": "Archivo"
},
"menu": {
"hide": "Ocultar",
"hide_others": "Ocultar otros",
"services": "Servicios",
"unhide": "Mostrar"
},
"right_click_menu": {
"add_to_dictionary": "Añadir al diccionario",
"copy_email": "Copiar dirección de correo",
"copy_image": "Copiar imagen",
"copy_image_url": "Copiar dirección de la imagen",
"copy_link_url": "Copiar dirección de enlace",
"save_image_as": "Guardar imagen como...",
"save_image_as_error_description": "La imagen no se ha podido guardar",
"save_image_as_error_title": "No se ha podido guardar la imagen"
},
"view_menu": {
"actual_size": "Tamaño real",
"toggle_developer_tools": "Abrir/cerrar herramientas de desarrollo",
"toggle_full_screen": "Entrar/salir de pantalla completa",
"view": "Ver"
},
"window_menu": {
"bring_all_to_front": "Traer todas al primer plano",
"label": "Ventana"
}
"Add to dictionary": "Añadir al diccionario",
"The image failed to save": "La imagen no se ha podido guardar",
"Failed to save image": "No se ha podido guardar la imagen",
"Save image as...": "Guardar imagen como...",
"Copy link address": "Copiar dirección de enlace",
"Copy email address": "Copiar dirección de correo",
"Copy image": "Copiar imagen",
"File": "Archivo",
"Bring All to Front": "Traer todas al primer plano",
"Zoom": "Zoom",
"Start Speaking": "Empezar a hablar",
"Stop Speaking": "Parar de hablar",
"Speech": "Dictado",
"Unhide": "Mostrar",
"Hide Others": "Ocultar otros",
"Hide": "Ocultar",
"Services": "Servicios",
"About": "Acerca de",
"Element Help": "Ayuda de Element",
"Help": "Ayuda",
"Close": "Cerrar",
"Minimize": "Minimizar",
"Window": "Ventana",
"Toggle Developer Tools": "Abrir/cerrar herramientas de desarrollo",
"Toggle Full Screen": "Entrar/salir de pantalla completa",
"Preferences": "Preferencias",
"Zoom Out": "Alejar",
"Zoom In": "Acercar",
"Actual Size": "Tamaño real",
"View": "Ver",
"Select All": "Seleccionar todo",
"Delete": "Eliminar",
"Paste and Match Style": "Pegar manteniendo estilo",
"Paste": "Pegar",
"Copy": "Copiar",
"Cut": "Cortar",
"Redo": "Rehacer",
"Undo": "Deshacer",
"Edit": "Editar",
"Quit": "Salir",
"Show/Hide": "Ver/Ocultar",
"Are you sure you want to quit?": "¿Quieres salir?",
"Cancel": "Cancelar",
"Copy image address": "Copiar dirección de la imagen",
"Close %(brand)s": "Cerrar %(brand)s"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Loobu",
"close": "Sulge",
"close_brand": "Sulge %(brand)s",
"copy": "Kopeeri",
"cut": "Lõika",
"delete": "Kustuta",
"edit": "Muuda",
"minimise": "Vähenda",
"paste": "Aseta",
"paste_match_style": "Aseta kasutades sama stiili",
"quit": "Välju",
"redo": "Tee uuesti",
"select_all": "Vali kõik",
"show_hide": "Näita/peida",
"undo": "Võta tagasi",
"zoom_in": "Suurenda",
"zoom_out": "Vähenda"
},
"common": {
"about": "Rakenduse teave",
"brand_help": "%(brand)s abiteave",
"help": "Abiteave",
"preferences": "Eelistused"
},
"confirm_quit": "Kas sa kindlasti soovid rakendusest väljuda?",
"edit_menu": {
"speech": "Kõne",
"speech_start_speaking": "Alusta rääkimist",
"speech_stop_speaking": "Lõpeta rääkimine"
},
"file_menu": {
"label": "Fail"
},
"menu": {
"hide": "Peida",
"hide_others": "Peida muud",
"services": "Teenused",
"unhide": "Näita uuesti"
},
"right_click_menu": {
"add_to_dictionary": "Lisa sõnastikku",
"copy_email": "Kopeeri e-posti aadress",
"copy_image": "Kopeeri pilt",
"copy_image_url": "Kopeeri pildi aadress",
"copy_link_url": "Kopeeri lingi aadress",
"save_image_as": "Salvesta pilt kui...",
"save_image_as_error_description": "Seda pilti ei õnnestunud salvestada",
"save_image_as_error_title": "Pildi salvestamine ei õnnestunud"
},
"view_menu": {
"actual_size": "Näita tavasuuruses",
"toggle_developer_tools": "Arendaja töövahendid sisse/välja",
"toggle_full_screen": "Täisekraanivaade sisse/välja",
"view": "Näita"
},
"window_menu": {
"bring_all_to_front": "Too kõik esiplaanile",
"label": "Aken",
"zoom": "Suumi"
}
"Element Help": "Rakenduse Element abiteave",
"About": "Rakenduse teave",
"The image failed to save": "Seda pilti ei õnnestunud salvestada",
"Add to dictionary": "Lisa sõnastikku",
"Failed to save image": "Pildi salvestamine ei õnnestunud",
"Save image as...": "Salvesta pilt kui...",
"Copy link address": "Kopeeri lingi aadress",
"Copy email address": "Kopeeri e-posti aadress",
"Copy image": "Kopeeri pilt",
"File": "Fail",
"Bring All to Front": "Too kõik esiplaanile",
"Zoom": "Suumi",
"Stop Speaking": "Lõpeta rääkimine",
"Start Speaking": "Alusta rääkimist",
"Speech": "Kõne",
"Unhide": "Näita uuesti",
"Hide Others": "Peida muud",
"Hide": "Peida",
"Services": "Teenused",
"Help": "Abiteave",
"Close": "Sulge",
"Minimize": "Vähenda",
"Window": "Aken",
"Toggle Developer Tools": "Arendaja töövahendid sisse/välja",
"Toggle Full Screen": "Täisekraanivaade sisse/välja",
"Preferences": "Seadistused",
"Zoom Out": "Vähenda",
"Zoom In": "Suurenda",
"Actual Size": "Näita tavasuuruses",
"View": "Vaata",
"Select All": "Vali kõik",
"Delete": "Kustuta",
"Paste and Match Style": "Aseta kasutades sama stiili",
"Paste": "Aseta",
"Copy": "Kopeeri",
"Cut": "Lõika",
"Redo": "Tee uuesti",
"Undo": "Võta tagasi",
"Edit": "Muuda",
"Quit": "Välju",
"Show/Hide": "Näita/peida",
"Are you sure you want to quit?": "Kas sa kindlasti soovid rakendusest väljuda?",
"Cancel": "Tühista",
"Copy image address": "Kopeeri pildi aadress",
"Close %(brand)s": "Sulge %(brand)s"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "لغو",
"close": "بستن",
"close_brand": "بستن %(brand)s",
"copy": "رونوشت",
"cut": "برش",
"delete": "پاک‌کردن",
"edit": "ویرایش",
"minimise": "کمینه",
"paste": "جای‌گذاری",
"paste_match_style": "جای‌گذاری و تطبیق سَبک",
"quit": "خروج",
"redo": "انجام دوباره",
"select_all": "گزینش همه",
"show_hide": "نمایش/پنهان",
"undo": "بازگردانی",
"zoom_in": "بزرگنمایی به داخل",
"zoom_out": "بزرگنمایی به خارج"
},
"common": {
"about": "درباره",
"brand_help": "کمک %(brand)s",
"help": "راهنما",
"preferences": "ترجیحات"
},
"confirm_quit": "آیا مطمئنید که می‌خواهید خارج شوید؟",
"edit_menu": {
"speech": "صحبت کردن",
"speech_start_speaking": "صحبت کردن را شروع کنید",
"speech_stop_speaking": "صحبت کردن را تمام کنید"
},
"file_menu": {
"label": "پرونده"
},
"menu": {
"hide": "پنهان",
"hide_others": "پنهان کردن دیگران",
"services": "خدمات",
"unhide": "آشکار"
},
"right_click_menu": {
"add_to_dictionary": "افزودن به لغت‌نامه",
"copy_email": "رونوشت نشانی رایانامه",
"copy_image": "رونوشت تصویر",
"copy_image_url": "رونوشت نشانی تصویر",
"copy_link_url": "رونوشت نشانی پیوند",
"save_image_as": "ذخیرهٔ تصویر به عنوان...",
"save_image_as_error_description": "تصویر ذخیره نشد",
"save_image_as_error_title": "ذخیرهٔ تصویر شکست خورد"
},
"view_menu": {
"actual_size": "اندازهٔ واقعی",
"toggle_developer_tools": "تغییر وضعیت ابزارهای توسعه‌دهنده",
"toggle_full_screen": "تغییر وضعیت تمام‌صفحه",
"view": "مشاهده"
},
"window_menu": {
"bring_all_to_front": "همه را به جلو بیاورید",
"label": "پنجره",
"zoom": "بزرگنمایی"
}
"Paste and Match Style": "جای‌گذاری و تطبیق سَبک",
"Add to dictionary": "افزودن به لغت‌نامه",
"The image failed to save": "تصویر ذخیره نشد",
"Failed to save image": "ذخیرهٔ تصویر شکست خورد",
"Save image as...": "ذخیرهٔ تصویر به عنوان...",
"Copy link address": "رونوشت نشانی پیوند",
"Copy image address": "رونوشت نشانی تصویر",
"Copy email address": "رونوشت نشانی رایانامه",
"Copy image": "رونوشت تصویر",
"File": "پرونده",
"Bring All to Front": "همه را به جلو بیاورید",
"Zoom": "بزرگنمایی",
"Speech": "صحبت کردن",
"Stop Speaking": "صحبت کردن را تمام کنید",
"Start Speaking": "صحبت کردن را شروع کنید",
"Unhide": "آشکار",
"Hide Others": "پنهان کردن دیگران",
"Hide": "پنهان",
"Services": "خدمات",
"About": "درباره",
"Element Help": "راهنمای المنت",
"Help": "راهنما",
"Close": "بستن",
"Minimize": "کمینه",
"Window": "پنجره",
"Toggle Developer Tools": "تغییر وضعیت ابزارهای توسعه‌دهنده",
"Toggle Full Screen": "تغییر وضعیت تمام‌صفحه",
"Preferences": "ترجیحات",
"Zoom Out": "بزرگنمایی به خارج",
"Zoom In": "بزرگنمایی به داخل",
"Actual Size": "اندازهٔ واقعی",
"View": "دیدن",
"Select All": "گزینش همه",
"Delete": "حذف",
"Paste": "جای‌گذاری",
"Copy": "رونوشت",
"Cut": "برش",
"Redo": "انجام دوباره",
"Undo": "بازگردانی",
"Edit": "ویرایش",
"Quit": "خروج",
"Show/Hide": "نمایش/پنهان",
"Are you sure you want to quit?": "آیا مطمئنید که می‌خواهید خارج شوید؟",
"Cancel": "لغو",
"Close %(brand)s": "بستن %(brand)s"
}

View File

@@ -1,62 +1,47 @@
{
"action": {
"cancel": "Peruuta",
"close": "Sulje",
"close_brand": "Sulje %(brand)s",
"copy": "Kopioi",
"cut": "Leikkaa",
"delete": "Poista",
"edit": "Muokkaa",
"minimise": "Pienennä",
"paste": "Liitä",
"paste_match_style": "Liitä ja sovita tyyli",
"quit": "Lopeta",
"redo": "Tee uudestaan",
"select_all": "Valitse kaikki",
"show_hide": "Näytä/piilota",
"undo": "Peru",
"zoom_in": "Suurenna",
"zoom_out": "Pienennä"
},
"common": {
"about": "Tietoa",
"help": "Ohje",
"preferences": "Valinnat"
},
"confirm_quit": "Haluatko varmasti poistua?",
"edit_menu": {
"speech": "Puhe",
"speech_start_speaking": "Aloita puhe",
"speech_stop_speaking": "Lopeta puhe"
},
"file_menu": {
"label": "Tiedosto"
},
"menu": {
"hide": "Piilota",
"hide_others": "Piilota muut",
"services": "Palvelut",
"unhide": "Palauta näkyviin"
},
"right_click_menu": {
"add_to_dictionary": "Lisää sanakirjaan",
"copy_email": "Kopioi sähköpostiosoite",
"copy_image": "Kopioi kuva",
"copy_image_url": "Kopioi kuvan osoite",
"copy_link_url": "Kopioi linkin osoite",
"save_image_as": "Tallenna kuva nimellä...",
"save_image_as_error_description": "Kuvan tallennus epäonnistui",
"save_image_as_error_title": "Kuvan tallennus epäonnistui"
},
"view_menu": {
"actual_size": "Alkuperäinen koko",
"toggle_developer_tools": "Näytä tai piilota kehittäjätyökalut",
"toggle_full_screen": "Vaihda koko näytön tilaa",
"view": "Näytä"
},
"window_menu": {
"bring_all_to_front": "Tuo kaikki eteen",
"label": "Ikkuna",
"zoom": "Suurennus"
}
"Paste": "Liitä",
"Paste and Match Style": "Liitä ja sovita tyyli",
"Add to dictionary": "Lisää sanakirjaan",
"The image failed to save": "Kuvan tallennus epäonnistui",
"Failed to save image": "Kuvan tallennus epäonnistui",
"Save image as...": "Tallenna kuva nimellä...",
"Copy link address": "Kopioi linkin osoite",
"Copy email address": "Kopioi sähköpostiosoite",
"Copy image": "Kopioi kuva",
"File": "Tiedosto",
"Bring All to Front": "Tuo kaikki eteen",
"Zoom": "Suurennus",
"Stop Speaking": "Lopeta puhe",
"Start Speaking": "Aloita puhe",
"Speech": "Puhe",
"Unhide": "Palauta näkyviin",
"Hide Others": "Piilota muut",
"Hide": "Piilota",
"Services": "Palvelut",
"About": "Tietoja",
"Element Help": "Elementin ohjeet",
"Help": "Apua",
"Close": "Sulje",
"Minimize": "Pienennä",
"Window": "Ikkuna",
"Toggle Developer Tools": "Näytä tai piilota kehittäjätyökalut",
"Toggle Full Screen": "Vaihda koko näytön tilaa",
"Preferences": "Asetukset",
"Zoom Out": "Pienennä",
"Zoom In": "Suurenna",
"Actual Size": "Alkuperäinen koko",
"View": "Näytä",
"Select All": "Valitse kaikki",
"Delete": "Poista",
"Copy": "Kopioi",
"Cut": "Leikkaa",
"Redo": "Tee uudestaan",
"Undo": "Peru",
"Edit": "Muokkaa",
"Quit": "Lopeta",
"Show/Hide": "Näytä/piilota",
"Are you sure you want to quit?": "Haluatko varmasti poistua?",
"Cancel": "Peruuta",
"Copy image address": "Kopioi kuvan osoite",
"Close %(brand)s": "Sulje %(brand)s"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Annuler",
"close": "Fermer",
"close_brand": "Fermer %(brand)s",
"copy": "Copier",
"cut": "Couper",
"delete": "Supprimer",
"edit": "Modifier",
"minimise": "Minimiser",
"paste": "Coller",
"paste_match_style": "Copier avec le style de destination",
"quit": "Quitter",
"redo": "Refaire",
"select_all": "Tout sélectionner",
"show_hide": "Afficher/Masquer",
"undo": "Annuler",
"zoom_in": "Zoomer",
"zoom_out": "Dé-zoomer"
},
"common": {
"about": "À propos",
"brand_help": "Aide de %(brand)s",
"help": "Aide",
"preferences": "Préférences"
},
"confirm_quit": "Êtes-vous sûr de vouloir quitter ?",
"edit_menu": {
"speech": "Dictée",
"speech_start_speaking": "Commencer la dictée",
"speech_stop_speaking": "Arrêter la dictée"
},
"file_menu": {
"label": "Fichier"
},
"menu": {
"hide": "Masquer",
"hide_others": "Masquer les autres",
"services": "Services",
"unhide": "Dé-masquer"
},
"right_click_menu": {
"add_to_dictionary": "Ajouter au dictionnaire",
"copy_email": "Copier ladresse e-mail",
"copy_image": "Copier limage",
"copy_image_url": "Copier l'adresse de l'image",
"copy_link_url": "Copier ladresse du lien",
"save_image_as": "Enregistrer limage sous…",
"save_image_as_error_description": "Limage na pas pu être sauvegardée",
"save_image_as_error_title": "Échec de la sauvegarde de limage"
},
"view_menu": {
"actual_size": "Taille réelle",
"toggle_developer_tools": "Basculer les outils de développement",
"toggle_full_screen": "Basculer le plein écran",
"view": "Afficher"
},
"window_menu": {
"bring_all_to_front": "Tout amener au premier plan",
"label": "Fenêtre",
"zoom": "Zoom"
}
"Undo": "Annuler",
"Edit": "Modifier",
"Quit": "Quitter",
"Show/Hide": "Afficher/Masquer",
"Are you sure you want to quit?": "Êtes-vous sûr de vouloir quitter ?",
"Cancel": "Annuler",
"Unhide": "Dé-masquer",
"Hide Others": "Masquer les autres",
"Hide": "Masquer",
"Services": "Services",
"About": "À propos",
"Element Help": "Aide dElement",
"Help": "Aide",
"Close": "Fermer",
"Minimize": "Minimiser",
"Window": "Fenêtre",
"Toggle Developer Tools": "Basculer les outils de développement",
"Toggle Full Screen": "Basculer le plein écran",
"Preferences": "Préférences",
"Zoom Out": "Dé-zoomer",
"Zoom In": "Zoomer",
"Actual Size": "Taille réelle",
"View": "Afficher",
"Select All": "Tout sélectionner",
"Delete": "Supprimer",
"Paste and Match Style": "Copier avec le style de destination",
"Paste": "Coller",
"Copy": "Copier",
"Cut": "Couper",
"Speech": "Dictée",
"Add to dictionary": "Ajouter au dictionnaire",
"The image failed to save": "Limage na pas pu être sauvegardée",
"Failed to save image": "Échec de la sauvegarde de limage",
"Save image as...": "Enregistrer limage sous…",
"Copy link address": "Copier ladresse du lien",
"Copy email address": "Copier ladresse e-mail",
"Copy image": "Copier limage",
"File": "Fichier",
"Bring All to Front": "Tout amener au premier plan",
"Zoom": "Zoom",
"Stop Speaking": "Arrêter la dictée",
"Start Speaking": "Commencer la dictée",
"Copy image address": "Copier l'adresse de l'image",
"Redo": "Refaire",
"Close %(brand)s": "Fermer %(brand)s"
}

45
src/i18n/strings/fy.json Normal file
View File

@@ -0,0 +1,45 @@
{
"Copy image": "Ofbylding kopiearje",
"Speech": "Spraak",
"View": "Byld",
"Paste and Match Style": "Plakke en lit stilen oerienkomme",
"Add to dictionary": "Oan wurdlist tafoegje",
"The image failed to save": "It is net slagge de ôfbylding te bewarjen",
"Failed to save image": "Ofbylding bewarjen mislearre",
"Save image as...": "Ofbylding bewarje as…",
"Copy link address": "Keppeling kopiearje",
"Copy email address": "E-mailadres kopiearje",
"File": "Bestân",
"Bring All to Front": "Alles nei foaren bringe",
"Zoom": "Zoom",
"Stop Speaking": "Stopje mei praten",
"Start Speaking": "Begjin mei praten",
"Unhide": "Wer toane",
"Hide Others": "Oare ferbergje",
"Hide": "Ferbergje",
"Services": "Tsjinsten",
"About": "Oer",
"Element Help": "Element help",
"Help": "Help",
"Close": "Slute",
"Minimize": "Minimalisearje",
"Window": "Finster",
"Toggle Developer Tools": "Untwikkelersark yn-/útskeakelje",
"Toggle Full Screen": "Folslein skerm yn-/útskeakelje",
"Preferences": "Foarkarren",
"Zoom Out": "Utzoome",
"Zoom In": "Ynzoome",
"Actual Size": "Werklike grutte",
"Select All": "Alles selektearje",
"Delete": "Fuortsmite",
"Paste": "Plakke",
"Copy": "Kopiearje",
"Cut": "Knippe",
"Redo": "Opnij útfiere",
"Undo": "Ungedien meitsje",
"Edit": "Bewurkje",
"Quit": "Ofslute",
"Show/Hide": "Toane/Ferbergje",
"Are you sure you want to quit?": "Binne jo der wis fan dat jo ôfslute wolle?",
"Cancel": "Annulearje"
}

View File

@@ -1,60 +1,45 @@
{
"action": {
"cancel": "Cancelar",
"close": "Pechar",
"copy": "Copiar",
"cut": "Cortar",
"delete": "Eliminar",
"edit": "Editar",
"minimise": "Minimizar",
"paste": "Pegar",
"paste_match_style": "Pegar e imitar estilo",
"quit": "Saír",
"redo": "Refacer",
"select_all": "Elexir todo",
"show_hide": "Mostrar/Agochar",
"undo": "Desfacer",
"zoom_in": "Aumentar",
"zoom_out": "Diminuir"
},
"common": {
"about": "Acerca de",
"help": "Axuda",
"preferences": "Preferencias"
},
"confirm_quit": "Tes a certeza de que queres saír?",
"edit_menu": {
"speech": "Falar",
"speech_start_speaking": "Comeza a falar",
"speech_stop_speaking": "Deixa de falar"
},
"file_menu": {
"label": "Ficheiro"
},
"menu": {
"hide": "Agochar",
"hide_others": "Agochar outras",
"services": "Servizos",
"unhide": "Desagochar"
},
"right_click_menu": {
"add_to_dictionary": "Engadir ao dicionario",
"copy_email": "Copiar enderezo de email",
"copy_image": "Copiar imaxe",
"copy_link_url": "Copiar enderezo da ligazón",
"save_image_as": "Gardar imaxe como...",
"save_image_as_error_description": "Non se gardou a imaxe",
"save_image_as_error_title": "Fallou o gardado da imaxe"
},
"view_menu": {
"actual_size": "Tamaño real",
"toggle_developer_tools": "Activar ferramentas de desenvolvemento",
"toggle_full_screen": "Activar pantalla completa",
"view": "Vista"
},
"window_menu": {
"bring_all_to_front": "Traer todo á fronte",
"label": "Ventá",
"zoom": "Aumento"
}
"Add to dictionary": "Engadir ao dicionario",
"The image failed to save": "Non se gardou a imaxe",
"Failed to save image": "Fallou o gardado da imaxe",
"Save image as...": "Gardar imaxe como...",
"Copy link address": "Copiar enderezo da ligazón",
"Copy email address": "Copiar enderezo de email",
"Copy image": "Copiar imaxe",
"File": "Ficheiro",
"Bring All to Front": "Traer todo á fronte",
"Zoom": "Aumento",
"Stop Speaking": "Deixa de falar",
"Start Speaking": "Comeza a falar",
"Speech": "Falar",
"Unhide": "Desagochar",
"Hide Others": "Agochar outras",
"Hide": "Agochar",
"Services": "Servizos",
"About": "Acerca de",
"Element Help": "Axuda de Element",
"Help": "Axuda",
"Close": "Pechar",
"Minimize": "Minimizar",
"Window": "Ventá",
"Toggle Developer Tools": "Activar ferramentas de desenvolvemento",
"Toggle Full Screen": "Activar pantalla completa",
"Preferences": "Preferencias",
"Zoom Out": "Diminuir",
"Zoom In": "Aumentar",
"Actual Size": "Tamaño real",
"View": "Ver",
"Select All": "Elexir todo",
"Delete": "Eliminar",
"Paste and Match Style": "Pegar e imitar estilo",
"Paste": "Pegar",
"Copy": "Copiar",
"Cut": "Cortar",
"Redo": "Refacer",
"Undo": "Desfacer",
"Edit": "Editar",
"Quit": "Saír",
"Show/Hide": "Mostrar/Agochar",
"Are you sure you want to quit?": "Tes a certeza de que queres saír?",
"Cancel": "Cancelar"
}

View File

@@ -1,61 +1,46 @@
{
"action": {
"cancel": "ביטול",
"close": "סגור",
"copy": "העתק",
"cut": "גזור",
"delete": "מחק",
"edit": "ערוך",
"minimise": "מזער",
"paste": "הדבק",
"paste_match_style": "הדבק והתאם סגנון",
"quit": "יציאה",
"redo": "בצע שוב",
"select_all": "בחר הכל",
"show_hide": "הצג\\הסתר",
"undo": "בטל ביצוע",
"zoom_in": "התקרב",
"zoom_out": "התרחק"
},
"common": {
"about": "אודות",
"help": "עזרה",
"preferences": "העדפות"
},
"confirm_quit": "האם אתה בטוח שברצונך לצאת?",
"edit_menu": {
"speech": "דיבור",
"speech_start_speaking": תחל לדבר",
"speech_stop_speaking": "הפסק לדבר"
},
"file_menu": {
"label": "קובץ"
},
"menu": {
"hide": סתר",
"hide_others": "הסתר אחרים",
"services": "שרותים",
"unhide": טל הסתרה"
},
"right_click_menu": {
"add_to_dictionary": "הוסף למילון",
"copy_email": "העתק כתובת אימייל",
"copy_image": "העתק תמונה",
"copy_image_url": "העתקת כתובת התמונה",
"copy_link_url": "העתק קישור",
"save_image_as": "שמור תמונה בשם...",
"save_image_as_error_description": "שמירת התמונה נכשלה",
"save_image_as_error_title": "נכשל בשמירת התמונה"
},
"view_menu": {
"actual_size": "גודל ממשי",
"toggle_developer_tools": "הפעל כלי מפתחים",
"toggle_full_screen": "הפעל מצב מסך מלא",
"view": "צפה"
},
"window_menu": {
"bring_all_to_front": "הבא הכל לחזית",
"label": "חלון",
"zoom": "גודל תצוגה"
}
"Actual Size": "גודל ממשי",
"Add to dictionary": "הוסף למילון",
"The image failed to save": "שמירת התמונה נכשלה",
"Failed to save image": "נכשל בשמירת התמונה",
"Save image as...": "שמור תמונה בשם...",
"Copy link address": "העתק קישור",
"Copy email address": "העתק כתובת אימייל",
"Copy image": "העתק תמונה",
"File": ובץ",
"Bring All to Front": "הבא הכל לחזית",
"Zoom": "גודל תצוגה",
"Stop Speaking": "הפסק לדבר",
"Start Speaking": "התחל לדבר",
"Speech": "דיבור",
"Unhide": "בטל הסתרה",
"Hide Others": "הסתר אחרים",
"Hide": סתר",
"Services": "שרותים",
"About": "אודות",
"Element Help": "עזרה של אלמנט",
"Help": "עזרה",
"Close": "סגור",
"Minimize": "מזער",
"Window": "חלון",
"Toggle Developer Tools": "הפעל כלי מפתחים",
"Toggle Full Screen": "הפעל מצב מסך מלא",
"Preferences": עדפות",
"Zoom Out": "התרחק",
"Zoom In": "התקרב",
"View": "צפה",
"Select All": "בחר הכל",
"Delete": "מחק",
"Paste": "הדבק",
"Copy": עתק",
"Cut": "גזור",
"Undo": "בטל ביצוע",
"Redo": צע שוב",
"Edit": "עריכה",
"Quit": "יציאה",
"Show/Hide": "הצג\\הסתר",
"Are you sure you want to quit?": "האם אתה בטוח שברצונך לצאת?",
"Cancel": "ביטול",
"Paste and Match Style": "הדבק והתאם סגנון",
"Copy image address": "העתקת כתובת התמונה"
}

12
src/i18n/strings/hr.json Normal file
View File

@@ -0,0 +1,12 @@
{
"Paste": "Zalijepiti",
"Copy": "Kopirati",
"Cut": "Izrezati",
"Redo": "Preurediti",
"Undo": "Poništi",
"Edit": "Uredi",
"Quit": "Prestati",
"Show/Hide": "Pokaži/sakrij",
"Are you sure you want to quit?": "Jesi li siguran da želiš odustati?",
"Cancel": "Otkazati"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Mégse",
"close": "Bezárás",
"close_brand": "%(brand)s bezárása",
"copy": "Másolás",
"cut": "Kivágás",
"delete": "Törlés",
"edit": "Szerkesztés",
"minimise": "Lecsukás",
"paste": "Beillesztés",
"paste_match_style": "Beillesztés formázással",
"quit": "Kilépés",
"redo": "Újra",
"select_all": "Összes kijelölése",
"show_hide": "Megjelenítés/elrejtés",
"undo": "Visszavonás",
"zoom_in": "Nagyítás",
"zoom_out": "Kicsinyítés"
},
"common": {
"about": "Névjegy",
"brand_help": "%(brand)s Súgó",
"help": "Súgó",
"preferences": "Beállítások"
},
"confirm_quit": "Biztos, hogy kilép?",
"edit_menu": {
"speech": "Beszéd",
"speech_start_speaking": "Kezdjen beszélni",
"speech_stop_speaking": "Fejezze be a beszédet"
},
"file_menu": {
"label": "Fájl"
},
"menu": {
"hide": "Elrejtés",
"hide_others": "Mások elrejtése",
"services": "Szolgáltatás",
"unhide": "Felfedés"
},
"right_click_menu": {
"add_to_dictionary": "Hozzáadás a szótárhoz",
"copy_email": "E-mail-cím másolása",
"copy_image": "Kép másolása",
"copy_image_url": "Kép címének másolása",
"copy_link_url": "Hivatkozás másolása",
"save_image_as": "Kép mentése másként…",
"save_image_as_error_description": "A kép mentése sikertelen",
"save_image_as_error_title": "Kép mentése sikertelen"
},
"view_menu": {
"actual_size": "Jelenlegi méret",
"toggle_developer_tools": "Fejlesztői eszközök",
"toggle_full_screen": "Teljes képernyő",
"view": "Megtekintés"
},
"window_menu": {
"bring_all_to_front": "Mindent előtérbe hoz",
"label": "Ablak",
"zoom": "Nagyítás"
}
"Add to dictionary": "Hozzáadás a szótárhoz",
"The image failed to save": "A kép mentése sikertelen",
"Failed to save image": "Kép mentése sikertelen",
"Save image as...": "Kép mentése másként...",
"Copy link address": "Hivatkozás másolása",
"Copy email address": "E-mail cím másolása",
"Copy image": "Kép másolása",
"File": "Fájl",
"Bring All to Front": "Mindent előtérbe hoz",
"Zoom": "Nagyítás",
"Stop Speaking": "Fejezze be a beszédet",
"Start Speaking": "Kezdjen beszélni",
"Speech": "Beszéd",
"Unhide": "Felfed",
"Hide Others": "Minden mást eltakar",
"Hide": "Eltakar",
"Services": "Szolgáltatás",
"About": "Névjegy",
"Element Help": "Element segítség",
"Help": "Segítség",
"Close": "Bezár",
"Minimize": "Lecsukás",
"Window": "Ablak",
"Toggle Developer Tools": "Fejlesztői eszközök",
"Toggle Full Screen": "Teljes képernyő",
"Preferences": "Beállítások",
"Zoom Out": "Kicsinyít",
"Zoom In": "Nagyít",
"Actual Size": "Jelenlegi méret",
"View": "Nézet",
"Select All": "Összes kijelölése",
"Delete": "Töröl",
"Paste and Match Style": "Beillesztés formázással",
"Paste": "Beillesztés",
"Copy": "Másol",
"Cut": "Kivág",
"Redo": "Újra",
"Undo": "Visszavon",
"Edit": "Szerkeszt",
"Quit": "Kilép",
"Show/Hide": "Megmutat/Elrejt",
"Are you sure you want to quit?": "Biztos, hogy kilép?",
"Cancel": "Mégsem",
"Copy image address": "Kép címének másolása",
"Close %(brand)s": "%(brand)s bezárása"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Batalkan",
"close": "Tutup",
"close_brand": "Tutuo %(brand)s",
"copy": "Salin",
"cut": "Potong",
"delete": "Hapus",
"edit": "Sunting",
"minimise": "Minimalkan",
"paste": "Tempel",
"paste_match_style": "Tempel dan Cocokkan Gaya",
"quit": "Keluar",
"redo": "Ulangi",
"select_all": "Pilih Semua",
"show_hide": "Tampilkan/Sembunyikan",
"undo": "Urungkan",
"zoom_in": "Perbesar",
"zoom_out": "Perkecil"
},
"common": {
"about": "Tentang",
"brand_help": "Bantuan %(brand)s",
"help": "Bantuan",
"preferences": "Preferensi"
},
"confirm_quit": "Apakah Anda yakin ingin keluar?",
"edit_menu": {
"speech": "Dikte",
"speech_start_speaking": "Mulai Berbicara",
"speech_stop_speaking": "Berhenti Berbicara"
},
"file_menu": {
"label": "Berkas"
},
"menu": {
"hide": "Sembunyikan",
"hide_others": "Sembunyikan yang Lain",
"services": "Layanan",
"unhide": "Tampilkan"
},
"right_click_menu": {
"add_to_dictionary": "Tambah ke kamus",
"copy_email": "Salin surel",
"copy_image": "Salin gambar",
"copy_image_url": "Salin alamat gambar",
"copy_link_url": "Salin alamat tautan",
"save_image_as": "Simpan gambar sebagai...",
"save_image_as_error_description": "Gambar gagal disimpan",
"save_image_as_error_title": "Gagal menyimpan gambar"
},
"view_menu": {
"actual_size": "Ukuran Sebenarnya",
"toggle_developer_tools": "Beralih Alat Pengembang",
"toggle_full_screen": "Beralih Layar Penuh",
"view": "Tampilan"
},
"window_menu": {
"bring_all_to_front": "Bawa Semua ke Depan",
"label": "Jendela",
"zoom": "Perbesar"
}
"Add to dictionary": "Tambah ke kamus",
"The image failed to save": "Gambar gagal disimpan",
"Failed to save image": "Gagal menyimpan gambar",
"Save image as...": "Simpan gambar sebagai...",
"Copy link address": "Salin alamat tautan",
"Copy email address": "Salin surel",
"Copy image": "Salin gambar",
"File": "File",
"Hide Others": "Sembunyikan yang Lain",
"Bring All to Front": "Bawa Semua ke Depan",
"Zoom": "Perbesar",
"Stop Speaking": "Berhenti Berbicara",
"Start Speaking": "Mulai Berbicara",
"Speech": "Dikte",
"Unhide": "Tampilkan",
"Hide": "Sembunyikan",
"Services": "Layanan",
"About": "Tentang",
"Element Help": "Bantuan Element",
"Help": "Bantuan",
"Close": "Tutup",
"Minimize": "Minimalkan",
"Window": "Jendela",
"Toggle Developer Tools": "Beralih Alat Pengembang",
"Toggle Full Screen": "Beralih Layar Penuh",
"Preferences": "Pengaturan",
"Zoom Out": "Perkecil",
"Zoom In": "Perbesar",
"Cut": "Potong",
"Redo": "Ulangi",
"Undo": "Urungkan",
"Actual Size": "Ukuran Sebenarnya",
"View": "Tampilan",
"Select All": "Pilih Semua",
"Delete": "Hapus",
"Paste and Match Style": "Tempel dan Cocokkan Gaya",
"Paste": "Tempel",
"Copy": "Salin",
"Edit": "Edit",
"Quit": "Keluar",
"Show/Hide": "Tampilkan/Sembunyikan",
"Are you sure you want to quit?": "Apakah Anda yakin ingin keluar?",
"Cancel": "Batal",
"Copy image address": "Salin alamat gambar",
"Close %(brand)s": "Tutuo %(brand)s"
}

View File

@@ -1,62 +1,47 @@
{
"action": {
"cancel": "Hætta við",
"close": "Loka",
"close_brand": "Loka %(brand)s",
"copy": "Afrita",
"cut": "Klippa",
"delete": "Eyða",
"edit": "Breyta",
"minimise": "Lágmarka",
"paste": "Líma",
"paste_match_style": "Líma og samsvara stíl",
"quit": "Hætta",
"redo": "Endurgera",
"select_all": "Velja allt",
"show_hide": "Sýna/Fela",
"undo": "Afturkalla",
"zoom_in": "Stækka",
"zoom_out": "Minnka"
},
"common": {
"about": "Um hugbúnaðinn",
"help": "Hjálp",
"preferences": "Stillingar"
},
"confirm_quit": "Ertu viss um að þú viljir hætta?",
"edit_menu": {
"speech": "Tal",
"speech_start_speaking": "Byrja tal",
"speech_stop_speaking": "Hætta tali"
},
"file_menu": {
"label": "Skrá"
},
"menu": {
"hide": "Fela",
"hide_others": "Fela aðra",
"services": "Þjónustur",
"unhide": "Birta"
},
"right_click_menu": {
"add_to_dictionary": "Bæta við orðasafn",
"copy_email": "Afrita tölvupóstfang",
"copy_image": "Afrita mynd",
"copy_image_url": "Afrita slóð myndar",
"copy_link_url": "Afrita vistfang tengils",
"save_image_as": "Vista mynd sem...",
"save_image_as_error_description": "Myndina var ekki hægt að vista",
"save_image_as_error_title": "Mistókst að vista mynd"
},
"view_menu": {
"actual_size": "Raunstærð",
"toggle_developer_tools": "Víxla forritunarverkfærum af/á",
"toggle_full_screen": "Víxla fullum skjá af/á",
"view": "Skoða"
},
"window_menu": {
"bring_all_to_front": "Setja allt fremst",
"label": "Gluggi",
"zoom": "Stærð"
}
"Add to dictionary": "Bæta við orðasafn",
"The image failed to save": "Myndina var ekki hægt að vista",
"Failed to save image": "Mistókst að vista mynd",
"Save image as...": "Vista mynd sem...",
"Copy link address": "Afrita vistfang tengils",
"Copy email address": "Afrita tölvupóstfang",
"Copy image": "Afrita mynd",
"File": "Skrá",
"Bring All to Front": "Setja allt fremst",
"Zoom": "Stærð",
"Stop Speaking": "Hætta tali",
"Start Speaking": "Byrja tal",
"Speech": "Tal",
"Unhide": "Birta",
"Hide Others": "Fela aðra",
"Hide": "Fela",
"Services": "Þjónustur",
"About": "Um hugbúnaðinn",
"Element Help": "Hjálp við Element",
"Help": "Hjálp",
"Close": "Loka",
"Minimize": "Lágmarka",
"Window": "Gluggi",
"Toggle Developer Tools": "Víxla forritunarverkfærum af/á",
"Toggle Full Screen": "Víxla fullum skjá af/á",
"Preferences": "Stillingar",
"Zoom Out": "Minnka",
"Zoom In": "Stækka",
"Actual Size": "Raunstærð",
"View": "Skoða",
"Select All": "Velja allt",
"Delete": "Eyða",
"Paste and Match Style": "Líma og samsvara stíl",
"Paste": "Líma",
"Copy": "Afrita",
"Cut": "Klippa",
"Redo": "Endurgera",
"Undo": "Afturkalla",
"Edit": "Breyta",
"Quit": "Hætta",
"Show/Hide": "Sýna/Fela",
"Are you sure you want to quit?": "Ertu viss um að þú viljir hætta?",
"Cancel": "Hætta við",
"Copy image address": "Afrita slóð myndar",
"Close %(brand)s": "Loka %(brand)s"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Annulla",
"close": "Chiudi",
"close_brand": "Chiudi %(brand)s",
"copy": "Copia",
"cut": "Taglia",
"delete": "Elimina",
"edit": "Modifica",
"minimise": "Riduci",
"paste": "Incolla",
"paste_match_style": "Incolla e adegua lo stile",
"quit": "Esci",
"redo": "Ripeti",
"select_all": "Seleziona tutto",
"show_hide": "Mostra/Nascondi",
"undo": "Annulla",
"zoom_in": "Ingrandisci",
"zoom_out": "Rimpicciolisci"
},
"common": {
"about": "Informazioni su",
"brand_help": "Aiuto per %(brand)s",
"help": "Aiuto",
"preferences": "Preferenze"
},
"confirm_quit": "Vuoi veramente uscire?",
"edit_menu": {
"speech": "Dettatura",
"speech_start_speaking": "Inizia a parlare",
"speech_stop_speaking": "Smetti di parlare"
},
"file_menu": {
"label": "File"
},
"menu": {
"hide": "Nascondi",
"hide_others": "Nascondi gli altri",
"services": "Servizi",
"unhide": "Mostra"
},
"right_click_menu": {
"add_to_dictionary": "Aggiungi al dizionario",
"copy_email": "Copia indirizzo email",
"copy_image": "Copia immagine",
"copy_image_url": "Copia indirizzo immagine",
"copy_link_url": "Copia indirizzo collegamento",
"save_image_as": "Salva immagine come...",
"save_image_as_error_description": "Non è stato possibile salvare l'immagine",
"save_image_as_error_title": "Salvataggio immagine fallito"
},
"view_menu": {
"actual_size": "Dimensione effettiva",
"toggle_developer_tools": "Attiva strumenti per sviluppatori",
"toggle_full_screen": "Passa a schermo intero",
"view": "Vedi"
},
"window_menu": {
"bring_all_to_front": "Porta tutto in primo piano",
"label": "Finestra",
"zoom": "Ingrandisci"
}
"Add to dictionary": "Aggiungi al dizionario",
"The image failed to save": "Non è stato possibile salvare l'immagine",
"Failed to save image": "Salvataggio immagine fallito",
"Save image as...": "Salva immagine come...",
"Copy link address": "Copia indirizzo collegamento",
"Copy email address": "Copia indirizzo email",
"Copy image": "Copia immagine",
"File": "File",
"Bring All to Front": "Porta tutto in primo piano",
"Zoom": "Zoom",
"Start Speaking": "Inizia a parlare",
"Unhide": "Mostra",
"Hide Others": "Nascondi gli altri",
"Hide": "Nascondi",
"Services": "Servizi",
"About": "Informazioni su",
"Element Help": "Aiuto di Element",
"Help": "Aiuto",
"Close": "Chiudi",
"Minimize": "Riduci",
"Window": "Finestra",
"Toggle Developer Tools": "Attiva strumenti per sviluppatori",
"Toggle Full Screen": "Passa a schermo intero",
"Preferences": "Preferenze",
"Zoom Out": "Rimpicciolisci",
"Zoom In": "Ingrandisci",
"Actual Size": "Dimensione effettiva",
"View": "Vedi",
"Select All": "Seleziona tutto",
"Delete": "Elimina",
"Paste and Match Style": "Incolla e adegua lo stile",
"Paste": "Incolla",
"Copy": "Copia",
"Cut": "Taglia",
"Redo": "Ripeti",
"Undo": "Annulla",
"Edit": "Modifica",
"Quit": "Esci",
"Show/Hide": "Mostra/Nascondi",
"Are you sure you want to quit?": "Vuoi veramente uscire?",
"Cancel": "Annulla",
"Stop Speaking": "Smetti di parlare",
"Speech": "Dettatura",
"Copy image address": "Copia indirizzo immagine",
"Close %(brand)s": "Chiudi %(brand)s"
}

View File

@@ -1,62 +1,47 @@
{
"action": {
"cancel": "キャンセル",
"close": "閉じる",
"close_brand": "%(brand)sを閉じる",
"copy": "コピー",
"cut": "切り取り",
"delete": "削除",
"edit": "編集",
"minimise": "最小化",
"paste": "貼り付け",
"paste_match_style": "スタイルを保持して貼り付け",
"quit": "終了",
"redo": "やり直す",
"select_all": "全て選択",
"show_hide": "表示/非表示",
"undo": "取り消す",
"zoom_in": "拡大",
"zoom_out": "縮小"
},
"common": {
"about": "概要",
"help": "ヘルプ",
"preferences": "環境設定"
},
"confirm_quit": "終了してよろしいですか?",
"edit_menu": {
"speech": "スピーチ",
"speech_start_speaking": "録音を開始",
"speech_stop_speaking": "録音を停止"
},
"file_menu": {
"label": "ファイル"
},
"menu": {
"hide": "表示",
"hide_others": "他を非表示",
"services": "サービス",
"unhide": "再表示"
},
"right_click_menu": {
"add_to_dictionary": "辞書に追加",
"copy_email": "メールアドレスをコピー",
"copy_image": "画像をコピー",
"copy_image_url": "画像のアドレスをコピー",
"copy_link_url": "リンクのアドレスをコピー",
"save_image_as": "画像を保存",
"save_image_as_error_description": "画像の保存に失敗しました",
"save_image_as_error_title": "画像の保存に失敗"
},
"view_menu": {
"actual_size": "等倍",
"toggle_developer_tools": "開発者ツールを切り替える",
"toggle_full_screen": "全画面表示を切り替える",
"view": "表示"
},
"window_menu": {
"bring_all_to_front": "全てを前面に表示",
"label": "ウィンドウ",
"zoom": "ズーム"
}
"Close %(brand)s": "%(brand)sを閉じる",
"Bring All to Front": "全てを前面に表示",
"The image failed to save": "画像の保存に失敗しました",
"Unhide": "再表示",
"Actual Size": "等倍",
"Paste and Match Style": "スタイルを保持して貼り付け",
"Add to dictionary": "辞書に追加",
"Failed to save image": "画像の保存に失敗",
"Save image as...": "画像を保存",
"Speech": "スピーチ",
"Stop Speaking": "録音を停止",
"Start Speaking": "録音を開始",
"Toggle Developer Tools": "開発者ツールを切り替える",
"Toggle Full Screen": "全画面表示を切り替える",
"Redo": "やり直す",
"Undo": "取り消す",
"Minimize": "最小化",
"Window": "ウィンドウ",
"Preferences": "環境設定",
"Zoom Out": "縮小",
"Zoom In": "拡大",
"Copy link address": "リンクのアドレスをコピー",
"Copy image address": "画像のアドレスをコピー",
"Copy email address": "メールアドレスをコピー",
"Copy image": "画像をコピー",
"File": "ファイル",
"Zoom": "ズーム",
"Hide Others": "他を非表示",
"Hide": "非表示",
"Services": "サービス",
"About": "概要",
"Element Help": "Element ヘルプ",
"Help": "ヘルプ",
"Close": "閉じる",
"View": "表示",
"Select All": "全て選択",
"Delete": "削除",
"Paste": "貼り付け",
"Copy": "コピー",
"Cut": "切り取り",
"Edit": "編集",
"Quit": "終了",
"Are you sure you want to quit?": "終了してよろしいですか?",
"Show/Hide": "表示/非表示",
"Cancel": "キャンセル"
}

12
src/i18n/strings/ko.json Normal file
View File

@@ -0,0 +1,12 @@
{
"File": "파일",
"Copy email address": "이메일 주소 복사",
"Paste": "붙여넣기",
"Hide": "숨기기",
"Preferences": "환경설정",
"Undo": "실행 취소",
"Edit": "수정",
"Quit": "종료",
"Delete": "삭제",
"Cancel": "취소"
}

View File

@@ -1,61 +1,46 @@
{
"action": {
"cancel": "ຍົກເລີກ",
"close": "ປິດ",
"copy": "ສຳເນົາ",
"cut": "ຕັດ",
"delete": "ລຶບ",
"edit": "ແກ້ໄຂ",
"minimise": "ຫຍໍ້ນ້ອຍ",
"paste": "ກັອບມາໃສ່",
"paste_match_style": "ກັອບມາໃສ່ ແລະໃຫ້ສະຕາຍຕົງກັນ",
"quit": "ຍົກເລີກ",
"redo": "ລຶ້ມຄືນ",
"select_all": "ເລືອກທັງໝົດ",
"show_hide": "ສະແດງ/ເຊື່ອງ",
"undo": "ຮື້ຄືນ",
"zoom_in": "ຊູມເຂົ້າ",
"zoom_out": "ຊູມອອກ"
},
"common": {
"about": "ກ່ຽວກັບ",
"help": "ຊ່ວຍເຫຼືອ",
"preferences": "ການຕັ້ງຄ່າ"
},
"confirm_quit": "ທ່ານຕ້ອງການປິດແທ້ບໍ່?",
"edit_menu": {
"speech": "ຄຳກ່າວ",
"speech_start_speaking": "ເລີ່ມສົນທະນາ",
"speech_stop_speaking": "ເຊົາສົນທະນາ"
},
"file_menu": {
"label": "ຟາຍ"
},
"menu": {
"hide": "ເຊື່ອງ",
"hide_others": "ເຊື່ອງອັນອື່ນ",
"services": "ບໍລິການ",
"unhide": "ໂຊຄືນ"
},
"right_click_menu": {
"add_to_dictionary": "ເພີ່ມເຂົ້າໄປວັດຈະນານຸກົມ",
"copy_email": "ສຳເນົາທີ່ຢູ່ເມວ",
"copy_image": "ສຳເນົາຮູບ",
"copy_image_url": "ສຳເນົາທີ່ຢູ່ຮູບພາບ",
"copy_link_url": "ສຳເນົາທີ່ຢູ່ລິ້ງ",
"save_image_as": "ບັນທຶກຮູບພາບເປັນ...",
"save_image_as_error_description": "ຮູບພາບບໍ່ສາມາດບັດທຶກໄດ້",
"save_image_as_error_title": "ການບັນທຶກຮູບພາບບໍ່ສຳເລັດ"
},
"view_menu": {
"actual_size": "ຂະໜາດຕົວຈິງ",
"toggle_developer_tools": "ສະຫຼັບໄປໜ້າເຄື່ອງມືພັດທະນາ",
"toggle_full_screen": "ສະຫຼັບເຕັມຈໍ",
"view": "ເບິ່ງ"
},
"window_menu": {
"bring_all_to_front": "ເອົາທັງໝົດມາທາງໜ້າ",
"label": "ປ່ອງຢ້ຽມ",
"zoom": "ຊູມ"
}
"Toggle Developer Tools": "ສະຫຼັບໄປໜ້າເຄື່ອງມືພັດທະນາ",
"Add to dictionary": "ເພີ່ມເຂົ້າໄປວັດຈະນານຸກົມ",
"The image failed to save": "ຮູບພາບບໍ່ສາມາດບັດທຶກໄດ້",
"Failed to save image": "ການບັນທຶກຮູບພາບບໍ່ສຳເລັດ",
"Save image as...": "ບັນທຶກຮູບພາບເປັນ...",
"Copy link address": "ສຳເນົາທີ່ຢູ່ລິ້ງ",
"Copy image address": "ສຳເນົາທີ່ຢູ່ຮູບພາບ",
"Copy email address": "ສຳເນົາທີ່ຢູ່ເມວ",
"Copy image": "ສຳເນົາຮູບ",
"File": "ຟາຍ",
"Bring All to Front": "ເອົາທັງໝົດມາທາງໜ້າ",
"Zoom": "ຊູມ",
"Stop Speaking": "ເຊົາສົນທະນາ",
"Start Speaking": "ເລີ່ມສົນທະນາ",
"Speech": "ຄຳກ່າວ",
"Unhide": "ໂຊຄືນ",
"Hide Others": "ເຊື່ອງອັນອື່ນ",
"Hide": "ເຊື່ອງ",
"Services": "ບໍລິການ",
"About": "ກ່ຽວກັບ",
"Element Help": "ລະບົບຊ່ວຍເຫຼືອ",
"Help": "ຊ່ວຍເຫຼືອ",
"Close": "ປິດ",
"Minimize": "ຫຍໍ້ນ້ອຍ",
"Window": "ປ່ອງຢ້ຽມ",
"Toggle Full Screen": "ສະຫຼັບເຕັມຈໍ",
"Preferences": "ການຕັ້ງຄ່າ",
"Zoom Out": "ຊູມອອກ",
"Zoom In": "ຊູມເຂົ້າ",
"Actual Size": "ຂະໜາດຕົວຈິງ",
"View": "ເບິ່ງ",
"Select All": "ເລືອກທັງໝົດ",
"Delete": "ລຶບ",
"Paste and Match Style": "ກັອບມາໃສ່ ແລະໃຫ້ສະຕາຍຕົງກັນ",
"Paste": "ກັອບມາໃສ່",
"Copy": "ສຳເນົາ",
"Cut": "ຕັດ",
"Redo": "ລຶ້ມຄືນ",
"Undo": "ຮື້ຄືນ",
"Edit": "ແກ້ໄຂ",
"Quit": "ຍົກເລີກ",
"Show/Hide": "ສະແດງ/ເຊື່ອງ",
"Are you sure you want to quit?": "ທ່ານຕ້ອງການປິດແທ້ບໍ່?",
"Cancel": "ຍົກເລີກ"
}

View File

@@ -1,62 +1,47 @@
{
"action": {
"cancel": "Atšaukti",
"close": "Uždaryti",
"close_brand": "Uždaryti %(brand)s",
"copy": "Kopijuoti",
"cut": "Iškirpti",
"delete": "Ištrinti",
"edit": "Koreguoti",
"minimise": "Sumažinti",
"paste": "Įklijuoti",
"paste_match_style": "Įklijuoti ir suderinti stilių",
"quit": "Išeiti",
"redo": "Sugrąžinti veiksmą",
"select_all": "Pasirinkti visus",
"show_hide": "Rodyti/Slėpti",
"undo": "Atšaukti veiksmą",
"zoom_in": "Priartinti",
"zoom_out": "Atitolinti"
},
"common": {
"about": "Apie",
"help": "Pagalba",
"preferences": "Nuostatos"
},
"confirm_quit": "Ar tikrai norite išeiti?",
"edit_menu": {
"speech": "Kalba",
"speech_start_speaking": "Pradėti kalbėti",
"speech_stop_speaking": "Nustoti kalbėti"
},
"file_menu": {
"label": "Failas"
},
"menu": {
"hide": "Slėpti",
"hide_others": "Slėpti kitus",
"services": "Paslaugos",
"unhide": "Nebeslėpti"
},
"right_click_menu": {
"add_to_dictionary": "Pridėti prie žodyno",
"copy_email": "Kopijuoti el. pašto adresą",
"copy_image": "Kopijuoti paveikslėlį",
"copy_image_url": "Kopijuoti paveikslėlio adresą",
"copy_link_url": "Kopijuoti nuorodos adresą",
"save_image_as": "Įrašyti paveikslėlį kaip...",
"save_image_as_error_description": "Paveikslėlio nepavyko išsaugoti",
"save_image_as_error_title": "Nepavyko įrašyti paveikslėlio"
},
"view_menu": {
"actual_size": "Tikrasis dydis",
"toggle_developer_tools": "Perjungti kūrėjo įrankius",
"toggle_full_screen": "Perjungti viso ekrano režimą",
"view": "Žiūrėti"
},
"window_menu": {
"bring_all_to_front": "Viską iškelti į priekį",
"label": "Langas",
"zoom": "Priartinti"
}
"Failed to save image": "Nepavyko įrašyti paveikslėlio",
"Save image as...": "Įrašyti paveikslėlį kaip...",
"Copy image address": "Kopijuoti paveikslėlio adresą",
"Copy image": "Kopijuoti paveikslėlį",
"The image failed to save": "Paveikslėlio nepavyko išsaugoti",
"Bring All to Front": "Viską iškelti į priekį",
"Speech": "Kalba",
"Actual Size": "Tikrasis dydis",
"Toggle Developer Tools": "Perjungti kūrėjo įrankius",
"Toggle Full Screen": "Perjungti viso ekrano režimą",
"Paste and Match Style": "Įklijuoti ir suderinti stilių",
"Redo": "Sugrąžinti veiksmą",
"Undo": "Atšaukti veiksmą",
"Select All": "Pasirinkti visus",
"Delete": "Ištrinti",
"Paste": "Įklijuoti",
"Copy": "Kopijuoti",
"Cut": "Iškirpti",
"Add to dictionary": "Pridėti prie žodyno",
"Copy link address": "Kopijuoti nuorodos adresą",
"Copy email address": "Kopijuoti el. pašto adresą",
"File": "Failas",
"Zoom": "Priartinti",
"Stop Speaking": "Nustoti kalbėti",
"Start Speaking": "Pradėti kalbėti",
"Unhide": "Nebeslėpti",
"Hide Others": "Slėpti kitus",
"Hide": "Slėpti",
"Services": "Paslaugos",
"About": "Apie",
"Element Help": "Element Pagalba",
"Help": "Pagalba",
"Close": "Uždaryti",
"Minimize": "Sumažinti",
"Window": "Langas",
"Preferences": "Nuostatos",
"Zoom Out": "Atitolinti",
"Zoom In": "Priartinti",
"View": "Peržiūrėti",
"Edit": "Redaguoti",
"Quit": "Išeiti",
"Show/Hide": "Rodyti/Slėpti",
"Are you sure you want to quit?": "Ar tikrai norite išeiti?",
"Cancel": "Atšaukti",
"Close %(brand)s": "Uždaryti %(brand)s"
}

47
src/i18n/strings/lv.json Normal file
View File

@@ -0,0 +1,47 @@
{
"Start Speaking": "Runājiet...",
"Add to dictionary": "Pievienot vārdnīcai",
"The image failed to save": "Attēlu neizdevās saglabāt",
"Failed to save image": "Neizdevās saglabāt attēlu",
"Save image as...": "Saglabāt attēlu kā...",
"Copy link address": "Kopēt saiti",
"Copy email address": "Kopēt e-pasta adresi",
"Copy image": "Kopēt attēlu",
"File": "Fails",
"Bring All to Front": "Iznest visu priekšplānā",
"Zoom": "Mērogošana",
"Stop Speaking": "Beidziet runāt",
"Speech": "Runa",
"Unhide": "Rādīt",
"Hide Others": "Slēpt citus",
"Hide": "Slēpt",
"Services": "Pakalpojumi",
"About": "Par programmu",
"Element Help": "Element palīdzība",
"Help": "Palīdzība",
"Close": "Aizvērt",
"Minimize": "Minimizēt",
"Window": "Logs",
"Toggle Developer Tools": "Pārslēgt uz Izstrādātāja rīkiem",
"Toggle Full Screen": "Pārslēgt uz pilnekrānu",
"Preferences": "Iestatījumi",
"Zoom Out": "Samazināt",
"Zoom In": "Palielināt",
"Actual Size": "Faktiskais izmērs",
"View": "Skats",
"Select All": "Atzīmēt visus",
"Delete": "Dzēst",
"Paste and Match Style": "Ievietot, saglabājot stilu",
"Paste": "Ievietot",
"Copy": "Kopēt",
"Cut": "Izgriezt",
"Redo": "Atatgriezt/atatsaukt/atatdarīt",
"Undo": "Atgriezt/atsaukt/atdarīt",
"Edit": "Rediģēt",
"Quit": "Iziet",
"Show/Hide": "Rādīt/nerādīt",
"Are you sure you want to quit?": "Tiešām vēlaties iziet?",
"Cancel": "Atcelt",
"Copy image address": "Kopēt attēla adresi",
"Close %(brand)s": "Aizvērt %(brand)s"
}

View File

@@ -0,0 +1,38 @@
{
"Toggle Developer Tools": "Veksle Utvikleralternativer",
"Add to dictionary": "Legg til i ordbok",
"The image failed to save": "Bildet kunne ikke lagres",
"Failed to save image": "Kunne ikke lagre bildet",
"Save image as...": "Lagre bildet som...",
"Copy email address": "Kopier e-postadressen",
"Copy image": "Kopier bildet",
"File": "Fil",
"Stop Speaking": "Slutt å snakke",
"Start Speaking": "Begynn å snakke",
"Speech": "Tale",
"Hide": "Skjul",
"About": "Om",
"Element Help": "Element Hjelp",
"Help": "Hjelp",
"Close": "Lukk",
"Minimize": "Minimere",
"Window": "Vindu",
"Zoom Out": "Zoom ut",
"Zoom In": "Zoom inn",
"Actual Size": "Faktisk størrelse",
"View": "Se",
"Select All": "Velg alle",
"Delete": "Slett",
"Paste": "Lim inn",
"Copy": "Kopier",
"Undo": "Angre",
"Edit": "Rediger",
"Quit": "Avslutt",
"Show/Hide": "Vis/Skjul",
"Are you sure you want to quit?": "Er du sikker på at du vil slutte?",
"Cancel": "Avbryt",
"Services": "Tjenester",
"Hide Others": "Skjul Andre",
"Bring All to Front": "Flytt Alt Frem",
"Toggle Full Screen": "Veksle Fullskjerm"
}

View File

@@ -1,60 +1,47 @@
{
"action": {
"cancel": "Annuleren",
"close": "Sluiten",
"close_brand": "Sluit %(brand)s",
"copy": "Kopiëren",
"cut": "Knippen",
"delete": "Verwijderen",
"edit": "Bewerken",
"minimise": "Minimaliseren",
"paste": "Plakken",
"paste_match_style": "Plakken zonder stijl",
"quit": "Sluiten",
"redo": "Opnieuw doen",
"select_all": "Alles selecteren",
"show_hide": "Tonen/Verbergen",
"undo": "Ongedaan maken",
"zoom_in": "Inzoomen",
"zoom_out": "Uitzoomen"
},
"common": {
"about": "Over",
"preferences": "Voorkeuren"
},
"confirm_quit": "Weet u zeker dat u wilt stoppen?",
"edit_menu": {
"speech": "Spraak",
"speech_start_speaking": "Begin met praten",
"speech_stop_speaking": "Stop met praten"
},
"file_menu": {
"label": "Bestand"
},
"menu": {
"hide": "Verbergen",
"hide_others": "Anderen verbergen",
"services": "Diensten",
"unhide": "Weer laten zien"
},
"right_click_menu": {
"add_to_dictionary": "Aan woordenboek toevoegen",
"copy_email": "E-mailadres kopiëren",
"copy_image": "Afbeelding kopiëren",
"copy_image_url": "Kopieer afbeeldingsadres",
"copy_link_url": "Link kopiëren",
"save_image_as": "Afbeelding opslaan als...",
"save_image_as_error_description": "De afbeelding opslaan is mislukt",
"save_image_as_error_title": "Afbeelding opslaan is mislukt"
},
"view_menu": {
"actual_size": "Werkelijke grootte",
"toggle_developer_tools": "Developer Tools wisselen",
"toggle_full_screen": "Volledig scherm wisselen",
"view": "Bekijken"
},
"window_menu": {
"bring_all_to_front": "Alles naar voren brengen",
"label": "Venster"
}
"Add to dictionary": "Aan woordenboek toevoegen",
"The image failed to save": "De afbeelding opslaan is mislukt",
"Failed to save image": "Afbeelding opslaan is mislukt",
"Save image as...": "Afbeelding opslaan als...",
"Copy link address": "Link kopiëren",
"Copy email address": "E-mailadres kopiëren",
"Copy image": "Afbeelding kopiëren",
"File": "Bestand",
"Bring All to Front": "Alles naar voren brengen",
"Zoom": "Zoom",
"Stop Speaking": "Stop met praten",
"Start Speaking": "Begin met praten",
"Speech": "Spraak",
"Unhide": "Weer laten zien",
"Hide Others": "Anderen verbergen",
"Hide": "Verbergen",
"Services": "Diensten",
"About": "Over",
"Element Help": "Element-hulp",
"Help": "Help",
"Close": "Sluiten",
"Minimize": "Minimaliseren",
"Window": "Venster",
"Toggle Developer Tools": "Developer Tools wisselen",
"Toggle Full Screen": "Volledig scherm wisselen",
"Preferences": "Voorkeuren",
"Zoom Out": "Uitzoomen",
"Zoom In": "Inzoomen",
"Actual Size": "Werkelijke grootte",
"View": "Bekijken",
"Select All": "Alles selecteren",
"Delete": "Verwijderen",
"Paste and Match Style": "Plakken zonder stijl",
"Paste": "Plakken",
"Copy": "Kopiëren",
"Cut": "Knippen",
"Redo": "Opnieuw doen",
"Undo": "Ongedaan maken",
"Edit": "Bewerken",
"Quit": "Sluiten",
"Show/Hide": "Tonen/Verbergen",
"Are you sure you want to quit?": "Weet u zeker dat u wilt stoppen?",
"Cancel": "Annuleren",
"Copy image address": "Kopieer afbeeldingsadres",
"Close %(brand)s": "Sluit %(brand)s"
}

45
src/i18n/strings/nn.json Normal file
View File

@@ -0,0 +1,45 @@
{
"The image failed to save": "Biletet vart ikkje lagra",
"Paste and Match Style": "Lim inn og tilpass stil",
"Redo": "Gjer om",
"Undo": "Angre",
"Are you sure you want to quit?": "Er du sikker på at du vil avslutta?",
"Add to dictionary": "Legg til i ordlista",
"Failed to save image": "Klarte ikkje å lagra biletet",
"Save image as...": "Lagre bilete som…",
"Copy link address": "Kopier lenkjeadresse",
"Copy email address": "Kopier e-postadresse",
"Copy image": "Kopier bilete",
"File": "Fil",
"Bring All to Front": "Plasser lengst fram",
"Zoom": "Zoom",
"Stop Speaking": "Stopp snakka",
"Start Speaking": "Byrja snakka",
"Speech": "Tale",
"Unhide": "Ikkje gøym",
"Hide Others": "Gøym andre",
"Hide": "Gøym",
"Services": "Tenester",
"About": "Om",
"Element Help": "Hjelp med Element",
"Help": "Hjelp",
"Close": "Lat att",
"Minimize": "Minimer",
"Window": "Vindauga",
"Toggle Developer Tools": "Developer Tools av/på",
"Toggle Full Screen": "Fullskjerm av/på",
"Preferences": "Innstillingar",
"Zoom Out": "Zoom ut",
"Zoom In": "Zoom inn",
"Actual Size": "Faktisk storleik",
"View": "Vis",
"Select All": "Marker alt",
"Delete": "Slett",
"Paste": "Lim inn",
"Copy": "Lim inn",
"Cut": "Klipp ut",
"Edit": "Rediger",
"Quit": "Avslutt",
"Show/Hide": "Vis/Gøym",
"Cancel": "Avbryt"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Anuluj",
"close": "Zamknij",
"close_brand": "Zamknij %(brand)s",
"copy": "Kopiuj",
"cut": "Wytnij",
"delete": "Usuń",
"edit": "Edytuj",
"minimise": "Minimalizuj",
"paste": "Wklej",
"paste_match_style": "Wklej i dopasuj styl",
"quit": "Zamknij",
"redo": "Ponów",
"select_all": "Zaznacz wszystko",
"show_hide": "Pokaż/Ukryj",
"undo": "Cofnij",
"zoom_in": "Powiększ",
"zoom_out": "Pomniejsz"
},
"common": {
"about": "Informacje",
"brand_help": "Pomoc %(brand)s",
"help": "Pomoc",
"preferences": "Preferencje"
},
"confirm_quit": "Czy na pewno chcesz zamknąć?",
"edit_menu": {
"speech": "Mowa",
"speech_start_speaking": "Zacznij mówić",
"speech_stop_speaking": "Przestań mówić"
},
"file_menu": {
"label": "Plik"
},
"menu": {
"hide": "Ukryj",
"hide_others": "Ukryj inne",
"services": "Usługi",
"unhide": "Odkryj"
},
"right_click_menu": {
"add_to_dictionary": "Dodaj do słownika",
"copy_email": "Kopiuj adres e-mail",
"copy_image": "Kopiuj obraz",
"copy_image_url": "Kopiuj adres obrazu",
"copy_link_url": "Kopiuj adres odnośnika",
"save_image_as": "Zapisz obraz jako...",
"save_image_as_error_description": "Obraz nie został zapisany",
"save_image_as_error_title": "Nie udało się zapisać obrazu"
},
"view_menu": {
"actual_size": "Rozmiar rzeczywisty",
"toggle_developer_tools": "Przełącz na narzędzia deweloperskie",
"toggle_full_screen": "Przełącz na pełny ekran",
"view": "Wyświetl"
},
"window_menu": {
"bring_all_to_front": "Wyciągnij wszystko do przodu",
"label": "Okno",
"zoom": "Powiększenie"
}
"Bring All to Front": "Wyciągnij wszystko do przodu",
"Add to dictionary": "Dodaj do słownika",
"The image failed to save": "Obraz nie został zapisany",
"Failed to save image": "Nie udało się zapisać obrazu",
"Save image as...": "Zapisz obraz jako...",
"Copy link address": "Kopiuj adres odnośnika",
"Copy email address": "Kopiuj adres e-mail",
"Copy image": "Kopiuj obraz",
"File": "Plik",
"Zoom": "Powiększenie",
"Stop Speaking": "Przestań mówić",
"Start Speaking": "Zacznij mówić",
"Speech": "Mowa",
"Unhide": "Odkryj",
"Hide Others": "Ukryj inne",
"Hide": "Ukryj",
"Services": "Usługi",
"About": "O nas",
"Element Help": "Pomoc Element",
"Help": "Pomoc",
"Close": "Zamknij",
"Minimize": "Minimalizuj",
"Window": "Okno",
"Toggle Developer Tools": "Przełącz na narzędzia deweloperskie",
"Toggle Full Screen": "Przełącz na pełny ekran",
"Preferences": "Preferencje",
"Zoom Out": "Pomniejsz",
"Zoom In": "Powiększ",
"Actual Size": "Rozmiar rzeczywisty",
"View": "Pokaż",
"Select All": "Zaznacz wszystko",
"Delete": "Usuń",
"Paste and Match Style": "Wklej i dopasuj styl",
"Paste": "Wklej",
"Copy": "Kopiuj",
"Cut": "Wytnij",
"Redo": "Ponów",
"Undo": "Cofnij",
"Edit": "Edytuj",
"Quit": "Zamknij",
"Show/Hide": "Pokaż/Ukryj",
"Are you sure you want to quit?": "Czy na pewno chcesz zamknąć?",
"Cancel": "Anuluj",
"Copy image address": "Kopiuj adres obrazu",
"Close %(brand)s": "Zamknij %(brand)s"
}

View File

@@ -1,61 +1,47 @@
{
"action": {
"cancel": "Cancelar",
"close": "Fechar",
"close_brand": "Fechar %(brand)s",
"copy": "Copiar",
"cut": "Cortar",
"delete": "Excluir",
"edit": "Editar",
"minimise": "Minimizar",
"paste": "Colar",
"paste_match_style": "Colar e Adequar Estilo",
"quit": "Sair",
"redo": "Refazer",
"select_all": "Selecionar Todas",
"show_hide": "Mostrar/Esconder",
"undo": "Desfazer",
"zoom_in": "Dar Zoom In",
"zoom_out": "Dar Zoom Out"
},
"common": {
"about": "Sobre",
"help": "Ajuda",
"preferences": "Preferências"
},
"confirm_quit": "Você tem certeza que você quer sair?",
"edit_menu": {
"speech": "Fala",
"speech_start_speaking": "Começar a Falar",
"speech_stop_speaking": "Parar de Falar"
},
"file_menu": {
"label": "Arquivo"
},
"menu": {
"hide": "Esconder",
"hide_others": "Esconder Outras(os)",
"services": "Serviços",
"unhide": "Desesconder"
},
"right_click_menu": {
"add_to_dictionary": "Adicionar a dicionário",
"copy_email": "Copiar endereço de email",
"copy_image": "Copiar imagem",
"copy_image_url": "Copiar endereço de imagem",
"copy_link_url": "Copiar endereço de link",
"save_image_as": "Salvar imagem como...",
"save_image_as_error_description": "A imagem falhou para salvar",
"save_image_as_error_title": "Falha para salvar imagem"
},
"view_menu": {
"actual_size": "Tamanho de Verdade",
"toggle_developer_tools": "Ativar/Desativar Ferramentas de Desenvolvimento",
"toggle_full_screen": "Pôr em/Tirar de Tela Cheia",
"view": "Ver"
},
"window_menu": {
"bring_all_to_front": "Trazer Todas Para Frente",
"label": "Janela"
}
"Add to dictionary": "Adicionar a dicionário",
"The image failed to save": "A imagem falhou para salvar",
"Failed to save image": "Falha para salvar imagem",
"Save image as...": "Salvar imagem como...",
"Copy link address": "Copiar endereço de link",
"Copy email address": "Copiar endereço de email",
"Copy image": "Copiar imagem",
"File": "Arquivo",
"Zoom": "Zoom",
"Stop Speaking": "Parar de Falar",
"Start Speaking": "Começar a Falar",
"Speech": "Fala",
"Unhide": "Desesconder",
"Hide": "Esconder",
"Services": "Serviços",
"About": "Sobre",
"Element Help": "Ajuda de Element",
"Help": "Ajuda",
"Close": "Fechar",
"Minimize": "Minimizar",
"Window": "Janela",
"Toggle Developer Tools": "Ativar/Desativar Ferramentas de Desenvolvimento",
"Toggle Full Screen": "Pôr em/Tirar de Tela Cheia",
"Preferences": "Preferências",
"Zoom Out": "Dar Zoom Out",
"Zoom In": "Dar Zoom In",
"Actual Size": "Tamanho de Verdade",
"View": "Visualizar",
"Select All": "Selecionar Todas",
"Delete": "Deletar",
"Paste and Match Style": "Colar e Adequar Estilo",
"Paste": "Colar",
"Copy": "Copiar",
"Cut": "Cortar",
"Redo": "Refazer",
"Undo": "Desfazer",
"Edit": "Editar",
"Quit": "Sair",
"Show/Hide": "Mostrar/Esconder",
"Are you sure you want to quit?": "Você tem certeza que você quer sair?",
"Cancel": "Cancelar",
"Bring All to Front": "Trazer Todas Para Frente",
"Hide Others": "Esconder Outras(os)",
"Copy image address": "Copiar endereço de imagem",
"Close %(brand)s": "Fechar %(brand)s"
}

44
src/i18n/strings/ro.json Normal file
View File

@@ -0,0 +1,44 @@
{
"Add to dictionary": "Adăugați la dicționar",
"Failed to save image": "Eroare în salvarea imaginii",
"Save image as...": "Salvează imagine ca ...",
"Copy link address": "Copiază link",
"Copy email address": "Copiază adresă de email",
"Copy image": "Copiază imagine",
"File": "Fișier",
"Bring All to Front": "Aduce-ți totul in față",
"Zoom": "Zoom",
"Stop Speaking": "Oprire Voce",
"Start Speaking": "Pornire Voce",
"Speech": "Voce",
"Hide Others": "Ascunde restul",
"Hide": "Ascunde",
"Services": "Servicii",
"About": "Despre",
"Element Help": "Ajutor Element",
"Help": "Ajutor",
"Close": "Inchide",
"Minimize": "Minimizare",
"Window": "Fereastră",
"Toggle Developer Tools": "Comutare unelte dezvoltator",
"Toggle Full Screen": "Comutare pe tot ecranul",
"Preferences": "Preferințe",
"Zoom Out": "Micșorează",
"Zoom In": "Mărește",
"Actual Size": "Mărime reală",
"View": "Vizualizează",
"Select All": "Selectează tot",
"Delete": "Șterge",
"Paste and Match Style": "Lipește si potrivește stilul",
"Paste": "Lipește",
"Copy": "Copiază",
"Redo": "Refă",
"Undo": "Anulare",
"Edit": "Editare",
"Quit": "Închid",
"Show/Hide": "Arată/Ascunde",
"Are you sure you want to quit?": "Sigur vrei să ieși din cont?",
"Cancel": "Anulare",
"Close %(brand)s": "Închide %(brand)s",
"Cut": "Taie"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Отмена",
"close": "Закрыть",
"close_brand": "Закрыть %(brand)s",
"copy": "Копировать",
"cut": "Вырезать",
"delete": "Удалить",
"edit": "Изменить",
"minimise": "Свернуть",
"paste": "Вставить",
"paste_match_style": "Вставить с тем же стилем",
"quit": "Выйти",
"redo": "Повторить",
"select_all": "Выбрать все",
"show_hide": "Показать/скрыть",
"undo": "Отменить",
"zoom_in": "Увеличить",
"zoom_out": "Уменьшить"
},
"common": {
"about": "О программе",
"brand_help": "Помощь %(brand)s",
"help": "Помощь",
"preferences": "Предпочтения"
},
"confirm_quit": "Вы уверены, что хотите выйти?",
"edit_menu": {
"speech": "Речь",
"speech_start_speaking": "Говорите",
"speech_stop_speaking": "Перестаньте говорить"
},
"file_menu": {
"label": "Файл"
},
"menu": {
"hide": "Скрыть",
"hide_others": "Скрыть прочие",
"services": "Службы",
"unhide": "Показать"
},
"right_click_menu": {
"add_to_dictionary": "Добавить в словарь",
"copy_email": "Копировать адрес почты",
"copy_image": "Копировать изображение",
"copy_image_url": "Копировать адрес изображения",
"copy_link_url": "Копировать ссылку",
"save_image_as": "Сохранить изображение как...",
"save_image_as_error_description": "Не удалось сохранить изображение",
"save_image_as_error_title": "Не удалось сохранить изображение"
},
"view_menu": {
"actual_size": "Фактический размер",
"toggle_developer_tools": "Переключить инструменты разработчика",
"toggle_full_screen": "Переключить полноэкранный режим",
"view": "Просмотр"
},
"window_menu": {
"bring_all_to_front": "Вынести всё вперёд",
"label": "Окно",
"zoom": "Масштаб"
}
"Edit": "Изменить",
"Quit": "Выйти",
"Cancel": "Отмена",
"Show/Hide": "Показать/скрыть",
"Are you sure you want to quit?": "Вы уверены, что хотите выйти?",
"Copy email address": "Копировать адрес почты",
"Copy image": "Копировать изображение",
"File": "Файл",
"Zoom": "Масштаб",
"Unhide": "Показать",
"Hide": "Скрыть",
"Services": "Сервисы",
"About": "О программе",
"Element Help": "Справка Element",
"Help": "Справка",
"Close": "Закрыть",
"Minimize": "Свернуть",
"Window": "Окно",
"Toggle Developer Tools": "Переключить инструменты разработчика",
"Toggle Full Screen": "Переключить полноэкранный режим",
"Preferences": "Параметры",
"Zoom Out": "Уменьшить",
"Zoom In": "Увеличить",
"Actual Size": "Фактический размер",
"View": "Просмотр",
"Select All": "Выбрать все",
"Delete": "Удалить",
"Paste": "Вставить",
"Copy": "Копировать",
"Cut": "Вырезать",
"Redo": "Повторить",
"Undo": "Отменить",
"Save image as...": "Сохранить изображение как...",
"Copy link address": "Копировать ссылку",
"Add to dictionary": "Добавить в словарь",
"The image failed to save": "Не удалось сохранить изображение",
"Failed to save image": "Не удалось сохранить изображение",
"Bring All to Front": "Вынести всё вперёд",
"Stop Speaking": "Перестаньте говорить",
"Start Speaking": "Говорите",
"Speech": "Голос",
"Hide Others": "Скрыть прочие",
"Paste and Match Style": "Вставить с тем же стилем",
"Copy image address": "Копировать адрес изображения",
"Close %(brand)s": "Закрыть %(brand)s"
}

46
src/i18n/strings/si.json Normal file
View File

@@ -0,0 +1,46 @@
{
"Show/Hide": "පෙන්වන්න/සඟවන්න",
"Are you sure you want to quit?": "ඔබට ඉවත් වීමට අවශ්‍ය බව විශ්වාස ද?",
"Cancel": "අවලංගු කරන්න",
"Add to dictionary": "ශබ්ද කෝෂයට එකතු කරන්න",
"Copy link address": "සබැඳියේ ලිපිනය පිටපත් කරන්න",
"Copy email address": "වි-තැපෑල පිටපත් කරන්න",
"File": "ගොනුව",
"Zoom": "විශාල කරන්න",
"Hide Others": "වෙනත් දෑ සඟවන්න",
"Hide": "සඟවන්න",
"Services": "සේවා",
"About": "පිළිබඳව",
"Element Help": "ඉලමෙන්ට් උපකාර",
"Help": "උපකාර",
"Close": "වසන්න",
"Minimize": "හකුලන්න",
"Window": "කවුළුව",
"Zoom Out": "කුඩාලනය කරන්න",
"Zoom In": "විශාලනය කරන්න",
"Actual Size": "සැබෑ ප්‍රමාණය",
"Select All": "සියල්ල තෝරන්න",
"Paste": "අලවන්න",
"Copy": "පිටපත්",
"Cut": "කපන්න",
"Redo": "පසුසේ",
"Undo": "පෙරසේ",
"Edit": "සංස්කරණය",
"Quit": "ඉවත් වන්න",
"Paste and Match Style": "අලවා ශෛලිය ගැළපුම",
"Delete": "මකන්න",
"The image failed to save": "රූපය සුරැකීමට අසමත්",
"Failed to save image": "රූපය සුරැකීමට අසමත්",
"Save image as...": "...ලෙස රූපය සුරකින්න",
"Copy image address": "රූපයේ ලිපිනයේ පිටපතක්",
"Copy image": "රූපයෙහි පිටපතක්",
"Bring All to Front": "සියල්ල ඉදිරිපසට",
"Stop Speaking": "කථාව නිමාව",
"Start Speaking": "කථාව ආරම්භය",
"Speech": "කථාව",
"Unhide": "නොසඟවන්න",
"Toggle Developer Tools": "සංවර්ධක මෙවලම්",
"Toggle Full Screen": "පූර්ණ තිරයට",
"Preferences": "පෙනුම",
"View": "දකින්න"
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Zrušiť",
"close": "Zavrieť",
"close_brand": "Zatvoriť %(brand)s",
"copy": "Kopírovať",
"cut": "Vystrihnúť",
"delete": "Odstrániť",
"edit": "Upraviť",
"minimise": "Minimalizovať",
"paste": "Vložiť",
"paste_match_style": "Vložiť a prispôsobiť štýl",
"quit": "Ukončiť",
"redo": "Opakovať",
"select_all": "Vybrať všetko",
"show_hide": "Zobraziť/Skryť",
"undo": "Späť",
"zoom_in": "Priblížiť",
"zoom_out": "Oddialiť"
},
"common": {
"about": "Informácie",
"brand_help": "%(brand)s Pomoc",
"help": "Pomocník",
"preferences": "Predvoľby"
},
"confirm_quit": "Naozaj chcete zavrieť aplikáciu?",
"edit_menu": {
"speech": "Reč",
"speech_start_speaking": "Spustiť nahrávanie hlasu",
"speech_stop_speaking": "Zastaviť nahrávanie hlasu"
},
"file_menu": {
"label": "Súbor"
},
"menu": {
"hide": "Skryť",
"hide_others": "Skryť ostatné",
"services": "Služby",
"unhide": "Odkryť"
},
"right_click_menu": {
"add_to_dictionary": "Pridať do slovníka",
"copy_email": "Kopírovať e-mailovú adresu",
"copy_image": "Kopírovať obrázok",
"copy_image_url": "Kopírovať adresu obrázka",
"copy_link_url": "Kopírovať adresu odkazu",
"save_image_as": "Uložiť obrázok ako...",
"save_image_as_error_description": "Obrázok sa nepodarilo uložiť",
"save_image_as_error_title": "Chyba pri ukladaní obrázka"
},
"view_menu": {
"actual_size": "Aktuálna veľkosť",
"toggle_developer_tools": "Nástroje pre vývojárov",
"toggle_full_screen": "Celá obrazovka",
"view": "Zobraziť"
},
"window_menu": {
"bring_all_to_front": "Preniesť všetky do popredia",
"label": "Okno",
"zoom": "Lupa"
}
"Unhide": "Odkryť",
"Stop Speaking": "Zastaviť nahrávanie hlasu",
"Start Speaking": "Spustiť nahrávanie hlasu",
"Speech": "Reč",
"Element Help": "Pomocník pre aplikáciu Element",
"Paste and Match Style": "Vložiť a prispôsobiť štýl",
"Add to dictionary": "Pridať do slovníka",
"The image failed to save": "Obrázok sa nepodarilo uložiť",
"Failed to save image": "Chyba pri ukladaní obrázka",
"Save image as...": "Uložiť obrázok ako...",
"Copy link address": "Kopírovať adresu odkazu",
"Copy email address": "Kopírovať e-mailovú adresu",
"Copy image": "Kopírovať obrázok",
"File": "Súbor",
"Bring All to Front": "Preniesť všetky do popredia",
"Zoom": "Lupa",
"Hide Others": "Skryť ostatné",
"Hide": "Skryť",
"Services": "Služby",
"About": "O aplikácii",
"Help": "Pomocník",
"Close": "Zavrieť",
"Minimize": "Minimalizovať",
"Window": "Okno",
"Toggle Developer Tools": "Nástroje pre vývojárov",
"Toggle Full Screen": "Celá obrazovka",
"Preferences": "Vlastnosti",
"Zoom Out": "Oddialiť",
"Zoom In": "Priblížiť",
"Actual Size": "Aktuálna veľkosť",
"View": "Zobraziť",
"Select All": "Vybrať všetko",
"Delete": "Odstrániť",
"Paste": "Vložiť",
"Copy": "Kopírovať",
"Cut": "Vystrihnúť",
"Redo": "Opakovať",
"Undo": "Späť",
"Edit": "Úpravy",
"Quit": "Ukončiť",
"Show/Hide": "Zobraziť/Skryť",
"Are you sure you want to quit?": "Naozaj chcete zavrieť aplikáciu?",
"Cancel": "Zrušiť",
"Copy image address": "Kopírovať adresu obrázka",
"Close %(brand)s": "Zatvoriť %(brand)s"
}

View File

@@ -1,17 +0,0 @@
{
"action": {
"cancel": "Anuloje",
"close": "Mbylle",
"copy": "Kopjoje",
"delete": "Fshije",
"edit": "Përpuno"
},
"common": {
"about": "Mbi",
"help": "Ndihmë",
"preferences": "Parapëlqime"
},
"view_menu": {
"view": "Shihni"
}
}

View File

@@ -1,63 +1,47 @@
{
"action": {
"cancel": "Avbryt",
"close": "Stäng",
"close_brand": "Stäng %(brand)s",
"copy": "Kopiera",
"cut": "Klipp ut",
"delete": "Radera",
"edit": "Ändra",
"minimise": "Minimera",
"paste": "Klistra in",
"paste_match_style": "Klistra in och matcha stilen",
"quit": "Avsluta",
"redo": "Gör om",
"select_all": "Markera allt",
"show_hide": "Visa/dölj",
"undo": "Ångra",
"zoom_in": "Zooma in",
"zoom_out": "Zooma ut"
},
"common": {
"about": "Om",
"brand_help": "%(brand)s-hjälp",
"help": "Hjälp",
"preferences": "Inställningar"
},
"confirm_quit": "Är du säker att du vill avsluta?",
"edit_menu": {
"speech": "Tal",
"speech_start_speaking": "Börja tala",
"speech_stop_speaking": "Sluta tala"
},
"file_menu": {
"label": "Arkiv"
},
"menu": {
"hide": "Göm",
"hide_others": "Göm övriga",
"services": "Tjänster",
"unhide": "Sluta gömma"
},
"right_click_menu": {
"add_to_dictionary": "Lägg till i ordlistan",
"copy_email": "Kopiera e-postadress",
"copy_image": "Kopiera bild",
"copy_image_url": "Kopiera bildadress",
"copy_link_url": "Kopiera länkadress",
"save_image_as": "Spara bild som…",
"save_image_as_error_description": "Bilden sparades inte",
"save_image_as_error_title": "Misslyckades med att spara bilden"
},
"view_menu": {
"actual_size": "Verklig storlek",
"toggle_developer_tools": "Växla utvecklarverktyg",
"toggle_full_screen": "Växla helskärm",
"view": "Visa"
},
"window_menu": {
"bring_all_to_front": "Lägg alla överst",
"label": "Fönster",
"zoom": "Zooma"
}
"Save image as...": "Spara bild som…",
"Copy link address": "Kopiera länkadress",
"Copy email address": "Kopiera e-postadress",
"Copy image": "Kopiera bild",
"File": "Arkiv",
"Bring All to Front": "Lägg alla överst",
"Stop Speaking": "Sluta tala",
"Start Speaking": "Börja tala",
"Speech": "Tal",
"Hide Others": "Göm övriga",
"Hide": "Göm",
"Services": "Tjänster",
"About": "Om",
"Element Help": "Element-Hjälp",
"Help": "Hjälp",
"Close": "Stäng",
"Minimize": "Minimera",
"Window": "Fönster",
"Preferences": "Inställningar",
"Actual Size": "Verklig storlek",
"View": "Visa",
"Select All": "Markera allt",
"Delete": "Radera",
"Paste and Match Style": "Klistra in och matcha stilen",
"Paste": "Klistra in",
"Copy": "Kopiera",
"Cut": "Klipp ut",
"Redo": "Gör om",
"Undo": "Ångra",
"Edit": "Redigera",
"Quit": "Avsluta",
"Cancel": "Avbryt",
"Zoom": "Zooma",
"Toggle Developer Tools": "Växla utvecklarverktyg",
"Toggle Full Screen": "Växla helskärm",
"Unhide": "Sluta gömma",
"Zoom Out": "Zooma ut",
"Zoom In": "Zooma in",
"Show/Hide": "Visa/dölj",
"Add to dictionary": "Lägg till i ordlistan",
"The image failed to save": "Bilden sparades inte",
"Failed to save image": "Misslyckades med att spara bilden",
"Are you sure you want to quit?": "Är du säker att du vill avsluta?",
"Copy image address": "Kopiera bildadress",
"Close %(brand)s": "Stäng %(brand)s"
}

47
src/i18n/strings/ta.json Normal file
View File

@@ -0,0 +1,47 @@
{
"Zoom": "பெரிதாக்குதல்",
"Minimize": "சிறிதாக்கு",
"Toggle Developer Tools": "உருவாக்குநர் கருவிகளை நிலைமாற்று",
"Toggle Full Screen": "முழு திரையை நிலைமாற்று",
"Paste and Match Style": "ஒட்டு மற்றும் நடையை பொருத்து",
"Add to dictionary": "அகராதியில் சேர்",
"The image failed to save": "படம் சேமிக்கத் தவறிவிட்டது",
"Failed to save image": "படத்தைச் சேமிப்பதில் தோல்வி",
"Save image as...": "படத்தை இவ்வாறு சேமி...",
"Copy link address": "இணைப்பு முகவரியை நகலெடு",
"Copy email address": "மின்னஞ்சல் முகவரியை நகலெடு",
"Copy image": "படத்தை நகலெடு",
"File": "கோப்பு",
"Bring All to Front": "அனைத்தையும் முன்னால் கொண்டுவா",
"Stop Speaking": "பேசுவதை நிறுத்து",
"Start Speaking": "பேசத் துவங்கு",
"Speech": "பேச்சு",
"Unhide": "மறைநீக்கு",
"Hide Others": "மற்றவற்றை மறை",
"Hide": "மறை",
"Services": "சேவைகள்",
"About": "இதனைப் பற்றி",
"Element Help": "எலிமெண்ட் உதவி",
"Help": "உதவி",
"Close": "மூடு",
"Window": "சாளரம்",
"Preferences": "விருப்பத்தேர்வுகள்",
"Zoom Out": "சிறிதாக்கு",
"Zoom In": "பெரிதாக்கு",
"Actual Size": "உண்மையான அளவு",
"View": "காட்டு",
"Select All": "அனைத்தையும் தேர்ந்தெடு",
"Delete": "அழி",
"Paste": "ஒட்டு",
"Copy": "நகலெடு",
"Cut": "வெட்டு",
"Redo": "மீண்டும் செய்",
"Undo": "செயல்தவிர்",
"Edit": "திருத்து",
"Quit": "வெளியேறு",
"Show/Hide": "காட்டு/மறை",
"Are you sure you want to quit?": "நீங்கள் நிச்சயம் வெளியேற விரும்புகிறீர்களா?",
"Cancel": "விலக்கிக்கொள்",
"Copy image address": "பட முகவரியை நகலெடு",
"Close %(brand)s": "%(brand)s ஐ மூடு"
}

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