Compare commits

..

12 Commits

Author SHA1 Message Date
Min Idzelis 053dd490b4 fix test 2025-06-15 03:40:31 +00:00
Min Idzelis f4f81341da tests 2025-06-15 03:22:32 +00:00
Min Idzelis 3e66913cf8 chore: lint 2025-06-15 03:16:39 +00:00
Min Idzelis 504309eff5 chore: make sql 2025-06-15 03:04:23 +00:00
Min Idzelis b44abf5b4b Merge remote-tracking branch 'origin/main' into timeline_events 2025-06-15 02:58:04 +00:00
Min Idzelis c76e8da173 chore: cleanup 2025-06-15 02:47:18 +00:00
Min Idzelis 9cc2189ef7 chore: remove unused code and fix test expectations
- Remove unused activityManager import from asset viewer components
- Remove unused function stub in activity manager
- Fix album service test expectations for emit parameters
- Clean up formatting in person repository mock
- Update trash service tests for emit event changes
2025-06-15 02:25:42 +00:00
Min Idzelis 6b87efe7a3 feat(web): improve websocket filtering and add restored assets support
- Refactor websocket support to use modular filter functions
- Add support for on_asset_restore events
- Improve handling of asset updates with proper filtering for visibility, favorites, trash, tags, albums, and persons
- Add null checks in timeline manager for empty arrays
2025-06-15 02:25:18 +00:00
Min Idzelis 7b75da1f10 refactor(server): change asset update events to send IDs instead of full assets
- Change on_asset_update event to send asset IDs array instead of full AssetResponseDto
- Add asset.update event emission in asset service for update operations
- Update notification handlers to work with asset IDs
- Improve update logic to avoid duplicate events when metadata is updated
- Update frontend websocket types to match new event format
2025-06-15 02:24:06 +00:00
Min Idzelis a7559f0691 feat(server): add websocket events for activity changes
- Add 'activity.change' event to event repository
- Emit event when new activity (reaction/comment) is created
- Add notification handler to broadcast activity changes to relevant users
- Update frontend websocket types to include on_activity_change event
- Update tests to mock album repository calls
2025-06-15 02:23:09 +00:00
Min Idzelis 6f2f295cf3 refactor(server): clean up asset repository and add getTrashedIds method
- Remove redundant return statement in asset repository update method
- Add getTrashedIds method to trash repository for retrieving trashed asset IDs by user
2025-06-15 02:22:37 +00:00
Min Idzelis b3d080f6e8 feat(server,web): add websocket events for album updates
and person face changes
2025-06-11 10:52:43 +00:00
2063 changed files with 53519 additions and 139194 deletions
+1 -1
View File
@@ -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:
+17 -40
View File
@@ -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
-13
View File
@@ -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
View File
@@ -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
-6
View File
@@ -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
View File
@@ -1 +1 @@
22.18.0 22.16.0
-4
View File
@@ -1,4 +0,0 @@
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
+3 -3
View File
@@ -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": {
+10 -44
View File
@@ -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 }}
+2 -5
View File
@@ -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
-96
View File
@@ -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
}
}'
+3 -3
View File
@@ -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}}'
+4 -4
View File
@@ -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) }}
+1 -5
View File
@@ -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
-2
View File
@@ -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
-13
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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 }}
-2
View File
@@ -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
+19 -14
View File
@@ -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
+9 -36
View File
@@ -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:
+2 -2
View File
@@ -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) }}
-1
View File
@@ -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
+2 -2
View File
@@ -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"
} }
] ]
+9 -21
View File
@@ -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
View File
@@ -1 +1 @@
22.18.0 22.16.0
-2
View File
@@ -1,2 +0,0 @@
#!/usr/bin/env node
import '../dist/index.js';
+301 -384
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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",
] ]
} }
+1 -1
View File
@@ -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"
} }
} }
} }
+14 -16
View File
@@ -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
+6 -7
View File
@@ -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
+3 -4
View File
@@ -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
View File
@@ -1 +1 @@
22.18.0 22.16.0
+2 -2
View File
@@ -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

+2 -8
View File
@@ -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.
:::
+9 -87
View File
@@ -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
+10 -29
View File
@@ -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 -6
View File
@@ -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! [![Open in VSCode Containers](https://img.shields.io/static/v1?label=VSCode%20DevContainer&message=Immich&color=blue)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/immich-app/immich/)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/immich-app/immich/) [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](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
-13
View File
@@ -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.
+1 -1
View File
@@ -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
+9 -9
View File
@@ -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' />
+2 -2
View File
@@ -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.
::: :::
+1 -1
View File
@@ -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 |
+6 -6
View File
@@ -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.
+43 -73
View File
@@ -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
+2 -2
View File
@@ -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

+2 -2
View File
@@ -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/
+19 -19
View File
@@ -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/
+2 -2
View File
@@ -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**".
+1 -1
View File
@@ -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.
+1
View File
@@ -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.
+970 -561
View File
File diff suppressed because it is too large Load Diff
+4 -6
View File
@@ -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"
} }
} }
-6
View File
@@ -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 {
+1 -20
View File
@@ -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
View File
@@ -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,
+2 -3
View File
@@ -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
-36
View File
@@ -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
View File
@@ -1 +1 @@
22.18.0 22.16.0
+3 -2
View File
@@ -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
+455 -1000
View File
File diff suppressed because it is too large Load Diff
+5 -7
View File
@@ -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"
} }
} }
-32
View File
@@ -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([]);
});
}); });
}); });
+2 -2
View File
@@ -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 () => {
+1 -1
View File
@@ -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', () => {
-440
View File
@@ -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, {
+146
View File
@@ -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',
});
});
});
});
+201 -2
View File
@@ -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}`)
-15
View File
@@ -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,
+12 -59
View File
@@ -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' })],
}); });
}); });
}); });
+1 -30
View File
@@ -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 &amp; 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);
+1 -1
View File
@@ -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', () => {
+230
View File
@@ -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]);
});
});
});
+1 -1
View File
@@ -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`, () => {
-178
View File
@@ -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);
}
-1
View File
@@ -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: '',
}, },
+1 -16
View File
@@ -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
View File
@@ -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) => {
-1
View File
@@ -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
+8 -110
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+9 -358
View File
@@ -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
View File
@@ -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
View File
@@ -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