Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 053dd490b4 | |||
| f4f81341da | |||
| 3e66913cf8 | |||
| 504309eff5 | |||
| b44abf5b4b | |||
| c76e8da173 | |||
| 9cc2189ef7 | |||
| 6b87efe7a3 | |||
| 7b75da1f10 | |||
| a7559f0691 | |||
| 6f2f295cf3 | |||
| b3d080f6e8 |
@@ -55,7 +55,7 @@
|
|||||||
"userEnvProbe": "loginInteractiveShell",
|
"userEnvProbe": "loginInteractiveShell",
|
||||||
"remoteEnv": {
|
"remoteEnv": {
|
||||||
// The location where your uploaded files are stored
|
// The location where your uploaded files are stored
|
||||||
"UPLOAD_LOCATION": "${localEnv:UPLOAD_LOCATION:./library}",
|
"UPLOAD_LOCATION": "${localEnv:UPLOAD_LOCATION:./Library}",
|
||||||
// Connection secret for postgres. You should change it to a random password
|
// Connection secret for postgres. You should change it to a random password
|
||||||
// Please use only the characters `A-Za-z0-9`, without special characters or spaces
|
// Please use only the characters `A-Za-z0-9`, without special characters or spaces
|
||||||
"DB_PASSWORD": "${localEnv:DB_PASSWORD:postgres}",
|
"DB_PASSWORD": "${localEnv:DB_PASSWORD:postgres}",
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ services:
|
|||||||
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
|
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
|
||||||
- server_node_modules:/workspaces/immich/server/node_modules
|
- server_node_modules:/workspaces/immich/server/node_modules
|
||||||
- web_node_modules:/workspaces/immich/web/node_modules
|
- web_node_modules:/workspaces/immich/web/node_modules
|
||||||
- ${UPLOAD_LOCATION}/photos:/data
|
- ${UPLOAD_LOCATION}/photos:/workspaces/immich/server/upload
|
||||||
- ${UPLOAD_LOCATION}/photos/upload:/data/upload
|
- ${UPLOAD_LOCATION}/photos/upload:/workspaces/immich/server/upload/upload
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
|
||||||
database:
|
database:
|
||||||
|
|||||||
@@ -7,34 +7,12 @@ export DEV_PORT="${DEV_PORT:-3000}"
|
|||||||
# Devcontainer: Clone [repository|pull request] in container volumne
|
# Devcontainer: Clone [repository|pull request] in container volumne
|
||||||
WORKSPACES_DIR="/workspaces"
|
WORKSPACES_DIR="/workspaces"
|
||||||
IMMICH_DIR="$WORKSPACES_DIR/immich"
|
IMMICH_DIR="$WORKSPACES_DIR/immich"
|
||||||
IMMICH_DEVCONTAINER_LOG="$HOME/immich-devcontainer.log"
|
|
||||||
|
|
||||||
log() {
|
|
||||||
# Display command on console, log with timestamp to file
|
|
||||||
echo "$*"
|
|
||||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >>"$IMMICH_DEVCONTAINER_LOG"
|
|
||||||
}
|
|
||||||
|
|
||||||
run_cmd() {
|
|
||||||
# Ensure log directory exists
|
|
||||||
mkdir -p "$(dirname "$IMMICH_DEVCONTAINER_LOG")"
|
|
||||||
|
|
||||||
log "$@"
|
|
||||||
|
|
||||||
# Execute command: display normally on console, log with timestamps to file
|
|
||||||
"$@" 2>&1 | tee >(while IFS= read -r line; do
|
|
||||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $line" >>"$IMMICH_DEVCONTAINER_LOG"
|
|
||||||
done)
|
|
||||||
|
|
||||||
# Preserve exit status
|
|
||||||
return "${PIPESTATUS[0]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Find directories excluding /workspaces/immich
|
# Find directories excluding /workspaces/immich
|
||||||
mapfile -t other_dirs < <(find "$WORKSPACES_DIR" -mindepth 1 -maxdepth 1 -type d ! -path "$IMMICH_DIR" ! -name ".*")
|
mapfile -t other_dirs < <(find "$WORKSPACES_DIR" -mindepth 1 -maxdepth 1 -type d ! -path "$IMMICH_DIR" ! -name ".*")
|
||||||
|
|
||||||
if [ ${#other_dirs[@]} -gt 1 ]; then
|
if [ ${#other_dirs[@]} -gt 1 ]; then
|
||||||
log "Error: More than one directory found in $WORKSPACES_DIR other than $IMMICH_DIR."
|
echo "Error: More than one directory found in $WORKSPACES_DIR other than $IMMICH_DIR."
|
||||||
exit 1
|
exit 1
|
||||||
elif [ ${#other_dirs[@]} -eq 1 ]; then
|
elif [ ${#other_dirs[@]} -eq 1 ]; then
|
||||||
export IMMICH_WORKSPACE="${other_dirs[0]}"
|
export IMMICH_WORKSPACE="${other_dirs[0]}"
|
||||||
@@ -42,39 +20,38 @@ else
|
|||||||
export IMMICH_WORKSPACE="$IMMICH_DIR"
|
export IMMICH_WORKSPACE="$IMMICH_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log "Found immich workspace in $IMMICH_WORKSPACE"
|
echo "Found immich workspace in $IMMICH_WORKSPACE"
|
||||||
log ""
|
|
||||||
|
run_cmd() {
|
||||||
|
echo "$@"
|
||||||
|
"$@"
|
||||||
|
}
|
||||||
|
|
||||||
fix_permissions() {
|
fix_permissions() {
|
||||||
|
|
||||||
log "Fixing permissions for ${IMMICH_WORKSPACE}"
|
echo "Fixing permissions for ${IMMICH_WORKSPACE}"
|
||||||
|
|
||||||
run_cmd sudo find "${IMMICH_WORKSPACE}/server/upload" -not -path "${IMMICH_WORKSPACE}/server/upload/postgres/*" -not -path "${IMMICH_WORKSPACE}/server/upload/postgres" -exec chown node {} +
|
run_cmd sudo find "${IMMICH_WORKSPACE}/server/upload" -not -path "${IMMICH_WORKSPACE}/server/upload/postgres/*" -not -path "${IMMICH_WORKSPACE}/server/upload/postgres" -exec chown node {} +
|
||||||
|
|
||||||
# Change ownership for directories that exist
|
run_cmd sudo chown node -R "${IMMICH_WORKSPACE}/.vscode" \
|
||||||
for dir in "${IMMICH_WORKSPACE}/.vscode" \
|
|
||||||
"${IMMICH_WORKSPACE}/cli/node_modules" \
|
"${IMMICH_WORKSPACE}/cli/node_modules" \
|
||||||
"${IMMICH_WORKSPACE}/e2e/node_modules" \
|
"${IMMICH_WORKSPACE}/e2e/node_modules" \
|
||||||
"${IMMICH_WORKSPACE}/open-api/typescript-sdk/node_modules" \
|
"${IMMICH_WORKSPACE}/open-api/typescript-sdk/node_modules" \
|
||||||
"${IMMICH_WORKSPACE}/server/node_modules" \
|
"${IMMICH_WORKSPACE}/server/node_modules" \
|
||||||
"${IMMICH_WORKSPACE}/server/dist" \
|
"${IMMICH_WORKSPACE}/server/dist" \
|
||||||
"${IMMICH_WORKSPACE}/web/node_modules" \
|
"${IMMICH_WORKSPACE}/web/node_modules" \
|
||||||
"${IMMICH_WORKSPACE}/web/dist"; do
|
"${IMMICH_WORKSPACE}/web/dist"
|
||||||
if [ -d "$dir" ]; then
|
|
||||||
run_cmd sudo chown node -R "$dir"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
log ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
install_dependencies() {
|
install_dependencies() {
|
||||||
|
|
||||||
log "Installing dependencies"
|
echo "Installing dependencies"
|
||||||
|
|
||||||
(
|
(
|
||||||
cd "${IMMICH_WORKSPACE}" || exit 1
|
cd "${IMMICH_WORKSPACE}" || exit 1
|
||||||
export CI=1 FROZEN=1 OFFLINE=1
|
run_cmd make install-server
|
||||||
run_cmd make setup-web-dev setup-server-dev
|
run_cmd make install-open-api
|
||||||
|
run_cmd make build-open-api
|
||||||
|
run_cmd make install-web
|
||||||
)
|
)
|
||||||
log ""
|
}
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ services:
|
|||||||
build:
|
build:
|
||||||
target: dev-container-server
|
target: dev-container-server
|
||||||
env_file: !reset []
|
env_file: !reset []
|
||||||
hostname: immich-dev
|
|
||||||
environment:
|
environment:
|
||||||
- IMMICH_SERVER_URL=http://127.0.0.1:2283/
|
- IMMICH_SERVER_URL=http://127.0.0.1:2283/
|
||||||
volumes: !override
|
volumes: !override
|
||||||
@@ -13,8 +12,8 @@ services:
|
|||||||
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
|
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
|
||||||
- server_node_modules:/workspaces/immich/server/node_modules
|
- server_node_modules:/workspaces/immich/server/node_modules
|
||||||
- web_node_modules:/workspaces/immich/web/node_modules
|
- web_node_modules:/workspaces/immich/web/node_modules
|
||||||
- ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/data
|
- ${UPLOAD_LOCATION-./Library}/photos:/workspaces/immich/server/upload
|
||||||
- ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/data/upload
|
- ${UPLOAD_LOCATION-./Library}/photos/upload:/workspaces/immich/server/upload/upload
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
|
||||||
immich-web:
|
immich-web:
|
||||||
@@ -22,7 +21,7 @@ services:
|
|||||||
|
|
||||||
immich-machine-learning:
|
immich-machine-learning:
|
||||||
env_file: !reset []
|
env_file: !reset []
|
||||||
|
|
||||||
database:
|
database:
|
||||||
env_file: !reset []
|
env_file: !reset []
|
||||||
environment: !override
|
environment: !override
|
||||||
@@ -30,9 +29,8 @@ services:
|
|||||||
POSTGRES_USER: ${DB_USERNAME-postgres}
|
POSTGRES_USER: ${DB_USERNAME-postgres}
|
||||||
POSTGRES_DB: ${DB_DATABASE_NAME-immich}
|
POSTGRES_DB: ${DB_DATABASE_NAME-immich}
|
||||||
POSTGRES_INITDB_ARGS: '--data-checksums'
|
POSTGRES_INITDB_ARGS: '--data-checksums'
|
||||||
POSTGRES_HOST_AUTH_METHOD: md5
|
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION:-postgres-devcontainer-volume}${UPLOAD_LOCATION:+/postgres}:/var/lib/postgresql/data
|
- ${UPLOAD_LOCATION-./Library}/postgres:/var/lib/postgresql/data
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
env_file: !reset []
|
env_file: !reset []
|
||||||
@@ -44,6 +42,3 @@ volumes:
|
|||||||
open_api_node_modules:
|
open_api_node_modules:
|
||||||
server_node_modules:
|
server_node_modules:
|
||||||
web_node_modules:
|
web_node_modules:
|
||||||
upload1-devcontainer-volume:
|
|
||||||
upload2-devcontainer-volume:
|
|
||||||
postgres-devcontainer-volume:
|
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source /immich-devcontainer/container-common.sh
|
source /immich-devcontainer/container-common.sh
|
||||||
|
|
||||||
log "Starting Nest API Server"
|
echo "Starting Nest API Server"
|
||||||
log ""
|
|
||||||
cd "${IMMICH_WORKSPACE}/server" || (
|
cd "${IMMICH_WORKSPACE}/server" || (
|
||||||
log "Immich workspace not found"
|
echo workspace not found
|
||||||
exit 1
|
exit 1
|
||||||
)
|
)
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
run_cmd node ./node_modules/.bin/nest start --debug "0.0.0.0:9230" --watch
|
node ./node_modules/.bin/nest start --debug "0.0.0.0:9230" --watch
|
||||||
log "Nest API Server crashed with exit code $?. Respawning in 3s ..."
|
echo " Nest API Server crashed with exit code $?. Respawning in 3s ..."
|
||||||
sleep 3
|
sleep 3
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -3,20 +3,20 @@
|
|||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source /immich-devcontainer/container-common.sh
|
source /immich-devcontainer/container-common.sh
|
||||||
|
|
||||||
log "Starting Immich Web Frontend"
|
echo "Starting Immich Web Frontend"
|
||||||
log ""
|
|
||||||
cd "${IMMICH_WORKSPACE}/web" || (
|
cd "${IMMICH_WORKSPACE}/web" || (
|
||||||
log "Immich Workspace not found"
|
echo Workspace not found
|
||||||
exit 1
|
exit 1
|
||||||
)
|
)
|
||||||
|
|
||||||
until curl --output /dev/null --silent --head --fail "http://127.0.0.1:${IMMICH_PORT}/api/server/config"; do
|
until curl --output /dev/null --silent --head --fail "http://127.0.0.1:${IMMICH_PORT}/api/server/config"; do
|
||||||
log "Waiting for api server..."
|
echo 'waiting for api server...'
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
run_cmd node ./node_modules/.bin/vite dev --host 0.0.0.0 --port "${DEV_PORT}"
|
node ./node_modules/.bin/vite dev --host 0.0.0.0 --port "${DEV_PORT}"
|
||||||
log "Web crashed with exit code $?. Respawning in 3s ..."
|
echo "Web crashed with exit code $?. Respawning in 3s ..."
|
||||||
sleep 3
|
sleep 3
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -3,18 +3,5 @@
|
|||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source /immich-devcontainer/container-common.sh
|
source /immich-devcontainer/container-common.sh
|
||||||
|
|
||||||
log "Setting up Immich dev container..."
|
|
||||||
fix_permissions
|
fix_permissions
|
||||||
|
|
||||||
log "Installing npm dependencies (node_modules)..."
|
|
||||||
install_dependencies
|
install_dependencies
|
||||||
|
|
||||||
log "Setup complete, please wait while backend and frontend services automatically start"
|
|
||||||
log
|
|
||||||
log "If necessary, the services may be manually started using"
|
|
||||||
log
|
|
||||||
log "$ /immich-devcontainer/container-start-backend.sh"
|
|
||||||
log "$ /immich-devcontainer/container-start-frontend.sh"
|
|
||||||
log
|
|
||||||
log "From different terminal windows, as these scripts automatically restart the server"
|
|
||||||
log "on error, and will continuously run in a loop"
|
|
||||||
|
|||||||
+13
-21
@@ -1,41 +1,33 @@
|
|||||||
.vscode/
|
.vscode/
|
||||||
.github/
|
.github/
|
||||||
.git/
|
.git/
|
||||||
.env*
|
|
||||||
*.log
|
|
||||||
*.tmp
|
|
||||||
*.temp
|
|
||||||
|
|
||||||
**/Dockerfile
|
|
||||||
**/node_modules/
|
|
||||||
**/.pnpm-store/
|
|
||||||
**/dist/
|
|
||||||
**/coverage/
|
|
||||||
**/build/
|
|
||||||
|
|
||||||
design/
|
design/
|
||||||
docker/
|
docker/
|
||||||
!docker/scripts
|
!docker/scripts
|
||||||
|
|
||||||
docs/
|
docs/
|
||||||
!docs/package.json
|
|
||||||
!docs/package-lock.json
|
|
||||||
|
|
||||||
e2e/
|
e2e/
|
||||||
!e2e/package.json
|
|
||||||
!e2e/package-lock.json
|
|
||||||
|
|
||||||
fastlane/
|
fastlane/
|
||||||
machine-learning/
|
machine-learning/
|
||||||
misc/
|
misc/
|
||||||
mobile/
|
mobile/
|
||||||
|
|
||||||
open-api/typescript-sdk/build/
|
cli/coverage/
|
||||||
!open-api/typescript-sdk/package.json
|
cli/dist/
|
||||||
!open-api/typescript-sdk/package-lock.json
|
cli/node_modules/
|
||||||
|
|
||||||
|
open-api/typescript-sdk/build/
|
||||||
|
open-api/typescript-sdk/node_modules/
|
||||||
|
|
||||||
|
server/coverage/
|
||||||
|
server/node_modules/
|
||||||
server/upload/
|
server/upload/
|
||||||
server/src/queries
|
server/src/queries
|
||||||
|
server/dist/
|
||||||
server/www/
|
server/www/
|
||||||
|
|
||||||
|
web/node_modules/
|
||||||
|
web/coverage/
|
||||||
web/.svelte-kit
|
web/.svelte-kit
|
||||||
|
web/build/
|
||||||
|
web/.env
|
||||||
|
|||||||
@@ -12,12 +12,6 @@ mobile/lib/**/*.drift.dart linguist-generated=true
|
|||||||
mobile/drift_schemas/main/drift_schema_*.json -diff -merge
|
mobile/drift_schemas/main/drift_schema_*.json -diff -merge
|
||||||
mobile/drift_schemas/main/drift_schema_*.json linguist-generated=true
|
mobile/drift_schemas/main/drift_schema_*.json linguist-generated=true
|
||||||
|
|
||||||
mobile/lib/infrastructure/repositories/db.repository.steps.dart -diff -merge
|
|
||||||
mobile/lib/infrastructure/repositories/db.repository.steps.dart linguist-generated=true
|
|
||||||
|
|
||||||
mobile/test/drift/main/generated/** -diff -merge
|
|
||||||
mobile/test/drift/main/generated/** linguist-generated=true
|
|
||||||
|
|
||||||
open-api/typescript-sdk/fetch-client.ts -diff -merge
|
open-api/typescript-sdk/fetch-client.ts -diff -merge
|
||||||
open-api/typescript-sdk/fetch-client.ts linguist-generated=true
|
open-api/typescript-sdk/fetch-client.ts linguist-generated=true
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
22.18.0
|
22.16.0
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
# Ignore files for PNPM, NPM and YARN
|
|
||||||
pnpm-lock.yaml
|
|
||||||
package-lock.json
|
|
||||||
yarn.lock
|
|
||||||
Generated
+3
-3
@@ -9,9 +9,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.6.2",
|
"version": "3.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
||||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
# Skip when PR from a fork
|
# Skip when PR from a fork
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' && needs.pre-job.outputs.should_run == 'true' }}
|
if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' && needs.pre-job.outputs.should_run == 'true' }}
|
||||||
runs-on: mich
|
runs-on: macos-14
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
@@ -66,40 +66,24 @@ jobs:
|
|||||||
ref: ${{ inputs.ref || github.sha }}
|
ref: ${{ inputs.ref || github.sha }}
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Create the Keystore
|
|
||||||
env:
|
|
||||||
KEY_JKS: ${{ secrets.KEY_JKS }}
|
|
||||||
working-directory: ./mobile
|
|
||||||
run: printf "%s" $KEY_JKS | base64 -d > android/key.jks
|
|
||||||
|
|
||||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
|
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
cache: 'gradle'
|
||||||
- name: Restore Gradle Cache
|
|
||||||
id: cache-gradle-restore
|
|
||||||
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.gradle/caches
|
|
||||||
~/.gradle/wrapper
|
|
||||||
~/.android/sdk
|
|
||||||
mobile/android/.gradle
|
|
||||||
mobile/.dart_tool
|
|
||||||
key: build-mobile-gradle-${{ runner.os }}-main
|
|
||||||
|
|
||||||
- name: Setup Flutter SDK
|
- name: Setup Flutter SDK
|
||||||
uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2.21.0
|
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version-file: ./mobile/pubspec.yaml
|
flutter-version-file: ./mobile/pubspec.yaml
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
- name: Setup Android SDK
|
- name: Create the Keystore
|
||||||
uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3.2.2
|
env:
|
||||||
with:
|
KEY_JKS: ${{ secrets.KEY_JKS }}
|
||||||
packages: ''
|
working-directory: ./mobile
|
||||||
|
run: echo $KEY_JKS | base64 -d > android/key.jks
|
||||||
|
|
||||||
- name: Get Packages
|
- name: Get Packages
|
||||||
working-directory: ./mobile
|
working-directory: ./mobile
|
||||||
@@ -119,30 +103,12 @@ jobs:
|
|||||||
ALIAS: ${{ secrets.ALIAS }}
|
ALIAS: ${{ secrets.ALIAS }}
|
||||||
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
||||||
ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
|
ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
|
||||||
IS_MAIN: ${{ github.ref == 'refs/heads/main' }}
|
|
||||||
run: |
|
run: |
|
||||||
if [[ $IS_MAIN == 'true' ]]; then
|
flutter build apk --release
|
||||||
flutter build apk --release
|
flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
|
||||||
flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
|
|
||||||
else
|
|
||||||
flutter build apk --debug --split-per-abi --target-platform android-arm64
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Publish Android Artifact
|
- name: Publish Android Artifact
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: release-apk-signed
|
name: release-apk-signed
|
||||||
path: mobile/build/app/outputs/flutter-apk/*.apk
|
path: mobile/build/app/outputs/flutter-apk/*.apk
|
||||||
|
|
||||||
- name: Save Gradle Cache
|
|
||||||
id: cache-gradle-save
|
|
||||||
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4
|
|
||||||
if: github.ref == 'refs/heads/main'
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.gradle/caches
|
|
||||||
~/.gradle/wrapper
|
|
||||||
~/.android/sdk
|
|
||||||
mobile/android/.gradle
|
|
||||||
mobile/.dart_tool
|
|
||||||
key: ${{ steps.cache-gradle-restore.outputs.cache-primary-key }}
|
|
||||||
|
|||||||
@@ -38,9 +38,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version-file: './cli/.nvmrc'
|
node-version-file: './cli/.nvmrc'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Prepare SDK
|
- name: Prepare SDK
|
||||||
run: npm ci --prefix ../open-api/typescript-sdk/
|
run: npm ci --prefix ../open-api/typescript-sdk/
|
||||||
- name: Build SDK
|
- name: Build SDK
|
||||||
@@ -70,7 +67,7 @@ jobs:
|
|||||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||||
@@ -99,7 +96,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
|
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
|
||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
|
||||||
with:
|
with:
|
||||||
file: cli/Dockerfile
|
file: cli/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened]
|
|
||||||
discussion:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
name: Close likely duplicates
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
get_body:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
EVENT: ${{ toJSON(github.event) }}
|
|
||||||
outputs:
|
|
||||||
body: ${{ steps.get_body.outputs.body }}
|
|
||||||
steps:
|
|
||||||
- id: get_body
|
|
||||||
run: |
|
|
||||||
BODY=$(echo """$EVENT""" | jq -r '.issue // .discussion | .body' | base64 -w 0)
|
|
||||||
echo "body=$BODY" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
get_checkbox_json:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: get_body
|
|
||||||
container:
|
|
||||||
image: yshavit/mdq:0.7.2
|
|
||||||
outputs:
|
|
||||||
json: ${{ steps.get_checkbox.outputs.json }}
|
|
||||||
steps:
|
|
||||||
- id: get_checkbox
|
|
||||||
env:
|
|
||||||
BODY: ${{ needs.get_body.outputs.body }}
|
|
||||||
run: |
|
|
||||||
JSON=$(echo "$BODY" | base64 -d | /mdq --output json '# I have searched | - [?] Yes')
|
|
||||||
echo "json=$JSON" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
close_and_comment:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: get_checkbox_json
|
|
||||||
if: ${{ !fromJSON(needs.get_checkbox_json.outputs.json).items[0].list[0].checked }}
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
discussions: write
|
|
||||||
steps:
|
|
||||||
- name: Close issue
|
|
||||||
if: ${{ github.event_name == 'issues' }}
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
NODE_ID: ${{ github.event.issue.node_id }}
|
|
||||||
run: |
|
|
||||||
gh api graphql \
|
|
||||||
-f issueId="$NODE_ID" \
|
|
||||||
-f body="This issue has automatically been closed as it is likely a duplicate. We get a lot of duplicate threads each day, which is why we ask you in the template to confirm that you searched for duplicates before opening one." \
|
|
||||||
-f query='
|
|
||||||
mutation CommentAndCloseIssue($issueId: ID!, $body: String!) {
|
|
||||||
addComment(input: {
|
|
||||||
subjectId: $issueId,
|
|
||||||
body: $body
|
|
||||||
}) {
|
|
||||||
__typename
|
|
||||||
}
|
|
||||||
|
|
||||||
closeIssue(input: {
|
|
||||||
issueId: $issueId,
|
|
||||||
stateReason: DUPLICATE
|
|
||||||
}) {
|
|
||||||
__typename
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
|
|
||||||
- name: Close discussion
|
|
||||||
if: ${{ github.event_name == 'discussion' && github.event.discussion.category.name == 'Feature Request' }}
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
NODE_ID: ${{ github.event.discussion.node_id }}
|
|
||||||
run: |
|
|
||||||
gh api graphql \
|
|
||||||
-f discussionId="$NODE_ID" \
|
|
||||||
-f body="This discussion has automatically been closed as it is likely a duplicate. We get a lot of duplicate threads each day, which is why we ask you in the template to confirm that you searched for duplicates before opening one." \
|
|
||||||
-f query='
|
|
||||||
mutation CommentAndCloseDiscussion($discussionId: ID!, $body: String!) {
|
|
||||||
addDiscussionComment(input: {
|
|
||||||
discussionId: $discussionId,
|
|
||||||
body: $body
|
|
||||||
}) {
|
|
||||||
__typename
|
|
||||||
}
|
|
||||||
|
|
||||||
closeDiscussion(input: {
|
|
||||||
discussionId: $discussionId,
|
|
||||||
reason: DUPLICATE
|
|
||||||
}) {
|
|
||||||
__typename
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||||
|
|
||||||
# âšī¸ Command-line programs to run using the OS shell.
|
# âšī¸ Command-line programs to run using the OS shell.
|
||||||
# đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
@@ -76,6 +76,6 @@ jobs:
|
|||||||
# ./location_of_script_within_repo/buildscript.sh
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||||
with:
|
with:
|
||||||
category: '/language:${{matrix.language}}'
|
category: '/language:${{matrix.language}}'
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ jobs:
|
|||||||
tag-suffix: '-rocm'
|
tag-suffix: '-rocm'
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
runner-mapping: '{"linux/amd64": "mich"}'
|
runner-mapping: '{"linux/amd64": "mich"}'
|
||||||
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@129aeda75a450666ce96e8bc8126652e717917a7 # multi-runner-build-workflow-0.1.1
|
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@094bfb927b8cd75b343abaac27b3241be0fccfe9 # multi-runner-build-workflow-0.1.0
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
actions: read
|
actions: read
|
||||||
@@ -154,7 +154,7 @@ jobs:
|
|||||||
name: Build and Push Server
|
name: Build and Push Server
|
||||||
needs: pre-job
|
needs: pre-job
|
||||||
if: ${{ needs.pre-job.outputs.should_run_server == 'true' }}
|
if: ${{ needs.pre-job.outputs.should_run_server == 'true' }}
|
||||||
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@129aeda75a450666ce96e8bc8126652e717917a7 # multi-runner-build-workflow-0.1.1
|
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@094bfb927b8cd75b343abaac27b3241be0fccfe9 # multi-runner-build-workflow-0.1.0
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
actions: read
|
actions: read
|
||||||
@@ -177,7 +177,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
|
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||||
with:
|
with:
|
||||||
needs: ${{ toJSON(needs) }}
|
needs: ${{ toJSON(needs) }}
|
||||||
|
|
||||||
@@ -188,6 +188,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
|
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||||
with:
|
with:
|
||||||
needs: ${{ toJSON(needs) }}
|
needs: ${{ toJSON(needs) }}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
outputs:
|
outputs:
|
||||||
should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.found_paths.outputs.open-api == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
@@ -32,8 +32,6 @@ jobs:
|
|||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
workflow:
|
workflow:
|
||||||
- '.github/workflows/docs-build.yml'
|
- '.github/workflows/docs-build.yml'
|
||||||
open-api:
|
|
||||||
- 'open-api/immich-openapi-specs.json'
|
|
||||||
- name: Check if we should force jobs to run
|
- name: Check if we should force jobs to run
|
||||||
id: should_force
|
id: should_force
|
||||||
run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'release' || github.ref_name == 'main' }}" >> "$GITHUB_OUTPUT"
|
run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'release' || github.ref_name == 'main' }}" >> "$GITHUB_OUTPUT"
|
||||||
@@ -59,8 +57,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './docs/.nvmrc'
|
node-version-file: './docs/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run npm install
|
- name: Run npm install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Fix formatting
|
- name: Fix formatting
|
||||||
run: make install-all && make format-all
|
run: make install-all && make format-all
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
name: Org Checks
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_review:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-approvals:
|
|
||||||
name: Check for Team/Admin Review
|
|
||||||
uses: immich-app/devtools/.github/workflows/required-approval.yml@main
|
|
||||||
permissions:
|
|
||||||
pull-requests: read
|
|
||||||
contents: read
|
|
||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Require PR to have a changelog label
|
- name: Require PR to have a changelog label
|
||||||
uses: mheap/github-action-required-labels@8afbe8ae6ab7647d0c9f0cfa7c2f939650d22509 # v5.5.1
|
uses: mheap/github-action-required-labels@fb29a14a076b0f74099f6198f77750e8fc236016 # v5.5.0
|
||||||
with:
|
with:
|
||||||
mode: exactly
|
mode: exactly
|
||||||
count: 1
|
count: 1
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ jobs:
|
|||||||
name: release-apk-signed
|
name: release-apk-signed
|
||||||
|
|
||||||
- name: Create draft release
|
- name: Create draft release
|
||||||
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
|
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
|
||||||
with:
|
with:
|
||||||
draft: true
|
draft: true
|
||||||
tag_name: ${{ env.IMMICH_VERSION }}
|
tag_name: ${{ env.IMMICH_VERSION }}
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version-file: './open-api/typescript-sdk/.nvmrc'
|
node-version-file: './open-api/typescript-sdk/.nvmrc'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: npm ci
|
run: npm ci
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|||||||
@@ -42,9 +42,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: ./mobile
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
@@ -52,29 +49,34 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Flutter SDK
|
- name: Setup Flutter SDK
|
||||||
uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2.21.0
|
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version-file: ./mobile/pubspec.yaml
|
flutter-version-file: ./mobile/pubspec.yaml
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: dart pub get
|
run: dart pub get
|
||||||
|
working-directory: ./mobile
|
||||||
|
|
||||||
- name: Install DCM
|
- name: Install DCM
|
||||||
uses: CQLabs/setup-dcm@8697ae0790c0852e964a6ef1d768d62a6675481a # v2.0.1
|
run: |
|
||||||
with:
|
sudo apt-get update
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
wget -qO- https://dcm.dev/pgp-key.public | sudo gpg --dearmor -o /usr/share/keyrings/dcm.gpg
|
||||||
version: auto
|
echo 'deb [signed-by=/usr/share/keyrings/dcm.gpg arch=amd64] https://dcm.dev/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list
|
||||||
working-directory: ./mobile
|
sudo apt-get update
|
||||||
|
sudo apt-get install dcm
|
||||||
|
|
||||||
- name: Generate translation file
|
- name: Generate translation file
|
||||||
run: make translation
|
run: make translation
|
||||||
|
working-directory: ./mobile
|
||||||
|
|
||||||
- name: Run Build Runner
|
- name: Run Build Runner
|
||||||
run: make build
|
run: make build
|
||||||
|
working-directory: ./mobile
|
||||||
|
|
||||||
- name: Generate platform API
|
- name: Generate platform API
|
||||||
run: make pigeon
|
run: make pigeon
|
||||||
|
working-directory: ./mobile
|
||||||
|
|
||||||
- name: Find file changes
|
- name: Find file changes
|
||||||
uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20.0.4
|
uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20.0.4
|
||||||
@@ -90,22 +92,25 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CHANGED_FILES: ${{ steps.verify-changed-files.outputs.changed_files }}
|
CHANGED_FILES: ${{ steps.verify-changed-files.outputs.changed_files }}
|
||||||
run: |
|
run: |
|
||||||
echo "ERROR: Generated files not up to date! Run 'make build' and 'make pigeon' inside the mobile directory"
|
echo "ERROR: Generated files not up to date! Run make_build inside the mobile directory"
|
||||||
echo "Changed files: ${CHANGED_FILES}"
|
echo "Changed files: ${CHANGED_FILES}"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
- name: Run dart analyze
|
- name: Run dart analyze
|
||||||
run: dart analyze --fatal-infos
|
run: dart analyze --fatal-infos
|
||||||
|
working-directory: ./mobile
|
||||||
|
|
||||||
- name: Run dart format
|
- name: Run dart format
|
||||||
run: make format
|
run: dart format lib/ --set-exit-if-changed
|
||||||
|
working-directory: ./mobile
|
||||||
|
|
||||||
- name: Run dart custom_lint
|
- name: Run dart custom_lint
|
||||||
run: dart run custom_lint
|
run: dart run custom_lint
|
||||||
|
working-directory: ./mobile
|
||||||
|
|
||||||
# TODO: Use https://github.com/CQLabs/dcm-action
|
|
||||||
- name: Run DCM
|
- name: Run DCM
|
||||||
run: dcm analyze lib --fatal-style --fatal-warnings
|
run: dcm analyze lib
|
||||||
|
working-directory: ./mobile
|
||||||
|
|
||||||
zizmor:
|
zizmor:
|
||||||
name: zizmor
|
name: zizmor
|
||||||
@@ -129,7 +134,7 @@ jobs:
|
|||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Upload SARIF file
|
- name: Upload SARIF file
|
||||||
uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
category: zizmor
|
category: zizmor
|
||||||
|
|||||||
@@ -84,8 +84,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run npm install
|
- name: Run npm install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -103,7 +101,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Run small tests & coverage
|
- name: Run small tests & coverage
|
||||||
run: npm test
|
run: npm run test:cov
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
cli-unit-tests:
|
cli-unit-tests:
|
||||||
@@ -127,8 +125,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './cli/.nvmrc'
|
node-version-file: './cli/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Setup typescript-sdk
|
- name: Setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -150,7 +146,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Run unit tests & coverage
|
- name: Run unit tests & coverage
|
||||||
run: npm run test
|
run: npm run test:cov
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
cli-unit-tests-win:
|
cli-unit-tests-win:
|
||||||
@@ -174,8 +170,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './cli/.nvmrc'
|
node-version-file: './cli/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Setup typescript-sdk
|
- name: Setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -190,7 +184,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Run unit tests & coverage
|
- name: Run unit tests & coverage
|
||||||
run: npm run test
|
run: npm run test:cov
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
web-lint:
|
web-lint:
|
||||||
@@ -214,8 +208,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './web/.nvmrc'
|
node-version-file: './web/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -257,8 +249,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './web/.nvmrc'
|
node-version-file: './web/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -272,7 +262,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Run unit tests & coverage
|
- name: Run unit tests & coverage
|
||||||
run: npm run test
|
run: npm run test:cov
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
i18n-tests:
|
i18n-tests:
|
||||||
@@ -292,8 +282,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './web/.nvmrc'
|
node-version-file: './web/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm --prefix=web ci
|
run: npm --prefix=web ci
|
||||||
@@ -338,8 +326,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './e2e/.nvmrc'
|
node-version-file: './e2e/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -383,8 +369,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run npm install
|
- name: Run npm install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -418,8 +402,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './e2e/.nvmrc'
|
node-version-file: './e2e/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -468,8 +450,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './e2e/.nvmrc'
|
node-version-file: './e2e/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -481,7 +461,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Install Playwright Browsers
|
- name: Install Playwright Browsers
|
||||||
run: npx playwright install chromium --only-shell
|
run: npx playwright install --with-deps chromium
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Docker build
|
- name: Docker build
|
||||||
@@ -499,7 +479,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
|
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||||
with:
|
with:
|
||||||
needs: ${{ toJSON(needs) }}
|
needs: ${{ toJSON(needs) }}
|
||||||
|
|
||||||
@@ -516,7 +496,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Flutter SDK
|
- name: Setup Flutter SDK
|
||||||
uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2.21.0
|
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version-file: ./mobile/pubspec.yaml
|
flutter-version-file: ./mobile/pubspec.yaml
|
||||||
@@ -588,8 +568,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './.github/.nvmrc'
|
node-version-file: './.github/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run npm install
|
- name: Run npm install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -609,7 +587,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Run ShellCheck
|
- name: Run ShellCheck
|
||||||
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0
|
uses: ludeeus/action-shellcheck@master
|
||||||
with:
|
with:
|
||||||
ignore_paths: >-
|
ignore_paths: >-
|
||||||
**/open-api/**
|
**/open-api/**
|
||||||
@@ -631,8 +609,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Install server dependencies
|
- name: Install server dependencies
|
||||||
run: npm --prefix=server ci
|
run: npm --prefix=server ci
|
||||||
@@ -668,7 +644,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:ec713143dca1a426eba2e03707c319e2ec3cc9d304ef767f777f8e297dee820c
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.1
|
||||||
env:
|
env:
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
@@ -694,8 +670,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Install server dependencies
|
- name: Install server dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -748,7 +722,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "ERROR: Generated SQL files not up to date!"
|
echo "ERROR: Generated SQL files not up to date!"
|
||||||
echo "Changed files: ${CHANGED_FILES}"
|
echo "Changed files: ${CHANGED_FILES}"
|
||||||
git diff
|
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
# mobile-integration-tests:
|
# mobile-integration-tests:
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
- name: Find Pull Request
|
- name: Find Pull Request
|
||||||
uses: juliangruber/find-pull-request-action@952b3bb1ddb2dcc0aa3479e98bb1c2d1a922f096 # v1.10.0
|
uses: juliangruber/find-pull-request-action@48b6133aa6c826f267ebd33aa2d29470f9d9e7d0 # v1.9.0
|
||||||
id: find-pr
|
id: find-pr
|
||||||
with:
|
with:
|
||||||
branch: chore/translations
|
branch: chore/translations
|
||||||
@@ -52,6 +52,6 @@ jobs:
|
|||||||
permissions: {}
|
permissions: {}
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
|
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||||
with:
|
with:
|
||||||
needs: ${{ toJSON(needs) }}
|
needs: ${{ toJSON(needs) }}
|
||||||
|
|||||||
@@ -24,4 +24,3 @@ mobile/android/fastlane/report.xml
|
|||||||
mobile/ios/fastlane/report.xml
|
mobile/ios/fastlane/report.xml
|
||||||
|
|
||||||
vite.config.js.timestamp-*
|
vite.config.js.timestamp-*
|
||||||
.pnpm-store
|
|
||||||
|
|||||||
Vendored
+2
-2
@@ -7,7 +7,7 @@
|
|||||||
"restart": true,
|
"restart": true,
|
||||||
"port": 9231,
|
"port": 9231,
|
||||||
"name": "Immich API Server",
|
"name": "Immich API Server",
|
||||||
"remoteRoot": "/usr/src/app/server",
|
"remoteRoot": "/usr/src/app",
|
||||||
"localRoot": "${workspaceFolder}/server"
|
"localRoot": "${workspaceFolder}/server"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"restart": true,
|
"restart": true,
|
||||||
"port": 9230,
|
"port": 9230,
|
||||||
"name": "Immich Workers",
|
"name": "Immich Workers",
|
||||||
"remoteRoot": "/usr/src/app/server",
|
"remoteRoot": "/usr/src/app",
|
||||||
"localRoot": "${workspaceFolder}/server"
|
"localRoot": "${workspaceFolder}/server"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,33 +1,27 @@
|
|||||||
dev:
|
dev:
|
||||||
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --remove-orphans
|
docker compose -f ./docker/docker-compose.dev.yml up --remove-orphans || make dev-down
|
||||||
|
|
||||||
dev-down:
|
dev-down:
|
||||||
docker compose -f ./docker/docker-compose.dev.yml down --remove-orphans
|
docker compose -f ./docker/docker-compose.dev.yml down --remove-orphans
|
||||||
|
|
||||||
dev-update:
|
dev-update:
|
||||||
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --build -V --remove-orphans
|
docker compose -f ./docker/docker-compose.dev.yml up --build -V --remove-orphans
|
||||||
|
|
||||||
dev-scale:
|
dev-scale:
|
||||||
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --build -V --scale immich-server=3 --remove-orphans
|
docker compose -f ./docker/docker-compose.dev.yml up --build -V --scale immich-server=3 --remove-orphans
|
||||||
|
|
||||||
.PHONY: e2e
|
.PHONY: e2e
|
||||||
e2e:
|
e2e:
|
||||||
@trap 'make e2e-down' EXIT; COMPOSE_BAKE=true docker compose -f ./e2e/docker-compose.yml up --build -V --remove-orphans
|
docker compose -f ./e2e/docker-compose.yml up --build -V --remove-orphans
|
||||||
|
|
||||||
e2e-update:
|
|
||||||
@trap 'make e2e-down' EXIT; COMPOSE_BAKE=true docker compose -f ./e2e/docker-compose.yml up --build -V --remove-orphans
|
|
||||||
|
|
||||||
e2e-down:
|
|
||||||
docker compose -f ./e2e/docker-compose.yml down --remove-orphans
|
|
||||||
|
|
||||||
prod:
|
prod:
|
||||||
@trap 'make prod-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.prod.yml up --build -V --remove-orphans
|
docker compose -f ./docker/docker-compose.prod.yml up --build -V --remove-orphans
|
||||||
|
|
||||||
prod-down:
|
prod-down:
|
||||||
docker compose -f ./docker/docker-compose.prod.yml down --remove-orphans
|
docker compose -f ./docker/docker-compose.prod.yml down --remove-orphans
|
||||||
|
|
||||||
prod-scale:
|
prod-scale:
|
||||||
@trap 'make prod-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.prod.yml up --build -V --scale immich-server=3 --scale immich-microservices=3 --remove-orphans
|
docker compose -f ./docker/docker-compose.prod.yml up --build -V --scale immich-server=3 --scale immich-microservices=3 --remove-orphans
|
||||||
|
|
||||||
.PHONY: open-api
|
.PHONY: open-api
|
||||||
open-api:
|
open-api:
|
||||||
@@ -54,8 +48,6 @@ audit-%:
|
|||||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
||||||
install-%:
|
install-%:
|
||||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) i
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) i
|
||||||
ci-%:
|
|
||||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) ci
|
|
||||||
build-cli: build-sdk
|
build-cli: build-sdk
|
||||||
build-web: build-sdk
|
build-web: build-sdk
|
||||||
build-%: install-%
|
build-%: install-%
|
||||||
@@ -90,7 +82,6 @@ test-medium-dev:
|
|||||||
|
|
||||||
build-all: $(foreach M,$(filter-out e2e .github,$(MODULES)),build-$M) ;
|
build-all: $(foreach M,$(filter-out e2e .github,$(MODULES)),build-$M) ;
|
||||||
install-all: $(foreach M,$(MODULES),install-$M) ;
|
install-all: $(foreach M,$(MODULES),install-$M) ;
|
||||||
ci-all: $(foreach M,$(filter-out .github,$(MODULES)),ci-$M) ;
|
|
||||||
check-all: $(foreach M,$(filter-out sdk cli docs .github,$(MODULES)),check-$M) ;
|
check-all: $(foreach M,$(filter-out sdk cli docs .github,$(MODULES)),check-$M) ;
|
||||||
lint-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),lint-$M) ;
|
lint-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),lint-$M) ;
|
||||||
format-all: $(foreach M,$(filter-out sdk,$(MODULES)),format-$M) ;
|
format-all: $(foreach M,$(filter-out sdk,$(MODULES)),format-$M) ;
|
||||||
@@ -99,12 +90,9 @@ hygiene-all: lint-all format-all check-all sql audit-all;
|
|||||||
test-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),test-$M) ;
|
test-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),test-$M) ;
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
find . -name "node_modules" -type d -prune -exec rm -rf {} +
|
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
|
||||||
find . -name "dist" -type d -prune -exec rm -rf '{}' +
|
find . -name "dist" -type d -prune -exec rm -rf '{}' +
|
||||||
find . -name "build" -type d -prune -exec rm -rf '{}' +
|
find . -name "build" -type d -prune -exec rm -rf '{}' +
|
||||||
find . -name "svelte-kit" -type d -prune -exec rm -rf '{}' +
|
find . -name "svelte-kit" -type d -prune -exec rm -rf '{}' +
|
||||||
command -v docker >/dev/null 2>&1 && docker compose -f ./docker/docker-compose.dev.yml rm -v -f || true
|
docker compose -f ./docker/docker-compose.dev.yml rm -v -f || true
|
||||||
command -v docker >/dev/null 2>&1 && docker compose -f ./e2e/docker-compose.yml rm -v -f || true
|
docker compose -f ./e2e/docker-compose.yml rm -v -f || true
|
||||||
|
|
||||||
setup-server-dev: install-server
|
|
||||||
setup-web-dev: install-sdk build-sdk install-web
|
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
22.18.0
|
22.16.0
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
import '../dist/index.js';
|
|
||||||
Generated
+301
-384
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.77",
|
"version": "2.2.68",
|
||||||
"description": "Command Line Interface (CLI) for Immich",
|
"description": "Command Line Interface (CLI) for Immich",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": "./dist/index.js",
|
"exports": "./dist/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"immich": "./bin/immich"
|
"immich": "dist/index.js"
|
||||||
},
|
},
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -21,22 +21,22 @@
|
|||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^22.17.0",
|
"@types/node": "^22.15.29",
|
||||||
"@vitest/coverage-v8": "^3.0.0",
|
"@vitest/coverage-v8": "^3.0.0",
|
||||||
"byte-size": "^9.0.0",
|
"byte-size": "^9.0.0",
|
||||||
"cli-progress": "^3.12.0",
|
"cli-progress": "^3.12.0",
|
||||||
"commander": "^12.0.0",
|
"commander": "^12.0.0",
|
||||||
"eslint": "^9.14.0",
|
"eslint": "^9.14.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.0.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-unicorn": "^60.0.0",
|
"eslint-plugin-unicorn": "^59.0.0",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"mock-fs": "^5.2.0",
|
"mock-fs": "^5.2.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-organize-imports": "^4.0.0",
|
"prettier-plugin-organize-imports": "^4.0.0",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"typescript-eslint": "^8.28.0",
|
"typescript-eslint": "^8.28.0",
|
||||||
"vite": "^7.0.0",
|
"vite": "^6.0.0",
|
||||||
"vite-tsconfig-paths": "^5.0.0",
|
"vite-tsconfig-paths": "^5.0.0",
|
||||||
"vitest": "^3.0.0",
|
"vitest": "^3.0.0",
|
||||||
"vitest-fetch-mock": "^0.4.0",
|
"vitest-fetch-mock": "^0.4.0",
|
||||||
@@ -69,6 +69,6 @@
|
|||||||
"micromatch": "^4.0.8"
|
"micromatch": "^4.0.8"
|
||||||
},
|
},
|
||||||
"volta": {
|
"volta": {
|
||||||
"node": "22.18.0"
|
"node": "22.16.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-30
@@ -2,37 +2,37 @@
|
|||||||
# Manual edits may be lost in future updates.
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||||
version = "4.52.1"
|
version = "4.52.0"
|
||||||
constraints = "4.52.1"
|
constraints = "4.52.0"
|
||||||
hashes = [
|
hashes = [
|
||||||
"h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=",
|
"h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=",
|
||||||
"h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=",
|
"h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=",
|
||||||
"h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=",
|
"h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=",
|
||||||
"h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=",
|
"h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=",
|
||||||
"h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=",
|
"h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=",
|
||||||
"h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=",
|
"h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=",
|
||||||
"h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=",
|
"h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=",
|
||||||
"h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=",
|
"h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=",
|
||||||
"h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=",
|
"h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=",
|
||||||
"h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=",
|
"h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=",
|
||||||
"h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=",
|
"h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=",
|
||||||
"h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=",
|
"h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=",
|
||||||
"h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=",
|
"h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=",
|
||||||
"h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=",
|
"h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=",
|
||||||
"zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2",
|
"zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0",
|
||||||
"zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e",
|
"zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8",
|
||||||
"zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f",
|
"zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238",
|
||||||
"zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703",
|
"zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f",
|
||||||
"zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae",
|
"zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f",
|
||||||
"zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e",
|
"zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8",
|
||||||
"zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e",
|
"zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9",
|
||||||
"zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496",
|
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060",
|
||||||
"zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937",
|
|
||||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||||
"zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1",
|
"zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6",
|
||||||
"zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a",
|
"zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb",
|
||||||
"zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849",
|
"zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b",
|
||||||
"zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955",
|
"zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380",
|
||||||
"zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e",
|
"zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7",
|
||||||
|
"zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
cloudflare = {
|
cloudflare = {
|
||||||
source = "cloudflare/cloudflare"
|
source = "cloudflare/cloudflare"
|
||||||
version = "4.52.1"
|
version = "4.52.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-30
@@ -2,37 +2,37 @@
|
|||||||
# Manual edits may be lost in future updates.
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||||
version = "4.52.1"
|
version = "4.52.0"
|
||||||
constraints = "4.52.1"
|
constraints = "4.52.0"
|
||||||
hashes = [
|
hashes = [
|
||||||
"h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=",
|
"h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=",
|
||||||
"h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=",
|
"h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=",
|
||||||
"h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=",
|
"h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=",
|
||||||
"h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=",
|
"h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=",
|
||||||
"h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=",
|
"h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=",
|
||||||
"h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=",
|
"h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=",
|
||||||
"h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=",
|
"h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=",
|
||||||
"h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=",
|
"h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=",
|
||||||
"h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=",
|
"h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=",
|
||||||
"h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=",
|
"h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=",
|
||||||
"h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=",
|
"h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=",
|
||||||
"h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=",
|
"h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=",
|
||||||
"h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=",
|
"h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=",
|
||||||
"h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=",
|
"h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=",
|
||||||
"zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2",
|
"zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0",
|
||||||
"zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e",
|
"zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8",
|
||||||
"zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f",
|
"zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238",
|
||||||
"zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703",
|
"zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f",
|
||||||
"zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae",
|
"zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f",
|
||||||
"zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e",
|
"zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8",
|
||||||
"zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e",
|
"zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9",
|
||||||
"zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496",
|
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060",
|
||||||
"zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937",
|
|
||||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||||
"zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1",
|
"zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6",
|
||||||
"zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a",
|
"zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb",
|
||||||
"zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849",
|
"zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b",
|
||||||
"zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955",
|
"zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380",
|
||||||
"zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e",
|
"zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7",
|
||||||
|
"zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
cloudflare = {
|
cloudflare = {
|
||||||
source = "cloudflare/cloudflare"
|
source = "cloudflare/cloudflare"
|
||||||
version = "4.52.1"
|
version = "4.52.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ name: immich-dev
|
|||||||
services:
|
services:
|
||||||
immich-server:
|
immich-server:
|
||||||
container_name: immich_server
|
container_name: immich_server
|
||||||
command: ['immich-dev']
|
command: [ '/usr/src/app/bin/immich-dev' ]
|
||||||
image: immich-server-dev:latest
|
image: immich-server-dev:latest
|
||||||
# extends:
|
# extends:
|
||||||
# file: hwaccel.transcoding.yml
|
# file: hwaccel.transcoding.yml
|
||||||
@@ -27,11 +27,11 @@ services:
|
|||||||
target: dev
|
target: dev
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ../server:/usr/src/app/server
|
- ../server:/usr/src/app
|
||||||
- ../open-api:/usr/src/app/open-api
|
- ../open-api:/usr/src/open-api
|
||||||
- ${UPLOAD_LOCATION}/photos:/data
|
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||||
- ${UPLOAD_LOCATION}/photos/upload:/data/upload
|
- ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload/upload
|
||||||
- /usr/src/app/server/node_modules
|
- /usr/src/app/node_modules
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
@@ -69,20 +69,19 @@ services:
|
|||||||
# Needed for rootless docker setup, see https://github.com/moby/moby/issues/45919
|
# Needed for rootless docker setup, see https://github.com/moby/moby/issues/45919
|
||||||
# user: 0:0
|
# user: 0:0
|
||||||
build:
|
build:
|
||||||
context: ../
|
context: ../web
|
||||||
dockerfile: web/Dockerfile
|
command: [ '/usr/src/app/bin/immich-web' ]
|
||||||
command: ['immich-web']
|
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
- 24678:24678
|
- 24678:24678
|
||||||
volumes:
|
volumes:
|
||||||
- ../web:/usr/src/app/web
|
- ../web:/usr/src/app
|
||||||
- ../i18n:/usr/src/app/i18n
|
- ../i18n:/usr/src/i18n
|
||||||
- ../open-api/:/usr/src/app/open-api/
|
- ../open-api/:/usr/src/open-api/
|
||||||
# - ../../ui:/usr/ui
|
# - ../../ui:/usr/ui
|
||||||
- /usr/src/app/web/node_modules
|
- /usr/src/app/node_modules
|
||||||
ulimits:
|
ulimits:
|
||||||
nofile:
|
nofile:
|
||||||
soft: 1048576
|
soft: 1048576
|
||||||
@@ -117,13 +116,13 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: immich_redis
|
container_name: immich_redis
|
||||||
image: docker.io/valkey/valkey:8-bookworm@sha256:facc1d2c3462975c34e10fccb167bfa92b0e0dbd992fc282c29a61c3243afb11
|
image: docker.io/valkey/valkey:8-bookworm@sha256:a19bebed6a91bd5e6e2106fef015f9602a3392deeb7c9ed47548378dcee3dfc2
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: redis-cli ping || exit 1
|
test: redis-cli ping || exit 1
|
||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.1-pgvectors0.2.0
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
@@ -135,7 +134,6 @@ services:
|
|||||||
- ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data
|
- ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data
|
||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
shm_size: 128mb
|
|
||||||
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
|
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
|
||||||
# immich-prometheus:
|
# immich-prometheus:
|
||||||
# container_name: immich_prometheus
|
# container_name: immich_prometheus
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ services:
|
|||||||
context: ../
|
context: ../
|
||||||
dockerfile: server/Dockerfile
|
dockerfile: server/Dockerfile
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION}/photos:/data
|
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
@@ -56,14 +56,14 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: immich_redis
|
container_name: immich_redis
|
||||||
image: docker.io/valkey/valkey:8-bookworm@sha256:facc1d2c3462975c34e10fccb167bfa92b0e0dbd992fc282c29a61c3243afb11
|
image: docker.io/valkey/valkey:8-bookworm@sha256:a19bebed6a91bd5e6e2106fef015f9602a3392deeb7c9ed47548378dcee3dfc2
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: redis-cli ping || exit 1
|
test: redis-cli ping || exit 1
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.1-pgvectors0.2.0
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
@@ -75,7 +75,6 @@ services:
|
|||||||
- ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data
|
- ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data
|
||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
shm_size: 128mb
|
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
|
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
|
||||||
@@ -83,7 +82,7 @@ services:
|
|||||||
container_name: immich_prometheus
|
container_name: immich_prometheus
|
||||||
ports:
|
ports:
|
||||||
- 9090:9090
|
- 9090:9090
|
||||||
image: prom/prometheus@sha256:63805ebb8d2b3920190daf1cb14a60871b16fd38bed42b857a3182bc621f4996
|
image: prom/prometheus@sha256:9abc6cf6aea7710d163dbb28d8eeb7dc5baef01e38fa4cd146a406dd9f07f70d
|
||||||
volumes:
|
volumes:
|
||||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||||
- prometheus-data:/prometheus
|
- prometheus-data:/prometheus
|
||||||
@@ -92,10 +91,10 @@ services:
|
|||||||
# add data source for http://immich-prometheus:9090 to get started
|
# add data source for http://immich-prometheus:9090 to get started
|
||||||
immich-grafana:
|
immich-grafana:
|
||||||
container_name: immich_grafana
|
container_name: immich_grafana
|
||||||
command: ['./run.sh', '-disable-reporting']
|
command: [ './run.sh', '-disable-reporting' ]
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
image: grafana/grafana:12.1.0-ubuntu@sha256:397aa30dd1af16cb6c5c9879498e467973a7f87eacf949f6d5a29407a3843809
|
image: grafana/grafana:12.0.1-ubuntu@sha256:65575bb9c761335e2ff30e364f21d38632e3b2e75f5f81d83cc92f44b9bbc055
|
||||||
volumes:
|
volumes:
|
||||||
- grafana-data:/var/lib/grafana
|
- grafana-data:/var/lib/grafana
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ services:
|
|||||||
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
|
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
|
||||||
volumes:
|
volumes:
|
||||||
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
|
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
|
||||||
- ${UPLOAD_LOCATION}:/data
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
@@ -49,14 +49,14 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: immich_redis
|
container_name: immich_redis
|
||||||
image: docker.io/valkey/valkey:8-bookworm@sha256:facc1d2c3462975c34e10fccb167bfa92b0e0dbd992fc282c29a61c3243afb11
|
image: docker.io/valkey/valkey:8-bookworm@sha256:a19bebed6a91bd5e6e2106fef015f9602a3392deeb7c9ed47548378dcee3dfc2
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: redis-cli ping || exit 1
|
test: redis-cli ping || exit 1
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.1-pgvectors0.2.0
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||||
POSTGRES_USER: ${DB_USERNAME}
|
POSTGRES_USER: ${DB_USERNAME}
|
||||||
@@ -67,7 +67,6 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
# Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
|
# Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
|
||||||
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
||||||
shm_size: 128mb
|
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
22.18.0
|
22.16.0
|
||||||
|
|||||||
+2
-2
@@ -180,7 +180,7 @@ services:
|
|||||||
...
|
...
|
||||||
volumes:
|
volumes:
|
||||||
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
|
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
|
||||||
- ${UPLOAD_LOCATION}:/data
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
+ - originals:/usr/src/app/originals
|
+ - originals:/usr/src/app/originals
|
||||||
...
|
...
|
||||||
@@ -490,7 +490,7 @@ You can also scan the Postgres database file structure for errors:
|
|||||||
<details>
|
<details>
|
||||||
<summary>Scan for file structure errors</summary>
|
<summary>Scan for file structure errors</summary>
|
||||||
```bash
|
```bash
|
||||||
docker exec -it immich_postgres pg_amcheck --username=<DB_USERNAME> --heapallindexed --parent-check --rootdescend --progress --all --install-missing
|
docker exec -it immich_postgres pg_amcheck --username=postgres --heapallindexed --parent-check --rootdescend --progress --all --install-missing
|
||||||
```
|
```
|
||||||
|
|
||||||
A normal result will end something like this and return with an exit code of `0`:
|
A normal result will end something like this and return with an exit code of `0`:
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ Then please follow the steps in the following section for restoring the database
|
|||||||
<TabItem value="Linux system" label="Linux system" default>
|
<TabItem value="Linux system" label="Linux system" default>
|
||||||
|
|
||||||
```bash title='Backup'
|
```bash title='Backup'
|
||||||
docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=<DB_USERNAME> | gzip > "/path/to/backup/dump.sql.gz"
|
docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres | gzip > "/path/to/backup/dump.sql.gz"
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash title='Restore'
|
```bash title='Restore'
|
||||||
@@ -79,7 +79,7 @@ docker compose up -d # Start remainder of Immich apps
|
|||||||
<TabItem value="Windows system (PowerShell)" label="Windows system (PowerShell)">
|
<TabItem value="Windows system (PowerShell)" label="Windows system (PowerShell)">
|
||||||
|
|
||||||
```powershell title='Backup'
|
```powershell title='Backup'
|
||||||
[System.IO.File]::WriteAllLines("C:\absolute\path\to\backup\dump.sql", (docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=<DB_USERNAME>))
|
[System.IO.File]::WriteAllLines("C:\absolute\path\to\backup\dump.sql", (docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres))
|
||||||
```
|
```
|
||||||
|
|
||||||
```powershell title='Restore'
|
```powershell title='Restore'
|
||||||
@@ -150,10 +150,12 @@ for more info read the [release notes](https://github.com/immich-app/immich/rele
|
|||||||
- Preview images (small thumbnails and large previews) for each asset and thumbnails for recognized faces.
|
- Preview images (small thumbnails and large previews) for each asset and thumbnails for recognized faces.
|
||||||
- Stored in `UPLOAD_LOCATION/thumbs/<userID>`.
|
- Stored in `UPLOAD_LOCATION/thumbs/<userID>`.
|
||||||
- **Encoded Assets:**
|
- **Encoded Assets:**
|
||||||
|
|
||||||
- Videos that have been re-encoded from the original for wider compatibility. The original is not removed.
|
- Videos that have been re-encoded from the original for wider compatibility. The original is not removed.
|
||||||
- Stored in `UPLOAD_LOCATION/encoded-video/<userID>`.
|
- Stored in `UPLOAD_LOCATION/encoded-video/<userID>`.
|
||||||
|
|
||||||
- **Postgres**
|
- **Postgres**
|
||||||
|
|
||||||
- The Immich database containing all the information to allow the system to function properly.
|
- The Immich database containing all the information to allow the system to function properly.
|
||||||
**Note:** This folder will only appear to users who have made the changes mentioned in [v1.102.0](https://github.com/immich-app/immich/discussions/8930) (an optional, non-mandatory change) or who started with this version.
|
**Note:** This folder will only appear to users who have made the changes mentioned in [v1.102.0](https://github.com/immich-app/immich/discussions/8930) (an optional, non-mandatory change) or who started with this version.
|
||||||
- Stored in `DB_DATA_LOCATION`.
|
- Stored in `DB_DATA_LOCATION`.
|
||||||
@@ -199,6 +201,7 @@ When you turn off the storage template engine, it will leave the assets in `UPLO
|
|||||||
- Temporarily located in `UPLOAD_LOCATION/upload/<userID>`.
|
- Temporarily located in `UPLOAD_LOCATION/upload/<userID>`.
|
||||||
- Transferred to `UPLOAD_LOCATION/library/<userID>` upon successful upload.
|
- Transferred to `UPLOAD_LOCATION/library/<userID>` upon successful upload.
|
||||||
- **Postgres**
|
- **Postgres**
|
||||||
|
|
||||||
- The Immich database containing all the information to allow the system to function properly.
|
- The Immich database containing all the information to allow the system to function properly.
|
||||||
**Note:** This folder will only appear to users who have made the changes mentioned in [v1.102.0](https://github.com/immich-app/immich/discussions/8930) (an optional, non-mandatory change) or who started with this version.
|
**Note:** This folder will only appear to users who have made the changes mentioned in [v1.102.0](https://github.com/immich-app/immich/discussions/8930) (an optional, non-mandatory change) or who started with this version.
|
||||||
- Stored in `DB_DATA_LOCATION`.
|
- Stored in `DB_DATA_LOCATION`.
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 33 KiB |
@@ -46,12 +46,6 @@ services:
|
|||||||
|
|
||||||
When a new asset is uploaded it kicks off a series of jobs, which include metadata extraction, thumbnail generation, machine learning tasks, and storage template migration, if enabled. To view the status of a job navigate to the Administration -> Jobs page.
|
When a new asset is uploaded it kicks off a series of jobs, which include metadata extraction, thumbnail generation, machine learning tasks, and storage template migration, if enabled. To view the status of a job navigate to the Administration -> Jobs page.
|
||||||
|
|
||||||
|
Additionally, some jobs run on a schedule, which is every night at midnight. This schedule, with the exception of [External Libraries](/docs/features/libraries) scanning, cannot be changed.
|
||||||
|
|
||||||
<img src={require('./img/admin-jobs.webp').default} width="60%" title="Admin jobs" />
|
<img src={require('./img/admin-jobs.webp').default} width="60%" title="Admin jobs" />
|
||||||
|
|
||||||
Additionally, some jobs (such as memories generation) run on a schedule, which is every night at midnight by default. To change when they run or enable/disable a job navigate to System Settings -> [Nightly Tasks Settings](https://my.immich.app/admin/system-settings?isOpen=nightly-tasks).
|
|
||||||
|
|
||||||
<img src={require('./img/admin-nightly-tasks.webp').default} width="60%" title="Admin nightly tasks" />
|
|
||||||
|
|
||||||
:::note
|
|
||||||
Some jobs ([External Libraries](/docs/features/libraries) scanning, Database Dump) are configured in their own sections in System Settings.
|
|
||||||
:::
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ Immich supports 3rd party authentication via [OpenID Connect][oidc] (OIDC), an i
|
|||||||
Before enabling OAuth in Immich, a new client application needs to be configured in the 3rd-party authentication server. While the specifics of this setup vary from provider to provider, the general approach should be the same.
|
Before enabling OAuth in Immich, a new client application needs to be configured in the 3rd-party authentication server. While the specifics of this setup vary from provider to provider, the general approach should be the same.
|
||||||
|
|
||||||
1. Create a new (Client) Application
|
1. Create a new (Client) Application
|
||||||
|
|
||||||
1. The **Provider** type should be `OpenID Connect` or `OAuth2`
|
1. The **Provider** type should be `OpenID Connect` or `OAuth2`
|
||||||
2. The **Client type** should be `Confidential`
|
2. The **Client type** should be `Confidential`
|
||||||
3. The **Application** type should be `Web`
|
3. The **Application** type should be `Web`
|
||||||
@@ -28,6 +29,7 @@ Before enabling OAuth in Immich, a new client application needs to be configured
|
|||||||
2. Configure Redirect URIs/Origins
|
2. Configure Redirect URIs/Origins
|
||||||
|
|
||||||
The **Sign-in redirect URIs** should include:
|
The **Sign-in redirect URIs** should include:
|
||||||
|
|
||||||
- `app.immich:///oauth-callback` - for logging in with OAuth from the [Mobile App](/docs/features/mobile-app.mdx)
|
- `app.immich:///oauth-callback` - for logging in with OAuth from the [Mobile App](/docs/features/mobile-app.mdx)
|
||||||
- `http://DOMAIN:PORT/auth/login` - for logging in with OAuth from the Web Client
|
- `http://DOMAIN:PORT/auth/login` - for logging in with OAuth from the Web Client
|
||||||
- `http://DOMAIN:PORT/user-settings` - for manually linking OAuth in the Web Client
|
- `http://DOMAIN:PORT/user-settings` - for manually linking OAuth in the Web Client
|
||||||
@@ -35,17 +37,21 @@ Before enabling OAuth in Immich, a new client application needs to be configured
|
|||||||
Redirect URIs should contain all the domains you will be using to access Immich. Some examples include:
|
Redirect URIs should contain all the domains you will be using to access Immich. Some examples include:
|
||||||
|
|
||||||
Mobile
|
Mobile
|
||||||
|
|
||||||
- `app.immich:///oauth-callback` (You **MUST** include this for iOS and Android mobile apps to work properly)
|
- `app.immich:///oauth-callback` (You **MUST** include this for iOS and Android mobile apps to work properly)
|
||||||
|
|
||||||
Localhost
|
Localhost
|
||||||
|
|
||||||
- `http://localhost:2283/auth/login`
|
- `http://localhost:2283/auth/login`
|
||||||
- `http://localhost:2283/user-settings`
|
- `http://localhost:2283/user-settings`
|
||||||
|
|
||||||
Local IP
|
Local IP
|
||||||
|
|
||||||
- `http://192.168.0.200:2283/auth/login`
|
- `http://192.168.0.200:2283/auth/login`
|
||||||
- `http://192.168.0.200:2283/user-settings`
|
- `http://192.168.0.200:2283/user-settings`
|
||||||
|
|
||||||
Hostname
|
Hostname
|
||||||
|
|
||||||
- `https://immich.example.com/auth/login`
|
- `https://immich.example.com/auth/login`
|
||||||
- `https://immich.example.com/user-settings`
|
- `https://immich.example.com/user-settings`
|
||||||
|
|
||||||
@@ -62,9 +68,8 @@ Once you have a new OAuth client application configured, Immich can be configure
|
|||||||
| Scope | string | openid email profile | Full list of scopes to send with the request (space delimited) |
|
| Scope | string | openid email profile | Full list of scopes to send with the request (space delimited) |
|
||||||
| Signing Algorithm | string | RS256 | The algorithm used to sign the id token (examples: RS256, HS256) |
|
| Signing Algorithm | string | RS256 | The algorithm used to sign the id token (examples: RS256, HS256) |
|
||||||
| Storage Label Claim | string | preferred_username | Claim mapping for the user's storage label**š** |
|
| Storage Label Claim | string | preferred_username | Claim mapping for the user's storage label**š** |
|
||||||
| Role Claim | string | immich_role | Claim mapping for the user's role. (should return "user" or "admin")**š** |
|
|
||||||
| Storage Quota Claim | string | immich_quota | Claim mapping for the user's storage**š** |
|
| Storage Quota Claim | string | immich_quota | Claim mapping for the user's storage**š** |
|
||||||
| Default Storage Quota (GiB) | number | 0 | Default quota for user without storage quota claim (empty for unlimited quota) |
|
| Default Storage Quota (GiB) | number | 0 | Default quota for user without storage quota claim (Enter 0 for unlimited quota) |
|
||||||
| Button Text | string | Login with OAuth | Text for the OAuth button on the web |
|
| Button Text | string | Login with OAuth | Text for the OAuth button on the web |
|
||||||
| Auto Register | boolean | true | When true, will automatically register a user the first time they sign in |
|
| Auto Register | boolean | true | When true, will automatically register a user the first time they sign in |
|
||||||
| [Auto Launch](#auto-launch) | boolean | false | When true, will skip the login page and automatically start the OAuth login process |
|
| [Auto Launch](#auto-launch) | boolean | false | When true, will skip the login page and automatically start the OAuth login process |
|
||||||
@@ -106,89 +111,6 @@ Immich has a route (`/api/oauth/mobile-redirect`) that is already configured to
|
|||||||
|
|
||||||
## Example Configuration
|
## Example Configuration
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Authelia Example</summary>
|
|
||||||
|
|
||||||
### Authelia Example
|
|
||||||
|
|
||||||
Here's an example of OAuth configured for Authelia:
|
|
||||||
|
|
||||||
This assumes there exist an attribute `immichquota` in the user schema, which is used to set the user's storage quota in Immich.
|
|
||||||
The configuration concerning the quota is optional.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
authentication_backend:
|
|
||||||
ldap:
|
|
||||||
# The LDAP server configuration goes here.
|
|
||||||
# See: https://www.authelia.com/c/ldap
|
|
||||||
attributes:
|
|
||||||
extra:
|
|
||||||
immichquota: # The attribute name from LDAP
|
|
||||||
name: 'immich_quota'
|
|
||||||
multi_valued: false
|
|
||||||
value_type: 'integer'
|
|
||||||
identity_providers:
|
|
||||||
oidc:
|
|
||||||
## The other portions of the mandatory OpenID Connect 1.0 configuration go here.
|
|
||||||
## See: https://www.authelia.com/c/oidc
|
|
||||||
claims_policies:
|
|
||||||
immich_policy:
|
|
||||||
custom_claims:
|
|
||||||
immich_quota:
|
|
||||||
attribute: 'immich_quota'
|
|
||||||
scopes:
|
|
||||||
immich_scope:
|
|
||||||
claims:
|
|
||||||
- 'immich_quota'
|
|
||||||
|
|
||||||
clients:
|
|
||||||
- client_id: 'immich'
|
|
||||||
client_name: 'Immich'
|
|
||||||
# https://www.authelia.com/integration/openid-connect/frequently-asked-questions/#how-do-i-generate-a-client-identifier-or-client-secret
|
|
||||||
client_secret: $pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng'
|
|
||||||
public: false
|
|
||||||
require_pkce: false
|
|
||||||
redirect_uris:
|
|
||||||
- 'https://example.immich.app/auth/login'
|
|
||||||
- 'https://example.immich.app/user-settings'
|
|
||||||
- 'app.immich:///oauth-callback'
|
|
||||||
scopes:
|
|
||||||
- 'openid'
|
|
||||||
- 'profile'
|
|
||||||
- 'email'
|
|
||||||
- 'immich_scope'
|
|
||||||
claims_policy: 'immich_policy'
|
|
||||||
response_types:
|
|
||||||
- 'code'
|
|
||||||
grant_types:
|
|
||||||
- 'authorization_code'
|
|
||||||
id_token_signed_response_alg: 'RS256'
|
|
||||||
userinfo_signed_response_alg: 'RS256'
|
|
||||||
token_endpoint_auth_method: 'client_secret_post'
|
|
||||||
```
|
|
||||||
|
|
||||||
Configuration of OAuth in Immich System Settings
|
|
||||||
|
|
||||||
| Setting | Value |
|
|
||||||
| ---------------------------------- | ------------------------------------------------------------------- |
|
|
||||||
| Issuer URL | `https://example.immich.app/.well-known/openid-configuration` |
|
|
||||||
| Client ID | immich |
|
|
||||||
| Client Secret | 0v89FXkQOWO\***\*\*\*\*\***\*\*\***\*\*\*\*\***mprbvXD549HH6s1iw... |
|
|
||||||
| Token Endpoint Auth Method | client_secret_post |
|
|
||||||
| Scope | openid email profile immich_scope |
|
|
||||||
| ID Token Signed Response Algorithm | RS256 |
|
|
||||||
| Userinfo Signed Response Algorithm | RS256 |
|
|
||||||
| Storage Label Claim | uid |
|
|
||||||
| Storage Quota Claim | immich_quota |
|
|
||||||
| Default Storage Quota (GiB) | 0 (empty for unlimited quota) |
|
|
||||||
| Button Text | Sign in with Authelia (optional) |
|
|
||||||
| Auto Register | Enabled (optional) |
|
|
||||||
| Auto Launch | Enabled (optional) |
|
|
||||||
| Mobile Redirect URI Override | Disable |
|
|
||||||
| Mobile Redirect URI | |
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Authentik Example</summary>
|
<summary>Authentik Example</summary>
|
||||||
|
|
||||||
@@ -211,7 +133,7 @@ Configuration of OAuth in Immich System Settings
|
|||||||
| Signing Algorithm | RS256 |
|
| Signing Algorithm | RS256 |
|
||||||
| Storage Label Claim | preferred_username |
|
| Storage Label Claim | preferred_username |
|
||||||
| Storage Quota Claim | immich_quota |
|
| Storage Quota Claim | immich_quota |
|
||||||
| Default Storage Quota (GiB) | 0 (empty for unlimited quota) |
|
| Default Storage Quota (GiB) | 0 (0 for unlimited quota) |
|
||||||
| Button Text | Sign in with Authentik (optional) |
|
| Button Text | Sign in with Authentik (optional) |
|
||||||
| Auto Register | Enabled (optional) |
|
| Auto Register | Enabled (optional) |
|
||||||
| Auto Launch | Enabled (optional) |
|
| Auto Launch | Enabled (optional) |
|
||||||
@@ -242,7 +164,7 @@ Configuration of OAuth in Immich System Settings
|
|||||||
| Signing Algorithm | RS256 |
|
| Signing Algorithm | RS256 |
|
||||||
| Storage Label Claim | preferred_username |
|
| Storage Label Claim | preferred_username |
|
||||||
| Storage Quota Claim | immich_quota |
|
| Storage Quota Claim | immich_quota |
|
||||||
| Default Storage Quota (GiB) | 0 (empty for unlimited quota) |
|
| Default Storage Quota (GiB) | 0 (0 for unlimited quota) |
|
||||||
| Button Text | Sign in with Google (optional) |
|
| Button Text | Sign in with Google (optional) |
|
||||||
| Auto Register | Enabled (optional) |
|
| Auto Register | Enabled (optional) |
|
||||||
| Auto Launch | Enabled |
|
| Auto Launch | Enabled |
|
||||||
|
|||||||
@@ -64,13 +64,7 @@ COMMIT;
|
|||||||
|
|
||||||
### Updating VectorChord
|
### Updating VectorChord
|
||||||
|
|
||||||
When installing a new version of VectorChord, you will need to manually update the extension and reindex by connecting to the Immich database and running:
|
When installing a new version of VectorChord, you will need to manually update the extension by connecting to the Immich database and running `ALTER EXTENSION vchord UPDATE;`.
|
||||||
|
|
||||||
```
|
|
||||||
ALTER EXTENSION vchord UPDATE;
|
|
||||||
REINDEX INDEX face_index;
|
|
||||||
REINDEX INDEX clip_index;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migrating to VectorChord
|
## Migrating to VectorChord
|
||||||
|
|
||||||
@@ -82,8 +76,6 @@ Support for pgvecto.rs will be dropped in a later release, hence we recommend al
|
|||||||
|
|
||||||
The easiest option is to have both extensions installed during the migration:
|
The easiest option is to have both extensions installed during the migration:
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Migration steps (automatic)</summary>
|
|
||||||
1. Ensure you still have pgvecto.rs installed
|
1. Ensure you still have pgvecto.rs installed
|
||||||
2. Install `pgvector` (`>= 0.7.0, < 1.0.0`). The easiest way to do this is on Debian/Ubuntu by adding the [PostgreSQL Apt repository][pg-apt] and then running `apt install postgresql-NN-pgvector`, where `NN` is your Postgres version (e.g., `16`)
|
2. Install `pgvector` (`>= 0.7.0, < 1.0.0`). The easiest way to do this is on Debian/Ubuntu by adding the [PostgreSQL Apt repository][pg-apt] and then running `apt install postgresql-NN-pgvector`, where `NN` is your Postgres version (e.g., `16`)
|
||||||
3. [Install VectorChord][vchord-install]
|
3. [Install VectorChord][vchord-install]
|
||||||
@@ -97,12 +89,8 @@ The easiest option is to have both extensions installed during the migration:
|
|||||||
11. Restart the Postgres database
|
11. Restart the Postgres database
|
||||||
12. Uninstall pgvecto.rs (e.g. `apt-get purge vectors-pg14` on Debian-based environments, replacing `pg14` as appropriate). `pgvector` must remain installed as it provides the data types used by `vchord`
|
12. Uninstall pgvecto.rs (e.g. `apt-get purge vectors-pg14` on Debian-based environments, replacing `pg14` as appropriate). `pgvector` must remain installed as it provides the data types used by `vchord`
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
If it is not possible to have both VectorChord and pgvecto.rs installed at the same time, you can perform the migration with more manual steps:
|
If it is not possible to have both VectorChord and pgvecto.rs installed at the same time, you can perform the migration with more manual steps:
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Migration steps (manual)</summary>
|
|
||||||
1. While pgvecto.rs is still installed, run the following SQL command using psql or your choice of database client. Take note of the number outputted by this command as you will need it later
|
1. While pgvecto.rs is still installed, run the following SQL command using psql or your choice of database client. Take note of the number outputted by this command as you will need it later
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
@@ -135,20 +123,14 @@ ALTER TABLE face_search ALTER COLUMN embedding SET DATA TYPE vector(512);
|
|||||||
|
|
||||||
5. Start Immich and let it create new indices using VectorChord
|
5. Start Immich and let it create new indices using VectorChord
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Migrating from pgvector
|
### Migrating from pgvector
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Migration steps</summary>
|
|
||||||
1. Ensure you have at least 0.7.0 of pgvector installed. If it is below that, please upgrade it and run the SQL command `ALTER EXTENSION vector UPDATE;` using psql or your choice of database client
|
1. Ensure you have at least 0.7.0 of pgvector installed. If it is below that, please upgrade it and run the SQL command `ALTER EXTENSION vector UPDATE;` using psql or your choice of database client
|
||||||
2. Follow the Prerequisites to install VectorChord
|
2. Follow the Prerequisites to install VectorChord
|
||||||
3. If Immich does not have superuser permissions, run the SQL command `CREATE EXTENSION vchord CASCADE;`
|
3. If Immich does not have superuser permissions, run the SQL command `CREATE EXTENSION vchord CASCADE;`
|
||||||
4. Remove the `DB_VECTOR_EXTENSION=pgvector` environmental variable as it will make Immich still use pgvector if set
|
4. Remove the `DB_VECTOR_EXTENSION=pgvector` environmental variable as it will make Immich still use pgvector if set
|
||||||
5. Start Immich and let it create new indices using VectorChord
|
5. Start Immich and let it create new indices using VectorChord
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
Note that VectorChord itself uses pgvector types, so you should not uninstall pgvector after following these steps.
|
Note that VectorChord itself uses pgvector types, so you should not uninstall pgvector after following these steps.
|
||||||
|
|
||||||
[vchord-install]: https://docs.vectorchord.ai/vectorchord/getting-started/installation.html
|
[vchord-install]: https://docs.vectorchord.ai/vectorchord/getting-started/installation.html
|
||||||
|
|||||||
@@ -2,17 +2,16 @@
|
|||||||
|
|
||||||
The `immich-server` docker image comes preinstalled with an administrative CLI (`immich-admin`) that supports the following commands:
|
The `immich-server` docker image comes preinstalled with an administrative CLI (`immich-admin`) that supports the following commands:
|
||||||
|
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
| ------------------------ | ------------------------------------------------------------- |
|
| ------------------------ | ------------------------------------- |
|
||||||
| `help` | Display help |
|
| `help` | Display help |
|
||||||
| `reset-admin-password` | Reset the password for the admin user |
|
| `reset-admin-password` | Reset the password for the admin user |
|
||||||
| `disable-password-login` | Disable password login |
|
| `disable-password-login` | Disable password login |
|
||||||
| `enable-password-login` | Enable password login |
|
| `enable-password-login` | Enable password login |
|
||||||
| `enable-oauth-login` | Enable OAuth login |
|
| `enable-oauth-login` | Enable OAuth login |
|
||||||
| `disable-oauth-login` | Disable OAuth login |
|
| `disable-oauth-login` | Disable OAuth login |
|
||||||
| `list-users` | List Immich users |
|
| `list-users` | List Immich users |
|
||||||
| `version` | Print Immich version |
|
| `version` | Print Immich version |
|
||||||
| `change-media-location` | Change database file paths to align with a new media location |
|
|
||||||
|
|
||||||
## How to run a command
|
## How to run a command
|
||||||
|
|
||||||
@@ -89,21 +88,3 @@ Print Immich Version
|
|||||||
immich-admin version
|
immich-admin version
|
||||||
v1.129.0
|
v1.129.0
|
||||||
```
|
```
|
||||||
|
|
||||||
Change media location
|
|
||||||
|
|
||||||
```
|
|
||||||
immich-admin change-media-location
|
|
||||||
? Enter the previous value of IMMICH_MEDIA_LOCATION: /data
|
|
||||||
? Enter the new value of IMMICH_MEDIA_LOCATION: /my-data
|
|
||||||
...
|
|
||||||
Previous value: /data
|
|
||||||
Current value: /my-data
|
|
||||||
|
|
||||||
Changing database paths from "/data/*" to "/my-data/*"
|
|
||||||
|
|
||||||
? Do you want to proceed? [Y/n] y
|
|
||||||
|
|
||||||
Database file paths updated successfully! đ
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ sidebar_position: 3
|
|||||||
|
|
||||||
Dev Containers provide a consistent, reproducible development environment using Docker containers. With a single click, you can get started with an Immich development environment on Mac, Linux, Windows, or in the cloud using GitHub Codespaces.
|
Dev Containers provide a consistent, reproducible development environment using Docker containers. With a single click, you can get started with an Immich development environment on Mac, Linux, Windows, or in the cloud using GitHub Codespaces.
|
||||||
|
|
||||||
Get started fast!
|
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/immich-app/immich/)
|
||||||
|
|
||||||
[](https://codespaces.new/immich-app/immich/)
|
[](https://codespaces.new/immich-app/immich/)
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ cd immich
|
|||||||
|
|
||||||
The immich dev containers read environment variables from your shell environment, not from `.env` files. This allows them to work in cloud environments without pre-configuration.
|
The immich dev containers read environment variables from your shell environment, not from `.env` files. This allows them to work in cloud environments without pre-configuration.
|
||||||
|
|
||||||
:::important Configuration
|
:::important Required Configuration
|
||||||
When running locally, and if you want to create (or use an existing) DB and/or photo storage folder, you must set the `UPLOAD_LOCATION` variable in your shell environment before launching the Dev Container. This determines where uploaded files are stored and also where the DB stores it data.
|
When running locally, and if you want to create (or use an existing) DB and/or photo storage folder, you must set the `UPLOAD_LOCATION` variable in your shell environment before launching the Dev Container. This determines where uploaded files are stored and also where the DB stores it data.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -88,10 +88,6 @@ source ~/.bashrc
|
|||||||
|
|
||||||
### Step 3: Launch the Dev Container
|
### Step 3: Launch the Dev Container
|
||||||
|
|
||||||
:::tip
|
|
||||||
Immich development makes extensive use of specialized [base images](https://github.com/immich-app/base-images) for its docker-compose based development. For this reason, you won't be able to use VSCode's **_Clone Repository in a Container Volume_** command.
|
|
||||||
:::
|
|
||||||
|
|
||||||
#### Using VS Code UI:
|
#### Using VS Code UI:
|
||||||
|
|
||||||
1. Open the cloned repository in VS Code
|
1. Open the cloned repository in VS Code
|
||||||
@@ -203,11 +199,13 @@ To use your SSH key for commit signing, see the [GitHub guide on SSH commit sign
|
|||||||
When the Dev Container starts, it automatically:
|
When the Dev Container starts, it automatically:
|
||||||
|
|
||||||
1. **Runs post-create script** (`container-server-post-create.sh`):
|
1. **Runs post-create script** (`container-server-post-create.sh`):
|
||||||
|
|
||||||
- Adjusts file permissions for the `node` user
|
- Adjusts file permissions for the `node` user
|
||||||
- Installs dependencies: `npm install` in all packages
|
- Installs dependencies: `npm install` in all packages
|
||||||
- Builds TypeScript SDK: `npm run build` in `open-api/typescript-sdk`
|
- Builds TypeScript SDK: `npm run build` in `open-api/typescript-sdk`
|
||||||
|
|
||||||
2. **Starts development servers** via VS Code tasks:
|
2. **Starts development servers** via VS Code tasks:
|
||||||
|
|
||||||
- `Immich API Server (Nest)` - API server with hot-reloading on port 2283
|
- `Immich API Server (Nest)` - API server with hot-reloading on port 2283
|
||||||
- `Immich Web Server (Vite)` - Web frontend with hot-reloading on port 3000
|
- `Immich Web Server (Vite)` - Web frontend with hot-reloading on port 3000
|
||||||
- Both servers watch for file changes and recompile automatically
|
- Both servers watch for file changes and recompile automatically
|
||||||
@@ -337,12 +335,14 @@ make install-all # Install all dependencies
|
|||||||
The Dev Container is pre-configured for debugging:
|
The Dev Container is pre-configured for debugging:
|
||||||
|
|
||||||
1. **API Server Debugging**:
|
1. **API Server Debugging**:
|
||||||
|
|
||||||
- Set breakpoints in VS Code
|
- Set breakpoints in VS Code
|
||||||
- Press `F5` or use "Run and Debug" panel
|
- Press `F5` or use "Run and Debug" panel
|
||||||
- Select "Attach to Server" configuration
|
- Select "Attach to Server" configuration
|
||||||
- Debug port: 9231
|
- Debug port: 9231
|
||||||
|
|
||||||
2. **Worker Debugging**:
|
2. **Worker Debugging**:
|
||||||
|
|
||||||
- Use "Attach to Workers" configuration
|
- Use "Attach to Workers" configuration
|
||||||
- Debug port: 9230
|
- Debug port: 9230
|
||||||
|
|
||||||
@@ -428,6 +428,7 @@ While the Dev Container focuses on server and web development, you can connect m
|
|||||||
```
|
```
|
||||||
|
|
||||||
2. **Configure mobile app**:
|
2. **Configure mobile app**:
|
||||||
|
|
||||||
- Server URL: `http://YOUR_IP:2283/api`
|
- Server URL: `http://YOUR_IP:2283/api`
|
||||||
- Ensure firewall allows port 2283
|
- Ensure firewall allows port 2283
|
||||||
|
|
||||||
|
|||||||
@@ -38,19 +38,6 @@ Run all server checks with `npm run check:all`
|
|||||||
You can use `npm run __:fix` to potentially correct some issues automatically for `npm run format` and `lint`.
|
You can use `npm run __:fix` to potentially correct some issues automatically for `npm run format` and `lint`.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Mobile Checks
|
|
||||||
|
|
||||||
The following commands must be executed from within the mobile app directory of the codebase.
|
|
||||||
|
|
||||||
- [ ] `make build` (auto-generate files using build_runner)
|
|
||||||
- [ ] `make analyze` (static analysis via Dart Analyzer and DCM)
|
|
||||||
- [ ] `make format` (formatting via Dart Formatter)
|
|
||||||
- [ ] `make test` (unit tests)
|
|
||||||
|
|
||||||
:::info Auto Fix
|
|
||||||
You can use `dart fix --apply` and `dcm fix lib` to potentially correct some issues automatically for `make analyze`.
|
|
||||||
:::
|
|
||||||
|
|
||||||
## OpenAPI
|
## OpenAPI
|
||||||
|
|
||||||
The OpenAPI client libraries need to be regenerated whenever there are changes to the `immich-openapi-specs.json` file. Note that you should not modify this file directly as it is auto-generated. See [OpenAPI](/docs/developer/open-api.md) for more details.
|
The OpenAPI client libraries need to be regenerated whenever there are changes to the `immich-openapi-specs.json` file. Note that you should not modify this file directly as it is auto-generated. See [OpenAPI](/docs/developer/open-api.md) for more details.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Folder view provides an additional view besides the timeline that is similar to a file explorer. It allows you to navigate through the folders and files in the library. This feature is handy for a highly curated and customized external library or a nicely configured storage template.
|
Folder view provides an additional view besides the timeline that is similar to a file explorer. It allows you to navigate through the folders and files in the library. This feature is handy for a highly curated and customized external library or a nicely configured storage template.
|
||||||
|
|
||||||
You can enable this feature under [`Account Settings > Features > Folders`](https://my.immich.app/user-settings?isOpen=feature+folders)
|
You can enable this feature under [`Account Settings > Features > Folder View`](https://my.immich.app/user-settings?isOpen=feature+folders)
|
||||||
|
|
||||||
## Enable folder view
|
## Enable folder view
|
||||||
|
|
||||||
|
|||||||
@@ -56,9 +56,9 @@ Internally, Immich uses the [glob](https://www.npmjs.com/package/glob) package t
|
|||||||
|
|
||||||
### Automatic watching (EXPERIMENTAL)
|
### Automatic watching (EXPERIMENTAL)
|
||||||
|
|
||||||
This feature is considered experimental and for advanced users only. If enabled, it will allow automatic watching of the filesystem which means new assets are automatically imported to Immich without needing to rescan.
|
This feature - currently hidden in the config file - is considered experimental and for advanced users only. If enabled, it will allow automatic watching of the filesystem which means new assets are automatically imported to Immich without needing to rescan.
|
||||||
|
|
||||||
If your photos are on a network drive, automatic file watching likely won't work. In that case, you will have to rely on a [periodic library refresh](#set-custom-scan-interval) to pull in your changes.
|
If your photos are on a network drive, automatic file watching likely won't work. In that case, you will have to rely on a periodic library refresh to pull in your changes.
|
||||||
|
|
||||||
#### Troubleshooting
|
#### Troubleshooting
|
||||||
|
|
||||||
@@ -72,9 +72,7 @@ In rare cases, the library watcher can hang, preventing Immich from starting up.
|
|||||||
|
|
||||||
### Nightly job
|
### Nightly job
|
||||||
|
|
||||||
There is an automatic scan job that is scheduled to run once a day. Its schedule is configurable, see [Set Custom Scan Interval](#set-custom-scan-interval).
|
There is an automatic scan job that is scheduled to run once a day. This job also cleans up any libraries stuck in deletion. It is possible to trigger the cleanup by clicking "Scan all libraries" in the library management page.
|
||||||
|
|
||||||
This job also cleans up any libraries stuck in deletion. It is possible to trigger the cleanup by clicking "Scan all libraries" in the library management page.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -93,7 +91,7 @@ The `immich-server` container will need access to the gallery. Modify your docke
|
|||||||
```diff title="docker-compose.yml"
|
```diff title="docker-compose.yml"
|
||||||
immich-server:
|
immich-server:
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION}:/data
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
+ - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro
|
+ - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro
|
||||||
+ - /home/user/old-pics:/mnt/media/old-pics:ro
|
+ - /home/user/old-pics:/mnt/media/old-pics:ro
|
||||||
+ - /mnt/media/videos:/mnt/media/videos:ro
|
+ - /mnt/media/videos:/mnt/media/videos:ro
|
||||||
@@ -114,7 +112,7 @@ _Remember to run `docker compose up -d` to register the changes. Make sure you c
|
|||||||
|
|
||||||
These actions must be performed by the Immich administrator.
|
These actions must be performed by the Immich administrator.
|
||||||
|
|
||||||
- Click on your avatar in the upper right corner
|
- Click on your avatar on the upper right corner
|
||||||
- Click on Administration -> External Libraries
|
- Click on Administration -> External Libraries
|
||||||
- Click on Create an external libraryâĻ
|
- Click on Create an external libraryâĻ
|
||||||
- Select which user owns the library, this can not be changed later
|
- Select which user owns the library, this can not be changed later
|
||||||
@@ -161,7 +159,9 @@ Within seconds, the assets from the old-pics and videos folders should show up i
|
|||||||
|
|
||||||
Folder view provides an additional view besides the timeline that is similar to a file explorer. It allows you to navigate through the folders and files in the library. This feature is handy for a highly curated and customized external library or a nicely configured storage template.
|
Folder view provides an additional view besides the timeline that is similar to a file explorer. It allows you to navigate through the folders and files in the library. This feature is handy for a highly curated and customized external library or a nicely configured storage template.
|
||||||
|
|
||||||
You can enable this feature under [`Account Settings > Features > Folders`](https://my.immich.app/user-settings?isOpen=feature+folders)
|
You can enable this feature under [`Account Settings > Features > Folder View`](https://my.immich.app/user-settings?isOpen=feature+folders)
|
||||||
|
|
||||||
|
The UI is currently only available for the web; mobile will come in a subsequent release.
|
||||||
|
|
||||||
<img src={require('./img/folder-view-1.webp').default} width="100%" title='Folder-view' />
|
<img src={require('./img/folder-view-1.webp').default} width="100%" title='Folder-view' />
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ You can enable this feature under [`Account Settings > Features > Folders`](http
|
|||||||
Only an admin can do this.
|
Only an admin can do this.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
You can define a custom interval for the trigger external library rescan under Administration -> Settings -> External Library.
|
You can define a custom interval for the trigger external library rescan under Administration -> Settings -> Library.
|
||||||
You can set the scanning interval using the preset or cron format. For more information you can refer to [Crontab Guru](https://crontab.guru/).
|
You can set the scanning interval using the preset or cron format. For more information you can refer to [Crontab Guru](https://crontab.guru/).
|
||||||
|
|
||||||
<img src={require('./img/library-custom-scan-interval.webp').default} width="75%" title='Set custom scan interval for external library' />
|
<img src={require('./img/library-custom-scan-interval.webp').default} width="75%" title='Set custom scan interval for external library' />
|
||||||
|
|||||||
@@ -88,9 +88,9 @@ It will only reflect files you add.
|
|||||||
:::
|
:::
|
||||||
|
|
||||||
If the same asset is in more than one album it will only sync to the first album it's in, after that it won't sync again even if the user clicks sync albums manually.
|
If the same asset is in more than one album it will only sync to the first album it's in, after that it won't sync again even if the user clicks sync albums manually.
|
||||||
To overcome this limitation, the files must be removed from the ignore list by
|
To overcome this limitation, the files must be removed from the blacklist by
|
||||||
App settings -> Advanced -> Duplicate Assets -> Clear
|
App settings -> Advanced -> Duplicate Assets -> Clear
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
Cleaning duplicate assets from the list will cause all the previously uploaded duplicate files to be re-uploaded, the files will not actually be uploaded and will be rejected on the server side (due to duplication) but will be synchronized to the album and at the end will be added to the ignore list again at the end of the synchronization.
|
Cleaning duplicate assets from the list will cause all the previously uploaded duplicate files to be re-uploaded, the files will not actually be uploaded and will be rejected on the server side (due to duplication) but will be synchronized to the album and at the end will be added to the black list again at the end of the synchronization.
|
||||||
:::
|
:::
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ For the full list, refer to the [Immich source code](https://github.com/immich-a
|
|||||||
| `HEIC` | `.heic` | :white_check_mark: | |
|
| `HEIC` | `.heic` | :white_check_mark: | |
|
||||||
| `HEIF` | `.heif` | :white_check_mark: | |
|
| `HEIF` | `.heif` | :white_check_mark: | |
|
||||||
| `JPEG 2000` | `.jp2` | :white_check_mark: | |
|
| `JPEG 2000` | `.jp2` | :white_check_mark: | |
|
||||||
| `JPEG` | `.jpeg` `.jpg` `.jpe` `.insp` | :white_check_mark: | |
|
| `JPEG` | `.webp` `.jpg` `.jpe` `.insp` | :white_check_mark: | |
|
||||||
| `JPEG XL` | `.jxl` | :white_check_mark: | |
|
| `JPEG XL` | `.jxl` | :white_check_mark: | |
|
||||||
| `PNG` | `.png` | :white_check_mark: | |
|
| `PNG` | `.png` | :white_check_mark: | |
|
||||||
| `PSD` | `.psd` | :white_check_mark: | Adobe Photoshop |
|
| `PSD` | `.psd` | :white_check_mark: | Adobe Photoshop |
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ After defining the locations of these files, we will edit the `docker-compose.ym
|
|||||||
services:
|
services:
|
||||||
immich-server:
|
immich-server:
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION}:/data
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
+ - ${THUMB_LOCATION}:/data/thumbs
|
+ - ${THUMB_LOCATION}:/usr/src/app/upload/thumbs
|
||||||
+ - ${ENCODED_VIDEO_LOCATION}:/data/encoded-video
|
+ - ${ENCODED_VIDEO_LOCATION}:/usr/src/app/upload/encoded-video
|
||||||
+ - ${PROFILE_LOCATION}:/data/profile
|
+ - ${PROFILE_LOCATION}:/usr/src/app/upload/profile
|
||||||
+ - ${BACKUP_LOCATION}:/data/backups
|
+ - ${BACKUP_LOCATION}:/usr/src/app/upload/backups
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ docker compose up -d
|
|||||||
|
|
||||||
:::note
|
:::note
|
||||||
Because of the underlying properties of docker bind mounts, it is not recommended to mount the `upload/` and `library/` folders as separate bind mounts if they are on the same device.
|
Because of the underlying properties of docker bind mounts, it is not recommended to mount the `upload/` and `library/` folders as separate bind mounts if they are on the same device.
|
||||||
For this reason, we mount the HDD or the network storage (NAS) to `/data` and then mount the folders we want to access under that folder.
|
For this reason, we mount the HDD or the network storage (NAS) to `/usr/src/app/upload` and then mount the folders we want to access under that folder.
|
||||||
|
|
||||||
The `thumbs/` folder contains both the small thumbnails displayed in the timeline and the larger previews shown when clicking into an image. These cannot be separated.
|
The `thumbs/` folder contains both the small thumbnails displayed in the timeline and the larger previews shown when clicking into an image. These cannot be separated.
|
||||||
|
|
||||||
|
|||||||
@@ -12,131 +12,105 @@ Run `docker exec -it immich_postgres psql --dbname=<DB_DATABASE_NAME> --username
|
|||||||
|
|
||||||
## Assets
|
## Assets
|
||||||
|
|
||||||
### Name
|
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
The `"originalFileName"` column is the name of the file at time of upload, including the extension.
|
The `"originalFileName"` column is the name of the file at time of upload, including the extension.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
```sql title="Find by original filename"
|
```sql title="Find by original filename"
|
||||||
SELECT * FROM "asset" WHERE "originalFileName" = 'PXL_20230903_232542848.jpg';
|
SELECT * FROM "assets" WHERE "originalFileName" = 'PXL_20230903_232542848.jpg';
|
||||||
SELECT * FROM "asset" WHERE "originalFileName" LIKE 'PXL_%'; -- all files starting with PXL_
|
SELECT * FROM "assets" WHERE "originalFileName" LIKE 'PXL_%'; -- all files starting with PXL_
|
||||||
SELECT * FROM "asset" WHERE "originalFileName" LIKE '%_2023_%'; -- all files with _2023_ in the middle
|
SELECT * FROM "assets" WHERE "originalFileName" LIKE '%_2023_%'; -- all files with _2023_ in the middle
|
||||||
```
|
```
|
||||||
|
|
||||||
```sql title="Find by path"
|
```sql title="Find by path"
|
||||||
SELECT * FROM "asset" WHERE "originalPath" = 'upload/library/admin/2023/2023-09-03/PXL_2023.jpg';
|
SELECT * FROM "assets" WHERE "originalPath" = 'upload/library/admin/2023/2023-09-03/PXL_2023.jpg';
|
||||||
SELECT * FROM "asset" WHERE "originalPath" LIKE 'upload/library/admin/2023/%';
|
SELECT * FROM "assets" WHERE "originalPath" LIKE 'upload/library/admin/2023/%';
|
||||||
```
|
```
|
||||||
|
|
||||||
### ID
|
|
||||||
|
|
||||||
```sql title="Find by ID"
|
```sql title="Find by ID"
|
||||||
SELECT * FROM "asset" WHERE "id" = '9f94e60f-65b6-47b7-ae44-a4df7b57f0e9';
|
SELECT * FROM "assets" WHERE "id" = '9f94e60f-65b6-47b7-ae44-a4df7b57f0e9';
|
||||||
```
|
```
|
||||||
|
|
||||||
```sql title="Find by partial ID"
|
```sql title="Find by partial ID"
|
||||||
SELECT * FROM "asset" WHERE "id"::text LIKE '%ab431d3a%';
|
SELECT * FROM "assets" WHERE "id"::text LIKE '%ab431d3a%';
|
||||||
```
|
```
|
||||||
|
|
||||||
### Checksum
|
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
You can calculate the checksum for a particular file by using the command `sha1sum <filename>`.
|
You can calculate the checksum for a particular file by using the command `sha1sum <filename>`.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
```sql title="Find by checksum (SHA-1)"
|
```sql title="Find by checksum (SHA-1)"
|
||||||
SELECT encode("checksum", 'hex') FROM "asset";
|
SELECT encode("checksum", 'hex') FROM "assets";
|
||||||
SELECT * FROM "asset" WHERE "checksum" = decode('69de19c87658c4c15d9cacb9967b8e033bf74dd1', 'hex');
|
SELECT * FROM "assets" WHERE "checksum" = decode('69de19c87658c4c15d9cacb9967b8e033bf74dd1', 'hex');
|
||||||
SELECT * FROM "asset" WHERE "checksum" = '\x69de19c87658c4c15d9cacb9967b8e033bf74dd1'; -- alternate notation
|
SELECT * FROM "assets" WHERE "checksum" = '\x69de19c87658c4c15d9cacb9967b8e033bf74dd1'; -- alternate notation
|
||||||
```
|
```
|
||||||
|
|
||||||
```sql title="Find duplicate assets with identical checksum (SHA-1) (excluding trashed files)"
|
```sql title="Find duplicate assets with identical checksum (SHA-1) (excluding trashed files)"
|
||||||
SELECT T1."checksum", array_agg(T2."id") ids FROM "asset" T1
|
SELECT T1."checksum", array_agg(T2."id") ids FROM "assets" T1
|
||||||
INNER JOIN "asset" T2 ON T1."checksum" = T2."checksum" AND T1."id" != T2."id" AND T2."deletedAt" IS NULL
|
INNER JOIN "assets" T2 ON T1."checksum" = T2."checksum" AND T1."id" != T2."id" AND T2."deletedAt" IS NULL
|
||||||
WHERE T1."deletedAt" IS NULL GROUP BY T1."checksum";
|
WHERE T1."deletedAt" IS NULL GROUP BY T1."checksum";
|
||||||
```
|
```
|
||||||
|
|
||||||
### Metadata
|
|
||||||
|
|
||||||
```sql title="Live photos"
|
```sql title="Live photos"
|
||||||
SELECT * FROM "asset" WHERE "livePhotoVideoId" IS NOT NULL;
|
SELECT * FROM "assets" WHERE "livePhotoVideoId" IS NOT NULL;
|
||||||
```
|
```
|
||||||
|
|
||||||
```sql title="By description"
|
```sql title="By description"
|
||||||
SELECT "asset".*, "asset_exif"."description" FROM "asset_exif"
|
SELECT "assets".*, "exif"."description" FROM "exif"
|
||||||
JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
|
JOIN "assets" ON "assets"."id" = "exif"."assetId"
|
||||||
WHERE TRIM("asset_exif"."description") <> ''; -- all files with a description
|
WHERE TRIM("exif"."description") <> ''; -- all files with a description
|
||||||
SELECT "asset".*, "asset_exif"."description" FROM "asset_exif"
|
SELECT "assets".*, "exif"."description" FROM "exif"
|
||||||
JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
|
JOIN "assets" ON "assets"."id" = "exif"."assetId"
|
||||||
WHERE "asset_exif"."description" ILIKE '%string to match%'; -- search by string
|
WHERE "exif"."description" ILIKE '%string to match%'; -- search by string
|
||||||
```
|
```
|
||||||
|
|
||||||
```sql title="Without metadata"
|
```sql title="Without metadata"
|
||||||
SELECT "asset".* FROM "asset_exif"
|
SELECT "assets".* FROM "exif"
|
||||||
LEFT JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
|
LEFT JOIN "assets" ON "assets"."id" = "exif"."assetId"
|
||||||
WHERE "asset_exif"."assetId" IS NULL;
|
WHERE "exif"."assetId" IS NULL;
|
||||||
```
|
```
|
||||||
|
|
||||||
```sql title="size < 100,000 bytes, smallest to largest"
|
```sql title="size < 100,000 bytes, smallest to largest"
|
||||||
SELECT * FROM "asset"
|
SELECT * FROM "assets"
|
||||||
JOIN "asset_exif" ON "asset"."id" = "asset_exif"."assetId"
|
JOIN "exif" ON "assets"."id" = "exif"."assetId"
|
||||||
WHERE "asset_exif"."fileSizeInByte" < 100000
|
WHERE "exif"."fileSizeInByte" < 100000
|
||||||
ORDER BY "asset_exif"."fileSizeInByte" ASC;
|
ORDER BY "exif"."fileSizeInByte" ASC;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Type
|
```sql title="Without thumbnails"
|
||||||
|
SELECT * FROM "assets" WHERE "assets"."previewPath" IS NULL OR "assets"."thumbnailPath" IS NULL;
|
||||||
|
```
|
||||||
|
|
||||||
```sql title="By type"
|
```sql title="By type"
|
||||||
SELECT * FROM "asset" WHERE "asset"."type" = 'VIDEO';
|
SELECT * FROM "assets" WHERE "assets"."type" = 'VIDEO';
|
||||||
SELECT * FROM "asset" WHERE "asset"."type" = 'IMAGE';
|
SELECT * FROM "assets" WHERE "assets"."type" = 'IMAGE';
|
||||||
```
|
```
|
||||||
|
|
||||||
```sql title="Count by type"
|
```sql title="Count by type"
|
||||||
SELECT "asset"."type", COUNT(*) FROM "asset" GROUP BY "asset"."type";
|
SELECT "assets"."type", COUNT(*) FROM "assets" GROUP BY "assets"."type";
|
||||||
```
|
```
|
||||||
|
|
||||||
```sql title="Count by type (per user)"
|
```sql title="Count by type (per user)"
|
||||||
SELECT "user"."email", "asset"."type", COUNT(*) FROM "asset"
|
SELECT "users"."email", "assets"."type", COUNT(*) FROM "assets"
|
||||||
JOIN "user" ON "asset"."ownerId" = "user"."id"
|
JOIN "users" ON "assets"."ownerId" = "users"."id"
|
||||||
GROUP BY "asset"."type", "user"."email" ORDER BY "user"."email";
|
GROUP BY "assets"."type", "users"."email" ORDER BY "users"."email";
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tags
|
```sql title="Failed file movements"
|
||||||
|
SELECT * FROM "move_history";
|
||||||
```sql title="Count by tag"
|
|
||||||
SELECT "t"."value" AS "tag_name", COUNT(*) AS "number_assets" FROM "tag" "t"
|
|
||||||
JOIN "tag_asset" "ta" ON "t"."id" = "ta"."tagsId" JOIN "asset" "a" ON "ta"."assetsId" = "a"."id"
|
|
||||||
WHERE "a"."visibility" != 'hidden'
|
|
||||||
GROUP BY "t"."value" ORDER BY "number_assets" DESC;
|
|
||||||
```
|
|
||||||
|
|
||||||
```sql title="Count by tag (per user)"
|
|
||||||
SELECT "t"."value" AS "tag_name", "u"."email" as "user_email", COUNT(*) AS "number_assets" FROM "tag" "t"
|
|
||||||
JOIN "tag_asset" "ta" ON "t"."id" = "ta"."tagsId" JOIN "asset" "a" ON "ta"."assetsId" = "a"."id" JOIN "user" "u" ON "a"."ownerId" = "u"."id"
|
|
||||||
WHERE "a"."visibility" != 'hidden'
|
|
||||||
GROUP BY "t"."value", "u"."email" ORDER BY "number_assets" DESC;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Users
|
## Users
|
||||||
|
|
||||||
```sql title="List all users"
|
```sql title="List all users"
|
||||||
SELECT * FROM "user";
|
SELECT * FROM "users";
|
||||||
```
|
```
|
||||||
|
|
||||||
```sql title="Get owner info from asset ID"
|
```sql title="Get owner info from asset ID"
|
||||||
SELECT "user".* FROM "user" JOIN "asset" ON "user"."id" = "asset"."ownerId" WHERE "asset"."id" = 'fa310b01-2f26-4b7a-9042-d578226e021f';
|
SELECT "users".* FROM "users" JOIN "assets" ON "users"."id" = "assets"."ownerId" WHERE "assets"."id" = 'fa310b01-2f26-4b7a-9042-d578226e021f';
|
||||||
```
|
```
|
||||||
|
|
||||||
## Persons
|
## System Config
|
||||||
|
|
||||||
```sql title="Delete person and unset it for the faces it was associated with"
|
|
||||||
DELETE FROM "person" WHERE "name" = 'PersonNameHere';
|
|
||||||
```
|
|
||||||
|
|
||||||
## System
|
|
||||||
|
|
||||||
### Config
|
|
||||||
|
|
||||||
```sql title="Custom settings"
|
```sql title="Custom settings"
|
||||||
SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config';
|
SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config';
|
||||||
@@ -144,14 +118,10 @@ SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config';
|
|||||||
|
|
||||||
(Only used when not using the [config file](/docs/install/config-file))
|
(Only used when not using the [config file](/docs/install/config-file))
|
||||||
|
|
||||||
### File properties
|
## Persons
|
||||||
|
|
||||||
```sql title="Without thumbnails"
|
```sql title="Delete person and unset it for the faces it was associated with"
|
||||||
SELECT * FROM "asset" WHERE "asset"."previewPath" IS NULL OR "asset"."thumbnailPath" IS NULL;
|
DELETE FROM "person" WHERE "name" = 'PersonNameHere';
|
||||||
```
|
|
||||||
|
|
||||||
```sql title="Failed file movements"
|
|
||||||
SELECT * FROM "move_history";
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Postgres internal
|
## Postgres internal
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ If you want Immich to be able to delete the images in the external library or ad
|
|||||||
```diff
|
```diff
|
||||||
immich-server:
|
immich-server:
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION}:/data
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
+ - /home/user/photos1:/home/user/photos1:ro
|
+ - /home/user/photos1:/home/user/photos1:ro
|
||||||
+ - /mnt/photos2:/mnt/photos2:ro # you can delete this line if you only have one mount point, or you can add more lines if you have more than two
|
+ - /mnt/photos2:/mnt/photos2:ro # you can delete this line if you only have one mount point, or you can add more lines if you have more than two
|
||||||
```
|
```
|
||||||
@@ -41,7 +41,7 @@ In the Immich web UI:
|
|||||||
- Click Add path
|
- Click Add path
|
||||||
<img src={require('./img/add-path-button.webp').default} width="50%" title="Add Path button" />
|
<img src={require('./img/add-path-button.webp').default} width="50%" title="Add Path button" />
|
||||||
|
|
||||||
- Enter **/home/user/photos1** as the path and click Add
|
- Enter **/usr/src/app/external** as the path and click Add
|
||||||
<img src={require('./img/add-path-field.webp').default} width="50%" title="Add Path field" />
|
<img src={require('./img/add-path-field.webp').default} width="50%" title="Add Path field" />
|
||||||
|
|
||||||
- Save the new path
|
- Save the new path
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 2.3 KiB |
@@ -52,9 +52,9 @@ REMOTE_BACKUP_PATH="/path/to/remote/backup/directory"
|
|||||||
### Local
|
### Local
|
||||||
|
|
||||||
# Backup Immich database
|
# Backup Immich database
|
||||||
docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=<DB_USERNAME> > "$UPLOAD_LOCATION"/database-backup/immich-database.sql
|
docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres > "$UPLOAD_LOCATION"/database-backup/immich-database.sql
|
||||||
# For deduplicating backup programs such as Borg or Restic, compressing the content can increase backup size by making it harder to deduplicate. If you are using a different program or still prefer to compress, you can use the following command instead:
|
# For deduplicating backup programs such as Borg or Restic, compressing the content can increase backup size by making it harder to deduplicate. If you are using a different program or still prefer to compress, you can use the following command instead:
|
||||||
# docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=<DB_USERNAME> | /usr/bin/gzip --rsyncable > "$UPLOAD_LOCATION"/database-backup/immich-database.sql.gz
|
# docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres | /usr/bin/gzip --rsyncable > "$UPLOAD_LOCATION"/database-backup/immich-database.sql.gz
|
||||||
|
|
||||||
### Append to local Borg repository
|
### Append to local Borg repository
|
||||||
borg create "$BACKUP_PATH/immich-borg::{now}" "$UPLOAD_LOCATION" --exclude "$UPLOAD_LOCATION"/thumbs/ --exclude "$UPLOAD_LOCATION"/encoded-video/
|
borg create "$BACKUP_PATH/immich-borg::{now}" "$UPLOAD_LOCATION" --exclude "$UPLOAD_LOCATION"/thumbs/ --exclude "$UPLOAD_LOCATION"/encoded-video/
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ These environment variables are used by the `docker-compose.yml` file and do **N
|
|||||||
| `TZ` | Timezone | <sup>\*1</sup> | server | microservices |
|
| `TZ` | Timezone | <sup>\*1</sup> | server | microservices |
|
||||||
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
|
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
|
||||||
| `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
|
| `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
|
||||||
| `IMMICH_MEDIA_LOCATION` | Media location inside the container â ī¸**You probably shouldn't set this**<sup>\*2</sup>â ī¸ | `/data` | server | api, microservices |
|
| `IMMICH_MEDIA_LOCATION` | Media location inside the container â ī¸**You probably shouldn't set this**<sup>\*2</sup>â ī¸ | `./upload`<sup>\*3</sup> | server | api, microservices |
|
||||||
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
|
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
|
||||||
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
|
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
|
||||||
| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | |
|
| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | |
|
||||||
@@ -49,6 +49,9 @@ These environment variables are used by the `docker-compose.yml` file and do **N
|
|||||||
|
|
||||||
\*2: This path is where the Immich code looks for the files, which is internal to the docker container. Setting it to a path on your host will certainly break things, you should use the `UPLOAD_LOCATION` variable instead.
|
\*2: This path is where the Immich code looks for the files, which is internal to the docker container. Setting it to a path on your host will certainly break things, you should use the `UPLOAD_LOCATION` variable instead.
|
||||||
|
|
||||||
|
\*3: With the default `WORKDIR` of `/usr/src/app`, this path will resolve to `/usr/src/app/upload`.
|
||||||
|
It only needs to be set if the Immich deployment method is changing.
|
||||||
|
|
||||||
## Workers
|
## Workers
|
||||||
|
|
||||||
| Variable | Description | Default | Containers |
|
| Variable | Description | Default | Containers |
|
||||||
@@ -69,25 +72,22 @@ Information on the current workers can be found [here](/docs/administration/jobs
|
|||||||
|
|
||||||
## Database
|
## Database
|
||||||
|
|
||||||
| Variable | Description | Default | Containers |
|
| Variable | Description | Default | Containers |
|
||||||
| :---------------------------------- | :------------------------------------------------------------------------------------- | :--------: | :----------------------------- |
|
| :---------------------------------- | :--------------------------------------------------------------------------- | :--------: | :----------------------------- |
|
||||||
| `DB_URL` | Database URL | | server |
|
| `DB_URL` | Database URL | | server |
|
||||||
| `DB_HOSTNAME` | Database host | `database` | server |
|
| `DB_HOSTNAME` | Database host | `database` | server |
|
||||||
| `DB_PORT` | Database port | `5432` | server |
|
| `DB_PORT` | Database port | `5432` | server |
|
||||||
| `DB_USERNAME` | Database user | `postgres` | server, database<sup>\*1</sup> |
|
| `DB_USERNAME` | Database user | `postgres` | server, database<sup>\*1</sup> |
|
||||||
| `DB_PASSWORD` | Database password | `postgres` | server, database<sup>\*1</sup> |
|
| `DB_PASSWORD` | Database password | `postgres` | server, database<sup>\*1</sup> |
|
||||||
| `DB_DATABASE_NAME` | Database name | `immich` | server, database<sup>\*1</sup> |
|
| `DB_DATABASE_NAME` | Database name | `immich` | server, database<sup>\*1</sup> |
|
||||||
| `DB_SSL_MODE` | Database SSL mode | | server |
|
| `DB_SSL_MODE` | Database SSL mode | | server |
|
||||||
| `DB_VECTOR_EXTENSION`<sup>\*2</sup> | Database vector extension (one of [`vectorchord`, `pgvector`, `pgvecto.rs`]) | | server |
|
| `DB_VECTOR_EXTENSION`<sup>\*2</sup> | Database vector extension (one of [`vectorchord`, `pgvector`, `pgvecto.rs`]) | | server |
|
||||||
| `DB_SKIP_MIGRATIONS` | Whether to skip running migrations on startup (one of [`true`, `false`]) | `false` | server |
|
| `DB_SKIP_MIGRATIONS` | Whether to skip running migrations on startup (one of [`true`, `false`]) | `false` | server |
|
||||||
| `DB_STORAGE_TYPE` | Optimize concurrent IO on SSDs or sequential IO on HDDs ([`SSD`, `HDD`])<sup>\*3</sup> | `SSD` | server |
|
|
||||||
|
|
||||||
\*1: The values of `DB_USERNAME`, `DB_PASSWORD`, and `DB_DATABASE_NAME` are passed to the Postgres container as the variables `POSTGRES_USER`, `POSTGRES_PASSWORD`, and `POSTGRES_DB` in `docker-compose.yml`.
|
\*1: The values of `DB_USERNAME`, `DB_PASSWORD`, and `DB_DATABASE_NAME` are passed to the Postgres container as the variables `POSTGRES_USER`, `POSTGRES_PASSWORD`, and `POSTGRES_DB` in `docker-compose.yml`.
|
||||||
|
|
||||||
\*2: If not provided, the appropriate extension to use is auto-detected at startup by introspecting the database. When multiple extensions are installed, the order of preference is VectorChord, pgvecto.rs, pgvector.
|
\*2: If not provided, the appropriate extension to use is auto-detected at startup by introspecting the database. When multiple extensions are installed, the order of preference is VectorChord, pgvecto.rs, pgvector.
|
||||||
|
|
||||||
\*3: Uses either [`postgresql.ssd.conf`](https://github.com/immich-app/base-images/blob/main/postgres/postgresql.ssd.conf) or [`postgresql.hdd.conf`](https://github.com/immich-app/base-images/blob/main/postgres/postgresql.hdd.conf) which mainly controls the Postgres `effective_io_concurrency` setting to allow for concurrenct IO on SSDs and sequential IO on HDDs.
|
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
|
||||||
All `DB_` variables must be provided to all Immich workers, including `api` and `microservices`.
|
All `DB_` variables must be provided to all Immich workers, including `api` and `microservices`.
|
||||||
@@ -199,11 +199,12 @@ Additional machine learning parameters can be tuned from the admin UI.
|
|||||||
| `IMMICH_TELEMETRY_INCLUDE` | Collect these telemetries. List of `host`, `api`, `io`, `repo`, `job`. Note: You can also specify `all` to enable all | | server | api, microservices |
|
| `IMMICH_TELEMETRY_INCLUDE` | Collect these telemetries. List of `host`, `api`, `io`, `repo`, `job`. Note: You can also specify `all` to enable all | | server | api, microservices |
|
||||||
| `IMMICH_TELEMETRY_EXCLUDE` | Do not collect these telemetries. List of `host`, `api`, `io`, `repo`, `job` | | server | api, microservices |
|
| `IMMICH_TELEMETRY_EXCLUDE` | Do not collect these telemetries. List of `host`, `api`, `io`, `repo`, `job` | | server | api, microservices |
|
||||||
|
|
||||||
## Secrets
|
## Docker Secrets
|
||||||
|
|
||||||
The following variables support reading from files, either via [Systemd Credentials][systemd-creds] or [Docker secrets][docker-secrets] for additional security.
|
The following variables support the use of [Docker secrets][docker-secrets] for additional security.
|
||||||
|
|
||||||
To use any of these, either set `CREDENTIALS_DIRECTORY` to a directory that contains files whose name is the âregular variableâ name, and whose content is the secret. If using Docker Secrets, setting `CREDENTIALS_DIRECTORY=/run/secrets` will cause all secrets present to be used. Alternatively, replace the regular variable with the equivalent `_FILE` environment variable as below. The value of the `_FILE` variable should be set to the path of a file containing the variable value.
|
To use any of these, replace the regular environment variable with the equivalent `_FILE` environment variable. The value of
|
||||||
|
the `_FILE` variable should be set to the path of a file containing the variable value.
|
||||||
|
|
||||||
| Regular Variable | Equivalent Docker Secrets '\_FILE' Variable |
|
| Regular Variable | Equivalent Docker Secrets '\_FILE' Variable |
|
||||||
| :----------------- | :------------------------------------------ |
|
| :----------------- | :------------------------------------------ |
|
||||||
@@ -225,4 +226,3 @@ to use a Docker secret for the password in the Redis container.
|
|||||||
[docker-secrets-docs]: https://github.com/docker-library/docs/tree/master/postgres#docker-secrets
|
[docker-secrets-docs]: https://github.com/docker-library/docs/tree/master/postgres#docker-secrets
|
||||||
[docker-secrets]: https://docs.docker.com/engine/swarm/secrets/
|
[docker-secrets]: https://docs.docker.com/engine/swarm/secrets/
|
||||||
[ioredis]: https://ioredis.readthedocs.io/en/latest/README/#connect-to-redis
|
[ioredis]: https://ioredis.readthedocs.io/en/latest/README/#connect-to-redis
|
||||||
[systemd-creds]: https://systemd.io/CREDENTIALS/
|
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ alt="Dot Env Example"
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
- Change the default `DB_PASSWORD`, and add custom database connection information if necessary.
|
- Change the default `DB_PASSWORD`, and add custom database connection information if necessary.
|
||||||
- Change `DB_DATA_LOCATION` to a folder (absolute path) where the database will be saved to disk.
|
- Change `DB_DATA_LOCATION` to a folder where the database will be saved to disk.
|
||||||
- Change `UPLOAD_LOCATION` to a folder (absolute path) where media (uploaded and generated) will be stored.
|
- Change `UPLOAD_LOCATION` to a folder where media (uploaded and generated) will be stored.
|
||||||
|
|
||||||
11. Click on "**Deploy the stack**".
|
11. Click on "**Deploy the stack**".
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ This is a community contribution and not officially supported by the Immich team
|
|||||||
|
|
||||||
Community support can be found in the dedicated channel on the [Discord Server](https://discord.immich.app/).
|
Community support can be found in the dedicated channel on the [Discord Server](https://discord.immich.app/).
|
||||||
|
|
||||||
**Please report app issues to the corresponding [Github Repository](https://github.com/truenas/apps/tree/master/trains/community/immich).**
|
**Please report app issues to the corresponding [Github Repository](https://github.com/truenas/charts/tree/master/community/immich).**
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Immich can easily be installed on TrueNAS Community Edition via the **Community** train application.
|
Immich can easily be installed on TrueNAS Community Edition via the **Community** train application.
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
|
|||||||
5. Click "**Save Changes**", you will be prompted to edit stack UI labels, just leave this blank and click "**Ok**"
|
5. Click "**Save Changes**", you will be prompted to edit stack UI labels, just leave this blank and click "**Ok**"
|
||||||
6. Select the cog âī¸ next to Immich, click "**Edit Stack**", then click "**Env File**"
|
6. Select the cog âī¸ next to Immich, click "**Edit Stack**", then click "**Env File**"
|
||||||
7. Paste the entire contents of the [Immich example.env](https://github.com/immich-app/immich/releases/latest/download/example.env) file into the Unraid editor, then **before saving** edit the following:
|
7. Paste the entire contents of the [Immich example.env](https://github.com/immich-app/immich/releases/latest/download/example.env) file into the Unraid editor, then **before saving** edit the following:
|
||||||
|
|
||||||
- `UPLOAD_LOCATION`: Create a folder in your Images Unraid share and place the **absolute** location here > For example my _"images"_ share has a folder within it called _"immich"_. If I browse to this directory in the terminal and type `pwd` the output is `/mnt/user/images/immich`. This is the exact value I need to enter as my `UPLOAD_LOCATION`
|
- `UPLOAD_LOCATION`: Create a folder in your Images Unraid share and place the **absolute** location here > For example my _"images"_ share has a folder within it called _"immich"_. If I browse to this directory in the terminal and type `pwd` the output is `/mnt/user/images/immich`. This is the exact value I need to enter as my `UPLOAD_LOCATION`
|
||||||
- `DB_DATA_LOCATION`: Change this to use an Unraid share (preferably a cache pool, e.g. `/mnt/user/appdata/postgresql/data`). This uses the `appdata` share. Do also create the `postgresql` folder, by running `mkdir /mnt/user/{share_location}/postgresql/data`. If left at default it will try to use Unraid's `/boot/config/plugins/compose.manager/projects/[stack_name]/postgres` folder which it doesn't have permissions to, resulting in this container continuously restarting.
|
- `DB_DATA_LOCATION`: Change this to use an Unraid share (preferably a cache pool, e.g. `/mnt/user/appdata/postgresql/data`). This uses the `appdata` share. Do also create the `postgresql` folder, by running `mkdir /mnt/user/{share_location}/postgresql/data`. If left at default it will try to use Unraid's `/boot/config/plugins/compose.manager/projects/[stack_name]/postgres` folder which it doesn't have permissions to, resulting in this container continuously restarting.
|
||||||
|
|
||||||
|
|||||||
Generated
+970
-561
File diff suppressed because it is too large
Load Diff
+4
-6
@@ -16,9 +16,8 @@
|
|||||||
"write-heading-ids": "docusaurus write-heading-ids"
|
"write-heading-ids": "docusaurus write-heading-ids"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "~3.8.0",
|
"@docusaurus/core": "~3.7.0",
|
||||||
"@docusaurus/preset-classic": "~3.8.0",
|
"@docusaurus/preset-classic": "~3.7.0",
|
||||||
"@docusaurus/theme-common": "~3.8.0",
|
|
||||||
"@mdi/js": "^7.3.67",
|
"@mdi/js": "^7.3.67",
|
||||||
"@mdi/react": "^1.6.1",
|
"@mdi/react": "^1.6.1",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
@@ -27,7 +26,6 @@
|
|||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"docusaurus-lunr-search": "^3.3.2",
|
"docusaurus-lunr-search": "^3.3.2",
|
||||||
"docusaurus-preset-openapi": "^0.7.5",
|
"docusaurus-preset-openapi": "^0.7.5",
|
||||||
"lunr": "^2.3.9",
|
|
||||||
"postcss": "^8.4.25",
|
"postcss": "^8.4.25",
|
||||||
"prism-react-renderer": "^2.3.1",
|
"prism-react-renderer": "^2.3.1",
|
||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
@@ -37,7 +35,7 @@
|
|||||||
"url": "^0.11.0"
|
"url": "^0.11.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "~3.8.0",
|
"@docusaurus/module-type-aliases": "~3.7.0",
|
||||||
"@docusaurus/tsconfig": "^3.7.0",
|
"@docusaurus/tsconfig": "^3.7.0",
|
||||||
"@docusaurus/types": "^3.7.0",
|
"@docusaurus/types": "^3.7.0",
|
||||||
"prettier": "^3.2.4",
|
"prettier": "^3.2.4",
|
||||||
@@ -59,6 +57,6 @@
|
|||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
"volta": {
|
"volta": {
|
||||||
"node": "22.18.0"
|
"node": "22.16.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,12 +58,6 @@ const guides: CommunityGuidesProps[] = [
|
|||||||
description: 'Access Immich with an end-to-end encrypted connection.',
|
description: 'Access Immich with an end-to-end encrypted connection.',
|
||||||
url: 'https://meshnet.nordvpn.com/how-to/remote-files-media-access/immich-remote-access',
|
url: 'https://meshnet.nordvpn.com/how-to/remote-files-media-access/immich-remote-access',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'Trust Self Signed Certificates with Immich - OAuth Setup',
|
|
||||||
description:
|
|
||||||
'Set up Certificate Authority trust with Immich, and your private OAuth2/OpenID service, while using a private CA for HTTPS commication.',
|
|
||||||
url: 'https://github.com/immich-app/immich/discussions/18614',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element {
|
function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element {
|
||||||
|
|||||||
@@ -100,11 +100,6 @@ const projects: CommunityProjectProps[] = [
|
|||||||
description: 'Automatically optimize files uploaded to Immich in order to save storage space',
|
description: 'Automatically optimize files uploaded to Immich in order to save storage space',
|
||||||
url: 'https://github.com/miguelangel-nubla/immich-upload-optimizer',
|
url: 'https://github.com/miguelangel-nubla/immich-upload-optimizer',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'Immich Machine Learning Load Balancer',
|
|
||||||
description: 'Speed up your machine learning by load balancing your requests to multiple computers',
|
|
||||||
url: 'https://github.com/apetersson/immich_ml_balancer',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element {
|
function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element {
|
||||||
|
|||||||
@@ -2,23 +2,4 @@
|
|||||||
|
|
||||||
## TypeORM Upgrade
|
## TypeORM Upgrade
|
||||||
|
|
||||||
In order to update to Immich to `v1.137.0` (or above), the application must be started at least once on a version in the range between `1.132.0` and `1.136.0`. Doing so will complete database schema upgrades that are required for `v1.137.0` (and above). After Immich has successfully updated to a version in this range, you can now attempt to update to v1.137.0 (or above). We recommend users upgrade to `1.132.0` since it does not have any other breaking changes.
|
The upgrade to Immich `v2.x.x` has a required upgrade path to `v1.132.0+`. This means it is required to start up the application at least once on version `1.132.0` (or later). Doing so will complete database schema upgrades that are required for `v2.0.0`. After Immich has successfully booted on this version, shut the system down and try the `v2.x.x` upgrade again.
|
||||||
|
|
||||||
## Inconsistent Media Location
|
|
||||||
|
|
||||||
:::caution
|
|
||||||
This error is related to the location of media files _inside the container_. Never move files on the host system when you run into this error message.
|
|
||||||
:::
|
|
||||||
|
|
||||||
Immich automatically tries to detect where your Immich data is located. On start up, it compares the detected media location with the file paths in the database and throws an Inconsistent Media Location error when they do not match.
|
|
||||||
|
|
||||||
To fix this issue, verify that the `IMMICH_MEDIA_LOCATION` environment variable and `UPLOAD_LOCATION` volume mount are in sync with the database paths.
|
|
||||||
|
|
||||||
If you would like to migrate from one media location to another, simply successfully start Immich on `v1.136.0` or later, then do the following steps:
|
|
||||||
|
|
||||||
1. Stop Immich
|
|
||||||
2. Update `IMMICH_MEDIA_LOCATION` to the new location
|
|
||||||
3. Update the right-hand side of the `UPLOAD_LOCATION` volume mount to the new location
|
|
||||||
4. Start up Immich
|
|
||||||
|
|
||||||
After version `1.136.0`, Immich can detect when a media location has moved and will automatically update the database paths to keep them in sync.
|
|
||||||
|
|||||||
+10
-17
@@ -85,7 +85,6 @@ import React from 'react';
|
|||||||
import { Item, Timeline } from '../components/timeline';
|
import { Item, Timeline } from '../components/timeline';
|
||||||
|
|
||||||
const releases = {
|
const releases = {
|
||||||
'v1.135.0': new Date(2025, 5, 18),
|
|
||||||
'v1.133.0': new Date(2025, 4, 21),
|
'v1.133.0': new Date(2025, 4, 21),
|
||||||
'v1.130.0': new Date(2025, 2, 25),
|
'v1.130.0': new Date(2025, 2, 25),
|
||||||
'v1.127.0': new Date(2025, 1, 26),
|
'v1.127.0': new Date(2025, 1, 26),
|
||||||
@@ -197,6 +196,14 @@ const roadmap: Item[] = [
|
|||||||
description: 'Automate tasks with workflows',
|
description: 'Automate tasks with workflows',
|
||||||
getDateLabel: () => 'Planned for 2025',
|
getDateLabel: () => 'Planned for 2025',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
done: false,
|
||||||
|
icon: mdiTableKey,
|
||||||
|
iconColor: 'gray',
|
||||||
|
title: 'Fine grained access controls',
|
||||||
|
description: 'Granular access controls for users and api keys',
|
||||||
|
getDateLabel: () => 'Planned for 2025',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
done: false,
|
done: false,
|
||||||
icon: mdiImageEdit,
|
icon: mdiImageEdit,
|
||||||
@@ -232,26 +239,12 @@ const roadmap: Item[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const milestones: Item[] = [
|
const milestones: Item[] = [
|
||||||
{
|
|
||||||
icon: mdiStar,
|
|
||||||
iconColor: 'gold',
|
|
||||||
title: '70,000 Stars',
|
|
||||||
description: 'Reached 70K Stars on GitHub!',
|
|
||||||
getDateLabel: withLanguage(new Date(2025, 6, 9)),
|
|
||||||
},
|
|
||||||
withRelease({
|
|
||||||
icon: mdiTableKey,
|
|
||||||
iconColor: 'gray',
|
|
||||||
title: 'Fine grained access controls',
|
|
||||||
description: 'Granular access controls for api keys',
|
|
||||||
release: 'v1.135.0',
|
|
||||||
}),
|
|
||||||
withRelease({
|
withRelease({
|
||||||
icon: mdiCast,
|
icon: mdiCast,
|
||||||
iconColor: 'aqua',
|
iconColor: 'aqua',
|
||||||
title: 'Google Cast (web and mobile)',
|
title: 'Google Cast (web)',
|
||||||
description: 'Cast assets to Google Cast/Chromecast compatible devices',
|
description: 'Cast assets to Google Cast/Chromecast compatible devices',
|
||||||
release: 'v1.135.0',
|
release: 'v1.133.0',
|
||||||
}),
|
}),
|
||||||
withRelease({
|
withRelease({
|
||||||
icon: mdiLockOutline,
|
icon: mdiLockOutline,
|
||||||
|
|||||||
Vendored
+2
-3
@@ -1,5 +1,4 @@
|
|||||||
/docs /docs/overview/welcome 307
|
/docs /docs/overview/introduction 307
|
||||||
/docs/ /docs/overview/welcome 307
|
|
||||||
/docs/mobile-app-beta-program /docs/features/mobile-app 307
|
/docs/mobile-app-beta-program /docs/features/mobile-app 307
|
||||||
/docs/contribution-guidelines /docs/overview/support-the-project#contributing 307
|
/docs/contribution-guidelines /docs/overview/support-the-project#contributing 307
|
||||||
/docs/install /docs/install/docker-compose 307
|
/docs/install /docs/install/docker-compose 307
|
||||||
@@ -31,4 +30,4 @@
|
|||||||
/docs/guides/api-album-sync /docs/community-projects 307
|
/docs/guides/api-album-sync /docs/community-projects 307
|
||||||
/docs/guides/remove-offline-files /docs/community-projects 307
|
/docs/guides/remove-offline-files /docs/community-projects 307
|
||||||
/milestones /roadmap 307
|
/milestones /roadmap 307
|
||||||
/docs/overview/introduction /docs/overview/welcome 307
|
/docs/overview/introduction /docs/overview/welcome 307
|
||||||
Vendored
-36
@@ -1,40 +1,4 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"label": "v1.137.3",
|
|
||||||
"url": "https://v1.137.3.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.137.2",
|
|
||||||
"url": "https://v1.137.2.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.137.1",
|
|
||||||
"url": "https://v1.137.1.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.137.0",
|
|
||||||
"url": "https://v1.137.0.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.136.0",
|
|
||||||
"url": "https://v1.136.0.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.135.3",
|
|
||||||
"url": "https://v1.135.3.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.135.2",
|
|
||||||
"url": "https://v1.135.2.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.135.1",
|
|
||||||
"url": "https://v1.135.1.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.135.0",
|
|
||||||
"url": "https://v1.135.0.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"label": "v1.134.0",
|
"label": "v1.134.0",
|
||||||
"url": "https://v1.134.0.archive.immich.app"
|
"url": "https://v1.134.0.archive.immich.app"
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
22.18.0
|
22.16.0
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ name: immich-e2e
|
|||||||
services:
|
services:
|
||||||
immich-server:
|
immich-server:
|
||||||
container_name: immich-e2e-server
|
container_name: immich-e2e-server
|
||||||
|
command: ['./start.sh']
|
||||||
image: immich-server:latest
|
image: immich-server:latest
|
||||||
build:
|
build:
|
||||||
context: ../
|
context: ../
|
||||||
@@ -35,10 +36,10 @@ services:
|
|||||||
- 2285:2285
|
- 2285:2285
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:6.2-alpine@sha256:7fe72c486b910f6b1a9769c937dad5d63648ddee82e056f47417542dd40825bb
|
image: redis:6.2-alpine@sha256:3211c33a618c457e5d241922c975dbc4f446d0bdb2dc75694f5573ef8e2d01fa
|
||||||
|
|
||||||
database:
|
database:
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:0e763a2383d56f90364fcd72767ac41400cd30d2627f407f7e7960c9f1923c21
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:9c704fb49ce27549df00f1b096cc93f8b0c959ef087507704d74954808f78a82
|
||||||
command: -c fsync=off -c shared_preload_libraries=vchord.so -c config_file=/var/lib/postgresql/data/postgresql.conf
|
command: -c fsync=off -c shared_preload_libraries=vchord.so -c config_file=/var/lib/postgresql/data/postgresql.conf
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
|
|||||||
Generated
+455
-1000
File diff suppressed because it is too large
Load Diff
+5
-7
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.137.3",
|
"version": "1.134.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -24,18 +24,17 @@
|
|||||||
"@immich/cli": "file:../cli",
|
"@immich/cli": "file:../cli",
|
||||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@socket.io/component-emitter": "^3.1.2",
|
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/node": "^22.17.0",
|
"@types/node": "^22.15.29",
|
||||||
"@types/oidc-provider": "^9.0.0",
|
"@types/oidc-provider": "^9.0.0",
|
||||||
"@types/pg": "^8.15.1",
|
"@types/pg": "^8.15.1",
|
||||||
"@types/pngjs": "^6.0.4",
|
"@types/pngjs": "^6.0.4",
|
||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
"@vitest/coverage-v8": "^3.0.0",
|
"@vitest/coverage-v8": "^3.0.0",
|
||||||
"eslint": "^9.14.0",
|
"eslint": "^9.14.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.0.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-unicorn": "^60.0.0",
|
"eslint-plugin-unicorn": "^59.0.0",
|
||||||
"exiftool-vendored": "^28.3.1",
|
"exiftool-vendored": "^28.3.1",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"jose": "^5.6.3",
|
"jose": "^5.6.3",
|
||||||
@@ -45,7 +44,6 @@
|
|||||||
"pngjs": "^7.0.0",
|
"pngjs": "^7.0.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-organize-imports": "^4.0.0",
|
"prettier-plugin-organize-imports": "^4.0.0",
|
||||||
"sharp": "^0.34.0",
|
|
||||||
"socket.io-client": "^4.7.4",
|
"socket.io-client": "^4.7.4",
|
||||||
"supertest": "^7.0.0",
|
"supertest": "^7.0.0",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
@@ -54,6 +52,6 @@
|
|||||||
"vitest": "^3.0.0"
|
"vitest": "^3.0.0"
|
||||||
},
|
},
|
||||||
"volta": {
|
"volta": {
|
||||||
"node": "22.18.0"
|
"node": "22.16.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
ReactionType,
|
ReactionType,
|
||||||
createActivity as create,
|
createActivity as create,
|
||||||
createAlbum,
|
createAlbum,
|
||||||
removeAssetFromAlbum,
|
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { createUserDto, uuidDto } from 'src/fixtures';
|
import { createUserDto, uuidDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
@@ -343,36 +342,5 @@ describe('/activities', () => {
|
|||||||
|
|
||||||
expect(status).toBe(204);
|
expect(status).toBe(204);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty list when asset is removed', async () => {
|
|
||||||
const album3 = await createAlbum(
|
|
||||||
{
|
|
||||||
createAlbumDto: {
|
|
||||||
albumName: 'Album 3',
|
|
||||||
assetIds: [asset.id],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ headers: asBearerAuth(admin.accessToken) },
|
|
||||||
);
|
|
||||||
|
|
||||||
await createActivity({ albumId: album3.id, assetId: asset.id, type: ReactionType.Like });
|
|
||||||
|
|
||||||
await removeAssetFromAlbum(
|
|
||||||
{
|
|
||||||
id: album3.id,
|
|
||||||
bulkIdsDto: {
|
|
||||||
ids: [asset.id],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ headers: asBearerAuth(admin.accessToken) },
|
|
||||||
);
|
|
||||||
|
|
||||||
const { status, body } = await request(app)
|
|
||||||
.get('/activities')
|
|
||||||
.query({ albumId: album.id })
|
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
||||||
expect(status).toEqual(200);
|
|
||||||
expect(body).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -470,7 +470,7 @@ describe('/albums', () => {
|
|||||||
.send({ ids: [asset.id] });
|
.send({ ids: [asset.id] });
|
||||||
|
|
||||||
expect(status).toBe(400);
|
expect(status).toBe(400);
|
||||||
expect(body).toEqual(errorDto.badRequest('Not found or no albumAsset.create access'));
|
expect(body).toEqual(errorDto.badRequest('Not found or no album.addAsset access'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add duplicate assets only once', async () => {
|
it('should add duplicate assets only once', async () => {
|
||||||
@@ -599,7 +599,7 @@ describe('/albums', () => {
|
|||||||
.send({ ids: [user1Asset1.id] });
|
.send({ ids: [user1Asset1.id] });
|
||||||
|
|
||||||
expect(status).toBe(400);
|
expect(status).toBe(400);
|
||||||
expect(body).toEqual(errorDto.badRequest('Not found or no albumAsset.delete access'));
|
expect(body).toEqual(errorDto.badRequest('Not found or no album.removeAsset access'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove duplicate assets only once', async () => {
|
it('should remove duplicate assets only once', async () => {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ describe('/api-keys', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await utils.resetDatabase(['api_key']);
|
await utils.resetDatabase(['api_keys']);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /api-keys', () => {
|
describe('POST /api-keys', () => {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import { DateTime } from 'luxon';
|
|||||||
import { randomBytes } from 'node:crypto';
|
import { randomBytes } from 'node:crypto';
|
||||||
import { readFile, writeFile } from 'node:fs/promises';
|
import { readFile, writeFile } from 'node:fs/promises';
|
||||||
import { basename, join } from 'node:path';
|
import { basename, join } from 'node:path';
|
||||||
import sharp from 'sharp';
|
|
||||||
import { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import { createUserDto, uuidDto } from 'src/fixtures';
|
import { createUserDto, uuidDto } from 'src/fixtures';
|
||||||
import { makeRandomImage } from 'src/generators';
|
import { makeRandomImage } from 'src/generators';
|
||||||
@@ -41,40 +40,6 @@ const today = DateTime.fromObject({
|
|||||||
}) as DateTime<true>;
|
}) as DateTime<true>;
|
||||||
const yesterday = today.minus({ days: 1 });
|
const yesterday = today.minus({ days: 1 });
|
||||||
|
|
||||||
const createTestImageWithExif = async (filename: string, exifData: Record<string, any>) => {
|
|
||||||
// Generate unique color to ensure different checksums for each image
|
|
||||||
const r = Math.floor(Math.random() * 256);
|
|
||||||
const g = Math.floor(Math.random() * 256);
|
|
||||||
const b = Math.floor(Math.random() * 256);
|
|
||||||
|
|
||||||
// Create a 100x100 solid color JPEG using Sharp
|
|
||||||
const imageBytes = await sharp({
|
|
||||||
create: {
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
channels: 3,
|
|
||||||
background: { r, g, b },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.jpeg({ quality: 90 })
|
|
||||||
.toBuffer();
|
|
||||||
|
|
||||||
// Add random suffix to filename to avoid collisions
|
|
||||||
const uniqueFilename = filename.replace('.jpg', `-${randomBytes(4).toString('hex')}.jpg`);
|
|
||||||
const filepath = join(tempDir, uniqueFilename);
|
|
||||||
await writeFile(filepath, imageBytes);
|
|
||||||
|
|
||||||
// Filter out undefined values before writing EXIF
|
|
||||||
const cleanExifData = Object.fromEntries(Object.entries(exifData).filter(([, value]) => value !== undefined));
|
|
||||||
|
|
||||||
await exiftool.write(filepath, cleanExifData);
|
|
||||||
|
|
||||||
// Re-read the image bytes after EXIF has been written
|
|
||||||
const finalImageBytes = await readFile(filepath);
|
|
||||||
|
|
||||||
return { filepath, imageBytes: finalImageBytes, filename: uniqueFilename };
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('/asset', () => {
|
describe('/asset', () => {
|
||||||
let admin: LoginResponseDto;
|
let admin: LoginResponseDto;
|
||||||
let websocket: Socket;
|
let websocket: Socket;
|
||||||
@@ -1225,411 +1190,6 @@ describe('/asset', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('EXIF metadata extraction', () => {
|
|
||||||
describe('Additional date tag extraction', () => {
|
|
||||||
describe('Date-time vs time-only tag handling', () => {
|
|
||||||
it('should fall back to file timestamps when only time-only tags are available', async () => {
|
|
||||||
const { imageBytes, filename } = await createTestImageWithExif('time-only-fallback.jpg', {
|
|
||||||
TimeCreated: '2023:11:15 14:30:00', // Time-only tag, should not be used for dateTimeOriginal
|
|
||||||
// Exclude all date-time tags to force fallback to file timestamps
|
|
||||||
SubSecDateTimeOriginal: undefined,
|
|
||||||
DateTimeOriginal: undefined,
|
|
||||||
SubSecCreateDate: undefined,
|
|
||||||
SubSecMediaCreateDate: undefined,
|
|
||||||
CreateDate: undefined,
|
|
||||||
MediaCreateDate: undefined,
|
|
||||||
CreationDate: undefined,
|
|
||||||
DateTimeCreated: undefined,
|
|
||||||
GPSDateTime: undefined,
|
|
||||||
DateTimeUTC: undefined,
|
|
||||||
SonyDateTime2: undefined,
|
|
||||||
GPSDateStamp: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const oldDate = new Date('2020-01-01T00:00:00.000Z');
|
|
||||||
const asset = await utils.createAsset(admin.accessToken, {
|
|
||||||
assetData: {
|
|
||||||
filename,
|
|
||||||
bytes: imageBytes,
|
|
||||||
},
|
|
||||||
fileCreatedAt: oldDate.toISOString(),
|
|
||||||
fileModifiedAt: oldDate.toISOString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
|
|
||||||
|
|
||||||
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
|
|
||||||
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
|
|
||||||
// Should fall back to file timestamps, which we set to 2020-01-01
|
|
||||||
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
|
|
||||||
new Date('2020-01-01T00:00:00.000Z').getTime(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should prefer DateTimeOriginal over time-only tags', async () => {
|
|
||||||
const { imageBytes, filename } = await createTestImageWithExif('datetime-over-time.jpg', {
|
|
||||||
DateTimeOriginal: '2023:10:10 10:00:00', // Should be preferred
|
|
||||||
TimeCreated: '2023:11:15 14:30:00', // Should be ignored (time-only)
|
|
||||||
});
|
|
||||||
|
|
||||||
const asset = await utils.createAsset(admin.accessToken, {
|
|
||||||
assetData: {
|
|
||||||
filename,
|
|
||||||
bytes: imageBytes,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
|
|
||||||
|
|
||||||
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
|
|
||||||
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
|
|
||||||
// Should use DateTimeOriginal, not TimeCreated
|
|
||||||
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
|
|
||||||
new Date('2023-10-10T10:00:00.000Z').getTime(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('GPSDateTime tag extraction', () => {
|
|
||||||
it('should extract GPSDateTime with GPS coordinates', async () => {
|
|
||||||
const { imageBytes, filename } = await createTestImageWithExif('gps-datetime.jpg', {
|
|
||||||
GPSDateTime: '2023:11:15 12:30:00Z',
|
|
||||||
GPSLatitude: 37.7749,
|
|
||||||
GPSLongitude: -122.4194,
|
|
||||||
// Exclude other date tags
|
|
||||||
SubSecDateTimeOriginal: undefined,
|
|
||||||
DateTimeOriginal: undefined,
|
|
||||||
SubSecCreateDate: undefined,
|
|
||||||
SubSecMediaCreateDate: undefined,
|
|
||||||
CreateDate: undefined,
|
|
||||||
MediaCreateDate: undefined,
|
|
||||||
CreationDate: undefined,
|
|
||||||
DateTimeCreated: undefined,
|
|
||||||
TimeCreated: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const asset = await utils.createAsset(admin.accessToken, {
|
|
||||||
assetData: {
|
|
||||||
filename,
|
|
||||||
bytes: imageBytes,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
|
|
||||||
|
|
||||||
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
|
|
||||||
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
|
|
||||||
expect(assetInfo.exifInfo?.latitude).toBeCloseTo(37.7749, 4);
|
|
||||||
expect(assetInfo.exifInfo?.longitude).toBeCloseTo(-122.4194, 4);
|
|
||||||
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
|
|
||||||
new Date('2023-11-15T12:30:00.000Z').getTime(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('CreateDate tag extraction', () => {
|
|
||||||
it('should extract CreateDate when available', async () => {
|
|
||||||
const { imageBytes, filename } = await createTestImageWithExif('create-date.jpg', {
|
|
||||||
CreateDate: '2023:11:15 10:30:00',
|
|
||||||
// Exclude other higher priority date tags
|
|
||||||
SubSecDateTimeOriginal: undefined,
|
|
||||||
DateTimeOriginal: undefined,
|
|
||||||
SubSecCreateDate: undefined,
|
|
||||||
SubSecMediaCreateDate: undefined,
|
|
||||||
MediaCreateDate: undefined,
|
|
||||||
CreationDate: undefined,
|
|
||||||
DateTimeCreated: undefined,
|
|
||||||
TimeCreated: undefined,
|
|
||||||
GPSDateTime: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const asset = await utils.createAsset(admin.accessToken, {
|
|
||||||
assetData: {
|
|
||||||
filename,
|
|
||||||
bytes: imageBytes,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
|
|
||||||
|
|
||||||
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
|
|
||||||
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
|
|
||||||
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
|
|
||||||
new Date('2023-11-15T10:30:00.000Z').getTime(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('GPSDateStamp tag extraction', () => {
|
|
||||||
it('should fall back to file timestamps when only date-only tags are available', async () => {
|
|
||||||
const { imageBytes, filename } = await createTestImageWithExif('gps-datestamp.jpg', {
|
|
||||||
GPSDateStamp: '2023:11:15', // Date-only tag, should not be used for dateTimeOriginal
|
|
||||||
// Note: NOT including GPSTimeStamp to avoid automatic GPSDateTime creation
|
|
||||||
GPSLatitude: 51.5074,
|
|
||||||
GPSLongitude: -0.1278,
|
|
||||||
// Explicitly exclude all testable date-time tags to force fallback to file timestamps
|
|
||||||
DateTimeOriginal: undefined,
|
|
||||||
CreateDate: undefined,
|
|
||||||
CreationDate: undefined,
|
|
||||||
GPSDateTime: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const oldDate = new Date('2020-01-01T00:00:00.000Z');
|
|
||||||
const asset = await utils.createAsset(admin.accessToken, {
|
|
||||||
assetData: {
|
|
||||||
filename,
|
|
||||||
bytes: imageBytes,
|
|
||||||
},
|
|
||||||
fileCreatedAt: oldDate.toISOString(),
|
|
||||||
fileModifiedAt: oldDate.toISOString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
|
|
||||||
|
|
||||||
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
|
|
||||||
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
|
|
||||||
expect(assetInfo.exifInfo?.latitude).toBeCloseTo(51.5074, 4);
|
|
||||||
expect(assetInfo.exifInfo?.longitude).toBeCloseTo(-0.1278, 4);
|
|
||||||
// Should fall back to file timestamps, which we set to 2020-01-01
|
|
||||||
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
|
|
||||||
new Date('2020-01-01T00:00:00.000Z').getTime(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE: The following EXIF date tags are NOT effectively usable with JPEG test files:
|
|
||||||
*
|
|
||||||
* NOT WRITABLE to JPEG:
|
|
||||||
* - MediaCreateDate: Can be read from video files but not written to JPEG
|
|
||||||
* - DateTimeCreated: Read-only tag in JPEG format
|
|
||||||
* - DateTimeUTC: Cannot be written to JPEG files
|
|
||||||
* - SonyDateTime2: Proprietary Sony tag, not writable to JPEG
|
|
||||||
* - SubSecMediaCreateDate: Tag not defined for JPEG format
|
|
||||||
* - SourceImageCreateTime: Non-standard insta360 tag, not writable to JPEG
|
|
||||||
*
|
|
||||||
* WRITABLE but NOT READABLE from JPEG:
|
|
||||||
* - SubSecDateTimeOriginal: Can be written but not read back from JPEG
|
|
||||||
* - SubSecCreateDate: Can be written but not read back from JPEG
|
|
||||||
*
|
|
||||||
* EFFECTIVELY TESTABLE TAGS (writable and readable):
|
|
||||||
* - DateTimeOriginal â
|
|
||||||
* - CreateDate â
|
|
||||||
* - CreationDate â
|
|
||||||
* - GPSDateTime â
|
|
||||||
*
|
|
||||||
* The metadata service correctly handles non-readable tags and will fall back to
|
|
||||||
* file timestamps when only non-readable tags are present.
|
|
||||||
*/
|
|
||||||
|
|
||||||
describe('Date tag priority order', () => {
|
|
||||||
it('should respect the complete date tag priority order', async () => {
|
|
||||||
// Test cases using only EFFECTIVELY TESTABLE tags (writable AND readable from JPEG)
|
|
||||||
const testCases = [
|
|
||||||
{
|
|
||||||
name: 'DateTimeOriginal has highest priority among testable tags',
|
|
||||||
exifData: {
|
|
||||||
DateTimeOriginal: '2023:04:04 04:00:00', // TESTABLE - highest priority among readable tags
|
|
||||||
CreateDate: '2023:05:05 05:00:00', // TESTABLE
|
|
||||||
CreationDate: '2023:07:07 07:00:00', // TESTABLE
|
|
||||||
GPSDateTime: '2023:10:10 10:00:00', // TESTABLE
|
|
||||||
},
|
|
||||||
expectedDate: '2023-04-04T04:00:00.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'CreateDate when DateTimeOriginal missing',
|
|
||||||
exifData: {
|
|
||||||
CreateDate: '2023:05:05 05:00:00', // TESTABLE
|
|
||||||
CreationDate: '2023:07:07 07:00:00', // TESTABLE
|
|
||||||
GPSDateTime: '2023:10:10 10:00:00', // TESTABLE
|
|
||||||
},
|
|
||||||
expectedDate: '2023-05-05T05:00:00.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'CreationDate when standard EXIF tags missing',
|
|
||||||
exifData: {
|
|
||||||
CreationDate: '2023:07:07 07:00:00', // TESTABLE
|
|
||||||
GPSDateTime: '2023:10:10 10:00:00', // TESTABLE
|
|
||||||
},
|
|
||||||
expectedDate: '2023-07-07T07:00:00.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'GPSDateTime when no other testable date tags present',
|
|
||||||
exifData: {
|
|
||||||
GPSDateTime: '2023:10:10 10:00:00', // TESTABLE
|
|
||||||
Make: 'SONY',
|
|
||||||
},
|
|
||||||
expectedDate: '2023-10-10T10:00:00.000Z',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const testCase of testCases) {
|
|
||||||
const { imageBytes, filename } = await createTestImageWithExif(
|
|
||||||
`${testCase.name.replaceAll(/\s+/g, '-').toLowerCase()}.jpg`,
|
|
||||||
testCase.exifData,
|
|
||||||
);
|
|
||||||
|
|
||||||
const asset = await utils.createAsset(admin.accessToken, {
|
|
||||||
assetData: {
|
|
||||||
filename,
|
|
||||||
bytes: imageBytes,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
|
|
||||||
|
|
||||||
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
|
|
||||||
expect(assetInfo.exifInfo?.dateTimeOriginal, `Failed for: ${testCase.name}`).toBeDefined();
|
|
||||||
expect(
|
|
||||||
new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime(),
|
|
||||||
`Date mismatch for: ${testCase.name}`,
|
|
||||||
).toBe(new Date(testCase.expectedDate).getTime());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Edge cases for date tag handling', () => {
|
|
||||||
it('should fall back to file timestamps with GPSDateStamp alone', async () => {
|
|
||||||
const { imageBytes, filename } = await createTestImageWithExif('gps-datestamp-only.jpg', {
|
|
||||||
GPSDateStamp: '2023:08:08', // Date-only tag, should not be used for dateTimeOriginal
|
|
||||||
// Intentionally no GPSTimeStamp
|
|
||||||
// Exclude all other date tags
|
|
||||||
SubSecDateTimeOriginal: undefined,
|
|
||||||
DateTimeOriginal: undefined,
|
|
||||||
SubSecCreateDate: undefined,
|
|
||||||
SubSecMediaCreateDate: undefined,
|
|
||||||
CreateDate: undefined,
|
|
||||||
MediaCreateDate: undefined,
|
|
||||||
CreationDate: undefined,
|
|
||||||
DateTimeCreated: undefined,
|
|
||||||
TimeCreated: undefined,
|
|
||||||
GPSDateTime: undefined,
|
|
||||||
DateTimeUTC: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const oldDate = new Date('2020-01-01T00:00:00.000Z');
|
|
||||||
const asset = await utils.createAsset(admin.accessToken, {
|
|
||||||
assetData: {
|
|
||||||
filename,
|
|
||||||
bytes: imageBytes,
|
|
||||||
},
|
|
||||||
fileCreatedAt: oldDate.toISOString(),
|
|
||||||
fileModifiedAt: oldDate.toISOString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
|
|
||||||
|
|
||||||
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
|
|
||||||
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
|
|
||||||
// Should fall back to file timestamps, which we set to 2020-01-01
|
|
||||||
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
|
|
||||||
new Date('2020-01-01T00:00:00.000Z').getTime(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle all testable date tags present to verify complete priority order', async () => {
|
|
||||||
const { imageBytes, filename } = await createTestImageWithExif('all-testable-date-tags.jpg', {
|
|
||||||
// All TESTABLE date tags to JPEG format (writable AND readable)
|
|
||||||
DateTimeOriginal: '2023:04:04 04:00:00', // TESTABLE - highest priority among readable tags
|
|
||||||
CreateDate: '2023:05:05 05:00:00', // TESTABLE
|
|
||||||
CreationDate: '2023:07:07 07:00:00', // TESTABLE
|
|
||||||
GPSDateTime: '2023:10:10 10:00:00', // TESTABLE
|
|
||||||
// Note: Excluded non-testable tags:
|
|
||||||
// SubSec tags: writable but not readable from JPEG
|
|
||||||
// Non-writable tags: MediaCreateDate, DateTimeCreated, DateTimeUTC, SonyDateTime2, etc.
|
|
||||||
// Time-only/date-only tags: already excluded from EXIF_DATE_TAGS
|
|
||||||
});
|
|
||||||
|
|
||||||
const asset = await utils.createAsset(admin.accessToken, {
|
|
||||||
assetData: {
|
|
||||||
filename,
|
|
||||||
bytes: imageBytes,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
|
|
||||||
|
|
||||||
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
|
|
||||||
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
|
|
||||||
// Should use DateTimeOriginal as it has the highest priority among testable tags
|
|
||||||
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
|
|
||||||
new Date('2023-04-04T04:00:00.000Z').getTime(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use CreationDate when SubSec tags are missing', async () => {
|
|
||||||
const { imageBytes, filename } = await createTestImageWithExif('creation-date-priority.jpg', {
|
|
||||||
CreationDate: '2023:07:07 07:00:00', // WRITABLE
|
|
||||||
GPSDateTime: '2023:10:10 10:00:00', // WRITABLE
|
|
||||||
// Note: DateTimeCreated, DateTimeUTC, SonyDateTime2 are NOT writable to JPEG
|
|
||||||
// Note: TimeCreated and GPSDateStamp are excluded from EXIF_DATE_TAGS (time-only/date-only)
|
|
||||||
// Exclude SubSec and standard EXIF tags
|
|
||||||
SubSecDateTimeOriginal: undefined,
|
|
||||||
DateTimeOriginal: undefined,
|
|
||||||
SubSecCreateDate: undefined,
|
|
||||||
CreateDate: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const asset = await utils.createAsset(admin.accessToken, {
|
|
||||||
assetData: {
|
|
||||||
filename,
|
|
||||||
bytes: imageBytes,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
|
|
||||||
|
|
||||||
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
|
|
||||||
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
|
|
||||||
// Should use CreationDate when available
|
|
||||||
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
|
|
||||||
new Date('2023-07-07T07:00:00.000Z').getTime(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should skip invalid date formats and use next valid tag', async () => {
|
|
||||||
const { imageBytes, filename } = await createTestImageWithExif('invalid-date-handling.jpg', {
|
|
||||||
// Note: Testing invalid date handling with only WRITABLE tags
|
|
||||||
GPSDateTime: '2023:10:10 10:00:00', // WRITABLE - Valid date
|
|
||||||
CreationDate: '2023:13:13 13:00:00', // WRITABLE - Valid date
|
|
||||||
// Note: TimeCreated excluded (time-only), DateTimeCreated not writable to JPEG
|
|
||||||
// Exclude other date tags
|
|
||||||
SubSecDateTimeOriginal: undefined,
|
|
||||||
DateTimeOriginal: undefined,
|
|
||||||
SubSecCreateDate: undefined,
|
|
||||||
CreateDate: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const asset = await utils.createAsset(admin.accessToken, {
|
|
||||||
assetData: {
|
|
||||||
filename,
|
|
||||||
bytes: imageBytes,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
|
|
||||||
|
|
||||||
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
|
|
||||||
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
|
|
||||||
// Should skip invalid dates and use the first valid one (GPSDateTime)
|
|
||||||
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
|
|
||||||
new Date('2023-10-10T10:00:00.000Z').getTime(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('POST /assets/exist', () => {
|
describe('POST /assets/exist', () => {
|
||||||
it('ignores invalid deviceAssetIds', async () => {
|
it('ignores invalid deviceAssetIds', async () => {
|
||||||
const response = await utils.checkExistingAssets(user1.accessToken, {
|
const response = await utils.checkExistingAssets(user1.accessToken, {
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
import { LoginResponseDto, login, signUpAdmin } from '@immich/sdk';
|
||||||
|
import { loginDto, signupDto } from 'src/fixtures';
|
||||||
|
import { errorDto, loginResponseDto, signupResponseDto } from 'src/responses';
|
||||||
|
import { app, utils } from 'src/utils';
|
||||||
|
import request from 'supertest';
|
||||||
|
import { beforeEach, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
const { email, password } = signupDto.admin;
|
||||||
|
|
||||||
|
describe(`/auth/admin-sign-up`, () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await utils.resetDatabase();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST /auth/admin-sign-up', () => {
|
||||||
|
it(`should sign up the admin`, async () => {
|
||||||
|
const { status, body } = await request(app).post('/auth/admin-sign-up').send(signupDto.admin);
|
||||||
|
expect(status).toBe(201);
|
||||||
|
expect(body).toEqual(signupResponseDto.admin);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow a second admin to sign up', async () => {
|
||||||
|
await signUpAdmin({ signUpDto: signupDto.admin });
|
||||||
|
|
||||||
|
const { status, body } = await request(app).post('/auth/admin-sign-up').send(signupDto.admin);
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.alreadyHasAdmin);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('/auth/*', () => {
|
||||||
|
let admin: LoginResponseDto;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await utils.resetDatabase();
|
||||||
|
await signUpAdmin({ signUpDto: signupDto.admin });
|
||||||
|
admin = await login({ loginCredentialDto: loginDto.admin });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`POST /auth/login`, () => {
|
||||||
|
it('should reject an incorrect password', async () => {
|
||||||
|
const { status, body } = await request(app).post('/auth/login').send({ email, password: 'incorrect' });
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.incorrectLogin);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should accept a correct password', async () => {
|
||||||
|
const { status, body, headers } = await request(app).post('/auth/login').send({ email, password });
|
||||||
|
expect(status).toBe(201);
|
||||||
|
expect(body).toEqual(loginResponseDto.admin);
|
||||||
|
|
||||||
|
const token = body.accessToken;
|
||||||
|
expect(token).toBeDefined();
|
||||||
|
|
||||||
|
const cookies = headers['set-cookie'];
|
||||||
|
expect(cookies).toHaveLength(3);
|
||||||
|
expect(cookies[0].split(';').map((item) => item.trim())).toEqual([
|
||||||
|
`immich_access_token=${token}`,
|
||||||
|
'Max-Age=34560000',
|
||||||
|
'Path=/',
|
||||||
|
expect.stringContaining('Expires='),
|
||||||
|
'HttpOnly',
|
||||||
|
'SameSite=Lax',
|
||||||
|
]);
|
||||||
|
expect(cookies[1].split(';').map((item) => item.trim())).toEqual([
|
||||||
|
'immich_auth_type=password',
|
||||||
|
'Max-Age=34560000',
|
||||||
|
'Path=/',
|
||||||
|
expect.stringContaining('Expires='),
|
||||||
|
'HttpOnly',
|
||||||
|
'SameSite=Lax',
|
||||||
|
]);
|
||||||
|
expect(cookies[2].split(';').map((item) => item.trim())).toEqual([
|
||||||
|
'immich_is_authenticated=true',
|
||||||
|
'Max-Age=34560000',
|
||||||
|
'Path=/',
|
||||||
|
expect.stringContaining('Expires='),
|
||||||
|
'SameSite=Lax',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST /auth/validateToken', () => {
|
||||||
|
it('should reject an invalid token', async () => {
|
||||||
|
const { status, body } = await request(app).post(`/auth/validateToken`).set('Authorization', 'Bearer 123');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.invalidToken);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should accept a valid token', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post(`/auth/validateToken`)
|
||||||
|
.send({})
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({ authStatus: true });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST /auth/change-password', () => {
|
||||||
|
it('should require the current password', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post(`/auth/change-password`)
|
||||||
|
.send({ password: 'wrong-password', newPassword: 'Password1234' })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.wrongPassword);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change the password', async () => {
|
||||||
|
const { status } = await request(app)
|
||||||
|
.post(`/auth/change-password`)
|
||||||
|
.send({ password, newPassword: 'Password1234' })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
|
||||||
|
await login({
|
||||||
|
loginCredentialDto: {
|
||||||
|
email: 'admin@immich.cloud',
|
||||||
|
password: 'Password1234',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST /auth/logout', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).post(`/auth/logout`);
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should logout the user', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post(`/auth/logout`)
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
successful: true,
|
||||||
|
redirectUri: '/auth/login?autoLaunch=0',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
createMemory,
|
createMemory,
|
||||||
getMemory,
|
getMemory,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { createUserDto } from 'src/fixtures';
|
import { createUserDto, uuidDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { app, asBearerAuth, utils } from 'src/utils';
|
import { app, asBearerAuth, utils } from 'src/utils';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
@@ -17,6 +17,7 @@ describe('/memories', () => {
|
|||||||
let user: LoginResponseDto;
|
let user: LoginResponseDto;
|
||||||
let adminAsset: AssetMediaResponseDto;
|
let adminAsset: AssetMediaResponseDto;
|
||||||
let userAsset1: AssetMediaResponseDto;
|
let userAsset1: AssetMediaResponseDto;
|
||||||
|
let userAsset2: AssetMediaResponseDto;
|
||||||
let userMemory: MemoryResponseDto;
|
let userMemory: MemoryResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
@@ -24,9 +25,10 @@ describe('/memories', () => {
|
|||||||
|
|
||||||
admin = await utils.adminSetup();
|
admin = await utils.adminSetup();
|
||||||
user = await utils.userSetup(admin.accessToken, createUserDto.user1);
|
user = await utils.userSetup(admin.accessToken, createUserDto.user1);
|
||||||
[adminAsset, userAsset1] = await Promise.all([
|
[adminAsset, userAsset1, userAsset2] = await Promise.all([
|
||||||
utils.createAsset(admin.accessToken),
|
utils.createAsset(admin.accessToken),
|
||||||
utils.createAsset(user.accessToken),
|
utils.createAsset(user.accessToken),
|
||||||
|
utils.createAsset(user.accessToken),
|
||||||
]);
|
]);
|
||||||
userMemory = await createMemory(
|
userMemory = await createMemory(
|
||||||
{
|
{
|
||||||
@@ -41,7 +43,121 @@ describe('/memories', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('GET /memories', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/memories');
|
||||||
|
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST /memories', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).post('/memories');
|
||||||
|
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should validate data when type is on this day', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post('/memories')
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`)
|
||||||
|
.send({
|
||||||
|
type: 'on_this_day',
|
||||||
|
data: {},
|
||||||
|
memoryAt: new Date(2021).toISOString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(
|
||||||
|
errorDto.badRequest(['data.year must be a positive number', 'data.year must be an integer number']),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a new memory', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post('/memories')
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`)
|
||||||
|
.send({
|
||||||
|
type: 'on_this_day',
|
||||||
|
data: { year: 2021 },
|
||||||
|
memoryAt: new Date(2021).toISOString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(201);
|
||||||
|
expect(body).toEqual({
|
||||||
|
id: expect.any(String),
|
||||||
|
type: 'on_this_day',
|
||||||
|
data: { year: 2021 },
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
updatedAt: expect.any(String),
|
||||||
|
isSaved: false,
|
||||||
|
memoryAt: expect.any(String),
|
||||||
|
ownerId: user.userId,
|
||||||
|
assets: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a new memory (with assets)', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post('/memories')
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`)
|
||||||
|
.send({
|
||||||
|
type: 'on_this_day',
|
||||||
|
data: { year: 2021 },
|
||||||
|
memoryAt: new Date(2021).toISOString(),
|
||||||
|
assetIds: [userAsset1.id, userAsset2.id],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(201);
|
||||||
|
expect(body).toMatchObject({
|
||||||
|
id: expect.any(String),
|
||||||
|
assets: expect.arrayContaining([
|
||||||
|
expect.objectContaining({ id: userAsset1.id }),
|
||||||
|
expect.objectContaining({ id: userAsset2.id }),
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
expect(body.assets).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a new memory and ignore assets the user does not have access to', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post('/memories')
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`)
|
||||||
|
.send({
|
||||||
|
type: 'on_this_day',
|
||||||
|
data: { year: 2021 },
|
||||||
|
memoryAt: new Date(2021).toISOString(),
|
||||||
|
assetIds: [userAsset1.id, adminAsset.id],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(201);
|
||||||
|
expect(body).toMatchObject({
|
||||||
|
id: expect.any(String),
|
||||||
|
assets: [expect.objectContaining({ id: userAsset1.id })],
|
||||||
|
});
|
||||||
|
expect(body.assets).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('GET /memories/:id', () => {
|
describe('GET /memories/:id', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get(`/memories/${uuidDto.invalid}`);
|
||||||
|
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should require a valid id', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get(`/memories/${uuidDto.invalid}`)
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`);
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
|
||||||
|
});
|
||||||
|
|
||||||
it('should require access', async () => {
|
it('should require access', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.get(`/memories/${userMemory.id}`)
|
.get(`/memories/${userMemory.id}`)
|
||||||
@@ -60,6 +176,22 @@ describe('/memories', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('PUT /memories/:id', () => {
|
describe('PUT /memories/:id', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).put(`/memories/${uuidDto.invalid}`).send({ isSaved: true });
|
||||||
|
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should require a valid id', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/memories/${uuidDto.invalid}`)
|
||||||
|
.send({ isSaved: true })
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`);
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
|
||||||
|
});
|
||||||
|
|
||||||
it('should require access', async () => {
|
it('should require access', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.put(`/memories/${userMemory.id}`)
|
.put(`/memories/${userMemory.id}`)
|
||||||
@@ -86,6 +218,23 @@ describe('/memories', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('PUT /memories/:id/assets', () => {
|
describe('PUT /memories/:id/assets', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/memories/${userMemory.id}/assets`)
|
||||||
|
.send({ ids: [userAsset1.id] });
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should require a valid id', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/memories/${uuidDto.invalid}/assets`)
|
||||||
|
.send({ ids: [userAsset1.id] })
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`);
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
|
||||||
|
});
|
||||||
|
|
||||||
it('should require access', async () => {
|
it('should require access', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.put(`/memories/${userMemory.id}/assets`)
|
.put(`/memories/${userMemory.id}/assets`)
|
||||||
@@ -95,6 +244,15 @@ describe('/memories', () => {
|
|||||||
expect(body).toEqual(errorDto.noPermission);
|
expect(body).toEqual(errorDto.noPermission);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should require a valid asset id', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/memories/${userMemory.id}/assets`)
|
||||||
|
.send({ ids: [uuidDto.invalid] })
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`);
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(['each value in ids must be a UUID']));
|
||||||
|
});
|
||||||
|
|
||||||
it('should require asset access', async () => {
|
it('should require asset access', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.put(`/memories/${userMemory.id}/assets`)
|
.put(`/memories/${userMemory.id}/assets`)
|
||||||
@@ -121,6 +279,23 @@ describe('/memories', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('DELETE /memories/:id/assets', () => {
|
describe('DELETE /memories/:id/assets', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.delete(`/memories/${userMemory.id}/assets`)
|
||||||
|
.send({ ids: [userAsset1.id] });
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should require a valid id', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.delete(`/memories/${uuidDto.invalid}/assets`)
|
||||||
|
.send({ ids: [userAsset1.id] })
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`);
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
|
||||||
|
});
|
||||||
|
|
||||||
it('should require access', async () => {
|
it('should require access', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.delete(`/memories/${userMemory.id}/assets`)
|
.delete(`/memories/${userMemory.id}/assets`)
|
||||||
@@ -130,6 +305,15 @@ describe('/memories', () => {
|
|||||||
expect(body).toEqual(errorDto.noPermission);
|
expect(body).toEqual(errorDto.noPermission);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should require a valid asset id', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.delete(`/memories/${userMemory.id}/assets`)
|
||||||
|
.send({ ids: [uuidDto.invalid] })
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`);
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(['each value in ids must be a UUID']));
|
||||||
|
});
|
||||||
|
|
||||||
it('should only remove assets in the memory', async () => {
|
it('should only remove assets in the memory', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.delete(`/memories/${userMemory.id}/assets`)
|
.delete(`/memories/${userMemory.id}/assets`)
|
||||||
@@ -156,6 +340,21 @@ describe('/memories', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('DELETE /memories/:id', () => {
|
describe('DELETE /memories/:id', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).delete(`/memories/${uuidDto.invalid}`);
|
||||||
|
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should require a valid id', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.delete(`/memories/${uuidDto.invalid}`)
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`);
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
|
||||||
|
});
|
||||||
|
|
||||||
it('should require access', async () => {
|
it('should require access', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.delete(`/memories/${userMemory.id}`)
|
.delete(`/memories/${userMemory.id}`)
|
||||||
|
|||||||
@@ -227,21 +227,6 @@ describe(`/oauth`, () => {
|
|||||||
expect(user.storageLabel).toBe('user-username');
|
expect(user.storageLabel).toBe('user-username');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the admin status from a role claim', async () => {
|
|
||||||
const callbackParams = await loginWithOAuth(OAuthUser.WITH_ROLE);
|
|
||||||
const { status, body } = await request(app).post('/oauth/callback').send(callbackParams);
|
|
||||||
expect(status).toBe(201);
|
|
||||||
expect(body).toMatchObject({
|
|
||||||
accessToken: expect.any(String),
|
|
||||||
userId: expect.any(String),
|
|
||||||
userEmail: 'oauth-with-role@immich.app',
|
|
||||||
isAdmin: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const user = await getMyUser({ headers: asBearerAuth(body.accessToken) });
|
|
||||||
expect(user.isAdmin).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work with RS256 signed tokens', async () => {
|
it('should work with RS256 signed tokens', async () => {
|
||||||
await setupOAuth(admin.accessToken, {
|
await setupOAuth(admin.accessToken, {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|||||||
@@ -14,11 +14,7 @@ describe('/people', () => {
|
|||||||
let nameAlicePerson: PersonResponseDto;
|
let nameAlicePerson: PersonResponseDto;
|
||||||
let nameBobPerson: PersonResponseDto;
|
let nameBobPerson: PersonResponseDto;
|
||||||
let nameCharliePerson: PersonResponseDto;
|
let nameCharliePerson: PersonResponseDto;
|
||||||
let nameNullPerson4Assets: PersonResponseDto;
|
let nameNullPerson: PersonResponseDto;
|
||||||
let nameNullPerson3Assets: PersonResponseDto;
|
|
||||||
let nameNullPerson1Asset: PersonResponseDto;
|
|
||||||
let nameBillPersonFavourite: PersonResponseDto;
|
|
||||||
let nameFreddyPersonFavourite: PersonResponseDto;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await utils.resetDatabase();
|
await utils.resetDatabase();
|
||||||
@@ -31,11 +27,7 @@ describe('/people', () => {
|
|||||||
nameCharliePerson,
|
nameCharliePerson,
|
||||||
nameBobPerson,
|
nameBobPerson,
|
||||||
nameAlicePerson,
|
nameAlicePerson,
|
||||||
nameNullPerson4Assets,
|
nameNullPerson,
|
||||||
nameNullPerson3Assets,
|
|
||||||
nameNullPerson1Asset,
|
|
||||||
nameBillPersonFavourite,
|
|
||||||
nameFreddyPersonFavourite,
|
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
utils.createPerson(admin.accessToken, {
|
utils.createPerson(admin.accessToken, {
|
||||||
name: 'visible_person',
|
name: 'visible_person',
|
||||||
@@ -60,26 +52,11 @@ describe('/people', () => {
|
|||||||
utils.createPerson(admin.accessToken, {
|
utils.createPerson(admin.accessToken, {
|
||||||
name: '',
|
name: '',
|
||||||
}),
|
}),
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: '',
|
|
||||||
}),
|
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: '',
|
|
||||||
}),
|
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: 'Bill',
|
|
||||||
isFavorite: true,
|
|
||||||
}),
|
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: 'Freddy',
|
|
||||||
isFavorite: true,
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const asset1 = await utils.createAsset(admin.accessToken);
|
const asset1 = await utils.createAsset(admin.accessToken);
|
||||||
const asset2 = await utils.createAsset(admin.accessToken);
|
const asset2 = await utils.createAsset(admin.accessToken);
|
||||||
const asset3 = await utils.createAsset(admin.accessToken);
|
const asset3 = await utils.createAsset(admin.accessToken);
|
||||||
const asset4 = await utils.createAsset(admin.accessToken);
|
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
utils.createFace({ assetId: asset1.id, personId: visiblePerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: visiblePerson.id }),
|
||||||
@@ -87,27 +64,15 @@ describe('/people', () => {
|
|||||||
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
||||||
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
||||||
utils.createFace({ assetId: asset2.id, personId: multipleAssetsPerson.id }),
|
utils.createFace({ assetId: asset2.id, personId: multipleAssetsPerson.id }),
|
||||||
utils.createFace({ assetId: asset3.id, personId: multipleAssetsPerson.id }), // 4 assets
|
utils.createFace({ assetId: asset3.id, personId: multipleAssetsPerson.id }),
|
||||||
// Named persons
|
// Named persons
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameCharliePerson.id }), // 1 asset
|
utils.createFace({ assetId: asset1.id, personId: nameCharliePerson.id }), // 1 asset
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameBobPerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: nameBobPerson.id }),
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameBobPerson.id }), // 2 assets
|
utils.createFace({ assetId: asset2.id, personId: nameBobPerson.id }), // 2 assets
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameAlicePerson.id }), // 1 asset
|
utils.createFace({ assetId: asset1.id, personId: nameAlicePerson.id }), // 1 asset
|
||||||
// Null-named person 4 assets
|
// Null-named person
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameNullPerson4Assets.id }),
|
utils.createFace({ assetId: asset1.id, personId: nameNullPerson.id }),
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameNullPerson4Assets.id }),
|
utils.createFace({ assetId: asset2.id, personId: nameNullPerson.id }), // 2 assets
|
||||||
utils.createFace({ assetId: asset3.id, personId: nameNullPerson4Assets.id }),
|
|
||||||
utils.createFace({ assetId: asset4.id, personId: nameNullPerson4Assets.id }), // 4 assets
|
|
||||||
// Null-named person 3 assets
|
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameNullPerson3Assets.id }),
|
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameNullPerson3Assets.id }),
|
|
||||||
utils.createFace({ assetId: asset3.id, personId: nameNullPerson3Assets.id }), // 3 assets
|
|
||||||
// Null-named person 1 asset
|
|
||||||
utils.createFace({ assetId: asset3.id, personId: nameNullPerson1Asset.id }),
|
|
||||||
// Favourite People
|
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameFreddyPersonFavourite.id }),
|
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameFreddyPersonFavourite.id }),
|
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameBillPersonFavourite.id }),
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,19 +87,15 @@ describe('/people', () => {
|
|||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
total: 11,
|
total: 7,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [
|
people: [
|
||||||
expect.objectContaining({ name: 'Freddy' }),
|
|
||||||
expect.objectContaining({ name: 'Bill' }),
|
|
||||||
expect.objectContaining({ name: 'multiple_assets_person' }),
|
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||||
expect.objectContaining({ name: 'Bob' }),
|
expect.objectContaining({ name: 'Bob' }),
|
||||||
expect.objectContaining({ name: 'Alice' }),
|
expect.objectContaining({ name: 'Alice' }),
|
||||||
expect.objectContaining({ name: 'Charlie' }),
|
expect.objectContaining({ name: 'Charlie' }),
|
||||||
expect.objectContaining({ name: 'visible_person' }),
|
expect.objectContaining({ name: 'visible_person' }),
|
||||||
expect.objectContaining({ id: nameNullPerson4Assets.id, name: '' }),
|
expect.objectContaining({ name: 'hidden_person' }),
|
||||||
expect.objectContaining({ id: nameNullPerson3Assets.id, name: '' }),
|
|
||||||
expect.objectContaining({ name: 'hidden_person' }), // Should really be before the null names
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -144,21 +105,17 @@ describe('/people', () => {
|
|||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body.hasNextPage).toBe(false);
|
expect(body.hasNextPage).toBe(false);
|
||||||
expect(body.total).toBe(11); // All persons
|
expect(body.total).toBe(7); // All persons
|
||||||
expect(body.hidden).toBe(1); // 'hidden_person'
|
expect(body.hidden).toBe(1); // 'hidden_person'
|
||||||
|
|
||||||
const people = body.people as PersonResponseDto[];
|
const people = body.people as PersonResponseDto[];
|
||||||
|
|
||||||
expect(people.map((p) => p.id)).toEqual([
|
expect(people.map((p) => p.id)).toEqual([
|
||||||
nameFreddyPersonFavourite.id, // name: 'Freddy', count: 2
|
|
||||||
nameBillPersonFavourite.id, // name: 'Bill', count: 1
|
|
||||||
multipleAssetsPerson.id, // name: 'multiple_assets_person', count: 3
|
multipleAssetsPerson.id, // name: 'multiple_assets_person', count: 3
|
||||||
nameBobPerson.id, // name: 'Bob', count: 2
|
nameBobPerson.id, // name: 'Bob', count: 2
|
||||||
nameAlicePerson.id, // name: 'Alice', count: 1
|
nameAlicePerson.id, // name: 'Alice', count: 1
|
||||||
nameCharliePerson.id, // name: 'Charlie', count: 1
|
nameCharliePerson.id, // name: 'Charlie', count: 1
|
||||||
visiblePerson.id, // name: 'visible_person', count: 1
|
visiblePerson.id, // name: 'visible_person', count: 1
|
||||||
nameNullPerson4Assets.id, // name: '', count: 4
|
|
||||||
nameNullPerson3Assets.id, // name: '', count: 3
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(people.some((p) => p.id === hiddenPerson.id)).toBe(false);
|
expect(people.some((p) => p.id === hiddenPerson.id)).toBe(false);
|
||||||
@@ -170,18 +127,14 @@ describe('/people', () => {
|
|||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
total: 11,
|
total: 7,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [
|
people: [
|
||||||
expect.objectContaining({ name: 'Freddy' }),
|
|
||||||
expect.objectContaining({ name: 'Bill' }),
|
|
||||||
expect.objectContaining({ name: 'multiple_assets_person' }),
|
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||||
expect.objectContaining({ name: 'Bob' }),
|
expect.objectContaining({ name: 'Bob' }),
|
||||||
expect.objectContaining({ name: 'Alice' }),
|
expect.objectContaining({ name: 'Alice' }),
|
||||||
expect.objectContaining({ name: 'Charlie' }),
|
expect.objectContaining({ name: 'Charlie' }),
|
||||||
expect.objectContaining({ name: 'visible_person' }),
|
expect.objectContaining({ name: 'visible_person' }),
|
||||||
expect.objectContaining({ id: nameNullPerson4Assets.id, name: '' }),
|
|
||||||
expect.objectContaining({ id: nameNullPerson3Assets.id, name: '' }),
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -195,9 +148,9 @@ describe('/people', () => {
|
|||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
hasNextPage: true,
|
hasNextPage: true,
|
||||||
total: 11,
|
total: 7,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [expect.objectContaining({ name: 'Alice' })],
|
people: [expect.objectContaining({ name: 'visible_person' })],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { createUserDto, uuidDto } from 'src/fixtures';
|
import { createUserDto, uuidDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { app, asBearerAuth, baseUrl, shareUrl, utils } from 'src/utils';
|
import { app, asBearerAuth, shareUrl, utils } from 'src/utils';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import { beforeAll, describe, expect, it } from 'vitest';
|
import { beforeAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
@@ -78,7 +78,6 @@ describe('/shared-links', () => {
|
|||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
albumId: metadataAlbum.id,
|
albumId: metadataAlbum.id,
|
||||||
showMetadata: true,
|
showMetadata: true,
|
||||||
slug: 'metadata-album',
|
|
||||||
}),
|
}),
|
||||||
utils.createSharedLink(user1.accessToken, {
|
utils.createSharedLink(user1.accessToken, {
|
||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
@@ -118,36 +117,8 @@ describe('/shared-links', () => {
|
|||||||
const resp = await request(shareUrl).get(`/${linkWithAssets.key}`);
|
const resp = await request(shareUrl).get(`/${linkWithAssets.key}`);
|
||||||
expect(resp.status).toBe(200);
|
expect(resp.status).toBe(200);
|
||||||
expect(resp.header['content-type']).toContain('text/html');
|
expect(resp.header['content-type']).toContain('text/html');
|
||||||
expect(resp.text).toContain(`<meta property="og:image" content="http://127.0.0.1:2285`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fall back to my.immich.app og:image meta tag for shared asset if Host header is not present', async () => {
|
|
||||||
const resp = await request(shareUrl).get(`/${linkWithAssets.key}`).set('Host', '');
|
|
||||||
expect(resp.status).toBe(200);
|
|
||||||
expect(resp.header['content-type']).toContain('text/html');
|
|
||||||
expect(resp.text).toContain(`<meta property="og:image" content="https://my.immich.app`);
|
expect(resp.text).toContain(`<meta property="og:image" content="https://my.immich.app`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return 404 for an invalid shared link', async () => {
|
|
||||||
const resp = await request(shareUrl).get(`/invalid-key`);
|
|
||||||
expect(resp.status).toBe(404);
|
|
||||||
expect(resp.header['content-type']).toContain('text/html');
|
|
||||||
expect(resp.text).not.toContain(`og:type`);
|
|
||||||
expect(resp.text).not.toContain(`og:title`);
|
|
||||||
expect(resp.text).not.toContain(`og:description`);
|
|
||||||
expect(resp.text).not.toContain(`og:image`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('GET /s/:slug', () => {
|
|
||||||
it('should work for slug auth', async () => {
|
|
||||||
const resp = await request(baseUrl).get(`/s/${linkWithMetadata.slug}`);
|
|
||||||
expect(resp.status).toBe(200);
|
|
||||||
expect(resp.header['content-type']).toContain('text/html');
|
|
||||||
expect(resp.text).toContain(
|
|
||||||
`<meta name="description" content="${metadataAlbum.assets.length} shared photos & videos" />`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /shared-links', () => {
|
describe('GET /shared-links', () => {
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ describe('/system-config', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('PUT /system-config', () => {
|
describe('PUT /system-config', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).put('/system-config');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
it('should always return the new config', async () => {
|
it('should always return the new config', async () => {
|
||||||
const config = await getSystemConfig(admin.accessToken);
|
const config = await getSystemConfig(admin.accessToken);
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ describe('/tags', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
// tagging assets eventually triggers metadata extraction which can impact other tests
|
// tagging assets eventually triggers metadata extraction which can impact other tests
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
||||||
await utils.resetDatabase(['tag']);
|
await utils.resetDatabase(['tags']);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /tags', () => {
|
describe('POST /tags', () => {
|
||||||
|
|||||||
@@ -0,0 +1,230 @@
|
|||||||
|
import {
|
||||||
|
AssetMediaResponseDto,
|
||||||
|
AssetVisibility,
|
||||||
|
LoginResponseDto,
|
||||||
|
SharedLinkType,
|
||||||
|
TimeBucketAssetResponseDto,
|
||||||
|
} from '@immich/sdk';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
import { createUserDto } from 'src/fixtures';
|
||||||
|
import { errorDto } from 'src/responses';
|
||||||
|
import { app, utils } from 'src/utils';
|
||||||
|
import request from 'supertest';
|
||||||
|
import { beforeAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
// TODO this should probably be a test util function
|
||||||
|
const today = DateTime.fromObject({
|
||||||
|
year: 2023,
|
||||||
|
month: 11,
|
||||||
|
day: 3,
|
||||||
|
}) as DateTime<true>;
|
||||||
|
const yesterday = today.minus({ days: 1 });
|
||||||
|
|
||||||
|
describe('/timeline', () => {
|
||||||
|
let admin: LoginResponseDto;
|
||||||
|
let user: LoginResponseDto;
|
||||||
|
let timeBucketUser: LoginResponseDto;
|
||||||
|
|
||||||
|
let user1Assets: AssetMediaResponseDto[];
|
||||||
|
let user2Assets: AssetMediaResponseDto[];
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await utils.resetDatabase();
|
||||||
|
admin = await utils.adminSetup({ onboarding: false });
|
||||||
|
[user, timeBucketUser] = await Promise.all([
|
||||||
|
utils.userSetup(admin.accessToken, createUserDto.create('1')),
|
||||||
|
utils.userSetup(admin.accessToken, createUserDto.create('time-bucket')),
|
||||||
|
]);
|
||||||
|
|
||||||
|
user1Assets = await Promise.all([
|
||||||
|
utils.createAsset(user.accessToken),
|
||||||
|
utils.createAsset(user.accessToken),
|
||||||
|
utils.createAsset(user.accessToken, {
|
||||||
|
isFavorite: true,
|
||||||
|
fileCreatedAt: yesterday.toISO(),
|
||||||
|
fileModifiedAt: yesterday.toISO(),
|
||||||
|
assetData: { filename: 'example.mp4' },
|
||||||
|
}),
|
||||||
|
utils.createAsset(user.accessToken),
|
||||||
|
utils.createAsset(user.accessToken),
|
||||||
|
]);
|
||||||
|
|
||||||
|
user2Assets = await Promise.all([
|
||||||
|
utils.createAsset(timeBucketUser.accessToken, { fileCreatedAt: new Date('1970-01-01').toISOString() }),
|
||||||
|
utils.createAsset(timeBucketUser.accessToken, { fileCreatedAt: new Date('1970-02-10').toISOString() }),
|
||||||
|
utils.createAsset(timeBucketUser.accessToken, { fileCreatedAt: new Date('1970-02-11').toISOString() }),
|
||||||
|
utils.createAsset(timeBucketUser.accessToken, { fileCreatedAt: new Date('1970-02-11').toISOString() }),
|
||||||
|
utils.createAsset(timeBucketUser.accessToken, { fileCreatedAt: new Date('1970-02-12').toISOString() }),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await utils.deleteAssets(timeBucketUser.accessToken, [user2Assets[4].id]);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /timeline/buckets', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/timeline/buckets');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get time buckets by month', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/timeline/buckets')
|
||||||
|
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
{ count: 3, timeBucket: '1970-02-01' },
|
||||||
|
{ count: 1, timeBucket: '1970-01-01' },
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow access for unrelated shared links', async () => {
|
||||||
|
const sharedLink = await utils.createSharedLink(user.accessToken, {
|
||||||
|
type: SharedLinkType.Individual,
|
||||||
|
assetIds: user1Assets.map(({ id }) => id),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { status, body } = await request(app).get('/timeline/buckets').query({ key: sharedLink.key });
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.noPermission);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return error if time bucket is requested with partners asset and archived', async () => {
|
||||||
|
const req1 = await request(app)
|
||||||
|
.get('/timeline/buckets')
|
||||||
|
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
|
||||||
|
.query({ withPartners: true, visibility: AssetVisibility.Archive });
|
||||||
|
|
||||||
|
expect(req1.status).toBe(400);
|
||||||
|
expect(req1.body).toEqual(errorDto.badRequest());
|
||||||
|
|
||||||
|
const req2 = await request(app)
|
||||||
|
.get('/timeline/buckets')
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`)
|
||||||
|
.query({ withPartners: true, visibility: undefined });
|
||||||
|
|
||||||
|
expect(req2.status).toBe(400);
|
||||||
|
expect(req2.body).toEqual(errorDto.badRequest());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return error if time bucket is requested with partners asset and favorite', async () => {
|
||||||
|
const req1 = await request(app)
|
||||||
|
.get('/timeline/buckets')
|
||||||
|
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
|
||||||
|
.query({ withPartners: true, isFavorite: true });
|
||||||
|
|
||||||
|
expect(req1.status).toBe(400);
|
||||||
|
expect(req1.body).toEqual(errorDto.badRequest());
|
||||||
|
|
||||||
|
const req2 = await request(app)
|
||||||
|
.get('/timeline/buckets')
|
||||||
|
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
|
||||||
|
.query({ withPartners: true, isFavorite: false });
|
||||||
|
|
||||||
|
expect(req2.status).toBe(400);
|
||||||
|
expect(req2.body).toEqual(errorDto.badRequest());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return error if time bucket is requested with partners asset and trash', async () => {
|
||||||
|
const req = await request(app)
|
||||||
|
.get('/timeline/buckets')
|
||||||
|
.set('Authorization', `Bearer ${user.accessToken}`)
|
||||||
|
.query({ withPartners: true, isTrashed: true });
|
||||||
|
|
||||||
|
expect(req.status).toBe(400);
|
||||||
|
expect(req.body).toEqual(errorDto.badRequest());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /timeline/bucket', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/timeline/bucket').query({
|
||||||
|
timeBucket: '1900-01-01',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle 5 digit years', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/timeline/bucket')
|
||||||
|
.query({ timeBucket: '012345-01-01' })
|
||||||
|
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
city: [],
|
||||||
|
country: [],
|
||||||
|
duration: [],
|
||||||
|
id: [],
|
||||||
|
visibility: [],
|
||||||
|
isFavorite: [],
|
||||||
|
isImage: [],
|
||||||
|
isTrashed: [],
|
||||||
|
livePhotoVideoId: [],
|
||||||
|
fileCreatedAt: [],
|
||||||
|
localOffsetHours: [],
|
||||||
|
ownerId: [],
|
||||||
|
projectionType: [],
|
||||||
|
ratio: [],
|
||||||
|
status: [],
|
||||||
|
thumbhash: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO enable date string validation while still accepting 5 digit years
|
||||||
|
// it('should fail if time bucket is invalid', async () => {
|
||||||
|
// const { status, body } = await request(app)
|
||||||
|
// .get('/timeline/bucket')
|
||||||
|
// .set('Authorization', `Bearer ${user.accessToken}`)
|
||||||
|
// .query({ timeBucket: 'foo' });
|
||||||
|
|
||||||
|
// expect(status).toBe(400);
|
||||||
|
// expect(body).toEqual(errorDto.badRequest);
|
||||||
|
// });
|
||||||
|
|
||||||
|
it('should return time bucket', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/timeline/bucket')
|
||||||
|
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
|
||||||
|
.query({ timeBucket: '1970-02-10' });
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
city: [],
|
||||||
|
country: [],
|
||||||
|
duration: [],
|
||||||
|
id: [],
|
||||||
|
visibility: [],
|
||||||
|
isFavorite: [],
|
||||||
|
isImage: [],
|
||||||
|
isTrashed: [],
|
||||||
|
livePhotoVideoId: [],
|
||||||
|
fileCreatedAt: [],
|
||||||
|
localOffsetHours: [],
|
||||||
|
ownerId: [],
|
||||||
|
projectionType: [],
|
||||||
|
ratio: [],
|
||||||
|
status: [],
|
||||||
|
thumbhash: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return time bucket in trash', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/timeline/bucket')
|
||||||
|
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
|
||||||
|
.query({ timeBucket: '1970-02-01', isTrashed: true });
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
|
||||||
|
const timeBucket: TimeBucketAssetResponseDto = body;
|
||||||
|
expect(timeBucket.isTrashed).toEqual([true]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -97,7 +97,7 @@ describe(`immich upload`, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await utils.resetDatabase(['asset', 'album']);
|
await utils.resetDatabase(['assets', 'albums']);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe(`immich upload /path/to/file.jpg`, () => {
|
describe(`immich upload /path/to/file.jpg`, () => {
|
||||||
|
|||||||
@@ -1,178 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Script to generate test images with additional EXIF date tags
|
|
||||||
* This creates actual JPEG images with embedded metadata for testing
|
|
||||||
* Images are generated into e2e/test-assets/metadata/dates/
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { execSync } from 'node:child_process';
|
|
||||||
import { writeFileSync } from 'node:fs';
|
|
||||||
import { dirname, join } from 'node:path';
|
|
||||||
import { fileURLToPath } from 'node:url';
|
|
||||||
import sharp from 'sharp';
|
|
||||||
|
|
||||||
interface TestImage {
|
|
||||||
filename: string;
|
|
||||||
description: string;
|
|
||||||
exifTags: Record<string, string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const testImages: TestImage[] = [
|
|
||||||
{
|
|
||||||
filename: 'time-created.jpg',
|
|
||||||
description: 'Image with TimeCreated tag',
|
|
||||||
exifTags: {
|
|
||||||
TimeCreated: '2023:11:15 14:30:00',
|
|
||||||
Make: 'Canon',
|
|
||||||
Model: 'EOS R5',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
filename: 'gps-datetime.jpg',
|
|
||||||
description: 'Image with GPSDateTime and coordinates',
|
|
||||||
exifTags: {
|
|
||||||
GPSDateTime: '2023:11:15 12:30:00Z',
|
|
||||||
GPSLatitude: '37.7749',
|
|
||||||
GPSLongitude: '-122.4194',
|
|
||||||
GPSLatitudeRef: 'N',
|
|
||||||
GPSLongitudeRef: 'W',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
filename: 'datetime-utc.jpg',
|
|
||||||
description: 'Image with DateTimeUTC tag',
|
|
||||||
exifTags: {
|
|
||||||
DateTimeUTC: '2023:11:15 10:30:00',
|
|
||||||
Make: 'Nikon',
|
|
||||||
Model: 'D850',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
filename: 'gps-datestamp.jpg',
|
|
||||||
description: 'Image with GPSDateStamp and GPSTimeStamp',
|
|
||||||
exifTags: {
|
|
||||||
GPSDateStamp: '2023:11:15',
|
|
||||||
GPSTimeStamp: '08:30:00',
|
|
||||||
GPSLatitude: '51.5074',
|
|
||||||
GPSLongitude: '-0.1278',
|
|
||||||
GPSLatitudeRef: 'N',
|
|
||||||
GPSLongitudeRef: 'W',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
filename: 'sony-datetime2.jpg',
|
|
||||||
description: 'Sony camera image with SonyDateTime2 tag',
|
|
||||||
exifTags: {
|
|
||||||
SonyDateTime2: '2023:11:15 06:30:00',
|
|
||||||
Make: 'SONY',
|
|
||||||
Model: 'ILCE-7RM5',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
filename: 'date-priority-test.jpg',
|
|
||||||
description: 'Image with multiple date tags to test priority',
|
|
||||||
exifTags: {
|
|
||||||
SubSecDateTimeOriginal: '2023:01:01 01:00:00',
|
|
||||||
DateTimeOriginal: '2023:02:02 02:00:00',
|
|
||||||
SubSecCreateDate: '2023:03:03 03:00:00',
|
|
||||||
CreateDate: '2023:04:04 04:00:00',
|
|
||||||
CreationDate: '2023:05:05 05:00:00',
|
|
||||||
DateTimeCreated: '2023:06:06 06:00:00',
|
|
||||||
TimeCreated: '2023:07:07 07:00:00',
|
|
||||||
GPSDateTime: '2023:08:08 08:00:00',
|
|
||||||
DateTimeUTC: '2023:09:09 09:00:00',
|
|
||||||
GPSDateStamp: '2023:10:10',
|
|
||||||
SonyDateTime2: '2023:11:11 11:00:00',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
filename: 'new-tags-only.jpg',
|
|
||||||
description: 'Image with only additional date tags (no standard tags)',
|
|
||||||
exifTags: {
|
|
||||||
TimeCreated: '2023:12:01 15:45:30',
|
|
||||||
GPSDateTime: '2023:12:01 13:45:30Z',
|
|
||||||
DateTimeUTC: '2023:12:01 13:45:30',
|
|
||||||
GPSDateStamp: '2023:12:01',
|
|
||||||
SonyDateTime2: '2023:12:01 08:45:30',
|
|
||||||
GPSLatitude: '40.7128',
|
|
||||||
GPSLongitude: '-74.0060',
|
|
||||||
GPSLatitudeRef: 'N',
|
|
||||||
GPSLongitudeRef: 'W',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const generateTestImages = async (): Promise<void> => {
|
|
||||||
// Target directory: e2e/test-assets/metadata/dates/
|
|
||||||
// Current file is in: e2e/src/
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = dirname(__filename);
|
|
||||||
const targetDir = join(__dirname, '..', 'test-assets', 'metadata', 'dates');
|
|
||||||
|
|
||||||
console.log('Generating test images with additional EXIF date tags...');
|
|
||||||
console.log(`Target directory: ${targetDir}`);
|
|
||||||
|
|
||||||
for (const image of testImages) {
|
|
||||||
try {
|
|
||||||
const imagePath = join(targetDir, image.filename);
|
|
||||||
|
|
||||||
// Create unique JPEG file using Sharp
|
|
||||||
const r = Math.floor(Math.random() * 256);
|
|
||||||
const g = Math.floor(Math.random() * 256);
|
|
||||||
const b = Math.floor(Math.random() * 256);
|
|
||||||
|
|
||||||
const jpegData = await sharp({
|
|
||||||
create: {
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
channels: 3,
|
|
||||||
background: { r, g, b },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.jpeg({ quality: 90 })
|
|
||||||
.toBuffer();
|
|
||||||
|
|
||||||
writeFileSync(imagePath, jpegData);
|
|
||||||
|
|
||||||
// Build exiftool command to add EXIF data
|
|
||||||
const exifArgs = Object.entries(image.exifTags)
|
|
||||||
.map(([tag, value]) => `-${tag}="${value}"`)
|
|
||||||
.join(' ');
|
|
||||||
|
|
||||||
const command = `exiftool ${exifArgs} -overwrite_original "${imagePath}"`;
|
|
||||||
|
|
||||||
console.log(`Creating ${image.filename}: ${image.description}`);
|
|
||||||
execSync(command, { stdio: 'pipe' });
|
|
||||||
|
|
||||||
// Verify the tags were written
|
|
||||||
const verifyCommand = `exiftool -json "${imagePath}"`;
|
|
||||||
const result = execSync(verifyCommand, { encoding: 'utf8' });
|
|
||||||
const metadata = JSON.parse(result)[0];
|
|
||||||
|
|
||||||
console.log(` â Created with ${Object.keys(image.exifTags).length} EXIF tags`);
|
|
||||||
|
|
||||||
// Log first date tag found for verification
|
|
||||||
const firstDateTag = Object.keys(image.exifTags).find(
|
|
||||||
(tag) => tag.includes('Date') || tag.includes('Time') || tag.includes('Created'),
|
|
||||||
);
|
|
||||||
if (firstDateTag && metadata[firstDateTag]) {
|
|
||||||
console.log(` â Verified ${firstDateTag}: ${metadata[firstDateTag]}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Failed to create ${image.filename}:`, (error as Error).message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('\nTest image generation complete!');
|
|
||||||
console.log('Files created in:', targetDir);
|
|
||||||
console.log('\nTo test these images:');
|
|
||||||
console.log(`cd ${targetDir} && exiftool -time:all -gps:all *.jpg`);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { generateTestImages };
|
|
||||||
|
|
||||||
// Run the generator if this file is executed directly
|
|
||||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
||||||
generateTestImages().catch(console.error);
|
|
||||||
}
|
|
||||||
@@ -116,7 +116,6 @@ export const deviceDto = {
|
|||||||
createdAt: expect.any(String),
|
createdAt: expect.any(String),
|
||||||
updatedAt: expect.any(String),
|
updatedAt: expect.any(String),
|
||||||
current: true,
|
current: true,
|
||||||
isPendingSyncReset: false,
|
|
||||||
deviceOS: '',
|
deviceOS: '',
|
||||||
deviceType: '',
|
deviceType: '',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ export enum OAuthUser {
|
|||||||
NO_NAME = 'no-name',
|
NO_NAME = 'no-name',
|
||||||
WITH_QUOTA = 'with-quota',
|
WITH_QUOTA = 'with-quota',
|
||||||
WITH_USERNAME = 'with-username',
|
WITH_USERNAME = 'with-username',
|
||||||
WITH_ROLE = 'with-role',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const claims = [
|
const claims = [
|
||||||
@@ -35,12 +34,6 @@ const claims = [
|
|||||||
preferred_username: 'user-quota',
|
preferred_username: 'user-quota',
|
||||||
immich_quota: 25,
|
immich_quota: 25,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
sub: OAuthUser.WITH_ROLE,
|
|
||||||
email: 'oauth-with-role@immich.app',
|
|
||||||
email_verified: true,
|
|
||||||
immich_role: 'admin',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const withDefaultClaims = (sub: string) => ({
|
const withDefaultClaims = (sub: string) => ({
|
||||||
@@ -71,15 +64,7 @@ const setup = async () => {
|
|||||||
claims: {
|
claims: {
|
||||||
openid: ['sub'],
|
openid: ['sub'],
|
||||||
email: ['email', 'email_verified'],
|
email: ['email', 'email_verified'],
|
||||||
profile: [
|
profile: ['name', 'given_name', 'family_name', 'preferred_username', 'immich_quota', 'immich_username'],
|
||||||
'name',
|
|
||||||
'given_name',
|
|
||||||
'family_name',
|
|
||||||
'preferred_username',
|
|
||||||
'immich_quota',
|
|
||||||
'immich_username',
|
|
||||||
'immich_role',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
features: {
|
features: {
|
||||||
jwtUserinfo: {
|
jwtUserinfo: {
|
||||||
|
|||||||
+31
-16
@@ -60,7 +60,6 @@ import { io, type Socket } from 'socket.io-client';
|
|||||||
import { loginDto, signupDto } from 'src/fixtures';
|
import { loginDto, signupDto } from 'src/fixtures';
|
||||||
import { makeRandomImage } from 'src/generators';
|
import { makeRandomImage } from 'src/generators';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
export type { Emitter } from '@socket.io/component-emitter';
|
|
||||||
|
|
||||||
type CommandResponse = { stdout: string; stderr: string; exitCode: number | null };
|
type CommandResponse = { stdout: string; stderr: string; exitCode: number | null };
|
||||||
type EventType = 'assetUpload' | 'assetUpdate' | 'assetDelete' | 'userDelete' | 'assetHidden';
|
type EventType = 'assetUpload' | 'assetUpdate' | 'assetDelete' | 'userDelete' | 'assetHidden';
|
||||||
@@ -85,10 +84,10 @@ export const immichAdmin = (args: string[]) =>
|
|||||||
export const specialCharStrings = ["'", '"', ',', '{', '}', '*'];
|
export const specialCharStrings = ["'", '"', ',', '{', '}', '*'];
|
||||||
export const TEN_TIMES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
export const TEN_TIMES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
|
||||||
const executeCommand = (command: string, args: string[], options?: { cwd?: string }) => {
|
const executeCommand = (command: string, args: string[]) => {
|
||||||
let _resolve: (value: CommandResponse) => void;
|
let _resolve: (value: CommandResponse) => void;
|
||||||
const promise = new Promise<CommandResponse>((resolve) => (_resolve = resolve));
|
const promise = new Promise<CommandResponse>((resolve) => (_resolve = resolve));
|
||||||
const child = spawn(command, args, { stdio: 'pipe', cwd: options?.cwd });
|
const child = spawn(command, args, { stdio: 'pipe' });
|
||||||
|
|
||||||
let stdout = '';
|
let stdout = '';
|
||||||
let stderr = '';
|
let stderr = '';
|
||||||
@@ -154,19 +153,19 @@ export const utils = {
|
|||||||
|
|
||||||
tables = tables || [
|
tables = tables || [
|
||||||
// TODO e2e test for deleting a stack, since it is quite complex
|
// TODO e2e test for deleting a stack, since it is quite complex
|
||||||
'stack',
|
'asset_stack',
|
||||||
'library',
|
'libraries',
|
||||||
'shared_link',
|
'shared_links',
|
||||||
'person',
|
'person',
|
||||||
'album',
|
'albums',
|
||||||
'asset',
|
'assets',
|
||||||
'asset_face',
|
'asset_faces',
|
||||||
'activity',
|
'activity',
|
||||||
'api_key',
|
'api_keys',
|
||||||
'session',
|
'sessions',
|
||||||
'user',
|
'users',
|
||||||
'system_metadata',
|
'system_metadata',
|
||||||
'tag',
|
'tags',
|
||||||
];
|
];
|
||||||
|
|
||||||
const sql: string[] = [];
|
const sql: string[] = [];
|
||||||
@@ -175,7 +174,7 @@ export const utils = {
|
|||||||
if (table === 'system_metadata') {
|
if (table === 'system_metadata') {
|
||||||
sql.push(`DELETE FROM "system_metadata" where "key" NOT IN ('reverse-geocoding-state', 'system-flags');`);
|
sql.push(`DELETE FROM "system_metadata" where "key" NOT IN ('reverse-geocoding-state', 'system-flags');`);
|
||||||
} else {
|
} else {
|
||||||
sql.push(`DELETE FROM "${table}" CASCADE;`);
|
sql.push(`DELETE FROM ${table} CASCADE;`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +185,18 @@ export const utils = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
resetFilesystem: async () => {
|
||||||
|
const mediaInternal = '/usr/src/app/upload';
|
||||||
|
const dirs = [
|
||||||
|
`"${mediaInternal}/thumbs"`,
|
||||||
|
`"${mediaInternal}/upload"`,
|
||||||
|
`"${mediaInternal}/library"`,
|
||||||
|
`"${mediaInternal}/encoded-video"`,
|
||||||
|
].join(' ');
|
||||||
|
|
||||||
|
await execPromise(`docker exec -i "immich-e2e-server" /bin/bash -c "rm -rf ${dirs} && mkdir ${dirs}"`);
|
||||||
|
},
|
||||||
|
|
||||||
unzip: async (input: string, output: string) => {
|
unzip: async (input: string, output: string) => {
|
||||||
await execPromise(`unzip -o -d "${output}" "${input}"`);
|
await execPromise(`unzip -o -d "${output}" "${input}"`);
|
||||||
},
|
},
|
||||||
@@ -205,7 +216,11 @@ export const utils = {
|
|||||||
websocket
|
websocket
|
||||||
.on('connect', () => resolve(websocket))
|
.on('connect', () => resolve(websocket))
|
||||||
.on('on_upload_success', (data: AssetResponseDto) => onEvent({ event: 'assetUpload', id: data.id }))
|
.on('on_upload_success', (data: AssetResponseDto) => onEvent({ event: 'assetUpload', id: data.id }))
|
||||||
.on('on_asset_update', (data: AssetResponseDto) => onEvent({ event: 'assetUpdate', id: data.id }))
|
.on('on_asset_update', (assetId: string[]) => {
|
||||||
|
for (const id of assetId) {
|
||||||
|
onEvent({ event: 'assetUpdate', id });
|
||||||
|
}
|
||||||
|
})
|
||||||
.on('on_asset_hidden', (assetId: string) => onEvent({ event: 'assetHidden', id: assetId }))
|
.on('on_asset_hidden', (assetId: string) => onEvent({ event: 'assetHidden', id: assetId }))
|
||||||
.on('on_asset_delete', (assetId: string) => onEvent({ event: 'assetDelete', id: assetId }))
|
.on('on_asset_delete', (assetId: string) => onEvent({ event: 'assetDelete', id: assetId }))
|
||||||
.on('on_user_delete', (userId: string) => onEvent({ event: 'userDelete', id: userId }))
|
.on('on_user_delete', (userId: string) => onEvent({ event: 'userDelete', id: userId }))
|
||||||
@@ -439,7 +454,7 @@ export const utils = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.query('INSERT INTO asset_face ("assetId", "personId") VALUES ($1, $2)', [assetId, personId]);
|
await client.query('INSERT INTO asset_faces ("assetId", "personId") VALUES ($1, $2)', [assetId, personId]);
|
||||||
},
|
},
|
||||||
|
|
||||||
setPersonThumbnail: async (personId: string) => {
|
setPersonThumbnail: async (personId: string) => {
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ test.describe('Registration', () => {
|
|||||||
await page.getByRole('button', { name: 'Server Privacy' }).click();
|
await page.getByRole('button', { name: 'Server Privacy' }).click();
|
||||||
await page.getByRole('button', { name: 'User Privacy' }).click();
|
await page.getByRole('button', { name: 'User Privacy' }).click();
|
||||||
await page.getByRole('button', { name: 'Storage Template' }).click();
|
await page.getByRole('button', { name: 'Storage Template' }).click();
|
||||||
await page.getByRole('button', { name: 'Backups' }).click();
|
|
||||||
await page.getByRole('button', { name: 'Done' }).click();
|
await page.getByRole('button', { name: 'Done' }).click();
|
||||||
|
|
||||||
// success
|
// success
|
||||||
|
|||||||
+1
-1
Submodule e2e/test-assets updated: 37f60ea537...8885d6d01c
+8
-110
@@ -4,7 +4,6 @@
|
|||||||
"account_settings": "Rekeninginstellings",
|
"account_settings": "Rekeninginstellings",
|
||||||
"acknowledge": "Erken",
|
"acknowledge": "Erken",
|
||||||
"action": "Aksie",
|
"action": "Aksie",
|
||||||
"action_common_update": "Opdateur",
|
|
||||||
"actions": "Aksies",
|
"actions": "Aksies",
|
||||||
"active": "Aktief",
|
"active": "Aktief",
|
||||||
"activity": "Aktiwiteite",
|
"activity": "Aktiwiteite",
|
||||||
@@ -14,7 +13,6 @@
|
|||||||
"add_a_location": "Voeg 'n ligging by",
|
"add_a_location": "Voeg 'n ligging by",
|
||||||
"add_a_name": "Voeg 'n naam by",
|
"add_a_name": "Voeg 'n naam by",
|
||||||
"add_a_title": "Voeg 'n titel by",
|
"add_a_title": "Voeg 'n titel by",
|
||||||
"add_endpoint": "Voeg Koppelvlakpunt by",
|
|
||||||
"add_exclusion_pattern": "Voeg uitsgluitingspatrone by",
|
"add_exclusion_pattern": "Voeg uitsgluitingspatrone by",
|
||||||
"add_import_path": "Voeg invoerpad by",
|
"add_import_path": "Voeg invoerpad by",
|
||||||
"add_location": "Voeg ligging by",
|
"add_location": "Voeg ligging by",
|
||||||
@@ -22,30 +20,26 @@
|
|||||||
"add_partner": "Voeg vennoot by",
|
"add_partner": "Voeg vennoot by",
|
||||||
"add_path": "Voeg pad by",
|
"add_path": "Voeg pad by",
|
||||||
"add_photos": "Voeg foto's by",
|
"add_photos": "Voeg foto's by",
|
||||||
"add_tag": "Voeg tag by",
|
|
||||||
"add_to": "Voeg byâĻ",
|
"add_to": "Voeg byâĻ",
|
||||||
"add_to_album": "Voeg na album",
|
"add_to_album": "Voeg na album",
|
||||||
"add_to_album_bottom_sheet_added": "By {album} bygevoeg",
|
"add_to_shared_album": "Voeg na gedeelde album",
|
||||||
"add_to_album_bottom_sheet_already_exists": "Reeds in {album}",
|
|
||||||
"add_to_shared_album": "Voeg toe aan gedeelde album",
|
|
||||||
"add_url": "Voeg URL by",
|
"add_url": "Voeg URL by",
|
||||||
"added_to_archive": "By argief toegevoegd",
|
"added_to_archive": "By argief gevoeg",
|
||||||
"added_to_favorites": "By gunstelinge toegevoegd",
|
"added_to_favorites": "By gunstelinge gevoeg",
|
||||||
"added_to_favorites_count": "Het {count, number} by gunstelinge toegevoegd",
|
"added_to_favorites_count": "Het {count, number} by gunstelinge gevoeg",
|
||||||
"admin": {
|
"admin": {
|
||||||
"add_exclusion_pattern_description": "Voeg uitsluitingspatrone by. Globbing met *, ** en ? word ondersteun. Om alle lÃĒers in enige lÃĒergids genaamd \"Raw\" te ignoreer, gebruik \"**/Raw/**\". Om alle lÃĒers wat op \".tif\" eindig, te ignoreer, gebruik \"**/*.tif\". Om 'n absolute pad te ignoreer, gebruik \"/path/to/ignore/**\".",
|
"add_exclusion_pattern_description": "Voeg uitsluitingspatrone by. Globbing met *, ** en ? word ondersteun. Om alle lÃĒers in enige lÃĒergids genaamd \"Raw\" te ignoreer, gebruik \"**/Raw/**\". Om alle lÃĒers wat op \".tif\" eindig, te ignoreer, gebruik \"**/*.tif\". Om 'n absolute pad te ignoreer, gebruik \"/path/to/ignore/**\".",
|
||||||
"admin_user": "Admin gebruiker",
|
|
||||||
"asset_offline_description": "Hierdie eksterne biblioteekbate word nie meer op skyf gevind nie en is na die asblik geskuif. As die lÃĒer binne die biblioteek geskuif is, gaan jou tydlyn na vir die nuwe ooreenstemmende bate. Om hierdie bate te herstel, maak asseblief seker dat die lÃĒerpad hieronder deur Immich verkry kan word en skandeer die biblioteek.",
|
"asset_offline_description": "Hierdie eksterne biblioteekbate word nie meer op skyf gevind nie en is na die asblik geskuif. As die lÃĒer binne die biblioteek geskuif is, gaan jou tydlyn na vir die nuwe ooreenstemmende bate. Om hierdie bate te herstel, maak asseblief seker dat die lÃĒerpad hieronder deur Immich verkry kan word en skandeer die biblioteek.",
|
||||||
"authentication_settings": "Verifikasie instellings",
|
"authentication_settings": "Verifikasie instellings",
|
||||||
"authentication_settings_description": "Bestuur wagwoord, OAuth en ander verifikasie instellings",
|
"authentication_settings_description": "Bestuur wagwoord, OAuth en ander verifikasie instellings",
|
||||||
"authentication_settings_disable_all": "Is jy seker jy wil alle aanmeldmetodes deaktiveer? Aanmelding sal heeltemal gedeaktiveer word.",
|
"authentication_settings_disable_all": "Is jy seker jy wil alle aanmeldmetodes deaktiveer? Aanmelding sal heeltemal gedeaktiveer word.",
|
||||||
"authentication_settings_reenable": "Om te heraktiveer, gebruik 'n <link>Server Command</link>.",
|
"authentication_settings_reenable": "Om te heraktiveer, gebruik 'n <link>Server Command</link>.",
|
||||||
"background_task_job": "Agtergrondtake",
|
"background_task_job": "Agtergrondtake",
|
||||||
"backup_database": "Skep DatastortlÃĒer",
|
"backup_database": "Rugsteun databasis",
|
||||||
"backup_database_enable_description": "Aktiveer databasisrugsteun",
|
"backup_database_enable_description": "Aktiveer databasisrugsteun",
|
||||||
"backup_keep_last_amount": "Aantal vorige rugsteune om te hou",
|
"backup_keep_last_amount": "Aantal vorige rugsteune om te hou",
|
||||||
"backup_settings": "Rugsteun instellings",
|
"backup_settings": "Rugsteun instellings",
|
||||||
"backup_settings_description": "Bestuur databasis rugsteun instellings.",
|
"backup_settings_description": "Bestuur databasis rugsteun instellings",
|
||||||
"cleared_jobs": "Poste gevee vir: {job}",
|
"cleared_jobs": "Poste gevee vir: {job}",
|
||||||
"config_set_by_file": "Config word tans deur 'n konfigurasielÃĒer gestel",
|
"config_set_by_file": "Config word tans deur 'n konfigurasielÃĒer gestel",
|
||||||
"confirm_delete_library": "Is jy seker jy wil {library}-biblioteek uitvee?",
|
"confirm_delete_library": "Is jy seker jy wil {library}-biblioteek uitvee?",
|
||||||
@@ -53,7 +47,6 @@
|
|||||||
"confirm_email_below": "Om te bevestig, tik \"{email}\" hieronder",
|
"confirm_email_below": "Om te bevestig, tik \"{email}\" hieronder",
|
||||||
"confirm_reprocess_all_faces": "Is jy seker jy wil alle gesigte herverwerk? Dit sal ook genoemde mense skoonmaak.",
|
"confirm_reprocess_all_faces": "Is jy seker jy wil alle gesigte herverwerk? Dit sal ook genoemde mense skoonmaak.",
|
||||||
"confirm_user_password_reset": "Is jy seker jy wil {user} se wagwoord terugstel?",
|
"confirm_user_password_reset": "Is jy seker jy wil {user} se wagwoord terugstel?",
|
||||||
"confirm_user_pin_code_reset": "Is jy seker jy wil {user} se PIN kode herstel?",
|
|
||||||
"create_job": "Skep werk",
|
"create_job": "Skep werk",
|
||||||
"cron_expression": "Cron uitdrukking",
|
"cron_expression": "Cron uitdrukking",
|
||||||
"cron_expression_description": "Stel die skanderingsinterval in met die cron-formaat. Vir meer inligting verwys asseblief na bv. <link>Crontab Guru</link>",
|
"cron_expression_description": "Stel die skanderingsinterval in met die cron-formaat. Vir meer inligting verwys asseblief na bv. <link>Crontab Guru</link>",
|
||||||
@@ -63,14 +56,10 @@
|
|||||||
"exclusion_pattern_description": "Met uitsluitingspatrone kan jy lÃĒers en vouers ignoreer wanneer jy jou biblioteek skandeer. Dit is nuttig as jy vouers het wat lÃĒers bevat wat jy nie wil invoer nie, soos RAW-lÃĒers.",
|
"exclusion_pattern_description": "Met uitsluitingspatrone kan jy lÃĒers en vouers ignoreer wanneer jy jou biblioteek skandeer. Dit is nuttig as jy vouers het wat lÃĒers bevat wat jy nie wil invoer nie, soos RAW-lÃĒers.",
|
||||||
"external_library_management": "Eksterne Biblioteekbestuur",
|
"external_library_management": "Eksterne Biblioteekbestuur",
|
||||||
"face_detection": "Gesig deteksie",
|
"face_detection": "Gesig deteksie",
|
||||||
"face_detection_description": "Detecteer die gesigte in media deur middel van masjienleer. Vir videos word slegs die duimnaelskets oorweeg. âHerlaaiâ (ver)werk al die media weer. âStel terugâ verwyder boonop alle huidige gesigdata. âOnverwerkâ plaas bates in die tou wat nog nie verwerk is nie. Gedekte gesigte sal nÃĄ voltooiing van Gesigdetectie vir Gesigherkenning in die tou geplaas word, om hulle in bestaande of nuwe persone te groepeer.",
|
|
||||||
"facial_recognition_job_description": "Groepeer gesigte in mense in. Die stap is vinniger nadat Gesig Deteksie klaar is. \"Herstel\" (her-)groepeer alle gesigte. \"Vermiste\" plaas gesigte in ry wat nie 'n persoon gekoppel het nie.",
|
|
||||||
"failed_job_command": "Opdrag {command} het misluk vir werk: {job}",
|
"failed_job_command": "Opdrag {command} het misluk vir werk: {job}",
|
||||||
"force_delete_user_warning": "WAARSKUWING: Dit sal onmiddellik die gebruiker en alle bates verwyder. Dit kan nie ontdoen word nie en die lÃĒers kan nie herstel word nie.",
|
"force_delete_user_warning": "WAARSKUWING: Dit sal onmiddellik die gebruiker en alle bates verwyder. Dit kan nie ontdoen word nie en die lÃĒers kan nie herstel word nie.",
|
||||||
"image_format": "Formaat",
|
"image_format": "Formaat",
|
||||||
"image_format_description": "WebP produseer kleiner lÃĒers as JPEG, maar is stadiger om te enkodeer.",
|
"image_format_description": "WebP produseer kleiner lÃĒers as JPEG, maar is stadiger om te enkodeer.",
|
||||||
"image_fullsize_description": "Vol grote prent met geen metadata, gebruik wanner ingezoem",
|
|
||||||
"image_fullsize_enabled": "Skakel aan vol grote prent generasie",
|
|
||||||
"image_prefer_embedded_preview": "Verkies ingebedde voorskou",
|
"image_prefer_embedded_preview": "Verkies ingebedde voorskou",
|
||||||
"image_prefer_wide_gamut": "Verkies wide gamut",
|
"image_prefer_wide_gamut": "Verkies wide gamut",
|
||||||
"image_prefer_wide_gamut_setting_description": "Gebruik Display P3 vir kleinkiekies. Dit behou die lewendheid van beelde met wye kleurruimtes beter, maar beelde kan anders verskyn op ou apparate met 'n ou blaaierweergawe. sRGB-beelde gebruik steeds sRGB om kleurverskuiwings te voorkom.",
|
"image_prefer_wide_gamut_setting_description": "Gebruik Display P3 vir kleinkiekies. Dit behou die lewendheid van beelde met wye kleurruimtes beter, maar beelde kan anders verskyn op ou apparate met 'n ou blaaierweergawe. sRGB-beelde gebruik steeds sRGB om kleurverskuiwings te voorkom.",
|
||||||
@@ -88,99 +77,8 @@
|
|||||||
"job_concurrency": "{job} gelyktydigheid",
|
"job_concurrency": "{job} gelyktydigheid",
|
||||||
"job_created": "Taak gemaak",
|
"job_created": "Taak gemaak",
|
||||||
"job_not_concurrency_safe": "Hierdie taak kan nie gelyktydig uitgevoer word nie.",
|
"job_not_concurrency_safe": "Hierdie taak kan nie gelyktydig uitgevoer word nie.",
|
||||||
"job_settings": "Agtergrondtaakinstellings",
|
"job_settings": "Agtergrondtaakinstellings"
|
||||||
"job_settings_description": "Bestuur werkgelyktydigheid",
|
|
||||||
"job_status": "Werkstatus",
|
|
||||||
"library_created": "Biblioteek geskep: {library}",
|
|
||||||
"library_deleted": "Biblioteek verwyder",
|
|
||||||
"library_import_path_description": "Spesifiseer 'n leer om in te neem. Hierdie leer, en al die sub leers, gaan geskandeer for vir prente en videos.",
|
|
||||||
"library_scanning": "Periodieke Skandering",
|
|
||||||
"library_scanning_description": "Stel periodieke skandering van biblioteek in",
|
|
||||||
"library_scanning_enable_description": "Aktiveer periodieke biblioteekskandering",
|
|
||||||
"library_settings": "Eksterne Biblioteek",
|
|
||||||
"map_settings": "Kaart",
|
|
||||||
"migration_job": "Migrasie",
|
|
||||||
"oauth_settings": "OAuth",
|
|
||||||
"transcoding_acceleration_vaapi": "VAAPI"
|
|
||||||
},
|
},
|
||||||
"administration": "Administrasie",
|
|
||||||
"advanced": "Gevorderde",
|
|
||||||
"albums": "Albums",
|
|
||||||
"all": "Alle",
|
|
||||||
"anti_clockwise": "Anti-kloksgewys",
|
|
||||||
"archive": "Argief",
|
|
||||||
"asset_skipped": "Oorgeslaan",
|
|
||||||
"asset_uploaded": "Opgelaai",
|
|
||||||
"asset_uploading": "OplaaiâĻ",
|
|
||||||
"assets": "Bates",
|
|
||||||
"back": "Terug",
|
|
||||||
"backward": "Agteruit",
|
|
||||||
"build": "Bou",
|
|
||||||
"camera": "Kamera",
|
|
||||||
"cancel": "Kanselleer",
|
|
||||||
"city": "Stad",
|
|
||||||
"clockwise": "Kloksgewys",
|
|
||||||
"close": "Maak toe",
|
|
||||||
"color": "Kleur",
|
|
||||||
"confirm": "Bevestig",
|
|
||||||
"contain": "Bevat",
|
|
||||||
"context": "Konteks",
|
|
||||||
"continue": "Gaan voort",
|
|
||||||
"country": "Land",
|
|
||||||
"cover": "Bedek",
|
|
||||||
"create": "Skep",
|
|
||||||
"created": "Geskep",
|
|
||||||
"dark": "Donker",
|
|
||||||
"day": "Dag",
|
|
||||||
"delete": "Verwyder",
|
|
||||||
"description": "Beskrywing",
|
|
||||||
"details": "Besonderhede",
|
|
||||||
"direction": "Rigting",
|
|
||||||
"discover": "Ontdek",
|
|
||||||
"documentation": "Dokumentasie",
|
|
||||||
"done": "Klaar",
|
|
||||||
"download": "Aflaai",
|
|
||||||
"download_settings": "Aflaai",
|
|
||||||
"duplicates": "Duplikate",
|
|
||||||
"duration": "Duur",
|
|
||||||
"edit": "Wysig",
|
|
||||||
"edited": "Gewysigd",
|
|
||||||
"search_by_description": "Soek by beskrywing",
|
"search_by_description": "Soek by beskrywing",
|
||||||
"search_by_description_example": "Stapdag in Sapa",
|
"search_by_description_example": "Stapdag in Sapa"
|
||||||
"version": "Weergawe",
|
|
||||||
"version_announcement_closing": "Jou friend, Alex",
|
|
||||||
"version_history": "Weergawegeskiedenis",
|
|
||||||
"version_history_item": "{version} geinstaleerd op {date}",
|
|
||||||
"video": "Video",
|
|
||||||
"videos": "Video's",
|
|
||||||
"view": "Bekyk",
|
|
||||||
"view_album": "Bekyk Album",
|
|
||||||
"view_all": "Bekyk alle",
|
|
||||||
"view_all_users": "Bekyk alle gebruikers",
|
|
||||||
"view_in_timeline": "Bekyk in tydlyn",
|
|
||||||
"view_link": "Bekyk skakel",
|
|
||||||
"view_links": "Bekyk skakels",
|
|
||||||
"view_name": "Bekyk",
|
|
||||||
"view_next_asset": "Bekyk volgende bate",
|
|
||||||
"view_previous_asset": "Bekyk vorige bate",
|
|
||||||
"view_qr_code": "Bekyk QR-kode",
|
|
||||||
"view_stack": "Bekyk stapel",
|
|
||||||
"view_user": "Bekyk gebruiker",
|
|
||||||
"viewer_remove_from_stack": "Verwyder van stapel",
|
|
||||||
"viewer_stack_use_as_main_asset": "Gebruik as hoofbate",
|
|
||||||
"viewer_unstack": "Ontstapel",
|
|
||||||
"visibility_changed": "Sigbaarheid verander voor {count, plural, one {# person} other {# people}}",
|
|
||||||
"waiting": "Wag",
|
|
||||||
"warning": "Waaskuwing",
|
|
||||||
"week": "Week",
|
|
||||||
"welcome": "Welkom",
|
|
||||||
"welcome_to_immich": "Welkom by Immich",
|
|
||||||
"wifi_name": "Wi-Fi Naam",
|
|
||||||
"wrong_pin_code": "Verkeerde PIN-kode",
|
|
||||||
"year": "Jaar",
|
|
||||||
"years_ago": "{years, plural, one {# year} other {# years}} gelede",
|
|
||||||
"yes": "Ja",
|
|
||||||
"you_dont_have_any_shared_links": "Jy het geen gedeelde skakels",
|
|
||||||
"your_wifi_name": "Jou Wi-Fi naam",
|
|
||||||
"zoom_image": "Vergroot Prent"
|
|
||||||
}
|
}
|
||||||
|
|||||||
+88
-405
File diff suppressed because it is too large
Load Diff
+9
-358
@@ -6,7 +6,7 @@
|
|||||||
"action": "ĐСĐĩŅĐŊĐŊĐĩ",
|
"action": "ĐСĐĩŅĐŊĐŊĐĩ",
|
||||||
"action_common_update": "ĐĐąĐŊавŅŅŅ",
|
"action_common_update": "ĐĐąĐŊавŅŅŅ",
|
||||||
"actions": "ĐСĐĩŅĐŊĐŊŅ",
|
"actions": "ĐСĐĩŅĐŊĐŊŅ",
|
||||||
"active": "ĐĐēŅŅŅĐŊŅŅ
",
|
"active": "ĐĐēŅŅŅĐŊŅ",
|
||||||
"activity": "ĐĐēŅŅŅĐŊаŅŅŅ",
|
"activity": "ĐĐēŅŅŅĐŊаŅŅŅ",
|
||||||
"activity_changed": "ĐĐēŅŅŅĐŊаŅŅŅ {enabled, select, true {ŅĐēĐģŅŅаĐŊа} other {адĐēĐģŅŅаĐŊа}}",
|
"activity_changed": "ĐĐēŅŅŅĐŊаŅŅŅ {enabled, select, true {ŅĐēĐģŅŅаĐŊа} other {адĐēĐģŅŅаĐŊа}}",
|
||||||
"add": "ĐадаŅŅ",
|
"add": "ĐадаŅŅ",
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
"add_partner": "ĐадаŅŅ ĐŋаŅŅĐŊŅŅа",
|
"add_partner": "ĐадаŅŅ ĐŋаŅŅĐŊŅŅа",
|
||||||
"add_path": "ĐадаŅŅ ŅĐģŅŅ
",
|
"add_path": "ĐадаŅŅ ŅĐģŅŅ
",
|
||||||
"add_photos": "ĐадаŅŅ ŅĐžŅа",
|
"add_photos": "ĐадаŅŅ ŅĐžŅа",
|
||||||
"add_tag": "ĐадаŅŅ ŅŅĐŗ",
|
|
||||||
"add_to": "ĐадаŅŅ ŅâĻ",
|
"add_to": "ĐадаŅŅ ŅâĻ",
|
||||||
"add_to_album": "ĐадаŅŅ Ņ Đ°ĐģŅйОĐŧ",
|
"add_to_album": "ĐадаŅŅ Ņ Đ°ĐģŅйОĐŧ",
|
||||||
"add_to_album_bottom_sheet_added": "ĐададСĐĩĐŊа да {album}",
|
"add_to_album_bottom_sheet_added": "ĐададСĐĩĐŊа да {album}",
|
||||||
@@ -34,30 +33,28 @@
|
|||||||
"added_to_favorites_count": "ĐададСĐĩĐŊа {count, number} да айŅаĐŊĐ°ĐŗĐ°",
|
"added_to_favorites_count": "ĐададСĐĩĐŊа {count, number} да айŅаĐŊĐ°ĐŗĐ°",
|
||||||
"admin": {
|
"admin": {
|
||||||
"add_exclusion_pattern_description": "ĐадаКŅĐĩ ŅайĐģĐžĐŊŅ Đ˛ŅĐēĐģŅŅŅĐŊĐŊŅŅ. ĐадŅŅŅĐŧĐģŅваĐĩŅŅа вŅĐēаŅŅŅŅаĐŊĐŊĐĩ ŅŅĐŧваĐģĐ°Ņ * , ** Ņ ?. Đай ŅĐŗĐŊаŅаваŅŅ ŅŅĐĩ ŅаКĐģŅ Ņ ĐģŅйОК Đ´ŅŅŅĐēŅĐžŅŅŅ Đˇ ĐŊаСваК \"Raw\", вŅĐēаŅŅŅŅĐžŅваКŅĐĩ \"**/Raw/**\". Đай ŅĐŗĐŊаŅаваŅŅ ŅŅĐĩ ŅаКĐģŅ, ŅĐēŅŅ ĐˇĐ°ĐēаĐŊŅваŅŅŅа ĐŊа \".tif\", вŅĐēаŅŅŅŅĐžŅваКŅĐĩ \"**/.tif\". Đай ŅĐŗĐŊаŅаваŅŅ Đ°ĐąŅĐžĐģŅŅĐŊŅ ŅĐģŅŅ
, вŅĐēаŅŅŅŅĐžŅваКŅĐĩ \"/path/to/ignore/**\".",
|
"add_exclusion_pattern_description": "ĐадаКŅĐĩ ŅайĐģĐžĐŊŅ Đ˛ŅĐēĐģŅŅŅĐŊĐŊŅŅ. ĐадŅŅŅĐŧĐģŅваĐĩŅŅа вŅĐēаŅŅŅŅаĐŊĐŊĐĩ ŅŅĐŧваĐģĐ°Ņ * , ** Ņ ?. Đай ŅĐŗĐŊаŅаваŅŅ ŅŅĐĩ ŅаКĐģŅ Ņ ĐģŅйОК Đ´ŅŅŅĐēŅĐžŅŅŅ Đˇ ĐŊаСваК \"Raw\", вŅĐēаŅŅŅŅĐžŅваКŅĐĩ \"**/Raw/**\". Đай ŅĐŗĐŊаŅаваŅŅ ŅŅĐĩ ŅаКĐģŅ, ŅĐēŅŅ ĐˇĐ°ĐēаĐŊŅваŅŅŅа ĐŊа \".tif\", вŅĐēаŅŅŅŅĐžŅваКŅĐĩ \"**/.tif\". Đай ŅĐŗĐŊаŅаваŅŅ Đ°ĐąŅĐžĐģŅŅĐŊŅ ŅĐģŅŅ
, вŅĐēаŅŅŅŅĐžŅваКŅĐĩ \"/path/to/ignore/**\".",
|
||||||
"admin_user": "ĐĐ´ĐŧŅĐŊŅŅŅŅаŅаŅ",
|
|
||||||
"asset_offline_description": "ĐŅŅŅ ĐˇĐŊĐĩŅĐŊŅ ĐąŅĐąĐģŅŅŅŅŅĐŊŅ Đ°ĐēŅŅŅ ĐąĐžĐģŅŅ ĐŊĐĩ СĐŊОКдСĐĩĐŊŅ ĐŊа Đ´ŅŅĐēŅ Ņ ĐąŅŅ ĐŋĐĩŅаĐŧĐĩŅŅаĐŊŅ Ņ ŅĐŧĐĩŅĐŊŅŅŅ. ĐаĐģŅ ŅаКĐģ ĐąŅŅ ĐŋĐĩŅаĐŧĐĩŅŅаĐŊŅ Ņ ĐŧĐĩĐļаŅ
ĐąŅĐąĐģŅŅŅŅĐēŅ, ĐŋŅавĐĩŅŅĐĩ ваŅŅ Ņ
ŅĐžĐŊŅĐēŅ Đ´ĐģŅ ĐŊĐžĐ˛Đ°ĐŗĐ° адĐŋавĐĩĐ´ĐŊĐ°ĐŗĐ° аĐēŅŅва. Đай адĐŊавŅŅŅ ĐŗŅŅŅ Đ°ĐēŅŅŅ, ĐŋĐĩŅаĐēаĐŊаКŅĐĩŅŅ, ŅŅĐž ŅĐģŅŅ
да ŅаКĐģа ĐŊŅĐļŅĐš даŅŅŅĐŋĐŊŅ Đ´ĐģŅ Immich Ņ Đ°Đ´ŅĐēаĐŊŅĐšŅĐĩ ĐąŅĐąĐģŅŅŅŅĐēŅ.",
|
"asset_offline_description": "ĐŅŅŅ ĐˇĐŊĐĩŅĐŊŅ ĐąŅĐąĐģŅŅŅŅŅĐŊŅ Đ°ĐēŅŅŅ ĐąĐžĐģŅŅ ĐŊĐĩ СĐŊОКдСĐĩĐŊŅ ĐŊа Đ´ŅŅĐēŅ Ņ ĐąŅŅ ĐŋĐĩŅаĐŧĐĩŅŅаĐŊŅ Ņ ŅĐŧĐĩŅĐŊŅŅŅ. ĐаĐģŅ ŅаКĐģ ĐąŅŅ ĐŋĐĩŅаĐŧĐĩŅŅаĐŊŅ Ņ ĐŧĐĩĐļаŅ
ĐąŅĐąĐģŅŅŅŅĐēŅ, ĐŋŅавĐĩŅŅĐĩ ваŅŅ Ņ
ŅĐžĐŊŅĐēŅ Đ´ĐģŅ ĐŊĐžĐ˛Đ°ĐŗĐ° адĐŋавĐĩĐ´ĐŊĐ°ĐŗĐ° аĐēŅŅва. Đай адĐŊавŅŅŅ ĐŗŅŅŅ Đ°ĐēŅŅŅ, ĐŋĐĩŅаĐēаĐŊаКŅĐĩŅŅ, ŅŅĐž ŅĐģŅŅ
да ŅаКĐģа ĐŊŅĐļŅĐš даŅŅŅĐŋĐŊŅ Đ´ĐģŅ Immich Ņ Đ°Đ´ŅĐēаĐŊŅĐšŅĐĩ ĐąŅĐąĐģŅŅŅŅĐēŅ.",
|
||||||
"authentication_settings": "ĐаĐģĐ°Đ´Ņ ĐŋŅавĐĩŅĐēŅ ŅаĐŋŅаŅĐ´ĐŊаŅŅŅ",
|
"authentication_settings": "ĐаĐģĐ°Đ´Ņ ĐŋŅавĐĩŅĐēŅ ŅаĐŋŅаŅĐ´ĐŊаŅŅŅ",
|
||||||
"authentication_settings_description": "ĐŅŅаваĐŊĐŊĐĩ ĐŋаŅĐžĐģŅĐŧŅ, OAuth, Ņ ŅĐŊŅŅŅ ĐŊаĐģĐ°Đ´Ņ ĐŋŅавĐĩŅĐēŅ ŅаĐŋŅаŅĐ´ĐŊаŅŅŅ",
|
"authentication_settings_description": "ĐŅŅаваĐŊĐŊĐĩ ĐŋаŅĐžĐģŅĐŧŅ, OAuth, Ņ ŅĐŊŅŅŅ ĐŊаĐģĐ°Đ´Ņ ĐŋŅавĐĩŅĐēŅ ŅаĐŋŅаŅĐ´ĐŊаŅŅŅ",
|
||||||
"authentication_settings_disable_all": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž ĐļадаĐĩŅĐĩ адĐēĐģŅŅŅŅŅ ŅŅĐĩ ŅĐŋĐžŅĐ°ĐąŅ ĐģĐžĐŗŅĐŊŅ? ĐĐžĐŗŅĐŊ ĐąŅдСĐĩ ŅаĐģĐēаĐŧ адĐēĐģŅŅаĐŊŅ.",
|
"authentication_settings_disable_all": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž ĐļадаĐĩŅĐĩ адĐēĐģŅŅŅŅŅ ŅŅĐĩ ŅĐŋĐžŅĐ°ĐąŅ ĐģĐžĐŗŅĐŊŅ? ĐĐžĐŗŅĐŊ ĐąŅдСĐĩ ŅаĐģĐēаĐŧ адĐēĐģŅŅаĐŊŅ.",
|
||||||
"authentication_settings_reenable": "Đай СĐŊĐžŅ ŅĐēĐģŅŅŅŅŅ, вŅĐēаŅŅŅŅаКŅĐĩ <link>ĐаĐŧаĐŊĐ´Ņ ŅĐĩŅвĐĩŅа</link>.",
|
"authentication_settings_reenable": "Đай СĐŊĐžŅ ŅĐēĐģŅŅŅŅŅ, вŅĐēаŅŅŅŅаКŅĐĩ <link>ĐаĐŧаĐŊĐ´Ņ ŅĐĩŅвĐĩŅа</link>.",
|
||||||
"background_task_job": "ФОĐŊавŅŅ ĐˇĐ°Đ´Đ°ĐŊĐŊŅ",
|
"background_task_job": "ФОĐŊавŅŅ ĐˇĐ°Đ´Đ°ĐŊĐŊŅ",
|
||||||
"backup_database": "ĐĄŅваŅŅŅŅ ŅŅСĐĩŅвОвŅŅ ĐēĐžĐŋŅŅ ĐąĐ°ĐˇŅ Đ´Đ°ĐŊŅŅ
",
|
"backup_database": "Đ ŅСĐĩŅĐ˛ĐžĐ˛Đ°Ņ ĐēĐžĐŋŅŅ ĐąĐ°ĐˇŅ Đ´Đ°ĐŊŅŅ
",
|
||||||
"backup_database_enable_description": "ĐŖĐēĐģŅŅŅŅŅ ŅŅСĐĩŅваваĐŊĐŊĐĩ ĐąĐ°ĐˇŅ Đ´Đ°ĐŊŅŅ
",
|
"backup_database_enable_description": "ĐŖĐēĐģŅŅŅŅŅ ŅŅСĐĩŅваваĐŊĐŊĐĩ ĐąĐ°ĐˇŅ Đ´Đ°ĐŊŅŅ
",
|
||||||
"backup_keep_last_amount": "ĐĐžĐģŅĐēаŅŅŅ ĐŋаĐŋŅŅŅĐ´ĐŊŅŅ
ŅŅСĐĩŅвОвŅŅ
ĐēĐžĐŋŅĐš Đ´ĐģŅ ĐˇĐ°Ņ
аваĐŊĐŊŅ",
|
"backup_keep_last_amount": "ĐĐžĐģŅĐēаŅŅŅ ĐŋаĐŋŅŅŅĐ´ĐŊŅŅ
ŅŅСĐĩŅвОвŅŅ
ĐēĐžĐŋŅĐš Đ´ĐģŅ ĐˇĐ°Ņ
аваĐŊĐŊŅ",
|
||||||
"backup_settings": "ĐаĐģĐ°Đ´Ņ ŅŅСĐĩŅĐ˛ĐžĐ˛Đ°ĐŗĐ° ĐēаĐŋŅŅваĐŊĐŊŅ",
|
"backup_settings": "ĐаĐģĐ°Đ´Ņ ŅŅСĐĩŅĐ˛ĐžĐ˛Đ°ĐŗĐ° ĐēаĐŋŅŅваĐŊĐŊŅ",
|
||||||
"backup_settings_description": "ĐŅŅаваĐŊĐŊĐĩ ĐŊаĐģадаĐŧŅ ŅŅСĐĩŅваваĐŊĐŊŅ ĐąĐ°ĐˇŅ Đ´Đ°ĐŊŅŅ
.",
|
"backup_settings_description": "ĐŅŅаваĐŊĐŊĐĩ ĐŊаĐģадаĐŧŅ Đ´Đ°ĐŧĐŋа ĐąĐ°ĐˇŅ Đ´Đ°Đ´ĐˇĐĩĐŊŅŅ
. ĐаŅĐ˛Đ°ĐŗĐ°: ĐŗŅŅŅŅ ĐˇĐ°Đ´Đ°ŅŅ ĐŊĐĩ ĐēаĐŊŅŅаĐģŅŅŅŅа, Ņ Ņ Đ˛ŅĐŋадĐēŅ ĐŊŅŅдаŅŅ ĐŋавĐĩдаĐŧĐģĐĩĐŊĐŊĐĩ адĐŋŅаŅĐģĐĩĐŊа ĐŊĐĩ ĐąŅдСĐĩ.",
|
||||||
"cleared_jobs": "ĐŅŅŅŅаĐŊŅ ĐˇĐ°Đ´Đ°ĐŊĐŊŅ Đ´ĐģŅ: {job}",
|
"cleared_jobs": "ĐŅŅŅŅаĐŊŅ ĐˇĐ°Đ´Đ°ĐŊĐŊŅ Đ´ĐģŅ: {job}",
|
||||||
"config_set_by_file": "ĐаĐŊŅŅĐŗŅŅаŅŅŅ ĐˇĐ°ŅаС ŅŅŅаĐģŅваĐŊа ĐŋŅаС ŅаКĐģ ĐēаĐŊŅŅĐŗŅŅаŅŅŅ",
|
"config_set_by_file": "ĐаĐŊŅŅĐŗŅŅаŅŅŅ Ņ ĐˇĐ°ŅаС ŅŅŅаĐģŅваĐŊа ĐŋŅаС ŅаКĐģ ĐēаĐŊŅŅĐŗŅŅаŅŅŅ",
|
||||||
"confirm_delete_library": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ ŅŅĐž ĐļадаĐĩŅĐĩ вŅдаĐģŅŅŅ ĐąŅĐąĐģŅŅŅŅĐēŅ {library}?",
|
"confirm_delete_library": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ ŅŅĐž ĐļадаĐĩŅĐĩ вŅдаĐģŅŅŅ {library} ĐąŅĐąĐģŅŅŅŅĐēŅ?",
|
||||||
"confirm_delete_library_assets": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž Ņ
ĐžŅаŅĐĩ вŅдаĐģŅŅŅ ĐŗŅŅŅŅ ĐąŅĐąĐģŅŅŅŅĐēŅ? ĐŅŅа ĐŋŅŅвŅдСĐĩ да вŅдаĐģĐĩĐŊĐŊŅ {count, plural, one {# аĐēŅŅвŅ} other {ŅŅŅŅ
# аĐēŅŅваŅ}}, ŅĐēŅŅ ĐˇĐŧŅŅŅаŅŅŅа Ņ Immich, Ņ ĐŗŅŅа дСĐĩŅĐŊĐŊĐĩ ĐŊĐĩĐŧĐ°ĐŗŅŅĐŧа ĐąŅдСĐĩ адĐŧŅĐŊŅŅŅ. ФаКĐģŅ ĐˇĐ°ŅŅаĐŊŅŅŅа ĐŊа Đ´ŅŅĐēŅ.",
|
"confirm_delete_library_assets": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž Ņ
ĐžŅаŅĐĩ вŅдаĐģŅŅŅ ĐŗŅŅŅŅ ĐąŅĐąĐģŅŅŅŅĐēŅ? ĐŅŅа ĐŋŅŅвŅдСĐĩ да вŅдаĐģĐĩĐŊĐŊŅ {count, plural, one {# аĐēŅŅвŅ} other {ŅŅŅŅ
# аĐēŅŅваŅ}}, ŅĐēŅŅ ĐˇĐŧŅŅŅаŅŅŅа Ņ Immich, Ņ ĐŗŅŅа дСĐĩŅĐŊĐŊĐĩ ĐŊĐĩĐŧĐ°ĐŗŅŅĐŧа ĐąŅдСĐĩ адĐŧŅĐŊŅŅŅ. ФаКĐģŅ ĐˇĐ°ŅŅаĐŊŅŅŅа ĐŊа Đ´ŅŅĐēŅ.",
|
||||||
"confirm_email_below": "Đай ĐŋаŅвĐĩŅдСŅŅŅ, ŅвŅдСŅŅĐĩ \"{email}\" ĐŊŅĐļŅĐš",
|
"confirm_email_below": "Đай ĐŋаŅвĐĩŅдСŅŅŅ, ŅвŅдСŅŅĐĩ \"{email}\" ĐŊŅĐļŅĐš",
|
||||||
"confirm_reprocess_all_faces": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž Ņ
ĐžŅаŅĐĩ ĐŋĐĩŅааĐŋŅаŅаваŅŅ ŅŅĐĩ ŅваŅŅ? ĐŅŅа ŅаĐēŅаĐŧа ĐŋŅŅвŅдСĐĩ да вŅдаĐģĐĩĐŊĐŊŅ ŅĐŧŅ ĐģŅдСĐĩĐš.",
|
"confirm_reprocess_all_faces": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž Ņ
ĐžŅаŅĐĩ ĐŋĐĩŅааĐŋŅаŅаваŅŅ ŅŅĐĩ ŅваŅŅ? ĐŅŅа ŅаĐēŅаĐŧа ĐŋŅŅвŅдСĐĩ да вŅдаĐģĐĩĐŊĐŊŅ ŅĐŧŅ ĐģŅдСĐĩĐš.",
|
||||||
"confirm_user_password_reset": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ Ņ ŅŅĐŧ, ŅŅĐž ĐļадаĐĩŅĐĩ ŅĐēŅĐŊŅŅŅ ĐŋаŅĐžĐģŅ {user}?",
|
"confirm_user_password_reset": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ Ņ ŅŅĐŧ, ŅŅĐž ĐļадаĐĩŅĐĩ ŅĐēŅĐŊŅŅŅ ĐŋаŅĐžĐģŅ {user}?",
|
||||||
"confirm_user_pin_code_reset": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ Ņ ŅŅĐŧ, ŅŅĐž ĐļадаĐĩŅĐĩ ŅĐēŅĐŊŅŅŅ PIN-ĐēОд {user}?",
|
|
||||||
"create_job": "ĐĄŅваŅŅŅŅ ĐˇĐ°Đ´Đ°ĐŊĐŊĐĩ",
|
"create_job": "ĐĄŅваŅŅŅŅ ĐˇĐ°Đ´Đ°ĐŊĐŊĐĩ",
|
||||||
"cron_expression": "ĐŅŅаС Cron",
|
"cron_expression": "ĐŅŅаС Cron",
|
||||||
"cron_expression_description": "ĐŖŅŅаĐģŅĐšŅĐĩ ŅĐŊŅŅŅваĐģ ŅĐēаĐŊаваĐŊĐŊŅ, вŅĐēаŅŅŅŅĐžŅваŅŅŅ ŅаŅĐŧĐ°Ņ cron. ĐĐģŅ Đ°ŅŅŅĐŧаĐŊĐŊŅ Đ´Đ°Đ´Đ°ŅĐēОваК ŅĐŊŅаŅĐŧаŅŅŅ, ĐēаĐģŅ ĐģаŅĐēа, СвŅŅĐŊŅŅĐĩŅŅ, ĐŊаĐŋŅŅĐēĐģад, да <link>Crontab Guru</link>",
|
"cron_expression_description": "ĐŖŅŅаĐģŅĐšŅĐĩ ŅĐŊŅŅŅваĐģ ŅĐēаĐŊаваĐŊĐŊŅ, вŅĐēаŅŅŅŅĐžŅваŅŅŅ ŅаŅĐŧĐ°Ņ cron. ĐĐģŅ Đ°ŅŅŅĐŧаĐŊĐŊŅ Đ´Đ°Đ´Đ°ŅĐēОваК ŅĐŊŅаŅĐŧаŅŅŅ, ĐēаĐģŅ ĐģаŅĐēа, СвŅŅĐŊŅŅĐĩŅŅ, ĐŊаĐŋŅŅĐēĐģад, да <link>Crontab Guru</link>",
|
||||||
"cron_expression_presets": "ĐŅадŅŅŅаĐŊĐžŅĐēŅ Đ˛ŅŅĐ°ĐˇĐ°Ņ Cron",
|
"cron_expression_presets": "ĐŅадŅŅŅаĐŊОвĐēŅ Đ˛ŅŅĐ°ĐˇĐ°Ņ Cron",
|
||||||
"disable_login": "ĐĐ´ĐēĐģŅŅŅŅŅ ŅваŅ
Од",
|
"disable_login": "ĐĐ´ĐēĐģŅŅŅŅŅ ŅваŅ
Од",
|
||||||
"duplicate_detection_job_description": "ĐаĐŋŅŅŅŅŅŅ ĐŧаŅŅĐŊĐŊаĐĩ ĐŊавŅŅаĐŊĐŊĐĩ ĐŊа аĐēŅŅваŅ
Đ´ĐģŅ Đ˛ŅŅŅĐģĐĩĐŊĐŊŅ ĐŋадОйĐŊŅŅ
вŅŅŅ. ĐаĐģĐĩĐļŅŅŅ Đ°Đ´ Smart Search",
|
"duplicate_detection_job_description": "ĐаĐŋŅŅŅŅŅŅ ĐŧаŅŅĐŊĐŊаĐĩ ĐŊавŅŅаĐŊĐŊĐĩ ĐŊа аĐēŅŅваŅ
Đ´ĐģŅ Đ˛ŅŅŅĐģĐĩĐŊĐŊŅ ĐŋадОйĐŊŅŅ
вŅŅŅ. ĐаĐģĐĩĐļŅŅŅ Đ°Đ´ Smart Search",
|
||||||
"exclusion_pattern_description": "ШайĐģĐžĐŊŅ Đ˛ŅĐēĐģŅŅŅĐŊĐŊŅ Đ´Đ°ĐˇĐ˛Đ°ĐģŅŅŅŅ ŅĐŗĐŊаŅаваŅŅ ŅаКĐģŅ Ņ ĐŋаĐŋĐēŅ ĐŋŅŅ ŅĐēаĐŊаваĐŊĐŊŅ Đ˛Đ°ŅаК ĐąŅĐąĐģŅŅŅŅĐēŅ. ĐŅŅа ĐēаŅŅŅĐŊа, ĐēаĐģŅ Ņ Đ˛Đ°Ņ ŅŅŅŅ ĐŋаĐŋĐēŅ, ŅĐēŅŅ ĐˇĐŧŅŅŅаŅŅŅ ŅаКĐģŅ, ŅĐēŅŅ Đ˛Ņ ĐŊĐĩ Ņ
ĐžŅаŅĐĩ ŅĐŧĐŋаŅŅаваŅŅ, ĐŊаĐŋŅŅĐēĐģад, ŅаКĐģŅ RAW.",
|
"exclusion_pattern_description": "ШайĐģĐžĐŊŅ Đ˛ŅĐēĐģŅŅŅĐŊĐŊŅ Đ´Đ°ĐˇĐ˛Đ°ĐģŅŅŅŅ ŅĐŗĐŊаŅаваŅŅ ŅаКĐģŅ Ņ ĐŋаĐŋĐēŅ ĐŋŅŅ ŅĐēаĐŊаваĐŊĐŊŅ Đ˛Đ°ŅаК ĐąŅĐąĐģŅŅŅŅĐēŅ. ĐŅŅа ĐēаŅŅŅĐŊа, ĐēаĐģŅ Ņ Đ˛Đ°Ņ ŅŅŅŅ ĐŋаĐŋĐēŅ, ŅĐēŅŅ ĐˇĐŧŅŅŅаŅŅŅ ŅаКĐģŅ, ŅĐēŅŅ Đ˛Ņ ĐŊĐĩ Ņ
ĐžŅаŅĐĩ ŅĐŧĐŋаŅŅаваŅŅ, ĐŊаĐŋŅŅĐēĐģад, ŅаКĐģŅ RAW.",
|
||||||
@@ -74,361 +71,15 @@
|
|||||||
"image_fullsize_enabled_description": "ĐĄŅваŅаŅŅ Đ˛ŅŅĐ˛Ņ Ņ ĐŋĐžŅĐŊŅĐŧ ĐŋаĐŧĐĩŅŅ Đ´ĐģŅ ŅаŅĐŧаŅаŅ, ŅŅĐž ĐŊĐĩ ĐŋŅŅдаŅĐŊŅŅ Đ´ĐģŅ Đ˛ŅĐą. ĐаĐģŅ ŅĐēĐģŅŅаĐŊа ĐžĐŋŅŅŅ \"ĐддаваŅŅ ĐŋĐĩŅĐ°Đ˛Đ°ĐŗŅ ŅĐąŅдаваĐŊаК ĐŋŅаŅвĐĩ\", ĐŋŅĐ°ĐŗĐģŅĐ´Ņ Đ˛ŅĐēаŅŅŅŅĐžŅваŅŅŅа ĐŊĐĩĐŋаŅŅŅĐ´ĐŊа ĐąĐĩС ĐēаĐŊвĐĩŅŅаŅŅŅ. ĐĐĩ ŅĐŋĐģŅваĐĩ ĐŊа вŅĐą-ĐŋŅŅдаŅĐŊŅŅ ŅаŅĐŧаŅŅ, ŅаĐēŅŅ ŅĐē JPEG.",
|
"image_fullsize_enabled_description": "ĐĄŅваŅаŅŅ Đ˛ŅŅĐ˛Ņ Ņ ĐŋĐžŅĐŊŅĐŧ ĐŋаĐŧĐĩŅŅ Đ´ĐģŅ ŅаŅĐŧаŅаŅ, ŅŅĐž ĐŊĐĩ ĐŋŅŅдаŅĐŊŅŅ Đ´ĐģŅ Đ˛ŅĐą. ĐаĐģŅ ŅĐēĐģŅŅаĐŊа ĐžĐŋŅŅŅ \"ĐддаваŅŅ ĐŋĐĩŅĐ°Đ˛Đ°ĐŗŅ ŅĐąŅдаваĐŊаК ĐŋŅаŅвĐĩ\", ĐŋŅĐ°ĐŗĐģŅĐ´Ņ Đ˛ŅĐēаŅŅŅŅĐžŅваŅŅŅа ĐŊĐĩĐŋаŅŅŅĐ´ĐŊа ĐąĐĩС ĐēаĐŊвĐĩŅŅаŅŅŅ. ĐĐĩ ŅĐŋĐģŅваĐĩ ĐŊа вŅĐą-ĐŋŅŅдаŅĐŊŅŅ ŅаŅĐŧаŅŅ, ŅаĐēŅŅ ŅĐē JPEG.",
|
||||||
"image_fullsize_quality_description": "Đ¯ĐēаŅŅŅ Đ˛ŅŅĐ˛Ņ Ņ ĐŋĐžŅĐŊŅĐŧ ĐŋаĐŧĐĩŅŅ Đ°Đ´ 1 да 100. ĐĐžĐģŅŅ Đ˛ŅŅĐžĐēаĐĩ СĐŊаŅŅĐŊĐŊĐĩ ĐģĐĩĐŋŅаĐĩ, аĐģĐĩ ĐŋŅŅвОдСŅŅŅ Đ´Đ° ĐŋавĐĩĐģŅŅŅĐŊĐŊŅ ĐŋаĐŧĐĩŅŅ ŅаКĐģа.",
|
"image_fullsize_quality_description": "Đ¯ĐēаŅŅŅ Đ˛ŅŅĐ˛Ņ Ņ ĐŋĐžŅĐŊŅĐŧ ĐŋаĐŧĐĩŅŅ Đ°Đ´ 1 да 100. ĐĐžĐģŅŅ Đ˛ŅŅĐžĐēаĐĩ СĐŊаŅŅĐŊĐŊĐĩ ĐģĐĩĐŋŅаĐĩ, аĐģĐĩ ĐŋŅŅвОдСŅŅŅ Đ´Đ° ĐŋавĐĩĐģŅŅŅĐŊĐŊŅ ĐŋаĐŧĐĩŅŅ ŅаКĐģа.",
|
||||||
"image_fullsize_title": "ĐаĐģĐ°Đ´Ņ Đ˛ŅŅĐ˛Ņ Ņ ĐŋĐžŅĐŊŅĐŧ ĐŋаĐŧĐĩŅŅ",
|
"image_fullsize_title": "ĐаĐģĐ°Đ´Ņ Đ˛ŅŅĐ˛Ņ Ņ ĐŋĐžŅĐŊŅĐŧ ĐŋаĐŧĐĩŅŅ",
|
||||||
"image_prefer_embedded_preview": "ĐддаваŅŅ ĐŋĐĩŅĐ°Đ˛Đ°ĐŗŅ ŅĐąŅдаваĐŊаК ĐŋŅаŅвĐĩ",
|
|
||||||
"image_prefer_embedded_preview_setting_description": "ĐŅĐēаŅŅŅŅĐžŅваŅŅ ŅĐąŅдаваĐŊŅŅ ĐŋŅаŅĐ˛Ņ Ņ RAW-ŅĐžŅаСдŅĐŧĐēаŅ
Ņ ŅĐēаŅŅŅ ŅваŅ
ОдĐŊŅŅ
дадСĐĩĐŊŅŅ
Đ´ĐģŅ Đ°ĐŋŅаŅĐžŅĐēŅ ĐŧаĐģŅĐŊĐēаŅ, ĐēаĐģŅ ĐŧĐ°ĐŗŅŅĐŧа. ĐŅŅа даСваĐģŅĐĩ аŅŅŅĐŧаŅŅ ĐąĐžĐģŅŅ Đ´Đ°ĐēĐģадĐŊŅŅ ĐēĐžĐģĐĩŅŅ Đ´ĐģŅ ĐŊĐĩĐēаŅĐžŅŅŅ
вŅдаŅŅŅаŅ, аĐģĐĩ Đļ ŅĐēаŅŅŅ ĐŋŅаŅŅ ĐˇĐ°ĐģĐĩĐļŅŅŅ Đ°Đ´ ĐēаĐŧĐĩŅŅ, Ņ ĐŊа вŅдаŅŅŅĐĩ ĐŧĐžĐļа ĐąŅŅŅ ĐąĐžĐģŅŅ Đ°ŅŅŅŅаĐēŅĐ°Ņ ŅŅŅŅĐēŅ.",
|
|
||||||
"image_prefer_wide_gamut": "ĐддаŅŅ ĐŋĐĩŅĐ°Đ˛Đ°ĐŗŅ ŅŅŅĐžĐēаК ĐŗĐ°ĐŧĐĩ",
|
|
||||||
"image_preview_description": "ĐŅдаŅŅŅ ŅŅŅŅĐ´ĐŊŅĐŗĐ° ĐŋаĐŧĐĩŅŅ Đˇ вŅдаĐģĐĩĐŊŅĐŧŅ ĐŧĐĩŅададСĐĩĐŊŅĐŧŅ, вŅĐēаŅŅŅŅĐžŅваĐĩŅŅа ĐŋŅŅ ĐŋŅĐ°ĐŗĐģŅдСĐĩ аŅОйĐŊĐ°ĐŗĐ° ŅŅŅŅŅŅŅ Ņ Đ´ĐģŅ ĐŧаŅŅĐŊĐŊĐ°ĐŗĐ° ĐŊавŅŅаĐŊĐŊŅ",
|
|
||||||
"image_preview_quality_description": "Đ¯ĐēаŅŅŅ ĐŋŅаŅĐ˛Ņ Đ°Đ´ 1 да 100. ЧŅĐŧ вŅŅŅĐš, ŅŅĐŧ ĐģĐĩĐŋŅ, аĐģĐĩ ĐŋŅŅ ĐŗŅŅŅĐŧ ŅŅваŅаŅŅŅа ŅаКĐģŅ ĐąĐžĐģŅŅĐ°ĐŗĐ° ĐŋаĐŧĐĩŅŅ Ņ ĐŧĐžĐļа СĐŊŅСŅŅŅа Ņ
ŅŅĐēаŅŅŅ Đ˛ĐžĐ´ĐŗŅĐēŅ ĐŋŅŅĐēĐģадаĐŊĐŊŅ. ĐŅŅаĐŊĐžŅĐēа ĐŊŅСĐēĐ°ĐŗĐ° СĐŊаŅŅĐŊĐŊŅ ĐŧĐžĐļа ĐŋаŅĐŋĐģŅваŅŅ ĐŊа ŅĐēаŅŅŅ ĐŧаŅŅĐŊĐŊĐ°ĐŗĐ° ĐŊавŅŅаĐŊĐŊŅ.",
|
|
||||||
"image_preview_title": "ĐаĐģĐ°Đ´Ņ ĐŋаĐŋŅŅŅĐ´ĐŊŅĐŗĐ° ĐŋŅĐ°ĐŗĐģŅĐ´Ņ",
|
"image_preview_title": "ĐаĐģĐ°Đ´Ņ ĐŋаĐŋŅŅŅĐ´ĐŊŅĐŗĐ° ĐŋŅĐ°ĐŗĐģŅĐ´Ņ",
|
||||||
"image_quality": "Đ¯ĐēаŅŅŅ",
|
"image_quality": "Đ¯ĐēаŅŅŅ",
|
||||||
"image_resolution": "РаСдСŅĐģŅĐģŅĐŊаŅŅŅ",
|
"image_resolution": "РаСдСŅĐģŅĐģŅĐŊаŅŅŅ",
|
||||||
"image_settings": "ĐаĐģĐ°Đ´Ņ Đ˛ŅдаŅŅŅа",
|
"image_settings": "ĐаĐģĐ°Đ´Ņ Đ˛ŅдаŅŅŅа",
|
||||||
"image_settings_description": "ĐŅŅŅĐšŅĐĩ ŅĐēаŅŅŅ Ņ ŅаСдСŅĐģŅĐģŅĐŊаŅŅŅ ŅĐŗĐĩĐŊĐĩŅŅŅаваĐŊŅŅ
вŅдаŅŅŅаŅ",
|
"image_settings_description": "ĐŅŅŅĐšŅĐĩ ŅĐēаŅŅŅ Ņ ŅаСдСŅĐģŅĐģŅĐŊаŅŅŅ ŅĐŗĐĩĐŊĐĩŅŅŅаваĐŊŅŅ
вŅдаŅŅŅаŅ"
|
||||||
"library_created": "ĐĄŅвОŅаĐŊа ĐąŅĐąĐģŅŅŅŅĐēа: {library}",
|
|
||||||
"library_deleted": "ĐŅĐąĐģŅŅŅŅĐēа вŅдаĐģĐĩĐŊа",
|
|
||||||
"map_dark_style": "ĐĻŅĐŧĐŊŅ ŅŅŅĐģŅ",
|
|
||||||
"map_enable_description": "ĐŖĐēĐģŅŅŅŅŅ ŅŅĐŊĐēŅŅŅ ĐēаŅŅŅ",
|
|
||||||
"map_gps_settings": "ĐаĐģĐ°Đ´Ņ ĐēаŅŅŅ Ņ GPS",
|
|
||||||
"map_light_style": "ХвĐĩŅĐģŅ ŅŅŅĐģŅ",
|
|
||||||
"map_settings": "ĐаŅŅа",
|
|
||||||
"map_settings_description": "ĐŅŅаваĐŊĐŊĐĩ ĐŊаĐģадаĐŧŅ ĐēаŅŅŅ",
|
|
||||||
"map_style_description": "URL-адŅĐ°Ņ style.json ŅŅĐŧŅ ĐēаŅŅŅ",
|
|
||||||
"metadata_settings": "ĐаĐģĐ°Đ´Ņ ĐŧĐĩŅадаĐŊŅŅ
",
|
|
||||||
"oauth_button_text": "ĐĸŅĐēŅŅ ĐēĐŊĐžĐŋĐēŅ",
|
|
||||||
"oauth_settings": "OAuth",
|
|
||||||
"refreshing_all_libraries": "ĐĐąĐŊаŅĐģĐĩĐŊĐŊĐĩ ŅŅŅŅ
ĐąŅĐąĐģŅŅŅŅĐē",
|
|
||||||
"registration": "Đ ŅĐŗŅŅŅŅаŅŅŅ Đ°Đ´ĐŧŅĐŊŅŅŅŅаŅаŅа",
|
|
||||||
"registration_description": "ĐŅ Đˇ'ŅŅĐģŅĐĩŅĐĩŅŅ ĐŋĐĩŅŅŅĐŧ ĐēаŅŅŅŅаĐģŅĐŊŅĐēаĐŧ ŅŅŅŅŅĐŧŅ, ŅаĐŧŅ Đ˛Ņ ĐąŅдСĐĩŅĐĩ ĐŋŅŅСĐŊаŅаĐŊŅ Đ°Đ´ĐŧŅĐŊŅŅŅŅаŅаŅаĐŧ. ĐŅ ĐąŅдСĐĩŅĐĩ адĐēаСваŅŅ ĐˇĐ° адĐŧŅĐŊŅŅŅŅаŅŅĐšĐŊŅŅ ĐˇĐ°Đ´Đ°ŅŅ, а ŅаĐēŅаĐŧа ŅŅваŅаŅŅ ĐŊОвŅŅ
ĐēаŅŅŅŅаĐģŅĐŊŅĐēаŅ.",
|
|
||||||
"require_password_change_on_login": "ĐаŅŅайаваŅŅ ĐˇĐŧŅĐŊŅŅŅ ĐŋаŅĐžĐģŅ ĐŋŅŅ ĐŋĐĩŅŅŅĐŧ ŅваŅ
ОдСĐĩ Ņ ŅŅŅŅŅĐŧŅ",
|
|
||||||
"reset_settings_to_default": "ĐĄĐēŅĐŊŅŅŅ ĐŊаĐģĐ°Đ´Ņ Đ´Đ° ĐŋŅадвŅСĐŊаŅаĐŊŅŅ
",
|
|
||||||
"reset_settings_to_recent_saved": "ĐĄĐēŅĐŊŅŅŅ ĐŊаĐģĐ°Đ´Ņ Đ´Đ° ĐŊŅдаŅĐŊа СаŅ
аваĐŊŅŅ
",
|
|
||||||
"scanning_library": "ĐĄĐēаĐŊŅŅаваĐŊĐŊĐĩ ĐąŅĐąĐģŅŅŅŅĐēŅ",
|
|
||||||
"server_external_domain_settings": "ĐĐŊĐĩŅĐŊŅ Đ´Đ°ĐŧĐĩĐŊ",
|
|
||||||
"server_settings": "ĐаĐģĐ°Đ´Ņ ŅĐĩŅвĐĩŅа",
|
|
||||||
"server_settings_description": "ĐŅŅаваĐŊĐŊĐĩ ĐŊаĐģадаĐŧŅ ŅĐĩŅвĐĩŅа",
|
|
||||||
"server_welcome_message": "ĐŅŅвŅŅаĐģŅĐŊаĐĩ ĐŋавĐĩдаĐŧĐģĐĩĐŊĐŊĐĩ",
|
|
||||||
"server_welcome_message_description": "ĐавĐĩдаĐŧĐģĐĩĐŊĐŊĐĩ, ŅĐēĐžĐĩ адĐģŅŅŅŅĐžŅваĐĩŅŅа ĐŊа ŅŅаŅĐžĐŊŅŅ ŅваŅ
ОдŅ.",
|
|
||||||
"system_settings": "ĐĄŅŅŅŅĐŧĐŊŅŅ ĐŊаĐģадŅ",
|
|
||||||
"tag_cleanup_job": "ĐŅŅŅŅĐēа ŅŅĐŗĐ°Ņ",
|
|
||||||
"template_email_preview": "ĐĐĩŅадĐŋŅĐ°ĐŗĐģŅĐ´",
|
|
||||||
"theme_settings": "ĐаĐģĐ°Đ´Ņ ŅŅĐŧŅ",
|
|
||||||
"transcoding_acceleration_nvenc": "NVENC (ĐŋаŅŅайŅĐĩŅŅа вŅĐ´ŅаĐēаŅŅа NVIDIA)",
|
|
||||||
"transcoding_acceleration_vaapi": "VAAPI",
|
|
||||||
"transcoding_accepted_containers": "ĐŅŅĐŊŅŅŅŅ ĐēаĐŊŅŅĐšĐŊĐĩŅŅ",
|
|
||||||
"transcoding_accepted_video_codecs": "ĐŅŅĐŊŅŅŅŅ Đ˛ŅĐ´ŅаĐēОдŅĐēŅ",
|
|
||||||
"transcoding_advanced_options_description": "ĐаŅаĐŧĐĩŅŅŅ, ŅĐēŅŅ ĐąĐžĐģŅŅаŅŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēĐ°Ņ ĐŊĐĩ ŅŅŅйа СĐŧŅĐŊŅŅŅ",
|
|
||||||
"transcoding_audio_codec": "ĐŅĐ´ŅŅĐēОдŅĐē",
|
|
||||||
"transcoding_encoding_options": "ĐаŅаĐŧĐĩŅŅŅ ĐēадСŅŅаваĐŊĐŊŅ",
|
|
||||||
"transcoding_video_codec": "ĐŅĐ´ŅаĐēОдŅĐē",
|
|
||||||
"trash_enabled_description": "ĐŖĐēĐģŅŅŅŅŅ ŅŅĐŊĐēŅŅŅ ŅĐŧĐĩŅĐŊŅŅŅ",
|
|
||||||
"trash_number_of_days": "ĐĐžĐģŅĐēаŅŅŅ Đ´ĐˇŅĐŊ",
|
|
||||||
"trash_settings": "ĐаĐģĐ°Đ´Ņ ŅĐŧĐĩŅĐŊŅŅŅ",
|
|
||||||
"trash_settings_description": "ĐŅŅаваĐŊĐŊĐĩ ĐŊаĐģадаĐŧŅ ŅĐŧĐĩŅĐŊŅŅŅ",
|
|
||||||
"user_cleanup_job": "ĐŅŅŅŅĐēа ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
|
||||||
"user_management": "ĐŅŅаваĐŊĐŊĐĩ ĐēаŅŅŅŅаĐģŅĐŊŅĐēаĐŧŅ",
|
|
||||||
"user_password_has_been_reset": "ĐаŅĐžĐģŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа ĐąŅŅ ŅĐēŅĐŊŅŅŅ:",
|
|
||||||
"user_password_reset_description": "ĐадаКŅĐĩ ĐēаŅŅŅŅаĐģŅĐŊŅĐēŅ ŅаŅĐžĐ˛Ņ ĐŋаŅĐžĐģŅ Ņ ĐŋавĐĩдаĐŧŅŅĐĩ ŅĐŧŅ, ŅŅĐž ĐŋŅŅ ĐŊаŅŅŅĐŋĐŊŅĐŧ ŅваŅ
ОдСĐĩ Ņ ŅŅŅŅŅĐŧŅ ŅĐŧŅ ŅŅŅйа ĐąŅдСĐĩ СĐŧŅĐŊŅŅŅ ĐŋаŅĐžĐģŅ.",
|
|
||||||
"user_restore_description": "ĐŖĐģŅĐēĐžĐ˛Ņ ĐˇĐ°ĐŋŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа <b>{user}</b> ĐąŅдСĐĩ адĐŊĐžŅĐģĐĩĐŊŅ.",
|
|
||||||
"user_settings": "ĐаĐģĐ°Đ´Ņ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
|
||||||
"user_settings_description": "ĐŅŅаваĐŊĐŊĐĩ ĐŊаĐģадаĐŧŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
|
||||||
"user_successfully_removed": "ĐаŅŅŅŅаĐģŅĐŊŅĐē {email} ĐąŅŅ ĐŋаŅĐŋŅŅ
Ова вŅдаĐģĐĩĐŊŅ.",
|
|
||||||
"version_check_enabled_description": "ĐŖĐēĐģŅŅŅŅŅ ĐŋŅавĐĩŅĐēŅ Đ˛ĐĩŅŅŅŅ",
|
|
||||||
"version_check_implications": "ФŅĐŊĐēŅŅŅ ĐŋŅавĐĩŅĐēŅ Đ˛ĐĩŅŅŅŅ ĐŋĐĩŅŅŅĐ´ŅŅĐŊа СвŅŅŅаĐĩŅŅа да github.com",
|
|
||||||
"version_check_settings": "ĐŅавĐĩŅĐēа вĐĩŅŅŅŅ",
|
|
||||||
"version_check_settings_description": "ĐŖĐēĐģŅŅŅŅŅ/адĐēĐģŅŅŅŅŅ Đ°ĐŋавŅŅŅŅĐŊĐŊŅ Đ°Đą ĐŊОваК вĐĩŅŅŅŅ"
|
|
||||||
},
|
},
|
||||||
"admin_email": "ĐĐģĐĩĐēŅŅĐžĐŊĐŊĐ°Ņ ĐŋĐžŅŅа адĐŧŅĐŊŅŅŅŅаŅаŅа",
|
|
||||||
"admin_password": "ĐаŅĐžĐģŅ Đ°Đ´ĐŧŅĐŊŅŅŅŅаŅаŅа",
|
|
||||||
"administration": "ĐŅŅаваĐŊĐŊĐĩ ŅĐĩŅвĐĩŅаĐŧ",
|
|
||||||
"advanced": "ĐаŅŅŅаĐŊŅŅ",
|
|
||||||
"advanced_settings_log_level_title": "ĐŖĐˇŅОвĐĩĐŊŅ Đ˛ŅдСĐĩĐŊĐŊŅ ĐļŅŅĐŊаĐģа: {level}",
|
|
||||||
"advanced_settings_proxy_headers_title": "ĐĐ°ĐŗĐ°ĐģĐžŅĐēŅ ĐŋŅĐžĐēŅŅ",
|
|
||||||
"advanced_settings_tile_subtitle": "ĐаŅŅŅаĐŊŅŅ ĐŊаĐģĐ°Đ´Ņ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
|
||||||
"advanced_settings_troubleshooting_subtitle": "ĐŖĐēĐģŅŅŅŅŅ Đ´Đ°Đ´Đ°ŅĐēОвŅŅ ŅŅĐŊĐēŅŅŅ Đ´ĐģŅ Đ˛ŅĐŋŅаŅĐģĐĩĐŊĐŊŅ ĐŊĐĩĐŋаĐģадаĐē",
|
|
||||||
"advanced_settings_troubleshooting_title": "ĐŅĐŋŅаŅĐģĐĩĐŊĐŊĐĩ ĐŊĐĩĐŋаĐģадаĐē",
|
|
||||||
"age_months": "ĐŖĐˇŅĐžŅŅ {months, plural, one {# ĐŧĐĩŅŅŅ} few {# ĐŧĐĩŅŅŅŅ} many {# ĐŧĐĩŅŅŅаŅ} other {# ĐŧĐĩŅŅŅаŅ}}",
|
|
||||||
"age_year_months": "ĐŖĐˇŅĐžŅŅ 1 ĐŗĐžĐ´, {months, plural, one {# ĐŧĐĩŅŅŅ} few {# ĐŧĐĩŅŅŅŅ} many {# ĐŧĐĩŅŅŅаŅ} other {# ĐŧĐĩŅŅŅаŅ}}",
|
|
||||||
"age_years": "{years, plural, other {ĐŖĐˇŅĐžŅŅ #}}",
|
|
||||||
"album_added": "ĐĐģŅйОĐŧ дададСĐĩĐŊŅ",
|
|
||||||
"album_cover_updated": "ĐĐžĐēĐģадĐēа аĐģŅйОĐŧа айĐŊĐžŅĐģĐĩĐŊа",
|
|
||||||
"album_delete_confirmation": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž Ņ
ĐžŅаŅĐĩ вŅдаĐģŅŅŅ Đ°ĐģŅйОĐŧ {album}?",
|
|
||||||
"album_delete_confirmation_description": "ĐаĐģŅ ĐŗŅŅŅ Đ°ĐģŅйОĐŧ Đ°ĐąĐ°ĐŗŅĐģĐĩĐŊŅ, ŅĐŊŅŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēŅ ĐąĐžĐģŅŅ ĐŊĐĩ СĐŧĐžĐŗŅŅŅ Đ°ŅŅŅĐŧаŅŅ Đ´Đ° ŅĐŗĐž Đ´ĐžŅŅŅĐŋ.",
|
|
||||||
"album_deleted": "ĐĐģŅйОĐŧ вŅдаĐģĐĩĐŊŅ",
|
|
||||||
"album_info_card_backup_album_excluded": "ĐĐĢĐĐЎЧĐĐĐĢ",
|
|
||||||
"album_info_card_backup_album_included": "ĐŖĐĐЎЧĐĐĐĢ",
|
|
||||||
"album_info_updated": "ĐĐŊŅаŅĐŧаŅŅŅ ĐŋŅа аĐģŅйОĐŧ айĐŊĐžŅĐģĐĩĐŊа",
|
|
||||||
"album_leave": "ĐаĐēŅĐŊŅŅŅ Đ°ĐģŅйОĐŧ?",
|
|
||||||
"album_leave_confirmation": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž Ņ
ĐžŅаŅĐĩ ĐŋаĐēŅĐŊŅŅŅ {album}?",
|
|
||||||
"album_name": "ĐаСва аĐģŅйОĐŧа",
|
|
||||||
"album_options": "ĐаŅаĐŧĐĩŅŅŅ Đ°ĐģŅйОĐŧа",
|
|
||||||
"album_remove_user": "ĐŅдаĐģŅŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа?",
|
|
||||||
"album_remove_user_confirmation": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž Ņ
ĐžŅаŅĐĩ вŅдаĐģŅŅŅ {user}?",
|
|
||||||
"album_search_not_found": "Đа ваŅŅĐŧ СаĐŋŅŅĐĩ ĐŊĐĩ СĐŊОКдСĐĩĐŊа аĐģŅйОĐŧаŅ",
|
|
||||||
"album_share_no_users": "ĐдаĐĩŅŅа, Đ˛Ņ ĐŋадСŅĐģŅĐģŅŅŅ ĐŗŅŅŅĐŧ аĐģŅйОĐŧаĐŧ С ŅŅŅĐŧŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēаĐŧŅ, айО Ņ Đ˛Đ°Ņ ĐŊŅĐŧа ĐŊŅвОдĐŊĐ°ĐŗĐ° ĐēаŅŅŅŅаĐģŅĐŊŅĐēа, С ŅĐēŅĐŧ ĐŧĐžĐļĐŊа ĐŋадСŅĐģŅŅŅа.",
|
|
||||||
"album_updated": "ĐĐģŅйОĐŧ айĐŊĐžŅĐģĐĩĐŊŅ",
|
|
||||||
"album_user_left": "ĐŅ ĐŋаĐēŅĐŊŅĐģŅ {album}",
|
|
||||||
"album_user_removed": "ĐаŅŅŅŅаĐģŅĐŊŅĐē {user} вŅдаĐģĐĩĐŊŅ",
|
|
||||||
"album_viewer_appbar_delete_confirm": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž Ņ
ĐžŅаŅĐĩ вŅдаĐģŅŅŅ ĐŗŅŅŅ Đ°ĐģŅйОĐŧ Ņа ŅĐ˛Đ°ĐšĐŗĐž ŅĐģŅĐēĐžĐ˛Đ°ĐŗĐ° СаĐŋŅŅŅ?",
|
|
||||||
"album_viewer_appbar_share_err_delete": "ĐĐĩ ŅдаĐģĐžŅŅ Đ˛ŅдаĐģŅŅŅ Đ°ĐģŅйОĐŧ",
|
|
||||||
"album_viewer_appbar_share_err_leave": "ĐĐĩ ŅдаĐģĐžŅŅ ĐŋаĐēŅĐŊŅŅŅ Đ°ĐģŅйОĐŧ",
|
|
||||||
"album_viewer_appbar_share_err_title": "ĐĐĩ ŅдаĐģĐžŅŅ ĐˇĐŧŅĐŊŅŅŅ ĐŊĐ°ĐˇĐ˛Ņ Đ°ĐģŅйОĐŧа",
|
|
||||||
"album_viewer_appbar_share_leave": "ĐаĐēŅĐŊŅŅŅ Đ°ĐģŅйОĐŧ",
|
|
||||||
"album_viewer_appbar_share_to": "ĐĐąĐ°ĐŗŅĐģŅŅŅ Đˇ",
|
|
||||||
"album_viewer_page_share_add_users": "ĐадаŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēаŅ",
|
|
||||||
"album_with_link_access": "ĐаСвОĐģŅŅŅ ŅŅŅĐŧ, Ņ
ŅĐž ĐŧаĐĩ ŅĐŋаŅŅĐģĐēŅ, йаŅŅŅŅ ŅĐžŅа Ņ ĐģŅдСĐĩĐš Ņ ĐŗŅŅŅĐŧ аĐģŅйОĐŧĐĩ.",
|
|
||||||
"albums": "ĐĐģŅйОĐŧŅ",
|
|
||||||
"albums_count": "{count, plural, one {1 аĐģŅйОĐŧ} few {{count, number} аĐģŅйОĐŧŅ} many {{count, number} аĐģŅйОĐŧаŅ} other {{count, number} аĐģŅйОĐŧаŅ}}",
|
|
||||||
"albums_default_sort_order": "ĐŅадвŅСĐŊаŅаĐŊŅ ĐŋаŅадаĐē ŅаŅŅаваĐŊĐŊŅ Đ°ĐģŅйОĐŧаŅ",
|
|
||||||
"albums_on_device_count": "ĐĐģŅйОĐŧŅ ĐŊа ĐŋŅŅĐģадСĐĩ ({count})",
|
|
||||||
"all": "ĐŖŅĐĩ",
|
|
||||||
"all_albums": "ĐŖŅĐĩ аĐģŅйОĐŧŅ",
|
|
||||||
"all_people": "ĐŖŅĐĩ ĐģŅдСŅ",
|
|
||||||
"all_videos": "ĐŖŅĐĩ вŅĐ´Ņа",
|
|
||||||
"allow_dark_mode": "ĐаСвОĐģŅŅŅ ŅŅĐŧĐŊŅ ŅŅĐļŅĐŧ",
|
|
||||||
"allow_edits": "ĐаСвОĐģŅŅŅ ŅŅĐ´Đ°ĐŗĐ°Đ˛Đ°ĐŊĐŊĐĩ",
|
|
||||||
"alt_text_qr_code": "ĐŅдаŅŅŅ QR-ĐēОда",
|
|
||||||
"anti_clockwise": "ĐĄŅĐŋŅаŅŅ ĐŗĐ°Đ´ĐˇŅĐŊĐŊŅĐēаваК ŅŅŅŅĐģĐēŅ",
|
|
||||||
"api_key": "ĐĐģŅŅ API",
|
|
||||||
"api_key_empty": "ĐаСва ĐēĐģŅŅа API ĐŊĐĩ ĐŋавŅĐŊĐŊа ĐąŅŅŅ ĐŋŅŅŅОК",
|
|
||||||
"api_keys": "ĐĐģŅŅŅ API",
|
|
||||||
"app_bar_signout_dialog_content": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž Ņ
ĐžŅаŅĐĩ вŅĐšŅŅŅ?",
|
|
||||||
"app_bar_signout_dialog_ok": "ĐĸаĐē",
|
|
||||||
"app_bar_signout_dialog_title": "ĐŅĐšŅŅŅ",
|
|
||||||
"app_settings": "ĐаĐģĐ°Đ´Ņ ĐŋŅĐ°ĐŗŅаĐŧŅ",
|
|
||||||
"archive": "ĐŅŅ
ŅŅ",
|
|
||||||
"archive_page_title": "ĐŅŅ
ŅŅ ({count})",
|
|
||||||
"archive_size": "ĐаĐŧĐĩŅ Đ°ŅŅ
Ņва",
|
|
||||||
"are_these_the_same_person": "ĐĻŅ ĐŗŅŅа адСŅĐŊ Ņ ŅОК Đļа ŅаĐģавĐĩĐē?",
|
|
||||||
"are_you_sure_to_do_this": "ĐŅ ŅĐŋŅŅĐŊĐĩĐŊŅ, ŅŅĐž Ņ
ĐžŅаŅĐĩ ĐŗŅŅа СŅайŅŅŅ?",
|
|
||||||
"asset_added_to_album": "ĐададСĐĩĐŊа Ņ Đ°ĐģŅйОĐŧ",
|
|
||||||
"asset_adding_to_album": "ĐадаваĐŊĐŊĐĩ Ņ Đ°ĐģŅйОĐŧâĻ",
|
|
||||||
"asset_skipped": "ĐŅаĐŋŅŅŅаĐŊа",
|
|
||||||
"asset_skipped_in_trash": "ĐŖ ŅĐŧĐĩŅĐŊŅŅŅ",
|
|
||||||
"asset_uploaded": "ĐаĐŋаĐŧĐŋаваĐŊа",
|
|
||||||
"asset_uploading": "ĐаĐŋаĐŧĐŋĐžŅваĐŊĐŊĐĩâĻ",
|
|
||||||
"authorized_devices": "ĐŅŅаŅŅСаваĐŊŅŅ ĐŋŅŅĐģадŅ",
|
|
||||||
"back": "ĐаСад",
|
|
||||||
"backup_album_selection_page_albums_device": "ĐĐģŅйОĐŧŅ ĐŊа ĐŋŅŅĐģадСĐĩ ({count})",
|
|
||||||
"backup_all": "ĐŖŅĐĩ",
|
|
||||||
"backup_controller_page_background_wifi": "ĐĸĐžĐģŅĐēŅ ĐŋŅаС Wi-Fi",
|
|
||||||
"buy": "ĐŅĐŋŅŅŅ Immich",
|
|
||||||
"cache_settings_clear_cache_button": "ĐŅŅŅŅŅŅŅ ĐēŅŅ",
|
|
||||||
"cache_settings_tile_title": "ĐаĐēаĐģŅĐŊаĐĩ ŅŅ
ОвŅŅŅа",
|
|
||||||
"cancel": "ĐĄĐēаŅаваŅŅ",
|
|
||||||
"cancel_search": "ĐĄĐēаŅаваŅŅ ĐŋĐžŅŅĐē",
|
|
||||||
"canceled": "ĐĄĐēаŅаваĐŊа",
|
|
||||||
"city": "ĐĐžŅад",
|
|
||||||
"clear": "ĐŅŅŅŅŅŅŅ",
|
|
||||||
"clear_all": "ĐŅŅŅŅŅŅŅ ŅŅŅ",
|
|
||||||
"client_cert_dialog_msg_confirm": "ĐĐ",
|
|
||||||
"client_cert_enter_password": "ĐŖĐ˛ŅдСŅŅĐĩ ĐŋаŅĐžĐģŅ",
|
|
||||||
"client_cert_import": "ĐĐŧĐŋаŅŅ",
|
|
||||||
"close": "ĐаĐēŅŅŅŅ",
|
|
||||||
"collapse": "ĐĐŗĐ°ŅĐŊŅŅŅ",
|
|
||||||
"collapse_all": "ĐĐŗĐ°ŅĐŊŅŅŅ ŅŅŅ",
|
|
||||||
"color": "ĐĐžĐģĐĩŅ",
|
|
||||||
"color_theme": "ĐĐžĐģĐĩŅĐ°Đ˛Đ°Ņ ŅŅĐŧа",
|
|
||||||
"continue": "ĐŅаŅŅĐŗĐŊŅŅŅ",
|
|
||||||
"control_bottom_app_bar_create_new_album": "ĐĄŅваŅŅŅŅ ĐŊĐžĐ˛Ņ Đ°ĐģŅйОĐŧ",
|
|
||||||
"control_bottom_app_bar_delete_from_immich": "ĐŅдаĐģŅŅŅ Đˇ Immich",
|
|
||||||
"control_bottom_app_bar_delete_from_local": "ĐŅдаĐģŅŅŅ Đˇ ĐŋŅŅĐģадŅ",
|
|
||||||
"control_bottom_app_bar_edit_location": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ĐŧĐĩŅŅаСĐŊаŅ
ОдĐļаĐŊĐŊĐĩ",
|
|
||||||
"country": "ĐŅаŅĐŊа",
|
|
||||||
"cover": "ĐĐžĐēĐģадĐēа",
|
|
||||||
"covers": "ĐĐžĐēĐģадĐēŅ",
|
|
||||||
"create": "ĐĄŅваŅŅŅŅ",
|
|
||||||
"create_album": "ĐĄŅваŅŅŅŅ Đ°ĐģŅйОĐŧ",
|
|
||||||
"create_album_page_untitled": "ĐĐĩС ĐŊаСвŅ",
|
|
||||||
"create_library": "ĐĄŅваŅŅŅŅ ĐąŅĐąĐģŅŅŅŅĐēŅ",
|
|
||||||
"create_link": "ĐĄŅваŅŅŅŅ ŅĐŋаŅŅĐģĐēŅ",
|
|
||||||
"create_new_user": "ĐĄŅваŅŅŅŅ ĐŊĐžĐ˛Đ°ĐŗĐ° ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
|
||||||
"create_tag": "ĐĄŅваŅŅŅŅ ŅŅĐŗ",
|
|
||||||
"create_user": "ĐĄŅваŅŅŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
|
||||||
"dark": "ĐĻŅĐŧĐŊаŅ",
|
|
||||||
"day": "ĐСĐĩĐŊŅ",
|
|
||||||
"delete": "ĐŅдаĐģŅŅŅ",
|
|
||||||
"delete_album": "ĐŅдаĐģŅŅŅ Đ°ĐģŅйОĐŧ",
|
|
||||||
"delete_dialog_ok_force": "ĐŖŅŅ Đ°Đ´ĐŊĐž вŅдаĐģŅŅŅ",
|
|
||||||
"delete_dialog_title": "ĐŅдаĐģŅŅŅ ĐŊаСаŅĐļĐ´Ņ",
|
|
||||||
"delete_face": "ĐŅдаĐģŅŅŅ ŅваŅ",
|
|
||||||
"delete_key": "ĐŅдаĐģŅŅŅ ĐēĐģŅŅ",
|
|
||||||
"delete_library": "ĐŅдаĐģŅŅŅ ĐąŅĐąĐģŅŅŅŅĐēŅ",
|
|
||||||
"delete_link": "ĐŅдаĐģŅŅŅ ŅĐŋаŅŅĐģĐēŅ",
|
|
||||||
"delete_local_dialog_ok_force": "ĐŖŅŅ Đ°Đ´ĐŊĐž вŅдаĐģŅŅŅ",
|
|
||||||
"delete_others": "ĐŅдаĐģŅŅŅ ŅĐŊŅŅŅ",
|
|
||||||
"delete_tag": "ĐŅдаĐģŅŅŅ ŅŅĐŗ",
|
|
||||||
"delete_user": "ĐŅдаĐģŅŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
|
||||||
"discord": "Discord",
|
|
||||||
"documentation": "ĐаĐēŅĐŧĐĩĐŊŅаŅŅŅ",
|
|
||||||
"done": "ĐаŅОва",
|
|
||||||
"download": "ĐĄĐŋаĐŧĐŋаваŅŅ",
|
|
||||||
"download_canceled": "ĐĄĐŋаĐŧĐŋĐžŅваĐŊĐŊĐĩ ŅĐēаŅаваĐŊа",
|
|
||||||
"download_complete": "ĐĄĐŋаĐŧĐŋĐžŅваĐŊĐŊĐĩ СавĐĩŅŅаĐŊа",
|
|
||||||
"download_enqueue": "ĐĄĐŋаĐŧĐŋĐžŅваĐŊĐŊĐĩ дададСĐĩĐŊа Ņ ŅаŅĐŗŅ",
|
|
||||||
"downloading": "ĐĄĐŋаĐŧĐŋĐžŅваĐŊĐŊĐĩ",
|
|
||||||
"edit": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ",
|
|
||||||
"edit_album": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ Đ°ĐģŅйОĐŧ",
|
|
||||||
"edit_avatar": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ Đ°Đ˛Đ°ŅаŅ",
|
|
||||||
"edit_date": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ Đ´Đ°ŅŅ",
|
|
||||||
"edit_date_and_time": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°Ņ Đ´Đ°ŅŅ Ņ ŅаŅ",
|
|
||||||
"edit_description": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ Đ°ĐŋŅŅаĐŊĐŊĐĩ",
|
|
||||||
"edit_description_prompt": "ĐŅĐąĐĩŅŅŅĐĩ ĐŊОваĐĩ аĐŋŅŅаĐŊĐŊĐĩ:",
|
|
||||||
"edit_faces": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ŅваŅŅ",
|
|
||||||
"edit_import_path": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ŅĐģŅŅ
ŅĐŧĐŋаŅŅŅ",
|
|
||||||
"edit_import_paths": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ŅĐģŅŅ
Ņ ŅĐŧĐŋаŅŅŅ",
|
|
||||||
"edit_key": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ĐēĐģŅŅ",
|
|
||||||
"edit_link": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ŅĐŋаŅŅĐģĐēŅ",
|
|
||||||
"edit_location": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ĐŧĐĩŅŅаСĐŊаŅ
ОдĐļаĐŊĐŊĐĩ",
|
|
||||||
"edit_location_dialog_title": "ĐĐĩŅŅаСĐŊаŅ
ОдĐļаĐŊĐŊĐĩ",
|
|
||||||
"edit_name": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ĐŊаСвŅ",
|
|
||||||
"edit_people": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ĐģŅдСĐĩĐš",
|
|
||||||
"edit_tag": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ŅŅĐŗ",
|
|
||||||
"edit_title": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ĐˇĐ°ĐŗĐ°ĐģОваĐē",
|
|
||||||
"edit_user": "Đ ŅĐ´Đ°ĐŗĐ°Đ˛Đ°ŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
|
||||||
"edited": "ĐĐ´ŅŅĐ´Đ°ĐŗĐ°Đ˛Đ°ĐŊа",
|
|
||||||
"editor": "Đ ŅдаĐēŅаŅ",
|
|
||||||
"editor_close_without_save_prompt": "ĐĐŧĐĩĐŊŅ ĐŊĐĩ ĐąŅĐ´ŅŅŅ ĐˇĐ°Ņ
аваĐŊŅ",
|
|
||||||
"editor_close_without_save_title": "ĐаĐēŅŅŅŅ ŅŅдаĐēŅаŅ?",
|
|
||||||
"editor_crop_tool_h2_aspect_ratios": "ĐĄŅадĐŊĐžŅŅĐŊŅ ĐąĐ°ĐēĐžŅ",
|
|
||||||
"editor_crop_tool_h2_rotation": "ĐаваŅĐžŅ",
|
|
||||||
"error": "ĐаĐŧŅĐģĐēа",
|
|
||||||
"error_saving_image": "ĐаĐŧŅĐģĐēа: {error}",
|
|
||||||
"exif": "Exif",
|
|
||||||
"exif_bottom_sheet_description": "ĐадаŅŅ Đ°ĐŋŅŅаĐŊĐŊĐĩ...",
|
|
||||||
"favorite": "ĐŖ айŅаĐŊŅĐŧ",
|
|
||||||
"favorite_or_unfavorite_photo": "ĐадаŅŅ Đ°ĐąĐž вŅдаĐģŅŅŅ ŅĐžŅа С айŅаĐŊĐ°ĐŗĐ°",
|
|
||||||
"favorites": "ĐĐąŅаĐŊŅŅ",
|
|
||||||
"file_name": "ĐаСва ŅаКĐģа",
|
|
||||||
"filename": "ĐаСва ŅаКĐģа",
|
|
||||||
"filetype": "ĐĸŅĐŋ ŅаКĐģа",
|
|
||||||
"filter": "ФŅĐģŅŅŅ",
|
|
||||||
"forward": "ĐаĐŋĐĩŅад",
|
|
||||||
"gcast_enabled": "Google Cast",
|
|
||||||
"general": "ĐĐŗŅĐģŅĐŊŅŅ",
|
|
||||||
"go_back": "ĐаСад",
|
|
||||||
"go_to_folder": "ĐĐĩŅаКŅŅŅ Đ´Đ° ĐŋаĐŋĐēŅ",
|
|
||||||
"hi_user": "ĐŅŅаĐĩĐŧ, {name} ({email})",
|
|
||||||
"hide_all_people": "ĐĄŅ
аваŅŅ ŅŅŅŅ
ĐģŅдСĐĩĐš",
|
|
||||||
"hide_gallery": "ĐĄŅ
аваŅŅ ĐŗĐ°ĐģĐĩŅŅŅ",
|
|
||||||
"hide_named_person": "ĐĄŅ
аваŅŅ {name}",
|
|
||||||
"hide_password": "ĐĄŅ
аваŅŅ ĐŋаŅĐžĐģŅ",
|
|
||||||
"hide_person": "ĐĄŅ
аваŅŅ ŅаĐģавĐĩĐēа",
|
|
||||||
"image_viewer_page_state_provider_download_started": "ĐĄĐŋаĐŧĐŋĐžŅваĐŊĐŊĐĩ ĐŋаŅаĐģĐžŅŅ",
|
|
||||||
"immich_logo": "ĐĐ°ĐŗĐ°ŅŅĐŋ Immich",
|
|
||||||
"interval": {
|
|
||||||
"day_at_onepm": "ĐĐžĐļĐŊŅ Đ´ĐˇĐĩĐŊŅ Đ° 13-Đš ĐŗĐ°Đ´ĐˇŅĐŊĐĩ",
|
|
||||||
"hours": "{hours, plural, one {ĐĐžĐļĐŊŅŅ ĐŗĐ°Đ´ĐˇŅĐŊŅ} few {ĐĐžĐļĐŊŅŅ {hours, number} ĐŗĐ°Đ´ĐˇŅĐŊŅ} many {ĐĐžĐļĐŊŅŅ {hours, number} ĐŗĐ°Đ´ĐˇŅĐŊ} other {ĐĐžĐļĐŊŅŅ {hours, number} ĐŗĐ°Đ´ĐˇŅĐŊ}}",
|
|
||||||
"night_at_midnight": "ĐĐžĐļĐŊŅŅ ĐŊĐžŅ Đ°ĐŋĐžŅĐŊаŅŅ",
|
|
||||||
"night_at_twoam": "ĐĐžĐļĐŊŅŅ ĐŊĐžŅ Đ° 2-Đš ĐŗĐ°Đ´ĐˇŅĐŊĐĩ"
|
|
||||||
},
|
|
||||||
"language": "ĐОва",
|
|
||||||
"library": "ĐŅĐąĐģŅŅŅŅĐēа",
|
|
||||||
"light": "ХвĐĩŅĐģаŅ",
|
|
||||||
"login_form_back_button_text": "ĐаСад",
|
|
||||||
"login_form_email_hint": "youremail@email.com",
|
|
||||||
"login_form_endpoint_hint": "http://your-server-ip:port",
|
|
||||||
"login_form_password_hint": "ĐŋаŅĐžĐģŅ",
|
|
||||||
"login_form_save_login": "ĐаŅŅаваŅŅа Ņ ŅŅŅŅŅĐŧĐĩ",
|
|
||||||
"main_menu": "ĐаĐģĐžŅĐŊаĐĩ ĐŧĐĩĐŊŅ",
|
|
||||||
"map_location_dialog_yes": "ĐĸаĐē",
|
|
||||||
"map_settings_dark_mode": "ĐĻŅĐŧĐŊŅ ŅŅĐļŅĐŧ",
|
|
||||||
"map_settings_date_range_option_day": "ĐĐŋĐžŅĐŊŅŅ 24 ĐŗĐ°Đ´ĐˇŅĐŊŅ",
|
|
||||||
"map_settings_date_range_option_days": "ĐĐŋĐžŅĐŊŅŅ
дСŅĐŊ: {days}",
|
|
||||||
"map_settings_date_range_option_year": "ĐĐŋĐžŅĐŊŅ ĐŗĐžĐ´",
|
|
||||||
"map_settings_date_range_option_years": "ĐĐŋĐžŅĐŊŅŅ
ĐŗĐžĐ´: {years}",
|
|
||||||
"map_settings_dialog_title": "ĐаĐģĐ°Đ´Ņ ĐēаŅŅŅ",
|
|
||||||
"map_settings_theme_settings": "ĐĸŅĐŧа ĐēаŅŅŅ",
|
|
||||||
"menu": "ĐĐĩĐŊŅ",
|
|
||||||
"minute": "ĐĨвŅĐģŅĐŊа",
|
|
||||||
"month": "ĐĐĩŅŅŅ",
|
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
|
||||||
"my_albums": "ĐаĐĩ аĐģŅйОĐŧŅ",
|
|
||||||
"name": "ĐĐŧŅ",
|
|
||||||
"name_or_nickname": "ĐĐŧŅ Đ°ĐąĐž ĐŋŅĐĩŅдаĐŊŅĐŧ",
|
|
||||||
"next": "ĐаĐģĐĩĐš",
|
|
||||||
"no": "ĐĐĩ",
|
|
||||||
"offline": "Đа-Са ŅĐĩŅĐēаК",
|
|
||||||
"ok": "ĐĐ",
|
|
||||||
"online": "ĐŖ ŅĐĩŅŅŅ",
|
|
||||||
"open": "ĐĐ´ĐēŅŅŅŅ",
|
|
||||||
"or": "айО",
|
|
||||||
"partner_list_user_photos": "ФОŅа ĐēаŅŅŅŅаĐģŅĐŊŅĐēа {user}",
|
|
||||||
"pause": "ĐŅŅĐŋŅĐŊŅŅŅ",
|
|
||||||
"people": "ĐŅдСŅ",
|
|
||||||
"permission_onboarding_back": "ĐаСад",
|
|
||||||
"permission_onboarding_continue_anyway": "ĐŖŅŅ Đ°Đ´ĐŊĐž ĐŋŅаŅŅĐŗĐŊŅŅŅ",
|
|
||||||
"photos": "ФОŅа",
|
|
||||||
"photos_and_videos": "ФОŅа Ņ Đ˛ŅĐ´Ņа",
|
|
||||||
"place": "ĐĐĩŅŅа",
|
|
||||||
"places": "ĐĐĩŅŅŅ",
|
|
||||||
"port": "ĐĐžŅŅ",
|
|
||||||
"previous": "ĐаĐŋŅŅŅĐ´ĐŊŅĐĩ",
|
|
||||||
"profile": "ĐŅĐžŅŅĐģŅ",
|
|
||||||
"profile_drawer_app_logs": "ĐŅŅĐŊаĐģŅ",
|
|
||||||
"profile_drawer_github": "GitHub",
|
|
||||||
"purchase_button_buy": "ĐŅĐŋŅŅŅ",
|
|
||||||
"purchase_button_buy_immich": "ĐŅĐŋŅŅŅ Immich",
|
|
||||||
"purchase_button_select": "ĐŅĐąŅаŅŅ",
|
|
||||||
"remove": "ĐŅдаĐģŅŅŅ",
|
|
||||||
"remove_from_album": "ĐŅдаĐģŅŅŅ Đˇ аĐģŅйОĐŧа",
|
|
||||||
"remove_from_favorites": "ĐŅдаĐģŅŅŅ Đˇ айŅаĐŊŅŅ
",
|
|
||||||
"remove_tag": "ĐŅдаĐģŅŅŅ ŅŅĐŗ",
|
|
||||||
"remove_url": "ĐŅдаĐģŅŅŅ URL-адŅаŅ",
|
|
||||||
"remove_user": "ĐŅдаĐģŅŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
|
||||||
"rename": "ĐĐĩŅаКĐŧĐĩĐŊаваŅŅ",
|
|
||||||
"repository": "Đ ŅĐŋаСŅŅĐžŅŅĐš",
|
|
||||||
"reset": "ĐĄĐēŅĐŊŅŅŅ",
|
|
||||||
"reset_password": "ĐĄĐēŅĐŊŅŅŅ ĐŋаŅĐžĐģŅ",
|
|
||||||
"restore": "ĐĐ´ĐŊавŅŅŅ",
|
|
||||||
"restore_all": "ĐĐ´ĐŊавŅŅŅ ŅŅŅ",
|
|
||||||
"restore_user": "ĐĐ´ĐŊавŅŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
|
||||||
"resume": "ĐŖĐˇĐŊавŅŅŅ",
|
|
||||||
"role": "Đ ĐžĐģŅ",
|
|
||||||
"role_editor": "Đ ŅдаĐēŅаŅ",
|
|
||||||
"role_viewer": "ĐĐģŅдаŅ",
|
|
||||||
"save": "ĐаŅ
аваŅŅ",
|
|
||||||
"save_to_gallery": "ĐаŅ
аваŅŅ Ņ ĐŗĐ°ĐģĐĩŅŅŅ",
|
|
||||||
"search_filter_date": "ĐаŅа",
|
|
||||||
"search_filter_location": "ĐĐĩŅŅаСĐŊаŅ
ОдĐļаĐŊĐŊĐĩ",
|
|
||||||
"search_filter_location_title": "ĐŅĐąĐĩŅŅŅĐĩ ĐŧĐĩŅŅаСĐŊаŅ
ОдĐļаĐŊĐŊĐĩ",
|
|
||||||
"search_filter_media_type": "ĐĸŅĐŋ ĐŧĐĩĐ´ŅŅ",
|
|
||||||
"search_filter_media_type_title": "ĐŅĐąĐĩŅŅŅĐĩ ŅŅĐŋ ĐŧĐĩĐ´ŅŅ",
|
|
||||||
"search_page_screenshots": "ĐĐ´ŅĐŧĐēŅ ŅĐēŅаĐŊа",
|
|
||||||
"search_page_selfies": "ĐĄŅĐģŅŅ",
|
|
||||||
"search_page_things": "Đ ŅŅŅ",
|
|
||||||
"search_page_your_map": "ĐаŅа ĐēаŅŅа",
|
|
||||||
"second": "ĐĄĐĩĐēŅĐŊда",
|
|
||||||
"send_message": "ĐĐ´ĐŋŅавŅŅŅ ĐŋавĐĩдаĐŧĐģĐĩĐŊĐŊĐĩ",
|
|
||||||
"setting_languages_apply": "ĐŖĐļŅŅŅ",
|
|
||||||
"setting_notifications_notify_never": "ĐŊŅĐēĐžĐģŅ",
|
|
||||||
"settings": "ĐаĐģадŅ",
|
|
||||||
"share_add_photos": "ĐадаŅŅ ŅĐžŅа",
|
|
||||||
"shared_album_section_people_title": "ĐĐŽĐĐĐ",
|
|
||||||
"shared_link_info_chip_metadata": "EXIF",
|
|
||||||
"sharing_page_empty_list": "ĐĐŖĐĄĐĸĐĢ ĐĄĐĐĐĄ",
|
|
||||||
"sign_out": "ĐŅĐšŅŅŅ",
|
|
||||||
"sign_up": "ĐаŅŅĐŗŅŅŅŅаваŅŅа",
|
|
||||||
"size": "ĐаĐŧĐĩŅ",
|
|
||||||
"sort_title": "ĐĐ°ĐŗĐ°ĐģОваĐē",
|
|
||||||
"source": "ĐŅŅĐŊŅŅа",
|
|
||||||
"tag": "ĐĸŅĐŗ",
|
|
||||||
"tags": "ĐĸŅĐŗŅ",
|
|
||||||
"theme": "ĐĸŅĐŧа",
|
|
||||||
"theme_selection": "ĐŅĐąĐ°Ņ ŅŅĐŧŅ",
|
|
||||||
"timeline": "ĐĨŅĐžĐŊŅĐēа",
|
"timeline": "ĐĨŅĐžĐŊŅĐēа",
|
||||||
"total": "ĐŖŅŅĐŗĐž",
|
"total": "ĐŖŅŅĐŗĐž",
|
||||||
"trash": "ĐĄĐŧĐĩŅĐŊŅŅа",
|
|
||||||
"trash_page_delete_all": "ĐŅдаĐģŅŅŅ ŅŅĐĩ",
|
|
||||||
"trash_page_restore_all": "ĐĐ´ĐŊавŅŅŅ ŅŅĐĩ",
|
|
||||||
"trash_page_title": "ĐĄĐŧĐĩŅĐŊŅŅа ({count})",
|
|
||||||
"type": "ĐĸŅĐŋ",
|
|
||||||
"undo": "ĐĐ´ŅайŅŅŅ",
|
|
||||||
"upload": "ĐаĐŋаĐŧĐŋаваŅŅ",
|
|
||||||
"upload_status_errors": "ĐаĐŧŅĐģĐēŅ",
|
|
||||||
"uploading": "ĐаĐŋаĐŧĐŋĐžŅваĐŊĐŊĐĩ",
|
|
||||||
"url": "URL-адŅаŅ",
|
|
||||||
"user": "ĐаŅŅŅŅаĐģŅĐŊŅĐē",
|
"user": "ĐаŅŅŅŅаĐģŅĐŊŅĐē",
|
||||||
"user_has_been_deleted": "ĐŅŅŅ ĐēаŅŅŅŅаĐģŅĐŊŅĐē ĐąŅŅ Đ˛ŅдаĐģĐĩĐŊŅ.",
|
|
||||||
"user_id": "ID ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
"user_id": "ID ĐēаŅŅŅŅаĐģŅĐŊŅĐēа",
|
||||||
"user_purchase_settings": "ĐŅĐŋĐģŅ",
|
"user_purchase_settings": "ĐŅĐŋĐģŅ",
|
||||||
"user_purchase_settings_description": "ĐŅŅŅĐšŅĐĩ ĐŋаĐēŅĐŋĐēаĐŧŅ",
|
"user_purchase_settings_description": "ĐŅŅŅĐšŅĐĩ ĐŋаĐēŅĐŋĐēаĐŧŅ",
|
||||||
@@ -461,14 +112,14 @@
|
|||||||
"view_next_asset": "ĐаĐēаСаŅŅ ĐŊаŅŅŅĐŋĐŊŅ Đ°Đą'ĐĩĐēŅ",
|
"view_next_asset": "ĐаĐēаСаŅŅ ĐŊаŅŅŅĐŋĐŊŅ Đ°Đą'ĐĩĐēŅ",
|
||||||
"view_previous_asset": "ĐŅĐ°ĐŗĐģŅдСĐĩŅŅ ĐŋаĐŋŅŅŅĐ´ĐŊŅ Đ°Đą'ĐĩĐēŅ",
|
"view_previous_asset": "ĐŅĐ°ĐŗĐģŅдСĐĩŅŅ ĐŋаĐŋŅŅŅĐ´ĐŊŅ Đ°Đą'ĐĩĐēŅ",
|
||||||
"view_stack": "ĐŅĐ°ĐŗĐģŅĐ´ ŅŅŅĐēа",
|
"view_stack": "ĐŅĐ°ĐŗĐģŅĐ´ ŅŅŅĐēа",
|
||||||
"visibility_changed": "ĐаŅĐŊаŅŅŅ ĐˇĐŧŅĐŊŅĐģаŅŅ Đ´ĐģŅ {count, plural, one {# ŅаĐģавĐĩĐēа} other {# ŅаĐģавĐĩĐē}}",
|
"visibility_changed": "ĐŅдСŅĐŧаŅŅŅ ĐˇĐŧŅĐŊŅĐģаŅŅ Đ´ĐģŅ {count, plural, one {# ŅаĐģавĐĩĐē(-аŅ)} аŅŅаŅĐŊŅŅ
{# ŅаĐģавĐĩĐē}}",
|
||||||
"waiting": "ЧаĐēаŅŅŅ",
|
"waiting": "ЧаĐēаŅŅŅ",
|
||||||
"warning": "ĐаĐŋŅŅŅĐ´ĐļаĐŊĐŊĐĩ",
|
"warning": "ĐаĐŋŅŅŅĐ´ĐļаĐŊĐŊĐĩ",
|
||||||
"week": "ĐĸŅдСĐĩĐŊŅ",
|
"week": "ĐĸŅдСĐĩĐŊŅ",
|
||||||
"welcome": "ĐŅŅаĐĩĐŧ",
|
"welcome": "ĐŅŅаĐĩĐŧ",
|
||||||
"welcome_to_immich": "ĐŅŅаĐĩĐŧ Ņ Immich",
|
"welcome_to_immich": "ĐŅŅаĐĩĐŧ Ņ Immich",
|
||||||
"year": "ĐОд",
|
"year": "ĐОд",
|
||||||
"years_ago": "{years, plural, one {# ĐŗĐžĐ´} few {# ĐŗĐ°Đ´Ņ} many {# ĐŗĐ°Đ´ĐžŅ} other {# ĐŗĐ°Đ´ĐžŅ}} ŅаĐŧŅ",
|
"years_ago": "{years, plural, one {# ĐŗĐžĐ´} other {# ĐŗĐ°Đ´ĐžŅ}} ŅаĐŧŅ",
|
||||||
"yes": "ĐĸаĐē",
|
"yes": "ĐĸаĐē",
|
||||||
"you_dont_have_any_shared_links": "ĐŖ Đ˛Đ°Ņ ĐŊŅĐŧа Đ°ĐąĐ°ĐŗŅĐģĐĩĐŊŅŅ
ŅĐŋаŅŅĐģаĐē",
|
"you_dont_have_any_shared_links": "ĐŖ Đ˛Đ°Ņ ĐŊŅĐŧа Đ°ĐąĐ°ĐŗŅĐģĐĩĐŊŅŅ
ŅĐŋаŅŅĐģаĐē",
|
||||||
"zoom_image": "ĐавŅĐģŅŅŅŅŅ Đ˛ŅдаŅŅŅ"
|
"zoom_image": "ĐавŅĐģŅŅŅŅŅ Đ˛ŅдаŅŅŅ"
|
||||||
|
|||||||
+59
-148
@@ -34,7 +34,6 @@
|
|||||||
"added_to_favorites_count": "ĐОйавĐĩĐŊи {count, number} ĐēŅĐŧ ĐģŅйиĐŧи",
|
"added_to_favorites_count": "ĐОйавĐĩĐŊи {count, number} ĐēŅĐŧ ĐģŅйиĐŧи",
|
||||||
"admin": {
|
"admin": {
|
||||||
"add_exclusion_pattern_description": "ĐОйави ĐŧОдĐĩĐģи Са иСĐēĐģŅŅваĐŊĐĩ. ĐОддŅŅĐļа ŅĐĩ \"globbing\" Ņ ĐŋĐžĐŧĐžŅŅа ĐŊа *, ** и ?. Đа да Đ¸ĐŗĐŊĐžŅиŅаŅĐĩ вŅиŅĐēи ŅаКĐģОвĐĩ в диŅĐĩĐēŅĐžŅĐ¸Ņ Ņ Đ¸ĐŧĐĩ \"Raw\", иСĐŋĐžĐģСваКŅĐĩ \"**/Raw/**\". Đа да Đ¸ĐŗĐŊĐžŅиŅаŅĐĩ вŅиŅĐēи ŅаКĐģОвĐĩ, СавŅŅŅваŅи ĐŊа \".tif\", иСĐŋĐžĐģСваКŅĐĩ \"**/*.tif\". Đа да Đ¸ĐŗĐŊĐžŅиŅаŅĐĩ айŅĐžĐģŅŅĐĩĐŊ ĐŋŅŅ, иСĐŋĐžĐģСваКŅĐĩ \"/path/to/ignore/**\".",
|
"add_exclusion_pattern_description": "ĐОйави ĐŧОдĐĩĐģи Са иСĐēĐģŅŅваĐŊĐĩ. ĐОддŅŅĐļа ŅĐĩ \"globbing\" Ņ ĐŋĐžĐŧĐžŅŅа ĐŊа *, ** и ?. Đа да Đ¸ĐŗĐŊĐžŅиŅаŅĐĩ вŅиŅĐēи ŅаКĐģОвĐĩ в диŅĐĩĐēŅĐžŅĐ¸Ņ Ņ Đ¸ĐŧĐĩ \"Raw\", иСĐŋĐžĐģСваКŅĐĩ \"**/Raw/**\". Đа да Đ¸ĐŗĐŊĐžŅиŅаŅĐĩ вŅиŅĐēи ŅаКĐģОвĐĩ, СавŅŅŅваŅи ĐŊа \".tif\", иСĐŋĐžĐģСваКŅĐĩ \"**/*.tif\". Đа да Đ¸ĐŗĐŊĐžŅиŅаŅĐĩ айŅĐžĐģŅŅĐĩĐŊ ĐŋŅŅ, иСĐŋĐžĐģСваКŅĐĩ \"/path/to/ignore/**\".",
|
||||||
"admin_user": "ĐĐ´ĐŧиĐŊиŅŅŅаŅĐžŅ",
|
|
||||||
"asset_offline_description": "ĐĸОСи вŅĐŊŅĐĩĐŊ йийĐģиОŅĐĩŅĐĩĐŊ ĐĩĐģĐĩĐŧĐĩĐŊŅ ĐŊĐĩ ĐŧĐžĐļĐĩ да ĐąŅĐ´Đĩ ĐžŅĐēŅĐ¸Ņ ĐŊа диŅĐēа и Đĩ ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊ в ĐēĐžŅŅĐĩŅĐž Са йОĐēĐģŅĐē. ĐĐēĐž ŅаКĐģŅŅ Đĩ ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊ в йийĐģиОŅĐĩĐēаŅа, ĐŋŅОвĐĩŅĐĩŅĐĩ ваŅаŅа иŅŅĐžŅĐ¸Ņ ĐˇĐ° ĐŊОв ŅŅĐžŅвĐĩŅŅŅĐ˛Đ°Ņ ĐĩĐģĐĩĐŧĐĩĐŊŅ. Đа да вŅСŅŅаĐŊОвиŅĐĩ ĐĩĐģĐĩĐŧĐĩĐŊŅа, ĐŧĐžĐģŅ ĐŋŅОвĐĩŅĐĩŅĐĩ даĐģи ŅаКĐģОвиŅŅ ĐŋŅŅ ĐžŅĐ´ĐžĐģŅ ĐŧĐžĐļĐĩ да ĐąŅĐ´Đĩ Đ´ĐžŅŅŅĐŋĐĩĐŊ ĐžŅ Immich и ŅĐēаĐŊиŅаКŅĐĩ йийĐģиОŅĐĩĐēаŅа.",
|
"asset_offline_description": "ĐĸОСи вŅĐŊŅĐĩĐŊ йийĐģиОŅĐĩŅĐĩĐŊ ĐĩĐģĐĩĐŧĐĩĐŊŅ ĐŊĐĩ ĐŧĐžĐļĐĩ да ĐąŅĐ´Đĩ ĐžŅĐēŅĐ¸Ņ ĐŊа диŅĐēа и Đĩ ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊ в ĐēĐžŅŅĐĩŅĐž Са йОĐēĐģŅĐē. ĐĐēĐž ŅаКĐģŅŅ Đĩ ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊ в йийĐģиОŅĐĩĐēаŅа, ĐŋŅОвĐĩŅĐĩŅĐĩ ваŅаŅа иŅŅĐžŅĐ¸Ņ ĐˇĐ° ĐŊОв ŅŅĐžŅвĐĩŅŅŅĐ˛Đ°Ņ ĐĩĐģĐĩĐŧĐĩĐŊŅ. Đа да вŅСŅŅаĐŊОвиŅĐĩ ĐĩĐģĐĩĐŧĐĩĐŊŅа, ĐŧĐžĐģŅ ĐŋŅОвĐĩŅĐĩŅĐĩ даĐģи ŅаКĐģОвиŅŅ ĐŋŅŅ ĐžŅĐ´ĐžĐģŅ ĐŧĐžĐļĐĩ да ĐąŅĐ´Đĩ Đ´ĐžŅŅŅĐŋĐĩĐŊ ĐžŅ Immich и ŅĐēаĐŊиŅаКŅĐĩ йийĐģиОŅĐĩĐēаŅа.",
|
||||||
"authentication_settings": "ĐаŅŅŅОКĐēи Са ŅĐ´ĐžŅŅОвĐĩŅŅваĐŊĐĩ",
|
"authentication_settings": "ĐаŅŅŅОКĐēи Са ŅĐ´ĐžŅŅОвĐĩŅŅваĐŊĐĩ",
|
||||||
"authentication_settings_description": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа ĐŋаŅĐžĐģа, OAuth и Đ´ŅŅĐŗĐ¸ ĐŊаŅŅŅОКĐēи Са ŅĐ´ĐžŅŅОвĐĩŅŅваĐŊĐĩ",
|
"authentication_settings_description": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа ĐŋаŅĐžĐģа, OAuth и Đ´ŅŅĐŗĐ¸ ĐŊаŅŅŅОКĐēи Са ŅĐ´ĐžŅŅОвĐĩŅŅваĐŊĐĩ",
|
||||||
@@ -53,7 +52,7 @@
|
|||||||
"confirm_email_below": "Đа ĐŋĐžŅвŅŅĐļĐ´ĐĩĐŊиĐĩ, ĐŧĐžĐģŅ Đ˛ŅвĐĩĐ´ĐĩŅĐĩ \"{email}\" ĐžŅĐ´ĐžĐģŅ",
|
"confirm_email_below": "Đа ĐŋĐžŅвŅŅĐļĐ´ĐĩĐŊиĐĩ, ĐŧĐžĐģŅ Đ˛ŅвĐĩĐ´ĐĩŅĐĩ \"{email}\" ĐžŅĐ´ĐžĐģŅ",
|
||||||
"confirm_reprocess_all_faces": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да ŅĐĩ ОйŅайОŅŅŅ ĐģиŅаŅа ĐžŅĐŊОвО? ĐĸОва ŅĐĩ иСŅиŅŅи вŅиŅĐēи иĐŧĐĩĐŊŅваĐŊи Ņ
ĐžŅа.",
|
"confirm_reprocess_all_faces": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да ŅĐĩ ОйŅайОŅŅŅ ĐģиŅаŅа ĐžŅĐŊОвО? ĐĸОва ŅĐĩ иСŅиŅŅи вŅиŅĐēи иĐŧĐĩĐŊŅваĐŊи Ņ
ĐžŅа.",
|
||||||
"confirm_user_password_reset": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да ĐŊŅĐģиŅаŅĐĩ ĐŋаŅĐžĐģаŅа ĐŊа {user}?",
|
"confirm_user_password_reset": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да ĐŊŅĐģиŅаŅĐĩ ĐŋаŅĐžĐģаŅа ĐŊа {user}?",
|
||||||
"confirm_user_pin_code_reset": "ĐаиŅŅиĐŊа Đģи иŅĐēаŅĐĩ да ŅĐŧĐĩĐŊиŅĐĩ PIN ĐēОда ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģŅ {user}?",
|
"confirm_user_pin_code_reset": "ĐаиŅŅиĐŊа Đģи иŅĐēĐ°Ņ Đ´Đ° ŅĐŧĐĩĐŊĐ¸Ņ PIN-ĐēОда ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģŅ {user}?",
|
||||||
"create_job": "ĐĄŅСдаКŅĐĩ СадаŅа",
|
"create_job": "ĐĄŅСдаКŅĐĩ СадаŅа",
|
||||||
"cron_expression": "Cron иСŅаС",
|
"cron_expression": "Cron иСŅаС",
|
||||||
"cron_expression_description": "ĐаŅŅŅОК иĐŊŅĐĩŅваĐģа ĐŊа ŅĐēаĐŊиŅаĐŊĐĩ иСĐŋĐžĐģСваКĐēи cron ŅĐžŅĐŧаŅа. Đа ĐŋОвĐĩŅĐĩ иĐŊŅĐžŅĐŧаŅĐ¸Ņ <link>Crontab Guru</link>",
|
"cron_expression_description": "ĐаŅŅŅОК иĐŊŅĐĩŅваĐģа ĐŊа ŅĐēаĐŊиŅаĐŊĐĩ иСĐŋĐžĐģСваКĐēи cron ŅĐžŅĐŧаŅа. Đа ĐŋОвĐĩŅĐĩ иĐŊŅĐžŅĐŧаŅĐ¸Ņ <link>Crontab Guru</link>",
|
||||||
@@ -166,26 +165,12 @@
|
|||||||
"metadata_settings_description": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа ĐŊаŅŅŅОКĐēиŅĐĩ Са ĐŧĐĩŅадаĐŊĐŊи",
|
"metadata_settings_description": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа ĐŊаŅŅŅОКĐēиŅĐĩ Са ĐŧĐĩŅадаĐŊĐŊи",
|
||||||
"migration_job": "ĐĐ¸ĐŗŅаŅиŅ",
|
"migration_job": "ĐĐ¸ĐŗŅаŅиŅ",
|
||||||
"migration_job_description": "ĐĐ¸ĐŗŅиŅаĐŊĐĩ ĐŊа ĐŧиĐŊиаŅŅŅиŅĐĩ Са ĐĩĐģĐĩĐŧĐĩĐŊŅи и ĐģиŅа ĐēŅĐŧ ĐŊаК-ĐŊОваŅа ŅŅŅŅĐēŅŅŅа ĐŊа ĐŋаĐŋĐēиŅĐĩ",
|
"migration_job_description": "ĐĐ¸ĐŗŅиŅаĐŊĐĩ ĐŊа ĐŧиĐŊиаŅŅŅиŅĐĩ Са ĐĩĐģĐĩĐŧĐĩĐŊŅи и ĐģиŅа ĐēŅĐŧ ĐŊаК-ĐŊОваŅа ŅŅŅŅĐēŅŅŅа ĐŊа ĐŋаĐŋĐēиŅĐĩ",
|
||||||
"nightly_tasks_cluster_faces_setting_description": "ĐСĐŋŅĐģĐŊи ŅаСĐŋОСĐŊаваĐŊĐĩ ĐŊа ĐģиŅĐĩ Са ĐžŅĐēŅиŅи ĐŊОви ĐģиŅа",
|
|
||||||
"nightly_tasks_cluster_new_faces_setting": "РаСĐŋОСĐŊаваĐŊĐĩ ĐŊа ĐŊОви ĐģиŅа",
|
|
||||||
"nightly_tasks_database_cleanup_setting": "ĐадаŅи ĐŋĐž ĐŋĐžŅиŅŅваĐŊĐĩ ĐŊа йаСаŅа даĐŊĐŊи",
|
|
||||||
"nightly_tasks_database_cleanup_setting_description": "ĐŅĐĩĐŧаŅ
ĐŊи ŅŅаŅи, ĐŊĐĩĐŊŅĐļĐŊи СаĐŋиŅи ĐžŅ ĐąĐ°ĐˇĐ°Ņа даĐŊĐŊи",
|
|
||||||
"nightly_tasks_generate_memories_setting": "ĐĄŅСдаваĐŊĐĩ ĐŊа ŅĐŋĐžĐŧĐĩĐŊи",
|
|
||||||
"nightly_tasks_generate_memories_setting_description": "ĐĄŅСдаваĐŊĐĩ ĐŊа ĐŊОви ŅĐŋĐžĐŧĐĩĐŊи ĐžŅ ŅŅŅĐĩŅŅвŅваŅи ОйĐĩĐēŅи",
|
|
||||||
"nightly_tasks_missing_thumbnails_setting": "ĐĐĩĐŊĐĩŅиŅаĐŊĐĩ ĐŊа ĐģиĐŋŅваŅи ĐŧиĐŊиаŅŅŅи",
|
|
||||||
"nightly_tasks_missing_thumbnails_setting_description": "ĐОйавŅĐŊĐĩ ĐŊа ОйĐĩĐēŅи ĐąĐĩС ĐŧиĐŊиаŅŅŅа в ĐžĐŋаŅĐēаŅа Са ŅŅСдаваĐŊĐĩ ĐŊа ĐŧиĐŊиаŅŅŅа",
|
|
||||||
"nightly_tasks_settings": "ĐаŅŅŅОКĐēа ĐŊа СадаŅи Са ĐŋŅĐĩС ĐŊĐžŅŅа",
|
|
||||||
"nightly_tasks_settings_description": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа СадаŅиŅĐĩ, иСĐŋŅĐģĐŊŅваĐŊи ĐŋŅĐĩС ĐŊĐžŅŅа",
|
|
||||||
"nightly_tasks_start_time_setting": "ĐŅĐĩĐŧĐĩ Са ĐŊаŅаĐģĐž",
|
|
||||||
"nightly_tasks_start_time_setting_description": "ĐŅĐĩĐŧĐĩ, ĐēĐžĐŗĐ°ŅĐž ŅŅŅвŅŅа ŅĐĩ СаĐŋĐžŅĐŊĐĩ иСĐŋŅĐģĐŊĐĩĐŊиĐĩ ĐŊа ĐŊĐžŅĐŊи СадаŅи",
|
|
||||||
"nightly_tasks_sync_quota_usage_setting": "ĐвОŅа Са ŅиĐŊŅ
ŅĐžĐŊиСаŅиŅ",
|
|
||||||
"nightly_tasks_sync_quota_usage_setting_description": "ĐĐąĐŊОвŅваĐŊĐĩ ĐŊа ĐēвОŅаŅа ŅĐŋĐžŅĐĩĐ´ ŅĐĩĐēŅŅĐžŅĐž ĐŋĐžŅŅĐĩĐąĐģĐĩĐŊиĐĩ",
|
|
||||||
"no_paths_added": "ĐŅĐŧа дОйавĐĩĐŊи ĐŋŅŅиŅа",
|
"no_paths_added": "ĐŅĐŧа дОйавĐĩĐŊи ĐŋŅŅиŅа",
|
||||||
"no_pattern_added": "ĐŅĐŧа дОйавĐĩĐŊ ĐŧОдĐĩĐģ",
|
"no_pattern_added": "ĐŅĐŧа дОйавĐĩĐŊ ĐŧОдĐĩĐģ",
|
||||||
"note_apply_storage_label_previous_assets": "ĐайĐĩĐģĐĩĐļĐēа: Đа да ĐŋŅиĐģĐžĐļиŅĐĩ ĐĩŅиĐēĐĩŅа Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ ĐēŅĐŧ ĐŋŅĐĩдваŅиŅĐĩĐģĐŊĐž ĐēаŅĐĩĐŊи ŅаКĐģОвĐĩ, ŅŅаŅŅиŅаКŅĐĩ",
|
"note_apply_storage_label_previous_assets": "ĐайĐĩĐģĐĩĐļĐēа: Đа да ĐŋŅиĐģĐžĐļиŅĐĩ ĐĩŅиĐēĐĩŅа Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ ĐēŅĐŧ ĐŋŅĐĩдваŅиŅĐĩĐģĐŊĐž ĐēаŅĐĩĐŊи ŅаКĐģОвĐĩ, ŅŅаŅŅиŅаКŅĐĩ",
|
||||||
"note_cannot_be_changed_later": "ĐĐĐĐĐĐĐĐ: ĐĸОва ĐŊĐĩ ĐŧĐžĐļĐĩ да ĐąŅĐ´Đĩ ĐŋŅĐžĐŧĐĩĐŊĐĩĐŊĐž ĐŋĐž-ĐēŅŅĐŊĐž!",
|
"note_cannot_be_changed_later": "ĐĐĐĐĐĐĐĐ: ĐĸОва ĐŊĐĩ ĐŧĐžĐļĐĩ да ĐąŅĐ´Đĩ ĐŋŅĐžĐŧĐĩĐŊĐĩĐŊĐž ĐŋĐž-ĐēŅŅĐŊĐž!",
|
||||||
"notification_email_from_address": "ĐŅ Đ°Đ´ŅĐĩŅ",
|
"notification_email_from_address": "ĐŅ Đ°Đ´ŅĐĩŅ",
|
||||||
"notification_email_from_address_description": "ĐĐģĐĩĐēŅŅĐžĐŊĐŊа ĐŋĐžŅа ĐŊа иСĐŋŅаŅаŅа, ĐŊаĐŋŅиĐŧĐĩŅ: \"Immich Photo Server <noreply@example.com>\". ĐСĐŋĐžĐģСваКŅĐĩ адŅĐĩŅ, ĐžŅ ĐēОКŅĐž ĐŧĐžĐļĐĩ да иСĐŋŅаŅаŅĐĩ иĐŧĐĩĐšĐģи.",
|
"notification_email_from_address_description": "ĐĐģĐĩĐēŅŅĐžĐŊĐŊа ĐŋĐžŅа ĐŊа иСĐŋŅаŅаŅа, ĐŊаĐŋŅиĐŧĐĩŅ: \"Immich Photo Server <noreply@example.com>\". ĐСĐŋĐžĐģСваК адŅĐĩŅ, ĐžŅ ĐēОКŅĐž ĐŧĐžĐļĐĩ да иСĐŋŅаŅĐ°Ņ Đ¸ĐŧĐĩĐšĐģи.",
|
||||||
"notification_email_host_description": "ĐĨĐžŅŅ ĐŊа ŅŅŅвŅŅа Са ĐĩĐģĐĩĐēŅŅĐžĐŊĐŊа ĐŋĐžŅа (ĐŊаĐŋŅиĐŧĐĩŅ: smtp.immich.app)",
|
"notification_email_host_description": "ĐĨĐžŅŅ ĐŊа ŅŅŅвŅŅа Са ĐĩĐģĐĩĐēŅŅĐžĐŊĐŊа ĐŋĐžŅа (ĐŊаĐŋŅиĐŧĐĩŅ: smtp.immich.app)",
|
||||||
"notification_email_ignore_certificate_errors": "ĐĐŗĐŊĐžŅиŅаКŅĐĩ ŅĐĩŅŅиŅиĐēаŅиОĐŊĐŊи ĐŗŅĐĩŅĐēи",
|
"notification_email_ignore_certificate_errors": "ĐĐŗĐŊĐžŅиŅаКŅĐĩ ŅĐĩŅŅиŅиĐēаŅиОĐŊĐŊи ĐŗŅĐĩŅĐēи",
|
||||||
"notification_email_ignore_certificate_errors_description": "ĐĐŗĐŊĐžŅиŅаК ĐŗŅĐĩŅĐēи ŅвŅŅСаĐŊи Ņ Đ˛Đ°ĐģидаŅĐ¸Ņ ĐŊа TLS ŅĐĩŅŅиŅиĐēĐ°Ņ (ĐŊĐĩ ŅĐĩ ĐŋŅĐĩĐŋĐžŅŅŅва)",
|
"notification_email_ignore_certificate_errors_description": "ĐĐŗĐŊĐžŅиŅаК ĐŗŅĐĩŅĐēи ŅвŅŅСаĐŊи Ņ Đ˛Đ°ĐģидаŅĐ¸Ņ ĐŊа TLS ŅĐĩŅŅиŅиĐēĐ°Ņ (ĐŊĐĩ ŅĐĩ ĐŋŅĐĩĐŋĐžŅŅŅва)",
|
||||||
@@ -194,7 +179,7 @@
|
|||||||
"notification_email_sent_test_email_button": "ĐСĐŋŅаŅи ŅĐĩŅŅОв иĐŧĐĩĐšĐģ и СаĐŋаСи",
|
"notification_email_sent_test_email_button": "ĐСĐŋŅаŅи ŅĐĩŅŅОв иĐŧĐĩĐšĐģ и СаĐŋаСи",
|
||||||
"notification_email_setting_description": "ĐаŅŅŅОКĐēи Са иСĐŋŅаŅаĐŊĐĩ ĐŊа иĐŧĐĩĐšĐģ иСвĐĩŅŅиŅ",
|
"notification_email_setting_description": "ĐаŅŅŅОКĐēи Са иСĐŋŅаŅаĐŊĐĩ ĐŊа иĐŧĐĩĐšĐģ иСвĐĩŅŅиŅ",
|
||||||
"notification_email_test_email": "ĐСĐŋŅаŅи ŅĐĩŅŅОв иĐŧĐĩĐšĐģ",
|
"notification_email_test_email": "ĐСĐŋŅаŅи ŅĐĩŅŅОв иĐŧĐĩĐšĐģ",
|
||||||
"notification_email_test_email_failed": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž иСĐŋŅаŅаĐŊĐĩ ĐŊа ŅĐĩŅŅОв иĐŧĐĩĐšĐģ, ĐŋŅОвĐĩŅĐĩŅĐĩ ĐŊаŅŅŅОКĐēиŅĐĩ",
|
"notification_email_test_email_failed": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž иСĐŋŅаŅаĐŊĐĩ ĐŊа ŅĐĩŅŅОв иĐŧĐĩĐšĐģ, ĐŋŅОвĐĩŅи ĐŋŅĐžĐŧĐĩĐŊĐģивиŅĐĩ",
|
||||||
"notification_email_test_email_sent": "ĐĸĐĩŅŅОв иĐŧĐĩĐšĐģ ĐąĐĩŅĐĩ иСĐŋŅаŅĐĩĐŊ ĐŊа {email}. ĐŅОвĐĩŅĐĩŅĐĩ вŅ
ОдŅŅаŅа Ņи ĐŋĐžŅa.",
|
"notification_email_test_email_sent": "ĐĸĐĩŅŅОв иĐŧĐĩĐšĐģ ĐąĐĩŅĐĩ иСĐŋŅаŅĐĩĐŊ ĐŊа {email}. ĐŅОвĐĩŅĐĩŅĐĩ вŅ
ОдŅŅаŅа Ņи ĐŋĐžŅa.",
|
||||||
"notification_email_username_description": "ĐĐžŅŅĐĩйиŅĐĩĐģŅĐēĐž иĐŧĐĩ Са ŅĐ´ĐžŅŅОвĐĩŅŅваĐŊĐĩ ĐŋŅĐĩĐ´ иĐŧĐĩĐšĐģ ŅŅŅвŅŅа",
|
"notification_email_username_description": "ĐĐžŅŅĐĩйиŅĐĩĐģŅĐēĐž иĐŧĐĩ Са ŅĐ´ĐžŅŅОвĐĩŅŅваĐŊĐĩ ĐŋŅĐĩĐ´ иĐŧĐĩĐšĐģ ŅŅŅвŅŅа",
|
||||||
"notification_enable_email_notifications": "ĐĐēĐģŅŅваĐŊĐĩ ĐŊа иĐŧĐĩĐšĐģ иСвĐĩŅŅиŅŅа",
|
"notification_enable_email_notifications": "ĐĐēĐģŅŅваĐŊĐĩ ĐŊа иĐŧĐĩĐšĐģ иСвĐĩŅŅиŅŅа",
|
||||||
@@ -210,8 +195,6 @@
|
|||||||
"oauth_mobile_redirect_uri": "URI Са ĐŧОйиĐģĐŊĐž ĐŋŅĐĩĐŊаŅĐžŅваĐŊĐĩ",
|
"oauth_mobile_redirect_uri": "URI Са ĐŧОйиĐģĐŊĐž ĐŋŅĐĩĐŊаŅĐžŅваĐŊĐĩ",
|
||||||
"oauth_mobile_redirect_uri_override": "URI ĐŋŅĐĩĐŊаŅĐžŅваĐŊĐĩ Са ĐŧОйиĐģĐŊи ŅŅŅŅОКŅŅва",
|
"oauth_mobile_redirect_uri_override": "URI ĐŋŅĐĩĐŊаŅĐžŅваĐŊĐĩ Са ĐŧОйиĐģĐŊи ŅŅŅŅОКŅŅва",
|
||||||
"oauth_mobile_redirect_uri_override_description": "РаСŅĐĩŅи ĐēĐžĐŗĐ°ŅĐž Đ´ĐžŅŅавŅиĐēа Са OAuth ŅĐ´ĐžŅŅОвĐĩŅŅваĐŊĐĩ ĐŊĐĩ ĐŋОСвОĐģŅва Са ĐŧОйиĐģĐŊи URI идĐĩĐŊŅиŅиĐēаŅĐžŅи, ĐēаŅĐž ''{callback}''",
|
"oauth_mobile_redirect_uri_override_description": "РаСŅĐĩŅи ĐēĐžĐŗĐ°ŅĐž Đ´ĐžŅŅавŅиĐēа Са OAuth ŅĐ´ĐžŅŅОвĐĩŅŅваĐŊĐĩ ĐŊĐĩ ĐŋОСвОĐģŅва Са ĐŧОйиĐģĐŊи URI идĐĩĐŊŅиŅиĐēаŅĐžŅи, ĐēаŅĐž ''{callback}''",
|
||||||
"oauth_role_claim": "ĐĐžŅвŅŅĐļĐ´ĐĩĐŊиĐĩ ĐŊа ŅĐžĐģŅ",
|
|
||||||
"oauth_role_claim_description": "ĐвŅĐžĐŧаŅиŅĐŊĐž ĐŋŅĐĩĐ´ĐžŅŅавŅĐŊĐĩ ĐŊа адĐŧиĐŊиŅŅŅаŅивĐŊи ĐŋŅава ĐŋŅи ĐŊаĐģиŅиĐĩ ĐŊа ŅОва ĐŋĐžŅвŅŅĐļĐĩĐŊиĐĩ. ĐĐžŅвŅŅĐļĐ´ĐĩĐŊиĐĩŅĐž ĐŧĐžĐļĐĩ да иĐŧа ŅŅОКĐŊĐžŅŅ 'user' иĐģи 'admin'.",
|
|
||||||
"oauth_settings": "OAuth",
|
"oauth_settings": "OAuth",
|
||||||
"oauth_settings_description": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа ĐŊаŅŅŅОКĐēиŅĐĩ Са вŅ
Од Ņ OAuth",
|
"oauth_settings_description": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа ĐŊаŅŅŅОКĐēиŅĐĩ Са вŅ
Од Ņ OAuth",
|
||||||
"oauth_settings_more_details": "Đа ĐŋОвĐĩŅĐĩ иĐŊŅĐžŅĐŧаŅĐ¸Ņ ĐˇĐ° ŅŅĐŊĐēŅиОĐŊаĐģĐŊĐžŅŅŅа, ŅĐĩ ĐŋĐžŅŅŅŅĐĩŅĐĩ в <link>docs</link>.",
|
"oauth_settings_more_details": "Đа ĐŋОвĐĩŅĐĩ иĐŊŅĐžŅĐŧаŅĐ¸Ņ ĐˇĐ° ŅŅĐŊĐēŅиОĐŊаĐģĐŊĐžŅŅŅа, ŅĐĩ ĐŋĐžŅŅŅŅĐĩŅĐĩ в <link>docs</link>.",
|
||||||
@@ -220,7 +203,7 @@
|
|||||||
"oauth_storage_quota_claim": "ĐаŅвĐēа Са ĐēвОŅа Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ",
|
"oauth_storage_quota_claim": "ĐаŅвĐēа Са ĐēвОŅа Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ",
|
||||||
"oauth_storage_quota_claim_description": "ĐвŅĐžĐŧаŅиŅĐŊĐž СадаКŅĐĩ ĐēвОŅаŅа Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģŅ ŅŅŅ ŅŅОКĐŊĐžŅŅŅа ĐžŅ ŅаСи СаŅвĐēа.",
|
"oauth_storage_quota_claim_description": "ĐвŅĐžĐŧаŅиŅĐŊĐž СадаКŅĐĩ ĐēвОŅаŅа Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģŅ ŅŅŅ ŅŅОКĐŊĐžŅŅŅа ĐžŅ ŅаСи СаŅвĐēа.",
|
||||||
"oauth_storage_quota_default": "ĐĄŅаĐŊдаŅŅĐŊа ĐēвОŅа Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ (GiB)",
|
"oauth_storage_quota_default": "ĐĄŅаĐŊдаŅŅĐŊа ĐēвОŅа Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ (GiB)",
|
||||||
"oauth_storage_quota_default_description": "ĐвОŅа в GiB, ĐēĐžŅŅĐž да ŅĐĩ иСĐŋĐžĐģСва, ĐēĐžĐŗĐ°ŅĐž ĐŊĐĩ Đĩ ĐŋĐžŅĐžŅĐĩĐŊĐž Đ´ŅŅĐŗĐž.",
|
"oauth_storage_quota_default_description": "ĐвОŅа в GiB, ĐēĐžŅŅĐž да ŅĐĩ иСĐŋĐžĐģСва, ĐēĐžĐŗĐ°ŅĐž ĐŊĐĩ Đĩ ĐŋŅĐĩĐ´ĐžŅŅавĐĩĐŊа СаŅвĐēа (ĐŅвĐĩĐ´ĐĩŅĐĩ 0 Са ĐŊĐĩĐžĐŗŅаĐŊиŅĐĩĐŊа ĐēвОŅа).",
|
||||||
"oauth_timeout": "ĐŅĐĩĐŧĐĩ ĐŊа иСŅаĐēваĐŊĐĩ ĐŋŅи СаŅвĐēа",
|
"oauth_timeout": "ĐŅĐĩĐŧĐĩ ĐŊа иСŅаĐēваĐŊĐĩ ĐŋŅи СаŅвĐēа",
|
||||||
"oauth_timeout_description": "ĐŅĐĩĐŧĐĩ Са иСŅаĐēваĐŊĐĩ ĐŊа ĐžŅĐŗĐžĐ˛ĐžŅ ĐŊа СаŅвĐēа, в ĐŧиĐģиŅĐĩĐēŅĐŊди",
|
"oauth_timeout_description": "ĐŅĐĩĐŧĐĩ Са иСŅаĐēваĐŊĐĩ ĐŊа ĐžŅĐŗĐžĐ˛ĐžŅ ĐŊа СаŅвĐēа, в ĐŧиĐģиŅĐĩĐēŅĐŊди",
|
||||||
"password_enable_description": "ĐĐģиСаĐŊĐĩ Ņ Đ¸ĐŧĐĩĐšĐģ и ĐŋаŅĐžĐģа",
|
"password_enable_description": "ĐĐģиСаĐŊĐĩ Ņ Đ¸ĐŧĐĩĐšĐģ и ĐŋаŅĐžĐģа",
|
||||||
@@ -260,7 +243,7 @@
|
|||||||
"storage_template_migration_info": "ШайĐģĐžĐŊа ŅĐĩ ĐŋŅĐĩОйŅаСŅва вŅиŅĐēи ŅаСŅиŅĐĩĐŊĐ¸Ņ ĐŊа иĐŧĐĩĐŊаŅа ĐŊа ŅаКĐģОвĐĩŅĐĩ в Đ´ĐžĐģĐĩĐŊ ŅĐĩĐŗĐ¸ŅŅŅŅ. ĐŅĐžĐŧĐĩĐŊиŅĐĩ в ŅайĐģĐžĐŊиŅĐĩ ŅĐĩ ŅĐĩ ĐŋŅиĐģĐ°ĐŗĐ°Ņ ŅаĐŧĐž Са ĐŊОви ĐĩĐģĐĩĐŧĐĩĐŊŅи. Đа да ĐŋŅиĐģĐžĐļиŅĐĩ ĐŋŅиĐŊŅдиŅĐĩĐģĐŊĐž ŅайĐģĐžĐŊа ĐēŅĐŧ вĐĩŅĐĩ ĐēаŅĐĩĐŊи ĐĩĐģĐĩĐŧĐĩĐŊŅи, иСĐŋŅĐģĐŊĐĩŅĐĩ <link>{job}</link>.",
|
"storage_template_migration_info": "ШайĐģĐžĐŊа ŅĐĩ ĐŋŅĐĩОйŅаСŅва вŅиŅĐēи ŅаСŅиŅĐĩĐŊĐ¸Ņ ĐŊа иĐŧĐĩĐŊаŅа ĐŊа ŅаКĐģОвĐĩŅĐĩ в Đ´ĐžĐģĐĩĐŊ ŅĐĩĐŗĐ¸ŅŅŅŅ. ĐŅĐžĐŧĐĩĐŊиŅĐĩ в ŅайĐģĐžĐŊиŅĐĩ ŅĐĩ ŅĐĩ ĐŋŅиĐģĐ°ĐŗĐ°Ņ ŅаĐŧĐž Са ĐŊОви ĐĩĐģĐĩĐŧĐĩĐŊŅи. Đа да ĐŋŅиĐģĐžĐļиŅĐĩ ĐŋŅиĐŊŅдиŅĐĩĐģĐŊĐž ŅайĐģĐžĐŊа ĐēŅĐŧ вĐĩŅĐĩ ĐēаŅĐĩĐŊи ĐĩĐģĐĩĐŧĐĩĐŊŅи, иСĐŋŅĐģĐŊĐĩŅĐĩ <link>{job}</link>.",
|
||||||
"storage_template_migration_job": "ĐадаŅа Са ĐŧĐ¸ĐŗŅаŅĐ¸Ņ ĐŊа ŅайĐģĐžĐŊа Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ",
|
"storage_template_migration_job": "ĐадаŅа Са ĐŧĐ¸ĐŗŅаŅĐ¸Ņ ĐŊа ŅайĐģĐžĐŊа Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ",
|
||||||
"storage_template_more_details": "Đа ĐŋОвĐĩŅĐĩ ĐŋОдŅОйĐŊĐžŅŅи ĐžŅĐŊĐžŅĐŊĐž ŅаСи ŅŅĐŊĐēŅĐ¸Ņ ŅĐĩ ОйŅŅĐŊĐĩŅĐĩ ĐēŅĐŧ ŅайĐģĐžĐŊа <template-link>Storage Template</template-link> и ĐŊĐĩĐŗĐžĐ˛Đ¸ŅĐĩ <implications-link> ĐŋĐžŅĐģĐĩĐ´ŅŅĐ˛Đ¸Ņ </implications-link>",
|
"storage_template_more_details": "Đа ĐŋОвĐĩŅĐĩ ĐŋОдŅОйĐŊĐžŅŅи ĐžŅĐŊĐžŅĐŊĐž ŅаСи ŅŅĐŊĐēŅĐ¸Ņ ŅĐĩ ОйŅŅĐŊĐĩŅĐĩ ĐēŅĐŧ ŅайĐģĐžĐŊа <template-link>Storage Template</template-link> и ĐŊĐĩĐŗĐžĐ˛Đ¸ŅĐĩ <implications-link> ĐŋĐžŅĐģĐĩĐ´ŅŅĐ˛Đ¸Ņ </implications-link>",
|
||||||
"storage_template_onboarding_description_v2": "ĐĐžĐŗĐ°ŅĐž Đĩ ŅаСŅĐĩŅĐĩĐŊа, ŅаСи ŅŅĐŊĐēŅĐ¸Ņ ŅĐĩ ĐžŅĐŗĐ°ĐŊиСиŅа авŅĐžĐŧаŅиŅĐŊĐž ŅаКĐģОвĐĩŅĐĩ, ŅĐŋĐžŅĐĩĐ´ ŅайĐģĐžĐŊ, Đ´ĐĩŅиĐŊиŅаĐŊ ĐžŅ ĐŋĐžŅŅĐĩйиŅĐĩĐģŅ. Đа Đ´ĐžĐŋŅĐģĐŊиŅĐĩĐģĐŊа иĐŊŅĐžŅĐŧаŅиŅ, ĐŧĐžĐģŅ Đ˛Đ¸ĐļŅĐĩ <link>Đ´ĐžĐēŅĐŧĐĩĐŊŅаŅиŅŅа</link>.",
|
"storage_template_onboarding_description": "ĐĐžĐŗĐ°ŅĐž Đĩ аĐēŅивиŅаĐŊа, ŅаСи ŅŅĐŊĐēŅĐ¸Ņ ŅĐĩ ĐžŅĐŗĐ°ĐŊиСиŅа авŅĐžĐŧаŅиŅĐŊĐž ŅаКĐģОвĐĩ вŅС ĐžŅĐŊОва ĐŊа Đ´ĐĩŅиĐŊиŅаĐŊ ĐžŅ ĐŋĐžŅŅĐĩйиŅĐĩĐģŅ ŅайĐģĐžĐŊ. ĐĐžŅади ĐŋŅОйĐģĐĩĐŧи ŅŅŅ ŅŅайиĐģĐŊĐžŅŅŅа, ŅŅĐŊĐēŅиŅŅа Đĩ иСĐēĐģŅŅĐĩĐŊа ĐŋĐž ĐŋОдŅаСйиŅаĐŊĐĩ. Đа ĐŋОвĐĩŅĐĩ иĐŊŅĐžŅĐŧаŅиŅ, ĐŧĐžĐģŅ, виĐļŅĐĩ <link>Đ´ĐžĐēŅĐŧĐĩĐŊŅаŅиŅŅа</link>.",
|
||||||
"storage_template_path_length": "ĐĐŗŅаĐŊиŅĐĩĐŊиĐĩ ĐŊа Đ´ŅĐģĐļиĐŊаŅа ĐŊа ĐŋŅŅŅ: <b>{length, number}</b>/{limit, number}",
|
"storage_template_path_length": "ĐĐŗŅаĐŊиŅĐĩĐŊиĐĩ ĐŊа Đ´ŅĐģĐļиĐŊаŅа ĐŊа ĐŋŅŅŅ: <b>{length, number}</b>/{limit, number}",
|
||||||
"storage_template_settings": "ШайĐģĐžĐŊ Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ",
|
"storage_template_settings": "ШайĐģĐžĐŊ Са ŅŅŅ
ŅаĐŊĐĩĐŊиĐĩ",
|
||||||
"storage_template_settings_description": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа ŅŅŅŅĐēŅŅŅаŅа ĐŊа ĐŋаĐŋĐēиŅĐĩ и иĐŧĐĩŅĐž ĐŊа ŅаКĐģа Са ĐēаŅваĐŊĐĩ",
|
"storage_template_settings_description": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа ŅŅŅŅĐēŅŅŅаŅа ĐŊа ĐŋаĐŋĐēиŅĐĩ и иĐŧĐĩŅĐž ĐŊа ŅаКĐģа Са ĐēаŅваĐŊĐĩ",
|
||||||
@@ -373,9 +356,7 @@
|
|||||||
"admin_password": "ĐĐ´ĐŧиĐŊиŅŅŅаŅĐžŅŅĐēа ĐŋаŅĐžĐģа",
|
"admin_password": "ĐĐ´ĐŧиĐŊиŅŅŅаŅĐžŅŅĐēа ĐŋаŅĐžĐģа",
|
||||||
"administration": "ĐĐ´ĐŧиĐŊиŅŅŅаŅиŅ",
|
"administration": "ĐĐ´ĐŧиĐŊиŅŅŅаŅиŅ",
|
||||||
"advanced": "РаСŅиŅĐĩĐŊĐž",
|
"advanced": "РаСŅиŅĐĩĐŊĐž",
|
||||||
"advanced_settings_beta_timeline_subtitle": "ĐĐŋиŅаКŅĐĩ ĐŊОвиŅĐĩ ŅŅĐŊĐēŅии ĐŊа ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž",
|
"advanced_settings_enable_alternate_media_filter_subtitle": "ĐŅи ŅиĐŊŅ
ŅĐžĐŊиСаŅиŅ, иСĐŋĐžĐģСваК ŅаСи ĐžĐŋŅĐ¸Ņ ĐēаŅĐž ŅиĐģŅŅŅ, ĐžŅĐŊОваĐŊ ĐŊа ĐŋŅĐžĐŧŅĐŊа ĐŊа дадĐĩĐŊ ĐēŅиŅĐĩŅии. ĐĐŋиŅаК ŅаĐŧĐž в ŅĐģŅŅаК, ŅĐĩ ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž иĐŧа ĐŋŅОйĐģĐĩĐŧ Ņ ĐžŅĐēŅиваĐŊĐĩ ĐŊа вŅиŅĐēи аĐģĐąŅĐŧи.",
|
||||||
"advanced_settings_beta_timeline_title": "ĐĐĩŅа вĐĩŅŅĐ¸Ņ ĐŊа вŅĐĩĐŧĐĩваŅа ĐģиĐŊиŅ",
|
|
||||||
"advanced_settings_enable_alternate_media_filter_subtitle": "ĐŅи ŅиĐŊŅ
ŅĐžĐŊиСаŅиŅ, иСĐŋĐžĐģСваКŅĐĩ ŅаСи ĐžĐŋŅĐ¸Ņ ĐēаŅĐž ŅиĐģŅŅŅ, ĐžŅĐŊОваĐŊ ĐŊа ĐŋŅĐžĐŧŅĐŊа ĐŊа дадĐĩĐŊ ĐēŅиŅĐĩŅии. ĐĐŋиŅаКŅĐĩ ŅаĐŧĐž в ŅĐģŅŅаК, ŅĐĩ ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž иĐŧа ĐŋŅОйĐģĐĩĐŧ Ņ ĐžŅĐēŅиваĐŊĐĩ ĐŊа вŅиŅĐēи аĐģĐąŅĐŧи.",
|
|
||||||
"advanced_settings_enable_alternate_media_filter_title": "[ĐĐĐĄĐĐĐ ĐĐĐĐĐĸĐĐĐĐ] ĐСĐŋĐžĐģСваК ŅиĐģŅŅŅа ĐŊа аĐģŅĐĩŅĐŊаŅивĐŊĐžŅĐž ŅŅŅŅОКŅŅвО Са ŅиĐŊŅ
ŅĐžĐŊиСаŅĐ¸Ņ ĐŊа аĐģĐąŅĐŧи",
|
"advanced_settings_enable_alternate_media_filter_title": "[ĐĐĐĄĐĐĐ ĐĐĐĐĐĸĐĐĐĐ] ĐСĐŋĐžĐģСваК ŅиĐģŅŅŅа ĐŊа аĐģŅĐĩŅĐŊаŅивĐŊĐžŅĐž ŅŅŅŅОКŅŅвО Са ŅиĐŊŅ
ŅĐžĐŊиСаŅĐ¸Ņ ĐŊа аĐģĐąŅĐŧи",
|
||||||
"advanced_settings_log_level_title": "ĐивО ĐŊа СаĐŋĐ¸Ņ Đ˛ Đ´ĐŊĐĩвĐŊиĐēа: {level}",
|
"advanced_settings_log_level_title": "ĐивО ĐŊа СаĐŋĐ¸Ņ Đ˛ Đ´ĐŊĐĩвĐŊиĐēа: {level}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "ĐŅĐēОи ŅŅŅŅОКŅŅва Ņа ŅвŅŅĐ´Đĩ йавĐŊи Са да ĐŗĐĩĐŊĐĩŅиŅĐ°Ņ ĐŧиĐŊиаŅŅŅи. ĐĐēŅивиŅаК ŅаСи ĐžĐŋŅĐ¸Ņ ĐˇĐ° да ŅĐĩ СаŅĐĩĐļĐ´Đ°Ņ Đ˛Đ¸ĐŊĐ°ĐŗĐ¸ ĐžŅ ŅŅŅвŅŅа.",
|
"advanced_settings_prefer_remote_subtitle": "ĐŅĐēОи ŅŅŅŅОКŅŅва Ņа ŅвŅŅĐ´Đĩ йавĐŊи Са да ĐŗĐĩĐŊĐĩŅиŅĐ°Ņ ĐŧиĐŊиаŅŅŅи. ĐĐēŅивиŅаК ŅаСи ĐžĐŋŅĐ¸Ņ ĐˇĐ° да ŅĐĩ СаŅĐĩĐļĐ´Đ°Ņ Đ˛Đ¸ĐŊĐ°ĐŗĐ¸ ĐžŅ ŅŅŅвŅŅа.",
|
||||||
@@ -411,7 +392,7 @@
|
|||||||
"album_updated_setting_description": "ĐĐžĐģŅŅаваКŅĐĩ иСвĐĩŅŅиĐĩ ĐŋĐž иĐŧĐĩĐšĐģ, ĐēĐžĐŗĐ°ŅĐž ŅĐŋОдĐĩĐģĐĩĐŊ аĐģĐąŅĐŧ иĐŧа ĐŊОви ŅаКĐģОвĐĩ",
|
"album_updated_setting_description": "ĐĐžĐģŅŅаваКŅĐĩ иСвĐĩŅŅиĐĩ ĐŋĐž иĐŧĐĩĐšĐģ, ĐēĐžĐŗĐ°ŅĐž ŅĐŋОдĐĩĐģĐĩĐŊ аĐģĐąŅĐŧ иĐŧа ĐŊОви ŅаКĐģОвĐĩ",
|
||||||
"album_user_left": "ĐаĐŋŅŅĐŊа {album}",
|
"album_user_left": "ĐаĐŋŅŅĐŊа {album}",
|
||||||
"album_user_removed": "ĐŅĐĩĐŧаŅ
ĐŊĐ°Ņ {user}",
|
"album_user_removed": "ĐŅĐĩĐŧаŅ
ĐŊĐ°Ņ {user}",
|
||||||
"album_viewer_appbar_delete_confirm": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСŅŅиĐĩŅĐĩ ŅОСи аĐģĐąŅĐŧ ĐžŅ ŅĐ˛ĐžŅ ĐŋŅĐžŅиĐģ?",
|
"album_viewer_appbar_delete_confirm": "ĐĄĐ¸ĐŗŅŅĐĩĐŊ Đģи Ņи, ŅĐĩ иŅĐēĐ°Ņ Đ´Đ° иСŅŅиĐĩŅ ŅОСи аĐģĐąŅĐŧ ĐžŅ ŅĐ˛ĐžŅ ĐŋŅĐžŅиĐģ?",
|
||||||
"album_viewer_appbar_share_err_delete": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž иСŅŅиваĐŊĐĩ ĐŊа аĐģĐąŅĐŧ",
|
"album_viewer_appbar_share_err_delete": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž иСŅŅиваĐŊĐĩ ĐŊа аĐģĐąŅĐŧ",
|
||||||
"album_viewer_appbar_share_err_leave": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐŊаĐŋŅŅĐēаĐŊĐĩ ĐŊа аĐģĐąŅĐŧ",
|
"album_viewer_appbar_share_err_leave": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐŊаĐŋŅŅĐēаĐŊĐĩ ĐŊа аĐģĐąŅĐŧ",
|
||||||
"album_viewer_appbar_share_err_remove": "ĐŅОйĐģĐĩĐŧ ĐŋŅи ĐŋĐĩŅĐŧаŅ
ваĐŊĐĩ ĐŊа ОйĐĩĐēŅи ĐžŅ Đ°ĐģĐąŅĐŧа",
|
"album_viewer_appbar_share_err_remove": "ĐŅОйĐģĐĩĐŧ ĐŋŅи ĐŋĐĩŅĐŧаŅ
ваĐŊĐĩ ĐŊа ОйĐĩĐēŅи ĐžŅ Đ°ĐģĐąŅĐŧа",
|
||||||
@@ -445,7 +426,6 @@
|
|||||||
"app_settings": "ĐаŅŅŅОКĐēи Đŧа ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž",
|
"app_settings": "ĐаŅŅŅОКĐēи Đŧа ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž",
|
||||||
"appears_in": "ĐСĐģиСа в",
|
"appears_in": "ĐСĐģиСа в",
|
||||||
"archive": "ĐŅŅ
ив",
|
"archive": "ĐŅŅ
ив",
|
||||||
"archive_action_prompt": "{count} Ņа дОйавĐĩĐŊи в ĐŅŅ
ива",
|
|
||||||
"archive_or_unarchive_photo": "ĐŅŅ
ивиŅаĐŊĐĩ иĐģи Đ´ĐĩаŅŅ
ивиŅаĐŊĐĩ ĐŊа ŅĐŊиĐŧĐēа",
|
"archive_or_unarchive_photo": "ĐŅŅ
ивиŅаĐŊĐĩ иĐģи Đ´ĐĩаŅŅ
ивиŅаĐŊĐĩ ĐŊа ŅĐŊиĐŧĐēа",
|
||||||
"archive_page_no_archived_assets": "ĐĐĩ Ņа ĐŊаĐŧĐĩŅĐĩĐŊи ОйĐĩĐēŅи в аŅŅ
ива",
|
"archive_page_no_archived_assets": "ĐĐĩ Ņа ĐŊаĐŧĐĩŅĐĩĐŊи ОйĐĩĐēŅи в аŅŅ
ива",
|
||||||
"archive_page_title": "ĐŅŅ
ив ({count})",
|
"archive_page_title": "ĐŅŅ
ив ({count})",
|
||||||
@@ -483,12 +463,10 @@
|
|||||||
"assets": "ĐĐģĐĩĐŧĐĩĐŊŅи",
|
"assets": "ĐĐģĐĩĐŧĐĩĐŊŅи",
|
||||||
"assets_added_count": "ĐОйавĐĩĐŊĐž {count, plural, one {# asset} other {# assets}}",
|
"assets_added_count": "ĐОйавĐĩĐŊĐž {count, plural, one {# asset} other {# assets}}",
|
||||||
"assets_added_to_album_count": "ĐОйавĐĩĐŊ(и) Ņа {count, plural, one {# аĐēŅив} other {# аĐēŅива}} в аĐģĐąŅĐŧа",
|
"assets_added_to_album_count": "ĐОйавĐĩĐŊ(и) Ņа {count, plural, one {# аĐēŅив} other {# аĐēŅива}} в аĐģĐąŅĐŧа",
|
||||||
"assets_cannot_be_added_to_album_count": "{count, plural, one {ĐĐąĐĩĐēŅа ĐŊĐĩ ĐŧĐžĐļĐĩ да ŅĐĩ дОйави} other {ĐĐąĐĩĐēŅиŅĐĩ ĐŊĐĩ ĐŧĐžĐļĐĩ да ŅĐĩ дОйавŅŅ}} в аĐģĐąŅĐŧа",
|
"assets_added_to_name_count": "ĐОйавĐĩĐŊ(и) Ņа {count, plural, one {# аĐēŅив} other {# аĐēŅива}} ĐēŅĐŧ {hasName, select, true {<b>{name}</b>} other {ĐŊОв аĐģĐąŅĐŧ}}",
|
||||||
"assets_count": "{count, plural, one {# аĐēŅив} other {# аĐēŅива}}",
|
"assets_count": "{count, plural, one {# аĐēŅив} other {# аĐēŅива}}",
|
||||||
"assets_deleted_permanently": "{count} ОйĐĩĐēŅа Ņа иСŅŅиŅи СавиĐŊĐ°ĐŗĐ¸",
|
"assets_deleted_permanently": "{count} ОйĐĩĐēŅа Ņа иСŅŅиŅи СавиĐŊĐ°ĐŗĐ¸",
|
||||||
"assets_deleted_permanently_from_server": "{count} ОйĐĩĐēŅа Ņа иСŅиŅи ĐžŅ Immich ŅŅŅвŅŅа СавиĐŊĐ°ĐŗĐ¸",
|
"assets_deleted_permanently_from_server": "{count} ОйĐĩĐēŅа Ņа иСŅиŅи ĐžŅ Immich ŅŅŅвŅŅа СавиĐŊĐ°ĐŗĐ¸",
|
||||||
"assets_downloaded_failed": "{count, plural, one {ĐаŅĐĩĐ´ĐĩĐŊ # ŅаКĐģ} many {ĐаŅĐĩĐ´ĐĩĐŊи # ŅаКĐģа} other {СаŅĐĩĐ´ĐĩĐŊи # ŅаКĐģа}}, {error} - ĐŊĐĩŅŅĐŋĐĩŅĐŊĐž",
|
|
||||||
"assets_downloaded_successfully": "ĐŖŅĐŋĐĩŅĐŊĐž {count, plural, one {Đĩ ĐēаŅĐĩĐŊ # ŅаКĐģ} many {Ņа ĐēаŅĐĩĐŊи # ŅаКĐģа} other {Ņа ĐēаŅĐĩĐŊи # ŅаКĐģа}}",
|
|
||||||
"assets_moved_to_trash_count": "ĐŅĐĩĐŧĐĩŅŅĐĩĐŊ(и) Ņа {count, plural, one {# аĐēŅив} other {# аĐēŅива}} в ĐēĐžŅŅĐĩŅĐž",
|
"assets_moved_to_trash_count": "ĐŅĐĩĐŧĐĩŅŅĐĩĐŊ(и) Ņа {count, plural, one {# аĐēŅив} other {# аĐēŅива}} в ĐēĐžŅŅĐĩŅĐž",
|
||||||
"assets_permanently_deleted_count": "ĐĐžŅŅĐžŅĐŊĐŊĐž иСŅŅиŅ(и) Ņа {count, plural, one {# аĐēŅив} other {# аĐēŅива}}",
|
"assets_permanently_deleted_count": "ĐĐžŅŅĐžŅĐŊĐŊĐž иСŅŅиŅ(и) Ņа {count, plural, one {# аĐēŅив} other {# аĐēŅива}}",
|
||||||
"assets_removed_count": "ĐŅĐĩĐŧаŅ
ĐŊаŅ(и) Ņа {count, plural, one {# аĐēŅив} other {# аĐēŅива}}",
|
"assets_removed_count": "ĐŅĐĩĐŧаŅ
ĐŊаŅ(и) Ņа {count, plural, one {# аĐēŅив} other {# аĐēŅива}}",
|
||||||
@@ -508,7 +486,6 @@
|
|||||||
"back_close_deselect": "ĐаСад, СаŅваŅŅĐŊĐĩ иĐģи ĐŋŅĐĩĐŧаŅ
ваĐŊĐĩ ĐŊа иСйОŅа",
|
"back_close_deselect": "ĐаСад, СаŅваŅŅĐŊĐĩ иĐģи ĐŋŅĐĩĐŧаŅ
ваĐŊĐĩ ĐŊа иСйОŅа",
|
||||||
"background_location_permission": "РаСŅĐĩŅĐĩĐŊиĐĩ Са Đ´ĐžŅŅŅĐŋ Đ´Đž ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž вŅв ŅĐžĐŊОв ŅĐĩĐļиĐŧ",
|
"background_location_permission": "РаСŅĐĩŅĐĩĐŊиĐĩ Са Đ´ĐžŅŅŅĐŋ Đ´Đž ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž вŅв ŅĐžĐŊОв ŅĐĩĐļиĐŧ",
|
||||||
"background_location_permission_content": "Đа да ĐŧĐžĐļĐĩ да ŅĐĩŅĐĩ иĐŧĐĩĐŊаŅа ĐŊа Wi-Fi ĐŧŅĐĩĐļиŅĐĩ и да ĐŗĐ¸ ĐŋŅĐĩвĐēĐģŅŅва ĐŋŅи ŅайОŅа вŅв ŅĐžĐŊОв ŅĐĩĐļиĐŧ, Immich ŅŅŅйва *виĐŊĐ°ĐŗĐ¸* да иĐŧа Đ´ĐžŅŅŅĐŋ Đ´Đž ŅĐžŅĐŊĐžŅĐž ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ",
|
"background_location_permission_content": "Đа да ĐŧĐžĐļĐĩ да ŅĐĩŅĐĩ иĐŧĐĩĐŊаŅа ĐŊа Wi-Fi ĐŧŅĐĩĐļиŅĐĩ и да ĐŗĐ¸ ĐŋŅĐĩвĐēĐģŅŅва ĐŋŅи ŅайОŅа вŅв ŅĐžĐŊОв ŅĐĩĐļиĐŧ, Immich ŅŅŅйва *виĐŊĐ°ĐŗĐ¸* да иĐŧа Đ´ĐžŅŅŅĐŋ Đ´Đž ŅĐžŅĐŊĐžŅĐž ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ",
|
||||||
"backup": "ĐŅŅ
ивиŅаĐŊĐĩ",
|
|
||||||
"backup_album_selection_page_albums_device": "ĐĐģĐąŅĐŧи ĐŊа ŅŅŅŅОКŅŅвОŅĐž ({count})",
|
"backup_album_selection_page_albums_device": "ĐĐģĐąŅĐŧи ĐŊа ŅŅŅŅОКŅŅвОŅĐž ({count})",
|
||||||
"backup_album_selection_page_albums_tap": "ĐаŅиŅĐŊи Са да вĐēĐģŅŅиŅ, двОКĐŊĐž Са да иСĐēĐģŅŅиŅ",
|
"backup_album_selection_page_albums_tap": "ĐаŅиŅĐŊи Са да вĐēĐģŅŅиŅ, двОКĐŊĐž Са да иСĐēĐģŅŅиŅ",
|
||||||
"backup_album_selection_page_assets_scatter": "ĐĐąĐĩĐēŅиŅĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ĐąŅĐ´Đ°Ņ ŅаСĐŋŅŅŅĐŊаŅи в ĐŊŅĐēĐžĐģĐēĐž аĐģĐąŅĐŧа. ĐĐž ŅОСи ĐŊаŅиĐŊ аĐģĐąŅĐŧиŅĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ĐąŅĐ´Đ°Ņ Đ˛ĐēĐģŅŅĐĩĐŊи иĐģи иСĐēĐģŅŅĐĩĐŊи ĐŋĐž вŅĐĩĐŧĐĩ ĐŊа ĐŋŅĐžŅĐĩŅа ĐŊа аŅŅ
ивиŅаĐŊĐĩ.",
|
"backup_album_selection_page_assets_scatter": "ĐĐąĐĩĐēŅиŅĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ĐąŅĐ´Đ°Ņ ŅаСĐŋŅŅŅĐŊаŅи в ĐŊŅĐēĐžĐģĐēĐž аĐģĐąŅĐŧа. ĐĐž ŅОСи ĐŊаŅиĐŊ аĐģĐąŅĐŧиŅĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ĐąŅĐ´Đ°Ņ Đ˛ĐēĐģŅŅĐĩĐŊи иĐģи иСĐēĐģŅŅĐĩĐŊи ĐŋĐž вŅĐĩĐŧĐĩ ĐŊа ĐŋŅĐžŅĐĩŅа ĐŊа аŅŅ
ивиŅаĐŊĐĩ.",
|
||||||
@@ -528,7 +505,7 @@
|
|||||||
"backup_controller_page_background_app_refresh_disabled_title": "ФОĐŊОвО ОйĐŊОвŅваĐŊĐĩ Đĩ иСĐēĐģŅŅĐĩĐŊĐž",
|
"backup_controller_page_background_app_refresh_disabled_title": "ФОĐŊОвО ОйĐŊОвŅваĐŊĐĩ Đĩ иСĐēĐģŅŅĐĩĐŊĐž",
|
||||||
"backup_controller_page_background_app_refresh_enable_button_text": "Đди в ĐŊаŅŅŅОКĐēи",
|
"backup_controller_page_background_app_refresh_enable_button_text": "Đди в ĐŊаŅŅŅОКĐēи",
|
||||||
"backup_controller_page_background_battery_info_link": "ĐĐžĐēаĐļи Đŧи ĐēаĐē",
|
"backup_controller_page_background_battery_info_link": "ĐĐžĐēаĐļи Đŧи ĐēаĐē",
|
||||||
"backup_controller_page_background_battery_info_message": "Đа ŅŅĐŋĐĩŅĐŊĐž аŅŅ
ивиŅаĐŊĐĩ вŅв ŅĐžĐŊОв ŅĐĩĐļиĐŧ, ĐŧĐžĐģŅ Đ¸ĐˇĐēĐģŅŅĐĩŅĐĩ ĐžĐŋŅиĐŧиСаŅииŅĐĩ ĐŊа йаŅĐĩŅиŅŅа, ĐžĐŗŅаĐŊиŅаваŅи ŅĐžĐŊОваŅа аĐēŅивĐŊĐžŅŅ ĐŊа Immich.\n\nĐĸаСи ĐŊаŅŅŅОКĐēа Đĩ ŅĐŋĐžŅĐĩĐ´ ŅŅŅŅОКŅŅвОŅĐž, ĐŧĐžĐģŅ ĐŋĐžŅŅŅŅĐĩŅĐĩ иĐŊŅĐžŅĐŧаŅĐ¸Ņ ŅĐŋĐžŅĐĩĐ´ ĐŋŅОиСвОдиŅĐĩĐģŅ ĐŊа ŅŅŅŅОКŅŅвОŅĐž.",
|
"backup_controller_page_background_battery_info_message": "Đа ŅŅĐŋĐĩŅĐŊĐž аŅŅ
ивиŅаĐŊĐĩ вŅв ŅĐžĐŊОв ŅĐĩĐļиĐŧ, ĐŧĐžĐģŅ Đ¸ĐˇĐēĐģŅŅи ĐžĐŋŅиĐŧиСаŅииŅĐĩ ĐŊа йаŅĐĩŅиŅŅа, ĐžĐŗŅаĐŊиŅаваŅи ŅĐžĐŊОваŅа аĐēŅивĐŊĐžŅŅ ĐŊа Immich.\n\nĐĸаСи ĐŊаŅŅŅОКĐēа Đĩ ŅĐŋĐžŅĐĩĐ´ ŅŅŅŅОКŅŅвОŅĐž, ĐŧĐžĐģŅ ĐŋĐžŅŅŅŅи иĐŊŅĐžŅĐŧаŅĐ¸Ņ ŅĐŋĐžŅĐĩĐ´ ĐŋŅОиСвОдиŅĐĩĐģŅ ĐŊа ŅŅŅŅОКŅŅвОŅĐž.",
|
||||||
"backup_controller_page_background_battery_info_ok": "ĐĐē",
|
"backup_controller_page_background_battery_info_ok": "ĐĐē",
|
||||||
"backup_controller_page_background_battery_info_title": "ĐĐŋŅиĐŧиСаŅĐ¸Ņ ĐŊа йаŅĐĩŅиŅŅа",
|
"backup_controller_page_background_battery_info_title": "ĐĐŋŅиĐŧиСаŅĐ¸Ņ ĐŊа йаŅĐĩŅиŅŅа",
|
||||||
"backup_controller_page_background_charging": "ХаĐŧĐž ĐŋŅи СаŅĐĩĐļдаĐŊĐĩ",
|
"backup_controller_page_background_charging": "ХаĐŧĐž ĐŋŅи СаŅĐĩĐļдаĐŊĐĩ",
|
||||||
@@ -609,8 +586,8 @@
|
|||||||
"cannot_merge_people": "ĐĐĩ ĐŧĐžĐļĐĩ да ОйĐĩдиĐŊŅва Ņ
ĐžŅа",
|
"cannot_merge_people": "ĐĐĩ ĐŧĐžĐļĐĩ да ОйĐĩдиĐŊŅва Ņ
ĐžŅа",
|
||||||
"cannot_undo_this_action": "ĐĐĩ ĐŧĐžĐļĐĩŅĐĩ да ĐžŅĐŧĐĩĐŊиŅĐĩ ŅОва Đ´ĐĩĐšŅŅвиĐĩ!",
|
"cannot_undo_this_action": "ĐĐĩ ĐŧĐžĐļĐĩŅĐĩ да ĐžŅĐŧĐĩĐŊиŅĐĩ ŅОва Đ´ĐĩĐšŅŅвиĐĩ!",
|
||||||
"cannot_update_the_description": "ĐĐŋиŅаĐŊиĐĩŅĐž ĐŊĐĩ ĐŧĐžĐļĐĩ да ĐąŅĐ´Đĩ аĐēŅŅаĐģиСиŅаĐŊĐž",
|
"cannot_update_the_description": "ĐĐŋиŅаĐŊиĐĩŅĐž ĐŊĐĩ ĐŧĐžĐļĐĩ да ĐąŅĐ´Đĩ аĐēŅŅаĐģиСиŅаĐŊĐž",
|
||||||
"cast": "ĐĐžŅĐžŅĐŊĐž ĐŋŅĐĩдаваĐŊĐĩ",
|
"cast": "ĐŅĐžĐŧŅĐŊа ĐŊа ŅĐĩĐŗĐ¸ŅŅŅŅа",
|
||||||
"cast_description": "ĐаŅŅŅОКĐēа ĐŊа ĐŊаĐģиŅĐŊиŅĐĩ ŅĐĩĐģи Са ĐŋŅĐĩдаваĐŊĐĩ",
|
"cast_description": "ĐаŅŅŅОКĐēа ĐŊа ĐŊаĐģиŅĐŊиŅĐĩ ŅĐĩĐģи Са ĐŋŅĐžĐŧŅĐŊа ĐŊа ŅĐĩĐŗĐ¸ŅŅŅŅа",
|
||||||
"change_date": "ĐŅĐžĐŧĐĩĐŊи даŅаŅа",
|
"change_date": "ĐŅĐžĐŧĐĩĐŊи даŅаŅа",
|
||||||
"change_description": "ĐŅĐžĐŧĐĩĐŊи ĐžĐŋиŅаĐŊиĐĩŅĐž",
|
"change_description": "ĐŅĐžĐŧĐĩĐŊи ĐžĐŋиŅаĐŊиĐĩŅĐž",
|
||||||
"change_display_order": "ĐŅĐžĐŧĐĩĐŊи ŅĐĩда ĐŊа ĐŋĐžĐēаСваĐŊĐĩ",
|
"change_display_order": "ĐŅĐžĐŧĐĩĐŊи ŅĐĩда ĐŊа ĐŋĐžĐēаСваĐŊĐĩ",
|
||||||
@@ -621,11 +598,11 @@
|
|||||||
"change_password": "ĐŅĐžĐŧĐĩĐŊи ĐŋаŅĐžĐģаŅа",
|
"change_password": "ĐŅĐžĐŧĐĩĐŊи ĐŋаŅĐžĐģаŅа",
|
||||||
"change_password_description": "ĐĸОва Đĩ иĐģи ĐŋŅŅвиŅŅ ĐŋŅŅ, ĐēĐžĐŗĐ°ŅĐž вĐģиСаŅĐĩ в ŅиŅŅĐĩĐŧаŅа, иĐģи Đĩ ĐŊаĐŋŅавĐĩĐŊа СаŅвĐēа Са ĐŋŅĐžĐŧŅĐŊа ĐŊа ĐŋаŅĐžĐģаŅа ви. ĐĐžĐģŅ, вŅвĐĩĐ´ĐĩŅĐĩ ĐŊОваŅа ĐŋаŅĐžĐģа ĐŋĐž-Đ´ĐžĐģŅ.",
|
"change_password_description": "ĐĸОва Đĩ иĐģи ĐŋŅŅвиŅŅ ĐŋŅŅ, ĐēĐžĐŗĐ°ŅĐž вĐģиСаŅĐĩ в ŅиŅŅĐĩĐŧаŅа, иĐģи Đĩ ĐŊаĐŋŅавĐĩĐŊа СаŅвĐēа Са ĐŋŅĐžĐŧŅĐŊа ĐŊа ĐŋаŅĐžĐģаŅа ви. ĐĐžĐģŅ, вŅвĐĩĐ´ĐĩŅĐĩ ĐŊОваŅа ĐŋаŅĐžĐģа ĐŋĐž-Đ´ĐžĐģŅ.",
|
||||||
"change_password_form_confirm_password": "ĐĐžŅвŅŅди ĐŋаŅĐžĐģаŅа",
|
"change_password_form_confirm_password": "ĐĐžŅвŅŅди ĐŋаŅĐžĐģаŅа",
|
||||||
"change_password_form_description": "ĐĐ´ŅавĐĩĐšŅĐĩ {name},\n\nĐĸОва иĐģи Đĩ ĐŋŅŅвОŅĐž ви вĐŋиŅваĐŊĐĩ в ŅиŅŅĐĩĐŧаŅа иĐģи иĐŧа ĐŋОдадĐĩĐŊа СаŅвĐēа Са ŅĐŧŅĐŊа ĐŊа ĐŋаŅĐžĐģаŅа. ĐĐžĐģŅ, вŅвĐĩĐ´ĐĩŅĐĩ ĐŊОва ĐŋаŅĐžĐģа в ĐŋĐžĐģĐĩŅĐž ĐŋĐž-Đ´ĐžĐģŅ.",
|
"change_password_form_description": "ĐĐ´ŅавĐĩĐš {name},\n\nĐĸОва иĐģи Đĩ ĐŋŅŅвОŅĐž Ņи вĐŋиŅваĐŊĐĩ в ŅиŅŅĐĩĐŧаŅа иĐģи иĐŧа ĐŋОдадĐĩĐŊа СаŅвĐēа Са ŅĐŧŅĐŊа ĐŊа ĐŋаŅĐžĐģаŅа. ĐĐžĐģŅ, вŅвĐĩди ĐŊОва ĐŋаŅĐžĐģа в ĐŋĐžĐģĐĩŅĐž ĐŋĐž-Đ´ĐžĐģŅ.",
|
||||||
"change_password_form_new_password": "ĐОва ĐŋаŅĐžĐģа",
|
"change_password_form_new_password": "ĐОва ĐŋаŅĐžĐģа",
|
||||||
"change_password_form_password_mismatch": "ĐаŅĐžĐģиŅĐĩ ĐŊĐĩ ŅŅвĐŋадаŅ",
|
"change_password_form_password_mismatch": "ĐаŅĐžĐģиŅĐĩ ĐŊĐĩ ŅŅвĐŋадаŅ",
|
||||||
"change_password_form_reenter_new_password": "ĐОвŅĐžŅи ĐŊОваŅа ĐŋаŅĐžĐģа",
|
"change_password_form_reenter_new_password": "ĐОвŅĐžŅи ĐŊОваŅа ĐŋаŅĐžĐģа",
|
||||||
"change_pin_code": "ĐĄĐŧĐĩĐŊи PIN ĐēОда",
|
"change_pin_code": "ĐĄĐŧĐĩĐŊи PIN-ĐēОда",
|
||||||
"change_your_password": "ĐŅĐžĐŧĐĩĐŊĐĩŅĐĩ ĐŋаŅĐžĐģаŅа Ņи",
|
"change_your_password": "ĐŅĐžĐŧĐĩĐŊĐĩŅĐĩ ĐŋаŅĐžĐģаŅа Ņи",
|
||||||
"changed_visibility_successfully": "ĐидиĐŧĐžŅŅŅа Đĩ ĐŋŅĐžĐŧĐĩĐŊĐĩĐŊа ŅŅĐŋĐĩŅĐŊĐž",
|
"changed_visibility_successfully": "ĐидиĐŧĐžŅŅŅа Đĩ ĐŋŅĐžĐŧĐĩĐŊĐĩĐŊа ŅŅĐŋĐĩŅĐŊĐž",
|
||||||
"check_corrupt_asset_backup": "ĐŅОвĐĩŅи Са ĐŋОвŅĐĩĐ´ĐĩĐŊи аŅŅ
ивĐŊи ĐēĐžĐŋиŅ",
|
"check_corrupt_asset_backup": "ĐŅОвĐĩŅи Са ĐŋОвŅĐĩĐ´ĐĩĐŊи аŅŅ
ивĐŊи ĐēĐžĐŋиŅ",
|
||||||
@@ -658,17 +635,17 @@
|
|||||||
"comments_and_likes": "ĐĐžĐŧĐĩĐŊŅаŅи и Ņ
аŅĐĩŅваĐŊиŅ",
|
"comments_and_likes": "ĐĐžĐŧĐĩĐŊŅаŅи и Ņ
аŅĐĩŅваĐŊиŅ",
|
||||||
"comments_are_disabled": "ĐĐžĐŧĐĩĐŊŅаŅиŅĐĩ Ņа Đ´ĐĩаĐēŅивиŅаĐŊи",
|
"comments_are_disabled": "ĐĐžĐŧĐĩĐŊŅаŅиŅĐĩ Ņа Đ´ĐĩаĐēŅивиŅаĐŊи",
|
||||||
"common_create_new_album": "ĐĄŅСдаК ĐŊОв аĐģĐąŅĐŧ",
|
"common_create_new_album": "ĐĄŅСдаК ĐŊОв аĐģĐąŅĐŧ",
|
||||||
"common_server_error": "ĐĐžĐģŅ, ĐŋŅОвĐĩŅĐĩŅĐĩ ĐŧŅĐĩĐļОваŅа вŅŅСĐēа, ŅĐąĐĩĐ´ĐĩŅĐĩ ŅĐĩ, ŅĐĩ ŅŅŅвŅŅа Đĩ Đ´ĐžŅŅŅĐŋĐĩĐŊ и вĐĩŅŅииŅĐĩ ĐŊа ŅŅŅвŅŅа и ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž Ņа ŅŅвĐŧĐĩŅŅиĐŧи.",
|
"common_server_error": "ĐĐžĐģŅ, ĐŋŅОвĐĩŅи ĐŧŅĐĩĐļОваŅа вŅŅСĐēа, ŅĐąĐĩди ŅĐĩ, ŅĐĩ ŅŅŅвŅŅа Đĩ Đ´ĐžŅŅŅĐŋĐĩĐŊ и вĐĩŅŅииŅĐĩ ĐŊа ŅŅŅвŅŅа и ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž Ņа ŅŅвĐŧĐĩŅŅиĐŧи.",
|
||||||
"completed": "ĐавŅŅŅĐĩĐŊĐž",
|
"completed": "ĐавŅŅŅĐĩĐŊĐž",
|
||||||
"confirm": "ĐĐžŅвŅŅди",
|
"confirm": "ĐĐžŅвŅŅди",
|
||||||
"confirm_admin_password": "ĐĐžŅвŅŅĐļдаваĐŊĐĩ ĐŊа ĐŋаŅĐžĐģаŅа ĐŊа адĐŧиĐŊиŅŅŅаŅĐžŅа",
|
"confirm_admin_password": "ĐĐžŅвŅŅĐļдаваĐŊĐĩ ĐŊа ĐŋаŅĐžĐģаŅа ĐŊа адĐŧиĐŊиŅŅŅаŅĐžŅа",
|
||||||
"confirm_delete_face": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСŅŅиĐĩŅĐĩ ĐģиŅĐĩŅĐž ĐŊа {name} ĐžŅ Đ°ĐēŅива?",
|
"confirm_delete_face": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСŅŅиĐĩŅĐĩ ĐģиŅĐĩŅĐž ĐŊа {name} ĐžŅ Đ°ĐēŅива?",
|
||||||
"confirm_delete_shared_link": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСŅŅиĐĩŅĐĩ ŅаСи ŅĐŋОдĐĩĐģĐĩĐŊа вŅŅСĐēа?",
|
"confirm_delete_shared_link": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСŅŅиĐĩŅĐĩ ŅаСи ŅĐŋОдĐĩĐģĐĩĐŊа вŅŅСĐēа?",
|
||||||
"confirm_keep_this_delete_others": "ĐŅиŅĐēи ĐžŅŅаĐŊаĐģи ŅаКĐģОвĐĩ в ŅŅĐĩĐēа ŅĐĩ ĐąŅĐ´Đ°Ņ Đ¸ĐˇŅŅиŅи, Ņ Đ¸ĐˇĐēĐģŅŅĐĩĐŊиĐĩ ĐŊа ŅОСи ŅаКĐģ. ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да ĐŋŅОдŅĐģĐļиŅĐĩ?",
|
"confirm_keep_this_delete_others": "ĐŅиŅĐēи ĐžŅŅаĐŊаĐģи ŅаКĐģОвĐĩ в ŅŅĐĩĐēа ŅĐĩ ĐąŅĐ´Đ°Ņ Đ¸ĐˇŅŅиŅи, Ņ Đ¸ĐˇĐēĐģŅŅĐĩĐŊиĐĩ ĐŊа ŅОСи ŅаКĐģ. ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да ĐŋŅОдŅĐģĐļиŅĐĩ?",
|
||||||
"confirm_new_pin_code": "ĐĐžŅвŅŅди ĐŊĐžĐ˛Đ¸Ņ PIN ĐēОд",
|
"confirm_new_pin_code": "ĐĐžŅвŅŅди ĐŊĐžĐ˛Đ¸Ņ PIN-ĐēОд",
|
||||||
"confirm_password": "ĐĐžŅвŅŅĐ´ĐĩŅĐĩ ĐŋаŅĐžĐģаŅа",
|
"confirm_password": "ĐĐžŅвŅŅĐ´ĐĩŅĐĩ ĐŋаŅĐžĐģаŅа",
|
||||||
"confirm_tag_face": "ĐŅĐēаŅĐĩ Đģи да ĐžŅĐąĐĩĐģĐĩĐļиŅĐĩ ŅОва ĐģиŅĐĩ ĐēаŅĐž {name}?",
|
"confirm_tag_face": "ĐŅĐēĐ°Ņ Đģи да ĐžŅĐąĐĩĐģĐĩĐļĐ¸Ņ ŅОва ĐģиŅĐĩ ĐēаŅĐž {name}?",
|
||||||
"confirm_tag_face_unnamed": "ĐŅĐēаŅĐĩ Đģи да ĐžŅĐąĐĩĐģĐĩĐļиŅĐĩ ŅОва ĐģиŅĐĩ?",
|
"confirm_tag_face_unnamed": "ĐŅĐēĐ°Ņ Đģи да ĐžŅĐąĐĩĐģĐĩĐļĐ¸Ņ ŅОва ĐģиŅĐĩ?",
|
||||||
"connected_device": "ХвŅŅСаĐŊĐž ŅŅŅŅОКŅŅвО",
|
"connected_device": "ХвŅŅСаĐŊĐž ŅŅŅŅОКŅŅвО",
|
||||||
"connected_to": "ХвŅŅСаĐŊ ĐēŅĐŧ",
|
"connected_to": "ХвŅŅСаĐŊ ĐēŅĐŧ",
|
||||||
"contain": "Đ ŅаĐŧĐēиŅĐĩ ĐŊа",
|
"contain": "Đ ŅаĐŧĐēиŅĐĩ ĐŊа",
|
||||||
@@ -715,14 +692,14 @@
|
|||||||
"crop": "ĐСŅĐĩĐļи",
|
"crop": "ĐСŅĐĩĐļи",
|
||||||
"curated_object_page_title": "ĐĐĩŅа",
|
"curated_object_page_title": "ĐĐĩŅа",
|
||||||
"current_device": "ĐĸĐĩĐēŅŅĐž ŅŅŅŅОКŅŅвО",
|
"current_device": "ĐĸĐĩĐēŅŅĐž ŅŅŅŅОКŅŅвО",
|
||||||
"current_pin_code": "ĐĄĐĩĐŗĐ°ŅĐĩĐŊ PIN ĐēОд",
|
"current_pin_code": "ĐĄĐĩĐŗĐ°ŅĐĩĐŊ PIN-ĐēОд",
|
||||||
"current_server_address": "ĐаŅŅĐžŅŅ Đ°Đ´ŅĐĩŅ ĐŊа ŅŅŅвŅŅа",
|
"current_server_address": "ĐаŅŅĐžŅŅ Đ°Đ´ŅĐĩŅ ĐŊа ŅŅŅвŅŅа",
|
||||||
"custom_locale": "ĐĐĩŅŅĐžĐŊаĐģиСиŅаĐŊ ĐģĐžĐēаĐģ",
|
"custom_locale": "ĐĐĩŅŅĐžĐŊаĐģиСиŅаĐŊ ĐģĐžĐēаĐģ",
|
||||||
"custom_locale_description": "ФОŅĐŧаŅиŅаĐŊĐĩ ĐŊа даŅи и ŅиŅĐģа в СавиŅиĐŧĐžŅŅ ĐžŅ ĐĩСиĐēа и ŅĐĩĐŗĐ¸ĐžĐŊа",
|
"custom_locale_description": "ФОŅĐŧаŅиŅаĐŊĐĩ ĐŊа даŅи и ŅиŅĐģа в СавиŅиĐŧĐžŅŅ ĐžŅ ĐĩСиĐēа и ŅĐĩĐŗĐ¸ĐžĐŊа",
|
||||||
"daily_title_text_date": "E, dd MMM",
|
"daily_title_text_date": "E, dd MMM",
|
||||||
"daily_title_text_date_year": "E, dd MMM yyyy",
|
"daily_title_text_date_year": "E, dd MMM yyyy",
|
||||||
"dark": "ĐĸŅĐŧĐĩĐŊ",
|
"dark": "ĐĸŅĐŧĐĩĐŊ",
|
||||||
"dark_theme": "ĐĸŅĐŧĐŊа ŅĐĩĐŧа",
|
"darkTheme": "ĐŅĐĩвĐēĐģŅŅи ĐŊа ŅŅĐŧĐŊа ŅĐĩĐŧа",
|
||||||
"date_after": "ĐаŅа ŅĐģĐĩĐ´",
|
"date_after": "ĐаŅа ŅĐģĐĩĐ´",
|
||||||
"date_and_time": "ĐаŅа и ŅаŅ",
|
"date_and_time": "ĐаŅа и ŅаŅ",
|
||||||
"date_before": "ĐаŅа ĐŋŅĐĩди",
|
"date_before": "ĐаŅа ĐŋŅĐĩди",
|
||||||
@@ -736,9 +713,8 @@
|
|||||||
"deduplication_info": "ĐĐŊŅĐžŅĐŧаŅĐ¸Ņ ĐˇĐ° Đ´ĐĩĐ´ŅĐŋĐģиĐēаŅиŅŅа",
|
"deduplication_info": "ĐĐŊŅĐžŅĐŧаŅĐ¸Ņ ĐˇĐ° Đ´ĐĩĐ´ŅĐŋĐģиĐēаŅиŅŅа",
|
||||||
"deduplication_info_description": "Đа авŅĐžĐŧаŅиŅĐŊĐž ĐŋŅĐĩдваŅиŅĐĩĐģĐŊĐž иСйиŅаĐŊĐĩ ĐŊа ŅĐĩŅŅŅŅи и ĐŋŅĐĩĐŧаŅ
ваĐŊĐĩ ĐŊа Đ´ŅĐąĐģиĐēаŅи ĐŊа ĐĩĐ´ŅĐž, ŅĐ°ĐˇĐŗĐģĐĩĐļдаĐŧĐĩ:",
|
"deduplication_info_description": "Đа авŅĐžĐŧаŅиŅĐŊĐž ĐŋŅĐĩдваŅиŅĐĩĐģĐŊĐž иСйиŅаĐŊĐĩ ĐŊа ŅĐĩŅŅŅŅи и ĐŋŅĐĩĐŧаŅ
ваĐŊĐĩ ĐŊа Đ´ŅĐąĐģиĐēаŅи ĐŊа ĐĩĐ´ŅĐž, ŅĐ°ĐˇĐŗĐģĐĩĐļдаĐŧĐĩ:",
|
||||||
"default_locale": "ĐĐžĐēаĐģиСаŅĐ¸Ņ ĐŋĐž ĐŋОдŅаСйиŅаĐŊĐĩ",
|
"default_locale": "ĐĐžĐēаĐģиСаŅĐ¸Ņ ĐŋĐž ĐŋОдŅаСйиŅаĐŊĐĩ",
|
||||||
"default_locale_description": "ФОŅĐŧаŅиŅаĐŊĐĩ ĐŊа даŅи и ŅиŅĐģа в СавиŅиĐŧĐžŅŅ ĐžŅ ĐĩСиĐēОваŅа ĐŊаŅŅŅОКĐēа ĐŊа ĐąŅаŅСŅŅа",
|
"default_locale_description": "ФОŅĐŧаŅиŅаĐŊĐĩ ĐŊа даŅи и ŅиŅĐģа в СавиŅиĐŧĐžŅŅ ĐžŅ ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž ĐŊа ĐąŅаŅСŅŅа",
|
||||||
"delete": "ĐСŅŅиК",
|
"delete": "ĐСŅŅиК",
|
||||||
"delete_action_prompt": "{count} Ņа иСŅŅиŅи СавиĐŊĐ°ĐŗĐ¸",
|
|
||||||
"delete_album": "ĐСŅŅиК аĐģĐąŅĐŧ",
|
"delete_album": "ĐСŅŅиК аĐģĐąŅĐŧ",
|
||||||
"delete_api_key_prompt": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСŅŅиĐĩŅĐĩ ŅОСи API ĐēĐģŅŅ?",
|
"delete_api_key_prompt": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСŅŅиĐĩŅĐĩ ŅОСи API ĐēĐģŅŅ?",
|
||||||
"delete_dialog_alert": "ĐĸĐĩСи ОйĐĩĐēŅи ŅĐĩ ĐąŅĐ´Đ°Ņ Đ¸ĐˇŅŅиŅи СавиĐŊĐ°ĐŗĐ¸ и ĐžŅ Immich ŅŅŅвŅŅа и ĐžŅ ŅŅŅŅОКŅŅвОŅĐž",
|
"delete_dialog_alert": "ĐĸĐĩСи ОйĐĩĐēŅи ŅĐĩ ĐąŅĐ´Đ°Ņ Đ¸ĐˇŅŅиŅи СавиĐŊĐ°ĐŗĐ¸ и ĐžŅ Immich ŅŅŅвŅŅа и ĐžŅ ŅŅŅŅОКŅŅвОŅĐž",
|
||||||
@@ -752,20 +728,19 @@
|
|||||||
"delete_key": "ĐСŅŅиК ĐēĐģŅŅ",
|
"delete_key": "ĐСŅŅиК ĐēĐģŅŅ",
|
||||||
"delete_library": "ĐСŅŅиК йийĐģиОŅĐĩĐēа",
|
"delete_library": "ĐСŅŅиК йийĐģиОŅĐĩĐēа",
|
||||||
"delete_link": "ĐСŅŅиК ĐģиĐŊĐē",
|
"delete_link": "ĐСŅŅиК ĐģиĐŊĐē",
|
||||||
"delete_local_action_prompt": "{count} Ņа иСŅŅиŅи ĐģĐžĐēаĐģĐŊĐž",
|
|
||||||
"delete_local_dialog_ok_backed_up_only": "ĐСŅŅиК ĐģĐžĐēаĐģĐŊĐž ŅаĐŧĐž аŅŅ
ивиŅаĐŊиŅĐĩ",
|
"delete_local_dialog_ok_backed_up_only": "ĐСŅŅиК ĐģĐžĐēаĐģĐŊĐž ŅаĐŧĐž аŅŅ
ивиŅаĐŊиŅĐĩ",
|
||||||
"delete_local_dialog_ok_force": "ĐŅĐŋŅĐĩĐēи ŅОва иСŅŅиК",
|
"delete_local_dialog_ok_force": "ĐŅĐŋŅĐĩĐēи ŅОва иСŅŅиК",
|
||||||
"delete_others": "ĐСŅŅиК ĐžŅŅаĐŊаĐģиŅĐĩ",
|
"delete_others": "ĐСŅŅиК ĐžŅŅаĐŊаĐģиŅĐĩ",
|
||||||
"delete_shared_link": "ĐСŅŅиваĐŊĐĩ ĐŊа ŅĐŋОдĐĩĐģĐĩĐŊ ĐģиĐŊĐē",
|
"delete_shared_link": "ĐСŅŅиваĐŊĐĩ ĐŊа ŅĐŋОдĐĩĐģĐĩĐŊ ĐģиĐŊĐē",
|
||||||
"delete_shared_link_dialog_title": "ĐСŅŅиК ŅĐŋОдĐĩĐģĐĩĐŊаŅа вŅŅСĐēа",
|
"delete_shared_link_dialog_title": "ĐСŅŅиК ŅĐŋОдĐĩĐģĐĩĐŊаŅа вŅŅСĐēа",
|
||||||
"delete_tag": "ĐСŅŅиК ŅĐ°Đŗ",
|
"delete_tag": "ĐСŅŅиК ŅĐ°Đŗ",
|
||||||
"delete_tag_confirmation_prompt": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСŅŅиĐĩŅĐĩ ŅĐ°ĐŗĐ° {tagName}?",
|
"delete_tag_confirmation_prompt": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСŅŅиĐĩŅĐĩ ŅĐ°Đŗ {tagName}?",
|
||||||
"delete_user": "ĐСŅŅиК ĐŋĐžŅŅĐĩйиŅĐĩĐģ",
|
"delete_user": "ĐСŅŅиК ĐŋĐžŅŅĐĩйиŅĐĩĐģ",
|
||||||
"deleted_shared_link": "ĐСŅŅĐ¸Ņ ŅĐŋОдĐĩĐģĐĩĐŊ ĐģиĐŊĐē",
|
"deleted_shared_link": "ĐСŅŅĐ¸Ņ ŅĐŋОдĐĩĐģĐĩĐŊ ĐģиĐŊĐē",
|
||||||
"deletes_missing_assets": "ĐСŅŅива ŅаКĐģОвĐĩ, ĐēОиŅĐž ĐģиĐŋŅĐ˛Đ°Ņ ĐŊа диŅĐēа",
|
"deletes_missing_assets": "ĐСŅŅива ŅаКĐģОвĐĩ, ĐēОиŅĐž ĐģиĐŋŅĐ˛Đ°Ņ ĐŊа диŅĐēа",
|
||||||
"description": "ĐĐŋиŅаĐŊиĐĩ",
|
"description": "ĐĐŋиŅаĐŊиĐĩ",
|
||||||
"description_input_hint_text": "ĐОйави ĐžĐŋиŅаĐŊиĐĩ...",
|
"description_input_hint_text": "ĐОйави ĐžĐŋиŅаĐŊиĐĩ...",
|
||||||
"description_input_submit_error": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ОйĐŊОвŅваĐŊĐĩ ĐŊа ĐžĐŋиŅаĐŊиĐĩŅĐž. Đа ĐŋОдŅОйĐŊĐžŅŅи виĐļŅĐĩ в Đ´ĐŊĐĩвĐŊиĐēа",
|
"description_input_submit_error": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ОйĐŊОвŅваĐŊĐĩ ĐŊа ĐžĐŋиŅаĐŊиĐĩŅĐž. Đа ĐŋОдŅОйĐŊĐžŅŅи виĐļ в Đ´ĐŊĐĩвĐŊиĐēа",
|
||||||
"details": "ĐĐĩŅаКĐģи",
|
"details": "ĐĐĩŅаКĐģи",
|
||||||
"direction": "ĐĐžŅĐžĐēа",
|
"direction": "ĐĐžŅĐžĐēа",
|
||||||
"disabled": "ĐСĐēĐģŅŅĐĩĐŊĐž",
|
"disabled": "ĐСĐēĐģŅŅĐĩĐŊĐž",
|
||||||
@@ -783,7 +758,6 @@
|
|||||||
"documentation": "ĐĐžĐēŅĐŧĐĩĐŊŅаŅиŅ",
|
"documentation": "ĐĐžĐēŅĐŧĐĩĐŊŅаŅиŅ",
|
||||||
"done": "ĐĐžŅОвО",
|
"done": "ĐĐžŅОвО",
|
||||||
"download": "ĐСŅĐĩĐŗĐģи",
|
"download": "ĐСŅĐĩĐŗĐģи",
|
||||||
"download_action_prompt": "ĐаŅĐĩĐļдаĐŊĐĩ ĐŊа {count} ОйĐĩĐēŅа",
|
|
||||||
"download_canceled": "ĐСŅĐĩĐŗĐģŅĐŊĐĩŅĐž Đĩ ĐžŅĐŧĐĩĐŊĐĩĐŊĐž",
|
"download_canceled": "ĐСŅĐĩĐŗĐģŅĐŊĐĩŅĐž Đĩ ĐžŅĐŧĐĩĐŊĐĩĐŊĐž",
|
||||||
"download_complete": "ĐСŅĐĩĐŗĐģŅĐŊĐĩŅĐž СавŅŅŅи",
|
"download_complete": "ĐСŅĐĩĐŗĐģŅĐŊĐĩŅĐž СавŅŅŅи",
|
||||||
"download_enqueue": "ĐСŅĐĩĐŗĐģŅĐŊĐĩŅĐž Đĩ дОйавĐĩĐŊĐž в ĐžĐŋаŅĐēаŅа",
|
"download_enqueue": "ĐСŅĐĩĐŗĐģŅĐŊĐĩŅĐž Đĩ дОйавĐĩĐŊĐž в ĐžĐŋаŅĐēаŅа",
|
||||||
@@ -821,7 +795,6 @@
|
|||||||
"edit_key": "Đ ĐĩдаĐēŅиŅаĐŊĐĩ ĐŊа ĐēĐģŅŅ",
|
"edit_key": "Đ ĐĩдаĐēŅиŅаĐŊĐĩ ĐŊа ĐēĐģŅŅ",
|
||||||
"edit_link": "Đ ĐĩдаĐēŅиŅаĐŊĐĩ ĐŊа ĐģиĐŊĐē",
|
"edit_link": "Đ ĐĩдаĐēŅиŅаĐŊĐĩ ĐŊа ĐģиĐŊĐē",
|
||||||
"edit_location": "Đ ĐĩдаĐēŅиŅаĐŊĐĩ ĐŊа ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž",
|
"edit_location": "Đ ĐĩдаĐēŅиŅаĐŊĐĩ ĐŊа ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž",
|
||||||
"edit_location_action_prompt": "{count} ĐģĐžĐēаŅии Ņа ŅĐĩдаĐēŅиŅаĐŊи",
|
|
||||||
"edit_location_dialog_title": "ĐĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ",
|
"edit_location_dialog_title": "ĐĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ",
|
||||||
"edit_name": "Đ ĐĩдаĐēŅиŅаĐŊĐĩ ĐŊа иĐŧĐĩ",
|
"edit_name": "Đ ĐĩдаĐēŅиŅаĐŊĐĩ ĐŊа иĐŧĐĩ",
|
||||||
"edit_people": "Đ ĐĩдаĐēŅиŅаĐŊĐĩ ĐŊа Ņ
ĐžŅа",
|
"edit_people": "Đ ĐĩдаĐēŅиŅаĐŊĐĩ ĐŊа Ņ
ĐžŅа",
|
||||||
@@ -840,13 +813,13 @@
|
|||||||
"empty_trash": "ĐСĐŋŅаСваĐŊĐĩ ĐŊа ĐēĐžŅ",
|
"empty_trash": "ĐСĐŋŅаСваĐŊĐĩ ĐŊа ĐēĐžŅ",
|
||||||
"empty_trash_confirmation": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСĐŋŅаСĐŊиŅĐĩ ĐēĐžŅŅĐĩŅĐž? ĐĸОва ŅĐĩ ĐŋŅĐĩĐŧаŅ
ĐŊĐĩ вŅиŅĐēĐž в ĐēĐžŅŅĐĩŅĐž Са ĐŋĐžŅŅĐžŅĐŊĐŊĐž ĐžŅ Immich.\nĐĐĩ ĐŧĐžĐļĐĩŅĐĩ да ĐžŅĐŧĐĩĐŊиŅĐĩ ŅОва Đ´ĐĩĐšŅŅвиĐĩ!",
|
"empty_trash_confirmation": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи ŅŅĐĩ, ŅĐĩ иŅĐēаŅĐĩ да иСĐŋŅаСĐŊиŅĐĩ ĐēĐžŅŅĐĩŅĐž? ĐĸОва ŅĐĩ ĐŋŅĐĩĐŧаŅ
ĐŊĐĩ вŅиŅĐēĐž в ĐēĐžŅŅĐĩŅĐž Са ĐŋĐžŅŅĐžŅĐŊĐŊĐž ĐžŅ Immich.\nĐĐĩ ĐŧĐžĐļĐĩŅĐĩ да ĐžŅĐŧĐĩĐŊиŅĐĩ ŅОва Đ´ĐĩĐšŅŅвиĐĩ!",
|
||||||
"enable": "ĐĐēĐģŅŅваĐŊĐĩ",
|
"enable": "ĐĐēĐģŅŅваĐŊĐĩ",
|
||||||
"enable_biometric_auth_description": "ĐŅвĐĩĐ´ĐĩŅĐĩ ваŅĐ¸Ņ PIN ĐēОд, Са да ŅаСŅĐĩŅиŅĐĩ йиОĐŧĐĩŅŅиŅĐŊĐž ŅĐ´ĐžŅŅОвĐĩŅŅваĐŊĐĩ",
|
"enable_biometric_auth_description": "ĐŅвĐĩди ŅĐ˛ĐžŅ ĐĐĐ-ĐēОд, Са да ŅаСŅĐĩŅĐ¸Ņ ĐąĐ¸ĐžĐŧĐĩŅŅиŅĐŊĐž ŅĐ´ĐžŅŅОвĐĩŅŅваĐŊĐĩ",
|
||||||
"enabled": "ĐĐēĐģŅŅĐĩĐŊĐž",
|
"enabled": "ĐĐēĐģŅŅĐĩĐŊĐž",
|
||||||
"end_date": "ĐŅаКĐŊа даŅа",
|
"end_date": "ĐŅаКĐŊа даŅа",
|
||||||
"enqueued": "ĐаŅĐĩĐ´ĐĩĐŊĐž в ĐžĐŋаŅĐēаŅа",
|
"enqueued": "ĐаŅĐĩĐ´ĐĩĐŊĐž в ĐžĐŋаŅĐēаŅа",
|
||||||
"enter_wifi_name": "ĐŅвĐĩди иĐŧĐĩ ĐŊа Wi-Fi",
|
"enter_wifi_name": "ĐŅвĐĩди иĐŧĐĩ ĐŊа Wi-Fi",
|
||||||
"enter_your_pin_code": "ĐŅвĐĩĐ´ĐĩŅĐĩ ваŅĐ¸Ņ PIN ĐēОд",
|
"enter_your_pin_code": "ĐŅвĐĩди ŅĐ˛ĐžŅ PIN-ĐēОд",
|
||||||
"enter_your_pin_code_subtitle": "ĐŅвĐĩĐļдаĐŊĐĩ ĐŊа PIN ĐēОд, Са Đ´ĐžŅŅŅĐŋ Đ´Đž СаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа",
|
"enter_your_pin_code_subtitle": "ĐŅвĐĩди ŅĐ˛ĐžŅ PIN-ĐēОд, Са да Đ´ĐžŅŅŅĐŋĐ¸Ņ ĐˇĐ°ĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа",
|
||||||
"error": "ĐŅĐĩŅĐēа",
|
"error": "ĐŅĐĩŅĐēа",
|
||||||
"error_change_sort_album": "ĐĐĩŅŅĐŋĐĩŅĐŊа ĐŋŅĐžĐŧŅĐŊа ĐŊа ŅĐĩда ĐŊа ŅĐžŅŅиŅаĐŊĐĩ ĐŊа аĐģĐąŅĐŧ",
|
"error_change_sort_album": "ĐĐĩŅŅĐŋĐĩŅĐŊа ĐŋŅĐžĐŧŅĐŊа ĐŊа ŅĐĩда ĐŊа ŅĐžŅŅиŅаĐŊĐĩ ĐŊа аĐģĐąŅĐŧ",
|
||||||
"error_delete_face": "ĐŅĐĩŅĐēа ĐŋŅи иСŅŅиваĐŊĐĩ ĐŊа ĐģиŅĐĩ ĐžŅ Đ°ĐēŅива",
|
"error_delete_face": "ĐŅĐĩŅĐēа ĐŋŅи иСŅŅиваĐŊĐĩ ĐŊа ĐģиŅĐĩ ĐžŅ Đ°ĐēŅива",
|
||||||
@@ -946,7 +919,7 @@
|
|||||||
"unable_to_remove_partner": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐŋŅĐĩĐŧаŅ
ваĐŊĐĩ ĐŊа ĐŋаŅŅĐŊŅĐžŅ",
|
"unable_to_remove_partner": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐŋŅĐĩĐŧаŅ
ваĐŊĐĩ ĐŊа ĐŋаŅŅĐŊŅĐžŅ",
|
||||||
"unable_to_remove_reaction": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐŋŅĐĩĐŧаŅ
ваĐŊĐĩ ĐŊа ŅĐĩаĐēŅиŅŅа",
|
"unable_to_remove_reaction": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐŋŅĐĩĐŧаŅ
ваĐŊĐĩ ĐŊа ŅĐĩаĐēŅиŅŅа",
|
||||||
"unable_to_reset_password": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ŅĐŧŅĐŊа ĐŊа ĐŋаŅĐžĐģаŅа",
|
"unable_to_reset_password": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ŅĐŧŅĐŊа ĐŊа ĐŋаŅĐžĐģаŅа",
|
||||||
"unable_to_reset_pin_code": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐŊŅĐģиŅаĐŊĐĩ ĐŊа PIN ĐēОда",
|
"unable_to_reset_pin_code": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐŊŅĐģиŅаĐŊĐĩ ĐŊа PIN-ĐēОда",
|
||||||
"unable_to_resolve_duplicate": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ŅĐŋŅавŅĐŊĐĩ Ņ Đ´ŅĐąĐģиŅаĐŊĐĩŅĐž",
|
"unable_to_resolve_duplicate": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ŅĐŋŅавŅĐŊĐĩ Ņ Đ´ŅĐąĐģиŅаĐŊĐĩŅĐž",
|
||||||
"unable_to_restore_assets": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž вŅСŅŅаĐŊОвŅваĐŊĐĩ ĐŊа ĐĩĐģĐĩĐŧĐĩĐŊŅи",
|
"unable_to_restore_assets": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž вŅСŅŅаĐŊОвŅваĐŊĐĩ ĐŊа ĐĩĐģĐĩĐŧĐĩĐŊŅи",
|
||||||
"unable_to_restore_trash": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž вŅСŅŅаĐŊОвŅваĐŊĐĩ ĐžŅ ĐēĐžŅŅĐĩŅĐž",
|
"unable_to_restore_trash": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž вŅСŅŅаĐŊОвŅваĐŊĐĩ ĐžŅ ĐēĐžŅŅĐĩŅĐž",
|
||||||
@@ -1007,7 +980,6 @@
|
|||||||
"failed_to_load_assets": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž СаŅĐĩĐļдаĐŊĐĩ ĐŊа ĐĩĐģĐĩĐŧĐĩĐŊŅи",
|
"failed_to_load_assets": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž СаŅĐĩĐļдаĐŊĐĩ ĐŊа ĐĩĐģĐĩĐŧĐĩĐŊŅи",
|
||||||
"failed_to_load_folder": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž СаŅĐĩĐļдаĐŊĐĩ ĐŊа ĐŋаĐŋĐēа",
|
"failed_to_load_folder": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž СаŅĐĩĐļдаĐŊĐĩ ĐŊа ĐŋаĐŋĐēа",
|
||||||
"favorite": "ĐŅйиĐŧ",
|
"favorite": "ĐŅйиĐŧ",
|
||||||
"favorite_action_prompt": "{count} Ņа дОйавĐĩĐŊи в ĐŅйиĐŧи",
|
|
||||||
"favorite_or_unfavorite_photo": "ĐОйави иĐģи ĐŋŅĐĩĐŧаŅ
ĐŊи ŅĐŊиĐŧĐēа ĐžŅ ĐŅйиĐŧи",
|
"favorite_or_unfavorite_photo": "ĐОйави иĐģи ĐŋŅĐĩĐŧаŅ
ĐŊи ŅĐŊиĐŧĐēа ĐžŅ ĐŅйиĐŧи",
|
||||||
"favorites": "ĐŅйиĐŧи",
|
"favorites": "ĐŅйиĐŧи",
|
||||||
"favorites_page_no_favorites": "ĐĐĩ Ņа ĐŊаĐŧĐĩŅĐĩĐŊи ĐģŅйиĐŧи ОйĐĩĐēŅи",
|
"favorites_page_no_favorites": "ĐĐĩ Ņа ĐŊаĐŧĐĩŅĐĩĐŊи ĐģŅйиĐŧи ОйĐĩĐēŅи",
|
||||||
@@ -1032,7 +1004,7 @@
|
|||||||
"gcast_enabled_description": "Đа да ŅайОŅи ŅаСи ŅŅĐŊĐēŅĐ¸Ņ ĐˇĐ°ŅĐĩĐļда вŅĐŊŅĐŊи ŅĐĩŅŅŅŅи ĐžŅ Google.",
|
"gcast_enabled_description": "Đа да ŅайОŅи ŅаСи ŅŅĐŊĐēŅĐ¸Ņ ĐˇĐ°ŅĐĩĐļда вŅĐŊŅĐŊи ŅĐĩŅŅŅŅи ĐžŅ Google.",
|
||||||
"general": "ĐĐąŅи",
|
"general": "ĐĐąŅи",
|
||||||
"get_help": "ĐĐžĐŧĐžŅ",
|
"get_help": "ĐĐžĐŧĐžŅ",
|
||||||
"get_wifiname_error": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐŋĐžĐģŅŅаваĐŊĐĩ иĐŧĐĩŅĐž ĐŊа Wi-Fi ĐŧŅĐĩĐļаŅа. ĐĐžĐģŅ, ŅĐąĐĩĐ´ĐĩŅĐĩ ŅĐĩ, ŅĐĩ Ņа ĐŋŅĐĩĐ´ĐžŅŅавĐĩĐŊи ĐŊŅĐļĐŊиŅĐĩ ŅаСŅĐĩŅĐĩĐŊĐ¸Ņ ĐŊа ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž и иĐŧа вŅŅСĐēа Ņ Wi-Fi",
|
"get_wifiname_error": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐŋĐžĐģŅŅаваĐŊĐĩ иĐŧĐĩŅĐž ĐŊа Wi-Fi ĐŧŅĐĩĐļаŅа. ĐĐžĐģŅ, ŅĐąĐĩди ŅĐĩ, ŅĐĩ Ņа ĐŋŅĐĩĐ´ĐžŅŅавĐĩĐŊи ĐŊŅĐļĐŊиŅĐĩ ŅаСŅĐĩŅĐĩĐŊĐ¸Ņ ĐŊа ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž и иĐŧа вŅŅСĐēа Ņ Wi-Fi",
|
||||||
"getting_started": "ĐаĐē да СаĐŋĐžŅĐŊĐĩĐŧ",
|
"getting_started": "ĐаĐē да СаĐŋĐžŅĐŊĐĩĐŧ",
|
||||||
"go_back": "ĐŅŅŅаĐŊĐĩ ĐŊаСад",
|
"go_back": "ĐŅŅŅаĐŊĐĩ ĐŊаСад",
|
||||||
"go_to_folder": "ĐŅиди в ĐŋаĐŋĐēаŅа",
|
"go_to_folder": "ĐŅиди в ĐŋаĐŋĐēаŅа",
|
||||||
@@ -1071,7 +1043,7 @@
|
|||||||
"home_page_delete_remote_err_local": "ĐĐžĐēаĐģĐŊи ОйĐĩĐēŅи ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ иСŅŅĐ¸Đ˛Đ°Ņ ĐžŅ ŅŅŅвŅŅа, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
"home_page_delete_remote_err_local": "ĐĐžĐēаĐģĐŊи ОйĐĩĐēŅи ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ иСŅŅĐ¸Đ˛Đ°Ņ ĐžŅ ŅŅŅвŅŅа, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
||||||
"home_page_favorite_err_local": "ĐĐžĐēаĐģĐŊи ОйĐĩĐēŅи вŅĐĩ ĐžŅĐĩ ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ ĐŋŅавŅŅ ĐģŅйиĐŧи, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
"home_page_favorite_err_local": "ĐĐžĐēаĐģĐŊи ОйĐĩĐēŅи вŅĐĩ ĐžŅĐĩ ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ ĐŋŅавŅŅ ĐģŅйиĐŧи, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
||||||
"home_page_favorite_err_partner": "ĐаŅŅĐŊŅĐžŅŅĐēи ОйĐĩĐēŅи вŅĐĩ ĐžŅĐĩ ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ ĐŋŅавŅŅ ĐģŅйиĐŧи, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
"home_page_favorite_err_partner": "ĐаŅŅĐŊŅĐžŅŅĐēи ОйĐĩĐēŅи вŅĐĩ ĐžŅĐĩ ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ ĐŋŅавŅŅ ĐģŅйиĐŧи, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
||||||
"home_page_first_time_notice": "ĐĐēĐž Са ĐŋŅŅви ĐŋŅŅ Đ¸ĐˇĐŋĐžĐģСваŅĐĩ ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž, ĐŧĐžĐģŅ Đ¸ĐˇĐąĐĩŅĐĩŅĐĩ аĐģĐąŅĐŧ Са аŅŅ
ивиŅаĐŊĐĩ, Са да ĐŧĐžĐļĐĩ ОйĐĩĐēŅиŅĐĩ ĐžŅ Đ˛ŅĐĩĐŧĐĩваŅа ĐģиĐŊĐ¸Ņ Đ´Đ° ŅĐĩ СаĐŋиŅĐ˛Đ°Ņ Đ˛ ĐŊĐĩĐŗĐž",
|
"home_page_first_time_notice": "ĐĐēĐž Са ĐŋŅŅви ĐŋŅŅ Đ¸ĐˇĐŋĐžĐģĐˇĐ˛Đ°Ņ ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž, ĐŧĐžĐģŅ Đ¸ĐˇĐąĐĩŅи аĐģĐąŅĐŧ Са аŅŅ
ивиŅаĐŊĐĩ, Са да ĐŧĐžĐļĐĩ ОйĐĩĐēŅиŅĐĩ ĐžŅ Đ˛ŅĐĩĐŧĐĩваŅа ĐģиĐŊĐ¸Ņ Đ´Đ° ŅĐĩ СаĐŋиŅĐ˛Đ°Ņ Đ˛ ĐŊĐĩĐŗĐž",
|
||||||
"home_page_locked_error_local": "ĐĐžĐēаĐģĐŊи ОйĐĩĐēŅи ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ ĐŋŅĐĩĐŧĐĩŅŅŅŅ Đ˛ СаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
"home_page_locked_error_local": "ĐĐžĐēаĐģĐŊи ОйĐĩĐēŅи ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ ĐŋŅĐĩĐŧĐĩŅŅŅŅ Đ˛ СаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
||||||
"home_page_locked_error_partner": "ĐаŅŅĐŊŅĐžŅŅĐēи ОйĐĩĐēŅи ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ ĐŋŅĐĩĐŧĐĩŅŅŅŅ Đ˛ СаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
"home_page_locked_error_partner": "ĐаŅŅĐŊŅĐžŅŅĐēи ОйĐĩĐēŅи ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ ĐŋŅĐĩĐŧĐĩŅŅŅŅ Đ˛ СаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
||||||
"home_page_share_err_local": "ĐĐžĐēаĐģĐŊи ОйĐĩĐēŅи ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ ŅĐŋОдĐĩĐģŅŅ ŅŅĐĩС вŅŅСĐēа, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
"home_page_share_err_local": "ĐĐžĐēаĐģĐŊи ОйĐĩĐēŅи ĐŊĐĩ ĐŧĐžĐŗĐ°Ņ Đ´Đ° ŅĐĩ ŅĐŋОдĐĩĐģŅŅ ŅŅĐĩС вŅŅСĐēа, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
||||||
@@ -1122,7 +1094,6 @@
|
|||||||
"ios_debug_info_last_sync_at": "ХиĐŊŅ
ŅĐžĐŊиСиŅаĐŊĐž ĐŊа {dateTime}",
|
"ios_debug_info_last_sync_at": "ХиĐŊŅ
ŅĐžĐŊиСиŅаĐŊĐž ĐŊа {dateTime}",
|
||||||
"ios_debug_info_no_processes_queued": "ĐŅĐŧа ŅĐžĐŊОви ĐŋŅĐžŅĐĩŅи в ĐžĐŋаŅĐēаŅа",
|
"ios_debug_info_no_processes_queued": "ĐŅĐŧа ŅĐžĐŊОви ĐŋŅĐžŅĐĩŅи в ĐžĐŋаŅĐēаŅа",
|
||||||
"ios_debug_info_no_sync_yet": "ĐŅĐĩ ĐžŅĐĩ ĐŊĐĩ Đĩ иСĐŋŅĐģĐŊŅваĐŊа СадаŅа Са ŅĐžĐŊОва ŅиĐŊŅ
ŅĐžĐŊиСаŅиŅ",
|
"ios_debug_info_no_sync_yet": "ĐŅĐĩ ĐžŅĐĩ ĐŊĐĩ Đĩ иСĐŋŅĐģĐŊŅваĐŊа СадаŅа Са ŅĐžĐŊОва ŅиĐŊŅ
ŅĐžĐŊиСаŅиŅ",
|
||||||
"ios_debug_info_processes_queued": "{count, plural, one {{count} ŅĐžĐŊОв ĐŋŅĐžŅĐĩŅ} many {{count} ŅĐžĐŊОви ĐŋŅĐžŅĐĩŅа} other {{count} ŅĐžĐŊОви ĐŋŅĐžŅĐĩŅа}} в ĐžĐŋаŅĐēаŅа",
|
|
||||||
"ios_debug_info_processing_ran_at": "ĐаĐŋĐžŅĐŊаŅа ОйŅайОŅĐēа ĐŊа {dateTime}",
|
"ios_debug_info_processing_ran_at": "ĐаĐŋĐžŅĐŊаŅа ОйŅайОŅĐēа ĐŊа {dateTime}",
|
||||||
"items_count": "{count, plural, one {# ĐĩĐģĐĩĐŧĐĩĐŊŅ} other {# ĐĩĐģĐĩĐŧĐĩĐŊŅи}}",
|
"items_count": "{count, plural, one {# ĐĩĐģĐĩĐŧĐĩĐŊŅ} other {# ĐĩĐģĐĩĐŧĐĩĐŊŅи}}",
|
||||||
"jobs": "ĐадаŅи",
|
"jobs": "ĐадаŅи",
|
||||||
@@ -1132,7 +1103,7 @@
|
|||||||
"kept_this_deleted_others": "ĐаĐŋаСи ŅОСи ĐĩĐģĐĩĐŧĐĩĐŊŅ Đ¸ Đ´ŅŅĐŗĐ¸ŅĐĩ иСŅŅиŅи {count, plural, one {# ĐĩĐģĐĩĐŧĐĩĐŊŅ} other {# ĐĩĐģĐĩĐŧĐĩĐŊŅа}}",
|
"kept_this_deleted_others": "ĐаĐŋаСи ŅОСи ĐĩĐģĐĩĐŧĐĩĐŊŅ Đ¸ Đ´ŅŅĐŗĐ¸ŅĐĩ иСŅŅиŅи {count, plural, one {# ĐĩĐģĐĩĐŧĐĩĐŊŅ} other {# ĐĩĐģĐĩĐŧĐĩĐŊŅа}}",
|
||||||
"keyboard_shortcuts": "ĐŅŅСи ĐēĐģавиŅĐŊи ĐēĐžĐŧйиĐŊаŅии",
|
"keyboard_shortcuts": "ĐŅŅСи ĐēĐģавиŅĐŊи ĐēĐžĐŧйиĐŊаŅии",
|
||||||
"language": "ĐСиĐē",
|
"language": "ĐСиĐē",
|
||||||
"language_no_results_subtitle": "ĐĐŋиŅаКŅĐĩ да ĐēĐžŅĐ¸ĐŗĐ¸ŅаŅĐĩ ŅĐĩŅĐŧиĐŊа Ņи Са ŅŅŅŅĐĩĐŊĐĩ",
|
"language_no_results_subtitle": "ĐĐŋиŅаК да ĐēĐžŅĐ¸ĐŗĐ¸ŅĐ°Ņ ŅĐĩŅĐŧиĐŊа Ņи Са ŅŅŅŅĐĩĐŊĐĩ",
|
||||||
"language_no_results_title": "ĐĐĩ Ņа ĐŊаĐŧĐĩŅĐĩĐŊи ĐĩСиŅи",
|
"language_no_results_title": "ĐĐĩ Ņа ĐŊаĐŧĐĩŅĐĩĐŊи ĐĩСиŅи",
|
||||||
"language_search_hint": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ĐĩСиŅи...",
|
"language_search_hint": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ĐĩСиŅи...",
|
||||||
"language_setting_description": "ĐСйĐĩŅĐĩŅĐĩ ĐŋŅĐĩĐ´ĐŋĐžŅиŅаĐŊ ĐĩСиĐē",
|
"language_setting_description": "ĐСйĐĩŅĐĩŅĐĩ ĐŋŅĐĩĐ´ĐŋĐžŅиŅаĐŊ ĐĩСиĐē",
|
||||||
@@ -1151,10 +1122,10 @@
|
|||||||
"library_page_sort_created": "ĐаŅа ĐŊа ŅŅСдаваĐŊĐĩ",
|
"library_page_sort_created": "ĐаŅа ĐŊа ŅŅСдаваĐŊĐĩ",
|
||||||
"library_page_sort_last_modified": "ĐĐžŅĐģĐĩĐ´ĐŊа ĐŋŅĐžĐŧŅĐŊа",
|
"library_page_sort_last_modified": "ĐĐžŅĐģĐĩĐ´ĐŊа ĐŋŅĐžĐŧŅĐŊа",
|
||||||
"library_page_sort_title": "ĐĐ°ĐŗĐģавиĐĩ ĐŊа аĐģĐąŅĐŧа",
|
"library_page_sort_title": "ĐĐ°ĐŗĐģавиĐĩ ĐŊа аĐģĐąŅĐŧа",
|
||||||
"licenses": "ĐиŅĐĩĐŊСи",
|
|
||||||
"light": "ХвĐĩŅĐģĐž",
|
"light": "ХвĐĩŅĐģĐž",
|
||||||
"like_deleted": "ĐаŅĐž иСŅŅиŅ",
|
"like_deleted": "ĐаŅĐž иСŅŅиŅ",
|
||||||
"link_motion_video": "ĐиĐŊĐē ĐēŅĐŧ видĐĩĐž",
|
"link_motion_video": "ĐиĐŊĐē ĐēŅĐŧ видĐĩĐž",
|
||||||
|
"link_options": "ĐĐŋŅии ĐŊа ĐģиĐŊĐē Са ŅĐŋОдĐĩĐģŅĐŊĐĩ",
|
||||||
"link_to_oauth": "ĐиĐŊĐē ĐēŅĐŧ OAuth",
|
"link_to_oauth": "ĐиĐŊĐē ĐēŅĐŧ OAuth",
|
||||||
"linked_oauth_account": "ХвŅŅСаĐŊ OAuth аĐēаŅĐŊŅ",
|
"linked_oauth_account": "ХвŅŅСаĐŊ OAuth аĐēаŅĐŊŅ",
|
||||||
"list": "ĐиŅŅ",
|
"list": "ĐиŅŅ",
|
||||||
@@ -1167,14 +1138,13 @@
|
|||||||
"location_permission_content": "Đа да ŅайОŅи ŅŅĐŊĐēŅиŅŅа авŅĐžĐŧаŅиŅĐŊĐž ĐŋŅĐĩвĐēĐģŅŅваĐŊĐĩ, Immich ŅĐĩ ĐŊŅĐļдаĐĩ ĐžŅ ŅаСŅĐĩŅĐĩĐŊиĐĩ Са ŅĐžŅĐŊĐž ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ, Са да ĐŧĐžĐļĐĩ да ŅĐĩŅĐĩ иĐŧĐĩŅĐž ĐŊа ŅĐĩĐēŅŅаŅа Wi-Fi ĐŧŅĐĩĐļа",
|
"location_permission_content": "Đа да ŅайОŅи ŅŅĐŊĐēŅиŅŅа авŅĐžĐŧаŅиŅĐŊĐž ĐŋŅĐĩвĐēĐģŅŅваĐŊĐĩ, Immich ŅĐĩ ĐŊŅĐļдаĐĩ ĐžŅ ŅаСŅĐĩŅĐĩĐŊиĐĩ Са ŅĐžŅĐŊĐž ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ, Са да ĐŧĐžĐļĐĩ да ŅĐĩŅĐĩ иĐŧĐĩŅĐž ĐŊа ŅĐĩĐēŅŅаŅа Wi-Fi ĐŧŅĐĩĐļа",
|
||||||
"location_picker_choose_on_map": "ĐСйĐĩŅи ĐŊа ĐēаŅŅа",
|
"location_picker_choose_on_map": "ĐСйĐĩŅи ĐŊа ĐēаŅŅа",
|
||||||
"location_picker_latitude_error": "ĐŅвĐĩди ĐŋŅавиĐģĐŊа ŅиŅиĐŊа",
|
"location_picker_latitude_error": "ĐŅвĐĩди ĐŋŅавиĐģĐŊа ŅиŅиĐŊа",
|
||||||
"location_picker_latitude_hint": "ĐŅвĐĩĐ´ĐĩŅĐĩ ĐŗĐĩĐžĐŗŅаŅŅĐēа ŅиŅиĐŊа ŅŅĐē",
|
"location_picker_latitude_hint": "ĐŅвĐĩди ŅиŅиĐŊаŅа ŅŅĐē",
|
||||||
"location_picker_longitude_error": "ĐŅвĐĩди ĐŋŅавиĐģĐŊа Đ´ŅĐģĐļиĐŊа",
|
"location_picker_longitude_error": "ĐŅвĐĩди ĐŋŅавиĐģĐŊа Đ´ŅĐģĐļиĐŊа",
|
||||||
"location_picker_longitude_hint": "ĐŅвĐĩĐ´ĐĩŅĐĩ ĐŗĐĩĐžĐŗŅаŅŅĐēа Đ´ŅĐģĐļиĐŊа ŅŅĐē",
|
"location_picker_longitude_hint": "ĐŅвĐĩди Đ´ŅĐģĐļиĐŊаŅа ŅŅĐē",
|
||||||
"lock": "ĐаĐēĐģŅŅи",
|
"lock": "ĐаĐēĐģŅŅи",
|
||||||
"locked_folder": "ĐаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа",
|
"locked_folder": "ĐаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа",
|
||||||
"log_out": "ĐСĐģиСаĐŊĐĩ",
|
"log_out": "ĐСĐģиСаĐŊĐĩ",
|
||||||
"log_out_all_devices": "ĐСĐģиСаĐŊĐĩ Ņ Đ˛ŅиŅĐēи ŅŅŅŅОКŅŅва",
|
"log_out_all_devices": "ĐСĐģиСаĐŊĐĩ Ņ Đ˛ŅиŅĐēи ŅŅŅŅОКŅŅва",
|
||||||
"logged_in_as": "ĐĐŋиŅаĐŊ ĐēаŅĐž {user}",
|
|
||||||
"logged_out_all_devices": "ĐŖŅĐŋĐĩŅĐŊĐž иСĐģиСаĐŊĐĩ ĐžŅ Đ˛ŅиŅĐēи ŅŅŅŅОКŅŅва",
|
"logged_out_all_devices": "ĐŖŅĐŋĐĩŅĐŊĐž иСĐģиСаĐŊĐĩ ĐžŅ Đ˛ŅиŅĐēи ŅŅŅŅОКŅŅва",
|
||||||
"logged_out_device": "ĐŖŅĐŋĐĩŅĐŊĐž иСĐģиСаĐŊĐĩ ĐžŅ ŅŅŅŅОКŅŅвО",
|
"logged_out_device": "ĐŖŅĐŋĐĩŅĐŊĐž иСĐģиСаĐŊĐĩ ĐžŅ ŅŅŅŅОКŅŅвО",
|
||||||
"login": "ĐĐŋиŅваĐŊĐĩ",
|
"login": "ĐĐŋиŅваĐŊĐĩ",
|
||||||
@@ -1191,8 +1161,8 @@
|
|||||||
"login_form_err_trailing_whitespace": "ĐĐŊŅĐĩŅваĐģ в ĐēŅаŅ",
|
"login_form_err_trailing_whitespace": "ĐĐŊŅĐĩŅваĐģ в ĐēŅаŅ",
|
||||||
"login_form_failed_get_oauth_server_config": "ĐŅĐĩŅĐēа ĐŋŅи вĐŋиŅваĐŊĐĩ Ņ OAuth, ĐŋŅОвĐĩŅи URL ĐŊа ŅŅŅвŅŅа",
|
"login_form_failed_get_oauth_server_config": "ĐŅĐĩŅĐēа ĐŋŅи вĐŋиŅваĐŊĐĩ Ņ OAuth, ĐŋŅОвĐĩŅи URL ĐŊа ŅŅŅвŅŅа",
|
||||||
"login_form_failed_get_oauth_server_disable": "Đа ŅОСи ŅŅŅвŅŅ OAuth ĐŊĐĩ Đĩ Đ´ĐžŅŅŅĐŋĐŊа",
|
"login_form_failed_get_oauth_server_disable": "Đа ŅОСи ŅŅŅвŅŅ OAuth ĐŊĐĩ Đĩ Đ´ĐžŅŅŅĐŋĐŊа",
|
||||||
"login_form_failed_login": "ĐŅĐĩŅĐēа ĐŋŅи вĐŋиŅваĐŊĐĩ, ĐŋŅОвĐĩŅĐĩŅĐĩ URL, иĐŧĐĩĐšĐģа и ĐŋаŅĐžĐģаŅа",
|
"login_form_failed_login": "ĐŅĐĩŅĐēа ĐŋŅи вĐŋиŅваĐŊĐĩ, ĐŋŅОвĐĩŅи URL, иĐŧĐĩĐšĐģа и ĐŋаŅĐžĐģаŅа",
|
||||||
"login_form_handshake_exception": "ĐŅĐĩŅĐēа ĐŋŅи Đ´ĐžĐŗĐžĐ˛Đ°ŅŅĐŊĐĩ ĐŊа вŅŅСĐēаŅа ŅŅŅ ŅŅŅвŅŅа. ĐĐēĐž иСĐŋĐžĐģСваŅĐĩ ŅаĐŧĐžĐŋОдĐŋиŅаĐŊ ŅĐĩŅŅиŅиĐēаŅ, ŅаСŅĐĩŅĐĩŅĐĩ в ĐŊаŅŅŅОКĐēŅĐĩ иСĐŋĐžĐģСваĐŊĐĩ ĐŊа ŅаĐŧĐžĐŋОдĐŋиŅаĐŊ ŅĐĩŅŅиŅиĐēаŅ.",
|
"login_form_handshake_exception": "ĐŅĐĩŅĐēа ĐŋŅи Đ´ĐžĐŗĐžĐ˛Đ°ŅŅĐŊĐĩ ĐŊа вŅŅСĐēаŅа ŅŅŅ ŅŅŅвŅŅа. ĐĐēĐž иСĐŋĐžĐģĐˇĐ˛Đ°Ņ ŅаĐŧĐžĐŋОдĐŋиŅаĐŊ ŅĐĩŅŅиŅиĐēаŅ, ŅаСŅĐĩŅи в ĐŊаŅŅŅОКĐēŅĐĩ иСĐŋĐžĐģСваĐŊĐĩ ĐŊа ŅаĐŧĐžĐŋОдĐŋиŅаĐŊ ŅĐĩŅŅиŅиĐēаŅ.",
|
||||||
"login_form_password_hint": "ĐŋаŅĐžĐģа",
|
"login_form_password_hint": "ĐŋаŅĐžĐģа",
|
||||||
"login_form_save_login": "ĐŅŅаĐŊи вĐŋиŅаĐŊ",
|
"login_form_save_login": "ĐŅŅаĐŊи вĐŋиŅаĐŊ",
|
||||||
"login_form_server_empty": "ĐŅвĐĩди URL ĐŊа ŅŅŅвŅŅа.",
|
"login_form_server_empty": "ĐŅвĐĩди URL ĐŊа ŅŅŅвŅŅа.",
|
||||||
@@ -1217,16 +1187,17 @@
|
|||||||
"manage_your_devices": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа вĐģĐĩСĐģиŅĐĩ в ŅиŅŅĐĩĐŧаŅа ŅŅŅŅОКŅŅва",
|
"manage_your_devices": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа вĐģĐĩСĐģиŅĐĩ в ŅиŅŅĐĩĐŧаŅа ŅŅŅŅОКŅŅва",
|
||||||
"manage_your_oauth_connection": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа OAuth вŅŅСĐēаŅа",
|
"manage_your_oauth_connection": "ĐŖĐŋŅавĐģĐĩĐŊиĐĩ ĐŊа OAuth вŅŅСĐēаŅа",
|
||||||
"map": "ĐаŅŅа",
|
"map": "ĐаŅŅа",
|
||||||
|
"map_assets_in_bound": "{count} ŅĐŊиĐŧĐēи",
|
||||||
"map_assets_in_bounds": "{count} ŅĐŊиĐŧĐēи",
|
"map_assets_in_bounds": "{count} ŅĐŊиĐŧĐēи",
|
||||||
"map_cannot_get_user_location": "ĐĐĩ ĐŧĐžĐļаŅ
да ĐŋĐžĐģŅŅа ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž",
|
"map_cannot_get_user_location": "ĐĐĩ ĐŧĐžĐļаŅ
да ĐŋĐžĐģŅŅа ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž",
|
||||||
"map_location_dialog_yes": "Đа",
|
"map_location_dialog_yes": "Đа",
|
||||||
"map_location_picker_page_use_location": "ĐСĐŋĐžĐģСваК ŅОва ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ",
|
"map_location_picker_page_use_location": "ĐСĐŋĐžĐģСваК ŅОва ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ",
|
||||||
"map_location_service_disabled_content": "Đа да ŅĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ ĐžĐąĐĩĐēŅиŅĐĩ ĐžŅ ŅĐĩĐēŅŅĐžŅĐž ĐŧŅŅŅĐž, ŅŅŅйва да ĐąŅĐ´Đĩ вĐēĐģŅŅĐĩĐŊа ŅŅĐģŅĐŗĐ°Ņа Са ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ. ĐŅĐēаŅĐĩ Đģи да Ņ Đ˛ĐēĐģŅŅиŅĐĩ ŅĐĩĐŗĐ°?",
|
"map_location_service_disabled_content": "Đа да ŅĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ ĐžĐąĐĩĐēŅиŅĐĩ ĐžŅ ŅĐĩĐēŅŅĐžŅĐž ĐŧŅŅŅĐž, ŅŅŅйва да ĐąŅĐ´Đĩ вĐēĐģŅŅĐĩĐŊа ŅŅĐģŅĐŗĐ°Ņа Са ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ. ĐŅĐēĐ°Ņ Đģи да Ņ Đ˛ĐēĐģŅŅĐ¸Ņ ŅĐĩĐŗĐ°?",
|
||||||
"map_location_service_disabled_title": "ĐŖŅĐģŅĐŗĐ°Ņа Са ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ Đĩ иСĐēĐģŅŅĐĩĐŊа",
|
"map_location_service_disabled_title": "ĐŖŅĐģŅĐŗĐ°Ņа Са ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ Đĩ иСĐēĐģŅŅĐĩĐŊа",
|
||||||
"map_marker_for_images": "ĐаŅĐēĐĩŅи ĐŊа ĐēаŅŅаŅа Са ŅĐŊиĐŧĐēи ĐŊаĐŋŅавĐĩĐŊи в {city}, {country}",
|
"map_marker_for_images": "ĐаŅĐēĐĩŅи ĐŊа ĐēаŅŅаŅа Са ŅĐŊиĐŧĐēи ĐŊаĐŋŅавĐĩĐŊи в {city}, {country}",
|
||||||
"map_marker_with_image": "ĐаŅĐēĐĩŅ ĐŊа ĐēаŅŅаŅа Ņ Đ¸ĐˇĐžĐąŅаĐļĐĩĐŊиĐĩ",
|
"map_marker_with_image": "ĐаŅĐēĐĩŅ ĐŊа ĐēаŅŅаŅа Ņ Đ¸ĐˇĐžĐąŅаĐļĐĩĐŊиĐĩ",
|
||||||
"map_no_assets_in_bounds": "ĐŅĐŧа ŅĐŊиĐŧĐēи ĐžŅ ŅОСи ŅаКОĐŊ",
|
"map_no_assets_in_bounds": "ĐŅĐŧа ŅĐŊиĐŧĐēи ĐžŅ ŅОСи ŅаКОĐŊ",
|
||||||
"map_no_location_permission_content": "Đа да ŅĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ ĐžĐąĐĩĐēŅиŅĐĩ ĐžŅ ŅĐĩĐēŅŅĐžŅĐž ĐŧŅŅŅĐž, ŅŅŅйва ŅаСŅĐĩŅĐĩĐŊиĐĩ Са ĐžĐŋŅĐĩĐ´ĐĩĐģŅĐŊĐĩ ĐŊа ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž. ĐŅĐēаŅĐĩ Đģи да ĐŋŅĐĩĐ´ĐžŅŅавиŅĐĩ ŅаСŅĐĩŅĐĩĐŊиĐĩ ŅĐĩĐŗĐ°?",
|
"map_no_location_permission_content": "Đа да ŅĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ ĐžĐąĐĩĐēŅиŅĐĩ ĐžŅ ŅĐĩĐēŅŅĐžŅĐž ĐŧŅŅŅĐž, ŅŅŅйва ŅаСŅĐĩŅĐĩĐŊиĐĩ Са ĐžĐŋŅĐĩĐ´ĐĩĐģŅĐŊĐĩ ĐŊа ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž. ĐŅĐēĐ°Ņ Đģи да ĐŋŅĐĩĐ´ĐžŅŅĐ°Đ˛Đ¸Ņ ŅаСŅĐĩŅĐĩĐŊиĐĩ ŅĐĩĐŗĐ°?",
|
||||||
"map_no_location_permission_title": "ĐŅĐēаСаĐŊ Đ´ĐžŅŅŅĐŋ Đ´Đž ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ",
|
"map_no_location_permission_title": "ĐŅĐēаСаĐŊ Đ´ĐžŅŅŅĐŋ Đ´Đž ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ",
|
||||||
"map_settings": "ĐаŅŅŅОКĐēи ĐŊа ĐēаŅŅаŅа",
|
"map_settings": "ĐаŅŅŅОКĐēи ĐŊа ĐēаŅŅаŅа",
|
||||||
"map_settings_dark_mode": "ĐĸŅĐŧĐĩĐŊ ŅĐĩĐļиĐŧ",
|
"map_settings_dark_mode": "ĐĸŅĐŧĐĩĐŊ ŅĐĩĐļиĐŧ",
|
||||||
@@ -1269,11 +1240,8 @@
|
|||||||
"more": "ĐŅĐĩ",
|
"more": "ĐŅĐĩ",
|
||||||
"move": "ĐŅĐĩĐŧĐĩŅŅи",
|
"move": "ĐŅĐĩĐŧĐĩŅŅи",
|
||||||
"move_off_locked_folder": "ĐСвади ĐžŅ ĐˇĐ°ĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа",
|
"move_off_locked_folder": "ĐСвади ĐžŅ ĐˇĐ°ĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа",
|
||||||
"move_to_lock_folder_action_prompt": "{count} Ņа дОйавĐĩĐŊи в СаĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа",
|
|
||||||
"move_to_locked_folder": "ĐŅĐĩĐŧĐĩŅŅи в СаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа",
|
"move_to_locked_folder": "ĐŅĐĩĐŧĐĩŅŅи в СаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа",
|
||||||
"move_to_locked_folder_confirmation": "ĐĸĐĩСи ŅĐŊиĐŧĐēи и видĐĩа ŅĐĩ ĐąŅĐ´Đ°Ņ Đ¸ĐˇŅŅиŅи ĐžŅ Đ˛ŅиŅĐēи аĐģĐąŅĐŧи и ŅĐĩ Ņа Đ´ĐžŅŅŅĐŋĐŊи ŅаĐŧĐž в СаĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа",
|
"move_to_locked_folder_confirmation": "ĐĸĐĩСи ŅĐŊиĐŧĐēи и видĐĩа ŅĐĩ ĐąŅĐ´Đ°Ņ Đ¸ĐˇŅŅиŅи ĐžŅ Đ˛ŅиŅĐēи аĐģĐąŅĐŧи и ŅĐĩ Ņа Đ´ĐžŅŅŅĐŋĐŊи ŅаĐŧĐž в СаĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа",
|
||||||
"moved_to_archive": "{count, plural, one {# ОйĐĩĐēŅ Đĩ ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊ} many {# ОйĐĩĐēŅа Ņа ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊи} other {# ОйĐĩĐēŅа Ņа ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊи}} в аŅŅ
ива",
|
|
||||||
"moved_to_library": "{count, plural, one {# ОйĐĩĐēŅ Đĩ ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊ} many {# ОйĐĩĐēŅа Ņа ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊи} other {# ОйĐĩĐēŅа Ņа ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊи}} в йийĐģиОŅĐĩĐēаŅа",
|
|
||||||
"moved_to_trash": "ĐŅĐĩĐŧĐĩŅŅĐĩĐŊĐž в ĐēĐžŅŅĐĩŅĐž",
|
"moved_to_trash": "ĐŅĐĩĐŧĐĩŅŅĐĩĐŊĐž в ĐēĐžŅŅĐĩŅĐž",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "ĐĐĩ ĐŧĐžĐļĐĩ да ŅĐĩ ŅĐĩдаĐēŅиŅа даŅаŅа ĐŊа ОйĐĩĐēŅ ŅаĐŧĐž Са ŅĐĩŅĐĩĐŊĐĩ, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
"multiselect_grid_edit_date_time_err_read_only": "ĐĐĩ ĐŧĐžĐļĐĩ да ŅĐĩ ŅĐĩдаĐēŅиŅа даŅаŅа ĐŊа ОйĐĩĐēŅ ŅаĐŧĐž Са ŅĐĩŅĐĩĐŊĐĩ, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "ĐĐĩ ĐŧĐžĐļĐĩ да ŅĐĩ ŅĐĩдаĐēŅиŅа ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž ĐŊа ОйĐĩĐēŅ ŅаĐŧĐž Са ŅĐĩŅĐĩĐŊĐĩ, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
"multiselect_grid_edit_gps_err_read_only": "ĐĐĩ ĐŧĐžĐļĐĩ да ŅĐĩ ŅĐĩдаĐēŅиŅа ĐŧĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩŅĐž ĐŊа ОйĐĩĐēŅ ŅаĐŧĐž Са ŅĐĩŅĐĩĐŊĐĩ, ĐŋŅĐžĐŋŅŅĐēаĐŊĐĩ",
|
||||||
@@ -1289,14 +1257,14 @@
|
|||||||
"new_password": "ĐОва ĐŋаŅĐžĐģа",
|
"new_password": "ĐОва ĐŋаŅĐžĐģа",
|
||||||
"new_person": "ĐОв ŅОвĐĩĐē",
|
"new_person": "ĐОв ŅОвĐĩĐē",
|
||||||
"new_pin_code": "ĐОв PIN ĐēОд",
|
"new_pin_code": "ĐОв PIN ĐēОд",
|
||||||
"new_pin_code_subtitle": "ĐĸОва Đĩ ĐŋŅŅви Đ´ĐžŅŅŅĐŋ Đ´Đž СаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа. ĐĄŅСдаКŅĐĩ PIN ĐēОд Са СаŅиŅĐĩĐŊ Đ´ĐžŅŅŅĐŋ Đ´Đž ŅаСи ŅŅŅаĐŊиŅа",
|
"new_pin_code_subtitle": "ĐĸОва Đĩ ĐŋŅŅви Đ´ĐžŅŅŅĐŋ Đ´Đž СаĐēĐģŅŅĐĩĐŊа ĐŋаĐŋĐēа. ĐĄŅСдаК PIN ĐēОд Са СаŅиŅĐĩĐŊ Đ´ĐžŅŅŅĐŋ Đ´Đž ŅаСи ŅŅŅаĐŊиŅа",
|
||||||
"new_user_created": "ĐĄŅСдадĐĩĐŊ ĐŊОв ĐŋĐžŅŅĐĩйиŅĐĩĐģ",
|
"new_user_created": "ĐĄŅСдадĐĩĐŊ ĐŊОв ĐŋĐžŅŅĐĩйиŅĐĩĐģ",
|
||||||
"new_version_available": "ĐĐĐĐЧĐĐ ĐĐĐĐ ĐĐĐ ĐĄĐĐ¯",
|
"new_version_available": "ĐĐĐĐЧĐĐ ĐĐĐĐ ĐĐĐ ĐĄĐĐ¯",
|
||||||
"newest_first": "ĐаК-ĐŊОвиŅĐĩ ĐŋŅŅви",
|
"newest_first": "ĐаК-ĐŊОвиŅĐĩ ĐŋŅŅви",
|
||||||
"next": "ĐĄĐģĐĩдваŅĐž",
|
"next": "ĐĄĐģĐĩдваŅĐž",
|
||||||
"next_memory": "ĐĄĐģĐĩĐ´Đ˛Đ°Ņ ŅĐŋĐžĐŧĐĩĐŊ",
|
"next_memory": "ĐĄĐģĐĩĐ´Đ˛Đ°Ņ ŅĐŋĐžĐŧĐĩĐŊ",
|
||||||
"no": "ĐĐĩ",
|
"no": "ĐĐĩ",
|
||||||
"no_albums_message": "ĐĄŅСдаКŅĐĩ аĐģĐąŅĐŧ Са ĐžŅĐŗĐ°ĐŊиСиŅаĐŊĐĩ ĐŊа ŅĐŊиĐŧĐēи и видĐĩĐžĐēĐģиĐŋОвĐĩ",
|
"no_albums_message": "ĐĄŅСдаваĐŊĐĩ ĐŊа аĐģĐąŅĐŧ Са ĐžŅĐŗĐ°ĐŊиСиŅаĐŊĐĩ ĐŊа ŅĐŊиĐŧĐēи и видĐĩĐžĐēĐģиĐŋОвĐĩ",
|
||||||
"no_albums_with_name_yet": "ĐĐˇĐŗĐģĐĩĐļда, ŅĐĩ вŅĐĩ ĐžŅĐĩ ĐŊŅĐŧаŅĐĩ аĐģĐąŅĐŧи Ņ ŅОва иĐŧĐĩ.",
|
"no_albums_with_name_yet": "ĐĐˇĐŗĐģĐĩĐļда, ŅĐĩ вŅĐĩ ĐžŅĐĩ ĐŊŅĐŧаŅĐĩ аĐģĐąŅĐŧи Ņ ŅОва иĐŧĐĩ.",
|
||||||
"no_albums_yet": "ĐĐˇĐŗĐģĐĩĐļда, ŅĐĩ вŅĐĩ ĐžŅĐĩ ĐŊŅĐŧаŅĐĩ аĐģĐąŅĐŧи.",
|
"no_albums_yet": "ĐĐˇĐŗĐģĐĩĐļда, ŅĐĩ вŅĐĩ ĐžŅĐĩ ĐŊŅĐŧаŅĐĩ аĐģĐąŅĐŧи.",
|
||||||
"no_archived_assets_message": "ĐŅŅ
ивиŅаКŅĐĩ ŅĐŊиĐŧĐēи и видĐĩĐžĐēĐģиĐŋОвĐĩ, Са да ĐŗĐ¸ ŅĐēŅиĐĩŅĐĩ ĐžŅ Đ¸ĐˇĐŗĐģĐĩда ĐŊа ĐĄĐŊиĐŧĐēи",
|
"no_archived_assets_message": "ĐŅŅ
ивиŅаКŅĐĩ ŅĐŊиĐŧĐēи и видĐĩĐžĐēĐģиĐŋОвĐĩ, Са да ĐŗĐ¸ ŅĐēŅиĐĩŅĐĩ ĐžŅ Đ¸ĐˇĐŗĐģĐĩда ĐŊа ĐĄĐŊиĐŧĐēи",
|
||||||
@@ -1306,8 +1274,8 @@
|
|||||||
"no_duplicates_found": "ĐĐĩ ĐąŅŅ
а ĐžŅĐēŅиŅи Đ´ŅĐąĐģиĐēаŅи.",
|
"no_duplicates_found": "ĐĐĩ ĐąŅŅ
а ĐžŅĐēŅиŅи Đ´ŅĐąĐģиĐēаŅи.",
|
||||||
"no_exif_info_available": "ĐŅĐŧа exif иĐŊŅĐžŅĐŧаŅиŅ",
|
"no_exif_info_available": "ĐŅĐŧа exif иĐŊŅĐžŅĐŧаŅиŅ",
|
||||||
"no_explore_results_message": "ĐаŅĐĩŅĐĩ ĐžŅĐĩ ŅĐŊиĐŧĐēи, Са да ŅĐ°ĐˇĐŗĐģĐĩдаŅĐĩ ĐēĐžĐģĐĩĐēŅиŅŅа Ņи.",
|
"no_explore_results_message": "ĐаŅĐĩŅĐĩ ĐžŅĐĩ ŅĐŊиĐŧĐēи, Са да ŅĐ°ĐˇĐŗĐģĐĩдаŅĐĩ ĐēĐžĐģĐĩĐēŅиŅŅа Ņи.",
|
||||||
"no_favorites_message": "ĐОйавĐĩŅĐĩ в ĐģŅйиĐŧи, Са да ĐŊаĐŧиŅаŅĐĩ ĐąŅŅСО ĐŊаК-дОйŅиŅĐĩ Ņи ŅĐŊиĐŧĐēи и видĐĩĐžĐēĐģиĐŋОвĐĩ",
|
"no_favorites_message": "ĐОйавŅĐŊĐĩ ĐŊа ĐģŅйиĐŧи, Са да ĐŊаĐŧĐĩŅиŅĐĩ ĐąŅŅСО ĐŊаК-дОйŅиŅĐĩ Ņи ŅĐŊиĐŧĐēи и видĐĩĐžĐēĐģиĐŋОвĐĩ",
|
||||||
"no_libraries_message": "ĐĄŅСдаКŅĐĩ вŅĐŊŅĐŊа йийĐģиОŅĐĩĐēа Са да ŅĐ°ĐˇĐŗĐģĐĩĐļдаŅĐĩ ŅĐŊиĐŧĐēи и видĐĩĐžĐēĐģиĐŋОвĐĩ",
|
"no_libraries_message": "ĐĄŅСдаваĐŊĐĩ ĐŊа вŅĐŊŅĐŊа йийĐģиОŅĐĩĐēа Са ŅĐ°ĐˇĐŗĐģĐĩĐļдаĐŊĐĩ ĐŊа ŅĐŊиĐŧĐēи и видĐĩĐžĐēĐģиĐŋОвĐĩ",
|
||||||
"no_locked_photos_message": "ĐĄĐŊиĐŧĐēиŅĐĩ и видĐĩаŅа в СаĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа Ņа ŅĐēŅиŅи и ĐŊĐĩ ŅĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ ĐŋŅи ŅĐ°ĐˇĐŗĐģĐĩĐļдаĐŊĐĩ ĐŊа йийĐģиОŅĐĩĐēаŅа.",
|
"no_locked_photos_message": "ĐĄĐŊиĐŧĐēиŅĐĩ и видĐĩаŅа в СаĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа Ņа ŅĐēŅиŅи и ĐŊĐĩ ŅĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ ĐŋŅи ŅĐ°ĐˇĐŗĐģĐĩĐļдаĐŊĐĩ ĐŊа йийĐģиОŅĐĩĐēаŅа.",
|
||||||
"no_name": "ĐĐĩС иĐŧĐĩ",
|
"no_name": "ĐĐĩС иĐŧĐĩ",
|
||||||
"no_notifications": "ĐŅĐŧа иСвĐĩŅŅиŅ",
|
"no_notifications": "ĐŅĐŧа иСвĐĩŅŅиŅ",
|
||||||
@@ -1335,7 +1303,7 @@
|
|||||||
"oldest_first": "ĐаК-ŅŅаŅиŅĐĩ ĐŋŅŅви",
|
"oldest_first": "ĐаК-ŅŅаŅиŅĐĩ ĐŋŅŅви",
|
||||||
"on_this_device": "Đа ŅОва ŅŅŅŅОКŅŅвО",
|
"on_this_device": "Đа ŅОва ŅŅŅŅОКŅŅвО",
|
||||||
"onboarding": "ĐŅвĐĩĐļдаĐŊĐĩ",
|
"onboarding": "ĐŅвĐĩĐļдаĐŊĐĩ",
|
||||||
"onboarding_locale_description": "ĐСйĐĩŅĐĩŅĐĩ ĐŋŅĐĩĐ´ĐŋĐžŅиŅаĐŊ ĐĩСиĐē. ĐĐž-ĐēŅŅĐŊĐž ĐŧĐžĐļĐĩ да ĐŗĐž ĐŋŅĐžĐŧĐĩĐŊиŅĐĩ в ĐаŅŅŅОКĐēи.",
|
"onboarding_locale_description": "ĐСйĐĩŅи ĐŋŅĐĩĐ´ĐŋĐžŅиŅаĐŊ ĐĩСиĐē. ĐĐž-ĐēŅŅĐŊĐž ĐŧĐžĐļĐĩ да ĐŗĐž ĐŋŅĐžĐŧĐĩĐŊĐ¸Ņ Đ˛ ĐаŅŅŅОКĐēи.",
|
||||||
"onboarding_privacy_description": "ĐĄĐģĐĩĐ´ĐŊиŅĐĩ (ĐŊĐĩСадŅĐģĐļиŅĐĩĐģĐŊи) ŅŅĐŊĐēŅии ŅаСŅиŅĐ°Ņ ĐŊа вŅĐŊŅĐŊи ŅŅĐģŅĐŗĐ¸ и ĐŧĐžĐŗĐ°Ņ Đ´Đ° ĐąŅĐ´Đ°Ņ Đ´ĐĩаĐēŅивиŅаĐŊи ĐŋĐž вŅŅĐēĐž вŅĐĩĐŧĐĩ в ĐŊаŅŅŅОКĐēиŅĐĩ.",
|
"onboarding_privacy_description": "ĐĄĐģĐĩĐ´ĐŊиŅĐĩ (ĐŊĐĩСадŅĐģĐļиŅĐĩĐģĐŊи) ŅŅĐŊĐēŅии ŅаСŅиŅĐ°Ņ ĐŊа вŅĐŊŅĐŊи ŅŅĐģŅĐŗĐ¸ и ĐŧĐžĐŗĐ°Ņ Đ´Đ° ĐąŅĐ´Đ°Ņ Đ´ĐĩаĐēŅивиŅаĐŊи ĐŋĐž вŅŅĐēĐž вŅĐĩĐŧĐĩ в ĐŊаŅŅŅОКĐēиŅĐĩ.",
|
||||||
"onboarding_server_welcome_description": "Đа ĐŊаĐŋŅавиĐŧ ОйŅиŅĐĩ ĐŊаŅŅŅОКĐēи ĐŊа ваŅаŅа иĐŊŅŅаĐģаŅиŅ.",
|
"onboarding_server_welcome_description": "Đа ĐŊаĐŋŅавиĐŧ ОйŅиŅĐĩ ĐŊаŅŅŅОКĐēи ĐŊа ваŅаŅа иĐŊŅŅаĐģаŅиŅ.",
|
||||||
"onboarding_theme_description": "ĐСйĐĩŅĐĩŅĐĩ ŅвĐĩŅОва ŅĐĩĐŧа. ĐĐžĐļĐĩ да Ņ ĐŋŅĐžĐŧĐĩĐŊиŅĐĩ ĐŋĐž-ĐēŅŅĐŊĐž в ĐŊаŅŅŅОКĐēиŅĐĩ.",
|
"onboarding_theme_description": "ĐСйĐĩŅĐĩŅĐĩ ŅвĐĩŅОва ŅĐĩĐŧа. ĐĐžĐļĐĩ да Ņ ĐŋŅĐžĐŧĐĩĐŊиŅĐĩ ĐŋĐž-ĐēŅŅĐŊĐž в ĐŊаŅŅŅОКĐēиŅĐĩ.",
|
||||||
@@ -1367,7 +1335,7 @@
|
|||||||
"partner_page_partner_add_failed": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž дОйавŅĐŊĐĩ ĐŊа ĐŋаŅŅĐŊŅĐžŅ",
|
"partner_page_partner_add_failed": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž дОйавŅĐŊĐĩ ĐŊа ĐŋаŅŅĐŊŅĐžŅ",
|
||||||
"partner_page_select_partner": "ĐСйĐĩŅи ĐŋаŅŅĐŊŅĐžŅ",
|
"partner_page_select_partner": "ĐСйĐĩŅи ĐŋаŅŅĐŊŅĐžŅ",
|
||||||
"partner_page_shared_to_title": "ĐĄĐŋОдĐĩĐģĐĩĐŊĐž Ņ",
|
"partner_page_shared_to_title": "ĐĄĐŋОдĐĩĐģĐĩĐŊĐž Ņ",
|
||||||
"partner_page_stop_sharing_content": "{partner} вĐĩŅĐĩ ĐŊŅĐŧа да иĐŧа Đ´ĐžŅŅŅĐŋ Đ´Đž ваŅиŅĐĩ ŅĐŊиĐŧĐēи.",
|
"partner_page_stop_sharing_content": "{partner} вĐĩŅĐĩ ĐŊŅĐŧа да иĐŧа Đ´ĐžŅŅŅĐŋ Đ´Đž ŅвОиŅĐĩ ŅĐŊиĐŧĐēи.",
|
||||||
"partner_sharing": "ĐĄĐŋОдĐĩĐģŅĐŊĐĩ Ņ ĐŋаŅŅĐŊŅĐžŅи",
|
"partner_sharing": "ĐĄĐŋОдĐĩĐģŅĐŊĐĩ Ņ ĐŋаŅŅĐŊŅĐžŅи",
|
||||||
"partners": "ĐаŅŅĐŊŅĐžŅи",
|
"partners": "ĐаŅŅĐŊŅĐžŅи",
|
||||||
"password": "ĐаŅĐžĐģа",
|
"password": "ĐаŅĐžĐģа",
|
||||||
@@ -1404,7 +1372,7 @@
|
|||||||
"permission_onboarding_go_to_settings": "ĐŅиди в ĐŊаŅŅŅОКĐēи",
|
"permission_onboarding_go_to_settings": "ĐŅиди в ĐŊаŅŅŅОКĐēи",
|
||||||
"permission_onboarding_permission_denied": "ĐŅĐēаСаĐŊ Đ´ĐžŅŅŅĐŋ. Đа да ĐŋĐžĐģĐˇĐ˛Đ°Ņ Immich, ŅаСŅĐĩŅи в ĐŊаŅŅŅОКĐēиŅĐĩ Đ´ĐžŅŅŅĐŋ Đ´Đž ŅĐŊиĐŧĐēи и видĐĩĐž.",
|
"permission_onboarding_permission_denied": "ĐŅĐēаСаĐŊ Đ´ĐžŅŅŅĐŋ. Đа да ĐŋĐžĐģĐˇĐ˛Đ°Ņ Immich, ŅаСŅĐĩŅи в ĐŊаŅŅŅОКĐēиŅĐĩ Đ´ĐžŅŅŅĐŋ Đ´Đž ŅĐŊиĐŧĐēи и видĐĩĐž.",
|
||||||
"permission_onboarding_permission_granted": "ĐŅĐĩĐ´ĐžŅŅавĐĩĐŊĐž Đĩ ŅаСŅĐĩŅĐĩĐŊиĐĩ! ĐŅиŅĐēĐž Đĩ ĐŗĐžŅОвО.",
|
"permission_onboarding_permission_granted": "ĐŅĐĩĐ´ĐžŅŅавĐĩĐŊĐž Đĩ ŅаСŅĐĩŅĐĩĐŊиĐĩ! ĐŅиŅĐēĐž Đĩ ĐŗĐžŅОвО.",
|
||||||
"permission_onboarding_permission_limited": "ĐĐŗŅаĐŊиŅĐĩĐŊ Đ´ĐžŅŅŅĐŋ. Đа да ĐŧĐžĐļĐĩ Immich да аŅŅ
ивиŅа и ŅĐŋŅавĐģŅва ĐŗĐ°ĐģĐĩŅиŅŅа, ĐŋŅĐĩĐ´ĐžŅŅавĐĩŅĐĩ Đ´ĐžŅŅŅĐŋ Đ´Đž ŅĐŊиĐŧĐēи и видĐĩĐž в ĐŊаŅŅŅОКĐēиŅĐĩ.",
|
"permission_onboarding_permission_limited": "ĐĐŗŅаĐŊиŅĐĩĐŊ Đ´ĐžŅŅŅĐŋ. Đа да ĐŧĐžĐļĐĩ Immich да аŅŅ
ивиŅа и ŅĐŋŅавĐģŅва ĐŗĐ°ĐģĐĩŅиŅŅа, ĐŋŅĐĩĐ´ĐžŅŅави Đ´ĐžŅŅŅĐŋ Đ´Đž ŅĐŊиĐŧĐēи и видĐĩĐž в ĐŊаŅŅŅОКĐēиŅĐĩ.",
|
||||||
"permission_onboarding_request": "Immich ŅĐĩ ĐŊŅĐļдаĐĩ ĐžŅ ŅаСŅĐĩŅĐĩĐŊиĐĩ Са ĐŋŅĐĩĐŗĐģĐĩĐ´ ĐŊа ŅĐŊиĐŧĐēи и видĐĩĐž.",
|
"permission_onboarding_request": "Immich ŅĐĩ ĐŊŅĐļдаĐĩ ĐžŅ ŅаСŅĐĩŅĐĩĐŊиĐĩ Са ĐŋŅĐĩĐŗĐģĐĩĐ´ ĐŊа ŅĐŊиĐŧĐēи и видĐĩĐž.",
|
||||||
"person": "ЧОвĐĩĐē",
|
"person": "ЧОвĐĩĐē",
|
||||||
"person_birthdate": "ĐаŅа ĐŊа ŅаĐļдаĐŊĐĩ {date}",
|
"person_birthdate": "ĐаŅа ĐŊа ŅаĐļдаĐŊĐĩ {date}",
|
||||||
@@ -1415,10 +1383,10 @@
|
|||||||
"photos_count": "{count, plural, one {{count, number} ĐĄĐŊиĐŧĐēа} other {{count, number} ĐĄĐŊиĐŧĐēи}}",
|
"photos_count": "{count, plural, one {{count, number} ĐĄĐŊиĐŧĐēа} other {{count, number} ĐĄĐŊиĐŧĐēи}}",
|
||||||
"photos_from_previous_years": "ĐĄĐŊиĐŧĐēи ĐžŅ ĐŋŅĐĩĐ´Ņ
ОдĐŊи ĐŗĐžĐ´Đ¸ĐŊи",
|
"photos_from_previous_years": "ĐĄĐŊиĐŧĐēи ĐžŅ ĐŋŅĐĩĐ´Ņ
ОдĐŊи ĐŗĐžĐ´Đ¸ĐŊи",
|
||||||
"pick_a_location": "ĐСйĐĩŅи ĐģĐžĐēаŅиŅ",
|
"pick_a_location": "ĐСйĐĩŅи ĐģĐžĐēаŅиŅ",
|
||||||
"pin_code_changed_successfully": "ĐŖŅĐŋĐĩŅĐŊĐž ŅĐŧĐĩĐŊĐĩĐŊ PIN ĐēОд",
|
"pin_code_changed_successfully": "ĐŖŅĐŋĐĩŅĐŊĐž ŅĐŧĐĩĐŊĐĩĐŊ PIN-ĐēОд",
|
||||||
"pin_code_reset_successfully": "ĐŖŅĐŋĐĩŅĐŊĐž ĐŊŅĐģиŅаĐŊ PIN ĐēОд",
|
"pin_code_reset_successfully": "ĐŖŅĐŋĐĩŅĐŊĐž ĐŊŅĐģиŅаĐŊ PIN-ĐēОд",
|
||||||
"pin_code_setup_successfully": "ĐŖŅĐŋĐĩŅĐŊĐž СададĐĩĐŊ PIN ĐēОд",
|
"pin_code_setup_successfully": "ĐŖŅĐŋĐĩŅĐŊĐž СададĐĩĐŊ PIN-ĐēОд",
|
||||||
"pin_verification": "ĐŅОвĐĩŅĐēа ĐŊа PIN ĐēОда",
|
"pin_verification": "ĐŅОвĐĩŅĐēа ĐŊа PIN-ĐēОда",
|
||||||
"place": "ĐĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ",
|
"place": "ĐĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиĐĩ",
|
||||||
"places": "ĐĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиŅ",
|
"places": "ĐĐĩŅŅĐžĐŋĐžĐģĐžĐļĐĩĐŊиŅ",
|
||||||
"places_count": "{count, plural, one {{count, number} ĐŅŅŅĐž} other {{count, number} ĐĐĩŅŅа}}",
|
"places_count": "{count, plural, one {{count, number} ĐŅŅŅĐž} other {{count, number} ĐĐĩŅŅа}}",
|
||||||
@@ -1472,7 +1440,7 @@
|
|||||||
"purchase_lifetime_description": "ĐĐžĐēŅĐŋĐēа Са ŅŅĐģ ĐļивОŅ",
|
"purchase_lifetime_description": "ĐĐžĐēŅĐŋĐēа Са ŅŅĐģ ĐļивОŅ",
|
||||||
"purchase_option_title": "ĐĐĐĻĐĐ ĐĐ ĐĐĐĐŖĐĐŖĐĐĐĐ",
|
"purchase_option_title": "ĐĐĐĻĐĐ ĐĐ ĐĐĐĐŖĐĐŖĐĐĐĐ",
|
||||||
"purchase_panel_info_1": "ĐĄŅСдаваĐŊĐĩŅĐž ĐŊа Immich ĐžŅĐŊĐĩĐŧа ĐŧĐŊĐžĐŗĐž вŅĐĩĐŧĐĩ и ŅŅиĐģиŅ, и иĐŧаĐŧĐĩ иĐŊĐļĐĩĐŊĐĩŅи ĐŊа ĐŋŅĐģĐŊĐž ŅайОŅĐŊĐž вŅĐĩĐŧĐĩ, ĐēОиŅĐž ŅайОŅŅŅ ĐŋĐž ĐŊĐĩĐŗĐž, Са да ĐŗĐž ĐŊаĐŋŅавиĐŧ вŅСĐŧĐžĐļĐŊĐž ĐŊаК-дОйŅĐž. ĐаŅаŅа ĐŧиŅĐ¸Ņ Đĩ ŅĐžŅŅŅĐĩŅŅŅ Ņ ĐžŅвОŅĐĩĐŊ ĐēОд и ĐĩŅиŅĐŊиŅĐĩ йиСĐŊĐĩŅ ĐŋŅаĐēŅиĐēи да ŅĐĩ ĐŋŅĐĩвŅŅĐŊĐ°Ņ Đ˛ ŅŅŅОКŅив иСŅĐžŅĐŊиĐē ĐŊа Đ´ĐžŅ
Оди Са ŅаСŅайОŅŅиŅиŅĐĩ и да ŅŅСдадĐĩĐŧ ĐĩĐēĐžŅиŅŅĐĩĐŧа, ĐēĐžŅŅĐž ŅваĐļава ĐģиŅĐŊаŅа ĐŊĐĩĐŋŅиĐēĐžŅĐŊОвĐĩĐŊĐžŅŅ Đ¸ ĐŋŅĐĩĐ´ĐģĐ°ĐŗĐ° иŅŅиĐŊŅĐēи аĐģŅĐĩŅĐŊаŅиви ĐŊа ĐĩĐēŅĐŋĐģОаŅаŅĐžŅŅĐēиŅĐĩ ОйĐģаŅĐŊи ŅŅĐģŅĐŗĐ¸.",
|
"purchase_panel_info_1": "ĐĄŅСдаваĐŊĐĩŅĐž ĐŊа Immich ĐžŅĐŊĐĩĐŧа ĐŧĐŊĐžĐŗĐž вŅĐĩĐŧĐĩ и ŅŅиĐģиŅ, и иĐŧаĐŧĐĩ иĐŊĐļĐĩĐŊĐĩŅи ĐŊа ĐŋŅĐģĐŊĐž ŅайОŅĐŊĐž вŅĐĩĐŧĐĩ, ĐēОиŅĐž ŅайОŅŅŅ ĐŋĐž ĐŊĐĩĐŗĐž, Са да ĐŗĐž ĐŊаĐŋŅавиĐŧ вŅСĐŧĐžĐļĐŊĐž ĐŊаК-дОйŅĐž. ĐаŅаŅа ĐŧиŅĐ¸Ņ Đĩ ŅĐžŅŅŅĐĩŅŅŅ Ņ ĐžŅвОŅĐĩĐŊ ĐēОд и ĐĩŅиŅĐŊиŅĐĩ йиСĐŊĐĩŅ ĐŋŅаĐēŅиĐēи да ŅĐĩ ĐŋŅĐĩвŅŅĐŊĐ°Ņ Đ˛ ŅŅŅОКŅив иСŅĐžŅĐŊиĐē ĐŊа Đ´ĐžŅ
Оди Са ŅаСŅайОŅŅиŅиŅĐĩ и да ŅŅСдадĐĩĐŧ ĐĩĐēĐžŅиŅŅĐĩĐŧа, ĐēĐžŅŅĐž ŅваĐļава ĐģиŅĐŊаŅа ĐŊĐĩĐŋŅиĐēĐžŅĐŊОвĐĩĐŊĐžŅŅ Đ¸ ĐŋŅĐĩĐ´ĐģĐ°ĐŗĐ° иŅŅиĐŊŅĐēи аĐģŅĐĩŅĐŊаŅиви ĐŊа ĐĩĐēŅĐŋĐģОаŅаŅĐžŅŅĐēиŅĐĩ ОйĐģаŅĐŊи ŅŅĐģŅĐŗĐ¸.",
|
||||||
"purchase_panel_info_2": "ĐĸŅĐš ĐēаŅĐž ŅĐŧĐĩ ОйĐĩŅаĐģи да ĐŊĐĩ дОйавŅĐŧĐĩ ĐŋĐģаŅĐĩĐŊи ŅŅĐŊĐēŅии, ŅаСи ĐŋĐžĐēŅĐŋĐēа ĐŊŅĐŧа да ви ĐŋŅĐĩĐ´ĐžŅŅави Đ´ĐžĐŋŅĐģĐŊиŅĐĩĐģĐŊи ŅŅĐŊĐēŅии в Immich. ĐиĐĩ ŅаСŅиŅаĐŧĐĩ ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģи ĐēаŅĐž ваŅ, Са да ĐŋОдĐēŅĐĩĐŋиŅĐĩ ĐŋŅОдŅĐģĐļаваĐŊĐĩ ĐŊа ŅаСвиŅиĐĩŅĐž ĐŊа Immich.",
|
"purchase_panel_info_2": "ĐĸŅĐš ĐēаŅĐž ŅĐŧĐĩ аĐŊĐŗĐ°ĐļиŅаĐŊи да ĐŊĐĩ дОйавŅĐŧĐĩ ĐŋĐģаŅĐĩĐŊи ŅŅĐĩĐŊи, ŅаСи ĐŋĐžĐēŅĐŋĐēа ĐŊŅĐŧа да ви ĐŋŅĐĩĐ´ĐžŅŅави Đ´ĐžĐŋŅĐģĐŊиŅĐĩĐģĐŊи ŅŅĐŊĐēŅии в Immich. ĐиĐĩ ŅаСŅиŅаĐŧĐĩ ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģи ĐēаŅĐž ваŅ, Са да ĐŋОдĐēŅĐĩĐŋŅŅĐĩ ĐŋŅОдŅĐģĐļаваŅĐžŅĐž ŅаСвиŅиĐĩ ĐŊа Immich.",
|
||||||
"purchase_panel_title": "ĐОддŅŅĐļаКŅĐĩ ĐŋŅĐžĐĩĐēŅа",
|
"purchase_panel_title": "ĐОддŅŅĐļаКŅĐĩ ĐŋŅĐžĐĩĐēŅа",
|
||||||
"purchase_per_server": "ĐŊа ŅŅŅвŅŅ",
|
"purchase_per_server": "ĐŊа ŅŅŅвŅŅ",
|
||||||
"purchase_per_user": "ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģ",
|
"purchase_per_user": "ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģ",
|
||||||
@@ -1519,11 +1487,9 @@
|
|||||||
"remove_custom_date_range": "ĐŅĐĩĐŧаŅ
ĐŊи СададĐĩĐŊĐ¸Ņ Đ´Đ¸Đ°ĐŋаСОĐŊ ĐžŅ Đ´Đ°Ņи",
|
"remove_custom_date_range": "ĐŅĐĩĐŧаŅ
ĐŊи СададĐĩĐŊĐ¸Ņ Đ´Đ¸Đ°ĐŋаСОĐŊ ĐžŅ Đ´Đ°Ņи",
|
||||||
"remove_deleted_assets": "ĐŅĐĩĐŧаŅ
ĐŊи ĐСŅŅиŅиŅĐĩ ĐĐģĐĩĐŧĐĩĐŊŅи",
|
"remove_deleted_assets": "ĐŅĐĩĐŧаŅ
ĐŊи ĐСŅŅиŅиŅĐĩ ĐĐģĐĩĐŧĐĩĐŊŅи",
|
||||||
"remove_from_album": "ĐŅĐĩĐŧаŅ
ĐŊи ĐžŅ Đ°ĐģĐąŅĐŧа",
|
"remove_from_album": "ĐŅĐĩĐŧаŅ
ĐŊи ĐžŅ Đ°ĐģĐąŅĐŧа",
|
||||||
"remove_from_album_action_prompt": "{count} Ņа ĐŋŅĐĩĐŧаŅ
ĐŊаŅи ĐžŅ Đ°ĐģĐąŅĐŧа",
|
|
||||||
"remove_from_favorites": "ĐŅĐĩĐŧаŅ
ĐŊи ĐžŅ ĐŅйиĐŧи",
|
"remove_from_favorites": "ĐŅĐĩĐŧаŅ
ĐŊи ĐžŅ ĐŅйиĐŧи",
|
||||||
"remove_from_lock_folder_action_prompt": "{count} Ņа ĐŋŅĐĩĐŧаŅ
ĐŊаŅи ĐžŅ ĐˇĐ°ĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа",
|
|
||||||
"remove_from_locked_folder": "ĐаŅ
ĐŊи ĐžŅ ĐˇĐ°ĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа",
|
"remove_from_locked_folder": "ĐаŅ
ĐŊи ĐžŅ ĐˇĐ°ĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа",
|
||||||
"remove_from_locked_folder_confirmation": "ĐĄĐ¸ĐŗŅŅĐŊи Đģи Ņи, ŅĐĩ иŅĐēаŅĐĩ ŅĐĩСи ŅĐŊиĐŧĐēи и видĐĩа да ĐąŅĐ´Đ°Ņ Đ¸ĐˇĐ˛Đ°Đ´ĐĩĐŊи ĐžŅ ĐˇĐ°ĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа? ĐĸĐĩ ŅĐĩ ĐąŅĐ´Đ°Ņ Đ˛Đ¸Đ´Đ¸Đŧи в йийĐģиОŅĐĩĐēаŅа.",
|
"remove_from_locked_folder_confirmation": "ĐĄĐ¸ĐŗŅŅĐĩĐŊ Đģи Ņи, ŅĐĩ иŅĐēĐ°Ņ ŅĐĩСи ŅĐŊиĐŧĐēи и видĐĩа да ĐąŅĐ´Đ°Ņ Đ¸ĐˇĐ˛Đ°Đ´ĐĩĐŊи ĐžŅ ĐˇĐ°ĐēĐģŅŅĐĩĐŊаŅа ĐŋаĐŋĐēа? ĐĸĐĩ ŅĐĩ ĐąŅĐ´Đ°Ņ Đ˛Đ¸Đ´Đ¸Đŧи в йийĐģиОŅĐĩĐēаŅа.",
|
||||||
"remove_from_shared_link": "ĐŅĐĩĐŧаŅ
ĐŊи ĐžŅ ŅĐŋОдĐĩĐģĐĩĐŊĐ¸Ņ ĐģиĐŊĐē",
|
"remove_from_shared_link": "ĐŅĐĩĐŧаŅ
ĐŊи ĐžŅ ŅĐŋОдĐĩĐģĐĩĐŊĐ¸Ņ ĐģиĐŊĐē",
|
||||||
"remove_memory": "ĐŅĐĩĐŧаŅ
ĐŊи ŅĐŋĐžĐŧĐĩĐŊиŅĐĩ",
|
"remove_memory": "ĐŅĐĩĐŧаŅ
ĐŊи ŅĐŋĐžĐŧĐĩĐŊиŅĐĩ",
|
||||||
"remove_photo_from_memory": "ĐŅĐĩĐŧаŅ
ĐŊи ŅĐŊиĐŧĐēиŅĐĩ ĐžŅ ŅĐŋĐžĐŧĐĩĐŊиŅĐĩ",
|
"remove_photo_from_memory": "ĐŅĐĩĐŧаŅ
ĐŊи ŅĐŊиĐŧĐēиŅĐĩ ĐžŅ ŅĐŋĐžĐŧĐĩĐŊиŅĐĩ",
|
||||||
@@ -1548,7 +1514,7 @@
|
|||||||
"reset": "ĐŅĐģиŅаĐŊĐĩ",
|
"reset": "ĐŅĐģиŅаĐŊĐĩ",
|
||||||
"reset_password": "ĐŅĐģиŅаĐŊĐĩ ĐŊа ĐŋаŅĐžĐģаŅа",
|
"reset_password": "ĐŅĐģиŅаĐŊĐĩ ĐŊа ĐŋаŅĐžĐģаŅа",
|
||||||
"reset_people_visibility": "ĐŅĐģиŅаĐŊĐĩ ĐŊа видиĐŧĐžŅŅŅа ĐŊа Ņ
ĐžŅаŅа",
|
"reset_people_visibility": "ĐŅĐģиŅаĐŊĐĩ ĐŊа видиĐŧĐžŅŅŅа ĐŊа Ņ
ĐžŅаŅа",
|
||||||
"reset_pin_code": "ĐŅĐģиŅаК PIN ĐēОда",
|
"reset_pin_code": "ĐŅĐģиŅаК PIN-ĐēОда",
|
||||||
"reset_to_default": "ĐŅŅŅаĐŊĐĩ ĐŊа ŅайŅиŅĐŊи ĐŊаŅŅŅОКĐēи",
|
"reset_to_default": "ĐŅŅŅаĐŊĐĩ ĐŊа ŅайŅиŅĐŊи ĐŊаŅŅŅОКĐēи",
|
||||||
"resolve_duplicates": "Đ ĐĩŅи Đ´ŅĐąĐģиĐēаŅиŅĐĩ",
|
"resolve_duplicates": "Đ ĐĩŅи Đ´ŅĐąĐģиĐēаŅиŅĐĩ",
|
||||||
"resolved_all_duplicates": "ĐŅиŅĐēи Đ´ŅĐąĐģиĐēаŅи Ņа ŅĐĩŅĐĩĐŊи",
|
"resolved_all_duplicates": "ĐŅиŅĐēи Đ´ŅĐąĐģиĐēаŅи Ņа ŅĐĩŅĐĩĐŊи",
|
||||||
@@ -1613,8 +1579,8 @@
|
|||||||
"search_page_selfies": "ĐĄĐĩĐģŅиŅа",
|
"search_page_selfies": "ĐĄĐĩĐģŅиŅа",
|
||||||
"search_page_things": "ĐŅĐĩĐ´ĐŧĐĩŅи",
|
"search_page_things": "ĐŅĐĩĐ´ĐŧĐĩŅи",
|
||||||
"search_page_view_all_button": "ĐиĐļ вŅиŅĐēи",
|
"search_page_view_all_button": "ĐиĐļ вŅиŅĐēи",
|
||||||
"search_page_your_activity": "ĐаŅиŅĐĩ Đ´ĐĩĐšŅŅвиŅ",
|
"search_page_your_activity": "ĐĸвОиŅĐĩ Đ´ĐĩĐšŅŅвиŅ",
|
||||||
"search_page_your_map": "ĐаŅаŅа ĐēаŅŅа",
|
"search_page_your_map": "ĐĸвОŅŅа ĐēаŅŅа",
|
||||||
"search_people": "ĐĸŅŅŅĐĩŅĐĩ ĐŊа Ņ
ĐžŅа",
|
"search_people": "ĐĸŅŅŅĐĩŅĐĩ ĐŊа Ņ
ĐžŅа",
|
||||||
"search_places": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ĐŧĐĩŅŅа",
|
"search_places": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ĐŧĐĩŅŅа",
|
||||||
"search_rating": "ĐĸŅŅŅи ĐŋĐž ŅĐĩĐšŅиĐŊĐŗâĻ",
|
"search_rating": "ĐĸŅŅŅи ĐŋĐž ŅĐĩĐšŅиĐŊĐŗâĻ",
|
||||||
@@ -1622,7 +1588,7 @@
|
|||||||
"search_settings": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ĐŊаŅŅŅОКĐēи",
|
"search_settings": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ĐŊаŅŅŅОКĐēи",
|
||||||
"search_state": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ŅаŅ...",
|
"search_state": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ŅаŅ...",
|
||||||
"search_suggestion_list_smart_search_hint_1": "ĐŖĐŧĐŊĐžŅĐž ŅŅŅŅĐĩĐŊĐĩ Đĩ вĐēĐģŅŅĐĩĐŊĐž ĐŋĐž ĐŋОдŅаСйиŅаĐŊĐĩ, Са ŅŅŅŅĐĩĐŊĐĩ в ĐŧĐĩŅадаĐŊĐŊиŅĐĩ иСĐŋĐžĐģСваК ŅĐŋĐĩŅиаĐģĐĩĐŊ ŅиĐŊŅаĐēŅ ",
|
"search_suggestion_list_smart_search_hint_1": "ĐŖĐŧĐŊĐžŅĐž ŅŅŅŅĐĩĐŊĐĩ Đĩ вĐēĐģŅŅĐĩĐŊĐž ĐŋĐž ĐŋОдŅаСйиŅаĐŊĐĩ, Са ŅŅŅŅĐĩĐŊĐĩ в ĐŧĐĩŅадаĐŊĐŊиŅĐĩ иСĐŋĐžĐģСваК ŅĐŋĐĩŅиаĐģĐĩĐŊ ŅиĐŊŅаĐēŅ ",
|
||||||
"search_suggestion_list_smart_search_hint_2": "m:ваŅиŅ-ŅĐĩŅĐŧиĐŊ-Са-ŅŅŅŅĐĩĐŊĐĩ",
|
"search_suggestion_list_smart_search_hint_2": "m:ŅвОŅ-ŅĐĩŅĐŧиĐŊ-Са-ŅŅŅŅĐĩĐŊĐĩ",
|
||||||
"search_tags": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ĐĩŅиĐēĐĩŅи...",
|
"search_tags": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ĐĩŅиĐēĐĩŅи...",
|
||||||
"search_timezone": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ŅаŅОва СОĐŊа...",
|
"search_timezone": "ĐĸŅŅŅĐĩĐŊĐĩ ĐŊа ŅаŅОва СОĐŊа...",
|
||||||
"search_type": "ĐĸиĐŋ ĐŊа ŅŅŅŅĐĩĐŊĐĩ",
|
"search_type": "ĐĸиĐŋ ĐŊа ŅŅŅŅĐĩĐŊĐĩ",
|
||||||
@@ -1634,7 +1600,6 @@
|
|||||||
"select_album_cover": "ĐСйĐĩŅĐĩŅĐĩ ОйĐģĐžĐļĐēа ĐŊа аĐģĐąŅĐŧ",
|
"select_album_cover": "ĐСйĐĩŅĐĩŅĐĩ ОйĐģĐžĐļĐēа ĐŊа аĐģĐąŅĐŧ",
|
||||||
"select_all": "ĐСйĐĩŅĐĩŅĐĩ вŅиŅĐēи",
|
"select_all": "ĐСйĐĩŅĐĩŅĐĩ вŅиŅĐēи",
|
||||||
"select_all_duplicates": "ĐСйĐĩŅи вŅиŅĐēи Đ´ŅĐąĐģиĐēаŅи",
|
"select_all_duplicates": "ĐСйĐĩŅи вŅиŅĐēи Đ´ŅĐąĐģиĐēаŅи",
|
||||||
"select_all_in": "ĐСйĐĩŅи вŅиŅĐēи ĐžŅ ĐŗŅŅĐŋаŅа {group}",
|
|
||||||
"select_avatar_color": "ĐСйĐĩŅĐĩŅĐĩ ŅвŅŅ ĐŊа аваŅаŅа",
|
"select_avatar_color": "ĐСйĐĩŅĐĩŅĐĩ ŅвŅŅ ĐŊа аваŅаŅа",
|
||||||
"select_face": "ĐСйĐĩŅĐĩŅĐĩ ĐģиŅĐĩ",
|
"select_face": "ĐСйĐĩŅĐĩŅĐĩ ĐģиŅĐĩ",
|
||||||
"select_featured_photo": "ĐСйĐĩŅи ĐŋŅĐĩĐ´ŅŅавиŅĐĩĐģĐŊа ŅĐŊиĐŧĐēа",
|
"select_featured_photo": "ĐСйĐĩŅи ĐŋŅĐĩĐ´ŅŅавиŅĐĩĐģĐŊа ŅĐŊиĐŧĐēа",
|
||||||
@@ -1691,16 +1656,15 @@
|
|||||||
"settings": "ĐаŅŅŅОКĐēи",
|
"settings": "ĐаŅŅŅОКĐēи",
|
||||||
"settings_require_restart": "ĐĐžĐģŅ, Са да ŅĐĩ ĐŋŅиĐģĐžĐļи ĐŊаŅŅŅОКĐēаŅа ŅĐĩŅŅаŅŅиŅаК Immich",
|
"settings_require_restart": "ĐĐžĐģŅ, Са да ŅĐĩ ĐŋŅиĐģĐžĐļи ĐŊаŅŅŅОКĐēаŅа ŅĐĩŅŅаŅŅиŅаК Immich",
|
||||||
"settings_saved": "ĐаŅŅŅОКĐēиŅĐĩ Ņа СаĐŋаСĐĩĐŊи",
|
"settings_saved": "ĐаŅŅŅОКĐēиŅĐĩ Ņа СаĐŋаСĐĩĐŊи",
|
||||||
"setup_pin_code": "ĐадаК PIN ĐēОд",
|
"setup_pin_code": "ĐадаК PIN-ĐēОд",
|
||||||
"share": "ĐĄĐŋОдĐĩĐģŅĐŊĐĩ",
|
"share": "ĐĄĐŋОдĐĩĐģŅĐŊĐĩ",
|
||||||
"share_action_prompt": "{count} ŅĐŋОдĐĩĐģĐĩĐŊи ОйĐĩĐēŅа",
|
|
||||||
"share_add_photos": "ĐОйави ŅĐŊиĐŧĐēи",
|
"share_add_photos": "ĐОйави ŅĐŊиĐŧĐēи",
|
||||||
"share_assets_selected": "{count} иСйŅаĐŊи",
|
"share_assets_selected": "{count} иСйŅаĐŊи",
|
||||||
"share_dialog_preparing": "ĐĐžĐ´ĐŗĐžŅОвĐēа...",
|
"share_dialog_preparing": "ĐĐžĐ´ĐŗĐžŅОвĐēа...",
|
||||||
"share_link": "ĐŅŅСĐēа Са ŅĐŋОдĐĩĐģŅĐŊĐĩ",
|
"share_link": "ĐŅŅСĐēа Са ŅĐŋОдĐĩĐģŅĐŊĐĩ",
|
||||||
"shared": "ĐĄĐŋОдĐĩĐģĐĩĐŊĐž",
|
"shared": "ĐĄĐŋОдĐĩĐģĐĩĐŊĐž",
|
||||||
"shared_album_activities_input_disable": "ĐĐžĐŧĐĩĐŊŅаŅиŅĐĩ Ņа иСĐēĐģŅŅĐĩĐŊи",
|
"shared_album_activities_input_disable": "ĐĐžĐŧĐĩĐŊŅаŅиŅĐĩ Ņа иСĐēĐģŅŅĐĩĐŊи",
|
||||||
"shared_album_activity_remove_content": "ĐŅĐēаŅĐĩ Đģи да иСŅŅиĐĩŅĐĩ ŅаСи аĐēŅивĐŊĐžŅŅ?",
|
"shared_album_activity_remove_content": "ĐŅĐēĐ°Ņ Đģи да иСŅŅиĐĩŅ ŅаСи аĐēŅивĐŊĐžŅŅ?",
|
||||||
"shared_album_activity_remove_title": "ĐСŅŅиК",
|
"shared_album_activity_remove_title": "ĐСŅŅиК",
|
||||||
"shared_album_section_people_action_error": "ĐŅĐĩŅĐēа ĐŋŅи ĐŊаĐŋŅŅĐēаĐŊĐĩ/ĐŋŅĐĩĐŧаŅ
ваĐŊĐĩ ĐžŅ Đ°ĐģĐąŅĐŧа",
|
"shared_album_section_people_action_error": "ĐŅĐĩŅĐēа ĐŋŅи ĐŊаĐŋŅŅĐēаĐŊĐĩ/ĐŋŅĐĩĐŧаŅ
ваĐŊĐĩ ĐžŅ Đ°ĐģĐąŅĐŧа",
|
||||||
"shared_album_section_people_action_leave": "ĐŅĐĩĐŧаŅ
ваĐŊĐĩ ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģ ĐžŅ Đ°ĐģĐąŅĐŧа",
|
"shared_album_section_people_action_leave": "ĐŅĐĩĐŧаŅ
ваĐŊĐĩ ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģ ĐžŅ Đ°ĐģĐąŅĐŧа",
|
||||||
@@ -1708,7 +1672,7 @@
|
|||||||
"shared_album_section_people_title": "ĐĨĐĐ Đ",
|
"shared_album_section_people_title": "ĐĨĐĐ Đ",
|
||||||
"shared_by": "ĐĄĐŋОдĐĩĐģĐĩĐŊĐž ĐžŅ",
|
"shared_by": "ĐĄĐŋОдĐĩĐģĐĩĐŊĐž ĐžŅ",
|
||||||
"shared_by_user": "ĐĄĐŋОдĐĩĐģĐĩĐŊĐž ĐžŅ {user}",
|
"shared_by_user": "ĐĄĐŋОдĐĩĐģĐĩĐŊĐž ĐžŅ {user}",
|
||||||
"shared_by_you": "ĐĄĐŋОдĐĩĐģĐĩĐŊĐž ĐžŅ Đ˛Đ°Ņ",
|
"shared_by_you": "ĐĄĐŋОдĐĩĐģĐĩĐŊĐž ĐžŅ ŅĐĩĐą",
|
||||||
"shared_from_partner": "ĐĄĐŊиĐŧĐēи ĐžŅ {partner}",
|
"shared_from_partner": "ĐĄĐŊиĐŧĐēи ĐžŅ {partner}",
|
||||||
"shared_intent_upload_button_progress_text": "{current} / {total} ĐаŅĐĩĐ´ĐĩĐŊĐž",
|
"shared_intent_upload_button_progress_text": "{current} / {total} ĐаŅĐĩĐ´ĐĩĐŊĐž",
|
||||||
"shared_link_app_bar_title": "ĐĄĐŋОдĐĩĐģĐĩĐŊи вŅŅСĐēи",
|
"shared_link_app_bar_title": "ĐĄĐŋОдĐĩĐģĐĩĐŊи вŅŅСĐēи",
|
||||||
@@ -1748,7 +1712,7 @@
|
|||||||
"sharing": "ĐĄĐŋОдĐĩĐģĐĩĐŊи",
|
"sharing": "ĐĄĐŋОдĐĩĐģĐĩĐŊи",
|
||||||
"sharing_enter_password": "ĐĐžĐģŅ, вŅвĐĩĐ´ĐĩŅĐĩ ĐŋаŅĐžĐģаŅа, Са да видиŅĐĩ ŅаСи ŅŅŅаĐŊиŅа.",
|
"sharing_enter_password": "ĐĐžĐģŅ, вŅвĐĩĐ´ĐĩŅĐĩ ĐŋаŅĐžĐģаŅа, Са да видиŅĐĩ ŅаСи ŅŅŅаĐŊиŅа.",
|
||||||
"sharing_page_album": "ĐĄĐŋОдĐĩĐģĐĩĐŊи аĐģĐąŅĐŧи",
|
"sharing_page_album": "ĐĄĐŋОдĐĩĐģĐĩĐŊи аĐģĐąŅĐŧи",
|
||||||
"sharing_page_description": "ĐĄŅСдаКŅĐĩ ŅĐŋОдĐĩĐģĐĩĐŊи аĐģĐąŅĐŧи Са да ŅĐŋОдĐĩĐģиŅĐĩ ŅĐŊиĐŧĐēи и видĐĩа Ņ Ņ
ĐžŅа ĐžŅ Đ˛Đ°ŅаŅа ĐŧŅĐĩĐļа.",
|
"sharing_page_description": "ĐĄŅСдаК ŅĐŋОдĐĩĐģĐĩĐŊи аĐģĐąŅĐŧи Са да ŅĐŋОдĐĩĐģĐ¸Ņ ŅĐŊиĐŧĐēи и видĐĩа Ņ Ņ
ĐžŅа ĐžŅ ŅвОŅŅа ĐŧŅĐĩĐļа.",
|
||||||
"sharing_page_empty_list": "ĐĐ ĐĐĐĐ ĐĄĐĐĐĄĐĒĐ",
|
"sharing_page_empty_list": "ĐĐ ĐĐĐĐ ĐĄĐĐĐĄĐĒĐ",
|
||||||
"sharing_sidebar_description": "ĐĐžĐēаĐļи вŅŅСĐēа ĐēŅĐŧ ĐĄĐŋОдĐĩĐģŅĐŊĐĩ в ŅŅŅаĐŊиŅĐŊаŅа ĐģĐĩĐŊŅа",
|
"sharing_sidebar_description": "ĐĐžĐēаĐļи вŅŅСĐēа ĐēŅĐŧ ĐĄĐŋОдĐĩĐģŅĐŊĐĩ в ŅŅŅаĐŊиŅĐŊаŅа ĐģĐĩĐŊŅа",
|
||||||
"sharing_silver_appbar_create_shared_album": "ĐОв ŅĐŋОдĐĩĐģĐĩĐŊ аĐģĐąŅĐŧ",
|
"sharing_silver_appbar_create_shared_album": "ĐОв ŅĐŋОдĐĩĐģĐĩĐŊ аĐģĐąŅĐŧ",
|
||||||
@@ -1795,7 +1759,6 @@
|
|||||||
"sort_title": "ĐĐ°ĐŗĐģавиĐĩ",
|
"sort_title": "ĐĐ°ĐŗĐģавиĐĩ",
|
||||||
"source": "ĐОд",
|
"source": "ĐОд",
|
||||||
"stack": "ĐĄŅĐąĐĩŅи",
|
"stack": "ĐĄŅĐąĐĩŅи",
|
||||||
"stack_action_prompt": "{count} Ņа ĐŗŅŅĐŋиŅаĐŊи",
|
|
||||||
"stack_duplicates": "ĐОдŅĐĩĐļдаĐŊĐĩ ĐŊа Đ´ŅĐąĐģиĐēаŅи",
|
"stack_duplicates": "ĐОдŅĐĩĐļдаĐŊĐĩ ĐŊа Đ´ŅĐąĐģиĐēаŅи",
|
||||||
"stack_select_one_photo": "ĐСйĐĩŅи ĐĩĐ´ĐŊа ĐŗĐģавĐŊа ŅĐŊиĐŧĐēа Са ŅŅĐąŅаĐŊиŅĐĩ ŅĐŊиĐŧĐēи",
|
"stack_select_one_photo": "ĐСйĐĩŅи ĐĩĐ´ĐŊа ĐŗĐģавĐŊа ŅĐŊиĐŧĐēа Са ŅŅĐąŅаĐŊиŅĐĩ ŅĐŊиĐŧĐēи",
|
||||||
"stack_selected_photos": "ĐОдŅĐĩĐļдаĐŊĐĩ ĐŊа иСйŅаĐŊи ŅĐŊиĐŧĐēи",
|
"stack_selected_photos": "ĐОдŅĐĩĐļдаĐŊĐĩ ĐŊа иСйŅаĐŊи ŅĐŊиĐŧĐēи",
|
||||||
@@ -1824,7 +1787,6 @@
|
|||||||
"sync": "ХиĐŊŅ
ŅĐžĐŊиСиŅаĐŊĐĩ",
|
"sync": "ХиĐŊŅ
ŅĐžĐŊиСиŅаĐŊĐĩ",
|
||||||
"sync_albums": "ХиĐŊŅ
ŅĐžĐŊиСиŅаĐŊĐĩ ĐŊа аĐģĐąŅĐŧи",
|
"sync_albums": "ХиĐŊŅ
ŅĐžĐŊиСиŅаĐŊĐĩ ĐŊа аĐģĐąŅĐŧи",
|
||||||
"sync_albums_manual_subtitle": "ХиĐŊŅ
ŅĐžĐŊиСиŅаК вŅиŅĐēи СаŅĐĩĐ´ĐĩĐŊи видĐĩа и ŅĐŊиĐŧĐēи в иСйŅаĐŊиŅĐĩ аŅŅ
ивĐŊи аĐģĐąŅĐŧи",
|
"sync_albums_manual_subtitle": "ХиĐŊŅ
ŅĐžĐŊиСиŅаК вŅиŅĐēи СаŅĐĩĐ´ĐĩĐŊи видĐĩа и ŅĐŊиĐŧĐēи в иСйŅаĐŊиŅĐĩ аŅŅ
ивĐŊи аĐģĐąŅĐŧи",
|
||||||
"sync_upload_album_setting_subtitle": "ĐĄŅСдаваКŅĐĩ и СаŅĐĩĐļдаКŅĐĩ ŅĐŊиĐŧĐēи и видĐĩа в иСйŅаĐŊи аĐģĐąŅĐŧи в Immich",
|
|
||||||
"tag": "ĐĸĐ°Đŗ",
|
"tag": "ĐĸĐ°Đŗ",
|
||||||
"tag_assets": "ĐĸĐ°ĐŗĐŊи ĐĩĐģĐĩĐŧĐĩĐŊŅи",
|
"tag_assets": "ĐĸĐ°ĐŗĐŊи ĐĩĐģĐĩĐŧĐĩĐŊŅи",
|
||||||
"tag_created": "ĐĄŅСдадĐĩĐŊ ĐĩŅиĐēĐĩŅ: {tag}",
|
"tag_created": "ĐĄŅСдадĐĩĐŊ ĐĩŅиĐēĐĩŅ: {tag}",
|
||||||
@@ -1838,19 +1800,6 @@
|
|||||||
"theme": "ĐĸĐĩĐŧа",
|
"theme": "ĐĸĐĩĐŧа",
|
||||||
"theme_selection": "ĐĐˇĐąĐžŅ ĐŊа ŅĐĩĐŧа",
|
"theme_selection": "ĐĐˇĐąĐžŅ ĐŊа ŅĐĩĐŧа",
|
||||||
"theme_selection_description": "ĐвŅĐžĐŧаŅиŅĐŊĐž СадаваĐŊĐĩ ĐŊа ŅвĐĩŅĐģа иĐģи ŅŅĐŧĐŊа ŅĐĩĐŧа вŅС ĐžŅĐŊОва ĐŊа ŅиŅŅĐĩĐŧĐŊиŅĐĩ ĐŋŅĐĩĐ´ĐŋĐžŅиŅаĐŊĐ¸Ņ ĐŊа ваŅĐ¸Ņ ĐąŅаŅСŅŅ",
|
"theme_selection_description": "ĐвŅĐžĐŧаŅиŅĐŊĐž СадаваĐŊĐĩ ĐŊа ŅвĐĩŅĐģа иĐģи ŅŅĐŧĐŊа ŅĐĩĐŧа вŅС ĐžŅĐŊОва ĐŊа ŅиŅŅĐĩĐŧĐŊиŅĐĩ ĐŋŅĐĩĐ´ĐŋĐžŅиŅаĐŊĐ¸Ņ ĐŊа ваŅĐ¸Ņ ĐąŅаŅСŅŅ",
|
||||||
"theme_setting_asset_list_storage_indicator_title": "ĐĐžĐēаСваК иĐŊдиĐēаŅĐžŅ ĐˇĐ° Ņ
ŅаĐŊиĐģиŅĐĩŅĐž в ĐˇĐ°ĐŗĐģавиŅŅа ĐŊа ОйĐĩĐēŅиŅĐĩ",
|
|
||||||
"theme_setting_asset_list_tiles_per_row_title": "ĐŅОК ОйĐĩĐēŅи ĐŊа ŅĐĩĐ´ ({count})",
|
|
||||||
"theme_setting_colorful_interface_subtitle": "ĐаĐŊĐĩŅи ĐžŅĐŊОвĐĩĐŊ ŅвŅŅ Đ˛ŅŅŅ
Ņ ŅĐžĐŊОвиŅĐĩ ĐŋОвŅŅŅ
ĐŊĐžŅŅи.",
|
|
||||||
"theme_setting_colorful_interface_title": "ĐĻвĐĩŅОвĐĩ ĐŊа иĐŊŅĐĩŅŅĐĩĐšŅа",
|
|
||||||
"theme_setting_image_viewer_quality_subtitle": "Đ ĐĩĐŗŅĐģиŅаĐŊĐĩ ĐŊа ĐēаŅĐĩŅŅвОŅĐž ĐŊа ĐŋŅĐžĐŗŅаĐŧаŅа Са ĐŋŅĐĩĐŗĐģĐĩĐ´ ĐŊа Đ´ĐĩŅаКĐģĐŊи иСОйŅаĐļĐĩĐŊиŅ",
|
|
||||||
"theme_setting_image_viewer_quality_title": "ĐаŅĐĩŅŅвО ĐŊа ĐŋŅĐĩĐŗĐģĐĩда ĐŊа иСОйŅаĐļĐĩĐŊиŅ",
|
|
||||||
"theme_setting_primary_color_subtitle": "ĐСйĐĩŅи ŅвŅŅ ĐˇĐ° ĐžŅĐŊОвĐŊиŅĐĩ Đ´ĐĩĐšŅŅĐ˛Đ¸Ņ Đ¸ аĐēŅĐĩĐŊŅи.",
|
|
||||||
"theme_setting_primary_color_title": "ĐŅĐŊОвĐĩĐŊ ŅвŅŅ",
|
|
||||||
"theme_setting_system_primary_color_title": "ĐСĐŋĐžĐģСваК ĐžŅ ŅиŅŅĐĩĐŧаŅа",
|
|
||||||
"theme_setting_system_theme_switch": "ĐвŅĐžĐŧаŅиŅĐŊĐž (ĐĄĐŋĐžŅĐĩĐ´ ŅиŅŅĐĩĐŧĐŊаŅа ĐŊаŅŅŅОКĐēа)",
|
|
||||||
"theme_setting_theme_subtitle": "ĐадаК ĐŊаŅŅŅОКĐēи ĐŊа ŅвĐĩŅОваŅа ŅĐĩĐŧа ĐŊа ĐŋŅиĐģĐžĐļĐĩĐŊиĐĩŅĐž",
|
|
||||||
"theme_setting_three_stage_loading_subtitle": "ĐĸŅи-ŅŅĐĩĐŋĐĩĐŊĐŊĐžŅĐž СаŅĐĩĐļдаĐŊĐĩ ĐŧĐžĐļĐĩ да ŅвĐĩĐģиŅи ĐŋŅОиСвОдиŅĐĩĐģĐŊĐžŅŅŅа, ĐŊĐž ŅĐĩ ŅвĐĩĐģиŅи СĐŊаŅиŅĐĩĐģĐŊĐž и ĐŧŅĐĩĐļĐžĐ˛Đ¸Ņ ŅŅаŅиĐē",
|
|
||||||
"theme_setting_three_stage_loading_title": "ĐĐēĐģŅŅи ŅŅи-ŅŅĐĩĐŋĐĩĐŊĐŊĐž СаŅĐĩĐļдаĐŊĐĩ",
|
|
||||||
"they_will_be_merged_together": "ĐĸĐĩ ŅĐĩ ĐąŅĐ´Đ°Ņ ĐžĐąĐĩдиĐŊĐĩĐŊи",
|
"they_will_be_merged_together": "ĐĸĐĩ ŅĐĩ ĐąŅĐ´Đ°Ņ ĐžĐąĐĩдиĐŊĐĩĐŊи",
|
||||||
"third_party_resources": "Đ ĐĩŅŅŅŅи ĐžŅ ŅŅĐĩŅи ŅŅŅаĐŊи",
|
"third_party_resources": "Đ ĐĩŅŅŅŅи ĐžŅ ŅŅĐĩŅи ŅŅŅаĐŊи",
|
||||||
"time_based_memories": "ĐĄĐŋĐžĐŧĐĩĐŊи, йаСиŅаĐŊи ĐŊа вŅĐĩĐŧĐĩŅĐž",
|
"time_based_memories": "ĐĄĐŋĐžĐŧĐĩĐŊи, йаСиŅаĐŊи ĐŊа вŅĐĩĐŧĐĩŅĐž",
|
||||||
@@ -1866,29 +1815,15 @@
|
|||||||
"total": "ĐĐąŅĐž",
|
"total": "ĐĐąŅĐž",
|
||||||
"total_usage": "ĐĐąŅĐž иСĐŋĐžĐģСваĐŊĐž",
|
"total_usage": "ĐĐąŅĐž иСĐŋĐžĐģСваĐŊĐž",
|
||||||
"trash": "ĐĐžŅŅĐĩ",
|
"trash": "ĐĐžŅŅĐĩ",
|
||||||
"trash_action_prompt": "{count} Ņа ĐŋŅĐĩĐŧĐĩŅŅĐĩĐŊи в ĐēĐžŅа",
|
|
||||||
"trash_all": "ĐСŅ
вŅŅĐģи вŅиŅĐēи",
|
"trash_all": "ĐСŅ
вŅŅĐģи вŅиŅĐēи",
|
||||||
"trash_count": "Đ ĐĐžŅŅĐĩŅĐž {count, number}",
|
"trash_count": "Đ ĐĐžŅŅĐĩŅĐž {count, number}",
|
||||||
"trash_delete_asset": "ĐĐēаŅаК в ĐĐžŅŅĐĩŅĐž/ĐСŅŅиК ĐĩĐģĐĩĐŧĐĩĐŊŅ",
|
"trash_delete_asset": "ĐĐēаŅаК в ĐĐžŅŅĐĩŅĐž/ĐСŅŅиК ĐĩĐģĐĩĐŧĐĩĐŊŅ",
|
||||||
"trash_emptied": "ĐĐžŅа Đĩ иСĐŋŅаСĐŊĐĩĐŊ",
|
|
||||||
"trash_no_results_message": "ĐСŅŅиŅиŅĐĩ ŅĐŊиĐŧĐēи и видĐĩĐžĐēĐģиĐŋОвĐĩ ŅĐĩ ŅĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ ŅŅĐē.",
|
"trash_no_results_message": "ĐСŅŅиŅиŅĐĩ ŅĐŊиĐŧĐēи и видĐĩĐžĐēĐģиĐŋОвĐĩ ŅĐĩ ŅĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ ŅŅĐē.",
|
||||||
"trash_page_delete_all": "ĐСŅŅиК вŅиŅĐēĐž",
|
|
||||||
"trash_page_empty_trash_dialog_content": "ĐŅĐēаŅĐĩ Đģи да иСĐŋŅаСĐŊŅ ĐēĐžŅа? ĐĸĐĩСи ОйĐĩĐēŅи ŅĐĩ ĐąŅĐ´Đ°Ņ Đ¸ĐˇŅŅиŅи СавиĐŊĐ°ĐŗĐ¸ ĐžŅ Immich",
|
|
||||||
"trash_page_info": "ĐĐąĐĩĐēŅиŅĐĩ в ĐēĐžŅа ŅĐĩ ĐąŅĐ´Đ°Ņ Đ¸ĐˇŅŅиваĐŊи СавиĐŊĐ°ĐŗĐ¸ ŅĐģĐĩĐ´ {days} Đ´ĐŊи",
|
|
||||||
"trash_page_no_assets": "ĐĐžŅа Đĩ ĐŋŅаСĐĩĐŊ",
|
|
||||||
"trash_page_restore_all": "ĐŅСŅŅаĐŊОвŅваĐŊĐĩ ĐŊа вŅиŅĐēи",
|
|
||||||
"trash_page_select_assets_btn": "ĐСйĐĩŅи ОйĐĩĐēŅи",
|
|
||||||
"trash_page_title": "Đ ĐēĐžŅа ({count})",
|
|
||||||
"trashed_items_will_be_permanently_deleted_after": "ĐСŅ
вŅŅĐģĐĩĐŊиŅĐĩ в ĐēĐžŅŅĐĩŅĐž ĐĩĐģĐĩĐŧĐĩĐŊŅи ŅĐĩ ĐąŅĐ´Đ°Ņ Đ¸ĐˇŅŅиŅи Са ĐŋĐžŅŅĐžŅĐŊĐŊĐž ŅĐģĐĩĐ´ {days, plural, one {# Đ´ĐĩĐŊ} other {# Đ´ĐŊи}}.",
|
"trashed_items_will_be_permanently_deleted_after": "ĐСŅ
вŅŅĐģĐĩĐŊиŅĐĩ в ĐēĐžŅŅĐĩŅĐž ĐĩĐģĐĩĐŧĐĩĐŊŅи ŅĐĩ ĐąŅĐ´Đ°Ņ Đ¸ĐˇŅŅиŅи Са ĐŋĐžŅŅĐžŅĐŊĐŊĐž ŅĐģĐĩĐ´ {days, plural, one {# Đ´ĐĩĐŊ} other {# Đ´ĐŊи}}.",
|
||||||
"type": "ĐĸиĐŋ",
|
"type": "ĐĸиĐŋ",
|
||||||
"unable_to_change_pin_code": "ĐĐĩвŅСĐŧĐžĐļĐŊа ĐŋŅĐžĐŧŅĐŊа ĐŊа PIN ĐēОда",
|
|
||||||
"unable_to_setup_pin_code": "ĐĐĩŅŅĐŋĐĩŅĐŊĐž СадаваĐŊĐĩ ĐŊа PIN ĐēОда",
|
|
||||||
"unarchive": "РаСаŅŅ
ивиŅаК",
|
"unarchive": "РаСаŅŅ
ивиŅаК",
|
||||||
"unarchive_action_prompt": "{count} Ņа ĐŋŅĐĩĐŧаŅ
ĐŊаŅи ĐžŅ ĐŅŅ
ива",
|
|
||||||
"unarchived_count": "{count, plural, other {ĐĐĩаŅŅ
ивиŅаĐŊи #}}",
|
"unarchived_count": "{count, plural, other {ĐĐĩаŅŅ
ивиŅаĐŊи #}}",
|
||||||
"undo": "ĐŅĐŧĐĩĐŊи",
|
|
||||||
"unfavorite": "ĐŅĐĩĐŧаŅ
ваĐŊĐĩ ĐžŅ ĐģŅйиĐŧиŅĐĩ",
|
"unfavorite": "ĐŅĐĩĐŧаŅ
ваĐŊĐĩ ĐžŅ ĐģŅйиĐŧиŅĐĩ",
|
||||||
"unfavorite_action_prompt": "{count} Ņа ĐŋŅĐĩĐŧаŅ
ĐŊаŅи ĐžŅ ĐŅйиĐŧи",
|
|
||||||
"unhide_person": "ĐĐžĐēаĐļи ĐžŅĐŊОвО ŅОвĐĩĐēа",
|
"unhide_person": "ĐĐžĐēаĐļи ĐžŅĐŊОвО ŅОвĐĩĐēа",
|
||||||
"unknown": "ĐĐĩиСвĐĩŅŅĐŊĐž",
|
"unknown": "ĐĐĩиСвĐĩŅŅĐŊĐž",
|
||||||
"unknown_country": "ĐĐĩĐŋОСĐŊаŅа ĐŅŅĐļава",
|
"unknown_country": "ĐĐĩĐŋОСĐŊаŅа ĐŅŅĐļава",
|
||||||
@@ -1904,18 +1839,12 @@
|
|||||||
"unsaved_change": "ĐĐĩСаĐŋаСĐĩĐŊа ĐŋŅĐžĐŧŅĐŊа",
|
"unsaved_change": "ĐĐĩСаĐŋаСĐĩĐŊа ĐŋŅĐžĐŧŅĐŊа",
|
||||||
"unselect_all": "ĐĐĩŅĐĩĐģĐĩĐēŅиŅаКŅĐĩ вŅиŅĐēи",
|
"unselect_all": "ĐĐĩŅĐĩĐģĐĩĐēŅиŅаКŅĐĩ вŅиŅĐēи",
|
||||||
"unselect_all_duplicates": "ĐŅ ĐŧаŅĐēиŅаК вŅиŅĐēи Đ´ŅĐąĐģиĐēаŅи",
|
"unselect_all_duplicates": "ĐŅ ĐŧаŅĐēиŅаК вŅиŅĐēи Đ´ŅĐąĐģиĐēаŅи",
|
||||||
"unselect_all_in": "ĐŅĐĩĐŧаŅ
ĐŊи иСйОŅа ĐŊа вŅиŅĐēи ĐžŅ ĐŗŅŅĐŋаŅа {group}",
|
|
||||||
"unstack": "РаСĐēаŅи",
|
"unstack": "РаСĐēаŅи",
|
||||||
"unstack_action_prompt": "{count} Ņа ŅĐ°ĐˇĐŗŅŅĐŋиŅаĐŊи",
|
|
||||||
"unstacked_assets_count": "РаСĐēаŅĐĩĐŊи {count, plural, one {# ĐĩĐģĐĩĐŧĐĩĐŊŅ} other {# ĐĩĐģĐĩĐŧĐĩĐŊŅи}}",
|
"unstacked_assets_count": "РаСĐēаŅĐĩĐŊи {count, plural, one {# ĐĩĐģĐĩĐŧĐĩĐŊŅ} other {# ĐĩĐģĐĩĐŧĐĩĐŊŅи}}",
|
||||||
"untagged": "ĐĐĩĐŧаŅĐēиŅаĐŊи",
|
|
||||||
"up_next": "ĐĄĐģĐĩдваŅ",
|
"up_next": "ĐĄĐģĐĩдваŅ",
|
||||||
"updated_at": "ĐĐąĐŊОвĐĩĐŊĐž",
|
|
||||||
"updated_password": "ĐаŅĐžĐģаŅа Đĩ аĐēŅŅаĐģиСиŅаĐŊа",
|
"updated_password": "ĐаŅĐžĐģаŅа Đĩ аĐēŅŅаĐģиСиŅаĐŊа",
|
||||||
"upload": "ĐаŅваĐŊĐĩ",
|
"upload": "ĐаŅваĐŊĐĩ",
|
||||||
"upload_concurrency": "ĐŖŅĐŋĐžŅĐĩĐ´ĐŊи ĐēаŅваĐŊиŅ",
|
"upload_concurrency": "ĐŖŅĐŋĐžŅĐĩĐ´ĐŊи ĐēаŅваĐŊиŅ",
|
||||||
"upload_dialog_info": "ĐŅĐēаŅĐĩ Đģи да аŅŅ
ивиŅаŅĐĩ ĐŊа ŅŅŅвŅŅа иСйŅаĐŊиŅĐĩ ОйĐĩĐēŅи?",
|
|
||||||
"upload_dialog_title": "ĐаŅи ОйĐĩĐēŅ",
|
|
||||||
"upload_errors": "ĐаŅваĐŊĐĩŅĐž Đĩ СавŅŅĐĩĐŊĐž Ņ {count, plural, one {# ĐŗŅĐĩŅĐēа} other {# ĐŗŅĐĩŅĐēи}}, ОйĐŊОвĐĩŅĐĩ ŅŅŅаĐŊиŅаŅа Са да видиŅĐĩ ĐŊОвиŅĐĩ ĐĩĐģĐĩĐŧĐĩĐŊŅи.",
|
"upload_errors": "ĐаŅваĐŊĐĩŅĐž Đĩ СавŅŅĐĩĐŊĐž Ņ {count, plural, one {# ĐŗŅĐĩŅĐēа} other {# ĐŗŅĐĩŅĐēи}}, ОйĐŊОвĐĩŅĐĩ ŅŅŅаĐŊиŅаŅа Са да видиŅĐĩ ĐŊОвиŅĐĩ ĐĩĐģĐĩĐŧĐĩĐŊŅи.",
|
||||||
"upload_progress": "ĐŅŅĐ°Đ˛Đ°Ņ {remaining, number} - ĐĐąŅайОŅĐĩĐŊи {processed, number}/{total, number}",
|
"upload_progress": "ĐŅŅĐ°Đ˛Đ°Ņ {remaining, number} - ĐĐąŅайОŅĐĩĐŊи {processed, number}/{total, number}",
|
||||||
"upload_skipped_duplicates": "ĐŅĐĩŅĐēĐžŅĐĩĐŊи {count, plural, one {# Đ´ŅĐąĐģиŅаĐŊ ĐĩĐģĐĩĐŧĐĩĐŊŅ} other {# Đ´ŅĐąĐģиŅаĐŊи ĐĩĐģĐĩĐŧĐĩĐŊŅи}}",
|
"upload_skipped_duplicates": "ĐŅĐĩŅĐēĐžŅĐĩĐŊи {count, plural, one {# Đ´ŅĐąĐģиŅаĐŊ ĐĩĐģĐĩĐŧĐĩĐŊŅ} other {# Đ´ŅĐąĐģиŅаĐŊи ĐĩĐģĐĩĐŧĐĩĐŊŅи}}",
|
||||||
@@ -1923,22 +1852,13 @@
|
|||||||
"upload_status_errors": "ĐŅĐĩŅĐēи",
|
"upload_status_errors": "ĐŅĐĩŅĐēи",
|
||||||
"upload_status_uploaded": "ĐаŅĐĩĐŊĐž",
|
"upload_status_uploaded": "ĐаŅĐĩĐŊĐž",
|
||||||
"upload_success": "ĐаŅваĐŊĐĩŅĐž Đĩ ŅŅĐŋĐĩŅĐŊĐž, ĐžĐŋŅĐĩŅĐŊĐĩŅĐĩ ŅŅŅаĐŊиŅаŅа, Са да видиŅĐĩ ĐŊОвиŅĐĩ ŅаКĐģОвĐĩ.",
|
"upload_success": "ĐаŅваĐŊĐĩŅĐž Đĩ ŅŅĐŋĐĩŅĐŊĐž, ĐžĐŋŅĐĩŅĐŊĐĩŅĐĩ ŅŅŅаĐŊиŅаŅа, Са да видиŅĐĩ ĐŊОвиŅĐĩ ŅаКĐģОвĐĩ.",
|
||||||
"upload_to_immich": "ĐаСваĐŊĐĩ в Immich ({count})",
|
|
||||||
"uploading": "ĐаŅваĐŧĐĩ",
|
|
||||||
"url": "URL",
|
|
||||||
"usage": "ĐĐžŅŅĐĩĐąĐģĐĩĐŊиĐĩ",
|
"usage": "ĐĐžŅŅĐĩĐąĐģĐĩĐŊиĐĩ",
|
||||||
"use_biometric": "ĐСĐŋĐžĐģСваК йиОĐŧĐĩŅŅиŅ",
|
|
||||||
"use_current_connection": "иСĐŋĐžĐģСваК ŅĐĩĐēŅŅаŅа вŅŅСĐēа",
|
|
||||||
"use_custom_date_range": "ĐСĐŋĐžĐģСваКŅĐĩ ŅОйŅŅвĐĩĐŊ диаĐŋаСОĐŊ ĐžŅ Đ´Đ°Ņи вĐŧĐĩŅŅĐž ŅОва",
|
"use_custom_date_range": "ĐСĐŋĐžĐģСваКŅĐĩ ŅОйŅŅвĐĩĐŊ диаĐŋаСОĐŊ ĐžŅ Đ´Đ°Ņи вĐŧĐĩŅŅĐž ŅОва",
|
||||||
"user": "ĐĐžŅŅĐĩйиŅĐĩĐģ",
|
"user": "ĐĐžŅŅĐĩйиŅĐĩĐģ",
|
||||||
"user_has_been_deleted": "ĐĸОСи ĐŋĐžŅŅĐĩйиŅĐĩĐģ Đĩ ĐŋŅĐĩĐŧаŅ
ĐŊаŅ.",
|
|
||||||
"user_id": "ĐĐžŅŅĐĩйиŅĐĩĐģ ĐĐ",
|
"user_id": "ĐĐžŅŅĐĩйиŅĐĩĐģ ĐĐ",
|
||||||
"user_liked": "{user} Ņ
аŅĐĩŅа {type, select, photo {ŅаСи ŅĐŊиĐŧĐēа} video {ŅОва видĐĩĐž} asset {ŅОСи ĐĩĐģĐĩĐŧĐĩĐŊŅ} other {}}",
|
"user_liked": "{user} Ņ
аŅĐĩŅа {type, select, photo {ŅаСи ŅĐŊиĐŧĐēа} video {ŅОва видĐĩĐž} asset {ŅОСи ĐĩĐģĐĩĐŧĐĩĐŊŅ} other {}}",
|
||||||
"user_pin_code_settings": "PIN ĐēОд",
|
|
||||||
"user_pin_code_settings_description": "ĐŖĐŋŅавĐģŅваКŅĐĩ ĐŊаŅŅŅОКĐēиŅĐĩ ĐŊа PIN ĐēОда",
|
|
||||||
"user_privacy": "ĐОвĐĩŅиŅĐĩĐģĐŊĐžŅŅ ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģиŅĐĩ",
|
|
||||||
"user_purchase_settings": "ĐĐžĐēŅĐŋĐēа",
|
"user_purchase_settings": "ĐĐžĐēŅĐŋĐēа",
|
||||||
"user_purchase_settings_description": "ĐŖĐŋŅавĐģŅваКŅĐĩ ĐŋĐžĐēŅĐŋĐēаŅа Ņи",
|
"user_purchase_settings_description": "ĐŖĐŋŅавĐģŅваК ĐŋĐžĐēŅĐŋĐēаŅа Ņи",
|
||||||
"user_role_set": "ĐадаК {user} ĐēаŅĐž {role}",
|
"user_role_set": "ĐадаК {user} ĐēаŅĐž {role}",
|
||||||
"user_usage_detail": "ĐОдŅОйĐŊĐžŅŅи Са иСĐŋĐžĐģСваĐŊĐĩŅĐž ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģŅ",
|
"user_usage_detail": "ĐОдŅОйĐŊĐžŅŅи Са иСĐŋĐžĐģСваĐŊĐĩŅĐž ĐŊа ĐŋĐžŅŅĐĩйиŅĐĩĐģŅ",
|
||||||
"user_usage_stats": "ĐĄŅаŅиŅŅиĐēа Са иСĐŋĐžĐģСваĐŊĐĩŅĐž ĐŊа аĐēаŅĐŊŅа",
|
"user_usage_stats": "ĐĄŅаŅиŅŅиĐēа Са иСĐŋĐžĐģСваĐŊĐĩŅĐž ĐŊа аĐēаŅĐŊŅа",
|
||||||
@@ -1947,7 +1867,6 @@
|
|||||||
"users": "ĐĐžŅŅĐĩйиŅĐĩĐģи",
|
"users": "ĐĐžŅŅĐĩйиŅĐĩĐģи",
|
||||||
"utilities": "ĐĐŊŅŅŅŅĐŧĐĩĐŊŅи",
|
"utilities": "ĐĐŊŅŅŅŅĐŧĐĩĐŊŅи",
|
||||||
"validate": "ĐаĐģидиŅаĐŊĐĩ",
|
"validate": "ĐаĐģидиŅаĐŊĐĩ",
|
||||||
"validate_endpoint_error": "ĐĐžĐģŅ, вŅвĐĩди ĐŋŅавиĐģĐĩĐŊ URL",
|
|
||||||
"variables": "ĐŅĐžĐŧĐĩĐŊĐģиви",
|
"variables": "ĐŅĐžĐŧĐĩĐŊĐģиви",
|
||||||
"version": "ĐĐĩŅŅиŅ",
|
"version": "ĐĐĩŅŅиŅ",
|
||||||
"version_announcement_closing": "ĐĸвОК ĐŋŅиŅŅĐĩĐģ, ĐĐģĐĩĐēŅ",
|
"version_announcement_closing": "ĐĸвОК ĐŋŅиŅŅĐĩĐģ, ĐĐģĐĩĐēŅ",
|
||||||
@@ -1969,24 +1888,16 @@
|
|||||||
"view_name": "ĐŅĐĩĐŗĐģĐĩдаК",
|
"view_name": "ĐŅĐĩĐŗĐģĐĩдаК",
|
||||||
"view_next_asset": "ĐŅĐĩĐŗĐģĐĩĐ´ ĐŊа ŅĐģĐĩдваŅĐ¸Ņ ŅаКĐģ",
|
"view_next_asset": "ĐŅĐĩĐŗĐģĐĩĐ´ ĐŊа ŅĐģĐĩдваŅĐ¸Ņ ŅаКĐģ",
|
||||||
"view_previous_asset": "ĐŅĐĩĐŗĐģĐĩĐ´ ĐŊа ĐŋŅĐĩдиŅĐŊĐ¸Ņ ŅаКĐģ",
|
"view_previous_asset": "ĐŅĐĩĐŗĐģĐĩĐ´ ĐŊа ĐŋŅĐĩдиŅĐŊĐ¸Ņ ŅаКĐģ",
|
||||||
"view_qr_code": "ĐиĐļ QR ĐēОда",
|
|
||||||
"view_stack": "ĐĐžĐēаĐļи в ŅŅĐĩĐē",
|
"view_stack": "ĐĐžĐēаĐļи в ŅŅĐĩĐē",
|
||||||
"view_user": "ĐиĐļ ĐŋĐžŅŅĐĩйиŅĐĩĐģŅ",
|
|
||||||
"viewer_remove_from_stack": "ĐŅĐĩĐŧаŅ
ваĐŊĐĩ ĐžŅ ĐžĐŋаŅĐēаŅа",
|
|
||||||
"viewer_stack_use_as_main_asset": "ĐСĐŋĐžĐģСваК ĐēаŅĐž ĐžŅĐŊОвĐĩĐŊ",
|
|
||||||
"viewer_unstack": "ĐŅĐĩĐŧаŅ
ĐŊи ĐžŅ ĐžĐŋаŅĐēаŅа",
|
|
||||||
"visibility_changed": "ĐидиĐŧĐžŅŅŅа Đĩ ĐŋŅĐžĐŧĐĩĐŊĐĩĐŊа Са {count, plural, one {# ŅОвĐĩĐē} other {# ŅОвĐĩĐēа}}",
|
"visibility_changed": "ĐидиĐŧĐžŅŅŅа Đĩ ĐŋŅĐžĐŧĐĩĐŊĐĩĐŊа Са {count, plural, one {# ŅОвĐĩĐē} other {# ŅОвĐĩĐēа}}",
|
||||||
"waiting": "в иСŅаĐēваĐŊĐĩ",
|
"waiting": "в иСŅаĐēваĐŊĐĩ",
|
||||||
"warning": "ĐĐŊиĐŧаĐŊиĐĩ",
|
"warning": "ĐĐŊиĐŧаĐŊиĐĩ",
|
||||||
"week": "ĐĄĐĩĐ´ĐŧиŅа",
|
"week": "ĐĄĐĩĐ´ĐŧиŅа",
|
||||||
"welcome": "ĐОйŅĐĩ Đ´ĐžŅĐģи",
|
"welcome": "ĐОйŅĐĩ Đ´ĐžŅĐģи",
|
||||||
"welcome_to_immich": "ĐОйŅĐĩ Đ´ĐžŅĐģи в Immich",
|
"welcome_to_immich": "ĐОйŅĐĩ Đ´ĐžŅĐģи в Immich",
|
||||||
"wifi_name": "Wi-Fi ĐŧŅĐĩĐļа",
|
|
||||||
"wrong_pin_code": "ĐŅĐĩŅĐĩĐŊ PIN ĐēОд",
|
|
||||||
"year": "ĐОдиĐŊа",
|
"year": "ĐОдиĐŊа",
|
||||||
"years_ago": "ĐŋŅĐĩди {years, plural, one {# ĐŗĐžĐ´Đ¸ĐŊа} other {# ĐŗĐžĐ´Đ¸ĐŊи}}",
|
"years_ago": "ĐŋŅĐĩди {years, plural, one {# ĐŗĐžĐ´Đ¸ĐŊа} other {# ĐŗĐžĐ´Đ¸ĐŊи}}",
|
||||||
"yes": "Đа",
|
"yes": "Đа",
|
||||||
"you_dont_have_any_shared_links": "ĐŅĐŧаŅĐĩ ŅĐŋОдĐĩĐģĐĩĐŊи вŅŅСĐēи",
|
"you_dont_have_any_shared_links": "ĐŅĐŧаŅĐĩ ŅĐŋОдĐĩĐģĐĩĐŊи вŅŅСĐēи",
|
||||||
"your_wifi_name": "ĐаŅаŅа Wi-Fi ĐŧŅĐĩĐļа",
|
|
||||||
"zoom_image": "ĐŖĐ˛ĐĩĐģиŅаваĐŊĐĩ ĐŊа иСОйŅаĐļĐĩĐŊиĐĩŅĐž"
|
"zoom_image": "ĐŖĐ˛ĐĩĐģиŅаваĐŊĐĩ ĐŊа иСОйŅаĐļĐĩĐŊиĐĩŅĐž"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-83
@@ -8,92 +8,10 @@
|
|||||||
"actions": "āĻāϰā§āĻŽ",
|
"actions": "āĻāϰā§āĻŽ",
|
||||||
"active": "āϏāĻāϞ",
|
"active": "āϏāĻāϞ",
|
||||||
"activity": "āĻāĻžāϰā§āϝāĻāϞāĻžāĻĒ",
|
"activity": "āĻāĻžāϰā§āϝāĻāϞāĻžāĻĒ",
|
||||||
"activity_changed": "āĻāĻāĻāĻŋāĻāĻŋāĻāĻŋ āĻāĻāύ {enabled, select, true {āĻāĻžāϞā§} other {āĻŦāύā§āϧ}} āĻāĻā§",
|
|
||||||
"add": "āϝā§āĻ āĻāϰā§āύ",
|
"add": "āϝā§āĻ āĻāϰā§āύ",
|
||||||
"add_a_description": "āĻāĻāĻāĻŋ āĻŦāĻŋāĻŦāϰāĻŖ āϝā§āĻ āĻāϰā§āύ",
|
"add_a_description": "āĻāĻāĻāĻŋ āĻŦāĻŋāĻŦāϰāĻŖ āϝā§āĻ āĻāϰā§āύ",
|
||||||
"add_a_location": "āĻāĻāĻāĻŋ āĻ
āĻŦāϏā§āĻĨāĻžāύ āϝā§āĻ āĻāϰā§āύ",
|
"add_a_location": "āĻāĻāĻāĻŋ āĻ
āĻŦāϏā§āĻĨāĻžāύ āϝā§āĻ āĻāϰā§āύ",
|
||||||
"add_a_name": "āĻāĻāĻāĻŋ āύāĻžāĻŽ āϝā§āĻ āĻāϰā§āύ",
|
"add_a_name": "āĻāĻāĻāĻŋ āύāĻžāĻŽ āϝā§āĻ āĻāϰā§āύ",
|
||||||
"add_a_title": "āĻāĻāĻāĻŋ āĻļāĻŋāϰā§āύāĻžāĻŽ āϝā§āĻ āĻāϰā§āύ",
|
"add_a_title": "āĻāĻāĻāĻŋ āĻļāĻŋāϰā§āύāĻžāĻŽ āϝā§āĻ āĻāϰā§āύ",
|
||||||
"add_endpoint": "āĻāύā§āĻĄāĻĒāϝāĻŧā§āύā§āĻ āϝā§āĻ āĻāϰā§āύ",
|
"add_endpoint": "āĻāύā§āĻĄāĻĒāϝāĻŧā§āύā§āĻ āϝā§āĻ āĻāϰā§āύ"
|
||||||
"add_exclusion_pattern": "āĻŦāĻšāĻŋāϰā§āĻā§āϤāĻāϰāĻŖ āύāĻŽā§āύāĻž",
|
|
||||||
"add_import_path": "āĻāĻŽāĻĒā§āϰā§āĻ āĻāϰāĻžāϰ āĻĒāĻžāĻĨ āϝā§āĻā§āϤ āĻāϰā§āύ",
|
|
||||||
"add_location": "āĻ
āĻŦāϏā§āĻĨāĻžāύ āϝā§āĻā§āϤ āĻāϰā§āύ",
|
|
||||||
"add_more_users": "āĻāϰ⧠āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āϝā§āĻā§āϤ āĻāϰā§āύ",
|
|
||||||
"add_partner": "āĻ
āĻāĻļā§āĻĻāĻžāϰ āϝā§āĻ āĻāϰā§āύ",
|
|
||||||
"add_path": "āĻĒāĻžāĻĨ āϝā§āĻā§āϤ āĻāϰā§āύ",
|
|
||||||
"add_photos": "āĻāĻŦāĻŋ āϝā§āĻā§āϤ āĻāϰā§āύ",
|
|
||||||
"add_tag": "āĻā§āϝāĻžāĻ āϝā§āĻā§āϤ āĻāϰā§āύ",
|
|
||||||
"add_to": "āϝā§āĻā§āϤ āĻāϰā§āύâĻ",
|
|
||||||
"add_to_album": "āĻāϞāĻŦāĻžāĻŽ āĻ āϝā§āĻ āĻāϰā§āύ",
|
|
||||||
"add_to_album_bottom_sheet_added": "{album} āĻ āϝā§āĻ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§",
|
|
||||||
"add_to_album_bottom_sheet_already_exists": "{album} āĻ āĻāĻā§ āĻĨā§āĻā§āĻ āĻāĻā§",
|
|
||||||
"add_to_shared_album": "āĻļā§āϝāĻŧāĻžāϰ āĻāϰāĻž āĻ
ā§āϝāĻžāϞāĻŦāĻžāĻŽā§ āϝā§āĻ āĻāϰā§āύ",
|
|
||||||
"add_url": "āϞāĻŋāĻā§āĻ āϝā§āĻ āĻāϰā§āύ",
|
|
||||||
"added_to_archive": "āĻāϰā§āĻāĻžāĻāĻ āĻ āϝā§āĻ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§",
|
|
||||||
"added_to_favorites": "āĻĢā§āĻāĻžāϰāĻŋāĻā§ āϝā§āĻ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§",
|
|
||||||
"added_to_favorites_count": "āĻĒāĻāύā§āĻĻā§āϰ āϤāĻžāϞāĻŋāĻāĻžā§ {count, number} āϝā§āĻ āĻāϰāĻž āĻšā§ā§āĻā§",
|
|
||||||
"admin": {
|
|
||||||
"add_exclusion_pattern_description": "āĻāĻā§āϏāĻā§āϞā§āĻļāύ āĻĒā§āϝāĻžāĻāĻžāϰā§āύ āϝā§āĻ āĻāϰā§āύāĨ¤ *, **, āĻāĻŦāĻ ? āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠āĻā§āϞā§āĻŦāĻŋāĻ āĻāϰāĻž āϏāĻŽā§āĻāĻŦāĨ¤ \"Raw\" āύāĻžāĻŽā§āϰ āϝā§āĻā§āύ⧠āĻĄāĻŋāϰā§āĻā§āĻāϰāĻŋāϤ⧠āĻĨāĻžāĻāĻž āϏāĻŽāϏā§āϤ āĻĢāĻžāĻāϞ āĻŦāĻžāĻĻ āĻĻāĻŋāϤ⧠\"**/Raw/**\" āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤ \".tif\" āĻĻāĻŋāϝāĻŧā§ āĻļā§āώ āĻšāĻāϝāĻŧāĻž āϏāĻŽāϏā§āϤ āĻĢāĻžāĻāϞ āĻŦāĻžāĻĻ āĻĻāĻŋāϤ⧠\"**/*.tif\" āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤ āĻāĻāĻāĻŋ āϏāĻŽā§āĻĒā§āϰā§āĻŖ āĻĒāĻžāĻĨ āĻŦāĻžāĻĻ āĻĻāĻŋāϤā§, \"/path/to/ignore/**\" āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤",
|
|
||||||
"admin_user": "āĻāĻĄāĻŽāĻŋāύ āĻāĻāĻāĻžāϰ",
|
|
||||||
"asset_offline_description": "āĻāĻ āĻŦāĻšāĻŋāϰāĻžāĻāϤ āϞāĻžāĻāĻŦā§āϰā§āϰāĻŋ āϏāĻŽā§āĻĒāĻĻāĻāĻŋ āĻāϰ āĻĄāĻŋāϏā§āĻā§ āĻĒāĻžāĻāϝāĻŧāĻž āϝāĻžāĻā§āĻā§ āύāĻž āĻāĻŦāĻ āĻā§āϰā§āϝāĻžāĻļā§ āϏāϰāĻžāύ⧠āĻšāϝāĻŧā§āĻā§āĨ¤ āϝāĻĻāĻŋ āĻĢāĻžāĻāϞāĻāĻŋ āϞāĻžāĻāĻŦā§āϰā§āϰāĻŋāϰ āĻŽāϧā§āϝ⧠āϏāϰāĻžāύ⧠āĻšāϝāĻŧā§ āĻĨāĻžāĻā§, āϤāĻžāĻšāϞ⧠āύāϤā§āύ āϏāĻāĻļā§āϞāĻŋāώā§āĻ āϏāĻŽā§āĻĒāĻĻā§āϰ āĻāύā§āϝ āĻāĻĒāύāĻžāϰ āĻāĻžāĻāĻŽāϞāĻžāĻāύ āĻĒāϰā§āĻā§āώāĻž āĻāϰā§āύāĨ¤ āĻāĻ āϏāĻŽā§āĻĒāĻĻāĻāĻŋ āĻĒā§āύāϰā§āĻĻā§āϧāĻžāϰ āĻāϰāϤā§, āĻĻāϝāĻŧāĻž āĻāϰ⧠āύāĻŋāĻļā§āĻāĻŋāϤ āĻāϰā§āύ āϝ⧠āύā§āĻā§āϰ āĻĢāĻžāĻāϞ āĻĒāĻžāĻĨāĻāĻŋ Immich āĻĻā§āĻŦāĻžāϰāĻž āĻ
ā§āϝāĻžāĻā§āϏā§āϏ āĻāϰāĻž āϝā§āϤ⧠āĻĒāĻžāϰ⧠āĻāĻŦāĻ āϞāĻžāĻāĻŦā§āϰā§āϰāĻŋāĻāĻŋ āϏā§āĻā§āϝāĻžāύ āĻāϰā§āύāĨ¤",
|
|
||||||
"authentication_settings": "āĻĒā§āϰāĻŽāĻžāĻŖā§āĻāϰāĻŖ āϏā§āĻāĻŋāĻāϏ",
|
|
||||||
"authentication_settings_description": "āĻĒāĻžāϏāĻāϝāĻŧāĻžāϰā§āĻĄ, OAuth āĻāĻŦāĻ āĻ
āύā§āϝāĻžāύā§āϝ āĻĒā§āϰāĻŽāĻžāĻŖā§āĻāϰāĻŖ āϏā§āĻāĻŋāĻāϏ āĻĒāϰāĻŋāĻāĻžāϞāύāĻž āĻāϰā§āύ",
|
|
||||||
"authentication_settings_disable_all": "āĻāĻĒāύāĻŋ āĻāĻŋ āύāĻŋāĻļā§āĻāĻŋāϤ āϝ⧠āĻāĻĒāύāĻŋ āϏāĻŽāϏā§āϤ āϞāĻāĻāύ āĻĒāĻĻā§āϧāϤāĻŋ āĻ
āĻā§āώāĻŽ āĻāϰāϤ⧠āĻāĻžāύ? āϞāĻāĻāύ āϏāĻŽā§āĻĒā§āϰā§āĻŖāϰā§āĻĒā§ āĻ
āĻā§āώāĻŽ āĻāϰāĻž āĻšāĻŦā§āĨ¤",
|
|
||||||
"authentication_settings_reenable": "āĻĒā§āύāϰāĻžāϝāĻŧ āϏāĻā§āώāĻŽ āĻāϰāϤā§, āĻāĻāĻāĻŋ <link>āϏāĻžāϰā§āĻāĻžāϰ āĻāĻŽāĻžāύā§āĻĄ</link> āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤",
|
|
||||||
"background_task_job": "āĻŦā§āϝāĻžāĻāĻā§āϰāĻžāĻāύā§āĻĄ āĻāĻžāϏā§āĻ",
|
|
||||||
"backup_database": "āĻĄāĻžāĻāĻžāĻŦā§āϏ āĻĄāĻžāĻŽā§āĻĒ āϤā§āϰāĻŋ āĻāϰā§āύ",
|
|
||||||
"backup_database_enable_description": "āĻĄāĻžāĻāĻžāĻŦā§āϏ āĻĄāĻžāĻŽā§āĻĒ āϏāĻā§āϰāĻŋāϝāĻŧ āĻāϰā§āύ",
|
|
||||||
"backup_keep_last_amount": "āĻāĻā§āϰ āĻĄāĻžāĻŽā§āĻĒā§āϰ āĻĒāϰāĻŋāĻŽāĻžāĻŖ āϰāĻžāĻāĻž āĻšāĻŦā§",
|
|
||||||
"backup_settings": "āĻĄāĻžāĻāĻžāĻŦā§āϏ āĻĄāĻžāĻŽā§āĻĒ āϏā§āĻāĻŋāĻāϏ",
|
|
||||||
"backup_settings_description": "āĻĄāĻžāĻāĻžāĻŦā§āϏ āĻĄāĻžāĻŽā§āĻĒ āϏā§āĻāĻŋāĻāϏ āĻĒāϰāĻŋāĻāĻžāϞāύāĻž āĻāϰā§āύāĨ¤",
|
|
||||||
"cleared_jobs": "{job} āĻāϰ āĻāύā§āϝ jobs āĻāĻžāϞāĻŋ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§",
|
|
||||||
"config_set_by_file": "āĻāύāĻĢāĻŋāĻ āĻŦāϰā§āϤāĻŽāĻžāύ⧠āĻāĻāĻāĻŋ āĻāύāĻĢāĻŋāĻ āĻĢāĻžāĻāϞ āĻĻā§āĻŦāĻžāϰāĻž āϏā§āĻ āĻāϰāĻž āĻāĻā§",
|
|
||||||
"confirm_delete_library": "āĻāĻĒāύāĻŋ āĻāĻŋ āύāĻŋāĻļā§āĻāĻŋāϤ āϝ⧠āĻāĻĒāύāĻŋ {library} āϞāĻžāĻāĻŦā§āϰā§āϰāĻŋ āĻŽā§āĻā§ āĻĢā§āϞāϤ⧠āĻāĻžāύ?",
|
|
||||||
"confirm_delete_library_assets": "āĻāĻĒāύāĻŋ āĻāĻŋ āύāĻŋāĻļā§āĻāĻŋāϤ āϝ⧠āĻāĻĒāύāĻŋ āĻāĻ āϞāĻžāĻāĻŦā§āϰā§āϰāĻŋāĻāĻŋ āĻŽā§āĻā§ āĻĢā§āϞāϤ⧠āĻāĻžāύ? āĻāĻāĻŋ Immich āĻĨā§āĻā§ {count, plural, one {# contained asset} other {all # contained asset}} āĻŽā§āĻā§ āĻĢā§āϞāĻŦā§ āĻāĻŦāĻ āĻĒā§āϰā§āĻŦāĻžāĻŦāϏā§āĻĨāĻžāϝāĻŧ āĻĢā§āϰāĻžāύ⧠āϝāĻžāĻŦā§ āύāĻžāĨ¤ āĻĢāĻžāĻāϞāĻā§āϞāĻŋ āĻĄāĻŋāϏā§āĻā§ āĻĨāĻžāĻāĻŦā§āĨ¤",
|
|
||||||
"confirm_email_below": "āύāĻŋāĻļā§āĻāĻŋāϤ āĻāϰāϤā§, āύāĻŋāĻā§ \"{email}\" āĻāĻžāĻāĻĒ āĻāϰā§āύ",
|
|
||||||
"confirm_reprocess_all_faces": "āĻāĻĒāύāĻŋ āĻāĻŋ āύāĻŋāĻļā§āĻāĻŋāϤ āϝ⧠āĻāĻĒāύāĻŋ āϏāĻŽāϏā§āϤ āĻŽā§āĻ āĻĒā§āύāϰāĻžāϝāĻŧ āĻĒā§āϰāĻā§āϰāĻŋāϝāĻŧāĻž āĻāϰāϤ⧠āĻāĻžāύ? āĻāĻāĻŋ āύāĻžāĻŽāϝā§āĻā§āϤ āĻŦā§āϝāĻā§āϤāĻŋāĻĻā§āϰāĻ āĻŽā§āĻā§ āĻĢā§āϞāĻŦā§āĨ¤",
|
|
||||||
"confirm_user_password_reset": "āĻāĻĒāύāĻŋ āĻāĻŋ āύāĻŋāĻļā§āĻāĻŋāϤ āϝ⧠āĻāĻĒāύāĻŋ {user} āĻāϰ āĻĒāĻžāϏāĻāϝāĻŧāĻžāϰā§āĻĄ āϰāĻŋāϏā§āĻ āĻāϰāϤ⧠āĻāĻžāύ?",
|
|
||||||
"confirm_user_pin_code_reset": "āĻāĻĒāύāĻŋ āĻāĻŋ āύāĻŋāĻļā§āĻāĻŋāϤ āϝ⧠āĻāĻĒāύāĻŋ {user} āĻāϰ āĻĒāĻŋāύ āĻā§āĻĄ āϰāĻŋāϏā§āĻ āĻāϰāϤ⧠āĻāĻžāύ?",
|
|
||||||
"create_job": "job āϤā§āϰāĻŋ āĻāϰā§āύ",
|
|
||||||
"cron_expression": "āĻā§āϰā§āύ āĻāĻā§āϏāĻĒā§āϰā§āĻļāύ",
|
|
||||||
"cron_expression_description": "āĻā§āϰā§āύ āĻĢāϰā§āĻŽā§āϝāĻžāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠āϏā§āĻā§āϝāĻžāύāĻŋāĻ āĻŦā§āϝāĻŦāϧāĻžāύ āϏā§āĻ āĻāϰā§āύāĨ¤ āĻāϰāĻ āϤāĻĨā§āϝā§āϰ āĻāύā§āϝ āĻĻāϝāĻŧāĻž āĻāϰ⧠āĻĻā§āĻā§āύ āϝā§āĻŽāύ <link>Crontab Guru</link>",
|
|
||||||
"cron_expression_presets": "āĻā§āϰā§āύ āĻāĻā§āϏāĻĒā§āϰā§āĻļāύ āĻĒā§āϰāĻŋāϏā§āĻ",
|
|
||||||
"disable_login": "āϞāĻāĻāύ āĻ
āĻā§āώāĻŽ āĻāϰā§āύ",
|
|
||||||
"duplicate_detection_job_description": "āĻ
āύā§āϰā§āĻĒ āĻāĻŦāĻŋ āϏāύāĻžāĻā§āϤ āĻāϰāϤ⧠āϏāĻŽā§āĻĒāĻĻāĻā§āϞāĻŋāϤ⧠āĻŽā§āĻļāĻŋāύ āϞāĻžāϰā§āύāĻŋāĻ āĻāĻžāϞāĻžāύāĨ¤ āϏā§āĻŽāĻžāϰā§āĻ āĻ
āύā§āϏāύā§āϧāĻžāύā§āϰ āĻāĻĒāϰ āύāĻŋāϰā§āĻāϰ āĻāϰā§",
|
|
||||||
"exclusion_pattern_description": "āĻāĻā§āϏāĻā§āϞā§āĻļāύ āĻĒā§āϝāĻžāĻāĻžāϰā§āύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠āĻāĻĒāύāĻŋ āĻāĻĒāύāĻžāϰ āϞāĻžāĻāĻŦā§āϰā§āϰāĻŋ āϏā§āĻā§āϝāĻžāύ āĻāϰāĻžāϰ āϏāĻŽāϝāĻŧ āĻĢāĻžāĻāϞ āĻāĻŦāĻ āĻĢā§āϞā§āĻĄāĻžāϰāĻā§āϞāĻŋāĻā§ āĻāĻĒā§āĻā§āώāĻž āĻāϰāϤ⧠āĻĒāĻžāϰāĻŦā§āύāĨ¤ āϝāĻĻāĻŋ āĻāĻĒāύāĻžāϰ āĻāĻŽāύ āĻĢā§āϞā§āĻĄāĻžāϰ āĻĨāĻžāĻā§ āϝā§āĻāĻžāύ⧠āĻāĻŽāύ āĻĢāĻžāĻāϞ āĻĨāĻžāĻā§ āϝāĻž āĻāĻĒāύāĻŋ āĻāĻŽāĻĻāĻžāύāĻŋ āĻāϰāϤ⧠āĻāĻžāύ āύāĻž, āϝā§āĻŽāύ RAW āĻĢāĻžāĻāϞāĨ¤",
|
|
||||||
"external_library_management": "āĻŦāĻšāĻŋāϰāĻžāĻāϤ āĻā§āϰāύā§āĻĨāĻžāĻāĻžāϰ āĻŦā§āϝāĻŦāϏā§āĻĨāĻžāĻĒāύāĻž",
|
|
||||||
"face_detection": "āĻŽā§āĻ āϏāύāĻžāĻā§āϤāĻāϰāĻŖ",
|
|
||||||
"face_detection_description": "āĻŽā§āĻļāĻŋāύ āϞāĻžāϰā§āύāĻŋāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠āĻ
ā§āϝāĻžāϏā§āĻā§ āĻĨāĻžāĻāĻž āĻŽā§āĻ/āĻā§āĻšāĻžāϰāĻž āĻā§āϞāĻŋ āϏāύāĻžāĻā§āϤ āĻāϰā§āύāĨ¤ āĻāĻŋāĻĄāĻŋāĻ āĻā§āϞāĻŋāϰ āĻāύā§āϝ, āĻļā§āϧā§āĻŽāĻžāϤā§āϰ āĻĨāĻžāĻŽā§āĻŦāύā§āĻāϞ āĻŦāĻŋāĻŦā§āĻāύāĻž āĻāϰāĻž āĻšāϝāĻŧāĨ¤ \"āϰāĻŋāĻĢā§āϰā§āĻļ\" (āĻĒā§āύāϰāĻžāϝāĻŧ) āϏāĻŽāϏā§āϤ āĻ
ā§āϝāĻžāϏā§āĻ āĻĒā§āϰāĻā§āϰāĻŋāϝāĻŧāĻž āĻāϰā§āĨ¤ \"āϰāĻŋāϏā§āĻ\" āĻāϰāĻžāϰ āĻŽāĻžāϧā§āϝāĻŽā§ āĻ
āϤāĻŋāϰāĻŋāĻā§āϤāĻāĻžāĻŦā§ āϏāĻŽāϏā§āϤ āĻŦāϰā§āϤāĻŽāĻžāύ āĻŽā§āĻā§āϰ āĻĄā§āĻāĻž āϏāĻžāĻĢ āĻāϰā§āĨ¤ \"āĻ
āύā§āĻĒāϏā§āĻĨāĻŋāϤ\" āĻ
ā§āϝāĻžāϏā§āĻāĻā§āϞāĻŋāĻā§ āϏāĻžāϰāĻŋāĻŦāĻĻā§āϧ āĻāϰ⧠āϝāĻž āĻāĻāύāĻ āĻĒā§āϰāĻā§āϰāĻŋāϝāĻŧāĻž āĻāϰāĻž āĻšāϝāĻŧāύāĻŋāĨ¤ āϏāύāĻžāĻā§āϤ āĻāϰāĻž āĻŽā§āĻāĻā§āϞāĻŋāĻā§ āĻĢā§āϏāĻŋāϝāĻŧāĻžāϞ āϰāĻŋāĻāĻāύāĻŋāĻļāύā§āϰ āĻāύā§āϝ āϏāĻžāϰāĻŋāĻŦāĻĻā§āϧ āĻāϰāĻž āĻšāĻŦā§, āĻĢā§āϏāĻŋāϝāĻŧāĻžāϞ āĻĄāĻŋāĻā§āĻāĻļāύ āϏāĻŽā§āĻĒā§āϰā§āĻŖ āĻšāĻāϝāĻŧāĻžāϰ āĻĒāϰā§, āĻŦāĻŋāĻĻā§āϝāĻŽāĻžāύ āĻŦāĻž āύāϤā§āύ āĻŦā§āϝāĻā§āϤāĻŋāĻĻā§āϰ āĻŽāϧā§āϝ⧠āĻā§āώā§āĻ ā§āĻŦāĻĻā§āϧ āĻāϰā§āĨ¤",
|
|
||||||
"facial_recognition_job_description": "āĻļāύāĻžāĻā§āϤ āĻāϰāĻž āĻŽā§āĻāĻā§āϞāĻŋāĻā§ āĻŽāĻžāύā§āώā§āϰ āĻŽāϧā§āϝ⧠āĻā§āώā§āĻ ā§āĻā§āĻā§āϤ āĻāϰā§āύāĨ¤ āĻŽā§āĻ āϏāύāĻžāĻā§āϤāĻāϰāĻŖ āϏāĻŽā§āĻĒā§āϰā§āĻŖ āĻšāĻāϝāĻŧāĻžāϰ āĻĒāϰ⧠āĻāĻ āϧāĻžāĻĒāĻāĻŋ āĻāϞā§āĨ¤ \"āϰāĻŋāϏā§āĻ\" (āĻĒā§āύāϰāĻžāϝāĻŧ) āϏāĻŽāϏā§āϤ āĻŽā§āĻāĻā§ āĻā§āϞāĻžāϏā§āĻāĻžāϰ āĻāϰā§āĨ¤ \"āĻ
āύā§āĻĒāϏā§āĻĨāĻŋāϤ\" āĻŽā§āĻāĻā§āϞāĻŋāĻā§ āϏāĻžāϰāĻŋāϤ⧠āϰāĻžāĻā§ āϝā§āĻāĻžāύ⧠āĻā§āύāĻ āĻŦā§āϝāĻā§āϤāĻŋāĻā§ āĻŦāϰāĻžāĻĻā§āĻĻ āĻāϰāĻž āĻšāϝāĻŧāύāĻŋāĨ¤",
|
|
||||||
"failed_job_command": "āĻāĻŽāĻžāύā§āĻĄ {command} āĻāĻžāĻā§āϰ āĻāύā§āϝ āĻŦā§āϝāϰā§āĻĨ āĻšāϝāĻŧā§āĻā§: {job}",
|
|
||||||
"force_delete_user_warning": "āϏāϤāϰā§āĻāϤāĻž: āĻāĻāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āĻāĻŦāĻ āϏāĻŽāϏā§āϤ āϏāĻŽā§āĻĒāĻĻ āĻ
āĻŦāĻŋāϞāĻŽā§āĻŦā§ āϏāϰāĻŋāϝāĻŧā§ āĻĢā§āϞāĻŦā§āĨ¤ āĻāĻāĻŋ āĻĒā§āϰā§āĻŦāĻžāĻŦāϏā§āĻĨāĻžāϝāĻŧ āĻĢā§āϰāĻžāύ⧠āϝāĻžāĻŦā§ āύāĻž āĻāĻŦāĻ āĻĢāĻžāĻāϞāĻā§āϞāĻŋ āĻĒā§āύāϰā§āĻĻā§āϧāĻžāϰ āĻāϰāĻž āϝāĻžāĻŦā§ āύāĻžāĨ¤",
|
|
||||||
"image_format": "āĻĢāϰāĻŽā§āϝāĻžāĻ",
|
|
||||||
"image_format_description": "WebP JPEG āĻāϰ āϤā§āϞāύāĻžā§ āĻā§āĻ āĻĢāĻžāĻāϞ āϤā§āϰāĻŋ āĻāϰā§, āĻāĻŋāύā§āϤ⧠āĻāύāĻā§āĻĄ āĻāϰāϤ⧠āϧā§āϰāĨ¤",
|
|
||||||
"image_fullsize_description": "āĻā§āĻŽ āĻāύ āĻāϰāĻžāϰ āϏāĻŽāϝāĻŧ āĻŦā§āϝāĻŦāĻšā§āϤ āϏā§āĻā§āϰāĻŋāĻĒāĻĄ āĻŽā§āĻāĻžāĻĄā§āĻāĻž āϏāĻš āĻĒā§āϰā§āĻŖ āĻāĻāĻžāϰā§āϰ āĻāĻŦāĻŋ",
|
|
||||||
"image_fullsize_enabled": "āĻĒā§āϰā§āĻŖ-āĻāĻāĻžāϰā§āϰ āĻāĻŦāĻŋ āϤā§āϰāĻŋ āϏāĻā§āώāĻŽ āĻāϰā§āύ",
|
|
||||||
"image_fullsize_enabled_description": "āĻāϝāĻŧā§āĻŦ-āĻŦāĻžāύā§āϧāĻŦ āύāϝāĻŧ āĻāĻŽāύ āĻĢāϰā§āĻŽā§āϝāĻžāĻā§āϰ āĻāύā§āϝ āĻĒā§āϰā§āĻŖ-āĻāĻāĻžāϰā§āϰ āĻāĻŦāĻŋ āϤā§āϰāĻŋ āĻāϰā§āύāĨ¤ \"āĻāĻŽāĻŦā§āĻĄā§āĻĄ āĻĒā§āϰāĻŋāĻāĻŋāĻ āĻĒāĻāύā§āĻĻ āĻāϰā§āύ\" āϏāĻā§āώāĻŽ āĻāϰāĻž āĻĨāĻžāĻāϞā§, āϰā§āĻĒāĻžāύā§āϤāϰ āĻāĻžāĻĄāĻŧāĻžāĻ āĻāĻŽāĻŦā§āĻĄā§āĻĄ āĻĒā§āϰāĻŋāĻāĻŋāĻ āϏāϰāĻžāϏāϰāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻž āĻšāϝāĻŧāĨ¤ JPEG-āĻāϰ āĻŽāϤ⧠āĻāϝāĻŧā§āĻŦ-āĻŦāĻžāύā§āϧāĻŦ āĻĢāϰā§āĻŽā§āϝāĻžāĻāĻā§āϞāĻŋāĻā§ āĻĒā§āϰāĻāĻžāĻŦāĻŋāϤ āĻāϰ⧠āύāĻžāĨ¤",
|
|
||||||
"image_fullsize_quality_description": "āĻĒā§āϰā§āĻŖ-āĻāĻāĻžāϰā§āϰ āĻāĻŦāĻŋāϰ āĻŽāĻžāύ ā§§-ā§§ā§Ļā§ĻāĨ¤ āĻāĻā§āĻāϤāϰ āĻšāϞ⧠āĻāĻžāϞā§, āĻāĻŋāύā§āϤ⧠āĻāϰāĻ āĻŦāĻĄāĻŧ āĻĢāĻžāĻāϞ āϤā§āϰāĻŋ āĻšāϝāĻŧāĨ¤",
|
|
||||||
"image_fullsize_title": "āĻĒā§āϰā§āĻŖ-āĻāĻāĻžāϰā§āϰ āĻāĻŋāϤā§āϰ āϏā§āĻāĻŋāĻāϏ",
|
|
||||||
"image_prefer_embedded_preview": "āĻāĻŽā§āĻŦā§āĻĄ āĻāϰāĻž āĻĒā§āϰāĻŋāĻāĻŋāĻ āĻĒāĻāύā§āĻĻ āĻāϰā§āύ",
|
|
||||||
"image_prefer_embedded_preview_setting_description": "āĻāĻŦāĻŋ āĻĒā§āϰāĻā§āϰāĻŋāϝāĻŧāĻžāĻāϰāĻŖā§āϰ āĻāύā§āϝ āĻāĻŦāĻ āϝāĻāύāĻ āĻāĻĒāϞāĻŦā§āϧ āĻĨāĻžāĻāĻŦā§ āϤāĻāύ RAW āĻĢāĻā§āϤ⧠āĻāĻŽāĻŦā§āĻĄā§āĻĄ āĻĒā§āϰāĻŋāĻāĻŋāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤ āĻāĻāĻŋ āĻāĻŋāĻā§ āĻāĻŦāĻŋāϰ āĻāύā§āϝ āĻāϰāĻ āϏāĻ āĻŋāĻ āϰāĻ āϤā§āϰāĻŋ āĻāϰāϤ⧠āĻĒāĻžāϰā§, āϤāĻŦā§ āĻĒā§āϰāĻŋāĻāĻŋāĻāϝāĻŧā§āϰ āĻŽāĻžāύ āĻā§āϝāĻžāĻŽā§āϰāĻž-āύāĻŋāϰā§āĻāϰ āĻāĻŦāĻ āĻāĻŦāĻŋāϤ⧠āĻāϰāĻ āĻāĻŽā§āĻĒā§āϰā§āĻļāύ āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ āĻĨāĻžāĻāϤ⧠āĻĒāĻžāϰā§āĨ¤",
|
|
||||||
"image_prefer_wide_gamut": "āĻĒā§āϰāĻļāϏā§āϤ āĻĒāϰāĻŋāϏāϰ āĻĒāĻāύā§āĻĻ āĻāϰā§āύ",
|
|
||||||
"image_prefer_wide_gamut_setting_description": "āĻĨāĻžāĻŽā§āĻŦāύā§āĻāϞā§āϰ āĻāύā§āϝ āĻĄāĻŋāϏāĻĒā§āϞ⧠P3 āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤ āĻāĻāĻŋ āĻĒā§āϰāĻļāϏā§āϤ āϰāĻā§āϰ āϏā§āĻĨāĻžāύ āϏāĻš āĻāĻŦāĻŋāϰ āĻĒā§āϰāĻžāĻŖāĻŦāύā§āϤāϤāĻž āĻāϰāĻ āĻāĻžāϞāĻāĻžāĻŦā§ āϏāĻāϰāĻā§āώāĻŖ āĻāϰā§, āϤāĻŦā§ āĻĒā§āϰāĻžāύ⧠āĻŦā§āϰāĻžāĻāĻāĻžāϰ āϏāĻāϏā§āĻāϰāĻŖ āϏāĻš āĻĒā§āϰāĻžāύ⧠āĻĄāĻŋāĻāĻžāĻāϏāĻā§āϞāĻŋāϤ⧠āĻāĻŦāĻŋāĻā§āϞāĻŋ āĻāĻŋāύā§āύāĻāĻžāĻŦā§ āĻĒā§āϰāĻĻāϰā§āĻļāĻŋāϤ āĻšāϤ⧠āĻĒāĻžāϰā§āĨ¤ āϰāĻā§āϰ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāĻĄāĻŧāĻžāϤ⧠sRGB āĻāĻŦāĻŋāĻā§āϞāĻŋāĻā§ sRGB āĻšāĻŋāϏāĻžāĻŦā§ āϰāĻžāĻāĻž āĻšāϝāĻŧāĨ¤",
|
|
||||||
"image_preview_description": "āϏā§āĻā§āϰāĻŋāĻĒāĻĄ āĻŽā§āĻāĻžāĻĄā§āĻāĻž āϏāĻš āĻŽāĻžāĻāĻžāϰāĻŋ āĻāĻāĻžāϰā§āϰ āĻāĻŦāĻŋ, āĻāĻāĻāĻŋ āĻāĻāĻ āϏāĻŽā§āĻĒāĻĻ āĻĻā§āĻāĻžāϰ āϏāĻŽāϝāĻŧ āĻāĻŦāĻ āĻŽā§āĻļāĻŋāύ āϞāĻžāϰā§āύāĻŋāĻāϝāĻŧā§āϰ āĻāύā§āϝ āĻŦā§āϝāĻŦāĻšā§āϤ āĻšāϝāĻŧ",
|
|
||||||
"image_preview_quality_description": "ā§§-ā§§ā§Ļā§Ļ āĻāϰ āĻŽāϧā§āϝ⧠āĻĒā§āϰāĻŋāĻāĻŋāĻ āĻā§āϝāĻŧāĻžāϞāĻŋāĻāĻŋāĨ¤ āĻŦā§āĻļāĻŋ āĻšāϞ⧠āĻāĻžāϞā§, āĻāĻŋāύā§āϤ⧠āĻŦāĻĄāĻŧ āĻĢāĻžāĻāϞ āϤā§āϰāĻŋ āĻšāϝāĻŧ āĻāĻŦāĻ āĻ
ā§āϝāĻžāĻĒā§āϰ āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻžāĻļā§āϞāϤāĻž āĻāĻŽāĻžāϤ⧠āĻĒāĻžāϰā§āĨ¤ āĻāĻŽ āĻŽāĻžāύ āϏā§āĻ āĻāϰāϞ⧠āĻŽā§āĻļāĻŋāύ āϞāĻžāϰā§āύāĻŋāĻ āĻā§āϝāĻŧāĻžāϞāĻŋāĻāĻŋāϰ āĻāĻĒāϰ āĻĒā§āϰāĻāĻžāĻŦ āĻĒāĻĄāĻŧāϤ⧠āĻĒāĻžāϰā§āĨ¤",
|
|
||||||
"image_preview_title": "āĻĒā§āϰāĻŋāĻāĻŋāĻ āϏā§āĻāĻŋāĻāϏ",
|
|
||||||
"image_quality": "āĻā§āĻŖāĻŽāĻžāύ",
|
|
||||||
"image_resolution": "āϰā§āĻā§āϞāĻŋāĻāĻļāύ",
|
|
||||||
"image_resolution_description": "āĻāĻā§āĻ āϰā§āĻā§āϞāĻŋāĻāĻļāύā§āϰ āĻā§āώā§āϤā§āϰ⧠āĻāϰāĻ āĻŦāĻŋāϏā§āϤāĻžāϰāĻŋāϤ āϤāĻĨā§āϝ āϏāĻāϰāĻā§āώāĻŖ āĻāϰāĻž āϏāĻŽā§āĻāĻŦ āĻāĻŋāύā§āϤ⧠āĻāύāĻā§āĻĄ āĻāϰāϤ⧠āĻŦā§āĻļāĻŋ āϏāĻŽāϝāĻŧ āϞāĻžāĻā§, āĻĢāĻžāĻāϞā§āϰ āĻāĻāĻžāϰ āĻŦāĻĄāĻŧ āĻšāϝāĻŧ āĻāĻŦāĻ āĻ
ā§āϝāĻžāĻĒā§āϰ āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻžāĻļā§āϞāϤāĻž āĻāĻŽāĻžāϤ⧠āĻĒāĻžāϰā§āĨ¤",
|
|
||||||
"image_settings": "āĻāĻŋāϤā§āϰ āϏā§āĻāĻŋāĻāϏ",
|
|
||||||
"image_settings_description": "āϤā§āϰāĻŋ āĻāϰāĻž āĻāĻŦāĻŋāϰ āĻŽāĻžāύ āĻāĻŦāĻ āϰā§āĻā§āϞāĻŋāĻāĻļāύ āĻĒāϰāĻŋāĻāĻžāϞāύāĻž āĻāϰā§āύ",
|
|
||||||
"image_thumbnail_description": "āĻŽā§āĻāĻžāĻĄā§āĻāĻž āĻŦāĻžāĻĻ āĻĻā§āĻā§āĻž āĻā§āĻ āĻĨāĻžāĻŽā§āĻŦāύā§āĻāϞ, āĻŽā§āϞ āĻāĻžāĻāĻŽāϞāĻžāĻāύā§āϰ āĻŽāϤ⧠āĻāĻŦāĻŋāϰ āĻā§āϰā§āĻĒ āĻĻā§āĻāĻžāϰ āϏāĻŽāϝāĻŧ āĻŦā§āϝāĻŦāĻšā§āϤ āĻšā§",
|
|
||||||
"image_thumbnail_quality_description": "āĻĨāĻžāĻŽā§āĻŦāύā§āĻāϞā§āϰ āĻŽāĻžāύ ā§§-ā§§ā§Ļā§ĻāĨ¤ āĻŦā§āĻļāĻŋ āĻšāϞ⧠āĻāĻžāϞā§, āĻāĻŋāύā§āϤ⧠āĻŦāĻĄāĻŧ āĻĢāĻžāĻāϞ āϤā§āϰāĻŋ āĻšāϝāĻŧ āĻāĻŦāĻ āĻ
ā§āϝāĻžāĻĒā§āϰ āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻžāĻļā§āϞāϤāĻž āĻāĻŽāĻžāϤ⧠āĻĒāĻžāϰā§āĨ¤",
|
|
||||||
"image_thumbnail_title": "āĻĨāĻžāĻŽā§āĻŦāύā§āϞ āϏā§āĻāĻŋāĻāϏ",
|
|
||||||
"job_concurrency": "{job} āĻāύāĻāĻžāϰā§āύā§āϏāĻŋ",
|
|
||||||
"job_created": "Job āϤā§āϰāĻŋ āĻšāϝāĻŧā§āĻā§",
|
|
||||||
"job_not_concurrency_safe": "āĻāĻ āĻāĻžāĻāĻāĻŋ āϏāĻŽāĻāĻžāϞā§āύ-āύāĻŋāϰāĻžāĻĒāĻĻ āύāϝāĻŧāĨ¤",
|
|
||||||
"job_settings": "āĻāĻžāĻā§āϰ āϏā§āĻāĻŋāĻāϏ",
|
|
||||||
"job_settings_description": "āĻāĻžāĻā§āϰ āϏāĻŽāĻžāύā§āϤāϰāĻžāϞāϤāĻž āĻĒāϰāĻŋāĻāĻžāϞāύāĻž āĻāϰā§āύ",
|
|
||||||
"job_status": "āĻāĻžāĻāϰāĻŋāϰ āĻ
āĻŦāϏā§āĻĨāĻž"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user