merge main
2
.github/workflows/cli.yml
vendored
@ -87,7 +87,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' }}
|
type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' }}
|
||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
uses: docker/build-push-action@v5.1.0
|
uses: docker/build-push-action@v5.2.0
|
||||||
with:
|
with:
|
||||||
file: cli/Dockerfile
|
file: cli/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
2
.github/workflows/docker.yml
vendored
@ -121,7 +121,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
uses: docker/build-push-action@v5.1.0
|
uses: docker/build-push-action@v5.2.0
|
||||||
with:
|
with:
|
||||||
context: ${{ matrix.context }}
|
context: ${{ matrix.context }}
|
||||||
file: ${{ matrix.file }}
|
file: ${{ matrix.file }}
|
||||||
|
2077
cli/package-lock.json
generated
@ -14,7 +14,6 @@
|
|||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||||
"@testcontainers/postgresql": "^10.7.1",
|
|
||||||
"@types/byte-size": "^8.1.0",
|
"@types/byte-size": "^8.1.0",
|
||||||
"@types/cli-progress": "^3.11.0",
|
"@types/cli-progress": "^3.11.0",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
@ -66,8 +66,8 @@ class Asset {
|
|||||||
assetData: new File([await fs.openAsBlob(this.path)], basename(this.path)),
|
assetData: new File([await fs.openAsBlob(this.path)], basename(this.path)),
|
||||||
deviceAssetId: this.deviceAssetId,
|
deviceAssetId: this.deviceAssetId,
|
||||||
deviceId: 'CLI',
|
deviceId: 'CLI',
|
||||||
fileCreatedAt: this.fileCreatedAt,
|
fileCreatedAt: this.fileCreatedAt.toISOString(),
|
||||||
fileModifiedAt: this.fileModifiedAt,
|
fileModifiedAt: this.fileModifiedAt.toISOString(),
|
||||||
isFavorite: String(false),
|
isFavorite: String(false),
|
||||||
};
|
};
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
@ -3,6 +3,7 @@ import { access, constants, mkdir, readFile, unlink, writeFile } from 'node:fs/p
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import yaml from 'yaml';
|
import yaml from 'yaml';
|
||||||
import { ImmichApi } from './api.service';
|
import { ImmichApi } from './api.service';
|
||||||
|
|
||||||
class LoginError extends Error {
|
class LoginError extends Error {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message);
|
super(message);
|
||||||
@ -14,14 +15,12 @@ class LoginError extends Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class SessionService {
|
export class SessionService {
|
||||||
readonly configDirectory!: string;
|
private get authPath() {
|
||||||
readonly authPath!: string;
|
return path.join(this.configDirectory, '/auth.yml');
|
||||||
|
|
||||||
constructor(configDirectory: string) {
|
|
||||||
this.configDirectory = configDirectory;
|
|
||||||
this.authPath = path.join(configDirectory, '/auth.yml');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor(private configDirectory: string) {}
|
||||||
|
|
||||||
async connect(): Promise<ImmichApi> {
|
async connect(): Promise<ImmichApi> {
|
||||||
let instanceUrl = process.env.IMMICH_INSTANCE_URL;
|
let instanceUrl = process.env.IMMICH_INSTANCE_URL;
|
||||||
let apiKey = process.env.IMMICH_API_KEY;
|
let apiKey = process.env.IMMICH_API_KEY;
|
||||||
@ -48,6 +47,8 @@ export class SessionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instanceUrl = await this.resolveApiEndpoint(instanceUrl);
|
||||||
|
|
||||||
const api = new ImmichApi(instanceUrl, apiKey);
|
const api = new ImmichApi(instanceUrl, apiKey);
|
||||||
|
|
||||||
const pingResponse = await api.pingServer().catch((error) => {
|
const pingResponse = await api.pingServer().catch((error) => {
|
||||||
@ -62,7 +63,9 @@ export class SessionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async login(instanceUrl: string, apiKey: string): Promise<ImmichApi> {
|
async login(instanceUrl: string, apiKey: string): Promise<ImmichApi> {
|
||||||
console.log('Logging in...');
|
console.log(`Logging in to ${instanceUrl}`);
|
||||||
|
|
||||||
|
instanceUrl = await this.resolveApiEndpoint(instanceUrl);
|
||||||
|
|
||||||
const api = new ImmichApi(instanceUrl, apiKey);
|
const api = new ImmichApi(instanceUrl, apiKey);
|
||||||
|
|
||||||
@ -83,7 +86,7 @@ export class SessionService {
|
|||||||
|
|
||||||
await writeFile(this.authPath, yaml.stringify({ instanceUrl, apiKey }), { mode: 0o600 });
|
await writeFile(this.authPath, yaml.stringify({ instanceUrl, apiKey }), { mode: 0o600 });
|
||||||
|
|
||||||
console.log('Wrote auth info to ' + this.authPath);
|
console.log(`Wrote auth info to ${this.authPath}`);
|
||||||
|
|
||||||
return api;
|
return api;
|
||||||
}
|
}
|
||||||
@ -98,4 +101,18 @@ export class SessionService {
|
|||||||
|
|
||||||
console.log('Successfully logged out');
|
console.log('Successfully logged out');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async resolveApiEndpoint(instanceUrl: string): Promise<string> {
|
||||||
|
const wellKnownUrl = new URL('.well-known/immich', instanceUrl);
|
||||||
|
try {
|
||||||
|
const wellKnown = await fetch(wellKnownUrl).then((response) => response.json());
|
||||||
|
const endpoint = new URL(wellKnown.api.endpoint, instanceUrl).toString();
|
||||||
|
if (endpoint !== instanceUrl) {
|
||||||
|
console.debug(`Discovered API at ${endpoint}`);
|
||||||
|
}
|
||||||
|
return endpoint;
|
||||||
|
} catch {
|
||||||
|
return instanceUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ Note: Either a manual or scheduled library scan must have been performed to iden
|
|||||||
|
|
||||||
In all above scan methods, Immich will check if any files are missing. This can happen if files are deleted, or if they are on a storage location that is currently unavailable, like a network drive that is not mounted, or a USB drive that has been unplugged. In order to prevent accidental deletion of assets, Immich will not immediately delete an asset from the library if the file is missing. Instead, the asset will be internally marked as offline and will still be visible in the main timeline. If the file is moved back to its original location and the library is scanned again, the asset will be restored.
|
In all above scan methods, Immich will check if any files are missing. This can happen if files are deleted, or if they are on a storage location that is currently unavailable, like a network drive that is not mounted, or a USB drive that has been unplugged. In order to prevent accidental deletion of assets, Immich will not immediately delete an asset from the library if the file is missing. Instead, the asset will be internally marked as offline and will still be visible in the main timeline. If the file is moved back to its original location and the library is scanned again, the asset will be restored.
|
||||||
|
|
||||||
Finally, files can be deleted from Immich via the `Remove Offline Files` job. This job can be found by the three dots menu for the associated external storage that was configured under user account settings > libraries (the same location described at [create external libraries](#create-external-libraries)). When this job is run, any assets marked as offline will then be removed from Immich. Run this job whenever files have been deleted from the file system and you want to remove them from Immich.
|
Finally, files can be deleted from Immich via the `Remove Offline Files` job. This job can be found by the three dots menu for the associated external storage that was configured under Administration > Libraries (the same location described at [create external libraries](#create-external-libraries)). When this job is run, any assets marked as offline will then be removed from Immich. Run this job whenever files have been deleted from the file system and you want to remove them from Immich.
|
||||||
|
|
||||||
### Import Paths
|
### Import Paths
|
||||||
|
|
||||||
@ -50,8 +50,6 @@ If the import paths are edited in a way that an external file is no longer in an
|
|||||||
|
|
||||||
Sometimes, an external library will not scan correctly. This can happen if immich_server or immich_microservices can't access the files. Here are some things to check:
|
Sometimes, an external library will not scan correctly. This can happen if immich_server or immich_microservices can't access the files. Here are some things to check:
|
||||||
|
|
||||||
- Is the external path set correctly? Each import path must be contained in the external path.
|
|
||||||
- Make sure the external path does not contain spaces
|
|
||||||
- In the docker-compose file, are the volumes mounted correctly?
|
- In the docker-compose file, are the volumes mounted correctly?
|
||||||
- Are the volumes identical between the `server` and `microservices` container?
|
- Are the volumes identical between the `server` and `microservices` container?
|
||||||
- Are the import paths set correctly, and do they match the path set in docker-compose file?
|
- Are the import paths set correctly, and do they match the path set in docker-compose file?
|
||||||
@ -61,18 +59,6 @@ Sometimes, an external library will not scan correctly. This can happen if immic
|
|||||||
|
|
||||||
To validate that Immich can reach your external library, start a shell inside the container. Run `docker exec -it immich_microservices /bin/bash` to a bash shell. If your import path is `/data/import/photos`, check it with `ls /data/import/photos`. Do the same check for the `immich_server` container. If you cannot access this directory in both the `microservices` and `server` containers, Immich won't be able to import files.
|
To validate that Immich can reach your external library, start a shell inside the container. Run `docker exec -it immich_microservices /bin/bash` to a bash shell. If your import path is `/data/import/photos`, check it with `ls /data/import/photos`. Do the same check for the `immich_server` container. If you cannot access this directory in both the `microservices` and `server` containers, Immich won't be able to import files.
|
||||||
|
|
||||||
### Security Considerations
|
|
||||||
|
|
||||||
:::caution
|
|
||||||
|
|
||||||
Please read and understand this section before setting external paths, as there are important security considerations.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
For security purposes, each Immich user is disallowed to add external files by default. This is to prevent devastating [path traversal attacks](https://owasp.org/www-community/attacks/Path_Traversal). An admin can allow individual users to use external path feature via the `external path` setting found in the admin panel. Without the external path restriction, a user can add any image or video file on the Immich host filesystem to be imported into Immich, potentially allowing sensitive data to be accessed. If you are running Immich as root in your Docker setup (which is the default), all external file reads are done with root privileges. This is particularly dangerous if the Immich host is a shared server.
|
|
||||||
|
|
||||||
With the `external path` set, a user is restricted to accessing external files to files or directories within that path. The Immich admin should still be careful not set the external path too generously. For example, `user1` wants to read their photos in to `/home/user1`. A lazy admin sets that user's external path to `/home/` since it "gets the job done". However, that user will then be able to read all photos in `/home/user2/private-photos`, too! Please set the external path as specific as possible. If multiple folders must be added, do this using the docker volume mount feature described below.
|
|
||||||
|
|
||||||
### Exclusion Patterns
|
### Exclusion Patterns
|
||||||
|
|
||||||
By default, all files in the import paths will be added to the library. If there are files that should not be added, exclusion patterns can be used to exclude them. Exclusion patterns are glob patterns are matched against the full file path. If a file matches an exclusion pattern, it will not be added to the library. Exclusion patterns can be added in the Scan Settings page for each library. Under the hood, Immich uses the [glob](https://www.npmjs.com/package/glob) package to match patterns, so please refer to [their documentation](https://github.com/isaacs/node-glob#glob-primer) to see what patterns are supported.
|
By default, all files in the import paths will be added to the library. If there are files that should not be added, exclusion patterns can be used to exclude them. Exclusion patterns are glob patterns are matched against the full file path. If a file matches an exclusion pattern, it will not be added to the library. Exclusion patterns can be added in the Scan Settings page for each library. Under the hood, Immich uses the [glob](https://www.npmjs.com/package/glob) package to match patterns, so please refer to [their documentation](https://github.com/isaacs/node-glob#glob-primer) to see what patterns are supported.
|
||||||
@ -90,6 +76,16 @@ This feature - currently hidden in the config file - is considered experimental
|
|||||||
|
|
||||||
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.
|
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
|
||||||
|
|
||||||
|
If you encounter an `ENOSPC` error, you need to increase your file watcher limit. In sysctl, this key is called `fs.inotify.max_user_watched` and has a default value of 8192. Increase this number to a suitable value greater than the number of files you will be watching. Note that Immich has to watch all files in your import paths including any ignored files.
|
||||||
|
|
||||||
|
```
|
||||||
|
ERROR [LibraryService] Library watcher for library c69faf55-f96d-4aa0-b83b-2d80cbc27d98 encountered error: Error: ENOSPC: System limit for number of file watchers reached, watch '/media/photo.jpg'
|
||||||
|
```
|
||||||
|
|
||||||
|
In rare cases, the library watcher can hang, preventing Immich from starting up. In this case, disable the library watcher in the configuration file. If the watcher is enabled from within Immich, the app must be started without the microservices. Disable the microservices in the docker compose file, start Immich, disable the library watcher in the admin settings, close Immich, re-enable the microservices, and then Immich can be started normally.
|
||||||
|
|
||||||
### Nightly job
|
### Nightly job
|
||||||
|
|
||||||
There is an automatic job that's run once a day and refreshes all modified files in all libraries as well as cleans up any libraries stuck in deletion.
|
There is an automatic job that's run once a day and refreshes all modified files in all libraries as well as cleans up any libraries stuck in deletion.
|
||||||
@ -135,27 +131,13 @@ The `ro` flag at the end only gives read-only access to the volumes. While Immic
|
|||||||
_Remember to bring the container `docker compose down/up` to register the changes. Make sure you can see the mounted path in the container._
|
_Remember to bring the container `docker compose down/up` to register the changes. Make sure you can see the mounted path in the container._
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Set External Path
|
|
||||||
|
|
||||||
Only an admin can do this.
|
|
||||||
|
|
||||||
- Navigate to `Administration > Users` page on the web.
|
|
||||||
- Click on the user edit button.
|
|
||||||
- Set `/mnt/media` to be the external path. This folder will only contain the three folders that we want to import, so nothing else can be accessed.
|
|
||||||
:::note
|
|
||||||
Spaces in the internal path aren't currently supported.
|
|
||||||
|
|
||||||
You must import it as:
|
|
||||||
`..:/mnt/media/my-media:ro`
|
|
||||||
instead of
|
|
||||||
`..:/mnt/media/my media:ro`
|
|
||||||
:::
|
|
||||||
|
|
||||||
### Create External Libraries
|
### Create External Libraries
|
||||||
|
|
||||||
- Click on your user name in the top right corner -> Account Settings
|
These actions must be performed by the Immich administrator.
|
||||||
- Click on Libraries
|
|
||||||
|
- Click on Administration -> Libraries
|
||||||
- Click on Create External Library
|
- Click on Create External Library
|
||||||
|
- Select which user owns the library, this can not be changed later
|
||||||
- Click the drop-down menu on the newly created library
|
- Click the drop-down menu on the newly created library
|
||||||
- Click on Rename Library and rename it to "Christmas Trip"
|
- Click on Rename Library and rename it to "Christmas Trip"
|
||||||
- Click Edit Import Paths
|
- Click Edit Import Paths
|
||||||
@ -166,7 +148,7 @@ NOTE: We have to use the `/mnt/media/christmas-trip` path and not the `/mnt/nas/
|
|||||||
|
|
||||||
Next, we'll add an exclusion pattern to filter out raw files.
|
Next, we'll add an exclusion pattern to filter out raw files.
|
||||||
|
|
||||||
- Click the drop-down menu on the newly christmas library
|
- Click the drop-down menu on the newly-created Christmas library
|
||||||
- Click on Manage
|
- Click on Manage
|
||||||
- Click on Scan Settings
|
- Click on Scan Settings
|
||||||
- Click on Add Exclusion Pattern
|
- Click on Add Exclusion Pattern
|
||||||
|
@ -13,7 +13,7 @@ Run `docker exec -it immich_postgres psql immich <DB_USERNAME>` to connect to th
|
|||||||
## Assets
|
## Assets
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
The `"originalFileName"` column is the name of the uploaded file _without_ 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"
|
||||||
@ -40,6 +40,10 @@ SELECT * FROM "assets" where "livePhotoVideoId" IS NOT NULL;
|
|||||||
SELECT "assets".* FROM "exif" LEFT JOIN "assets" ON "assets"."id" = "exif"."assetId" WHERE "exif"."assetId" IS NULL;
|
SELECT "assets".* FROM "exif" LEFT JOIN "assets" ON "assets"."id" = "exif"."assetId" WHERE "exif"."assetId" IS NULL;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```sql title="size < 100,000 bytes, smallest to largest"
|
||||||
|
SELECT * FROM "assets" JOIN "exif" ON "assets"."id" = "exif"."assetId" WHERE "exif"."fileSizeInByte" < 100000 ORDER BY "exif"."fileSizeInByte" ASC;
|
||||||
|
```
|
||||||
|
|
||||||
```sql title="Without thumbnails"
|
```sql title="Without thumbnails"
|
||||||
SELECT * FROM "assets" WHERE "assets"."resizePath" IS NULL OR "assets"."webpPath" IS NULL;
|
SELECT * FROM "assets" WHERE "assets"."resizePath" IS NULL OR "assets"."webpPath" IS NULL;
|
||||||
```
|
```
|
||||||
|
@ -28,6 +28,10 @@ On my computer, for example, I use this path:
|
|||||||
EXTERNAL_PATH=/home/tenino/photos
|
EXTERNAL_PATH=/home/tenino/photos
|
||||||
```
|
```
|
||||||
|
|
||||||
|
:::info EXTERNAL_PATH design
|
||||||
|
The design choice to put the EXTERNAL_PATH into .env rather than put two copies of the absolute path in the yml file in order to make everything easier, so if you have two copies of the same path that have to be kept in sync, then someday later when you move the data, update only one of the paths, without everything will break mysteriously.
|
||||||
|
:::
|
||||||
|
|
||||||
Restart Immich.
|
Restart Immich.
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -35,47 +39,26 @@ docker compose down
|
|||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
# Set the External Path
|
# Create the library
|
||||||
|
|
||||||
In the Immich web UI:
|
In the Immich web UI:
|
||||||
|
|
||||||
- click the **Administration** link in the upper right corner.
|
- click the **Administration** link in the upper right corner.
|
||||||
<img src={require('./img/administration-link.png').default} width="50%" title="Administration link" />
|
<img src={require('./img/administration-link.png').default} width="50%" title="Administration link" />
|
||||||
|
|
||||||
- Select the **Users** tab
|
- Select the **External Libraries** tab
|
||||||
<img src={require('./img/users-tab.png').default} width="50%" title="Users tab" />
|
<img src={require('./img/external-libraries.png').default} width="50%" title="External Libraries tab" />
|
||||||
|
|
||||||
- Select the **pencil** next to your user ID
|
- Click the **Create Library** button
|
||||||
<img src={require('./img/pencil.png').default} width="50%" title="Pencil" />
|
<img src={require('./img/create-external-library.png').default} width="50%" title="Create Library button" />
|
||||||
|
|
||||||
- Fill in the **External Path** field with `/usr/src/app/external`
|
- In the dialog, select which user should own the new library
|
||||||
<img src={require('./img/external-path.png').default} width="50%" title="External Path field" />
|
<img src={require('./img/library-owner.png').default} width="50%" title="Library owner diaglog" />
|
||||||
|
|
||||||
Notice this matches the path _inside the container_ where we mounted your photos.
|
|
||||||
The purpose of the external path field is for administrators who have multiple users
|
|
||||||
on their Immich instance. It lets you prevent other authorized users from
|
|
||||||
navigating to your external library.
|
|
||||||
|
|
||||||
# Import the library
|
|
||||||
|
|
||||||
In the Immich web UI:
|
|
||||||
|
|
||||||
- Click your user avatar in the upper-right corner (circle with your initials)
|
|
||||||
<img src={require('./img/user-avatar.png').default} width="50%" title="User avatar" />
|
|
||||||
|
|
||||||
- Click **Account Settings**
|
|
||||||
<img src={require('./img/account-settings.png').default} width="50%" title="Account Settings button" />
|
|
||||||
|
|
||||||
- Click to expand **Libraries**
|
|
||||||
<img src={require('./img/libraries-dropdown.png').default} width="50%" title="Libraries dropdown" />
|
|
||||||
|
|
||||||
- Click the **Create External Library** button
|
|
||||||
<img src={require('./img/create-external-library-button.png').default} width="50%" title="Create External Library button" />
|
|
||||||
|
|
||||||
- Click the three-dots menu and select **Edit Import Paths**
|
- Click the three-dots menu and select **Edit Import Paths**
|
||||||
<img src={require('./img/edit-import-paths.png').default} width="50%" title="Edit Import Paths menu option" />
|
<img src={require('./img/edit-import-paths.png').default} width="50%" title="Edit Import Paths menu option" />
|
||||||
|
|
||||||
- Click \*_Add path_
|
- Click Add path
|
||||||
<img src={require('./img/add-path-button.png').default} width="50%" title="Add Path button" />
|
<img src={require('./img/add-path-button.png').default} width="50%" title="Add Path button" />
|
||||||
|
|
||||||
- Enter **/usr/src/app/external** as the path and click Add
|
- Enter **/usr/src/app/external** as the path and click Add
|
||||||
|
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 5.7 KiB |
BIN
docs/docs/guides/img/create-external-library.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
docs/docs/guides/img/external-libraries.png
Normal file
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB |
BIN
docs/docs/guides/img/library-owner.png
Normal file
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 15 KiB |
@ -128,6 +128,9 @@ The default configuration looks like this:
|
|||||||
"theme": {
|
"theme": {
|
||||||
"customCss": ""
|
"customCss": ""
|
||||||
},
|
},
|
||||||
|
"user": {
|
||||||
|
"deleteDelay": 7
|
||||||
|
},
|
||||||
"library": {
|
"library": {
|
||||||
"scan": {
|
"scan": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
@ -124,16 +124,18 @@ Redis (Sentinel) URL example JSON before encoding:
|
|||||||
|
|
||||||
## Machine Learning
|
## Machine Learning
|
||||||
|
|
||||||
| Variable | Description | Default | Services |
|
| Variable | Description | Default | Services |
|
||||||
| :----------------------------------------------- | :----------------------------------------------------------------- | :-----------------: | :--------------- |
|
| :----------------------------------------------- | :------------------------------------------------------------------- | :-----------------: | :--------------- |
|
||||||
| `MACHINE_LEARNING_MODEL_TTL` | Inactivity time (s) before a model is unloaded (disabled if \<= 0) | `300` | machine learning |
|
| `MACHINE_LEARNING_MODEL_TTL` | Inactivity time (s) before a model is unloaded (disabled if \<= 0) | `300` | machine learning |
|
||||||
| `MACHINE_LEARNING_MODEL_TTL_POLL_S` | Interval (s) between checks for the model TTL (disabled if \<= 0) | `10` | machine learning |
|
| `MACHINE_LEARNING_MODEL_TTL_POLL_S` | Interval (s) between checks for the model TTL (disabled if \<= 0) | `10` | machine learning |
|
||||||
| `MACHINE_LEARNING_CACHE_FOLDER` | Directory where models are downloaded | `/cache` | machine learning |
|
| `MACHINE_LEARNING_CACHE_FOLDER` | Directory where models are downloaded | `/cache` | machine learning |
|
||||||
| `MACHINE_LEARNING_REQUEST_THREADS`<sup>\*1</sup> | Thread count of the request thread pool (disabled if \<= 0) | number of CPU cores | machine learning |
|
| `MACHINE_LEARNING_REQUEST_THREADS`<sup>\*1</sup> | Thread count of the request thread pool (disabled if \<= 0) | number of CPU cores | machine learning |
|
||||||
| `MACHINE_LEARNING_MODEL_INTER_OP_THREADS` | Number of parallel model operations | `1` | machine learning |
|
| `MACHINE_LEARNING_MODEL_INTER_OP_THREADS` | Number of parallel model operations | `1` | machine learning |
|
||||||
| `MACHINE_LEARNING_MODEL_INTRA_OP_THREADS` | Number of threads for each model operation | `2` | machine learning |
|
| `MACHINE_LEARNING_MODEL_INTRA_OP_THREADS` | Number of threads for each model operation | `2` | machine learning |
|
||||||
| `MACHINE_LEARNING_WORKERS`<sup>\*2</sup> | Number of worker processes to spawn | `1` | machine learning |
|
| `MACHINE_LEARNING_WORKERS`<sup>\*2</sup> | Number of worker processes to spawn | `1` | machine learning |
|
||||||
| `MACHINE_LEARNING_WORKER_TIMEOUT` | Maximum time (s) of unresponsiveness before a worker is killed | `120` | machine learning |
|
| `MACHINE_LEARNING_WORKER_TIMEOUT` | Maximum time (s) of unresponsiveness before a worker is killed | `120` | machine learning |
|
||||||
|
| `MACHINE_LEARNING_PRELOAD__CLIP` | Name of a CLIP model to be preloaded and kept in cache | | machine learning |
|
||||||
|
| `MACHINE_LEARNING_PRELOAD__FACIAL_RECOGNITION` | Name of a facial recognition model to be preloaded and kept in cache | | machine learning |
|
||||||
|
|
||||||
\*1: It is recommended to begin with this parameter when changing the concurrency levels of the machine learning service and then tune the other ones.
|
\*1: It is recommended to begin with this parameter when changing the concurrency levels of the machine learning service and then tune the other ones.
|
||||||
|
|
||||||
|
@ -28,6 +28,10 @@ Or before beginning app installation, [create the datasets](https://www.truenas.
|
|||||||
Immich requires seven datasets: **library**, **pgBackup**, **pgData**, **profile**, **thumbs**, **uploads**, and **video**.
|
Immich requires seven datasets: **library**, **pgBackup**, **pgData**, **profile**, **thumbs**, **uploads**, and **video**.
|
||||||
You can organize these as one parent with seven child datasets, for example `mnt/tank/immich/library`, `mnt/tank/immich/pgBackup`, and so on.
|
You can organize these as one parent with seven child datasets, for example `mnt/tank/immich/library`, `mnt/tank/immich/pgBackup`, and so on.
|
||||||
|
|
||||||
|
:::info Permissions
|
||||||
|
The **pgData** dataset must be owned by the user `netdata` (UID 999) for postgres to start. The other datasets must be owned by the user `root` (UID 0) or a group that includes the user `root` (UID 0) for immich to have the necessary permissions.
|
||||||
|
:::
|
||||||
|
|
||||||
## Installing the Immich Application
|
## Installing the Immich Application
|
||||||
|
|
||||||
To install the **Immich** application, go to **Apps**, click **Discover Apps**, either begin typing Immich into the search field or scroll down to locate the **Immich** application widget.
|
To install the **Immich** application, go to **Apps**, click **Discover Apps**, either begin typing Immich into the search field or scroll down to locate the **Immich** application widget.
|
||||||
|
8
docs/package-lock.json
generated
@ -12231,7 +12231,7 @@
|
|||||||
"mime-format": "2.0.0",
|
"mime-format": "2.0.0",
|
||||||
"mime-types": "2.1.27",
|
"mime-types": "2.1.27",
|
||||||
"postman-url-encoder": "2.1.3",
|
"postman-url-encoder": "2.1.3",
|
||||||
"sanitize-html": "^2.11.0",
|
"sanitize-html": "^2.12.1",
|
||||||
"semver": "^7.5.4",
|
"semver": "^7.5.4",
|
||||||
"uuid": "3.4.0"
|
"uuid": "3.4.0"
|
||||||
}
|
}
|
||||||
@ -14762,9 +14762,9 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
},
|
},
|
||||||
"node_modules/sanitize-html": {
|
"node_modules/sanitize-html": {
|
||||||
"version": "2.11.0",
|
"version": "2.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.12.1.tgz",
|
||||||
"integrity": "sha512-BG68EDHRaGKqlsNjJ2xUB7gpInPA8gVx/mvjO743hZaeMCZ2DwzW7xvsqZ+KNU4QKwj86HJ3uu2liISf2qBBUA==",
|
"integrity": "sha512-Plh+JAn0UVDpBRP/xEjsk+xDCoOvMBwQUf/K+/cBAVuTbtX8bj2VB7S1sL1dssVpykqp0/KPSesHrqXtokVBpA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
|
31
e2e/package-lock.json
generated
@ -49,7 +49,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||||
"@testcontainers/postgresql": "^10.7.1",
|
|
||||||
"@types/byte-size": "^8.1.0",
|
"@types/byte-size": "^8.1.0",
|
||||||
"@types/cli-progress": "^3.11.0",
|
"@types/cli-progress": "^3.11.0",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
@ -80,7 +79,7 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.97.0",
|
"version": "1.98.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -924,12 +923,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@playwright/test": {
|
"node_modules/@playwright/test": {
|
||||||
"version": "1.41.2",
|
"version": "1.42.1",
|
||||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.2.tgz",
|
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.42.1.tgz",
|
||||||
"integrity": "sha512-qQB9h7KbibJzrDpkXkYvsmiDJK14FULCCZgEcoe2AvFAS64oCirWTwzTlAYEbKaRxWs5TFesE1Na6izMv3HfGg==",
|
"integrity": "sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright": "1.41.2"
|
"playwright": "1.42.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
@ -1156,9 +1155,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.11.20",
|
"version": "20.11.24",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.20.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz",
|
||||||
"integrity": "sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==",
|
"integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
@ -3870,12 +3869,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright": {
|
"node_modules/playwright": {
|
||||||
"version": "1.41.2",
|
"version": "1.42.1",
|
||||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.2.tgz",
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.42.1.tgz",
|
||||||
"integrity": "sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A==",
|
"integrity": "sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.41.2"
|
"playwright-core": "1.42.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
@ -3888,9 +3887,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright-core": {
|
"node_modules/playwright-core": {
|
||||||
"version": "1.41.2",
|
"version": "1.42.1",
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.2.tgz",
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.42.1.tgz",
|
||||||
"integrity": "sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA==",
|
"integrity": "sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright-core": "cli.js"
|
"playwright-core": "cli.js"
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vitest --config vitest.config.ts",
|
"test": "vitest --run",
|
||||||
|
"test:watch": "vitest",
|
||||||
"test:web": "npx playwright test",
|
"test:web": "npx playwright test",
|
||||||
"start:web": "npx playwright test --ui",
|
"start:web": "npx playwright test --ui",
|
||||||
"format": "prettier --check .",
|
"format": "prettier --check .",
|
||||||
|
@ -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 { apiUtils, app, asBearerAuth, dbUtils } from 'src/utils';
|
import { app, asBearerAuth, utils } from 'src/utils';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
@ -23,12 +23,11 @@ describe('/activity', () => {
|
|||||||
create({ activityCreateDto: dto }, { headers: asBearerAuth(accessToken || admin.accessToken) });
|
create({ activityCreateDto: dto }, { headers: asBearerAuth(accessToken || admin.accessToken) });
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
|
||||||
|
|
||||||
admin = await apiUtils.adminSetup();
|
admin = await utils.adminSetup();
|
||||||
nonOwner = await apiUtils.userSetup(admin.accessToken, createUserDto.user1);
|
nonOwner = await utils.userSetup(admin.accessToken, createUserDto.user1);
|
||||||
asset = await apiUtils.createAsset(admin.accessToken);
|
asset = await utils.createAsset(admin.accessToken);
|
||||||
album = await createAlbum(
|
album = await createAlbum(
|
||||||
{
|
{
|
||||||
createAlbumDto: {
|
createAlbumDto: {
|
||||||
@ -42,7 +41,7 @@ describe('/activity', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await dbUtils.reset(['activity']);
|
await utils.resetDatabase(['activity']);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /activity', () => {
|
describe('GET /activity', () => {
|
||||||
|
@ -7,7 +7,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 { apiUtils, app, asBearerAuth, dbUtils } from 'src/utils';
|
import { app, asBearerAuth, utils } from 'src/utils';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
@ -29,49 +29,48 @@ describe('/album', () => {
|
|||||||
let user3: LoginResponseDto; // deleted
|
let user3: LoginResponseDto; // deleted
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
|
||||||
|
|
||||||
admin = await apiUtils.adminSetup();
|
admin = await utils.adminSetup();
|
||||||
|
|
||||||
[user1, user2, user3] = await Promise.all([
|
[user1, user2, user3] = await Promise.all([
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user1),
|
utils.userSetup(admin.accessToken, createUserDto.user1),
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user2),
|
utils.userSetup(admin.accessToken, createUserDto.user2),
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user3),
|
utils.userSetup(admin.accessToken, createUserDto.user3),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
[user1Asset1, user1Asset2] = await Promise.all([
|
[user1Asset1, user1Asset2] = await Promise.all([
|
||||||
apiUtils.createAsset(user1.accessToken, { isFavorite: true }),
|
utils.createAsset(user1.accessToken, { isFavorite: true }),
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const albums = await Promise.all([
|
const albums = await Promise.all([
|
||||||
// user 1
|
// user 1
|
||||||
apiUtils.createAlbum(user1.accessToken, {
|
utils.createAlbum(user1.accessToken, {
|
||||||
albumName: user1SharedUser,
|
albumName: user1SharedUser,
|
||||||
sharedWithUserIds: [user2.userId],
|
sharedWithUserIds: [user2.userId],
|
||||||
assetIds: [user1Asset1.id],
|
assetIds: [user1Asset1.id],
|
||||||
}),
|
}),
|
||||||
apiUtils.createAlbum(user1.accessToken, {
|
utils.createAlbum(user1.accessToken, {
|
||||||
albumName: user1SharedLink,
|
albumName: user1SharedLink,
|
||||||
assetIds: [user1Asset1.id],
|
assetIds: [user1Asset1.id],
|
||||||
}),
|
}),
|
||||||
apiUtils.createAlbum(user1.accessToken, {
|
utils.createAlbum(user1.accessToken, {
|
||||||
albumName: user1NotShared,
|
albumName: user1NotShared,
|
||||||
assetIds: [user1Asset1.id, user1Asset2.id],
|
assetIds: [user1Asset1.id, user1Asset2.id],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// user 2
|
// user 2
|
||||||
apiUtils.createAlbum(user2.accessToken, {
|
utils.createAlbum(user2.accessToken, {
|
||||||
albumName: user2SharedUser,
|
albumName: user2SharedUser,
|
||||||
sharedWithUserIds: [user1.userId],
|
sharedWithUserIds: [user1.userId],
|
||||||
assetIds: [user1Asset1.id],
|
assetIds: [user1Asset1.id],
|
||||||
}),
|
}),
|
||||||
apiUtils.createAlbum(user2.accessToken, { albumName: user2SharedLink }),
|
utils.createAlbum(user2.accessToken, { albumName: user2SharedLink }),
|
||||||
apiUtils.createAlbum(user2.accessToken, { albumName: user2NotShared }),
|
utils.createAlbum(user2.accessToken, { albumName: user2NotShared }),
|
||||||
|
|
||||||
// user 3
|
// user 3
|
||||||
apiUtils.createAlbum(user3.accessToken, {
|
utils.createAlbum(user3.accessToken, {
|
||||||
albumName: 'Deleted',
|
albumName: 'Deleted',
|
||||||
sharedWithUserIds: [user1.userId],
|
sharedWithUserIds: [user1.userId],
|
||||||
}),
|
}),
|
||||||
@ -82,12 +81,12 @@ describe('/album', () => {
|
|||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
// add shared link to user1SharedLink album
|
// add shared link to user1SharedLink album
|
||||||
apiUtils.createSharedLink(user1.accessToken, {
|
utils.createSharedLink(user1.accessToken, {
|
||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
albumId: user1Albums[1].id,
|
albumId: user1Albums[1].id,
|
||||||
}),
|
}),
|
||||||
// add shared link to user2SharedLink album
|
// add shared link to user2SharedLink album
|
||||||
apiUtils.createSharedLink(user2.accessToken, {
|
utils.createSharedLink(user2.accessToken, {
|
||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
albumId: user2Albums[1].id,
|
albumId: user2Albums[1].id,
|
||||||
}),
|
}),
|
||||||
@ -366,7 +365,7 @@ describe('/album', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to add own asset to own album', async () => {
|
it('should be able to add own asset to own album', async () => {
|
||||||
const asset = await apiUtils.createAsset(user1.accessToken);
|
const asset = await utils.createAsset(user1.accessToken);
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.put(`/album/${user1Albums[0].id}/assets`)
|
.put(`/album/${user1Albums[0].id}/assets`)
|
||||||
.set('Authorization', `Bearer ${user1.accessToken}`)
|
.set('Authorization', `Bearer ${user1.accessToken}`)
|
||||||
@ -377,7 +376,7 @@ describe('/album', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to add own asset to shared album', async () => {
|
it('should be able to add own asset to shared album', async () => {
|
||||||
const asset = await apiUtils.createAsset(user1.accessToken);
|
const asset = await utils.createAsset(user1.accessToken);
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.put(`/album/${user2Albums[0].id}/assets`)
|
.put(`/album/${user2Albums[0].id}/assets`)
|
||||||
.set('Authorization', `Bearer ${user1.accessToken}`)
|
.set('Authorization', `Bearer ${user1.accessToken}`)
|
||||||
@ -398,7 +397,7 @@ describe('/album', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update an album', async () => {
|
it('should update an album', async () => {
|
||||||
const album = await apiUtils.createAlbum(user1.accessToken, {
|
const album = await utils.createAlbum(user1.accessToken, {
|
||||||
albumName: 'New album',
|
albumName: 'New album',
|
||||||
});
|
});
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
@ -485,7 +484,7 @@ describe('/album', () => {
|
|||||||
let album: AlbumResponseDto;
|
let album: AlbumResponseDto;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
album = await apiUtils.createAlbum(user1.accessToken, {
|
album = await utils.createAlbum(user1.accessToken, {
|
||||||
albumName: 'testAlbum',
|
albumName: 'testAlbum',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,13 +7,12 @@ import {
|
|||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { exiftool } from 'exiftool-vendored';
|
import { exiftool } from 'exiftool-vendored';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { createHash } 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 { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import { createUserDto, uuidDto } from 'src/fixtures';
|
import { createUserDto, uuidDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { apiUtils, app, dbUtils, tempDir, testAssetDir, wsUtils } from 'src/utils';
|
import { app, tempDir, testAssetDir, utils } from 'src/utils';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
@ -21,8 +20,6 @@ const TEN_TIMES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|||||||
|
|
||||||
const locationAssetFilepath = `${testAssetDir}/metadata/gps-position/thompson-springs.jpg`;
|
const locationAssetFilepath = `${testAssetDir}/metadata/gps-position/thompson-springs.jpg`;
|
||||||
|
|
||||||
const sha1 = (bytes: Buffer) => createHash('sha1').update(bytes).digest('base64');
|
|
||||||
|
|
||||||
const readTags = async (bytes: Buffer, filename: string) => {
|
const readTags = async (bytes: Buffer, filename: string) => {
|
||||||
const filepath = join(tempDir, filename);
|
const filepath = join(tempDir, filename);
|
||||||
await writeFile(filepath, bytes);
|
await writeFile(filepath, bytes);
|
||||||
@ -47,42 +44,41 @@ describe('/asset', () => {
|
|||||||
let ws: Socket;
|
let ws: Socket;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
admin = await utils.adminSetup({ onboarding: false });
|
||||||
admin = await apiUtils.adminSetup({ onboarding: false });
|
|
||||||
|
|
||||||
[ws, user1, user2, userStats] = await Promise.all([
|
[ws, user1, user2, userStats] = await Promise.all([
|
||||||
wsUtils.connect(admin.accessToken),
|
utils.connectWebsocket(admin.accessToken),
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user1),
|
utils.userSetup(admin.accessToken, createUserDto.user1),
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user2),
|
utils.userSetup(admin.accessToken, createUserDto.user2),
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user3),
|
utils.userSetup(admin.accessToken, createUserDto.user3),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// asset location
|
// asset location
|
||||||
assetLocation = await apiUtils.createAsset(admin.accessToken, {
|
assetLocation = await utils.createAsset(admin.accessToken, {
|
||||||
assetData: {
|
assetData: {
|
||||||
filename: 'thompson-springs.jpg',
|
filename: 'thompson-springs.jpg',
|
||||||
bytes: await readFile(locationAssetFilepath),
|
bytes: await readFile(locationAssetFilepath),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await wsUtils.waitForEvent({ event: 'upload', assetId: assetLocation.id });
|
await utils.waitForWebsocketEvent({ event: 'upload', assetId: assetLocation.id });
|
||||||
|
|
||||||
user1Assets = await Promise.all([
|
user1Assets = await Promise.all([
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
apiUtils.createAsset(user1.accessToken, {
|
utils.createAsset(user1.accessToken, {
|
||||||
isFavorite: true,
|
isFavorite: true,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
fileCreatedAt: yesterday.toISO(),
|
fileCreatedAt: yesterday.toISO(),
|
||||||
fileModifiedAt: yesterday.toISO(),
|
fileModifiedAt: yesterday.toISO(),
|
||||||
assetData: { filename: 'example.mp4' },
|
assetData: { filename: 'example.mp4' },
|
||||||
}),
|
}),
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
user2Assets = await Promise.all([apiUtils.createAsset(user2.accessToken)]);
|
user2Assets = await Promise.all([utils.createAsset(user2.accessToken)]);
|
||||||
|
|
||||||
for (const asset of [...user1Assets, ...user2Assets]) {
|
for (const asset of [...user1Assets, ...user2Assets]) {
|
||||||
expect(asset.duplicate).toBe(false);
|
expect(asset.duplicate).toBe(false);
|
||||||
@ -90,27 +86,27 @@ describe('/asset', () => {
|
|||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
// stats
|
// stats
|
||||||
apiUtils.createAsset(userStats.accessToken),
|
utils.createAsset(userStats.accessToken),
|
||||||
apiUtils.createAsset(userStats.accessToken, { isFavorite: true }),
|
utils.createAsset(userStats.accessToken, { isFavorite: true }),
|
||||||
apiUtils.createAsset(userStats.accessToken, { isArchived: true }),
|
utils.createAsset(userStats.accessToken, { isArchived: true }),
|
||||||
apiUtils.createAsset(userStats.accessToken, {
|
utils.createAsset(userStats.accessToken, {
|
||||||
isArchived: true,
|
isArchived: true,
|
||||||
isFavorite: true,
|
isFavorite: true,
|
||||||
assetData: { filename: 'example.mp4' },
|
assetData: { filename: 'example.mp4' },
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const person1 = await apiUtils.createPerson(user1.accessToken, {
|
const person1 = await utils.createPerson(user1.accessToken, {
|
||||||
name: 'Test Person',
|
name: 'Test Person',
|
||||||
});
|
});
|
||||||
await dbUtils.createFace({
|
await utils.createFace({
|
||||||
assetId: user1Assets[0].id,
|
assetId: user1Assets[0].id,
|
||||||
personId: person1.id,
|
personId: person1.id,
|
||||||
});
|
});
|
||||||
}, 30_000);
|
}, 30_000);
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
wsUtils.disconnect(ws);
|
utils.disconnectWebsocket(ws);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /asset/:id', () => {
|
describe('GET /asset/:id', () => {
|
||||||
@ -145,7 +141,7 @@ describe('/asset', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should work with a shared link', async () => {
|
it('should work with a shared link', async () => {
|
||||||
const sharedLink = await apiUtils.createSharedLink(user1.accessToken, {
|
const sharedLink = await utils.createSharedLink(user1.accessToken, {
|
||||||
type: SharedLinkType.Individual,
|
type: SharedLinkType.Individual,
|
||||||
assetIds: [user1Assets[0].id],
|
assetIds: [user1Assets[0].id],
|
||||||
});
|
});
|
||||||
@ -175,7 +171,7 @@ describe('/asset', () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const sharedLink = await apiUtils.createSharedLink(user1.accessToken, {
|
const sharedLink = await utils.createSharedLink(user1.accessToken, {
|
||||||
type: SharedLinkType.Individual,
|
type: SharedLinkType.Individual,
|
||||||
assetIds: [user1Assets[0].id],
|
assetIds: [user1Assets[0].id],
|
||||||
});
|
});
|
||||||
@ -247,12 +243,12 @@ describe('/asset', () => {
|
|||||||
describe('GET /asset/random', () => {
|
describe('GET /asset/random', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
apiUtils.createAsset(user1.accessToken),
|
utils.createAsset(user1.accessToken),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -335,7 +331,7 @@ describe('/asset', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should favorite an asset', async () => {
|
it('should favorite an asset', async () => {
|
||||||
const before = await apiUtils.getAssetInfo(user1.accessToken, user1Assets[0].id);
|
const before = await utils.getAssetInfo(user1.accessToken, user1Assets[0].id);
|
||||||
expect(before.isFavorite).toBe(false);
|
expect(before.isFavorite).toBe(false);
|
||||||
|
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
@ -347,7 +343,7 @@ describe('/asset', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should archive an asset', async () => {
|
it('should archive an asset', async () => {
|
||||||
const before = await apiUtils.getAssetInfo(user1.accessToken, user1Assets[0].id);
|
const before = await utils.getAssetInfo(user1.accessToken, user1Assets[0].id);
|
||||||
expect(before.isArchived).toBe(false);
|
expect(before.isArchived).toBe(false);
|
||||||
|
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
@ -475,9 +471,9 @@ describe('/asset', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should move an asset to the trash', async () => {
|
it('should move an asset to the trash', async () => {
|
||||||
const { id: assetId } = await apiUtils.createAsset(admin.accessToken);
|
const { id: assetId } = await utils.createAsset(admin.accessToken);
|
||||||
|
|
||||||
const before = await apiUtils.getAssetInfo(admin.accessToken, assetId);
|
const before = await utils.getAssetInfo(admin.accessToken, assetId);
|
||||||
expect(before.isTrashed).toBe(false);
|
expect(before.isTrashed).toBe(false);
|
||||||
|
|
||||||
const { status } = await request(app)
|
const { status } = await request(app)
|
||||||
@ -486,7 +482,7 @@ describe('/asset', () => {
|
|||||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
expect(status).toBe(204);
|
expect(status).toBe(204);
|
||||||
|
|
||||||
const after = await apiUtils.getAssetInfo(admin.accessToken, assetId);
|
const after = await utils.getAssetInfo(admin.accessToken, assetId);
|
||||||
expect(after.isTrashed).toBe(true);
|
expect(after.isTrashed).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -497,7 +493,7 @@ describe('/asset', () => {
|
|||||||
input: 'formats/jpg/el_torcal_rocks.jpg',
|
input: 'formats/jpg/el_torcal_rocks.jpg',
|
||||||
expected: {
|
expected: {
|
||||||
type: AssetTypeEnum.Image,
|
type: AssetTypeEnum.Image,
|
||||||
originalFileName: 'el_torcal_rocks',
|
originalFileName: 'el_torcal_rocks.jpg',
|
||||||
resized: true,
|
resized: true,
|
||||||
exifInfo: {
|
exifInfo: {
|
||||||
dateTimeOriginal: '2012-08-05T11:39:59.000Z',
|
dateTimeOriginal: '2012-08-05T11:39:59.000Z',
|
||||||
@ -521,7 +517,7 @@ describe('/asset', () => {
|
|||||||
input: 'formats/heic/IMG_2682.heic',
|
input: 'formats/heic/IMG_2682.heic',
|
||||||
expected: {
|
expected: {
|
||||||
type: AssetTypeEnum.Image,
|
type: AssetTypeEnum.Image,
|
||||||
originalFileName: 'IMG_2682',
|
originalFileName: 'IMG_2682.heic',
|
||||||
resized: true,
|
resized: true,
|
||||||
fileCreatedAt: '2019-03-21T16:04:22.348Z',
|
fileCreatedAt: '2019-03-21T16:04:22.348Z',
|
||||||
exifInfo: {
|
exifInfo: {
|
||||||
@ -546,7 +542,7 @@ describe('/asset', () => {
|
|||||||
input: 'formats/png/density_plot.png',
|
input: 'formats/png/density_plot.png',
|
||||||
expected: {
|
expected: {
|
||||||
type: AssetTypeEnum.Image,
|
type: AssetTypeEnum.Image,
|
||||||
originalFileName: 'density_plot',
|
originalFileName: 'density_plot.png',
|
||||||
resized: true,
|
resized: true,
|
||||||
exifInfo: {
|
exifInfo: {
|
||||||
exifImageWidth: 800,
|
exifImageWidth: 800,
|
||||||
@ -561,7 +557,7 @@ describe('/asset', () => {
|
|||||||
input: 'formats/raw/Nikon/D80/glarus.nef',
|
input: 'formats/raw/Nikon/D80/glarus.nef',
|
||||||
expected: {
|
expected: {
|
||||||
type: AssetTypeEnum.Image,
|
type: AssetTypeEnum.Image,
|
||||||
originalFileName: 'glarus',
|
originalFileName: 'glarus.nef',
|
||||||
resized: true,
|
resized: true,
|
||||||
fileCreatedAt: '2010-07-20T17:27:12.000Z',
|
fileCreatedAt: '2010-07-20T17:27:12.000Z',
|
||||||
exifInfo: {
|
exifInfo: {
|
||||||
@ -583,7 +579,7 @@ describe('/asset', () => {
|
|||||||
input: 'formats/raw/Nikon/D700/philadelphia.nef',
|
input: 'formats/raw/Nikon/D700/philadelphia.nef',
|
||||||
expected: {
|
expected: {
|
||||||
type: AssetTypeEnum.Image,
|
type: AssetTypeEnum.Image,
|
||||||
originalFileName: 'philadelphia',
|
originalFileName: 'philadelphia.nef',
|
||||||
resized: true,
|
resized: true,
|
||||||
fileCreatedAt: '2016-09-22T22:10:29.060Z',
|
fileCreatedAt: '2016-09-22T22:10:29.060Z',
|
||||||
exifInfo: {
|
exifInfo: {
|
||||||
@ -607,15 +603,15 @@ describe('/asset', () => {
|
|||||||
for (const { input, expected } of tests) {
|
for (const { input, expected } of tests) {
|
||||||
it(`should generate a thumbnail for ${input}`, async () => {
|
it(`should generate a thumbnail for ${input}`, async () => {
|
||||||
const filepath = join(testAssetDir, input);
|
const filepath = join(testAssetDir, input);
|
||||||
const { id, duplicate } = await apiUtils.createAsset(admin.accessToken, {
|
const { id, duplicate } = await utils.createAsset(admin.accessToken, {
|
||||||
assetData: { bytes: await readFile(filepath), filename: basename(filepath) },
|
assetData: { bytes: await readFile(filepath), filename: basename(filepath) },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(duplicate).toBe(false);
|
expect(duplicate).toBe(false);
|
||||||
|
|
||||||
await wsUtils.waitForEvent({ event: 'upload', assetId: id });
|
await utils.waitForWebsocketEvent({ event: 'upload', assetId: id });
|
||||||
|
|
||||||
const asset = await apiUtils.getAssetInfo(admin.accessToken, id);
|
const asset = await utils.getAssetInfo(admin.accessToken, id);
|
||||||
|
|
||||||
expect(asset.exifInfo).toBeDefined();
|
expect(asset.exifInfo).toBeDefined();
|
||||||
expect(asset.exifInfo).toMatchObject(expected.exifInfo);
|
expect(asset.exifInfo).toMatchObject(expected.exifInfo);
|
||||||
@ -625,7 +621,7 @@ describe('/asset', () => {
|
|||||||
|
|
||||||
it('should handle a duplicate', async () => {
|
it('should handle a duplicate', async () => {
|
||||||
const filepath = 'formats/jpeg/el_torcal_rocks.jpeg';
|
const filepath = 'formats/jpeg/el_torcal_rocks.jpeg';
|
||||||
const { duplicate } = await apiUtils.createAsset(admin.accessToken, {
|
const { duplicate } = await utils.createAsset(admin.accessToken, {
|
||||||
assetData: {
|
assetData: {
|
||||||
bytes: await readFile(join(testAssetDir, filepath)),
|
bytes: await readFile(join(testAssetDir, filepath)),
|
||||||
filename: basename(filepath),
|
filename: basename(filepath),
|
||||||
@ -657,21 +653,21 @@ describe('/asset', () => {
|
|||||||
|
|
||||||
for (const { filepath, checksum } of motionTests) {
|
for (const { filepath, checksum } of motionTests) {
|
||||||
it(`should extract motionphoto video from ${filepath}`, async () => {
|
it(`should extract motionphoto video from ${filepath}`, async () => {
|
||||||
const response = await apiUtils.createAsset(admin.accessToken, {
|
const response = await utils.createAsset(admin.accessToken, {
|
||||||
assetData: {
|
assetData: {
|
||||||
bytes: await readFile(join(testAssetDir, filepath)),
|
bytes: await readFile(join(testAssetDir, filepath)),
|
||||||
filename: basename(filepath),
|
filename: basename(filepath),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await wsUtils.waitForEvent({ event: 'upload', assetId: response.id });
|
await utils.waitForWebsocketEvent({ event: 'upload', assetId: response.id });
|
||||||
|
|
||||||
expect(response.duplicate).toBe(false);
|
expect(response.duplicate).toBe(false);
|
||||||
|
|
||||||
const asset = await apiUtils.getAssetInfo(admin.accessToken, response.id);
|
const asset = await utils.getAssetInfo(admin.accessToken, response.id);
|
||||||
expect(asset.livePhotoVideoId).toBeDefined();
|
expect(asset.livePhotoVideoId).toBeDefined();
|
||||||
|
|
||||||
const video = await apiUtils.getAssetInfo(admin.accessToken, asset.livePhotoVideoId as string);
|
const video = await utils.getAssetInfo(admin.accessToken, asset.livePhotoVideoId as string);
|
||||||
expect(video.checksum).toStrictEqual(checksum);
|
expect(video.checksum).toStrictEqual(checksum);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -690,7 +686,7 @@ describe('/asset', () => {
|
|||||||
.get(`/asset/thumbnail/${assetLocation.id}?format=WEBP`)
|
.get(`/asset/thumbnail/${assetLocation.id}?format=WEBP`)
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
await wsUtils.waitForEvent({
|
await utils.waitForWebsocketEvent({
|
||||||
event: 'upload',
|
event: 'upload',
|
||||||
assetId: assetLocation.id,
|
assetId: assetLocation.id,
|
||||||
});
|
});
|
||||||
@ -736,11 +732,11 @@ describe('/asset', () => {
|
|||||||
expect(body).toBeDefined();
|
expect(body).toBeDefined();
|
||||||
expect(type).toBe('image/jpeg');
|
expect(type).toBe('image/jpeg');
|
||||||
|
|
||||||
const asset = await apiUtils.getAssetInfo(admin.accessToken, assetLocation.id);
|
const asset = await utils.getAssetInfo(admin.accessToken, assetLocation.id);
|
||||||
|
|
||||||
const original = await readFile(locationAssetFilepath);
|
const original = await readFile(locationAssetFilepath);
|
||||||
const originalChecksum = sha1(original);
|
const originalChecksum = utils.sha1(original);
|
||||||
const downloadChecksum = sha1(body);
|
const downloadChecksum = utils.sha1(body);
|
||||||
|
|
||||||
expect(originalChecksum).toBe(downloadChecksum);
|
expect(originalChecksum).toBe(downloadChecksum);
|
||||||
expect(downloadChecksum).toBe(asset.checksum);
|
expect(downloadChecksum).toBe(asset.checksum);
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
import { deleteAssets, getAuditFiles, updateAsset, type LoginResponseDto } from '@immich/sdk';
|
import { deleteAssets, getAuditFiles, updateAsset, type LoginResponseDto } from '@immich/sdk';
|
||||||
import { apiUtils, asBearerAuth, dbUtils, fileUtils } from 'src/utils';
|
import { asBearerAuth, utils } from 'src/utils';
|
||||||
import { beforeAll, describe, expect, it } from 'vitest';
|
import { beforeAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
describe('/audit', () => {
|
describe('/audit', () => {
|
||||||
let admin: LoginResponseDto;
|
let admin: LoginResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
await utils.resetFilesystem();
|
||||||
await fileUtils.reset();
|
|
||||||
|
|
||||||
admin = await apiUtils.adminSetup();
|
admin = await utils.adminSetup();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET :/file-report', () => {
|
describe('GET :/file-report', () => {
|
||||||
it('excludes assets without issues from report', async () => {
|
it('excludes assets without issues from report', async () => {
|
||||||
const [trashedAsset, archivedAsset] = await Promise.all([
|
const [trashedAsset, archivedAsset] = await Promise.all([
|
||||||
apiUtils.createAsset(admin.accessToken),
|
utils.createAsset(admin.accessToken),
|
||||||
apiUtils.createAsset(admin.accessToken),
|
utils.createAsset(admin.accessToken),
|
||||||
apiUtils.createAsset(admin.accessToken),
|
utils.createAsset(admin.accessToken),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
import { LoginResponseDto, getAuthDevices, login, signUpAdmin } from '@immich/sdk';
|
import { LoginResponseDto, getAuthDevices, login, signUpAdmin } from '@immich/sdk';
|
||||||
import { loginDto, signupDto, uuidDto } from 'src/fixtures';
|
import { loginDto, signupDto, uuidDto } from 'src/fixtures';
|
||||||
import { deviceDto, errorDto, loginResponseDto, signupResponseDto } from 'src/responses';
|
import { deviceDto, errorDto, loginResponseDto, signupResponseDto } from 'src/responses';
|
||||||
import { apiUtils, app, asBearerAuth, dbUtils } from 'src/utils';
|
import { app, asBearerAuth, utils } from 'src/utils';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
import { beforeEach, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
const { name, email, password } = signupDto.admin;
|
const { name, email, password } = signupDto.admin;
|
||||||
|
|
||||||
describe(`/auth/admin-sign-up`, () => {
|
describe(`/auth/admin-sign-up`, () => {
|
||||||
beforeAll(() => {
|
|
||||||
apiUtils.setup();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await dbUtils.reset();
|
await utils.resetDatabase();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /auth/admin-sign-up', () => {
|
describe('POST /auth/admin-sign-up', () => {
|
||||||
@ -84,7 +80,7 @@ describe('/auth/*', () => {
|
|||||||
let admin: LoginResponseDto;
|
let admin: LoginResponseDto;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await dbUtils.reset();
|
await utils.resetDatabase();
|
||||||
await signUpAdmin({ signUpDto: signupDto.admin });
|
await signUpAdmin({ signUpDto: signupDto.admin });
|
||||||
admin = await login({ loginCredentialDto: loginDto.admin });
|
admin = await login({ loginCredentialDto: loginDto.admin });
|
||||||
});
|
});
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
import { AssetFileUploadResponseDto, LoginResponseDto } from '@immich/sdk';
|
import { AssetFileUploadResponseDto, LoginResponseDto } from '@immich/sdk';
|
||||||
|
import { readFile, writeFile } from 'node:fs/promises';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { apiUtils, app, dbUtils } from 'src/utils';
|
import { app, tempDir, 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';
|
||||||
|
|
||||||
describe('/download', () => {
|
describe('/download', () => {
|
||||||
let admin: LoginResponseDto;
|
let admin: LoginResponseDto;
|
||||||
let asset1: AssetFileUploadResponseDto;
|
let asset1: AssetFileUploadResponseDto;
|
||||||
|
let asset2: AssetFileUploadResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
admin = await utils.adminSetup();
|
||||||
admin = await apiUtils.adminSetup();
|
[asset1, asset2] = await Promise.all([utils.createAsset(admin.accessToken), utils.createAsset(admin.accessToken)]);
|
||||||
asset1 = await apiUtils.createAsset(admin.accessToken);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /download/info', () => {
|
describe('POST /download/info', () => {
|
||||||
@ -40,6 +41,39 @@ describe('/download', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('POST /download/archive', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post(`/download/archive`)
|
||||||
|
.send({ assetIds: [asset1.id, asset2.id] });
|
||||||
|
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should download an archive', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post('/download/archive')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({ assetIds: [asset1.id, asset2.id] });
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body instanceof Buffer).toBe(true);
|
||||||
|
|
||||||
|
await writeFile(`${tempDir}/archive.zip`, body);
|
||||||
|
await utils.unzip(`${tempDir}/archive.zip`, `${tempDir}/archive`);
|
||||||
|
const files = [
|
||||||
|
{ filename: 'example.png', id: asset1.id },
|
||||||
|
{ filename: 'example+1.png', id: asset2.id },
|
||||||
|
];
|
||||||
|
for (const { id, filename } of files) {
|
||||||
|
const bytes = await readFile(`${tempDir}/archive/${filename}`);
|
||||||
|
const asset = await utils.getAssetInfo(admin.accessToken, id);
|
||||||
|
expect(utils.sha1(bytes)).toBe(asset.checksum);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('POST /download/asset/:id', () => {
|
describe('POST /download/asset/:id', () => {
|
||||||
it('should require authentication', async () => {
|
it('should require authentication', async () => {
|
||||||
const { status, body } = await request(app).post(`/download/asset/${asset1.id}`);
|
const { status, body } = await request(app).post(`/download/asset/${asset1.id}`);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { LibraryResponseDto, LibraryType, LoginResponseDto, getAllLibraries } from '@immich/sdk';
|
import { LibraryResponseDto, LibraryType, LoginResponseDto, getAllLibraries } from '@immich/sdk';
|
||||||
import { userDto, uuidDto } from 'src/fixtures';
|
import { userDto, uuidDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { apiUtils, app, asBearerAuth, dbUtils, testAssetDirInternal } from 'src/utils';
|
import { app, asBearerAuth, testAssetDirInternal, 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';
|
||||||
|
|
||||||
@ -11,11 +11,10 @@ describe('/library', () => {
|
|||||||
let library: LibraryResponseDto;
|
let library: LibraryResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
admin = await utils.adminSetup();
|
||||||
admin = await apiUtils.adminSetup();
|
user = await utils.userSetup(admin.accessToken, userDto.user1);
|
||||||
user = await apiUtils.userSetup(admin.accessToken, userDto.user1);
|
library = await utils.createLibrary(admin.accessToken, { type: LibraryType.External });
|
||||||
library = await apiUtils.createLibrary(admin.accessToken, { type: LibraryType.External });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /library', () => {
|
describe('GET /library', () => {
|
||||||
@ -303,7 +302,7 @@ describe('/library', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should get library by id', async () => {
|
it('should get library by id', async () => {
|
||||||
const library = await apiUtils.createLibrary(admin.accessToken, { type: LibraryType.External });
|
const library = await utils.createLibrary(admin.accessToken, { type: LibraryType.External });
|
||||||
|
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.get(`/library/${library.id}`)
|
.get(`/library/${library.id}`)
|
||||||
@ -359,7 +358,7 @@ describe('/library', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should delete an external library', async () => {
|
it('should delete an external library', async () => {
|
||||||
const library = await apiUtils.createLibrary(admin.accessToken, { type: LibraryType.External });
|
const library = await utils.createLibrary(admin.accessToken, { type: LibraryType.External });
|
||||||
|
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.delete(`/library/${library.id}`)
|
.delete(`/library/${library.id}`)
|
||||||
@ -415,14 +414,14 @@ describe('/library', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should pass with no import paths', async () => {
|
it('should pass with no import paths', async () => {
|
||||||
const response = await apiUtils.validateLibrary(admin.accessToken, library.id, { importPaths: [] });
|
const response = await utils.validateLibrary(admin.accessToken, library.id, { importPaths: [] });
|
||||||
expect(response.importPaths).toEqual([]);
|
expect(response.importPaths).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail if path does not exist', async () => {
|
it('should fail if path does not exist', async () => {
|
||||||
const pathToTest = `${testAssetDirInternal}/does/not/exist`;
|
const pathToTest = `${testAssetDirInternal}/does/not/exist`;
|
||||||
|
|
||||||
const response = await apiUtils.validateLibrary(admin.accessToken, library.id, {
|
const response = await utils.validateLibrary(admin.accessToken, library.id, {
|
||||||
importPaths: [pathToTest],
|
importPaths: [pathToTest],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -439,7 +438,7 @@ describe('/library', () => {
|
|||||||
it('should fail if path is a file', async () => {
|
it('should fail if path is a file', async () => {
|
||||||
const pathToTest = `${testAssetDirInternal}/albums/nature/el_torcal_rocks.jpg`;
|
const pathToTest = `${testAssetDirInternal}/albums/nature/el_torcal_rocks.jpg`;
|
||||||
|
|
||||||
const response = await apiUtils.validateLibrary(admin.accessToken, library.id, {
|
const response = await utils.validateLibrary(admin.accessToken, library.id, {
|
||||||
importPaths: [pathToTest],
|
importPaths: [pathToTest],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { apiUtils, app, dbUtils } from 'src/utils';
|
import { app, utils } from 'src/utils';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
import { beforeAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
describe(`/oauth`, () => {
|
describe(`/oauth`, () => {
|
||||||
beforeAll(() => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
});
|
await utils.adminSetup();
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await dbUtils.reset();
|
|
||||||
await apiUtils.adminSetup();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /oauth/authorize', () => {
|
describe('POST /oauth/authorize', () => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { LoginResponseDto, createPartner } from '@immich/sdk';
|
import { LoginResponseDto, createPartner } from '@immich/sdk';
|
||||||
import { createUserDto } from 'src/fixtures';
|
import { createUserDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { apiUtils, app, asBearerAuth, dbUtils } from 'src/utils';
|
import { app, asBearerAuth, 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';
|
||||||
|
|
||||||
@ -12,15 +12,14 @@ describe('/partner', () => {
|
|||||||
let user3: LoginResponseDto;
|
let user3: LoginResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
|
||||||
|
|
||||||
admin = await apiUtils.adminSetup();
|
admin = await utils.adminSetup();
|
||||||
|
|
||||||
[user1, user2, user3] = await Promise.all([
|
[user1, user2, user3] = await Promise.all([
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user1),
|
utils.userSetup(admin.accessToken, createUserDto.user1),
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user2),
|
utils.userSetup(admin.accessToken, createUserDto.user2),
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user3),
|
utils.userSetup(admin.accessToken, createUserDto.user3),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
@ -1,39 +1,49 @@
|
|||||||
import { LoginResponseDto, PersonResponseDto } from '@immich/sdk';
|
import { LoginResponseDto, PersonResponseDto } from '@immich/sdk';
|
||||||
import { uuidDto } from 'src/fixtures';
|
import { uuidDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { apiUtils, app, dbUtils } from 'src/utils';
|
import { app, utils } from 'src/utils';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
describe('/activity', () => {
|
const invalidBirthday = [
|
||||||
|
{ birthDate: 'false', response: 'birthDate must be a date string' },
|
||||||
|
{ birthDate: '123567', response: 'birthDate must be a date string' },
|
||||||
|
{ birthDate: 123_567, response: 'birthDate must be a date string' },
|
||||||
|
{ birthDate: new Date(9999, 0, 0).toISOString(), response: ['Birth date cannot be in the future'] },
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('/person', () => {
|
||||||
let admin: LoginResponseDto;
|
let admin: LoginResponseDto;
|
||||||
let visiblePerson: PersonResponseDto;
|
let visiblePerson: PersonResponseDto;
|
||||||
let hiddenPerson: PersonResponseDto;
|
let hiddenPerson: PersonResponseDto;
|
||||||
|
let multipleAssetsPerson: PersonResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
admin = await utils.adminSetup();
|
||||||
admin = await apiUtils.adminSetup();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
[visiblePerson, hiddenPerson, multipleAssetsPerson] = await Promise.all([
|
||||||
await dbUtils.reset(['person']);
|
utils.createPerson(admin.accessToken, {
|
||||||
|
|
||||||
[visiblePerson, hiddenPerson] = await Promise.all([
|
|
||||||
apiUtils.createPerson(admin.accessToken, {
|
|
||||||
name: 'visible_person',
|
name: 'visible_person',
|
||||||
}),
|
}),
|
||||||
apiUtils.createPerson(admin.accessToken, {
|
utils.createPerson(admin.accessToken, {
|
||||||
name: 'hidden_person',
|
name: 'hidden_person',
|
||||||
isHidden: true,
|
isHidden: true,
|
||||||
}),
|
}),
|
||||||
|
utils.createPerson(admin.accessToken, {
|
||||||
|
name: 'multiple_assets_person',
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const asset = await apiUtils.createAsset(admin.accessToken);
|
const asset1 = await utils.createAsset(admin.accessToken);
|
||||||
|
const asset2 = await utils.createAsset(admin.accessToken);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
dbUtils.createFace({ assetId: asset.id, personId: visiblePerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: visiblePerson.id }),
|
||||||
dbUtils.createFace({ assetId: asset.id, personId: hiddenPerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: hiddenPerson.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 }),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -55,9 +65,10 @@ describe('/activity', () => {
|
|||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
total: 2,
|
total: 3,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [
|
people: [
|
||||||
|
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||||
expect.objectContaining({ name: 'visible_person' }),
|
expect.objectContaining({ name: 'visible_person' }),
|
||||||
expect.objectContaining({ name: 'hidden_person' }),
|
expect.objectContaining({ name: 'hidden_person' }),
|
||||||
],
|
],
|
||||||
@ -69,9 +80,12 @@ describe('/activity', () => {
|
|||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
total: 2,
|
total: 3,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [expect.objectContaining({ name: 'visible_person' })],
|
people: [
|
||||||
|
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||||
|
expect.objectContaining({ name: 'visible_person' }),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -103,6 +117,68 @@ describe('/activity', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('GET /person/:id/statistics', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get(`/person/${multipleAssetsPerson.id}/statistics`);
|
||||||
|
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw error if person with id does not exist', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get(`/person/${uuidDto.notFound}/statistics`)
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the correct number of assets', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get(`/person/${multipleAssetsPerson.id}/statistics`)
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual(expect.objectContaining({ assets: 2 }));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST /person', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).post(`/person`);
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const { birthDate, response } of invalidBirthday) {
|
||||||
|
it(`should not accept an invalid birth date [${birthDate}]`, async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post(`/person`)
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({ birthDate });
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(response));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should create a person', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post(`/person`)
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({
|
||||||
|
name: 'New Person',
|
||||||
|
birthDate: '1990-01-01T05:00:00.000Z',
|
||||||
|
});
|
||||||
|
expect(status).toBe(201);
|
||||||
|
expect(body).toMatchObject({
|
||||||
|
id: expect.any(String),
|
||||||
|
name: 'New Person',
|
||||||
|
birthDate: '1990-01-01T05:00:00.000Z',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('PUT /person/:id', () => {
|
describe('PUT /person/:id', () => {
|
||||||
it('should require authentication', async () => {
|
it('should require authentication', async () => {
|
||||||
const { status, body } = await request(app).put(`/person/${uuidDto.notFound}`);
|
const { status, body } = await request(app).put(`/person/${uuidDto.notFound}`);
|
||||||
@ -125,24 +201,16 @@ describe('/activity', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should not accept invalid birth dates', async () => {
|
for (const { birthDate, response } of invalidBirthday) {
|
||||||
for (const { birthDate, response } of [
|
it(`should not accept an invalid birth date [${birthDate}]`, async () => {
|
||||||
{ birthDate: false, response: 'Not found or no person.write access' },
|
|
||||||
{ birthDate: 'false', response: ['birthDate must be a Date instance'] },
|
|
||||||
{
|
|
||||||
birthDate: '123567',
|
|
||||||
response: 'Not found or no person.write access',
|
|
||||||
},
|
|
||||||
{ birthDate: 123_567, response: 'Not found or no person.write access' },
|
|
||||||
]) {
|
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.put(`/person/${uuidDto.notFound}`)
|
.put(`/person/${visiblePerson.id}`)
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
.send({ birthDate });
|
.send({ birthDate });
|
||||||
expect(status).toBe(400);
|
expect(status).toBe(400);
|
||||||
expect(body).toEqual(errorDto.badRequest(response));
|
expect(body).toEqual(errorDto.badRequest(response));
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
it('should update a date of birth', async () => {
|
it('should update a date of birth', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
@ -154,15 +222,8 @@ describe('/activity', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should clear a date of birth', async () => {
|
it('should clear a date of birth', async () => {
|
||||||
// TODO ironically this uses the update endpoint to create the person
|
|
||||||
const person = await apiUtils.createPerson(admin.accessToken, {
|
|
||||||
birthDate: new Date('1990-01-01').toISOString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(person.birthDate).toBeDefined();
|
|
||||||
|
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.put(`/person/${person.id}`)
|
.put(`/person/${visiblePerson.id}`)
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
.send({ birthDate: null });
|
.send({ birthDate: null });
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
|
224
e2e/src/api/specs/search.e2e-spec.ts
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
import { AssetFileUploadResponseDto, LoginResponseDto } from '@immich/sdk';
|
||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
import { Socket } from 'socket.io-client';
|
||||||
|
import { errorDto } from 'src/responses';
|
||||||
|
import { app, testAssetDir, utils } from 'src/utils';
|
||||||
|
import request from 'supertest';
|
||||||
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
const albums = { total: 0, count: 0, items: [], facets: [] };
|
||||||
|
|
||||||
|
describe('/search', () => {
|
||||||
|
let admin: LoginResponseDto;
|
||||||
|
let assetFalcon: AssetFileUploadResponseDto;
|
||||||
|
let assetDenali: AssetFileUploadResponseDto;
|
||||||
|
let websocket: Socket;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await utils.resetDatabase();
|
||||||
|
admin = await utils.adminSetup();
|
||||||
|
websocket = await utils.connectWebsocket(admin.accessToken);
|
||||||
|
|
||||||
|
const files: string[] = [
|
||||||
|
'/albums/nature/prairie_falcon.jpg',
|
||||||
|
'/formats/webp/denali.webp',
|
||||||
|
'/formats/raw/Nikon/D700/philadelphia.nef',
|
||||||
|
'/albums/nature/orychophragmus_violaceus.jpg',
|
||||||
|
'/albums/nature/notocactus_minimus.jpg',
|
||||||
|
'/albums/nature/silver_fir.jpg',
|
||||||
|
'/albums/nature/tanners_ridge.jpg',
|
||||||
|
'/albums/nature/cyclamen_persicum.jpg',
|
||||||
|
'/albums/nature/polemonium_reptans.jpg',
|
||||||
|
'/albums/nature/wood_anemones.jpg',
|
||||||
|
'/formats/heic/IMG_2682.heic',
|
||||||
|
'/formats/jpg/el_torcal_rocks.jpg',
|
||||||
|
'/formats/png/density_plot.png',
|
||||||
|
'/formats/motionphoto/Samsung One UI 6.jpg',
|
||||||
|
'/formats/motionphoto/Samsung One UI 6.heic',
|
||||||
|
'/formats/motionphoto/Samsung One UI 5.jpg',
|
||||||
|
'/formats/raw/Nikon/D80/glarus.nef',
|
||||||
|
'/metadata/gps-position/thompson-springs.jpg',
|
||||||
|
];
|
||||||
|
const assets: AssetFileUploadResponseDto[] = [];
|
||||||
|
for (const filename of files) {
|
||||||
|
const bytes = await readFile(join(testAssetDir, filename));
|
||||||
|
assets.push(
|
||||||
|
await utils.createAsset(admin.accessToken, {
|
||||||
|
deviceAssetId: `test-${filename}`,
|
||||||
|
assetData: { bytes, filename },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const asset of assets) {
|
||||||
|
await utils.waitForWebsocketEvent({ event: 'upload', assetId: asset.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
[assetFalcon, assetDenali] = assets;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await utils.disconnectWebsocket(websocket);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST /search/metadata', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).post('/search/metadata');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should search by camera make', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post('/search/metadata')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({ make: 'Canon' });
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
albums,
|
||||||
|
assets: {
|
||||||
|
count: 2,
|
||||||
|
items: expect.arrayContaining([
|
||||||
|
expect.objectContaining({ id: assetDenali.id }),
|
||||||
|
expect.objectContaining({ id: assetFalcon.id }),
|
||||||
|
]),
|
||||||
|
facets: [],
|
||||||
|
nextPage: null,
|
||||||
|
total: 2,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should search by camera model', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post('/search/metadata')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({ model: 'Canon EOS 7D' });
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
albums,
|
||||||
|
assets: {
|
||||||
|
count: 1,
|
||||||
|
items: [expect.objectContaining({ id: assetDenali.id })],
|
||||||
|
facets: [],
|
||||||
|
nextPage: null,
|
||||||
|
total: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST /search/smart', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).post('/search/smart');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /search/explore', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/search/explore');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get explore data', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/search/explore')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual([
|
||||||
|
{ fieldName: 'exifInfo.city', items: [] },
|
||||||
|
{ fieldName: 'smartInfo.tags', items: [] },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /search/places', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/search/places');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get places', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/search/places?name=Paris')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(Array.isArray(body)).toBe(true);
|
||||||
|
expect(body.length).toBeGreaterThan(10);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /search/suggestions', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/search/suggestions');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get suggestions for country', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/search/suggestions?type=country')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(body).toEqual(['United States of America']);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get suggestions for state', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/search/suggestions?type=state')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(body).toEqual(['Douglas County, Nebraska', 'Mesa County, Colorado']);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get suggestions for city', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/search/suggestions?type=city')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(body).toEqual(['Palisade', 'Ralston']);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get suggestions for camera make', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/search/suggestions?type=camera-make')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(body).toEqual([
|
||||||
|
'Apple',
|
||||||
|
'Canon',
|
||||||
|
'FUJIFILM',
|
||||||
|
'NIKON CORPORATION',
|
||||||
|
'PENTAX Corporation',
|
||||||
|
'samsung',
|
||||||
|
'SONY',
|
||||||
|
]);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get suggestions for camera model', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/search/suggestions?type=camera-model')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(body).toEqual([
|
||||||
|
'Canon EOS 7D',
|
||||||
|
'Canon EOS R5',
|
||||||
|
'DSLR-A550',
|
||||||
|
'FinePix S3Pro',
|
||||||
|
'iPhone 7',
|
||||||
|
'NIKON D700',
|
||||||
|
'NIKON D750',
|
||||||
|
'NIKON D80',
|
||||||
|
'PENTAX K10D',
|
||||||
|
'SM-F711N',
|
||||||
|
'SM-S906U',
|
||||||
|
'SM-T970',
|
||||||
|
]);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,7 +1,7 @@
|
|||||||
import { LoginResponseDto, getServerConfig } from '@immich/sdk';
|
import { LoginResponseDto, getServerConfig } from '@immich/sdk';
|
||||||
import { createUserDto } from 'src/fixtures';
|
import { createUserDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { apiUtils, app, dbUtils } from 'src/utils';
|
import { app, 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';
|
||||||
|
|
||||||
@ -10,10 +10,9 @@ describe('/server-info', () => {
|
|||||||
let nonAdmin: LoginResponseDto;
|
let nonAdmin: LoginResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
admin = await utils.adminSetup({ onboarding: false });
|
||||||
admin = await apiUtils.adminSetup({ onboarding: false });
|
nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user1);
|
||||||
nonAdmin = await apiUtils.userSetup(admin.accessToken, createUserDto.user1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /server-info', () => {
|
describe('GET /server-info', () => {
|
||||||
@ -88,6 +87,7 @@ describe('/server-info', () => {
|
|||||||
loginPageMessage: '',
|
loginPageMessage: '',
|
||||||
oauthButtonText: 'Login with OAuth',
|
oauthButtonText: 'Login with OAuth',
|
||||||
trashDays: 30,
|
trashDays: 30,
|
||||||
|
userDeleteDelay: 7,
|
||||||
isInitialized: true,
|
isInitialized: true,
|
||||||
externalDomain: '',
|
externalDomain: '',
|
||||||
isOnboarded: false,
|
isOnboarded: false,
|
||||||
|
@ -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 { apiUtils, app, asBearerAuth, dbUtils } from 'src/utils';
|
import { app, asBearerAuth, 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';
|
||||||
|
|
||||||
@ -30,20 +30,16 @@ describe('/shared-link', () => {
|
|||||||
let linkWithoutMetadata: SharedLinkResponseDto;
|
let linkWithoutMetadata: SharedLinkResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
|
||||||
|
|
||||||
admin = await apiUtils.adminSetup();
|
admin = await utils.adminSetup();
|
||||||
|
|
||||||
[user1, user2] = await Promise.all([
|
[user1, user2] = await Promise.all([
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user1),
|
utils.userSetup(admin.accessToken, createUserDto.user1),
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user2),
|
utils.userSetup(admin.accessToken, createUserDto.user2),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
[asset1, asset2] = await Promise.all([
|
[asset1, asset2] = await Promise.all([utils.createAsset(user1.accessToken), utils.createAsset(user1.accessToken)]);
|
||||||
apiUtils.createAsset(user1.accessToken),
|
|
||||||
apiUtils.createAsset(user1.accessToken),
|
|
||||||
]);
|
|
||||||
|
|
||||||
[album, deletedAlbum, metadataAlbum] = await Promise.all([
|
[album, deletedAlbum, metadataAlbum] = await Promise.all([
|
||||||
createAlbum({ createAlbumDto: { albumName: 'album' } }, { headers: asBearerAuth(user1.accessToken) }),
|
createAlbum({ createAlbumDto: { albumName: 'album' } }, { headers: asBearerAuth(user1.accessToken) }),
|
||||||
@ -61,29 +57,29 @@ describe('/shared-link', () => {
|
|||||||
|
|
||||||
[linkWithDeletedAlbum, linkWithAlbum, linkWithAssets, linkWithPassword, linkWithMetadata, linkWithoutMetadata] =
|
[linkWithDeletedAlbum, linkWithAlbum, linkWithAssets, linkWithPassword, linkWithMetadata, linkWithoutMetadata] =
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
apiUtils.createSharedLink(user2.accessToken, {
|
utils.createSharedLink(user2.accessToken, {
|
||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
albumId: deletedAlbum.id,
|
albumId: deletedAlbum.id,
|
||||||
}),
|
}),
|
||||||
apiUtils.createSharedLink(user1.accessToken, {
|
utils.createSharedLink(user1.accessToken, {
|
||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
albumId: album.id,
|
albumId: album.id,
|
||||||
}),
|
}),
|
||||||
apiUtils.createSharedLink(user1.accessToken, {
|
utils.createSharedLink(user1.accessToken, {
|
||||||
type: SharedLinkType.Individual,
|
type: SharedLinkType.Individual,
|
||||||
assetIds: [asset1.id],
|
assetIds: [asset1.id],
|
||||||
}),
|
}),
|
||||||
apiUtils.createSharedLink(user1.accessToken, {
|
utils.createSharedLink(user1.accessToken, {
|
||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
albumId: album.id,
|
albumId: album.id,
|
||||||
password: 'foo',
|
password: 'foo',
|
||||||
}),
|
}),
|
||||||
apiUtils.createSharedLink(user1.accessToken, {
|
utils.createSharedLink(user1.accessToken, {
|
||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
albumId: metadataAlbum.id,
|
albumId: metadataAlbum.id,
|
||||||
showMetadata: true,
|
showMetadata: true,
|
||||||
}),
|
}),
|
||||||
apiUtils.createSharedLink(user1.accessToken, {
|
utils.createSharedLink(user1.accessToken, {
|
||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
albumId: metadataAlbum.id,
|
albumId: metadataAlbum.id,
|
||||||
showMetadata: false,
|
showMetadata: false,
|
||||||
@ -194,7 +190,7 @@ describe('/shared-link', () => {
|
|||||||
expect(body.assets).toHaveLength(1);
|
expect(body.assets).toHaveLength(1);
|
||||||
expect(body.assets[0]).toEqual(
|
expect(body.assets[0]).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
originalFileName: 'example',
|
originalFileName: 'example.png',
|
||||||
localDateTime: expect.any(String),
|
localDateTime: expect.any(String),
|
||||||
fileCreatedAt: expect.any(String),
|
fileCreatedAt: expect.any(String),
|
||||||
exifInfo: expect.any(Object),
|
exifInfo: expect.any(Object),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { LoginResponseDto } from '@immich/sdk';
|
import { LoginResponseDto } from '@immich/sdk';
|
||||||
import { createUserDto } from 'src/fixtures';
|
import { createUserDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { apiUtils, app, dbUtils } from 'src/utils';
|
import { app, 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';
|
||||||
|
|
||||||
@ -10,10 +10,9 @@ describe('/system-config', () => {
|
|||||||
let nonAdmin: LoginResponseDto;
|
let nonAdmin: LoginResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
admin = await utils.adminSetup();
|
||||||
admin = await apiUtils.adminSetup();
|
nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user1);
|
||||||
nonAdmin = await apiUtils.userSetup(admin.accessToken, createUserDto.user1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /system-config/map/style.json', () => {
|
describe('GET /system-config/map/style.json', () => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { LoginResponseDto, getAllAssets } from '@immich/sdk';
|
import { LoginResponseDto, getAllAssets } from '@immich/sdk';
|
||||||
import { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { apiUtils, app, asBearerAuth, dbUtils, wsUtils } from 'src/utils';
|
import { app, asBearerAuth, utils } from 'src/utils';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
@ -10,14 +10,13 @@ describe('/trash', () => {
|
|||||||
let ws: Socket;
|
let ws: Socket;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
admin = await utils.adminSetup({ onboarding: false });
|
||||||
admin = await apiUtils.adminSetup({ onboarding: false });
|
ws = await utils.connectWebsocket(admin.accessToken);
|
||||||
ws = await wsUtils.connect(admin.accessToken);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
wsUtils.disconnect(ws);
|
utils.disconnectWebsocket(ws);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /trash/empty', () => {
|
describe('POST /trash/empty', () => {
|
||||||
@ -29,8 +28,8 @@ describe('/trash', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should empty the trash', async () => {
|
it('should empty the trash', async () => {
|
||||||
const { id: assetId } = await apiUtils.createAsset(admin.accessToken);
|
const { id: assetId } = await utils.createAsset(admin.accessToken);
|
||||||
await apiUtils.deleteAssets(admin.accessToken, [assetId]);
|
await utils.deleteAssets(admin.accessToken, [assetId]);
|
||||||
|
|
||||||
const before = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
|
const before = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
|
||||||
|
|
||||||
@ -39,7 +38,7 @@ describe('/trash', () => {
|
|||||||
const { status } = await request(app).post('/trash/empty').set('Authorization', `Bearer ${admin.accessToken}`);
|
const { status } = await request(app).post('/trash/empty').set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
expect(status).toBe(204);
|
expect(status).toBe(204);
|
||||||
|
|
||||||
await wsUtils.waitForEvent({ event: 'delete', assetId });
|
await utils.waitForWebsocketEvent({ event: 'delete', assetId });
|
||||||
|
|
||||||
const after = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
|
const after = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
|
||||||
expect(after.length).toBe(0);
|
expect(after.length).toBe(0);
|
||||||
@ -55,16 +54,16 @@ describe('/trash', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should restore all trashed assets', async () => {
|
it('should restore all trashed assets', async () => {
|
||||||
const { id: assetId } = await apiUtils.createAsset(admin.accessToken);
|
const { id: assetId } = await utils.createAsset(admin.accessToken);
|
||||||
await apiUtils.deleteAssets(admin.accessToken, [assetId]);
|
await utils.deleteAssets(admin.accessToken, [assetId]);
|
||||||
|
|
||||||
const before = await apiUtils.getAssetInfo(admin.accessToken, assetId);
|
const before = await utils.getAssetInfo(admin.accessToken, assetId);
|
||||||
expect(before.isTrashed).toBe(true);
|
expect(before.isTrashed).toBe(true);
|
||||||
|
|
||||||
const { status } = await request(app).post('/trash/restore').set('Authorization', `Bearer ${admin.accessToken}`);
|
const { status } = await request(app).post('/trash/restore').set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
expect(status).toBe(204);
|
expect(status).toBe(204);
|
||||||
|
|
||||||
const after = await apiUtils.getAssetInfo(admin.accessToken, assetId);
|
const after = await utils.getAssetInfo(admin.accessToken, assetId);
|
||||||
expect(after.isTrashed).toBe(false);
|
expect(after.isTrashed).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -78,10 +77,10 @@ describe('/trash', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should restore a trashed asset by id', async () => {
|
it('should restore a trashed asset by id', async () => {
|
||||||
const { id: assetId } = await apiUtils.createAsset(admin.accessToken);
|
const { id: assetId } = await utils.createAsset(admin.accessToken);
|
||||||
await apiUtils.deleteAssets(admin.accessToken, [assetId]);
|
await utils.deleteAssets(admin.accessToken, [assetId]);
|
||||||
|
|
||||||
const before = await apiUtils.getAssetInfo(admin.accessToken, assetId);
|
const before = await utils.getAssetInfo(admin.accessToken, assetId);
|
||||||
expect(before.isTrashed).toBe(true);
|
expect(before.isTrashed).toBe(true);
|
||||||
|
|
||||||
const { status } = await request(app)
|
const { status } = await request(app)
|
||||||
@ -90,7 +89,7 @@ describe('/trash', () => {
|
|||||||
.send({ ids: [assetId] });
|
.send({ ids: [assetId] });
|
||||||
expect(status).toBe(204);
|
expect(status).toBe(204);
|
||||||
|
|
||||||
const after = await apiUtils.getAssetInfo(admin.accessToken, assetId);
|
const after = await utils.getAssetInfo(admin.accessToken, assetId);
|
||||||
expect(after.isTrashed).toBe(false);
|
expect(after.isTrashed).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { LoginResponseDto, deleteUser, getUserById } from '@immich/sdk';
|
import { LoginResponseDto, deleteUser, getUserById } from '@immich/sdk';
|
||||||
import { createUserDto, userDto } from 'src/fixtures';
|
import { createUserDto, userDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
import { apiUtils, app, asBearerAuth, dbUtils } from 'src/utils';
|
import { app, asBearerAuth, 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';
|
||||||
|
|
||||||
@ -12,14 +12,13 @@ describe('/server-info', () => {
|
|||||||
let nonAdmin: LoginResponseDto;
|
let nonAdmin: LoginResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
admin = await utils.adminSetup({ onboarding: false });
|
||||||
admin = await apiUtils.adminSetup({ onboarding: false });
|
|
||||||
|
|
||||||
[deletedUser, nonAdmin, userToDelete] = await Promise.all([
|
[deletedUser, nonAdmin, userToDelete] = await Promise.all([
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user1),
|
utils.userSetup(admin.accessToken, createUserDto.user1),
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user2),
|
utils.userSetup(admin.accessToken, createUserDto.user2),
|
||||||
apiUtils.userSetup(admin.accessToken, createUserDto.user3),
|
utils.userSetup(admin.accessToken, createUserDto.user3),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await deleteUser({ id: deletedUser.userId }, { headers: asBearerAuth(admin.accessToken) });
|
await deleteUser({ id: deletedUser.userId }, { headers: asBearerAuth(admin.accessToken) });
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { stat } from 'node:fs/promises';
|
import { stat } from 'node:fs/promises';
|
||||||
import { apiUtils, app, dbUtils, immichCli } from 'src/utils';
|
import { app, immichCli, utils } from 'src/utils';
|
||||||
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
import { beforeEach, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
describe(`immich login-key`, () => {
|
describe(`immich login-key`, () => {
|
||||||
beforeAll(() => {
|
|
||||||
apiUtils.setup();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await dbUtils.reset();
|
await utils.resetDatabase();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should require a url', async () => {
|
it('should require a url', async () => {
|
||||||
@ -29,12 +25,12 @@ describe(`immich login-key`, () => {
|
|||||||
expect(exitCode).toBe(1);
|
expect(exitCode).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should login', async () => {
|
it('should login and save auth.yml with 600', async () => {
|
||||||
const admin = await apiUtils.adminSetup();
|
const admin = await utils.adminSetup();
|
||||||
const key = await apiUtils.createApiKey(admin.accessToken);
|
const key = await utils.createApiKey(admin.accessToken);
|
||||||
const { stdout, stderr, exitCode } = await immichCli(['login-key', app, `${key.secret}`]);
|
const { stdout, stderr, exitCode } = await immichCli(['login-key', app, `${key.secret}`]);
|
||||||
expect(stdout.split('\n')).toEqual([
|
expect(stdout.split('\n')).toEqual([
|
||||||
'Logging in...',
|
'Logging in to http://127.0.0.1:2283/api',
|
||||||
'Logged in as admin@immich.cloud',
|
'Logged in as admin@immich.cloud',
|
||||||
'Wrote auth info to /tmp/immich/auth.yml',
|
'Wrote auth info to /tmp/immich/auth.yml',
|
||||||
]);
|
]);
|
||||||
@ -45,4 +41,18 @@ describe(`immich login-key`, () => {
|
|||||||
const mode = (stats.mode & 0o777).toString(8);
|
const mode = (stats.mode & 0o777).toString(8);
|
||||||
expect(mode).toEqual('600');
|
expect(mode).toEqual('600');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should login without /api in the url', async () => {
|
||||||
|
const admin = await utils.adminSetup();
|
||||||
|
const key = await utils.createApiKey(admin.accessToken);
|
||||||
|
const { stdout, stderr, exitCode } = await immichCli(['login-key', app.replaceAll('/api', ''), `${key.secret}`]);
|
||||||
|
expect(stdout.split('\n')).toEqual([
|
||||||
|
'Logging in to http://127.0.0.1:2283',
|
||||||
|
'Discovered API at http://127.0.0.1:2283/api',
|
||||||
|
'Logged in as admin@immich.cloud',
|
||||||
|
'Wrote auth info to /tmp/immich/auth.yml',
|
||||||
|
]);
|
||||||
|
expect(stderr).toBe('');
|
||||||
|
expect(exitCode).toBe(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { apiUtils, cliUtils, dbUtils, immichCli } from 'src/utils';
|
import { immichCli, utils } from 'src/utils';
|
||||||
import { beforeAll, describe, expect, it } from 'vitest';
|
import { beforeAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
describe(`immich server-info`, () => {
|
describe(`immich server-info`, () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
await utils.cliLogin();
|
||||||
await cliUtils.login();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the server info', async () => {
|
it('should return the server info', async () => {
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
import { getAllAlbums, getAllAssets } from '@immich/sdk';
|
import { getAllAlbums, getAllAssets } from '@immich/sdk';
|
||||||
import { mkdir, readdir, rm, symlink } from 'node:fs/promises';
|
import { mkdir, readdir, rm, symlink } from 'node:fs/promises';
|
||||||
import { apiUtils, asKeyAuth, cliUtils, dbUtils, immichCli, testAssetDir } from 'src/utils';
|
import { asKeyAuth, immichCli, testAssetDir, utils } from 'src/utils';
|
||||||
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
describe(`immich upload`, () => {
|
describe(`immich upload`, () => {
|
||||||
let key: string;
|
let key: string;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
await utils.resetDatabase();
|
||||||
await dbUtils.reset();
|
key = await utils.cliLogin();
|
||||||
key = await cliUtils.login();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await dbUtils.reset(['assets', 'albums']);
|
await utils.resetDatabase(['assets', 'albums']);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('immich upload --recursive', () => {
|
describe('immich upload --recursive', () => {
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import { apiUtils, immichCli } from 'src/utils';
|
import { immichCli } from 'src/utils';
|
||||||
import { beforeAll, describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
const pkg = JSON.parse(readFileSync('../cli/package.json', 'utf8'));
|
const pkg = JSON.parse(readFileSync('../cli/package.json', 'utf8'));
|
||||||
|
|
||||||
describe(`immich --version`, () => {
|
describe(`immich --version`, () => {
|
||||||
beforeAll(() => {
|
|
||||||
apiUtils.setup();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('immich --version', () => {
|
describe('immich --version', () => {
|
||||||
it('should print the cli version', async () => {
|
it('should print the cli version', async () => {
|
||||||
const { stdout, stderr, exitCode } = await immichCli(['--version']);
|
const { stdout, stderr, exitCode } = await immichCli(['--version']);
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
import { exec, spawn } from 'node:child_process';
|
import { exec, spawn } from 'node:child_process';
|
||||||
|
import { setTimeout } from 'node:timers';
|
||||||
|
|
||||||
export default async () => {
|
export default async () => {
|
||||||
let _resolve: () => unknown;
|
let _resolve: () => unknown;
|
||||||
const ready = new Promise<void>((resolve) => (_resolve = resolve));
|
let _reject: (error: Error) => unknown;
|
||||||
|
|
||||||
|
const ready = new Promise<void>((resolve, reject) => {
|
||||||
|
_resolve = resolve;
|
||||||
|
_reject = reject;
|
||||||
|
});
|
||||||
|
|
||||||
|
const timeout = setTimeout(() => _reject(new Error('Timeout starting e2e environment')), 60_000);
|
||||||
|
|
||||||
const child = spawn('docker', ['compose', 'up'], { stdio: 'pipe' });
|
const child = spawn('docker', ['compose', 'up'], { stdio: 'pipe' });
|
||||||
|
|
||||||
@ -17,6 +25,7 @@ export default async () => {
|
|||||||
child.stderr.on('data', (data) => console.log(data.toString()));
|
child.stderr.on('data', (data) => console.log(data.toString()));
|
||||||
|
|
||||||
await ready;
|
await ready;
|
||||||
|
clearTimeout(timeout);
|
||||||
|
|
||||||
return async () => {
|
return async () => {
|
||||||
await new Promise<void>((resolve) => exec('docker compose down', () => resolve()));
|
await new Promise<void>((resolve) => exec('docker compose down', () => resolve()));
|
||||||
|
283
e2e/src/utils.ts
@ -5,7 +5,7 @@ import {
|
|||||||
CreateAssetDto,
|
CreateAssetDto,
|
||||||
CreateLibraryDto,
|
CreateLibraryDto,
|
||||||
CreateUserDto,
|
CreateUserDto,
|
||||||
PersonUpdateDto,
|
PersonCreateDto,
|
||||||
SharedLinkCreateDto,
|
SharedLinkCreateDto,
|
||||||
ValidateLibraryDto,
|
ValidateLibraryDto,
|
||||||
createAlbum,
|
createAlbum,
|
||||||
@ -20,12 +20,12 @@ import {
|
|||||||
login,
|
login,
|
||||||
setAdminOnboarding,
|
setAdminOnboarding,
|
||||||
signUpAdmin,
|
signUpAdmin,
|
||||||
updatePerson,
|
|
||||||
validate,
|
validate,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { BrowserContext } from '@playwright/test';
|
import { BrowserContext } from '@playwright/test';
|
||||||
import { exec, spawn } from 'node:child_process';
|
import { exec, spawn } from 'node:child_process';
|
||||||
import { access } from 'node:fs/promises';
|
import { createHash } from 'node:crypto';
|
||||||
|
import { existsSync } from 'node:fs';
|
||||||
import { tmpdir } from 'node:os';
|
import { tmpdir } from 'node:os';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { promisify } from 'node:util';
|
import { promisify } from 'node:util';
|
||||||
@ -35,75 +35,71 @@ import { loginDto, signupDto } from 'src/fixtures';
|
|||||||
import { makeRandomImage } from 'src/generators';
|
import { makeRandomImage } from 'src/generators';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
|
|
||||||
const execPromise = promisify(exec);
|
type CliResponse = { stdout: string; stderr: string; exitCode: number | null };
|
||||||
|
type EventType = 'upload' | 'delete';
|
||||||
|
type WaitOptions = { event: EventType; assetId: string; timeout?: number };
|
||||||
|
type AdminSetupOptions = { onboarding?: boolean };
|
||||||
|
type AssetData = { bytes?: Buffer; filename: string };
|
||||||
|
|
||||||
export const app = 'http://127.0.0.1:2283/api';
|
const dbUrl = 'postgres://postgres:postgres@127.0.0.1:5433/immich';
|
||||||
|
const baseUrl = 'http://127.0.0.1:2283';
|
||||||
const directoryExists = (directory: string) =>
|
|
||||||
access(directory)
|
|
||||||
.then(() => true)
|
|
||||||
.catch(() => false);
|
|
||||||
|
|
||||||
|
export const app = `${baseUrl}/api`;
|
||||||
// TODO move test assets into e2e/assets
|
// TODO move test assets into e2e/assets
|
||||||
export const testAssetDir = path.resolve(`./../server/test/assets/`);
|
export const testAssetDir = path.resolve(`./../server/test/assets/`);
|
||||||
export const testAssetDirInternal = '/data/assets';
|
export const testAssetDirInternal = '/data/assets';
|
||||||
export const tempDir = tmpdir();
|
export const tempDir = tmpdir();
|
||||||
|
export const asBearerAuth = (accessToken: string) => ({ Authorization: `Bearer ${accessToken}` });
|
||||||
const serverContainerName = 'immich-e2e-server';
|
|
||||||
const mediaDir = '/usr/src/app/upload';
|
|
||||||
const dirs = [
|
|
||||||
`"${mediaDir}/thumbs"`,
|
|
||||||
`"${mediaDir}/upload"`,
|
|
||||||
`"${mediaDir}/library"`,
|
|
||||||
`"${mediaDir}/encoded-video"`,
|
|
||||||
].join(' ');
|
|
||||||
|
|
||||||
if (!(await directoryExists(`${testAssetDir}/albums`))) {
|
|
||||||
throw new Error(
|
|
||||||
`Test assets not found. Please checkout https://github.com/immich-app/test-assets into ${testAssetDir} before testing`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const asBearerAuth = (accessToken: string) => ({
|
|
||||||
Authorization: `Bearer ${accessToken}`,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const asKeyAuth = (key: string) => ({ 'x-api-key': key });
|
export const asKeyAuth = (key: string) => ({ 'x-api-key': key });
|
||||||
|
export const immichCli = async (args: string[]) => {
|
||||||
|
let _resolve: (value: CliResponse) => void;
|
||||||
|
const deferred = new Promise<CliResponse>((resolve) => (_resolve = resolve));
|
||||||
|
const _args = ['node_modules/.bin/immich', '-d', `/${tempDir}/immich/`, ...args];
|
||||||
|
const child = spawn('node', _args, {
|
||||||
|
stdio: 'pipe',
|
||||||
|
});
|
||||||
|
|
||||||
|
let stdout = '';
|
||||||
|
let stderr = '';
|
||||||
|
|
||||||
|
child.stdout.on('data', (data) => (stdout += data.toString()));
|
||||||
|
child.stderr.on('data', (data) => (stderr += data.toString()));
|
||||||
|
child.on('exit', (exitCode) => {
|
||||||
|
_resolve({
|
||||||
|
stdout: stdout.trim(),
|
||||||
|
stderr: stderr.trim(),
|
||||||
|
exitCode,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return deferred;
|
||||||
|
};
|
||||||
|
|
||||||
let client: pg.Client | null = null;
|
let client: pg.Client | null = null;
|
||||||
|
|
||||||
export const fileUtils = {
|
const events: Record<EventType, Set<string>> = {
|
||||||
reset: async () => {
|
upload: new Set<string>(),
|
||||||
await execPromise(`docker exec -i "${serverContainerName}" /bin/bash -c "rm -rf ${dirs} && mkdir ${dirs}"`);
|
delete: new Set<string>(),
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const dbUtils = {
|
const callbacks: Record<string, () => void> = {};
|
||||||
createFace: async ({ assetId, personId }: { assetId: string; personId: string }) => {
|
|
||||||
if (!client) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const vector = Array.from({ length: 512 }, Math.random);
|
const execPromise = promisify(exec);
|
||||||
const embedding = `[${vector.join(',')}]`;
|
|
||||||
|
|
||||||
await client.query('INSERT INTO asset_faces ("assetId", "personId", "embedding") VALUES ($1, $2, $3)', [
|
const onEvent = ({ event, assetId }: { event: EventType; assetId: string }) => {
|
||||||
assetId,
|
events[event].add(assetId);
|
||||||
personId,
|
const callback = callbacks[assetId];
|
||||||
embedding,
|
if (callback) {
|
||||||
]);
|
callback();
|
||||||
},
|
delete callbacks[assetId];
|
||||||
setPersonThumbnail: async (personId: string) => {
|
}
|
||||||
if (!client) {
|
};
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await client.query(`UPDATE "person" set "thumbnailPath" = '/my/awesome/thumbnail.jpg' where "id" = $1`, [personId]);
|
export const utils = {
|
||||||
},
|
resetDatabase: async (tables?: string[]) => {
|
||||||
reset: async (tables?: string[]) => {
|
|
||||||
try {
|
try {
|
||||||
if (!client) {
|
if (!client) {
|
||||||
client = new pg.Client('postgres://postgres:postgres@127.0.0.1:5433/immich');
|
client = new pg.Client(dbUrl);
|
||||||
await client.connect();
|
await client.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,83 +125,27 @@ export const dbUtils = {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
teardown: async () => {
|
|
||||||
try {
|
resetFilesystem: async () => {
|
||||||
if (client) {
|
const mediaInternal = '/usr/src/app/upload';
|
||||||
await client.end();
|
const dirs = [
|
||||||
client = null;
|
`"${mediaInternal}/thumbs"`,
|
||||||
}
|
`"${mediaInternal}/upload"`,
|
||||||
} catch (error) {
|
`"${mediaInternal}/library"`,
|
||||||
console.error('Failed to teardown database', error);
|
`"${mediaInternal}/encoded-video"`,
|
||||||
throw error;
|
].join(' ');
|
||||||
}
|
|
||||||
|
await execPromise(`docker exec -i "immich-e2e-server" /bin/bash -c "rm -rf ${dirs} && mkdir ${dirs}"`);
|
||||||
},
|
},
|
||||||
};
|
|
||||||
export interface CliResponse {
|
|
||||||
stdout: string;
|
|
||||||
stderr: string;
|
|
||||||
exitCode: number | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const immichCli = async (args: string[]) => {
|
unzip: async (input: string, output: string) => {
|
||||||
let _resolve: (value: CliResponse) => void;
|
await execPromise(`unzip -o -d "${output}" "${input}"`);
|
||||||
const deferred = new Promise<CliResponse>((resolve) => (_resolve = resolve));
|
},
|
||||||
const _args = ['node_modules/.bin/immich', '-d', '/tmp/immich/', ...args];
|
|
||||||
const child = spawn('node', _args, {
|
|
||||||
stdio: 'pipe',
|
|
||||||
});
|
|
||||||
|
|
||||||
let stdout = '';
|
sha1: (bytes: Buffer) => createHash('sha1').update(bytes).digest('base64'),
|
||||||
let stderr = '';
|
|
||||||
|
|
||||||
child.stdout.on('data', (data) => (stdout += data.toString()));
|
connectWebsocket: async (accessToken: string) => {
|
||||||
child.stderr.on('data', (data) => (stderr += data.toString()));
|
const websocket = io(baseUrl, {
|
||||||
child.on('exit', (exitCode) => {
|
|
||||||
_resolve({
|
|
||||||
stdout: stdout.trim(),
|
|
||||||
stderr: stderr.trim(),
|
|
||||||
exitCode,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface AdminSetupOptions {
|
|
||||||
onboarding?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum SocketEvent {
|
|
||||||
UPLOAD = 'upload',
|
|
||||||
DELETE = 'delete',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EventType = 'upload' | 'delete';
|
|
||||||
export interface WaitOptions {
|
|
||||||
event: EventType;
|
|
||||||
assetId: string;
|
|
||||||
timeout?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const events: Record<EventType, Set<string>> = {
|
|
||||||
upload: new Set<string>(),
|
|
||||||
delete: new Set<string>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const callbacks: Record<string, () => void> = {};
|
|
||||||
|
|
||||||
const onEvent = ({ event, assetId }: { event: EventType; assetId: string }) => {
|
|
||||||
events[event].add(assetId);
|
|
||||||
const callback = callbacks[assetId];
|
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
delete callbacks[assetId];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const wsUtils = {
|
|
||||||
connect: async (accessToken: string) => {
|
|
||||||
const websocket = io('http://127.0.0.1:2283', {
|
|
||||||
path: '/api/socket.io',
|
path: '/api/socket.io',
|
||||||
transports: ['websocket'],
|
transports: ['websocket'],
|
||||||
extraHeaders: { Authorization: `Bearer ${accessToken}` },
|
extraHeaders: { Authorization: `Bearer ${accessToken}` },
|
||||||
@ -221,7 +161,8 @@ export const wsUtils = {
|
|||||||
.connect();
|
.connect();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
disconnect: (ws: Socket) => {
|
|
||||||
|
disconnectWebsocket: (ws: Socket) => {
|
||||||
if (ws?.connected) {
|
if (ws?.connected) {
|
||||||
ws.disconnect();
|
ws.disconnect();
|
||||||
}
|
}
|
||||||
@ -230,14 +171,16 @@ export const wsUtils = {
|
|||||||
set.clear();
|
set.clear();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
waitForEvent: async ({ event, assetId, timeout: ms }: WaitOptions): Promise<void> => {
|
|
||||||
|
waitForWebsocketEvent: async ({ event, assetId, timeout: ms }: WaitOptions): Promise<void> => {
|
||||||
|
console.log(`Waiting for ${event} [${assetId}]`);
|
||||||
const set = events[event];
|
const set = events[event];
|
||||||
if (set.has(assetId)) {
|
if (set.has(assetId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const timeout = setTimeout(() => reject(new Error(`Timed out waiting for ${event} event`)), ms || 5000);
|
const timeout = setTimeout(() => reject(new Error(`Timed out waiting for ${event} event`)), ms || 10_000);
|
||||||
|
|
||||||
callbacks[assetId] = () => {
|
callbacks[assetId] = () => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
@ -245,12 +188,8 @@ export const wsUtils = {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
|
||||||
type AssetData = { bytes?: Buffer; filename: string };
|
setApiEndpoint: () => {
|
||||||
|
|
||||||
export const apiUtils = {
|
|
||||||
setup: () => {
|
|
||||||
defaults.baseUrl = app;
|
defaults.baseUrl = app;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -264,17 +203,21 @@ export const apiUtils = {
|
|||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
|
|
||||||
userSetup: async (accessToken: string, dto: CreateUserDto) => {
|
userSetup: async (accessToken: string, dto: CreateUserDto) => {
|
||||||
await createUser({ createUserDto: dto }, { headers: asBearerAuth(accessToken) });
|
await createUser({ createUserDto: dto }, { headers: asBearerAuth(accessToken) });
|
||||||
return login({
|
return login({
|
||||||
loginCredentialDto: { email: dto.email, password: dto.password },
|
loginCredentialDto: { email: dto.email, password: dto.password },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
createApiKey: (accessToken: string) => {
|
createApiKey: (accessToken: string) => {
|
||||||
return createApiKey({ apiKeyCreateDto: { name: 'e2e' } }, { headers: asBearerAuth(accessToken) });
|
return createApiKey({ apiKeyCreateDto: { name: 'e2e' } }, { headers: asBearerAuth(accessToken) });
|
||||||
},
|
},
|
||||||
|
|
||||||
createAlbum: (accessToken: string, dto: CreateAlbumDto) =>
|
createAlbum: (accessToken: string, dto: CreateAlbumDto) =>
|
||||||
createAlbum({ createAlbumDto: dto }, { headers: asBearerAuth(accessToken) }),
|
createAlbum({ createAlbumDto: dto }, { headers: asBearerAuth(accessToken) }),
|
||||||
|
|
||||||
createAsset: async (
|
createAsset: async (
|
||||||
accessToken: string,
|
accessToken: string,
|
||||||
dto?: Partial<Omit<CreateAssetDto, 'assetData'>> & { assetData?: AssetData },
|
dto?: Partial<Omit<CreateAssetDto, 'assetData'>> & { assetData?: AssetData },
|
||||||
@ -290,6 +233,10 @@ export const apiUtils = {
|
|||||||
const assetData = dto?.assetData?.bytes || makeRandomImage();
|
const assetData = dto?.assetData?.bytes || makeRandomImage();
|
||||||
const filename = dto?.assetData?.filename || 'example.png';
|
const filename = dto?.assetData?.filename || 'example.png';
|
||||||
|
|
||||||
|
if (dto?.assetData?.bytes) {
|
||||||
|
console.log(`Uploading ${filename}`);
|
||||||
|
}
|
||||||
|
|
||||||
const builder = request(app)
|
const builder = request(app)
|
||||||
.post(`/asset/upload`)
|
.post(`/asset/upload`)
|
||||||
.attach('assetData', assetData, filename)
|
.attach('assetData', assetData, filename)
|
||||||
@ -303,38 +250,51 @@ export const apiUtils = {
|
|||||||
|
|
||||||
return body as AssetFileUploadResponseDto;
|
return body as AssetFileUploadResponseDto;
|
||||||
},
|
},
|
||||||
|
|
||||||
getAssetInfo: (accessToken: string, id: string) => getAssetInfo({ id }, { headers: asBearerAuth(accessToken) }),
|
getAssetInfo: (accessToken: string, id: string) => getAssetInfo({ id }, { headers: asBearerAuth(accessToken) }),
|
||||||
|
|
||||||
deleteAssets: (accessToken: string, ids: string[]) =>
|
deleteAssets: (accessToken: string, ids: string[]) =>
|
||||||
deleteAssets({ assetBulkDeleteDto: { ids } }, { headers: asBearerAuth(accessToken) }),
|
deleteAssets({ assetBulkDeleteDto: { ids } }, { headers: asBearerAuth(accessToken) }),
|
||||||
createPerson: async (accessToken: string, dto?: PersonUpdateDto) => {
|
|
||||||
// TODO fix createPerson to accept a body
|
|
||||||
const person = await createPerson({ headers: asBearerAuth(accessToken) });
|
|
||||||
await dbUtils.setPersonThumbnail(person.id);
|
|
||||||
|
|
||||||
if (!dto) {
|
createPerson: async (accessToken: string, dto?: PersonCreateDto) => {
|
||||||
return person;
|
const person = await createPerson({ personCreateDto: dto || {} }, { headers: asBearerAuth(accessToken) });
|
||||||
|
await utils.setPersonThumbnail(person.id);
|
||||||
|
|
||||||
|
return person;
|
||||||
|
},
|
||||||
|
|
||||||
|
createFace: async ({ assetId, personId }: { assetId: string; personId: string }) => {
|
||||||
|
if (!client) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return updatePerson({ id: person.id, personUpdateDto: dto }, { headers: asBearerAuth(accessToken) });
|
const vector = Array.from({ length: 512 }, Math.random);
|
||||||
|
const embedding = `[${vector.join(',')}]`;
|
||||||
|
|
||||||
|
await client.query('INSERT INTO asset_faces ("assetId", "personId", "embedding") VALUES ($1, $2, $3)', [
|
||||||
|
assetId,
|
||||||
|
personId,
|
||||||
|
embedding,
|
||||||
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setPersonThumbnail: async (personId: string) => {
|
||||||
|
if (!client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.query(`UPDATE "person" set "thumbnailPath" = '/my/awesome/thumbnail.jpg' where "id" = $1`, [personId]);
|
||||||
|
},
|
||||||
|
|
||||||
createSharedLink: (accessToken: string, dto: SharedLinkCreateDto) =>
|
createSharedLink: (accessToken: string, dto: SharedLinkCreateDto) =>
|
||||||
createSharedLink({ sharedLinkCreateDto: dto }, { headers: asBearerAuth(accessToken) }),
|
createSharedLink({ sharedLinkCreateDto: dto }, { headers: asBearerAuth(accessToken) }),
|
||||||
|
|
||||||
createLibrary: (accessToken: string, dto: CreateLibraryDto) =>
|
createLibrary: (accessToken: string, dto: CreateLibraryDto) =>
|
||||||
createLibrary({ createLibraryDto: dto }, { headers: asBearerAuth(accessToken) }),
|
createLibrary({ createLibraryDto: dto }, { headers: asBearerAuth(accessToken) }),
|
||||||
|
|
||||||
validateLibrary: (accessToken: string, id: string, dto: ValidateLibraryDto) =>
|
validateLibrary: (accessToken: string, id: string, dto: ValidateLibraryDto) =>
|
||||||
validate({ id, validateLibraryDto: dto }, { headers: asBearerAuth(accessToken) }),
|
validate({ id, validateLibraryDto: dto }, { headers: asBearerAuth(accessToken) }),
|
||||||
};
|
|
||||||
|
|
||||||
export const cliUtils = {
|
|
||||||
login: async () => {
|
|
||||||
const admin = await apiUtils.adminSetup();
|
|
||||||
const key = await apiUtils.createApiKey(admin.accessToken);
|
|
||||||
await immichCli(['login-key', app, `${key.secret}`]);
|
|
||||||
return key.secret;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const webUtils = {
|
|
||||||
setAuthCookies: async (context: BrowserContext, accessToken: string) =>
|
setAuthCookies: async (context: BrowserContext, accessToken: string) =>
|
||||||
await context.addCookies([
|
await context.addCookies([
|
||||||
{
|
{
|
||||||
@ -368,4 +328,19 @@ export const webUtils = {
|
|||||||
sameSite: 'Lax',
|
sameSite: 'Lax',
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
cliLogin: async () => {
|
||||||
|
const admin = await utils.adminSetup();
|
||||||
|
const key = await utils.createApiKey(admin.accessToken);
|
||||||
|
await immichCli(['login-key', app, `${key.secret}`]);
|
||||||
|
return key.secret;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
utils.setApiEndpoint();
|
||||||
|
|
||||||
|
if (!existsSync(`${testAssetDir}/albums`)) {
|
||||||
|
throw new Error(
|
||||||
|
`Test assets not found. Please checkout https://github.com/immich-app/test-assets into ${testAssetDir} before testing`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
import { expect, test } from '@playwright/test';
|
import { expect, test } from '@playwright/test';
|
||||||
import { apiUtils, dbUtils, webUtils } from 'src/utils';
|
import { utils } from 'src/utils';
|
||||||
|
|
||||||
test.describe('Registration', () => {
|
test.describe('Registration', () => {
|
||||||
test.beforeAll(() => {
|
test.beforeAll(() => {
|
||||||
apiUtils.setup();
|
utils.setApiEndpoint();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
await dbUtils.reset();
|
await utils.resetDatabase();
|
||||||
});
|
|
||||||
|
|
||||||
test.afterAll(async () => {
|
|
||||||
await dbUtils.teardown();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('admin registration', async ({ page }) => {
|
test('admin registration', async ({ page }) => {
|
||||||
@ -45,8 +41,8 @@ test.describe('Registration', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('user registration', async ({ context, page }) => {
|
test('user registration', async ({ context, page }) => {
|
||||||
const admin = await apiUtils.adminSetup();
|
const admin = await utils.adminSetup();
|
||||||
await webUtils.setAuthCookies(context, admin.accessToken);
|
await utils.setAuthCookies(context, admin.accessToken);
|
||||||
|
|
||||||
// create user
|
// create user
|
||||||
await page.goto('/admin/user-management');
|
await page.goto('/admin/user-management');
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
createAlbum,
|
createAlbum,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { test } from '@playwright/test';
|
import { test } from '@playwright/test';
|
||||||
import { apiUtils, asBearerAuth, dbUtils } from 'src/utils';
|
import { asBearerAuth, utils } from 'src/utils';
|
||||||
|
|
||||||
test.describe('Shared Links', () => {
|
test.describe('Shared Links', () => {
|
||||||
let admin: LoginResponseDto;
|
let admin: LoginResponseDto;
|
||||||
@ -17,10 +17,10 @@ test.describe('Shared Links', () => {
|
|||||||
let sharedLinkPassword: SharedLinkResponseDto;
|
let sharedLinkPassword: SharedLinkResponseDto;
|
||||||
|
|
||||||
test.beforeAll(async () => {
|
test.beforeAll(async () => {
|
||||||
apiUtils.setup();
|
utils.setApiEndpoint();
|
||||||
await dbUtils.reset();
|
await utils.resetDatabase();
|
||||||
admin = await apiUtils.adminSetup();
|
admin = await utils.adminSetup();
|
||||||
asset = await apiUtils.createAsset(admin.accessToken);
|
asset = await utils.createAsset(admin.accessToken);
|
||||||
album = await createAlbum(
|
album = await createAlbum(
|
||||||
{
|
{
|
||||||
createAlbumDto: {
|
createAlbumDto: {
|
||||||
@ -30,21 +30,17 @@ test.describe('Shared Links', () => {
|
|||||||
},
|
},
|
||||||
{ headers: asBearerAuth(admin.accessToken) },
|
{ headers: asBearerAuth(admin.accessToken) },
|
||||||
);
|
);
|
||||||
sharedLink = await apiUtils.createSharedLink(admin.accessToken, {
|
sharedLink = await utils.createSharedLink(admin.accessToken, {
|
||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
albumId: album.id,
|
albumId: album.id,
|
||||||
});
|
});
|
||||||
sharedLinkPassword = await apiUtils.createSharedLink(admin.accessToken, {
|
sharedLinkPassword = await utils.createSharedLink(admin.accessToken, {
|
||||||
type: SharedLinkType.Album,
|
type: SharedLinkType.Album,
|
||||||
albumId: album.id,
|
albumId: album.id,
|
||||||
password: 'test-password',
|
password: 'test-password',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterAll(async () => {
|
|
||||||
await dbUtils.teardown();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('download from a shared link', async ({ page }) => {
|
test('download from a shared link', async ({ page }) => {
|
||||||
await page.goto(`/share/${sharedLink.key}`);
|
await page.goto(`/share/${sharedLink.key}`);
|
||||||
await page.getByRole('heading', { name: 'Test Album' }).waitFor();
|
await page.getByRole('heading', { name: 'Test Album' }).waitFor();
|
||||||
|
@ -12,6 +12,7 @@ export default defineConfig({
|
|||||||
test: {
|
test: {
|
||||||
include: ['src/{api,cli}/specs/*.e2e-spec.ts'],
|
include: ['src/{api,cli}/specs/*.e2e-spec.ts'],
|
||||||
globalSetup,
|
globalSetup,
|
||||||
|
testTimeout: 10_000,
|
||||||
poolOptions: {
|
poolOptions: {
|
||||||
threads: {
|
threads: {
|
||||||
singleThread: true,
|
singleThread: true,
|
||||||
|
6
machine-learning/.gitignore
vendored
@ -167,6 +167,10 @@ cython_debug/
|
|||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
# VS Code
|
||||||
|
.vscode
|
||||||
|
|
||||||
*.onnx
|
*.onnx
|
||||||
*.zip
|
*.zip
|
||||||
|
|
||||||
|
core
|
@ -39,7 +39,7 @@ FROM python:3.11-slim-bookworm@sha256:ce81dc539f0aedc9114cae640f8352fad83d37461c
|
|||||||
FROM openvino/ubuntu22_runtime:2023.1.0@sha256:002842a9005ba01543b7169ff6f14ecbec82287f09c4d1dd37717f0a8e8754a7 as prod-openvino
|
FROM openvino/ubuntu22_runtime:2023.1.0@sha256:002842a9005ba01543b7169ff6f14ecbec82287f09c4d1dd37717f0a8e8754a7 as prod-openvino
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
FROM nvidia/cuda:12.2.2-cudnn8-runtime-ubuntu22.04@sha256:8b51b1fe922964d73c482a267b5b519e990d90bf744ec7a40419923737caff6d as prod-cuda
|
FROM nvidia/cuda:12.2.2-cudnn8-runtime-ubuntu22.04@sha256:2d913b09e6be8387e1a10976933642c73c840c0b735f0bf3c28d97fc9bc422e0 as prod-cuda
|
||||||
|
|
||||||
COPY --from=builder-cuda /usr/local/bin/python3 /usr/local/bin/python3
|
COPY --from=builder-cuda /usr/local/bin/python3 /usr/local/bin/python3
|
||||||
COPY --from=builder-cuda /usr/local/lib/python3.11 /usr/local/lib/python3.11
|
COPY --from=builder-cuda /usr/local/lib/python3.11 /usr/local/lib/python3.11
|
||||||
|
@ -6,7 +6,7 @@ from pathlib import Path
|
|||||||
from socket import socket
|
from socket import socket
|
||||||
|
|
||||||
from gunicorn.arbiter import Arbiter
|
from gunicorn.arbiter import Arbiter
|
||||||
from pydantic import BaseSettings
|
from pydantic import BaseModel, BaseSettings
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.logging import RichHandler
|
from rich.logging import RichHandler
|
||||||
from uvicorn import Server
|
from uvicorn import Server
|
||||||
@ -15,6 +15,11 @@ from uvicorn.workers import UvicornWorker
|
|||||||
from .schemas import ModelType
|
from .schemas import ModelType
|
||||||
|
|
||||||
|
|
||||||
|
class PreloadModelData(BaseModel):
|
||||||
|
clip: str | None
|
||||||
|
facial_recognition: str | None
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
cache_folder: str = "/cache"
|
cache_folder: str = "/cache"
|
||||||
model_ttl: int = 300
|
model_ttl: int = 300
|
||||||
@ -27,10 +32,12 @@ class Settings(BaseSettings):
|
|||||||
model_inter_op_threads: int = 0
|
model_inter_op_threads: int = 0
|
||||||
model_intra_op_threads: int = 0
|
model_intra_op_threads: int = 0
|
||||||
ann: bool = True
|
ann: bool = True
|
||||||
|
preload: PreloadModelData | None = None
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
env_prefix = "MACHINE_LEARNING_"
|
env_prefix = "MACHINE_LEARNING_"
|
||||||
case_sensitive = False
|
case_sensitive = False
|
||||||
|
env_nested_delimiter = "__"
|
||||||
|
|
||||||
|
|
||||||
class LogSettings(BaseSettings):
|
class LogSettings(BaseSettings):
|
||||||
|
@ -17,7 +17,7 @@ from starlette.formparsers import MultiPartParser
|
|||||||
|
|
||||||
from app.models.base import InferenceModel
|
from app.models.base import InferenceModel
|
||||||
|
|
||||||
from .config import log, settings
|
from .config import PreloadModelData, log, settings
|
||||||
from .models.cache import ModelCache
|
from .models.cache import ModelCache
|
||||||
from .schemas import (
|
from .schemas import (
|
||||||
MessageResponse,
|
MessageResponse,
|
||||||
@ -27,7 +27,7 @@ from .schemas import (
|
|||||||
|
|
||||||
MultiPartParser.max_file_size = 2**26 # spools to disk if payload is 64 MiB or larger
|
MultiPartParser.max_file_size = 2**26 # spools to disk if payload is 64 MiB or larger
|
||||||
|
|
||||||
model_cache = ModelCache(ttl=settings.model_ttl, revalidate=settings.model_ttl > 0)
|
model_cache = ModelCache(revalidate=settings.model_ttl > 0)
|
||||||
thread_pool: ThreadPoolExecutor | None = None
|
thread_pool: ThreadPoolExecutor | None = None
|
||||||
lock = threading.Lock()
|
lock = threading.Lock()
|
||||||
active_requests = 0
|
active_requests = 0
|
||||||
@ -51,6 +51,8 @@ async def lifespan(_: FastAPI) -> AsyncGenerator[None, None]:
|
|||||||
log.info(f"Initialized request thread pool with {settings.request_threads} threads.")
|
log.info(f"Initialized request thread pool with {settings.request_threads} threads.")
|
||||||
if settings.model_ttl > 0 and settings.model_ttl_poll_s > 0:
|
if settings.model_ttl > 0 and settings.model_ttl_poll_s > 0:
|
||||||
asyncio.ensure_future(idle_shutdown_task())
|
asyncio.ensure_future(idle_shutdown_task())
|
||||||
|
if settings.preload is not None:
|
||||||
|
await preload_models(settings.preload)
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
log.handlers.clear()
|
log.handlers.clear()
|
||||||
@ -61,6 +63,14 @@ async def lifespan(_: FastAPI) -> AsyncGenerator[None, None]:
|
|||||||
gc.collect()
|
gc.collect()
|
||||||
|
|
||||||
|
|
||||||
|
async def preload_models(preload_models: PreloadModelData) -> None:
|
||||||
|
log.info(f"Preloading models: {preload_models}")
|
||||||
|
if preload_models.clip is not None:
|
||||||
|
await load(await model_cache.get(preload_models.clip, ModelType.CLIP))
|
||||||
|
if preload_models.facial_recognition is not None:
|
||||||
|
await load(await model_cache.get(preload_models.facial_recognition, ModelType.FACIAL_RECOGNITION))
|
||||||
|
|
||||||
|
|
||||||
def update_state() -> Iterator[None]:
|
def update_state() -> Iterator[None]:
|
||||||
global active_requests, last_called
|
global active_requests, last_called
|
||||||
active_requests += 1
|
active_requests += 1
|
||||||
@ -103,7 +113,7 @@ async def predict(
|
|||||||
except orjson.JSONDecodeError:
|
except orjson.JSONDecodeError:
|
||||||
raise HTTPException(400, f"Invalid options JSON: {options}")
|
raise HTTPException(400, f"Invalid options JSON: {options}")
|
||||||
|
|
||||||
model = await load(await model_cache.get(model_name, model_type, **kwargs))
|
model = await load(await model_cache.get(model_name, model_type, ttl=settings.model_ttl, **kwargs))
|
||||||
model.configure(**kwargs)
|
model.configure(**kwargs)
|
||||||
outputs = await run(model.predict, inputs)
|
outputs = await run(model.predict, inputs)
|
||||||
return ORJSONResponse(outputs)
|
return ORJSONResponse(outputs)
|
||||||
|
@ -2,7 +2,7 @@ from typing import Any
|
|||||||
|
|
||||||
from aiocache.backends.memory import SimpleMemoryCache
|
from aiocache.backends.memory import SimpleMemoryCache
|
||||||
from aiocache.lock import OptimisticLock
|
from aiocache.lock import OptimisticLock
|
||||||
from aiocache.plugins import BasePlugin, TimingPlugin
|
from aiocache.plugins import TimingPlugin
|
||||||
|
|
||||||
from app.models import from_model_type
|
from app.models import from_model_type
|
||||||
|
|
||||||
@ -15,28 +15,25 @@ class ModelCache:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
ttl: float | None = None,
|
|
||||||
revalidate: bool = False,
|
revalidate: bool = False,
|
||||||
timeout: int | None = None,
|
timeout: int | None = None,
|
||||||
profiling: bool = False,
|
profiling: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
ttl: Unloads model after this duration. Disabled if None. Defaults to None.
|
|
||||||
revalidate: Resets TTL on cache hit. Useful to keep models in memory while active. Defaults to False.
|
revalidate: Resets TTL on cache hit. Useful to keep models in memory while active. Defaults to False.
|
||||||
timeout: Maximum allowed time for model to load. Disabled if None. Defaults to None.
|
timeout: Maximum allowed time for model to load. Disabled if None. Defaults to None.
|
||||||
profiling: Collects metrics for cache operations, adding slight overhead. Defaults to False.
|
profiling: Collects metrics for cache operations, adding slight overhead. Defaults to False.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.ttl = ttl
|
|
||||||
plugins = []
|
plugins = []
|
||||||
|
|
||||||
if revalidate:
|
|
||||||
plugins.append(RevalidationPlugin())
|
|
||||||
if profiling:
|
if profiling:
|
||||||
plugins.append(TimingPlugin())
|
plugins.append(TimingPlugin())
|
||||||
|
|
||||||
self.cache = SimpleMemoryCache(ttl=ttl, timeout=timeout, plugins=plugins, namespace=None)
|
self.revalidate_enable = revalidate
|
||||||
|
|
||||||
|
self.cache = SimpleMemoryCache(timeout=timeout, plugins=plugins, namespace=None)
|
||||||
|
|
||||||
async def get(self, model_name: str, model_type: ModelType, **model_kwargs: Any) -> InferenceModel:
|
async def get(self, model_name: str, model_type: ModelType, **model_kwargs: Any) -> InferenceModel:
|
||||||
"""
|
"""
|
||||||
@ -49,11 +46,14 @@ class ModelCache:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
key = f"{model_name}{model_type.value}{model_kwargs.get('mode', '')}"
|
key = f"{model_name}{model_type.value}{model_kwargs.get('mode', '')}"
|
||||||
|
|
||||||
async with OptimisticLock(self.cache, key) as lock:
|
async with OptimisticLock(self.cache, key) as lock:
|
||||||
model: InferenceModel | None = await self.cache.get(key)
|
model: InferenceModel | None = await self.cache.get(key)
|
||||||
if model is None:
|
if model is None:
|
||||||
model = from_model_type(model_type, model_name, **model_kwargs)
|
model = from_model_type(model_type, model_name, **model_kwargs)
|
||||||
await lock.cas(model, ttl=self.ttl)
|
await lock.cas(model, ttl=model_kwargs.get("ttl", None))
|
||||||
|
elif self.revalidate_enable:
|
||||||
|
await self.revalidate(key, model_kwargs.get("ttl", None))
|
||||||
return model
|
return model
|
||||||
|
|
||||||
async def get_profiling(self) -> dict[str, float] | None:
|
async def get_profiling(self) -> dict[str, float] | None:
|
||||||
@ -62,21 +62,6 @@ class ModelCache:
|
|||||||
|
|
||||||
return self.cache.profiling
|
return self.cache.profiling
|
||||||
|
|
||||||
|
async def revalidate(self, key: str, ttl: int | None) -> None:
|
||||||
class RevalidationPlugin(BasePlugin): # type: ignore[misc]
|
if ttl is not None and key in self.cache._handlers:
|
||||||
"""Revalidates cache item's TTL after cache hit."""
|
await self.cache.expire(key, ttl)
|
||||||
|
|
||||||
async def post_get(
|
|
||||||
self,
|
|
||||||
client: SimpleMemoryCache,
|
|
||||||
key: str,
|
|
||||||
ret: Any | None = None,
|
|
||||||
namespace: str | None = None,
|
|
||||||
**kwargs: Any,
|
|
||||||
) -> None:
|
|
||||||
if ret is None:
|
|
||||||
return
|
|
||||||
if namespace is not None:
|
|
||||||
key = client.build_key(key, namespace)
|
|
||||||
if key in client._handlers:
|
|
||||||
await client.expire(key, client.ttl)
|
|
||||||
|
@ -13,11 +13,12 @@ import onnxruntime as ort
|
|||||||
import pytest
|
import pytest
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
from pytest import MonkeyPatch
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
|
|
||||||
from app.main import load
|
from app.main import load, preload_models
|
||||||
|
|
||||||
from .config import log, settings
|
from .config import Settings, log, settings
|
||||||
from .models.base import InferenceModel
|
from .models.base import InferenceModel
|
||||||
from .models.cache import ModelCache
|
from .models.cache import ModelCache
|
||||||
from .models.clip import MCLIPEncoder, OpenCLIPEncoder
|
from .models.clip import MCLIPEncoder, OpenCLIPEncoder
|
||||||
@ -509,20 +510,20 @@ class TestCache:
|
|||||||
|
|
||||||
@mock.patch("app.models.cache.OptimisticLock", autospec=True)
|
@mock.patch("app.models.cache.OptimisticLock", autospec=True)
|
||||||
async def test_model_ttl(self, mock_lock_cls: mock.Mock, mock_get_model: mock.Mock) -> None:
|
async def test_model_ttl(self, mock_lock_cls: mock.Mock, mock_get_model: mock.Mock) -> None:
|
||||||
model_cache = ModelCache(ttl=100)
|
model_cache = ModelCache()
|
||||||
await model_cache.get("test_model_name", ModelType.FACIAL_RECOGNITION)
|
await model_cache.get("test_model_name", ModelType.FACIAL_RECOGNITION, ttl=100)
|
||||||
mock_lock_cls.return_value.__aenter__.return_value.cas.assert_called_with(mock.ANY, ttl=100)
|
mock_lock_cls.return_value.__aenter__.return_value.cas.assert_called_with(mock.ANY, ttl=100)
|
||||||
|
|
||||||
@mock.patch("app.models.cache.SimpleMemoryCache.expire")
|
@mock.patch("app.models.cache.SimpleMemoryCache.expire")
|
||||||
async def test_revalidate_get(self, mock_cache_expire: mock.Mock, mock_get_model: mock.Mock) -> None:
|
async def test_revalidate_get(self, mock_cache_expire: mock.Mock, mock_get_model: mock.Mock) -> None:
|
||||||
model_cache = ModelCache(ttl=100, revalidate=True)
|
model_cache = ModelCache(revalidate=True)
|
||||||
await model_cache.get("test_model_name", ModelType.FACIAL_RECOGNITION)
|
await model_cache.get("test_model_name", ModelType.FACIAL_RECOGNITION, ttl=100)
|
||||||
await model_cache.get("test_model_name", ModelType.FACIAL_RECOGNITION)
|
await model_cache.get("test_model_name", ModelType.FACIAL_RECOGNITION, ttl=100)
|
||||||
mock_cache_expire.assert_called_once_with(mock.ANY, 100)
|
mock_cache_expire.assert_called_once_with(mock.ANY, 100)
|
||||||
|
|
||||||
async def test_profiling(self, mock_get_model: mock.Mock) -> None:
|
async def test_profiling(self, mock_get_model: mock.Mock) -> None:
|
||||||
model_cache = ModelCache(ttl=100, profiling=True)
|
model_cache = ModelCache(profiling=True)
|
||||||
await model_cache.get("test_model_name", ModelType.FACIAL_RECOGNITION)
|
await model_cache.get("test_model_name", ModelType.FACIAL_RECOGNITION, ttl=100)
|
||||||
profiling = await model_cache.get_profiling()
|
profiling = await model_cache.get_profiling()
|
||||||
assert isinstance(profiling, dict)
|
assert isinstance(profiling, dict)
|
||||||
assert profiling == model_cache.cache.profiling
|
assert profiling == model_cache.cache.profiling
|
||||||
@ -548,6 +549,25 @@ class TestCache:
|
|||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
await model_cache.get("test_model_name", ModelType.CLIP, mode="text")
|
await model_cache.get("test_model_name", ModelType.CLIP, mode="text")
|
||||||
|
|
||||||
|
async def test_preloads_models(self, monkeypatch: MonkeyPatch, mock_get_model: mock.Mock) -> None:
|
||||||
|
os.environ["MACHINE_LEARNING_PRELOAD__CLIP"] = "ViT-B-32__openai"
|
||||||
|
os.environ["MACHINE_LEARNING_PRELOAD__FACIAL_RECOGNITION"] = "buffalo_s"
|
||||||
|
|
||||||
|
settings = Settings()
|
||||||
|
assert settings.preload is not None
|
||||||
|
assert settings.preload.clip == "ViT-B-32__openai"
|
||||||
|
assert settings.preload.facial_recognition == "buffalo_s"
|
||||||
|
|
||||||
|
model_cache = ModelCache()
|
||||||
|
monkeypatch.setattr("app.main.model_cache", model_cache)
|
||||||
|
|
||||||
|
await preload_models(settings.preload)
|
||||||
|
assert len(model_cache.cache._cache) == 2
|
||||||
|
assert mock_get_model.call_count == 2
|
||||||
|
await model_cache.get("ViT-B-32__openai", ModelType.CLIP, ttl=100)
|
||||||
|
await model_cache.get("buffalo_s", ModelType.FACIAL_RECOGNITION, ttl=100)
|
||||||
|
assert mock_get_model.call_count == 2
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
class TestLoad:
|
class TestLoad:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM mambaorg/micromamba:bookworm-slim@sha256:6038b89363c9181215f3d9e8ce2720c880e224537f4028a854482e43a9b4998a as builder
|
FROM mambaorg/micromamba:bookworm-slim@sha256:96586e238e2fed914b839e50cf91943b5655262348d141466b34ced2e0b5b155 as builder
|
||||||
|
|
||||||
ENV NODE_ENV=production \
|
ENV NODE_ENV=production \
|
||||||
TRANSFORMERS_CACHE=/cache \
|
TRANSFORMERS_CACHE=/cache \
|
||||||
|
117
machine-learning/poetry.lock
generated
@ -680,13 +680,13 @@ test = ["pytest (>=6)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastapi"
|
name = "fastapi"
|
||||||
version = "0.109.2"
|
version = "0.110.0"
|
||||||
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "fastapi-0.109.2-py3-none-any.whl", hash = "sha256:2c9bab24667293b501cad8dd388c05240c850b58ec5876ee3283c47d6e1e3a4d"},
|
{file = "fastapi-0.110.0-py3-none-any.whl", hash = "sha256:87a1f6fb632a218222c5984be540055346a8f5d8a68e8f6fb647b1dc9934de4b"},
|
||||||
{file = "fastapi-0.109.2.tar.gz", hash = "sha256:f3817eac96fe4f65a2ebb4baa000f394e55f5fccdaf7f75250804bc58f354f73"},
|
{file = "fastapi-0.110.0.tar.gz", hash = "sha256:266775f0dcc95af9d3ef39bad55cff525329a931d5fd51930aadd4f428bf7ff3"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -1274,13 +1274,13 @@ socks = ["socksio (==1.*)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "huggingface-hub"
|
name = "huggingface-hub"
|
||||||
version = "0.20.3"
|
version = "0.21.3"
|
||||||
description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
|
description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8.0"
|
python-versions = ">=3.8.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "huggingface_hub-0.20.3-py3-none-any.whl", hash = "sha256:d988ae4f00d3e307b0c80c6a05ca6dbb7edba8bba3079f74cda7d9c2e562a7b6"},
|
{file = "huggingface_hub-0.21.3-py3-none-any.whl", hash = "sha256:b183144336fdf2810a8c109822e0bb6ef1fd61c65da6fb60e8c3f658b7144016"},
|
||||||
{file = "huggingface_hub-0.20.3.tar.gz", hash = "sha256:94e7f8e074475fbc67d6a71957b678e1b4a74ff1b64a644fd6cbb83da962d05d"},
|
{file = "huggingface_hub-0.21.3.tar.gz", hash = "sha256:26a15b604e4fc7bad37c467b76456543ec849386cbca9cd7e1e135f53e500423"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -1297,11 +1297,12 @@ all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi",
|
|||||||
cli = ["InquirerPy (==0.3.4)"]
|
cli = ["InquirerPy (==0.3.4)"]
|
||||||
dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "mypy (==1.5.1)", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.1.3)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
|
dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "mypy (==1.5.1)", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.1.3)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
|
||||||
fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"]
|
fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"]
|
||||||
|
hf-transfer = ["hf-transfer (>=0.1.4)"]
|
||||||
inference = ["aiohttp", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)"]
|
inference = ["aiohttp", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)"]
|
||||||
quality = ["mypy (==1.5.1)", "ruff (>=0.1.3)"]
|
quality = ["mypy (==1.5.1)", "ruff (>=0.1.3)"]
|
||||||
tensorflow = ["graphviz", "pydot", "tensorflow"]
|
tensorflow = ["graphviz", "pydot", "tensorflow"]
|
||||||
testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"]
|
testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"]
|
||||||
torch = ["torch"]
|
torch = ["safetensors", "torch"]
|
||||||
typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"]
|
typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1566,13 +1567,13 @@ test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "locust"
|
name = "locust"
|
||||||
version = "2.23.1"
|
version = "2.24.0"
|
||||||
description = "Developer friendly load testing framework"
|
description = "Developer friendly load testing framework"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "locust-2.23.1-py3-none-any.whl", hash = "sha256:96013a460a4b4d6d4fd46c70e6ff1fd2b6e03b48ddb1b48d1513d3134ba2cecf"},
|
{file = "locust-2.24.0-py3-none-any.whl", hash = "sha256:1b6b878b4fd0108fec956120815e69775d2616c8f4d1e9f365c222a7a5c17d9a"},
|
||||||
{file = "locust-2.23.1.tar.gz", hash = "sha256:6cc729729e5ebf5852fc9d845302cfcf0ab0132f198e68b3eb0c88b438b6a863"},
|
{file = "locust-2.24.0.tar.gz", hash = "sha256:6cffa378d995244a7472af6be1d6139331f19aee44e907deee73e0281252804d"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -1588,6 +1589,7 @@ pywin32 = {version = "*", markers = "platform_system == \"Windows\""}
|
|||||||
pyzmq = ">=25.0.0"
|
pyzmq = ">=25.0.0"
|
||||||
requests = ">=2.26.0"
|
requests = ">=2.26.0"
|
||||||
roundrobin = ">=0.0.2"
|
roundrobin = ">=0.0.2"
|
||||||
|
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||||
Werkzeug = ">=2.0.0"
|
Werkzeug = ">=2.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1988,36 +1990,36 @@ reference = ["Pillow", "google-re2"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "onnxruntime"
|
name = "onnxruntime"
|
||||||
version = "1.17.0"
|
version = "1.17.1"
|
||||||
description = "ONNX Runtime is a runtime accelerator for Machine Learning models"
|
description = "ONNX Runtime is a runtime accelerator for Machine Learning models"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
files = [
|
files = [
|
||||||
{file = "onnxruntime-1.17.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:d2b22a25a94109cc983443116da8d9805ced0256eb215c5e6bc6dcbabefeab96"},
|
{file = "onnxruntime-1.17.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:d43ac17ac4fa3c9096ad3c0e5255bb41fd134560212dc124e7f52c3159af5d21"},
|
||||||
{file = "onnxruntime-1.17.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4c87d83c6f58d1af2675fc99e3dc810f2dbdb844bcefd0c1b7573632661f6fc"},
|
{file = "onnxruntime-1.17.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55b5e92a4c76a23981c998078b9bf6145e4fb0b016321a8274b1607bd3c6bd35"},
|
||||||
{file = "onnxruntime-1.17.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dba55723bf9b835e358f48c98a814b41692c393eb11f51e02ece0625c756b797"},
|
{file = "onnxruntime-1.17.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebbcd2bc3a066cf54e6f18c75708eb4d309ef42be54606d22e5bdd78afc5b0d7"},
|
||||||
{file = "onnxruntime-1.17.0-cp310-cp310-win32.whl", hash = "sha256:ee48422349cc500273beea7607e33c2237909f58468ae1d6cccfc4aecd158565"},
|
{file = "onnxruntime-1.17.1-cp310-cp310-win32.whl", hash = "sha256:5e3716b5eec9092e29a8d17aab55e737480487deabfca7eac3cd3ed952b6ada9"},
|
||||||
{file = "onnxruntime-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f34cc46553359293854e38bdae2ab1be59543aad78a6317e7746d30e311110c3"},
|
{file = "onnxruntime-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:fbb98cced6782ae1bb799cc74ddcbbeeae8819f3ad1d942a74d88e72b6511337"},
|
||||||
{file = "onnxruntime-1.17.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:16d26badd092c8c257fa57c458bb600d96dc15282c647ccad0ed7b2732e6c03b"},
|
{file = "onnxruntime-1.17.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:36fd6f87a1ecad87e9c652e42407a50fb305374f9a31d71293eb231caae18784"},
|
||||||
{file = "onnxruntime-1.17.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f1273bebcdb47ed932d076c85eb9488bc4768fcea16d5f2747ca692fad4f9d3"},
|
{file = "onnxruntime-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99a8bddeb538edabc524d468edb60ad4722cff8a49d66f4e280c39eace70500b"},
|
||||||
{file = "onnxruntime-1.17.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cb60fd3c2c1acd684752eb9680e89ae223e9801a9b0e0dc7b28adabe45a2e380"},
|
{file = "onnxruntime-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd7fddb4311deb5a7d3390cd8e9b3912d4d963efbe4dfe075edbaf18d01c024e"},
|
||||||
{file = "onnxruntime-1.17.0-cp311-cp311-win32.whl", hash = "sha256:4b038324586bc905299e435f7c00007e6242389c856b82fe9357fdc3b1ef2bdc"},
|
{file = "onnxruntime-1.17.1-cp311-cp311-win32.whl", hash = "sha256:606a7cbfb6680202b0e4f1890881041ffc3ac6e41760a25763bd9fe146f0b335"},
|
||||||
{file = "onnxruntime-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:93d39b3fa1ee01f034f098e1c7769a811a21365b4883f05f96c14a2b60c6028b"},
|
{file = "onnxruntime-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:53e4e06c0a541696ebdf96085fd9390304b7b04b748a19e02cf3b35c869a1e76"},
|
||||||
{file = "onnxruntime-1.17.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:90c0890e36f880281c6c698d9bc3de2afbeee2f76512725ec043665c25c67d21"},
|
{file = "onnxruntime-1.17.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:40f08e378e0f85929712a2b2c9b9a9cc400a90c8a8ca741d1d92c00abec60843"},
|
||||||
{file = "onnxruntime-1.17.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7466724e809a40e986b1637cba156ad9fc0d1952468bc00f79ef340bc0199552"},
|
{file = "onnxruntime-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac79da6d3e1bb4590f1dad4bb3c2979d7228555f92bb39820889af8b8e6bd472"},
|
||||||
{file = "onnxruntime-1.17.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d47bee7557a8b99c8681b6882657a515a4199778d6d5e24e924d2aafcef55b0a"},
|
{file = "onnxruntime-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ae9ba47dc099004e3781f2d0814ad710a13c868c739ab086fc697524061695ea"},
|
||||||
{file = "onnxruntime-1.17.0-cp312-cp312-win32.whl", hash = "sha256:bb1bf1ee575c665b8bbc3813ab906e091a645a24ccc210be7932154b8260eca1"},
|
{file = "onnxruntime-1.17.1-cp312-cp312-win32.whl", hash = "sha256:2dff1a24354220ac30e4a4ce2fb1df38cb1ea59f7dac2c116238d63fe7f4c5ff"},
|
||||||
{file = "onnxruntime-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:ac2f286da3494b29b4186ca193c7d4e6a2c1f770c4184c7192c5da142c3dec28"},
|
{file = "onnxruntime-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:6226a5201ab8cafb15e12e72ff2a4fc8f50654e8fa5737c6f0bd57c5ff66827e"},
|
||||||
{file = "onnxruntime-1.17.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1ec485643b93e0a3896c655eb2426decd63e18a278bb7ccebc133b340723624f"},
|
{file = "onnxruntime-1.17.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:cd0c07c0d1dfb8629e820b05fda5739e4835b3b82faf43753d2998edf2cf00aa"},
|
||||||
{file = "onnxruntime-1.17.0-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83c35809cda898c5a11911c69ceac8a2ac3925911854c526f73bad884582f911"},
|
{file = "onnxruntime-1.17.1-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:617ebdf49184efa1ba6e4467e602fbfa029ed52c92f13ce3c9f417d303006381"},
|
||||||
{file = "onnxruntime-1.17.0-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fa464aa4d81df818375239e481887b656e261377d5b6b9a4692466f5f3261edc"},
|
{file = "onnxruntime-1.17.1-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9dae9071e3facdf2920769dceee03b71c684b6439021defa45b830d05e148924"},
|
||||||
{file = "onnxruntime-1.17.0-cp38-cp38-win32.whl", hash = "sha256:b7b337cd0586f7836601623cbd30a443df9528ef23965860d11c753ceeb009f2"},
|
{file = "onnxruntime-1.17.1-cp38-cp38-win32.whl", hash = "sha256:835d38fa1064841679433b1aa8138b5e1218ddf0cfa7a3ae0d056d8fd9cec713"},
|
||||||
{file = "onnxruntime-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:fbb9faaf51d01aa2c147ef52524d9326744c852116d8005b9041809a71838878"},
|
{file = "onnxruntime-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:96621e0c555c2453bf607606d08af3f70fbf6f315230c28ddea91754e17ad4e6"},
|
||||||
{file = "onnxruntime-1.17.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:5a06ab84eaa350bf64b1d747b33ccf10da64221ed1f38f7287f15eccbec81603"},
|
{file = "onnxruntime-1.17.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:7a9539935fb2d78ebf2cf2693cad02d9930b0fb23cdd5cf37a7df813e977674d"},
|
||||||
{file = "onnxruntime-1.17.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d3d11db2c8242766212a68d0b139745157da7ce53bd96ba349a5c65e5a02357"},
|
{file = "onnxruntime-1.17.1-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45c6a384e9d9a29c78afff62032a46a993c477b280247a7e335df09372aedbe9"},
|
||||||
{file = "onnxruntime-1.17.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5632077c3ab8b0cd4f74b0af9c4e924be012b1a7bcd7daa845763c6c6bf14b7d"},
|
{file = "onnxruntime-1.17.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4e19f966450f16863a1d6182a685ca33ae04d7772a76132303852d05b95411ea"},
|
||||||
{file = "onnxruntime-1.17.0-cp39-cp39-win32.whl", hash = "sha256:61a12732cba869b3ad2d4e29ab6cb62c7a96f61b8c213f7fcb961ba412b70b37"},
|
{file = "onnxruntime-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e2ae712d64a42aac29ed7a40a426cb1e624a08cfe9273dcfe681614aa65b07dc"},
|
||||||
{file = "onnxruntime-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:461fa0fc7d9c392c352b6cccdedf44d818430f3d6eacd924bb804fdea2dcfd02"},
|
{file = "onnxruntime-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:f7e9f7fb049825cdddf4a923cfc7c649d84d63c0134315f8e0aa9e0c3004672c"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2633,6 +2635,7 @@ files = [
|
|||||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||||
|
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||||
@ -2812,13 +2815,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rich"
|
name = "rich"
|
||||||
version = "13.7.0"
|
version = "13.7.1"
|
||||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.0"
|
python-versions = ">=3.7.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"},
|
{file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"},
|
||||||
{file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"},
|
{file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2840,28 +2843,28 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.2.2"
|
version = "0.3.0"
|
||||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"},
|
{file = "ruff-0.3.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7deb528029bacf845bdbb3dbb2927d8ef9b4356a5e731b10eef171e3f0a85944"},
|
||||||
{file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"},
|
{file = "ruff-0.3.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e1e0d4381ca88fb2b73ea0766008e703f33f460295de658f5467f6f229658c19"},
|
||||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"},
|
{file = "ruff-0.3.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f7dbba46e2827dfcb0f0cc55fba8e96ba7c8700e0a866eb8cef7d1d66c25dcb"},
|
||||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"},
|
{file = "ruff-0.3.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23dbb808e2f1d68eeadd5f655485e235c102ac6f12ad31505804edced2a5ae77"},
|
||||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"},
|
{file = "ruff-0.3.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ef655c51f41d5fa879f98e40c90072b567c666a7114fa2d9fe004dffba00932"},
|
||||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"},
|
{file = "ruff-0.3.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d0d3d7ef3d4f06433d592e5f7d813314a34601e6c5be8481cccb7fa760aa243e"},
|
||||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"},
|
{file = "ruff-0.3.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b08b356d06a792e49a12074b62222f9d4ea2a11dca9da9f68163b28c71bf1dd4"},
|
||||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"},
|
{file = "ruff-0.3.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9343690f95710f8cf251bee1013bf43030072b9f8d012fbed6ad702ef70d360a"},
|
||||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"},
|
{file = "ruff-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1f3ed501a42f60f4dedb7805fa8d4534e78b4e196f536bac926f805f0743d49"},
|
||||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"},
|
{file = "ruff-0.3.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:cc30a9053ff2f1ffb505a585797c23434d5f6c838bacfe206c0e6cf38c921a1e"},
|
||||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"},
|
{file = "ruff-0.3.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5da894a29ec018a8293d3d17c797e73b374773943e8369cfc50495573d396933"},
|
||||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"},
|
{file = "ruff-0.3.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:755c22536d7f1889be25f2baf6fedd019d0c51d079e8417d4441159f3bcd30c2"},
|
||||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"},
|
{file = "ruff-0.3.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dd73fe7f4c28d317855da6a7bc4aa29a1500320818dd8f27df95f70a01b8171f"},
|
||||||
{file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"},
|
{file = "ruff-0.3.0-py3-none-win32.whl", hash = "sha256:19eacceb4c9406f6c41af806418a26fdb23120dfe53583df76d1401c92b7c14b"},
|
||||||
{file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"},
|
{file = "ruff-0.3.0-py3-none-win_amd64.whl", hash = "sha256:128265876c1d703e5f5e5a4543bd8be47c73a9ba223fd3989d4aa87dd06f312f"},
|
||||||
{file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"},
|
{file = "ruff-0.3.0-py3-none-win_arm64.whl", hash = "sha256:e3a4a6d46aef0a84b74fcd201a4401ea9a6cd85614f6a9435f2d33dd8cefbf83"},
|
||||||
{file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"},
|
{file = "ruff-0.3.0.tar.gz", hash = "sha256:0886184ba2618d815067cf43e005388967b67ab9c80df52b32ec1152ab49f53a"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "machine-learning"
|
name = "machine-learning"
|
||||||
version = "1.97.0"
|
version = "1.98.0"
|
||||||
description = ""
|
description = ""
|
||||||
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -62,9 +62,12 @@ fi
|
|||||||
if [ "$CURRENT_SERVER" != "$NEXT_SERVER" ]; then
|
if [ "$CURRENT_SERVER" != "$NEXT_SERVER" ]; then
|
||||||
echo "Pumping Server: $CURRENT_SERVER => $NEXT_SERVER"
|
echo "Pumping Server: $CURRENT_SERVER => $NEXT_SERVER"
|
||||||
npm --prefix server version "$SERVER_PUMP"
|
npm --prefix server version "$SERVER_PUMP"
|
||||||
npm --prefix web version "$SERVER_PUMP"
|
|
||||||
npm --prefix open-api/typescript-sdk version "$SERVER_PUMP"
|
|
||||||
make open-api
|
make open-api
|
||||||
|
npm --prefix open-api/typescript-sdk version "$SERVER_PUMP"
|
||||||
|
npm --prefix web version "$SERVER_PUMP"
|
||||||
|
npm --prefix web i --package-lock-only
|
||||||
|
npm --prefix cli i --package-lock-only
|
||||||
|
npm --prefix e2e i --package-lock-only
|
||||||
poetry --directory machine-learning version "$SERVER_PUMP"
|
poetry --directory machine-learning version "$SERVER_PUMP"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -35,8 +35,8 @@ platform :android do
|
|||||||
task: 'bundle',
|
task: 'bundle',
|
||||||
build_type: 'Release',
|
build_type: 'Release',
|
||||||
properties: {
|
properties: {
|
||||||
"android.injected.version.code" => 125,
|
"android.injected.version.code" => 126,
|
||||||
"android.injected.version.name" => "1.97.0",
|
"android.injected.version.name" => "1.98.0",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETALLS",
|
"exif_bottom_sheet_details": "DETALLS",
|
||||||
"exif_bottom_sheet_location": "UBICACIÓ",
|
"exif_bottom_sheet_location": "UBICACIÓ",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
||||||
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||||
"experimental_settings_subtitle": "Use at your own risk!",
|
"experimental_settings_subtitle": "Use at your own risk!",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "PODROBNOSTI",
|
"exif_bottom_sheet_details": "PODROBNOSTI",
|
||||||
"exif_bottom_sheet_location": "LOKALITA",
|
"exif_bottom_sheet_location": "LOKALITA",
|
||||||
"exif_bottom_sheet_location_add": "Přidat polohu",
|
"exif_bottom_sheet_location_add": "Přidat polohu",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Zpracovávám",
|
"experimental_settings_new_asset_list_subtitle": "Zpracovávám",
|
||||||
"experimental_settings_new_asset_list_title": "Povolení experimentální mřížky fotografií",
|
"experimental_settings_new_asset_list_title": "Povolení experimentální mřížky fotografií",
|
||||||
"experimental_settings_subtitle": "Používejte na vlastní riziko!",
|
"experimental_settings_subtitle": "Používejte na vlastní riziko!",
|
||||||
|
@ -35,8 +35,8 @@
|
|||||||
"app_bar_signout_dialog_title": "Log ud",
|
"app_bar_signout_dialog_title": "Log ud",
|
||||||
"archive_page_no_archived_assets": "Ingen arkiverede elementer blev fundet",
|
"archive_page_no_archived_assets": "Ingen arkiverede elementer blev fundet",
|
||||||
"archive_page_title": "Arkivér ({})",
|
"archive_page_title": "Arkivér ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "Kan ikke slette kun læselige elementer. Springer over",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "Kan ikke hente offline element(er). Springer over",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Dynamisk layout",
|
"asset_list_layout_settings_dynamic_layout_title": "Dynamisk layout",
|
||||||
"asset_list_layout_settings_group_automatically": "Automatisk",
|
"asset_list_layout_settings_group_automatically": "Automatisk",
|
||||||
"asset_list_layout_settings_group_by": "Gruppér elementer pr. ",
|
"asset_list_layout_settings_group_by": "Gruppér elementer pr. ",
|
||||||
@ -150,7 +150,7 @@
|
|||||||
"control_bottom_app_bar_share": "Del",
|
"control_bottom_app_bar_share": "Del",
|
||||||
"control_bottom_app_bar_share_to": "Del til",
|
"control_bottom_app_bar_share_to": "Del til",
|
||||||
"control_bottom_app_bar_stack": "Stak",
|
"control_bottom_app_bar_stack": "Stak",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Flyt til papirkurv",
|
||||||
"control_bottom_app_bar_unarchive": "Afakivér",
|
"control_bottom_app_bar_unarchive": "Afakivér",
|
||||||
"control_bottom_app_bar_unfavorite": "Fjern favorit",
|
"control_bottom_app_bar_unfavorite": "Fjern favorit",
|
||||||
"control_bottom_app_bar_upload": "Upload",
|
"control_bottom_app_bar_upload": "Upload",
|
||||||
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETALJER",
|
"exif_bottom_sheet_details": "DETALJER",
|
||||||
"exif_bottom_sheet_location": "LOKATION",
|
"exif_bottom_sheet_location": "LOKATION",
|
||||||
"exif_bottom_sheet_location_add": "Tilføj en placering",
|
"exif_bottom_sheet_location_add": "Tilføj en placering",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Under udarbejdelse",
|
"experimental_settings_new_asset_list_subtitle": "Under udarbejdelse",
|
||||||
"experimental_settings_new_asset_list_title": "Aktiver eksperimentelt fotogitter",
|
"experimental_settings_new_asset_list_title": "Aktiver eksperimentelt fotogitter",
|
||||||
"experimental_settings_subtitle": "Brug på eget ansvar!",
|
"experimental_settings_subtitle": "Brug på eget ansvar!",
|
||||||
@ -199,7 +200,7 @@
|
|||||||
"home_page_archive_err_partner": "Kan endnu ikke arkivere partners elementer. Springer over",
|
"home_page_archive_err_partner": "Kan endnu ikke arkivere partners elementer. Springer over",
|
||||||
"home_page_building_timeline": "Bygger tidslinjen",
|
"home_page_building_timeline": "Bygger tidslinjen",
|
||||||
"home_page_delete_err_partner": "Kan endnu ikke slette partners elementer. Springer over",
|
"home_page_delete_err_partner": "Kan endnu ikke slette partners elementer. Springer over",
|
||||||
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
"home_page_delete_remote_err_local": "Lokale elementer i fjernsletningssektion. Springer over",
|
||||||
"home_page_favorite_err_local": "Kan endnu ikke gøre lokale elementer til favoritter. Springer over..",
|
"home_page_favorite_err_local": "Kan endnu ikke gøre lokale elementer til favoritter. Springer over..",
|
||||||
"home_page_favorite_err_partner": "Kan endnu ikke tilføje partners elementer som favoritter. Springer over",
|
"home_page_favorite_err_partner": "Kan endnu ikke tilføje partners elementer som favoritter. Springer over",
|
||||||
"home_page_first_time_notice": "Hvis det er din første gang i appen, bedes du vælge en sikkerhedskopi af albummer så tidlinjen kan blive fyldt med billeder og videoer fra albummerne.",
|
"home_page_first_time_notice": "Hvis det er din første gang i appen, bedes du vælge en sikkerhedskopi af albummer så tidlinjen kan blive fyldt med billeder og videoer fra albummerne.",
|
||||||
@ -279,8 +280,8 @@
|
|||||||
"map_zoom_to_see_photos": "Zoom ud for at vise billeder",
|
"map_zoom_to_see_photos": "Zoom ud for at vise billeder",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Bevægelsesbilleder",
|
"motion_photos_page_title": "Bevægelsesbilleder",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Kan ikke redigere datoen på kun læselige elementer. Springer over",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
"multiselect_grid_edit_gps_err_read_only": "Kan ikke redigere lokation af kun læselige elementer. Springer over",
|
||||||
"notification_permission_dialog_cancel": "Annuller",
|
"notification_permission_dialog_cancel": "Annuller",
|
||||||
"notification_permission_dialog_content": "Gå til indstillinger for at slå notifikationer til.",
|
"notification_permission_dialog_content": "Gå til indstillinger for at slå notifikationer til.",
|
||||||
"notification_permission_dialog_settings": "Indstillinger",
|
"notification_permission_dialog_settings": "Indstillinger",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETAILS",
|
"exif_bottom_sheet_details": "DETAILS",
|
||||||
"exif_bottom_sheet_location": "STANDORT",
|
"exif_bottom_sheet_location": "STANDORT",
|
||||||
"exif_bottom_sheet_location_add": "Aufnahmeort hinzufügen",
|
"exif_bottom_sheet_location_add": "Aufnahmeort hinzufügen",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "In Arbeit",
|
"experimental_settings_new_asset_list_subtitle": "In Arbeit",
|
||||||
"experimental_settings_new_asset_list_title": "Experimentelles Fotogitter aktivieren",
|
"experimental_settings_new_asset_list_title": "Experimentelles Fotogitter aktivieren",
|
||||||
"experimental_settings_subtitle": "Benutzung auf eigene Gefahr!",
|
"experimental_settings_subtitle": "Benutzung auf eigene Gefahr!",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETAILS",
|
"exif_bottom_sheet_details": "DETAILS",
|
||||||
"exif_bottom_sheet_location": "LOCATION",
|
"exif_bottom_sheet_location": "LOCATION",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
||||||
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||||
"experimental_settings_subtitle": "Use at your own risk!",
|
"experimental_settings_subtitle": "Use at your own risk!",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action_common_cancel": "Cancel",
|
"action_common_cancel": "Cancelar",
|
||||||
"action_common_update": "Update",
|
"action_common_update": "Actualizar",
|
||||||
"add_to_album_bottom_sheet_added": "Agregado a {album}",
|
"add_to_album_bottom_sheet_added": "Agregado a {album}",
|
||||||
"add_to_album_bottom_sheet_already_exists": "Ya se encuentra en {album}",
|
"add_to_album_bottom_sheet_already_exists": "Ya se encuentra en {album}",
|
||||||
"advanced_settings_log_level_title": "Nivel de log: {}",
|
"advanced_settings_log_level_title": "Nivel de log: {}",
|
||||||
@ -35,7 +35,7 @@
|
|||||||
"app_bar_signout_dialog_title": "Cerrar sesión",
|
"app_bar_signout_dialog_title": "Cerrar sesión",
|
||||||
"archive_page_no_archived_assets": "No se encontraron recursos archivados",
|
"archive_page_no_archived_assets": "No se encontraron recursos archivados",
|
||||||
"archive_page_title": "Archivo ({})",
|
"archive_page_title": "Archivo ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "No se pueden borrar los archivos de solo lectura. Saltando.",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Diseño dinámico",
|
"asset_list_layout_settings_dynamic_layout_title": "Diseño dinámico",
|
||||||
"asset_list_layout_settings_group_automatically": "Automatico",
|
"asset_list_layout_settings_group_automatically": "Automatico",
|
||||||
@ -142,15 +142,15 @@
|
|||||||
"control_bottom_app_bar_archive": "Archivar",
|
"control_bottom_app_bar_archive": "Archivar",
|
||||||
"control_bottom_app_bar_create_new_album": "Crear nuevo álbum",
|
"control_bottom_app_bar_create_new_album": "Crear nuevo álbum",
|
||||||
"control_bottom_app_bar_delete": "Eliminar",
|
"control_bottom_app_bar_delete": "Eliminar",
|
||||||
"control_bottom_app_bar_delete_from_immich": "Delete from Immich",
|
"control_bottom_app_bar_delete_from_immich": "Borrar de Immich",
|
||||||
"control_bottom_app_bar_delete_from_local": "Delete from device",
|
"control_bottom_app_bar_delete_from_local": "Borrar del dispositivo",
|
||||||
"control_bottom_app_bar_edit_location": "Editar ubicación",
|
"control_bottom_app_bar_edit_location": "Editar ubicación",
|
||||||
"control_bottom_app_bar_edit_time": "Editar fecha y hora",
|
"control_bottom_app_bar_edit_time": "Editar fecha y hora",
|
||||||
"control_bottom_app_bar_favorite": "Favorito",
|
"control_bottom_app_bar_favorite": "Favorito",
|
||||||
"control_bottom_app_bar_share": "Compartir",
|
"control_bottom_app_bar_share": "Compartir",
|
||||||
"control_bottom_app_bar_share_to": "Enviar",
|
"control_bottom_app_bar_share_to": "Enviar",
|
||||||
"control_bottom_app_bar_stack": "Apilar",
|
"control_bottom_app_bar_stack": "Apilar",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Mover a la papelera",
|
||||||
"control_bottom_app_bar_unarchive": "Desarchivar",
|
"control_bottom_app_bar_unarchive": "Desarchivar",
|
||||||
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
||||||
"control_bottom_app_bar_upload": "Subir",
|
"control_bottom_app_bar_upload": "Subir",
|
||||||
@ -165,9 +165,9 @@
|
|||||||
"daily_title_text_date_year": "E dd de MMM, yyyy",
|
"daily_title_text_date_year": "E dd de MMM, yyyy",
|
||||||
"date_format": "E d, LLL y • h:mm a",
|
"date_format": "E d, LLL y • h:mm a",
|
||||||
"delete_dialog_alert": "Estos elementos serán eliminados permanentemente de Immich y de tu dispositivo",
|
"delete_dialog_alert": "Estos elementos serán eliminados permanentemente de Immich y de tu dispositivo",
|
||||||
"delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server",
|
"delete_dialog_alert_local": "Estas imágenes van a ser borradas de tu dispositivo, pero seguirán disponibles en el servidor Immich",
|
||||||
"delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device",
|
"delete_dialog_alert_local_non_backed_up": "Algunas de las imágenes no tienen copia de seguridad y serán borradas de forma permanente de tu dispositivo",
|
||||||
"delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server",
|
"delete_dialog_alert_remote": "Estas imágenes van a ser borradas de forma permanente del servidor Immich",
|
||||||
"delete_dialog_cancel": "Cancelar",
|
"delete_dialog_cancel": "Cancelar",
|
||||||
"delete_dialog_ok": "Eliminar",
|
"delete_dialog_ok": "Eliminar",
|
||||||
"delete_dialog_ok_force": "Delete Anyway",
|
"delete_dialog_ok_force": "Delete Anyway",
|
||||||
@ -178,13 +178,14 @@
|
|||||||
"delete_shared_link_dialog_title": "Eliminar enlace compartido",
|
"delete_shared_link_dialog_title": "Eliminar enlace compartido",
|
||||||
"description_input_hint_text": "Agregar descripción...",
|
"description_input_hint_text": "Agregar descripción...",
|
||||||
"description_input_submit_error": "Error al actualizar la descripción, verifica el registro para obtener más detalles",
|
"description_input_submit_error": "Error al actualizar la descripción, verifica el registro para obtener más detalles",
|
||||||
"edit_date_time_dialog_date_time": "Date and Time",
|
"edit_date_time_dialog_date_time": "Fecha y Hora",
|
||||||
"edit_date_time_dialog_timezone": "Timezone",
|
"edit_date_time_dialog_timezone": "Zona horaria",
|
||||||
"edit_location_dialog_title": "Location",
|
"edit_location_dialog_title": "Ubicación",
|
||||||
"exif_bottom_sheet_description": "Agregar Descripción...",
|
"exif_bottom_sheet_description": "Agregar Descripción...",
|
||||||
"exif_bottom_sheet_details": "DETALLES",
|
"exif_bottom_sheet_details": "DETALLES",
|
||||||
"exif_bottom_sheet_location": "UBICACIÓN",
|
"exif_bottom_sheet_location": "UBICACIÓN",
|
||||||
"exif_bottom_sheet_location_add": "Añadir ubicación",
|
"exif_bottom_sheet_location_add": "Añadir ubicación",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Trabajo en progreso",
|
"experimental_settings_new_asset_list_subtitle": "Trabajo en progreso",
|
||||||
"experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental",
|
"experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental",
|
||||||
"experimental_settings_subtitle": "Úsalo bajo tu responsabilidad",
|
"experimental_settings_subtitle": "Úsalo bajo tu responsabilidad",
|
||||||
@ -220,13 +221,13 @@
|
|||||||
"library_page_sort_most_oldest_photo": "Foto más antigua",
|
"library_page_sort_most_oldest_photo": "Foto más antigua",
|
||||||
"library_page_sort_most_recent_photo": "Foto más reciente",
|
"library_page_sort_most_recent_photo": "Foto más reciente",
|
||||||
"library_page_sort_title": "Título del álbum",
|
"library_page_sort_title": "Título del álbum",
|
||||||
"location_picker_choose_on_map": "Choose on map",
|
"location_picker_choose_on_map": "Elegir en el mapa",
|
||||||
"location_picker_latitude": "Latitude",
|
"location_picker_latitude": "Latitud",
|
||||||
"location_picker_latitude_error": "Enter a valid latitude",
|
"location_picker_latitude_error": "Introduce una latitud válida",
|
||||||
"location_picker_latitude_hint": "Enter your latitude here",
|
"location_picker_latitude_hint": "Introduce tu latitud aquí",
|
||||||
"location_picker_longitude": "Longitude",
|
"location_picker_longitude": "Longitud",
|
||||||
"location_picker_longitude_error": "Enter a valid longitude",
|
"location_picker_longitude_error": "Introduce una longitud válida",
|
||||||
"location_picker_longitude_hint": "Enter your longitude here",
|
"location_picker_longitude_hint": "Introduce tu longitud aquí",
|
||||||
"login_disabled": "El inicio de sesión ha sido desactivado",
|
"login_disabled": "El inicio de sesión ha sido desactivado",
|
||||||
"login_form_api_exception": "Excepción producida por API. Por favor, verifica el URL del servidor e inténtalo de nuevo.",
|
"login_form_api_exception": "Excepción producida por API. Por favor, verifica el URL del servidor e inténtalo de nuevo.",
|
||||||
"login_form_back_button_text": "Atrás",
|
"login_form_back_button_text": "Atrás",
|
||||||
@ -252,12 +253,12 @@
|
|||||||
"login_form_server_error": "No se pudo conectar al servidor.",
|
"login_form_server_error": "No se pudo conectar al servidor.",
|
||||||
"login_password_changed_error": "Hubo un error actualizando la contraseña",
|
"login_password_changed_error": "Hubo un error actualizando la contraseña",
|
||||||
"login_password_changed_success": "Contraseña cambiado con éxito",
|
"login_password_changed_success": "Contraseña cambiado con éxito",
|
||||||
"map_assets_in_bound": "{} photo",
|
"map_assets_in_bound": "{} foto",
|
||||||
"map_assets_in_bounds": "{} photos",
|
"map_assets_in_bounds": "{} fotos",
|
||||||
"map_cannot_get_user_location": "No se pudo obtener la posición del usuario",
|
"map_cannot_get_user_location": "No se pudo obtener la posición del usuario",
|
||||||
"map_location_dialog_cancel": "Cancelar",
|
"map_location_dialog_cancel": "Cancelar",
|
||||||
"map_location_dialog_yes": "Sí",
|
"map_location_dialog_yes": "Sí",
|
||||||
"map_location_picker_page_use_location": "Use this location",
|
"map_location_picker_page_use_location": "Usar esta ubicación",
|
||||||
"map_location_service_disabled_content": "Los servicios de ubicación deben estar activados para mostrar elementos de tu ubicación actual. Deseas activarlos ahora?",
|
"map_location_service_disabled_content": "Los servicios de ubicación deben estar activados para mostrar elementos de tu ubicación actual. Deseas activarlos ahora?",
|
||||||
"map_location_service_disabled_title": "Servicios de ubicación desactivados",
|
"map_location_service_disabled_title": "Servicios de ubicación desactivados",
|
||||||
"map_no_assets_in_bounds": "No hay fotos en esta zona",
|
"map_no_assets_in_bounds": "No hay fotos en esta zona",
|
||||||
@ -265,22 +266,22 @@
|
|||||||
"map_no_location_permission_title": "Permisos de ubicación denegados",
|
"map_no_location_permission_title": "Permisos de ubicación denegados",
|
||||||
"map_settings_dark_mode": "Modo oscuro",
|
"map_settings_dark_mode": "Modo oscuro",
|
||||||
"map_settings_date_range_option_all": "Todo",
|
"map_settings_date_range_option_all": "Todo",
|
||||||
"map_settings_date_range_option_day": "Past 24 hours",
|
"map_settings_date_range_option_day": "Últimas 24 horas",
|
||||||
"map_settings_date_range_option_days": "Past {} days",
|
"map_settings_date_range_option_days": "Últimos {} días",
|
||||||
"map_settings_date_range_option_year": "Past year",
|
"map_settings_date_range_option_year": "Último año",
|
||||||
"map_settings_date_range_option_years": "Past {} years",
|
"map_settings_date_range_option_years": "Últimos {} años",
|
||||||
"map_settings_dialog_cancel": "Cancelar",
|
"map_settings_dialog_cancel": "Cancelar",
|
||||||
"map_settings_dialog_save": "Guardar",
|
"map_settings_dialog_save": "Guardar",
|
||||||
"map_settings_dialog_title": "Ajustes mapa",
|
"map_settings_dialog_title": "Ajustes mapa",
|
||||||
"map_settings_include_show_archived": "Incluir archivados",
|
"map_settings_include_show_archived": "Incluir archivados",
|
||||||
"map_settings_only_relative_range": "Rango de fechas",
|
"map_settings_only_relative_range": "Rango de fechas",
|
||||||
"map_settings_only_show_favorites": "Mostrar solo favoritas",
|
"map_settings_only_show_favorites": "Mostrar solo favoritas",
|
||||||
"map_settings_theme_settings": "Map Theme",
|
"map_settings_theme_settings": "Apariencia del Mapa",
|
||||||
"map_zoom_to_see_photos": "Alejar para ver fotos",
|
"map_zoom_to_see_photos": "Alejar para ver fotos",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Foto en Movimiento",
|
"motion_photos_page_title": "Foto en Movimiento",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "No se puede cambiar la fecha de archivos de solo lectura. Saltando.",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
"multiselect_grid_edit_gps_err_read_only": "No se puede cambiar la localización de archivos de solo lectura. Saltando.",
|
||||||
"notification_permission_dialog_cancel": "Cancelar",
|
"notification_permission_dialog_cancel": "Cancelar",
|
||||||
"notification_permission_dialog_content": "Para activar las notificaciones, ve a Configuración y selecciona permitir.",
|
"notification_permission_dialog_content": "Para activar las notificaciones, ve a Configuración y selecciona permitir.",
|
||||||
"notification_permission_dialog_settings": "Ajustes",
|
"notification_permission_dialog_settings": "Ajustes",
|
||||||
@ -318,7 +319,7 @@
|
|||||||
"profile_drawer_sign_out": "Cerrar Sesión",
|
"profile_drawer_sign_out": "Cerrar Sesión",
|
||||||
"profile_drawer_trash": "Papelera",
|
"profile_drawer_trash": "Papelera",
|
||||||
"recently_added_page_title": "Recién Agregadas",
|
"recently_added_page_title": "Recién Agregadas",
|
||||||
"scaffold_body_error_occurred": "Error occurred",
|
"scaffold_body_error_occurred": "Ha ocurrido un error",
|
||||||
"search_bar_hint": "Busca tus fotos",
|
"search_bar_hint": "Busca tus fotos",
|
||||||
"search_page_categories": "Categorías",
|
"search_page_categories": "Categorías",
|
||||||
"search_page_favorites": "Favoritos",
|
"search_page_favorites": "Favoritos",
|
||||||
@ -330,9 +331,9 @@
|
|||||||
"search_page_person_add_name_dialog_hint": "Nombre",
|
"search_page_person_add_name_dialog_hint": "Nombre",
|
||||||
"search_page_person_add_name_dialog_save": "Guardar",
|
"search_page_person_add_name_dialog_save": "Guardar",
|
||||||
"search_page_person_add_name_dialog_title": "Añadir nombre",
|
"search_page_person_add_name_dialog_title": "Añadir nombre",
|
||||||
"search_page_person_add_name_subtitle": "Find them fast by name with search",
|
"search_page_person_add_name_subtitle": "Encuéntralos rápido buscando por nombre",
|
||||||
"search_page_person_add_name_title": "Add a name",
|
"search_page_person_add_name_title": "Añadir nombre",
|
||||||
"search_page_person_edit_name": "Edit name",
|
"search_page_person_edit_name": "Cambiar nombre",
|
||||||
"search_page_places": "Lugares",
|
"search_page_places": "Lugares",
|
||||||
"search_page_recently_added": "Recién agregadas",
|
"search_page_recently_added": "Recién agregadas",
|
||||||
"search_page_screenshots": "Capturas de pantalla",
|
"search_page_screenshots": "Capturas de pantalla",
|
||||||
@ -341,7 +342,7 @@
|
|||||||
"search_page_videos": "Videos",
|
"search_page_videos": "Videos",
|
||||||
"search_page_view_all_button": "Ver todo",
|
"search_page_view_all_button": "Ver todo",
|
||||||
"search_page_your_activity": "Tu actividad",
|
"search_page_your_activity": "Tu actividad",
|
||||||
"search_page_your_map": "Your Map",
|
"search_page_your_map": "Tu Mapa",
|
||||||
"search_result_page_new_search_hint": "Nueva Busqueda",
|
"search_result_page_new_search_hint": "Nueva Busqueda",
|
||||||
"search_suggestion_list_smart_search_hint_1": "La búsqueda inteligente está habilitada por defecto, para buscar metadatos utiliza esta sintaxis ",
|
"search_suggestion_list_smart_search_hint_1": "La búsqueda inteligente está habilitada por defecto, para buscar metadatos utiliza esta sintaxis ",
|
||||||
"search_suggestion_list_smart_search_hint_2": "m:tu-término-de-búsqueda",
|
"search_suggestion_list_smart_search_hint_2": "m:tu-término-de-búsqueda",
|
||||||
@ -381,17 +382,17 @@
|
|||||||
"shared_album_activity_remove_title": "Eliminar Actividad",
|
"shared_album_activity_remove_title": "Eliminar Actividad",
|
||||||
"shared_album_activity_setting_subtitle": "Permitir que otros respondan",
|
"shared_album_activity_setting_subtitle": "Permitir que otros respondan",
|
||||||
"shared_album_activity_setting_title": "Comentarios y me gusta",
|
"shared_album_activity_setting_title": "Comentarios y me gusta",
|
||||||
"shared_album_section_people_action_error": "Error leaving/removing from album",
|
"shared_album_section_people_action_error": "Error dejando/eliminando del album",
|
||||||
"shared_album_section_people_action_leave": "Remove user from album",
|
"shared_album_section_people_action_leave": "Eliminar usuario del album",
|
||||||
"shared_album_section_people_action_remove_user": "Remove user from album",
|
"shared_album_section_people_action_remove_user": "Eliminar usuario del album",
|
||||||
"shared_album_section_people_owner_label": "Owner",
|
"shared_album_section_people_owner_label": "Propietario",
|
||||||
"shared_album_section_people_title": "PEOPLE",
|
"shared_album_section_people_title": "GENTE",
|
||||||
"share_dialog_preparing": "Preparando...",
|
"share_dialog_preparing": "Preparando...",
|
||||||
"shared_link_app_bar_title": "Enlaces compartidos",
|
"shared_link_app_bar_title": "Enlaces compartidos",
|
||||||
"shared_link_clipboard_copied_massage": "Copied to clipboard",
|
"shared_link_clipboard_copied_massage": "Copiado al portapapeles",
|
||||||
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
"shared_link_clipboard_text": "Enlace: {}\nContraseña: {}",
|
||||||
"shared_link_create_app_bar_title": "Crear enlace compartido",
|
"shared_link_create_app_bar_title": "Crear enlace compartido",
|
||||||
"shared_link_create_error": "Error while creating shared link",
|
"shared_link_create_error": "Error creando el enlace compartido",
|
||||||
"shared_link_create_info": "Cualquier persona con el enlace puede ver las fotos seleccionadas",
|
"shared_link_create_info": "Cualquier persona con el enlace puede ver las fotos seleccionadas",
|
||||||
"shared_link_create_submit_button": "Crear enlace",
|
"shared_link_create_submit_button": "Crear enlace",
|
||||||
"shared_link_edit_allow_download": "Permitir descargar a usuarios públicos",
|
"shared_link_edit_allow_download": "Permitir descargar a usuarios públicos",
|
||||||
@ -401,32 +402,32 @@
|
|||||||
"shared_link_edit_description": "Descripción",
|
"shared_link_edit_description": "Descripción",
|
||||||
"shared_link_edit_description_hint": "Introduce la descripción del enlace",
|
"shared_link_edit_description_hint": "Introduce la descripción del enlace",
|
||||||
"shared_link_edit_expire_after": "Expirar después de",
|
"shared_link_edit_expire_after": "Expirar después de",
|
||||||
"shared_link_edit_expire_after_option_day": "1 day",
|
"shared_link_edit_expire_after_option_day": "1 día",
|
||||||
"shared_link_edit_expire_after_option_days": "{} days",
|
"shared_link_edit_expire_after_option_days": "{} días",
|
||||||
"shared_link_edit_expire_after_option_hour": "1 hour",
|
"shared_link_edit_expire_after_option_hour": "1 hora",
|
||||||
"shared_link_edit_expire_after_option_hours": "{} hours",
|
"shared_link_edit_expire_after_option_hours": "{} horas",
|
||||||
"shared_link_edit_expire_after_option_minute": "1 minute",
|
"shared_link_edit_expire_after_option_minute": "1 minuto",
|
||||||
"shared_link_edit_expire_after_option_minutes": "{} minutes",
|
"shared_link_edit_expire_after_option_minutes": "{} minutos",
|
||||||
"shared_link_edit_expire_after_option_never": "Never",
|
"shared_link_edit_expire_after_option_never": "Nunca",
|
||||||
"shared_link_edit_password": "Contraseña",
|
"shared_link_edit_password": "Contraseña",
|
||||||
"shared_link_edit_password_hint": "Introduce la contraseña del enlace",
|
"shared_link_edit_password_hint": "Introduce la contraseña del enlace",
|
||||||
"shared_link_edit_show_meta": "Mostrar metadatos",
|
"shared_link_edit_show_meta": "Mostrar metadatos",
|
||||||
"shared_link_edit_submit_button": "Actualizar enlace",
|
"shared_link_edit_submit_button": "Actualizar enlace",
|
||||||
"shared_link_empty": "No tienes enlaces compartidos",
|
"shared_link_empty": "No tienes enlaces compartidos",
|
||||||
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
"shared_link_error_server_url_fetch": "No se puede adquirir la URL del servidor",
|
||||||
"shared_link_expired": "Expired",
|
"shared_link_expired": "Caducado",
|
||||||
"shared_link_expires_day": "Expires in {} day",
|
"shared_link_expires_day": "Caduca en {} día",
|
||||||
"shared_link_expires_days": "Expires in {} days",
|
"shared_link_expires_days": "Caduca en {} días",
|
||||||
"shared_link_expires_hour": "Expires in {} hour",
|
"shared_link_expires_hour": "Caduca en {} hora",
|
||||||
"shared_link_expires_hours": "Expires in {} hours",
|
"shared_link_expires_hours": "Caduca en {} horas",
|
||||||
"shared_link_expires_minute": "Expires in {} minute",
|
"shared_link_expires_minute": "Caduca en {} minuto",
|
||||||
"shared_link_expires_minutes": "Caduca en {} minutos",
|
"shared_link_expires_minutes": "Caduca en {} minutos",
|
||||||
"shared_link_expires_never": "Expires ∞",
|
"shared_link_expires_never": "Caduca ∞",
|
||||||
"shared_link_expires_second": "Expires in {} second",
|
"shared_link_expires_second": "Caduca en {} segundo",
|
||||||
"shared_link_expires_seconds": "Caduca en {} segundos",
|
"shared_link_expires_seconds": "Caduca en {} segundos",
|
||||||
"shared_link_info_chip_download": "Download",
|
"shared_link_info_chip_download": "Descargar",
|
||||||
"shared_link_info_chip_metadata": "EXIF",
|
"shared_link_info_chip_metadata": "EXIF",
|
||||||
"shared_link_info_chip_upload": "Upload",
|
"shared_link_info_chip_upload": "Subir",
|
||||||
"shared_link_manage_links": "Administrar enlaces compartidos",
|
"shared_link_manage_links": "Administrar enlaces compartidos",
|
||||||
"share_done": "Hecho",
|
"share_done": "Hecho",
|
||||||
"share_invite": "Invitar al álbum",
|
"share_invite": "Invitar al álbum",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETALLES",
|
"exif_bottom_sheet_details": "DETALLES",
|
||||||
"exif_bottom_sheet_location": "UBICACIÓN",
|
"exif_bottom_sheet_location": "UBICACIÓN",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Trabajo en progreso",
|
"experimental_settings_new_asset_list_subtitle": "Trabajo en progreso",
|
||||||
"experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental",
|
"experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental",
|
||||||
"experimental_settings_subtitle": "Úsalo bajo tu responsabilidad",
|
"experimental_settings_subtitle": "Úsalo bajo tu responsabilidad",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETALLES",
|
"exif_bottom_sheet_details": "DETALLES",
|
||||||
"exif_bottom_sheet_location": "UBICACIÓN",
|
"exif_bottom_sheet_location": "UBICACIÓN",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Trabajo en progreso",
|
"experimental_settings_new_asset_list_subtitle": "Trabajo en progreso",
|
||||||
"experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental",
|
"experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental",
|
||||||
"experimental_settings_subtitle": "Úsalo bajo tu responsabilidad",
|
"experimental_settings_subtitle": "Úsalo bajo tu responsabilidad",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "TIEDOT",
|
"exif_bottom_sheet_details": "TIEDOT",
|
||||||
"exif_bottom_sheet_location": "SIJAINTI",
|
"exif_bottom_sheet_location": "SIJAINTI",
|
||||||
"exif_bottom_sheet_location_add": "Lisää sijainti",
|
"exif_bottom_sheet_location_add": "Lisää sijainti",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Työn alla",
|
"experimental_settings_new_asset_list_subtitle": "Työn alla",
|
||||||
"experimental_settings_new_asset_list_title": "Ota käyttöön kokeellinen kuvaruudukko",
|
"experimental_settings_new_asset_list_title": "Ota käyttöön kokeellinen kuvaruudukko",
|
||||||
"experimental_settings_subtitle": "Käyttö omalla vastuulla!",
|
"experimental_settings_subtitle": "Käyttö omalla vastuulla!",
|
||||||
@ -199,7 +200,7 @@
|
|||||||
"home_page_archive_err_partner": "Kumppanin kohteita ei voi arkistoida. Hypätään yli",
|
"home_page_archive_err_partner": "Kumppanin kohteita ei voi arkistoida. Hypätään yli",
|
||||||
"home_page_building_timeline": "Rakennetaan aikajanaa",
|
"home_page_building_timeline": "Rakennetaan aikajanaa",
|
||||||
"home_page_delete_err_partner": "Kumppanin kohteita ei voi poistaa.Hypätään yli",
|
"home_page_delete_err_partner": "Kumppanin kohteita ei voi poistaa.Hypätään yli",
|
||||||
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
"home_page_delete_remote_err_local": "Paikallisia kohteita etäkohdevalintojen joukossa, ohitetaan",
|
||||||
"home_page_favorite_err_local": "Paikallisten kohteiden lisääminen suosikkeihin ei ole mahdollista, ohitetaan",
|
"home_page_favorite_err_local": "Paikallisten kohteiden lisääminen suosikkeihin ei ole mahdollista, ohitetaan",
|
||||||
"home_page_favorite_err_partner": "Kumppanin kohteita ei voi vielä merkitä suosikiksi. Hypätään yli",
|
"home_page_favorite_err_partner": "Kumppanin kohteita ei voi vielä merkitä suosikiksi. Hypätään yli",
|
||||||
"home_page_first_time_notice": "Jos käytät sovellusta ensimmäistä kertaa, muista valita varmuuskopioitavat albumi(t), jotta aikajanalla voi olla kuvia ja videoita.",
|
"home_page_first_time_notice": "Jos käytät sovellusta ensimmäistä kertaa, muista valita varmuuskopioitavat albumi(t), jotta aikajanalla voi olla kuvia ja videoita.",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DÉTAILS",
|
"exif_bottom_sheet_details": "DÉTAILS",
|
||||||
"exif_bottom_sheet_location": "LOCALISATION",
|
"exif_bottom_sheet_location": "LOCALISATION",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "En cours de développement",
|
"experimental_settings_new_asset_list_subtitle": "En cours de développement",
|
||||||
"experimental_settings_new_asset_list_title": "Activer la grille de photos expérimentale",
|
"experimental_settings_new_asset_list_title": "Activer la grille de photos expérimentale",
|
||||||
"experimental_settings_subtitle": "Utilisez à vos dépends !",
|
"experimental_settings_subtitle": "Utilisez à vos dépends !",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETAILS",
|
"exif_bottom_sheet_details": "DETAILS",
|
||||||
"exif_bottom_sheet_location": "LOCATION",
|
"exif_bottom_sheet_location": "LOCATION",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
||||||
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||||
"experimental_settings_subtitle": "Use at your own risk!",
|
"experimental_settings_subtitle": "Use at your own risk!",
|
||||||
|
@ -1,74 +1,74 @@
|
|||||||
{
|
{
|
||||||
"action_common_cancel": "Cancel",
|
"action_common_cancel": "Mégsem",
|
||||||
"action_common_update": "Update",
|
"action_common_update": "Frissít",
|
||||||
"add_to_album_bottom_sheet_added": "Hozzáadva a(z) {album} nevű albumhoz",
|
"add_to_album_bottom_sheet_added": "Hozzáadva a(z) {album} nevű albumhoz",
|
||||||
"add_to_album_bottom_sheet_already_exists": "Már eleme a(z) {album} nevű albumnak",
|
"add_to_album_bottom_sheet_already_exists": "Már eleme a(z) {album} nevű albumnak",
|
||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Naplózás szintje: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
"advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő elemeket. Ezzel a beállítással inkább a távoli képeket töltjük be helyette.",
|
||||||
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
"advanced_settings_prefer_remote_title": "Távoli képek preferálása",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
"advanced_settings_self_signed_ssl_subtitle": "SSL tanúsítvány ellenőrzésének kihagyása a szerver végponthoz. Ehhez saját aláírt tanúsítványok szükségesek.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
"advanced_settings_self_signed_ssl_title": "Saját aláírt SSL tanúsítványok engedélyezése",
|
||||||
"advanced_settings_tile_subtitle": "Haladó felhasználói beállítások",
|
"advanced_settings_tile_subtitle": "Haladó felhasználói beállítások",
|
||||||
"advanced_settings_tile_title": "Haladó",
|
"advanced_settings_tile_title": "Haladó",
|
||||||
"advanced_settings_troubleshooting_subtitle": "További funkciók engedélyezése hibaelhárítás céljából",
|
"advanced_settings_troubleshooting_subtitle": "További funkciók engedélyezése hibaelhárítás céljából",
|
||||||
"advanced_settings_troubleshooting_title": "Hibaelhárítás",
|
"advanced_settings_troubleshooting_title": "Hibaelhárítás",
|
||||||
"album_info_card_backup_album_excluded": "EXCLUDED",
|
"album_info_card_backup_album_excluded": "KIZÁRVA",
|
||||||
"album_info_card_backup_album_included": "INCLUDED",
|
"album_info_card_backup_album_included": "BELEÉRTVE",
|
||||||
"album_thumbnail_card_item": "1 elem",
|
"album_thumbnail_card_item": "1 elem",
|
||||||
"album_thumbnail_card_items": "{} elem",
|
"album_thumbnail_card_items": "{} elem",
|
||||||
"album_thumbnail_card_shared": "· Megosztott",
|
"album_thumbnail_card_shared": "· Megosztott",
|
||||||
"album_thumbnail_owned": "Tulajdonos",
|
"album_thumbnail_owned": "Tulajdonos",
|
||||||
"album_thumbnail_shared_by": "Megosztotta: {}",
|
"album_thumbnail_shared_by": "Megosztotta: {}",
|
||||||
"album_viewer_appbar_share_delete": "Album törlése",
|
"album_viewer_appbar_share_delete": "Album törlése",
|
||||||
"album_viewer_appbar_share_err_delete": "Hiba az album törlése közben",
|
"album_viewer_appbar_share_err_delete": "Nem sikerült törölni az albumot",
|
||||||
"album_viewer_appbar_share_err_leave": "Hiba az albumból való kilépés közben",
|
"album_viewer_appbar_share_err_leave": "Nem sikerült kilépni az albumból",
|
||||||
"album_viewer_appbar_share_err_remove": "Hiba az elemek törlése közben",
|
"album_viewer_appbar_share_err_remove": "Néhány elemet nem sikerült törölni az albumból",
|
||||||
"album_viewer_appbar_share_err_title": "Hiba az album átnevezése közben",
|
"album_viewer_appbar_share_err_title": "Nem sikerült átnevezni az albumot",
|
||||||
"album_viewer_appbar_share_leave": "Kilépés az albumból",
|
"album_viewer_appbar_share_leave": "Kilépés az albumból",
|
||||||
"album_viewer_appbar_share_remove": "Törlés az albumból",
|
"album_viewer_appbar_share_remove": "Eltávolítás az albumból",
|
||||||
"album_viewer_appbar_share_to": "Share To",
|
"album_viewer_appbar_share_to": "Megosztás Ide",
|
||||||
"album_viewer_page_share_add_users": "Felhasználók hozzáadása",
|
"album_viewer_page_share_add_users": "Felhasználók hozzáadása",
|
||||||
"all_people_page_title": "Emberek",
|
"all_people_page_title": "Emberek",
|
||||||
"all_videos_page_title": "Videók",
|
"all_videos_page_title": "Videók",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
"app_bar_signout_dialog_content": "Biztos, hogy ki szeretnél jelentkezni?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Igen",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Kijelentkezés",
|
||||||
"archive_page_no_archived_assets": "Nem található archivált média",
|
"archive_page_no_archived_assets": "Nem található archivált elem",
|
||||||
"archive_page_title": "Archívum ({})",
|
"archive_page_title": "Archívum ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "Nem sikerült törölni a csak-olvasható elem(ek)et, így ezeket átugorjuk",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "Nem sikerült betölteni az offline elem(ek)et, így ezeket kihagyjuk",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Dynamic layout",
|
"asset_list_layout_settings_dynamic_layout_title": "Dinamikus elrendezés",
|
||||||
"asset_list_layout_settings_group_automatically": "Automatikus",
|
"asset_list_layout_settings_group_automatically": "Automatikus",
|
||||||
"asset_list_layout_settings_group_by": "Group assets by",
|
"asset_list_layout_settings_group_by": "Elemek csoportosítása",
|
||||||
"asset_list_layout_settings_group_by_month": "Hónap",
|
"asset_list_layout_settings_group_by_month": "hónapok szerint",
|
||||||
"asset_list_layout_settings_group_by_month_day": "Hónap + nap",
|
"asset_list_layout_settings_group_by_month_day": "hónap és nap szerint",
|
||||||
"asset_list_settings_subtitle": "Photo grid layout settings",
|
"asset_list_settings_subtitle": "Fotórács elrendezése",
|
||||||
"asset_list_settings_title": "Photo Grid",
|
"asset_list_settings_title": "Fotórács",
|
||||||
"backup_album_selection_page_albums_device": "Az eszközön lévő albumok ({})",
|
"backup_album_selection_page_albums_device": "Ezen az eszközön lévő albumok ({})",
|
||||||
"backup_album_selection_page_albums_tap": "Tap to include, double tap to exclude",
|
"backup_album_selection_page_albums_tap": "Koppincs a hozzáadáshoz, duplán koppincs az eltávolításhoz",
|
||||||
"backup_album_selection_page_assets_scatter": "Assets can scatter across multiple albums. Thus, albums can be included or excluded during the backup process.",
|
"backup_album_selection_page_assets_scatter": "Egy elem több albumban is lehet. Ezért a mentéshez albumokat lehet hozzáadni vagy azokat a mentésből kihagyni.",
|
||||||
"backup_album_selection_page_select_albums": "Albumok kiválasztása",
|
"backup_album_selection_page_select_albums": "Válassz albumokat",
|
||||||
"backup_album_selection_page_selection_info": "Selection Info",
|
"backup_album_selection_page_selection_info": "Összegzés",
|
||||||
"backup_album_selection_page_total_assets": "Összes egyedi elem",
|
"backup_album_selection_page_total_assets": "Összes egyedi elem",
|
||||||
"backup_all": "Összes",
|
"backup_all": "Összes",
|
||||||
"backup_background_service_backup_failed_message": "HIba a mentés közben. Újrapróbálkozás...",
|
"backup_background_service_backup_failed_message": "HIba a mentés közben. Újrapróbálkozás...",
|
||||||
"backup_background_service_connection_failed_message": "HIba a szerverhez való csatlakozás közben. Újrapróbálkozás...",
|
"backup_background_service_connection_failed_message": "HIba a szerverhez való csatlakozás közben. Újrapróbálkozás...",
|
||||||
"backup_background_service_current_upload_notification": "Feltöltés {}",
|
"backup_background_service_current_upload_notification": "Feltöltés {}",
|
||||||
"backup_background_service_default_notification": "Keresés új elemek után...",
|
"backup_background_service_default_notification": "Új elemek keresése...",
|
||||||
"backup_background_service_error_title": "Hiba mentés közben",
|
"backup_background_service_error_title": "Hiba mentés közben",
|
||||||
"backup_background_service_in_progress_notification": "Elemek mentés alatt..",
|
"backup_background_service_in_progress_notification": "Elemek mentés alatt..",
|
||||||
"backup_background_service_upload_failure_notification": "Hiba feltöltés közben {}",
|
"backup_background_service_upload_failure_notification": "Hiba feltöltés közben {}",
|
||||||
"backup_controller_page_albums": "Albumok mentése",
|
"backup_controller_page_albums": "Albumok Mentése",
|
||||||
"backup_controller_page_background_app_refresh_disabled_content": "Enable background app refresh in Settings > General > Background App Refresh in order to use background backup.",
|
"backup_controller_page_background_app_refresh_disabled_content": "Engedélyezd a háttérben történő frissítést a Beállítások > Általános > Háttérben Frissítés menüpontban.",
|
||||||
"backup_controller_page_background_app_refresh_disabled_title": "Background app refresh disabled",
|
"backup_controller_page_background_app_refresh_disabled_title": "Háttérben frissítés kikapcsolva",
|
||||||
"backup_controller_page_background_app_refresh_enable_button_text": "Beállítások megnyitása",
|
"backup_controller_page_background_app_refresh_enable_button_text": "Beállítások megnyitása",
|
||||||
"backup_controller_page_background_battery_info_link": "Mutasd meg hogyan",
|
"backup_controller_page_background_battery_info_link": "Mutasd meg hogyan",
|
||||||
"backup_controller_page_background_battery_info_message": "For the best background backup experience, please disable any battery optimizations restricting background activity for Immich.\n\nSince this is device-specific, please lookup the required information for your device manufacturer.",
|
"backup_controller_page_background_battery_info_message": "A sikeres háttérben történő mentéshez kérjük, tiltsd le az Immich akkumulátor optimalizálását.\n\nMivel ezt a különféle eszközökön máshogy kell, ezért kérjük, az eszközöd gyártójától tudd meg, hogyan kell.",
|
||||||
"backup_controller_page_background_battery_info_ok": "OK",
|
"backup_controller_page_background_battery_info_ok": "OK",
|
||||||
"backup_controller_page_background_battery_info_title": "Akkumulátoroptimalizálás",
|
"backup_controller_page_background_battery_info_title": "Akkumulátor optimalizálás",
|
||||||
"backup_controller_page_background_charging": "Csak töltés közben",
|
"backup_controller_page_background_charging": "Csak töltés közben",
|
||||||
"backup_controller_page_background_configure_error": "Failed to configure the background service",
|
"backup_controller_page_background_configure_error": "Nem sikerült beállítani a háttér szolgáltatást",
|
||||||
"backup_controller_page_background_delay": "Delay new assets backup: {}",
|
"backup_controller_page_background_delay": "Új elemek mentésének késleltetése: {}",
|
||||||
"backup_controller_page_background_description": "Kapcsold be a háttérfolyamatot, hogy automatikusan mentsen elemeket az applikáció megnyitása nélkül",
|
"backup_controller_page_background_description": "Kapcsold be a háttérfolyamatot, hogy automatikusan mentsen elemeket az applikáció megnyitása nélkül",
|
||||||
"backup_controller_page_background_is_off": "Automatikus mentés a háttérben ki van kapcsolva",
|
"backup_controller_page_background_is_off": "Automatikus mentés a háttérben ki van kapcsolva",
|
||||||
"backup_controller_page_background_is_on": "Automatikus mentés a háttérben bekapcsolva",
|
"backup_controller_page_background_is_on": "Automatikus mentés a háttérben bekapcsolva",
|
||||||
@ -78,63 +78,63 @@
|
|||||||
"backup_controller_page_backup": "Mentés",
|
"backup_controller_page_backup": "Mentés",
|
||||||
"backup_controller_page_backup_selected": "Kiválasztva:",
|
"backup_controller_page_backup_selected": "Kiválasztva:",
|
||||||
"backup_controller_page_backup_sub": "Mentett fotók és videók",
|
"backup_controller_page_backup_sub": "Mentett fotók és videók",
|
||||||
"backup_controller_page_cancel": "Megszakít",
|
"backup_controller_page_cancel": "Mégsem",
|
||||||
"backup_controller_page_created": "Létrehozva: {}",
|
"backup_controller_page_created": "Létrehozva: {}",
|
||||||
"backup_controller_page_desc_backup": "Turn on foreground backup to automatically upload new assets to the server when opening the app.",
|
"backup_controller_page_desc_backup": "Ha engedélyezed az előtérben mentést, akkor az új elemek automatikusan feltöltődnek a szerverre, amikor megyitod az alkalmazást.",
|
||||||
"backup_controller_page_excluded": "Kivéve:",
|
"backup_controller_page_excluded": "Kivéve:",
|
||||||
"backup_controller_page_failed": "Sikertelen ({})",
|
"backup_controller_page_failed": "Sikertelen ({})",
|
||||||
"backup_controller_page_filename": "Fájlnév: {}[{}]",
|
"backup_controller_page_filename": "Fájlnév: {}[{}]",
|
||||||
"backup_controller_page_id": "Azonosító: {}",
|
"backup_controller_page_id": "Azonosító: {}",
|
||||||
"backup_controller_page_info": "Mentésinformációk",
|
"backup_controller_page_info": "Mentésinformációk",
|
||||||
"backup_controller_page_none_selected": "Egy sincs kiválasztva",
|
"backup_controller_page_none_selected": "Egy sincs kiválasztva",
|
||||||
"backup_controller_page_remainder": "Maradék",
|
"backup_controller_page_remainder": "Hátralévő",
|
||||||
"backup_controller_page_remainder_sub": "Hátralévő fotók és videók a kijelöltek közül",
|
"backup_controller_page_remainder_sub": "Hátralévő fotók és videók a kijelöltek közül",
|
||||||
"backup_controller_page_select": "Kiválaszt",
|
"backup_controller_page_select": "Kiválaszt",
|
||||||
"backup_controller_page_server_storage": "Szerver tárhely",
|
"backup_controller_page_server_storage": "Szerver Tárhely",
|
||||||
"backup_controller_page_start_backup": "Mentés elindítása",
|
"backup_controller_page_start_backup": "Mentés Elindítása",
|
||||||
"backup_controller_page_status_off": "Autoatikus mentés az előtérben kikapcsolva",
|
"backup_controller_page_status_off": "Automatikus mentés az előtérben kikapcsolva",
|
||||||
"backup_controller_page_status_on": "Autoatikus mentés az előtérben bekapcsolva",
|
"backup_controller_page_status_on": "Automatikus mentés az előtérben bekapcsolva",
|
||||||
"backup_controller_page_storage_format": "{} / {} felhasználva",
|
"backup_controller_page_storage_format": "{} / {} felhasználva",
|
||||||
"backup_controller_page_to_backup": "Albumok amiket mentesz",
|
"backup_controller_page_to_backup": "Mentésre kijelölt albumok",
|
||||||
"backup_controller_page_total": "Összes",
|
"backup_controller_page_total": "Összesen",
|
||||||
"backup_controller_page_total_sub": "Minden egyedi fotó és videó a kijelölt albumokból",
|
"backup_controller_page_total_sub": "Minden egyedi fotó és videó a kijelölt albumokból",
|
||||||
"backup_controller_page_turn_off": "Turn off foreground backup",
|
"backup_controller_page_turn_off": "Előtérben mentés kikapcsolása",
|
||||||
"backup_controller_page_turn_on": "Turn on foreground backup",
|
"backup_controller_page_turn_on": "Előtérben mentés bekapcsolása",
|
||||||
"backup_controller_page_uploading_file_info": "Uploading file info",
|
"backup_controller_page_uploading_file_info": "Fájl információk feltöltése",
|
||||||
"backup_err_only_album": "Az utolsó albumot nem tudod törölni",
|
"backup_err_only_album": "Az utolsó albumot nem tudod törölni",
|
||||||
"backup_info_card_assets": "elemek",
|
"backup_info_card_assets": "elemek",
|
||||||
"backup_manual_cancelled": "Megszakítva",
|
"backup_manual_cancelled": "Megszakítva",
|
||||||
"backup_manual_failed": "Failed",
|
"backup_manual_failed": "Sikertelen",
|
||||||
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
|
"backup_manual_in_progress": "Feltöltés már folyamatban. Próbáld meg később",
|
||||||
"backup_manual_success": "Sikeres",
|
"backup_manual_success": "Sikeres",
|
||||||
"backup_manual_title": "Upload status",
|
"backup_manual_title": "Feltöltés állapota",
|
||||||
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
|
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
|
||||||
"cache_settings_clear_cache_button": "Gyorsítótár törlése",
|
"cache_settings_clear_cache_button": "Gyorsítótár kiürítése",
|
||||||
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
|
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
|
||||||
"cache_settings_duplicated_assets_clear_button": "CLEAR",
|
"cache_settings_duplicated_assets_clear_button": "KIÜRÍT",
|
||||||
"cache_settings_duplicated_assets_subtitle": "Photos and videos that are black listed by the app",
|
"cache_settings_duplicated_assets_subtitle": "Fotók és videók, amiket az alkalmazás fekete listára tett",
|
||||||
"cache_settings_duplicated_assets_title": "Duplicated Assets ({})",
|
"cache_settings_duplicated_assets_title": "Duplikált Elemek ({})",
|
||||||
"cache_settings_image_cache_size": "Image cache size ({} assets)",
|
"cache_settings_image_cache_size": "Kép gyorsítótár mérete ({} elem)",
|
||||||
"cache_settings_statistics_album": "Library thumbnails",
|
"cache_settings_statistics_album": "Mappa bélyegképei",
|
||||||
"cache_settings_statistics_assets": "{} assets ({})",
|
"cache_settings_statistics_assets": "{} elem ({})",
|
||||||
"cache_settings_statistics_full": "Teljes képek",
|
"cache_settings_statistics_full": "Teljes méretű képek",
|
||||||
"cache_settings_statistics_shared": "Shared album thumbnails",
|
"cache_settings_statistics_shared": "Megosztott album bélyegképei",
|
||||||
"cache_settings_statistics_thumbnail": "Előnézeti képek",
|
"cache_settings_statistics_thumbnail": "Bélyegképek",
|
||||||
"cache_settings_statistics_title": "Gyorsítótár által használt terület",
|
"cache_settings_statistics_title": "Gyorsítótár használata",
|
||||||
"cache_settings_subtitle": "Control the caching behaviour of the Immich mobile application",
|
"cache_settings_subtitle": "Az Immich mobilalkalmazás gyorsítótár viselkedésének beállítása",
|
||||||
"cache_settings_thumbnail_size": "Thumbnail cache size ({} assets)",
|
"cache_settings_thumbnail_size": "Bélyegkép gyorsítótár mérete ({} elem)",
|
||||||
"cache_settings_tile_subtitle": "Control the local storage behaviour",
|
"cache_settings_tile_subtitle": "Helyi tárhely viselkedésének beállítása",
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Helyi Tárhely",
|
||||||
"cache_settings_title": "Gyorsítótár beállítások",
|
"cache_settings_title": "Gyorsítótár Beállítások",
|
||||||
"change_password_form_confirm_password": "Jelszó Megerősítése",
|
"change_password_form_confirm_password": "Jelszó Megerősítése",
|
||||||
"change_password_form_description": "Kedves {name}!\n\nMost jelentkezel be először a rendszerbe vagy más okból szükséfes a jelszavad meváltoztatása. Kérjük, add meg új jelszavad.",
|
"change_password_form_description": "Kedves {name}!\n\nMost jelentkezel be először a rendszerbe vagy más okból szükséges a jelszavad meváltoztatása. Kérjük, add meg új jelszavad.",
|
||||||
"change_password_form_new_password": "Új Jelszó",
|
"change_password_form_new_password": "Új Jelszó",
|
||||||
"change_password_form_password_mismatch": "A két beírt jelszó nem egyezik",
|
"change_password_form_password_mismatch": "A két beírt jelszó nem egyezik",
|
||||||
"change_password_form_reenter_new_password": "Jelszó (még egyszer)",
|
"change_password_form_reenter_new_password": "Jelszó (még egyszer)",
|
||||||
"common_add_to_album": "Albumhoz ad",
|
"common_add_to_album": "Albumhoz ad",
|
||||||
"common_change_password": "Jelszócsere",
|
"common_change_password": "Jelszócsere",
|
||||||
"common_create_new_album": "Új album létrehozása",
|
"common_create_new_album": "Új album létrehozása",
|
||||||
"common_server_error": "Kérjük, ellenőrizd a hálózati kapcsolatot, gondoskodj róla, hogy a szerver elérhető legyen, valamint az app és a szerver kompatibilis verziójú legyen.",
|
"common_server_error": "Kérjük, ellenőrizd a hálózati kapcsolatot, gondoskodj róla, hogy a szerver elérhető legyen, valamint az alkalmazás és a szerver kompatibilis verziójú legyen.",
|
||||||
"common_shared": "Megosztva",
|
"common_shared": "Megosztva",
|
||||||
"control_bottom_app_bar_add_to_album": "Hozzáadás az albumhoz",
|
"control_bottom_app_bar_add_to_album": "Hozzáadás az albumhoz",
|
||||||
"control_bottom_app_bar_album_info": "{} elem",
|
"control_bottom_app_bar_album_info": "{} elem",
|
||||||
@ -142,23 +142,23 @@
|
|||||||
"control_bottom_app_bar_archive": "Archivál",
|
"control_bottom_app_bar_archive": "Archivál",
|
||||||
"control_bottom_app_bar_create_new_album": "Album létrehozása",
|
"control_bottom_app_bar_create_new_album": "Album létrehozása",
|
||||||
"control_bottom_app_bar_delete": "Törlés",
|
"control_bottom_app_bar_delete": "Törlés",
|
||||||
"control_bottom_app_bar_delete_from_immich": "Delete from Immich",
|
"control_bottom_app_bar_delete_from_immich": "Törlés az Immich-ből",
|
||||||
"control_bottom_app_bar_delete_from_local": "Delete from device",
|
"control_bottom_app_bar_delete_from_local": "Törlés az eszközről",
|
||||||
"control_bottom_app_bar_edit_location": "Edit Location",
|
"control_bottom_app_bar_edit_location": "Hely Módosítása",
|
||||||
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
"control_bottom_app_bar_edit_time": "Dátum és Idő Módosítása",
|
||||||
"control_bottom_app_bar_favorite": "Kedvenc",
|
"control_bottom_app_bar_favorite": "Kedvenc",
|
||||||
"control_bottom_app_bar_share": "Megosztás",
|
"control_bottom_app_bar_share": "Megosztás",
|
||||||
"control_bottom_app_bar_share_to": "Share To",
|
"control_bottom_app_bar_share_to": "Megosztás Ide",
|
||||||
"control_bottom_app_bar_stack": "Stack",
|
"control_bottom_app_bar_stack": "Stack",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Lomtárba Helyez",
|
||||||
"control_bottom_app_bar_unarchive": "Archiválás megszüntetése",
|
"control_bottom_app_bar_unarchive": "Nem Archivált",
|
||||||
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
"control_bottom_app_bar_unfavorite": "Nem Kedvenc",
|
||||||
"control_bottom_app_bar_upload": "Upload",
|
"control_bottom_app_bar_upload": "Feltöltés",
|
||||||
"create_album_page_untitled": "Névtelen",
|
"create_album_page_untitled": "Névtelen",
|
||||||
"create_shared_album_page_create": "Létrehoz",
|
"create_shared_album_page_create": "Létrehoz",
|
||||||
"create_shared_album_page_share": "Megosztás",
|
"create_shared_album_page_share": "Megosztás",
|
||||||
"create_shared_album_page_share_add_assets": "ELEMEK HOZZÁADÁSA",
|
"create_shared_album_page_share_add_assets": "ELEMEK HOZZÁADÁSA",
|
||||||
"create_shared_album_page_share_select_photos": "Fotók kiválasztása",
|
"create_shared_album_page_share_select_photos": "Fotók választása",
|
||||||
"curated_location_page_title": "Helyek",
|
"curated_location_page_title": "Helyek",
|
||||||
"curated_object_page_title": "Dolgok",
|
"curated_object_page_title": "Dolgok",
|
||||||
"daily_title_text_date": "E, MMM dd",
|
"daily_title_text_date": "E, MMM dd",
|
||||||
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "RÉSZLETEK",
|
"exif_bottom_sheet_details": "RÉSZLETEK",
|
||||||
"exif_bottom_sheet_location": "HELYSZÍN",
|
"exif_bottom_sheet_location": "HELYSZÍN",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Fejlesztés alatt",
|
"experimental_settings_new_asset_list_subtitle": "Fejlesztés alatt",
|
||||||
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||||
"experimental_settings_subtitle": "Csak saját felelősségre használd",
|
"experimental_settings_subtitle": "Csak saját felelősségre használd",
|
||||||
@ -230,10 +231,10 @@
|
|||||||
"login_disabled": "A bejelentkezés letiltva",
|
"login_disabled": "A bejelentkezés letiltva",
|
||||||
"login_form_api_exception": "API hiba. Kérljük, ellenőrid a szerver címét, majd próbáld újra.",
|
"login_form_api_exception": "API hiba. Kérljük, ellenőrid a szerver címét, majd próbáld újra.",
|
||||||
"login_form_back_button_text": "Back",
|
"login_form_back_button_text": "Back",
|
||||||
"login_form_button_text": "Belépés",
|
"login_form_button_text": "Bejelentkezés",
|
||||||
"login_form_email_hint": "teemailed@email.com",
|
"login_form_email_hint": "email@cimed.hu",
|
||||||
"login_form_endpoint_hint": "http://szerver-címe:port/api",
|
"login_form_endpoint_hint": "http://szerver-címe:port/api",
|
||||||
"login_form_endpoint_url": "Kiszolgáló végpont címe",
|
"login_form_endpoint_url": "Szerver címe",
|
||||||
"login_form_err_http": "Kérem, adjon meg egy http:// vagy https:// címet",
|
"login_form_err_http": "Kérem, adjon meg egy http:// vagy https:// címet",
|
||||||
"login_form_err_invalid_email": "Érvénytelen email cím",
|
"login_form_err_invalid_email": "Érvénytelen email cím",
|
||||||
"login_form_err_invalid_url": "Érvénytelen cím",
|
"login_form_err_invalid_url": "Érvénytelen cím",
|
||||||
@ -346,7 +347,7 @@
|
|||||||
"search_suggestion_list_smart_search_hint_1": "Az intelligens keresés alapértelmezetten be van kapcsolva, metaadatokat így kereshetsz",
|
"search_suggestion_list_smart_search_hint_1": "Az intelligens keresés alapértelmezetten be van kapcsolva, metaadatokat így kereshetsz",
|
||||||
"search_suggestion_list_smart_search_hint_2": "m:keresési-kifejezés",
|
"search_suggestion_list_smart_search_hint_2": "m:keresési-kifejezés",
|
||||||
"select_additional_user_for_sharing_page_suggestions": "Javaslatok",
|
"select_additional_user_for_sharing_page_suggestions": "Javaslatok",
|
||||||
"select_user_for_sharing_page_err_album": "Hiba az album létrehozása közben",
|
"select_user_for_sharing_page_err_album": "Nem sikerült létrehozni az albumot",
|
||||||
"select_user_for_sharing_page_share_suggestions": "Javaslatok",
|
"select_user_for_sharing_page_share_suggestions": "Javaslatok",
|
||||||
"server_info_box_app_version": "Alkalmazás Verzió",
|
"server_info_box_app_version": "Alkalmazás Verzió",
|
||||||
"server_info_box_latest_release": "Latest Version",
|
"server_info_box_latest_release": "Latest Version",
|
||||||
@ -373,7 +374,7 @@
|
|||||||
"settings_require_restart": "Kérlek indítsd újra az Immich-et hogy alkalmazd ezt a beállítást",
|
"settings_require_restart": "Kérlek indítsd újra az Immich-et hogy alkalmazd ezt a beállítást",
|
||||||
"share_add": "Hozzáadás",
|
"share_add": "Hozzáadás",
|
||||||
"share_add_photos": "Fotók hozzáadása",
|
"share_add_photos": "Fotók hozzáadása",
|
||||||
"share_add_title": "Cím hozzáadása",
|
"share_add_title": "Album neve",
|
||||||
"share_create_album": "Album létrehozása",
|
"share_create_album": "Album létrehozása",
|
||||||
"shared_album_activities_input_disable": "Comment is disabled",
|
"shared_album_activities_input_disable": "Comment is disabled",
|
||||||
"shared_album_activities_input_hint": "Say something",
|
"shared_album_activities_input_hint": "Say something",
|
||||||
@ -431,11 +432,11 @@
|
|||||||
"share_done": "Done",
|
"share_done": "Done",
|
||||||
"share_invite": "Meghívás az albumba",
|
"share_invite": "Meghívás az albumba",
|
||||||
"sharing_page_album": "Megosztott albumok",
|
"sharing_page_album": "Megosztott albumok",
|
||||||
"sharing_page_description": "Hozzon létre megosztott albumokat, hogy megoszthasson fényképeket és videókat a hálózatában lévő emberekkel.",
|
"sharing_page_description": "Megosztott albumok létrehozásával fényképeket és videókatoszthatsz meg a hálózatodban lévő emberekkel.",
|
||||||
"sharing_page_empty_list": "ÜRES LISTA",
|
"sharing_page_empty_list": "ÜRES LISTA",
|
||||||
"sharing_silver_appbar_create_shared_album": "Megosztott album létrehozása",
|
"sharing_silver_appbar_create_shared_album": "Megosztott album létrehozása",
|
||||||
"sharing_silver_appbar_shared_links": "Shared links",
|
"sharing_silver_appbar_shared_links": "Shared links",
|
||||||
"sharing_silver_appbar_share_partner": "Megosztás másokkal",
|
"sharing_silver_appbar_share_partner": "Megosztás partnerrel",
|
||||||
"tab_controller_nav_library": "Könyvtár",
|
"tab_controller_nav_library": "Könyvtár",
|
||||||
"tab_controller_nav_photos": "Képek",
|
"tab_controller_nav_photos": "Képek",
|
||||||
"tab_controller_nav_search": "Keresés",
|
"tab_controller_nav_search": "Keresés",
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"action_common_cancel": "Cancel",
|
"action_common_cancel": "Annulla",
|
||||||
"action_common_update": "Update",
|
"action_common_update": "Aggiorna",
|
||||||
"add_to_album_bottom_sheet_added": "Aggiunto in {album}",
|
"add_to_album_bottom_sheet_added": "Aggiunto in {album}",
|
||||||
"add_to_album_bottom_sheet_already_exists": "Già presente in {album}",
|
"add_to_album_bottom_sheet_already_exists": "Già presente in {album}",
|
||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Livello log: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Alcuni dispositivi sono molto lenti a caricare le anteprime delle immagini dal dispositivo. Attivare questa impostazione per caricare invece le immagini remote.",
|
"advanced_settings_prefer_remote_subtitle": "Alcuni dispositivi sono molto lenti a caricare le anteprime delle immagini dal dispositivo. Attivare questa impostazione per caricare invece le immagini remote.",
|
||||||
"advanced_settings_prefer_remote_title": "Preferisci immagini remote.",
|
"advanced_settings_prefer_remote_title": "Preferisci immagini remote.",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
"advanced_settings_self_signed_ssl_subtitle": "Salta la verifica dei certificati SSL del server. Richiesto con l'uso di certificati self-signed.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
"advanced_settings_self_signed_ssl_title": "Consenti certificati SSL self-signed",
|
||||||
"advanced_settings_tile_subtitle": "Impostazioni aggiuntive utenti",
|
"advanced_settings_tile_subtitle": "Impostazioni aggiuntive utenti",
|
||||||
"advanced_settings_tile_title": "Avanzato",
|
"advanced_settings_tile_title": "Avanzato",
|
||||||
"advanced_settings_troubleshooting_subtitle": "Attiva funzioni addizionali per la risoluzione dei problemi",
|
"advanced_settings_troubleshooting_subtitle": "Attiva funzioni addizionali per la risoluzione dei problemi",
|
||||||
@ -35,7 +35,7 @@
|
|||||||
"app_bar_signout_dialog_title": "Disconnetti",
|
"app_bar_signout_dialog_title": "Disconnetti",
|
||||||
"archive_page_no_archived_assets": "Nessuna oggetto archiviato",
|
"archive_page_no_archived_assets": "Nessuna oggetto archiviato",
|
||||||
"archive_page_title": "Archivia ({})",
|
"archive_page_title": "Archivia ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "Non posso eliminare degli elementi in sola lettura, ignorato",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Layout dinamico",
|
"asset_list_layout_settings_dynamic_layout_title": "Layout dinamico",
|
||||||
"asset_list_layout_settings_group_automatically": "Automatico",
|
"asset_list_layout_settings_group_automatically": "Automatico",
|
||||||
@ -111,9 +111,9 @@
|
|||||||
"cache_settings_album_thumbnails": "Anteprime pagine librerie ({} assets)",
|
"cache_settings_album_thumbnails": "Anteprime pagine librerie ({} assets)",
|
||||||
"cache_settings_clear_cache_button": "Cancella cache",
|
"cache_settings_clear_cache_button": "Cancella cache",
|
||||||
"cache_settings_clear_cache_button_title": "Cancella la cache dell'app. Questo impatterà significativamente le prestazioni dell''app fino a quando la cache non sarà rigenerata.",
|
"cache_settings_clear_cache_button_title": "Cancella la cache dell'app. Questo impatterà significativamente le prestazioni dell''app fino a quando la cache non sarà rigenerata.",
|
||||||
"cache_settings_duplicated_assets_clear_button": "CLEAR",
|
"cache_settings_duplicated_assets_clear_button": "ELIMINA",
|
||||||
"cache_settings_duplicated_assets_subtitle": "Photos and videos that are black listed by the app",
|
"cache_settings_duplicated_assets_subtitle": "Foto e video che sono nella black list dell'applicazione",
|
||||||
"cache_settings_duplicated_assets_title": "Duplicated Assets ({})",
|
"cache_settings_duplicated_assets_title": "Elementi duplicati ({})",
|
||||||
"cache_settings_image_cache_size": "Dimensione cache delle foto ({} assets)",
|
"cache_settings_image_cache_size": "Dimensione cache delle foto ({} assets)",
|
||||||
"cache_settings_statistics_album": "Anteprime librerie",
|
"cache_settings_statistics_album": "Anteprime librerie",
|
||||||
"cache_settings_statistics_assets": "{} contenuti ({})",
|
"cache_settings_statistics_assets": "{} contenuti ({})",
|
||||||
@ -142,15 +142,15 @@
|
|||||||
"control_bottom_app_bar_archive": "Archivia",
|
"control_bottom_app_bar_archive": "Archivia",
|
||||||
"control_bottom_app_bar_create_new_album": "Crea nuovo album",
|
"control_bottom_app_bar_create_new_album": "Crea nuovo album",
|
||||||
"control_bottom_app_bar_delete": "Elimina",
|
"control_bottom_app_bar_delete": "Elimina",
|
||||||
"control_bottom_app_bar_delete_from_immich": "Delete from Immich",
|
"control_bottom_app_bar_delete_from_immich": "Elimina da Immich",
|
||||||
"control_bottom_app_bar_delete_from_local": "Delete from device",
|
"control_bottom_app_bar_delete_from_local": "Elimina dal dispositivo",
|
||||||
"control_bottom_app_bar_edit_location": "Edit Location",
|
"control_bottom_app_bar_edit_location": "Modifica posizione",
|
||||||
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
"control_bottom_app_bar_edit_time": "Modifica data e ora",
|
||||||
"control_bottom_app_bar_favorite": "Preferiti",
|
"control_bottom_app_bar_favorite": "Preferiti",
|
||||||
"control_bottom_app_bar_share": "Condividi",
|
"control_bottom_app_bar_share": "Condividi",
|
||||||
"control_bottom_app_bar_share_to": "Share To",
|
"control_bottom_app_bar_share_to": "Share To",
|
||||||
"control_bottom_app_bar_stack": "Stack",
|
"control_bottom_app_bar_stack": "Stack",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Sposta nel cestino",
|
||||||
"control_bottom_app_bar_unarchive": "Rimuovi dagli archivi",
|
"control_bottom_app_bar_unarchive": "Rimuovi dagli archivi",
|
||||||
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
||||||
"control_bottom_app_bar_upload": "Upload",
|
"control_bottom_app_bar_upload": "Upload",
|
||||||
@ -165,26 +165,27 @@
|
|||||||
"daily_title_text_date_year": "E, dd MMM, yyyy",
|
"daily_title_text_date_year": "E, dd MMM, yyyy",
|
||||||
"date_format": "E, d LLL, y • hh:mm",
|
"date_format": "E, d LLL, y • hh:mm",
|
||||||
"delete_dialog_alert": "Questi oggetti saranno cancellati definitivamente da Immich e dal tuo device",
|
"delete_dialog_alert": "Questi oggetti saranno cancellati definitivamente da Immich e dal tuo device",
|
||||||
"delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server",
|
"delete_dialog_alert_local": "Questi elementi verranno eliminati definitivamente dal dispositivo, ma saranno ancora disponibili sul server Immich",
|
||||||
"delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device",
|
"delete_dialog_alert_local_non_backed_up": "Alcuni degli elementi non sono stati caricati su Immich e saranno rimossi definitivamente dal tuo dispositivo",
|
||||||
"delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server",
|
"delete_dialog_alert_remote": "Questi elementi verranno eliminati permanentemente dal server Immich",
|
||||||
"delete_dialog_cancel": "Annulla",
|
"delete_dialog_cancel": "Annulla",
|
||||||
"delete_dialog_ok": "Elimina",
|
"delete_dialog_ok": "Elimina",
|
||||||
"delete_dialog_ok_force": "Delete Anyway",
|
"delete_dialog_ok_force": "Elimina comunque",
|
||||||
"delete_dialog_title": "Cancella definitivamente",
|
"delete_dialog_title": "Cancella definitivamente",
|
||||||
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
|
"delete_local_dialog_ok_backed_up_only": "Elimina solo quelli con backup",
|
||||||
"delete_local_dialog_ok_force": "Delete Anyway",
|
"delete_local_dialog_ok_force": "Elimina comunque",
|
||||||
"delete_shared_link_dialog_content": "Sei sicuro di voler eliminare questo link condiviso?",
|
"delete_shared_link_dialog_content": "Sei sicuro di voler eliminare questo link condiviso?",
|
||||||
"delete_shared_link_dialog_title": "Elimina link condiviso",
|
"delete_shared_link_dialog_title": "Elimina link condiviso",
|
||||||
"description_input_hint_text": "Aggiungi descrizione...",
|
"description_input_hint_text": "Aggiungi descrizione...",
|
||||||
"description_input_submit_error": "Errore modificare descrizione, controlli I log per maggiori dettagli",
|
"description_input_submit_error": "Errore modificare descrizione, controlli I log per maggiori dettagli",
|
||||||
"edit_date_time_dialog_date_time": "Date and Time",
|
"edit_date_time_dialog_date_time": "Data e ora",
|
||||||
"edit_date_time_dialog_timezone": "Timezone",
|
"edit_date_time_dialog_timezone": "Fuso orario",
|
||||||
"edit_location_dialog_title": "Location",
|
"edit_location_dialog_title": "Posizione",
|
||||||
"exif_bottom_sheet_description": "Aggiungi una descrizione...",
|
"exif_bottom_sheet_description": "Aggiungi una descrizione...",
|
||||||
"exif_bottom_sheet_details": "DETTAGLI",
|
"exif_bottom_sheet_details": "DETTAGLI",
|
||||||
"exif_bottom_sheet_location": "POSIZIONE",
|
"exif_bottom_sheet_location": "POSIZIONE",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Aggiungi una posizione",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
||||||
"experimental_settings_new_asset_list_title": "Attiva griglia di foto sperimentale",
|
"experimental_settings_new_asset_list_title": "Attiva griglia di foto sperimentale",
|
||||||
"experimental_settings_subtitle": "Usalo a tuo rischio!",
|
"experimental_settings_subtitle": "Usalo a tuo rischio!",
|
||||||
@ -199,7 +200,7 @@
|
|||||||
"home_page_archive_err_partner": "Can not archive partner assets, skipping",
|
"home_page_archive_err_partner": "Can not archive partner assets, skipping",
|
||||||
"home_page_building_timeline": "Costruendo il Timeline",
|
"home_page_building_timeline": "Costruendo il Timeline",
|
||||||
"home_page_delete_err_partner": "Can not delete partner assets, skipping",
|
"home_page_delete_err_partner": "Can not delete partner assets, skipping",
|
||||||
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
"home_page_delete_remote_err_local": "Immagini sul disco locale presenti pure nella selezione degli elementi remoti, skippando",
|
||||||
"home_page_favorite_err_local": "Non puoi aggiungere tra i preferiti le foto ancora non caricate",
|
"home_page_favorite_err_local": "Non puoi aggiungere tra i preferiti le foto ancora non caricate",
|
||||||
"home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping",
|
"home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping",
|
||||||
"home_page_first_time_notice": "Se è la prima volta che usi l'app, assicurati di scegliere gli album per avere il Timeline con immagini e video",
|
"home_page_first_time_notice": "Se è la prima volta che usi l'app, assicurati di scegliere gli album per avere il Timeline con immagini e video",
|
||||||
@ -214,22 +215,22 @@
|
|||||||
"library_page_favorites": "Preferiti",
|
"library_page_favorites": "Preferiti",
|
||||||
"library_page_new_album": "Nuovo Album",
|
"library_page_new_album": "Nuovo Album",
|
||||||
"library_page_sharing": "Condividendo",
|
"library_page_sharing": "Condividendo",
|
||||||
"library_page_sort_asset_count": "Number of assets",
|
"library_page_sort_asset_count": "Numero di elementi",
|
||||||
"library_page_sort_created": "Creato il più recente",
|
"library_page_sort_created": "Creato il più recente",
|
||||||
"library_page_sort_last_modified": "Ultima modifica",
|
"library_page_sort_last_modified": "Ultima modifica",
|
||||||
"library_page_sort_most_oldest_photo": "Oldest photo",
|
"library_page_sort_most_oldest_photo": "Foto più vecchia",
|
||||||
"library_page_sort_most_recent_photo": "Più recente",
|
"library_page_sort_most_recent_photo": "Più recente",
|
||||||
"library_page_sort_title": "Titolo album",
|
"library_page_sort_title": "Titolo album",
|
||||||
"location_picker_choose_on_map": "Choose on map",
|
"location_picker_choose_on_map": "Scegli una mappa",
|
||||||
"location_picker_latitude": "Latitude",
|
"location_picker_latitude": "Latitudine",
|
||||||
"location_picker_latitude_error": "Enter a valid latitude",
|
"location_picker_latitude_error": "Inserisci una latitudine valida",
|
||||||
"location_picker_latitude_hint": "Enter your latitude here",
|
"location_picker_latitude_hint": "Inserisci la tua latitudine qui",
|
||||||
"location_picker_longitude": "Longitude",
|
"location_picker_longitude": "Longitudine",
|
||||||
"location_picker_longitude_error": "Enter a valid longitude",
|
"location_picker_longitude_error": "Inserisci una longitudine valida",
|
||||||
"location_picker_longitude_hint": "Enter your longitude here",
|
"location_picker_longitude_hint": "Inserisci la longitudine qui",
|
||||||
"login_disabled": "L'accesso è stato disattivato",
|
"login_disabled": "L'accesso è stato disattivato",
|
||||||
"login_form_api_exception": "API error, per favore ricontrolli URL del server e riprovi",
|
"login_form_api_exception": "API error, per favore ricontrolli URL del server e riprovi",
|
||||||
"login_form_back_button_text": "Back",
|
"login_form_back_button_text": "Indietro",
|
||||||
"login_form_button_text": "Login",
|
"login_form_button_text": "Login",
|
||||||
"login_form_email_hint": "tuaemail@email.com",
|
"login_form_email_hint": "tuaemail@email.com",
|
||||||
"login_form_endpoint_hint": "http://ip-del-tuo-server:port/api",
|
"login_form_endpoint_hint": "http://ip-del-tuo-server:port/api",
|
||||||
@ -252,35 +253,35 @@
|
|||||||
"login_form_server_error": "Non è possibile connettersi al server",
|
"login_form_server_error": "Non è possibile connettersi al server",
|
||||||
"login_password_changed_error": "C'è stato un errore durante l'aggiornamento della password",
|
"login_password_changed_error": "C'è stato un errore durante l'aggiornamento della password",
|
||||||
"login_password_changed_success": "Password aggiornata con successo",
|
"login_password_changed_success": "Password aggiornata con successo",
|
||||||
"map_assets_in_bound": "{} photo",
|
"map_assets_in_bound": "{} foto",
|
||||||
"map_assets_in_bounds": "{} photos",
|
"map_assets_in_bounds": "{} foto",
|
||||||
"map_cannot_get_user_location": "Cannot get user's location",
|
"map_cannot_get_user_location": "Cannot get user's location",
|
||||||
"map_location_dialog_cancel": "Annulla",
|
"map_location_dialog_cancel": "Annulla",
|
||||||
"map_location_dialog_yes": "Si",
|
"map_location_dialog_yes": "Si",
|
||||||
"map_location_picker_page_use_location": "Use this location",
|
"map_location_picker_page_use_location": "Usa questa posizione",
|
||||||
"map_location_service_disabled_content": "Location service needs to be enabled to display assets from your current location. Do you want to enable it now?",
|
"map_location_service_disabled_content": "I servizi di geolocalizzazione devono essere attivati per visualizzare gli elementi per la tua posizione attuale. Vuoi attivarli adesso?",
|
||||||
"map_location_service_disabled_title": "Location Service disabled",
|
"map_location_service_disabled_title": "Location Service disabled",
|
||||||
"map_no_assets_in_bounds": "Nessuna foto in questa zona",
|
"map_no_assets_in_bounds": "Nessuna foto in questa zona",
|
||||||
"map_no_location_permission_content": "Location permission is needed to display assets from your current location. Do you want to allow it now?",
|
"map_no_location_permission_content": "L'accesso alla posizione è necessario per visualizzare gli elementi per la tua posizione attuale. Vuoi consentirlo adesso?",
|
||||||
"map_no_location_permission_title": "Location Permission denied",
|
"map_no_location_permission_title": "Location Permission denied",
|
||||||
"map_settings_dark_mode": "Modalità scura",
|
"map_settings_dark_mode": "Modalità scura",
|
||||||
"map_settings_date_range_option_all": "All",
|
"map_settings_date_range_option_all": "All",
|
||||||
"map_settings_date_range_option_day": "Past 24 hours",
|
"map_settings_date_range_option_day": "Ultime 24 ore",
|
||||||
"map_settings_date_range_option_days": "Past {} days",
|
"map_settings_date_range_option_days": "Ultimi {} giorni",
|
||||||
"map_settings_date_range_option_year": "Past year",
|
"map_settings_date_range_option_year": "Ultimo anno",
|
||||||
"map_settings_date_range_option_years": "Past {} years",
|
"map_settings_date_range_option_years": "Ultimi {} anni",
|
||||||
"map_settings_dialog_cancel": "Cancel",
|
"map_settings_dialog_cancel": "Cancel",
|
||||||
"map_settings_dialog_save": "Salva",
|
"map_settings_dialog_save": "Salva",
|
||||||
"map_settings_dialog_title": "Map Settings",
|
"map_settings_dialog_title": "Map Settings",
|
||||||
"map_settings_include_show_archived": "Include Archived",
|
"map_settings_include_show_archived": "Include Archived",
|
||||||
"map_settings_only_relative_range": "Date range",
|
"map_settings_only_relative_range": "Date range",
|
||||||
"map_settings_only_show_favorites": "Show Favorite Only",
|
"map_settings_only_show_favorites": "Show Favorite Only",
|
||||||
"map_settings_theme_settings": "Map Theme",
|
"map_settings_theme_settings": "Tema della mappa",
|
||||||
"map_zoom_to_see_photos": "Zoom out to see photos",
|
"map_zoom_to_see_photos": "Zoom out to see photos",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Motion Foto",
|
"motion_photos_page_title": "Motion Foto",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Non posso modificare la data degli elementi in sola lettura, ignorato",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
"multiselect_grid_edit_gps_err_read_only": "Non posso modificare la posizione degli elementi in sola lettura, ignorato",
|
||||||
"notification_permission_dialog_cancel": "Annulla",
|
"notification_permission_dialog_cancel": "Annulla",
|
||||||
"notification_permission_dialog_content": "Per attivare le notifiche, vai alle Impostazioni e seleziona concedi",
|
"notification_permission_dialog_content": "Per attivare le notifiche, vai alle Impostazioni e seleziona concedi",
|
||||||
"notification_permission_dialog_settings": "Impostazioni",
|
"notification_permission_dialog_settings": "Impostazioni",
|
||||||
@ -307,18 +308,18 @@
|
|||||||
"permission_onboarding_permission_limited": "Permessi limitati. Perché Immich possa controllare e fare i backup di tutte le foto, concedere i permessi all'intera galleria dalle impostazioni ",
|
"permission_onboarding_permission_limited": "Permessi limitati. Perché Immich possa controllare e fare i backup di tutte le foto, concedere i permessi all'intera galleria dalle impostazioni ",
|
||||||
"permission_onboarding_request": "Immich richiede i permessi per vedere le tue foto e video",
|
"permission_onboarding_request": "Immich richiede i permessi per vedere le tue foto e video",
|
||||||
"profile_drawer_app_logs": "Logs",
|
"profile_drawer_app_logs": "Logs",
|
||||||
"profile_drawer_client_out_of_date_major": "Mobile App is out of date. Please update to the latest major version.",
|
"profile_drawer_client_out_of_date_major": "L'applicazione non è aggiornata. Per favore aggiorna all'ultima versione principale.",
|
||||||
"profile_drawer_client_out_of_date_minor": "Mobile App is out of date. Please update to the latest minor version.",
|
"profile_drawer_client_out_of_date_minor": "L'applicazione non è aggiornata. Per favore aggiorna all'ultima versione minore.",
|
||||||
"profile_drawer_client_server_up_to_date": "Client e server sono aggiornati",
|
"profile_drawer_client_server_up_to_date": "Client e server sono aggiornati",
|
||||||
"profile_drawer_documentation": "Documentazione",
|
"profile_drawer_documentation": "Documentazione",
|
||||||
"profile_drawer_github": "GitHub",
|
"profile_drawer_github": "GitHub",
|
||||||
"profile_drawer_server_out_of_date_major": "Server is out of date. Please update to the latest major version.",
|
"profile_drawer_server_out_of_date_major": "Il server non è aggiornato. Per favore aggiorna all'ultima versione principale.",
|
||||||
"profile_drawer_server_out_of_date_minor": "Server is out of date. Please update to the latest minor version.",
|
"profile_drawer_server_out_of_date_minor": "Il server non è aggiornato. Per favore aggiorna all'ultima versione minore.",
|
||||||
"profile_drawer_settings": "Impostazioni ",
|
"profile_drawer_settings": "Impostazioni ",
|
||||||
"profile_drawer_sign_out": "Logout",
|
"profile_drawer_sign_out": "Logout",
|
||||||
"profile_drawer_trash": "Trash",
|
"profile_drawer_trash": "Trash",
|
||||||
"recently_added_page_title": "Aggiunti di recente",
|
"recently_added_page_title": "Aggiunti di recente",
|
||||||
"scaffold_body_error_occurred": "Error occurred",
|
"scaffold_body_error_occurred": "Si è verificato un errore.",
|
||||||
"search_bar_hint": "Cerca le tue foto",
|
"search_bar_hint": "Cerca le tue foto",
|
||||||
"search_page_categories": "Categoria",
|
"search_page_categories": "Categoria",
|
||||||
"search_page_favorites": "Preferiti",
|
"search_page_favorites": "Preferiti",
|
||||||
@ -326,13 +327,13 @@
|
|||||||
"search_page_no_objects": "Nessuna informazione relativa all'oggetto disponibile",
|
"search_page_no_objects": "Nessuna informazione relativa all'oggetto disponibile",
|
||||||
"search_page_no_places": "Nessun informazione sul luogo disponibile",
|
"search_page_no_places": "Nessun informazione sul luogo disponibile",
|
||||||
"search_page_people": "Persone",
|
"search_page_people": "Persone",
|
||||||
"search_page_person_add_name_dialog_cancel": "Cancel",
|
"search_page_person_add_name_dialog_cancel": "Annulla",
|
||||||
"search_page_person_add_name_dialog_hint": "Name",
|
"search_page_person_add_name_dialog_hint": "Nome",
|
||||||
"search_page_person_add_name_dialog_save": "Save",
|
"search_page_person_add_name_dialog_save": "Salva",
|
||||||
"search_page_person_add_name_dialog_title": "Add a name",
|
"search_page_person_add_name_dialog_title": "Aggiungi un nome",
|
||||||
"search_page_person_add_name_subtitle": "Find them fast by name with search",
|
"search_page_person_add_name_subtitle": "Find them fast by name with search",
|
||||||
"search_page_person_add_name_title": "Add a name",
|
"search_page_person_add_name_title": "Aggiungi un nome",
|
||||||
"search_page_person_edit_name": "Edit name",
|
"search_page_person_edit_name": "Modifica nome",
|
||||||
"search_page_places": "Luoghi",
|
"search_page_places": "Luoghi",
|
||||||
"search_page_recently_added": "Aggiunte di recente",
|
"search_page_recently_added": "Aggiunte di recente",
|
||||||
"search_page_screenshots": "Screenshot",
|
"search_page_screenshots": "Screenshot",
|
||||||
@ -341,7 +342,7 @@
|
|||||||
"search_page_videos": "Video",
|
"search_page_videos": "Video",
|
||||||
"search_page_view_all_button": "Guarda tutto",
|
"search_page_view_all_button": "Guarda tutto",
|
||||||
"search_page_your_activity": "Tua attività ",
|
"search_page_your_activity": "Tua attività ",
|
||||||
"search_page_your_map": "Your Map",
|
"search_page_your_map": "La tua mappa",
|
||||||
"search_result_page_new_search_hint": "Nuova ricerca ",
|
"search_result_page_new_search_hint": "Nuova ricerca ",
|
||||||
"search_suggestion_list_smart_search_hint_1": "\nRicerca Smart è attiva di default, per usare la ricerca con i metadata usare la seguente sintassi",
|
"search_suggestion_list_smart_search_hint_1": "\nRicerca Smart è attiva di default, per usare la ricerca con i metadata usare la seguente sintassi",
|
||||||
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
||||||
@ -381,17 +382,17 @@
|
|||||||
"shared_album_activity_remove_title": "Elimina attività",
|
"shared_album_activity_remove_title": "Elimina attività",
|
||||||
"shared_album_activity_setting_subtitle": "Let others respond",
|
"shared_album_activity_setting_subtitle": "Let others respond",
|
||||||
"shared_album_activity_setting_title": "Commenti e Mi piace",
|
"shared_album_activity_setting_title": "Commenti e Mi piace",
|
||||||
"shared_album_section_people_action_error": "Error leaving/removing from album",
|
"shared_album_section_people_action_error": "Errore durante la rimozione/uscita dell'album",
|
||||||
"shared_album_section_people_action_leave": "Remove user from album",
|
"shared_album_section_people_action_leave": "Rimuovi utente dall'album",
|
||||||
"shared_album_section_people_action_remove_user": "Remove user from album",
|
"shared_album_section_people_action_remove_user": "Rimuovi utente dall'album",
|
||||||
"shared_album_section_people_owner_label": "Owner",
|
"shared_album_section_people_owner_label": "Proprietario",
|
||||||
"shared_album_section_people_title": "PEOPLE",
|
"shared_album_section_people_title": "PERSONE",
|
||||||
"share_dialog_preparing": "Preparo…",
|
"share_dialog_preparing": "Preparo…",
|
||||||
"shared_link_app_bar_title": "Link condivisi",
|
"shared_link_app_bar_title": "Link condivisi",
|
||||||
"shared_link_clipboard_copied_massage": "Copied to clipboard",
|
"shared_link_clipboard_copied_massage": "Copiato negli appunti",
|
||||||
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
||||||
"shared_link_create_app_bar_title": "Crea link di condivisione",
|
"shared_link_create_app_bar_title": "Crea link di condivisione",
|
||||||
"shared_link_create_error": "Error while creating shared link",
|
"shared_link_create_error": "Si è verificato un errore durante la creazione del link condiviso",
|
||||||
"shared_link_create_info": "Consenti a chiunque abbia il link di vedere le foto selezionate",
|
"shared_link_create_info": "Consenti a chiunque abbia il link di vedere le foto selezionate",
|
||||||
"shared_link_create_submit_button": "Crea link di condivisione",
|
"shared_link_create_submit_button": "Crea link di condivisione",
|
||||||
"shared_link_edit_allow_download": "Consenti ad utenti pubblici di scaricare i contenuti",
|
"shared_link_edit_allow_download": "Consenti ad utenti pubblici di scaricare i contenuti",
|
||||||
@ -401,32 +402,32 @@
|
|||||||
"shared_link_edit_description": "Descrizione",
|
"shared_link_edit_description": "Descrizione",
|
||||||
"shared_link_edit_description_hint": "Inserisci la descrizione della condivisione",
|
"shared_link_edit_description_hint": "Inserisci la descrizione della condivisione",
|
||||||
"shared_link_edit_expire_after": "Scade dopo",
|
"shared_link_edit_expire_after": "Scade dopo",
|
||||||
"shared_link_edit_expire_after_option_day": "1 day",
|
"shared_link_edit_expire_after_option_day": "1 giorno",
|
||||||
"shared_link_edit_expire_after_option_days": "{} days",
|
"shared_link_edit_expire_after_option_days": "{} giorni",
|
||||||
"shared_link_edit_expire_after_option_hour": "1 hour",
|
"shared_link_edit_expire_after_option_hour": "1 ora",
|
||||||
"shared_link_edit_expire_after_option_hours": "{} hours",
|
"shared_link_edit_expire_after_option_hours": "{} ore",
|
||||||
"shared_link_edit_expire_after_option_minute": "1 minute",
|
"shared_link_edit_expire_after_option_minute": "1 minuto",
|
||||||
"shared_link_edit_expire_after_option_minutes": "{} minutes",
|
"shared_link_edit_expire_after_option_minutes": "{} minuti",
|
||||||
"shared_link_edit_expire_after_option_never": "Never",
|
"shared_link_edit_expire_after_option_never": "Mai",
|
||||||
"shared_link_edit_password": "Password",
|
"shared_link_edit_password": "Password",
|
||||||
"shared_link_edit_password_hint": "Inserire la password di condivisione",
|
"shared_link_edit_password_hint": "Inserire la password di condivisione",
|
||||||
"shared_link_edit_show_meta": "Visualizza metadati",
|
"shared_link_edit_show_meta": "Visualizza metadati",
|
||||||
"shared_link_edit_submit_button": "Aggiorna link",
|
"shared_link_edit_submit_button": "Aggiorna link",
|
||||||
"shared_link_empty": "Non hai alcun link condiviso",
|
"shared_link_empty": "Non hai alcun link condiviso",
|
||||||
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
||||||
"shared_link_expired": "Expired",
|
"shared_link_expired": "Scaduto",
|
||||||
"shared_link_expires_day": "Expires in {} day",
|
"shared_link_expires_day": "Scade tra {} giorno",
|
||||||
"shared_link_expires_days": "Expires in {} days",
|
"shared_link_expires_days": "Scade tra {} giorni",
|
||||||
"shared_link_expires_hour": "Expires in {} hour",
|
"shared_link_expires_hour": "Scade tra {} ora",
|
||||||
"shared_link_expires_hours": "Expires in {} hours",
|
"shared_link_expires_hours": "Scade tra {} ore",
|
||||||
"shared_link_expires_minute": "Expires in {} minute",
|
"shared_link_expires_minute": "Scade tra {} minuto",
|
||||||
"shared_link_expires_minutes": "Expires in {} minutes",
|
"shared_link_expires_minutes": "Scade tra {} minuti",
|
||||||
"shared_link_expires_never": "Expires ∞",
|
"shared_link_expires_never": "Scadenza ∞",
|
||||||
"shared_link_expires_second": "Expires in {} second",
|
"shared_link_expires_second": "Scade tra {} secondo",
|
||||||
"shared_link_expires_seconds": "Expires in {} seconds",
|
"shared_link_expires_seconds": "Scade tra {} secondi",
|
||||||
"shared_link_info_chip_download": "Download",
|
"shared_link_info_chip_download": "Scarica",
|
||||||
"shared_link_info_chip_metadata": "EXIF",
|
"shared_link_info_chip_metadata": "EXIF",
|
||||||
"shared_link_info_chip_upload": "Upload",
|
"shared_link_info_chip_upload": "Carica",
|
||||||
"shared_link_manage_links": "Gestisci link condivisi",
|
"shared_link_manage_links": "Gestisci link condivisi",
|
||||||
"share_done": "Done",
|
"share_done": "Done",
|
||||||
"share_invite": "Invita nell'album ",
|
"share_invite": "Invita nell'album ",
|
||||||
@ -454,7 +455,7 @@
|
|||||||
"trash_page_delete": "Elimina",
|
"trash_page_delete": "Elimina",
|
||||||
"trash_page_delete_all": "Elimina tutti",
|
"trash_page_delete_all": "Elimina tutti",
|
||||||
"trash_page_empty_trash_btn": "Svuota cestino",
|
"trash_page_empty_trash_btn": "Svuota cestino",
|
||||||
"trash_page_empty_trash_dialog_content": "Do you want to empty your trashed assets? These items will be permanently removed from Immich",
|
"trash_page_empty_trash_dialog_content": "Vuoi eliminare gli elementi nel cestino? Questi elementi saranno eliminati definitivamente da Immich",
|
||||||
"trash_page_empty_trash_dialog_ok": "Ok",
|
"trash_page_empty_trash_dialog_ok": "Ok",
|
||||||
"trash_page_info": "Gli elementi cestinati saranno eliminati definitivamente dopo {} giorni",
|
"trash_page_info": "Gli elementi cestinati saranno eliminati definitivamente dopo {} giorni",
|
||||||
"trash_page_no_assets": "Nessun elemento cestinato",
|
"trash_page_no_assets": "Nessun elemento cestinato",
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"action_common_cancel": "Cancel",
|
"action_common_cancel": "キャンセル",
|
||||||
"action_common_update": "Update",
|
"action_common_update": "更新",
|
||||||
"add_to_album_bottom_sheet_added": "{album}に追加",
|
"add_to_album_bottom_sheet_added": "{album}に追加",
|
||||||
"add_to_album_bottom_sheet_already_exists": "{album}に追加済み",
|
"add_to_album_bottom_sheet_already_exists": "{album}に追加済み",
|
||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "ログレベル: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
"advanced_settings_prefer_remote_subtitle": "端末によっては端末上に存在するサムネイルのロードに非常に時間がかかります。このオプションをに有効にする事によってサーバーから直接画像をロードすることが可能です",
|
||||||
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
"advanced_settings_prefer_remote_title": "リモートを優先する",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
"advanced_settings_self_signed_ssl_subtitle": "SSLのチェックをスキップする。Self-signedな署名で必要です",
|
||||||
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
"advanced_settings_self_signed_ssl_title": "Self-signed署名を許可する",
|
||||||
"advanced_settings_tile_subtitle": "追加ユーザー設定",
|
"advanced_settings_tile_subtitle": "追加ユーザー設定",
|
||||||
"advanced_settings_tile_title": "詳細設定",
|
"advanced_settings_tile_title": "詳細設定",
|
||||||
"advanced_settings_troubleshooting_subtitle": "トラブルシューティング用の詳細設定をオンにする",
|
"advanced_settings_troubleshooting_subtitle": "トラブルシューティング用の詳細設定をオンにする",
|
||||||
@ -26,17 +26,17 @@
|
|||||||
"album_viewer_appbar_share_err_title": "タイトル変更の失敗",
|
"album_viewer_appbar_share_err_title": "タイトル変更の失敗",
|
||||||
"album_viewer_appbar_share_leave": "アルバムから脱退",
|
"album_viewer_appbar_share_leave": "アルバムから脱退",
|
||||||
"album_viewer_appbar_share_remove": "アルバムから削除",
|
"album_viewer_appbar_share_remove": "アルバムから削除",
|
||||||
"album_viewer_appbar_share_to": "Share To",
|
"album_viewer_appbar_share_to": "次の方々と共有します",
|
||||||
"album_viewer_page_share_add_users": "ユーザーを追加",
|
"album_viewer_page_share_add_users": "ユーザーを追加",
|
||||||
"all_people_page_title": "People",
|
"all_people_page_title": "ピープル",
|
||||||
"all_videos_page_title": "ビデオ",
|
"all_videos_page_title": "ビデオ",
|
||||||
"app_bar_signout_dialog_content": " サインアウトしますか?",
|
"app_bar_signout_dialog_content": " サインアウトしますか?",
|
||||||
"app_bar_signout_dialog_ok": "はい",
|
"app_bar_signout_dialog_ok": "はい",
|
||||||
"app_bar_signout_dialog_title": " サインアウト",
|
"app_bar_signout_dialog_title": " サインアウト",
|
||||||
"archive_page_no_archived_assets": "アーカイブ済みの写真またはビデオがありません",
|
"archive_page_no_archived_assets": "アーカイブ済みの写真またはビデオがありません",
|
||||||
"archive_page_title": "アーカイブ({})",
|
"archive_page_title": "アーカイブ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "読み取り専用の項目は削除できません。スキップします",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "オフラインの項目をゲットできません。スキップします",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "ダイナミックレイアウト",
|
"asset_list_layout_settings_dynamic_layout_title": "ダイナミックレイアウト",
|
||||||
"asset_list_layout_settings_group_automatically": "自動",
|
"asset_list_layout_settings_group_automatically": "自動",
|
||||||
"asset_list_layout_settings_group_by": "写真のグループ分け",
|
"asset_list_layout_settings_group_by": "写真のグループ分け",
|
||||||
@ -103,17 +103,17 @@
|
|||||||
"backup_controller_page_uploading_file_info": "アップロード中のファイル",
|
"backup_controller_page_uploading_file_info": "アップロード中のファイル",
|
||||||
"backup_err_only_album": "最低1つのアルバムを選択してください",
|
"backup_err_only_album": "最低1つのアルバムを選択してください",
|
||||||
"backup_info_card_assets": "写真と動画",
|
"backup_info_card_assets": "写真と動画",
|
||||||
"backup_manual_cancelled": "Cancelled",
|
"backup_manual_cancelled": "キャンセルされました",
|
||||||
"backup_manual_failed": "Failed",
|
"backup_manual_failed": "失敗",
|
||||||
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
|
"backup_manual_in_progress": "アップロードが進行中です。後でもう一度試してください",
|
||||||
"backup_manual_success": "Success",
|
"backup_manual_success": "成功",
|
||||||
"backup_manual_title": "Upload status",
|
"backup_manual_title": "アップロード状況",
|
||||||
"cache_settings_album_thumbnails": "ライブラリのサムネイル ({}枚)",
|
"cache_settings_album_thumbnails": "ライブラリのサムネイル ({}枚)",
|
||||||
"cache_settings_clear_cache_button": "キャッシュをクリア",
|
"cache_settings_clear_cache_button": "キャッシュをクリア",
|
||||||
"cache_settings_clear_cache_button_title": "キャッシュを削除(キャッシュ再生成までアプリのパフォーマンスが著しく低下)",
|
"cache_settings_clear_cache_button_title": "キャッシュを削除(キャッシュ再生成までアプリのパフォーマンスが著しく低下)",
|
||||||
"cache_settings_duplicated_assets_clear_button": "CLEAR",
|
"cache_settings_duplicated_assets_clear_button": "クリア",
|
||||||
"cache_settings_duplicated_assets_subtitle": "Photos and videos that are black listed by the app",
|
"cache_settings_duplicated_assets_subtitle": "アプリがブラックリストに追加している項目",
|
||||||
"cache_settings_duplicated_assets_title": "Duplicated Assets ({})",
|
"cache_settings_duplicated_assets_title": "{}項目が重複",
|
||||||
"cache_settings_image_cache_size": "キャッシュのサイズ ({}枚) ",
|
"cache_settings_image_cache_size": "キャッシュのサイズ ({}枚) ",
|
||||||
"cache_settings_statistics_album": "ライブラリのサムネイル",
|
"cache_settings_statistics_album": "ライブラリのサムネイル",
|
||||||
"cache_settings_statistics_assets": "{} 枚 ({}枚中)",
|
"cache_settings_statistics_assets": "{} 枚 ({}枚中)",
|
||||||
@ -123,8 +123,8 @@
|
|||||||
"cache_settings_statistics_title": "キャッシュ",
|
"cache_settings_statistics_title": "キャッシュ",
|
||||||
"cache_settings_subtitle": "キャッシュの動作を変更する",
|
"cache_settings_subtitle": "キャッシュの動作を変更する",
|
||||||
"cache_settings_thumbnail_size": "サムネイルのキャッシュのサイズ ({}枚)",
|
"cache_settings_thumbnail_size": "サムネイルのキャッシュのサイズ ({}枚)",
|
||||||
"cache_settings_tile_subtitle": "Control the local storage behaviour",
|
"cache_settings_tile_subtitle": "ローカルストレージの挙動を確認する",
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "ローカルストレージ",
|
||||||
"cache_settings_title": "キャッシュの設定",
|
"cache_settings_title": "キャッシュの設定",
|
||||||
"change_password_form_confirm_password": "確定",
|
"change_password_form_confirm_password": "確定",
|
||||||
"change_password_form_description": "{name}さん こんにちは\n\nサーバーにアクセスするのが初めてか、パスワードリセットのリクエストがされました。新しいパスワードを入力してください",
|
"change_password_form_description": "{name}さん こんにちは\n\nサーバーにアクセスするのが初めてか、パスワードリセットのリクエストがされました。新しいパスワードを入力してください",
|
||||||
@ -142,18 +142,18 @@
|
|||||||
"control_bottom_app_bar_archive": "アーカイブ",
|
"control_bottom_app_bar_archive": "アーカイブ",
|
||||||
"control_bottom_app_bar_create_new_album": "アルバムを作成",
|
"control_bottom_app_bar_create_new_album": "アルバムを作成",
|
||||||
"control_bottom_app_bar_delete": "削除",
|
"control_bottom_app_bar_delete": "削除",
|
||||||
"control_bottom_app_bar_delete_from_immich": "Delete from Immich",
|
"control_bottom_app_bar_delete_from_immich": "Immichから削除",
|
||||||
"control_bottom_app_bar_delete_from_local": "Delete from device",
|
"control_bottom_app_bar_delete_from_local": "端末から削除",
|
||||||
"control_bottom_app_bar_edit_location": "Edit Location",
|
"control_bottom_app_bar_edit_location": "位置情報を編集",
|
||||||
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
"control_bottom_app_bar_edit_time": "日時を変更",
|
||||||
"control_bottom_app_bar_favorite": "お気に入り",
|
"control_bottom_app_bar_favorite": "お気に入り",
|
||||||
"control_bottom_app_bar_share": "共有",
|
"control_bottom_app_bar_share": "共有",
|
||||||
"control_bottom_app_bar_share_to": "Share To",
|
"control_bottom_app_bar_share_to": "次のユーザーに共有: ",
|
||||||
"control_bottom_app_bar_stack": "Stack",
|
"control_bottom_app_bar_stack": "スタック",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "ゴミ箱に捨てる",
|
||||||
"control_bottom_app_bar_unarchive": "アーカイブを解除",
|
"control_bottom_app_bar_unarchive": "アーカイブを解除",
|
||||||
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
"control_bottom_app_bar_unfavorite": "お気に入りから外す",
|
||||||
"control_bottom_app_bar_upload": "Upload",
|
"control_bottom_app_bar_upload": "アップロード",
|
||||||
"create_album_page_untitled": "タイトルなし",
|
"create_album_page_untitled": "タイトルなし",
|
||||||
"create_shared_album_page_create": "作成",
|
"create_shared_album_page_create": "作成",
|
||||||
"create_shared_album_page_share": "共有",
|
"create_shared_album_page_share": "共有",
|
||||||
@ -165,26 +165,27 @@
|
|||||||
"daily_title_text_date_year": "yyyy年 MM月 DD日, EE",
|
"daily_title_text_date_year": "yyyy年 MM月 DD日, EE",
|
||||||
"date_format": "MM月 DD日, EE • hh時mm分",
|
"date_format": "MM月 DD日, EE • hh時mm分",
|
||||||
"delete_dialog_alert": "サーバーとデバイスの両方から永久的に削除されます!",
|
"delete_dialog_alert": "サーバーとデバイスの両方から永久的に削除されます!",
|
||||||
"delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server",
|
"delete_dialog_alert_local": "選択された項目は端末から削除されますがImmichには残ります",
|
||||||
"delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device",
|
"delete_dialog_alert_local_non_backed_up": "Immichにバックアップされていない項目があります。それらの項目はデバイスからも永久に削除されます",
|
||||||
"delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server",
|
"delete_dialog_alert_remote": "選択された項目はImmichから永久に削除されます",
|
||||||
"delete_dialog_cancel": "キャンセル",
|
"delete_dialog_cancel": "キャンセル",
|
||||||
"delete_dialog_ok": "削除",
|
"delete_dialog_ok": "削除",
|
||||||
"delete_dialog_ok_force": "Delete Anyway",
|
"delete_dialog_ok_force": "削除します",
|
||||||
"delete_dialog_title": "永久的に削除",
|
"delete_dialog_title": "永久的に削除",
|
||||||
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
|
"delete_local_dialog_ok_backed_up_only": "バックアップ済みのみを削除",
|
||||||
"delete_local_dialog_ok_force": "Delete Anyway",
|
"delete_local_dialog_ok_force": "削除します",
|
||||||
"delete_shared_link_dialog_content": "本当にこの共有リンクを消しますか?",
|
"delete_shared_link_dialog_content": "本当にこの共有リンクを消しますか?",
|
||||||
"delete_shared_link_dialog_title": "共有リンクを消す",
|
"delete_shared_link_dialog_title": "共有リンクを消す",
|
||||||
"description_input_hint_text": "説明を追加",
|
"description_input_hint_text": "説明を追加",
|
||||||
"description_input_submit_error": "説明の編集に失敗、詳細の確認はログで行ってください",
|
"description_input_submit_error": "説明の編集に失敗、詳細の確認はログで行ってください",
|
||||||
"edit_date_time_dialog_date_time": "Date and Time",
|
"edit_date_time_dialog_date_time": "日付と時間",
|
||||||
"edit_date_time_dialog_timezone": "Timezone",
|
"edit_date_time_dialog_timezone": "タイムゾーン",
|
||||||
"edit_location_dialog_title": "Location",
|
"edit_location_dialog_title": "位置情報",
|
||||||
"exif_bottom_sheet_description": "説明を追加",
|
"exif_bottom_sheet_description": "説明を追加",
|
||||||
"exif_bottom_sheet_details": "詳細",
|
"exif_bottom_sheet_details": "詳細",
|
||||||
"exif_bottom_sheet_location": "撮影場所",
|
"exif_bottom_sheet_location": "撮影場所",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "位置情報を追加",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "製作途中(WIP)",
|
"experimental_settings_new_asset_list_subtitle": "製作途中(WIP)",
|
||||||
"experimental_settings_new_asset_list_title": "試験的なグリッドを有効化",
|
"experimental_settings_new_asset_list_title": "試験的なグリッドを有効化",
|
||||||
"experimental_settings_subtitle": "試験的機能につき自己責任で!",
|
"experimental_settings_subtitle": "試験的機能につき自己責任で!",
|
||||||
@ -194,42 +195,42 @@
|
|||||||
"home_page_add_to_album_conflicts": "{album}に{added}枚写真を追加しました。追加済みの{failed}枚はスキップしました。",
|
"home_page_add_to_album_conflicts": "{album}に{added}枚写真を追加しました。追加済みの{failed}枚はスキップしました。",
|
||||||
"home_page_add_to_album_err_local": "まだアップロードされてない項目はアルバムに登録できません",
|
"home_page_add_to_album_err_local": "まだアップロードされてない項目はアルバムに登録できません",
|
||||||
"home_page_add_to_album_success": "{album}に{added}枚写真を追加しました",
|
"home_page_add_to_album_success": "{album}に{added}枚写真を追加しました",
|
||||||
"home_page_album_err_partner": "Can not add partner assets to an album yet, skipping",
|
"home_page_album_err_partner": "まだパートナーの写真はアルバムに追加できません。スキップします(アップデート待ってね)",
|
||||||
"home_page_archive_err_local": "まだアップロードされてない項目はアーカイブできません",
|
"home_page_archive_err_local": "まだアップロードされてない項目はアーカイブできません",
|
||||||
"home_page_archive_err_partner": "Can not archive partner assets, skipping",
|
"home_page_archive_err_partner": "パートナーの写真はアーカイブできません。スキップします",
|
||||||
"home_page_building_timeline": "タイムライン構築中",
|
"home_page_building_timeline": "タイムライン構築中",
|
||||||
"home_page_delete_err_partner": "Can not delete partner assets, skipping",
|
"home_page_delete_err_partner": "パートナーの写真は削除できません。スキップします",
|
||||||
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
"home_page_delete_remote_err_local": "リモート削除の選択にローカルなアイテムが含まれています。スキップします",
|
||||||
"home_page_favorite_err_local": "まだアップロードされてない項目はお気に入り登録できません",
|
"home_page_favorite_err_local": "まだアップロードされてない項目はお気に入り登録できません",
|
||||||
"home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping",
|
"home_page_favorite_err_partner": "まだパートナーの写真をお気に入り登録できません。スキップします(アップデート待ってね)",
|
||||||
"home_page_first_time_notice": "はじめてアプリを使う場合、タイムラインに写真を表示するためにアルバムを選択してください",
|
"home_page_first_time_notice": "はじめてアプリを使う場合、タイムラインに写真を表示するためにアルバムを選択してください",
|
||||||
"home_page_share_err_local": "Can not share local assets via link, skipping",
|
"home_page_share_err_local": "ローカルのみの項目をリンクで共有はできません。スキップします",
|
||||||
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
|
"home_page_upload_err_limit": "一回でアップロードできる写真の数は30枚です。スキップします",
|
||||||
"image_viewer_page_state_provider_download_error": "ダウンロード失敗",
|
"image_viewer_page_state_provider_download_error": "ダウンロード失敗",
|
||||||
"image_viewer_page_state_provider_download_success": "ダウンロード成功",
|
"image_viewer_page_state_provider_download_success": "ダウンロード成功",
|
||||||
"image_viewer_page_state_provider_share_error": "Share Error",
|
"image_viewer_page_state_provider_share_error": "共有エラー",
|
||||||
"library_page_albums": "アルバム",
|
"library_page_albums": "アルバム",
|
||||||
"library_page_archive": "アーカイブ",
|
"library_page_archive": "アーカイブ",
|
||||||
"library_page_device_albums": "デバイス上のアルバム",
|
"library_page_device_albums": "デバイス上のアルバム",
|
||||||
"library_page_favorites": "お気に入り",
|
"library_page_favorites": "お気に入り",
|
||||||
"library_page_new_album": "新しいアルバム",
|
"library_page_new_album": "新しいアルバム",
|
||||||
"library_page_sharing": "共有中",
|
"library_page_sharing": "共有中",
|
||||||
"library_page_sort_asset_count": "Number of assets",
|
"library_page_sort_asset_count": "項目の数",
|
||||||
"library_page_sort_created": "作成日時",
|
"library_page_sort_created": "作成日時",
|
||||||
"library_page_sort_last_modified": "Last modified",
|
"library_page_sort_last_modified": "最終変更",
|
||||||
"library_page_sort_most_oldest_photo": "Oldest photo",
|
"library_page_sort_most_oldest_photo": "一番古い項目",
|
||||||
"library_page_sort_most_recent_photo": "Most recent photo",
|
"library_page_sort_most_recent_photo": "最近の項目",
|
||||||
"library_page_sort_title": "アルバム名",
|
"library_page_sort_title": "アルバム名",
|
||||||
"location_picker_choose_on_map": "Choose on map",
|
"location_picker_choose_on_map": "マップを選択",
|
||||||
"location_picker_latitude": "Latitude",
|
"location_picker_latitude": "緯度",
|
||||||
"location_picker_latitude_error": "Enter a valid latitude",
|
"location_picker_latitude_error": "有効な緯度を入力してください",
|
||||||
"location_picker_latitude_hint": "Enter your latitude here",
|
"location_picker_latitude_hint": "緯度をここに入力",
|
||||||
"location_picker_longitude": "Longitude",
|
"location_picker_longitude": "経度",
|
||||||
"location_picker_longitude_error": "Enter a valid longitude",
|
"location_picker_longitude_error": "有効な経度を入力してください",
|
||||||
"location_picker_longitude_hint": "Enter your longitude here",
|
"location_picker_longitude_hint": "経度をここに入力",
|
||||||
"login_disabled": "Login has been disabled",
|
"login_disabled": "ログインは無効化されました",
|
||||||
"login_form_api_exception": "APIエラー。URLをチェックしてもう一度試してください",
|
"login_form_api_exception": "APIエラー。URLをチェックしてもう一度試してください",
|
||||||
"login_form_back_button_text": "Back",
|
"login_form_back_button_text": "戻る",
|
||||||
"login_form_button_text": "ログイン",
|
"login_form_button_text": "ログイン",
|
||||||
"login_form_email_hint": "hoge@email.com",
|
"login_form_email_hint": "hoge@email.com",
|
||||||
"login_form_endpoint_hint": "https://example.com:port/api",
|
"login_form_endpoint_hint": "https://example.com:port/api",
|
||||||
@ -242,7 +243,7 @@
|
|||||||
"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": "There was an Handshake Exception with the server. Enable self-signed certificate support in the settings if you are using a self-signed certificate.",
|
"login_form_handshake_exception": "Handshake Exceptionエラー。self-signed署名を設定で有効にしてください",
|
||||||
"login_form_label_email": "メールアドレス",
|
"login_form_label_email": "メールアドレス",
|
||||||
"login_form_label_password": "パスワード",
|
"login_form_label_password": "パスワード",
|
||||||
"login_form_next_button": "次",
|
"login_form_next_button": "次",
|
||||||
@ -250,53 +251,53 @@
|
|||||||
"login_form_save_login": "ログインを保持",
|
"login_form_save_login": "ログインを保持",
|
||||||
"login_form_server_empty": "URLを入力",
|
"login_form_server_empty": "URLを入力",
|
||||||
"login_form_server_error": "サーバーに接続できません",
|
"login_form_server_error": "サーバーに接続できません",
|
||||||
"login_password_changed_error": "There was an error updating your password",
|
"login_password_changed_error": "パスワードの変更でエラーが発生しました",
|
||||||
"login_password_changed_success": "Password updated successfully",
|
"login_password_changed_success": "パスワードの変更に成功",
|
||||||
"map_assets_in_bound": "{} photo",
|
"map_assets_in_bound": "{}項目",
|
||||||
"map_assets_in_bounds": "{} photos",
|
"map_assets_in_bounds": "{}項目",
|
||||||
"map_cannot_get_user_location": "Cannot get user's location",
|
"map_cannot_get_user_location": "位置情報がゲットできません",
|
||||||
"map_location_dialog_cancel": "Cancel",
|
"map_location_dialog_cancel": "キャンセル",
|
||||||
"map_location_dialog_yes": "Yes",
|
"map_location_dialog_yes": "はい",
|
||||||
"map_location_picker_page_use_location": "Use this location",
|
"map_location_picker_page_use_location": "この位置情報を使う",
|
||||||
"map_location_service_disabled_content": "Location service needs to be enabled to display assets from your current location. Do you want to enable it now?",
|
"map_location_service_disabled_content": "現在地の項目を表示するには位置情報がオンである必要があります。有効化しますか?",
|
||||||
"map_location_service_disabled_title": "Location Service disabled",
|
"map_location_service_disabled_title": "位置情報がオフです",
|
||||||
"map_no_assets_in_bounds": "No photos in this area",
|
"map_no_assets_in_bounds": "このエリアに写真はありません",
|
||||||
"map_no_location_permission_content": "Location permission is needed to display assets from your current location. Do you want to allow it now?",
|
"map_no_location_permission_content": "現在地の項目を表示するには位置情報へのアクセスが必要です。許可しますか?",
|
||||||
"map_no_location_permission_title": "Location Permission denied",
|
"map_no_location_permission_title": "位置情報へのアクセスが拒否されました",
|
||||||
"map_settings_dark_mode": "Dark mode",
|
"map_settings_dark_mode": "ダークモード",
|
||||||
"map_settings_date_range_option_all": "All",
|
"map_settings_date_range_option_all": "全て",
|
||||||
"map_settings_date_range_option_day": "Past 24 hours",
|
"map_settings_date_range_option_day": "過去24時間",
|
||||||
"map_settings_date_range_option_days": "Past {} days",
|
"map_settings_date_range_option_days": "過去{}日間",
|
||||||
"map_settings_date_range_option_year": "Past year",
|
"map_settings_date_range_option_year": "過去1年",
|
||||||
"map_settings_date_range_option_years": "Past {} years",
|
"map_settings_date_range_option_years": "過去{}年間",
|
||||||
"map_settings_dialog_cancel": "Cancel",
|
"map_settings_dialog_cancel": "キャンセル",
|
||||||
"map_settings_dialog_save": "Save",
|
"map_settings_dialog_save": "セーブ",
|
||||||
"map_settings_dialog_title": "Map Settings",
|
"map_settings_dialog_title": "マップの設定",
|
||||||
"map_settings_include_show_archived": "Include Archived",
|
"map_settings_include_show_archived": "アーカイブ済みを含める",
|
||||||
"map_settings_only_relative_range": "Date range",
|
"map_settings_only_relative_range": "Date range",
|
||||||
"map_settings_only_show_favorites": "Show Favorite Only",
|
"map_settings_only_show_favorites": "お気に入りのみを表示",
|
||||||
"map_settings_theme_settings": "Map Theme",
|
"map_settings_theme_settings": "マップの見た目",
|
||||||
"map_zoom_to_see_photos": "Zoom out to see photos",
|
"map_zoom_to_see_photos": "写真を見るにはズームアウト",
|
||||||
"monthly_title_text_date_format": "yyyy年 MM月",
|
"monthly_title_text_date_format": "yyyy年 MM月",
|
||||||
"motion_photos_page_title": "モーションフォト",
|
"motion_photos_page_title": "モーションフォト",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "読み取り専用の項目の日付を変更できません",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
"multiselect_grid_edit_gps_err_read_only": "読み取り専用の項目の位置情報を変更できません",
|
||||||
"notification_permission_dialog_cancel": "キャンセル",
|
"notification_permission_dialog_cancel": "キャンセル",
|
||||||
"notification_permission_dialog_content": "通知を許可するには設定を開いてオンにしてください",
|
"notification_permission_dialog_content": "通知を許可するには設定を開いてオンにしてください",
|
||||||
"notification_permission_dialog_settings": "設定",
|
"notification_permission_dialog_settings": "設定",
|
||||||
"notification_permission_list_tile_content": "通知の許可 をオンにしてください",
|
"notification_permission_list_tile_content": "通知の許可 をオンにしてください",
|
||||||
"notification_permission_list_tile_enable_button": "通知をオンにする",
|
"notification_permission_list_tile_enable_button": "通知をオンにする",
|
||||||
"notification_permission_list_tile_title": "通知の許可",
|
"notification_permission_list_tile_title": "通知の許可",
|
||||||
"partner_page_add_partner": "Add partner",
|
"partner_page_add_partner": "パートナーを追加",
|
||||||
"partner_page_empty_message": "Your photos are not yet shared with any partner.",
|
"partner_page_empty_message": "まだどのパートナーとも写真を共有してません",
|
||||||
"partner_page_no_more_users": "No more users to add",
|
"partner_page_no_more_users": "追加できるユーザーがもういません",
|
||||||
"partner_page_partner_add_failed": "Failed to add partner",
|
"partner_page_partner_add_failed": "パートナーの追加に失敗",
|
||||||
"partner_page_select_partner": "Select partner",
|
"partner_page_select_partner": "パートナーを選択",
|
||||||
"partner_page_shared_to_title": "Shared to",
|
"partner_page_shared_to_title": "次のユーザーと共有しす: ",
|
||||||
"partner_page_stop_sharing_content": "{} will no longer be able to access your photos.",
|
"partner_page_stop_sharing_content": "{}は写真へのアクセスができなくなります",
|
||||||
"partner_page_stop_sharing_title": "Stop sharing your photos?",
|
"partner_page_stop_sharing_title": "写真の共有を無効化しますか?",
|
||||||
"partner_page_title": "Partner",
|
"partner_page_title": "パートナー",
|
||||||
"permission_onboarding_back": "Back",
|
"permission_onboarding_back": "戻る",
|
||||||
"permission_onboarding_continue_anyway": "無視して続行",
|
"permission_onboarding_continue_anyway": "無視して続行",
|
||||||
"permission_onboarding_get_started": "はじめる",
|
"permission_onboarding_get_started": "はじめる",
|
||||||
"permission_onboarding_go_to_settings": "システム設定",
|
"permission_onboarding_go_to_settings": "システム設定",
|
||||||
@ -307,32 +308,32 @@
|
|||||||
"permission_onboarding_permission_limited": "写真へのアクセスが制限されています。Immichに写真のバックアップと管理を行わせるにはシステム設定から写真と動画のアクセス権限を変更してください。",
|
"permission_onboarding_permission_limited": "写真へのアクセスが制限されています。Immichに写真のバックアップと管理を行わせるにはシステム設定から写真と動画のアクセス権限を変更してください。",
|
||||||
"permission_onboarding_request": "Immichは写真へのアクセス許可が必要です",
|
"permission_onboarding_request": "Immichは写真へのアクセス許可が必要です",
|
||||||
"profile_drawer_app_logs": "ログ",
|
"profile_drawer_app_logs": "ログ",
|
||||||
"profile_drawer_client_out_of_date_major": "Mobile App is out of date. Please update to the latest major version.",
|
"profile_drawer_client_out_of_date_major": "アプリが更新されてません。最新のバージョンに更新してください",
|
||||||
"profile_drawer_client_out_of_date_minor": "Mobile App is out of date. Please update to the latest minor version.",
|
"profile_drawer_client_out_of_date_minor": "アプリが更新されてません。最新のマイナーバージョンに更新してください",
|
||||||
"profile_drawer_client_server_up_to_date": "すべて最新です",
|
"profile_drawer_client_server_up_to_date": "すべて最新です",
|
||||||
"profile_drawer_documentation": "Documentation",
|
"profile_drawer_documentation": "Immcihの説明書",
|
||||||
"profile_drawer_github": "GitHub",
|
"profile_drawer_github": "GitHub",
|
||||||
"profile_drawer_server_out_of_date_major": "Server is out of date. Please update to the latest major version.",
|
"profile_drawer_server_out_of_date_major": "サーバーが更新されてません。最新のバージョンに更新してください",
|
||||||
"profile_drawer_server_out_of_date_minor": "Server is out of date. Please update to the latest minor version.",
|
"profile_drawer_server_out_of_date_minor": "サーバーが更新されてません。最新のマイナーバージョンに更新してください",
|
||||||
"profile_drawer_settings": "設定",
|
"profile_drawer_settings": "設定",
|
||||||
"profile_drawer_sign_out": "サインアウト",
|
"profile_drawer_sign_out": "サインアウト",
|
||||||
"profile_drawer_trash": "Trash",
|
"profile_drawer_trash": "ゴミ箱",
|
||||||
"recently_added_page_title": "最近",
|
"recently_added_page_title": "最近",
|
||||||
"scaffold_body_error_occurred": "Error occurred",
|
"scaffold_body_error_occurred": "エラーが発生しました",
|
||||||
"search_bar_hint": "写真を検索",
|
"search_bar_hint": "写真を検索",
|
||||||
"search_page_categories": "カテゴリ",
|
"search_page_categories": "カテゴリ",
|
||||||
"search_page_favorites": "お気に入り",
|
"search_page_favorites": "お気に入り",
|
||||||
"search_page_motion_photos": "モーションフォト",
|
"search_page_motion_photos": "モーションフォト",
|
||||||
"search_page_no_objects": "被写体に関するデータがなし",
|
"search_page_no_objects": "被写体に関するデータがなし",
|
||||||
"search_page_no_places": "場所に関するデータなし",
|
"search_page_no_places": "場所に関するデータなし",
|
||||||
"search_page_people": "People",
|
"search_page_people": "ピープル",
|
||||||
"search_page_person_add_name_dialog_cancel": "Cancel",
|
"search_page_person_add_name_dialog_cancel": "キャンセル",
|
||||||
"search_page_person_add_name_dialog_hint": "Name",
|
"search_page_person_add_name_dialog_hint": "名前",
|
||||||
"search_page_person_add_name_dialog_save": "Save",
|
"search_page_person_add_name_dialog_save": "セーブ",
|
||||||
"search_page_person_add_name_dialog_title": "Add a name",
|
"search_page_person_add_name_dialog_title": "名前を追加",
|
||||||
"search_page_person_add_name_subtitle": "Find them fast by name with search",
|
"search_page_person_add_name_subtitle": "名前で検索して高速に探す",
|
||||||
"search_page_person_add_name_title": "Add a name",
|
"search_page_person_add_name_title": "名前を追加",
|
||||||
"search_page_person_edit_name": "Edit name",
|
"search_page_person_edit_name": "名前を変更",
|
||||||
"search_page_places": "撮影地",
|
"search_page_places": "撮影地",
|
||||||
"search_page_recently_added": "最近追加",
|
"search_page_recently_added": "最近追加",
|
||||||
"search_page_screenshots": "スクリーンショット",
|
"search_page_screenshots": "スクリーンショット",
|
||||||
@ -341,7 +342,7 @@
|
|||||||
"search_page_videos": "ビデオ",
|
"search_page_videos": "ビデオ",
|
||||||
"search_page_view_all_button": "すべて表示",
|
"search_page_view_all_button": "すべて表示",
|
||||||
"search_page_your_activity": "アクティビティ",
|
"search_page_your_activity": "アクティビティ",
|
||||||
"search_page_your_map": "Your Map",
|
"search_page_your_map": "あなたのマップ",
|
||||||
"search_result_page_new_search_hint": "検索",
|
"search_result_page_new_search_hint": "検索",
|
||||||
"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:単語",
|
||||||
@ -349,7 +350,7 @@
|
|||||||
"select_user_for_sharing_page_err_album": "アルバム作成に失敗",
|
"select_user_for_sharing_page_err_album": "アルバム作成に失敗",
|
||||||
"select_user_for_sharing_page_share_suggestions": "ユーザ一覧",
|
"select_user_for_sharing_page_share_suggestions": "ユーザ一覧",
|
||||||
"server_info_box_app_version": "アプリVer.",
|
"server_info_box_app_version": "アプリVer.",
|
||||||
"server_info_box_latest_release": "Latest Version",
|
"server_info_box_latest_release": "最新バージョン",
|
||||||
"server_info_box_server_url": " サーバのURL",
|
"server_info_box_server_url": " サーバのURL",
|
||||||
"server_info_box_server_version": "サーバーVer.",
|
"server_info_box_server_version": "サーバーVer.",
|
||||||
"setting_image_viewer_help": "写真をタップするとサムネイル・中画質(要設定)・オリジナル(要設定)の順に読み込みます",
|
"setting_image_viewer_help": "写真をタップするとサムネイル・中画質(要設定)・オリジナル(要設定)の順に読み込みます",
|
||||||
@ -375,66 +376,66 @@
|
|||||||
"share_add_photos": "写真を追加",
|
"share_add_photos": "写真を追加",
|
||||||
"share_add_title": "タイトルを追加",
|
"share_add_title": "タイトルを追加",
|
||||||
"share_create_album": "アルバムを作成",
|
"share_create_album": "アルバムを作成",
|
||||||
"shared_album_activities_input_disable": "Comment is disabled",
|
"shared_album_activities_input_disable": "コメントはオフになってます",
|
||||||
"shared_album_activities_input_hint": "Say something",
|
"shared_album_activities_input_hint": "何か書き込みましょう",
|
||||||
"shared_album_activity_remove_content": "Do you want to delete this activity?",
|
"shared_album_activity_remove_content": "このアクティビティを削除しますか",
|
||||||
"shared_album_activity_remove_title": "Delete Activity",
|
"shared_album_activity_remove_title": "アクティビティを削除します",
|
||||||
"shared_album_activity_setting_subtitle": "Let others respond",
|
"shared_album_activity_setting_subtitle": "他のユーザーの返信を許可する",
|
||||||
"shared_album_activity_setting_title": "Comments & likes",
|
"shared_album_activity_setting_title": "お気に入りとコメント",
|
||||||
"shared_album_section_people_action_error": "Error leaving/removing from album",
|
"shared_album_section_people_action_error": "アルバムからの退出に失敗",
|
||||||
"shared_album_section_people_action_leave": "Remove user from album",
|
"shared_album_section_people_action_leave": "ユーザーをアルバムから退出",
|
||||||
"shared_album_section_people_action_remove_user": "Remove user from album",
|
"shared_album_section_people_action_remove_user": "ユーザーをアルバムから退出",
|
||||||
"shared_album_section_people_owner_label": "Owner",
|
"shared_album_section_people_owner_label": "オーナー",
|
||||||
"shared_album_section_people_title": "PEOPLE",
|
"shared_album_section_people_title": "ピープル",
|
||||||
"share_dialog_preparing": "準備中",
|
"share_dialog_preparing": "準備中",
|
||||||
"shared_link_app_bar_title": "共有リンク",
|
"shared_link_app_bar_title": "共有リンク",
|
||||||
"shared_link_clipboard_copied_massage": "Copied to clipboard",
|
"shared_link_clipboard_copied_massage": "クリップボードにコピーしました",
|
||||||
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
"shared_link_clipboard_text": "リンク: {}\nパスワード: {}",
|
||||||
"shared_link_create_app_bar_title": "共有リンクを作る",
|
"shared_link_create_app_bar_title": "共有リンクを作る",
|
||||||
"shared_link_create_error": "Error while creating shared link",
|
"shared_link_create_error": "共有用のリンク作成時にエラーが発生しました",
|
||||||
"shared_link_create_info": "Let anyone with the link see the selected photo(s)",
|
"shared_link_create_info": "誰でも写真を見れるようにする",
|
||||||
"shared_link_create_submit_button": "リンクを作る",
|
"shared_link_create_submit_button": "リンクを作る",
|
||||||
"shared_link_edit_allow_download": "Allow public user to download",
|
"shared_link_edit_allow_download": "写真のダウンロードの許可",
|
||||||
"shared_link_edit_allow_upload": "Allow public user to upload",
|
"shared_link_edit_allow_upload": "写真のアップロードを許可",
|
||||||
"shared_link_edit_app_bar_title": " リンクを編集する",
|
"shared_link_edit_app_bar_title": " リンクを編集する",
|
||||||
"shared_link_edit_change_expiry": "Change expiration time",
|
"shared_link_edit_change_expiry": "有効期限を変更",
|
||||||
"shared_link_edit_description": " デスクリプション ",
|
"shared_link_edit_description": "概要欄",
|
||||||
"shared_link_edit_description_hint": "Enter the share description",
|
"shared_link_edit_description_hint": "概要を追加",
|
||||||
"shared_link_edit_expire_after": "Expire after",
|
"shared_link_edit_expire_after": "有効期限は",
|
||||||
"shared_link_edit_expire_after_option_day": "1 day",
|
"shared_link_edit_expire_after_option_day": "1日",
|
||||||
"shared_link_edit_expire_after_option_days": "{} days",
|
"shared_link_edit_expire_after_option_days": "{}日",
|
||||||
"shared_link_edit_expire_after_option_hour": "1 hour",
|
"shared_link_edit_expire_after_option_hour": "1時間",
|
||||||
"shared_link_edit_expire_after_option_hours": "{} hours",
|
"shared_link_edit_expire_after_option_hours": "{}時間",
|
||||||
"shared_link_edit_expire_after_option_minute": "1 minute",
|
"shared_link_edit_expire_after_option_minute": "1分",
|
||||||
"shared_link_edit_expire_after_option_minutes": "{} minutes",
|
"shared_link_edit_expire_after_option_minutes": "{}分",
|
||||||
"shared_link_edit_expire_after_option_never": "Never",
|
"shared_link_edit_expire_after_option_never": "有効期限なし",
|
||||||
"shared_link_edit_password": " パスワード",
|
"shared_link_edit_password": " パスワード",
|
||||||
"shared_link_edit_password_hint": "共有パスワードを入力する",
|
"shared_link_edit_password_hint": "共有パスワードを入力する",
|
||||||
"shared_link_edit_show_meta": " メタデータを見る",
|
"shared_link_edit_show_meta": " メタデータを見る",
|
||||||
"shared_link_edit_submit_button": "リンクをアップデートする",
|
"shared_link_edit_submit_button": "リンクをアップデートする",
|
||||||
"shared_link_empty": "共有リンクはありません ",
|
"shared_link_empty": "共有リンクはありません ",
|
||||||
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
"shared_link_error_server_url_fetch": "サーバーのURLがゲットできません",
|
||||||
"shared_link_expired": "Expired",
|
"shared_link_expired": "有効期限が切れました",
|
||||||
"shared_link_expires_day": "Expires in {} day",
|
"shared_link_expires_day": "{}日間で切れます",
|
||||||
"shared_link_expires_days": "Expires in {} days",
|
"shared_link_expires_days": "{}日間で有効期限が切れます",
|
||||||
"shared_link_expires_hour": "Expires in {} hour",
|
"shared_link_expires_hour": "{}時間で切れます",
|
||||||
"shared_link_expires_hours": "Expires in {} hours",
|
"shared_link_expires_hours": "{}時間で有効期限が切れます",
|
||||||
"shared_link_expires_minute": "Expires in {} minute",
|
"shared_link_expires_minute": "{}分で切れます",
|
||||||
"shared_link_expires_minutes": "Expires in {} minutes",
|
"shared_link_expires_minutes": "{}分で切れます",
|
||||||
"shared_link_expires_never": "Expires ∞",
|
"shared_link_expires_never": "有効期限はありません",
|
||||||
"shared_link_expires_second": "Expires in {} second",
|
"shared_link_expires_second": "{}秒で切れます",
|
||||||
"shared_link_expires_seconds": "Expires in {} seconds",
|
"shared_link_expires_seconds": "{}秒で切れます",
|
||||||
"shared_link_info_chip_download": "Download",
|
"shared_link_info_chip_download": "ダウンロード",
|
||||||
"shared_link_info_chip_metadata": "EXIF",
|
"shared_link_info_chip_metadata": "EXIF",
|
||||||
"shared_link_info_chip_upload": "Upload",
|
"shared_link_info_chip_upload": "アップロード",
|
||||||
"shared_link_manage_links": "Manage Shared links",
|
"shared_link_manage_links": "共有済みのリンクを管理",
|
||||||
"share_done": "Done",
|
"share_done": "完了",
|
||||||
"share_invite": "アルバムに招待",
|
"share_invite": "アルバムに招待",
|
||||||
"sharing_page_album": "共有アルバム",
|
"sharing_page_album": "共有アルバム",
|
||||||
"sharing_page_description": "共有アルバムを作成して同じネットワークにいる人たちに写真を共有",
|
"sharing_page_description": "共有アルバムを作成して同じネットワークにいる人たちに写真を共有",
|
||||||
"sharing_page_empty_list": "共有アルバムなし",
|
"sharing_page_empty_list": "共有アルバムなし",
|
||||||
"sharing_silver_appbar_create_shared_album": "共有アルバムを作成",
|
"sharing_silver_appbar_create_shared_album": "共有アルバムを作成",
|
||||||
"sharing_silver_appbar_shared_links": "Shared links",
|
"sharing_silver_appbar_shared_links": "共有リンク",
|
||||||
"sharing_silver_appbar_share_partner": "パートナーと共有",
|
"sharing_silver_appbar_share_partner": "パートナーと共有",
|
||||||
"tab_controller_nav_library": "ライブラリ",
|
"tab_controller_nav_library": "ライブラリ",
|
||||||
"tab_controller_nav_photos": "写真",
|
"tab_controller_nav_photos": "写真",
|
||||||
@ -450,30 +451,30 @@
|
|||||||
"theme_setting_theme_title": "テーマ",
|
"theme_setting_theme_title": "テーマ",
|
||||||
"theme_setting_three_stage_loading_subtitle": "三段階読み込みを有効にするとパフォーマンスが改善する可能性がありますが、ネットワーク負荷が著しく増加します",
|
"theme_setting_three_stage_loading_subtitle": "三段階読み込みを有効にするとパフォーマンスが改善する可能性がありますが、ネットワーク負荷が著しく増加します",
|
||||||
"theme_setting_three_stage_loading_title": "三段階読み込みをオンにする",
|
"theme_setting_three_stage_loading_title": "三段階読み込みをオンにする",
|
||||||
"translated_text_options": "Options",
|
"translated_text_options": "オプション",
|
||||||
"trash_page_delete": "Delete",
|
"trash_page_delete": "削除",
|
||||||
"trash_page_delete_all": "Delete All",
|
"trash_page_delete_all": "全て削除",
|
||||||
"trash_page_empty_trash_btn": "Empty trash",
|
"trash_page_empty_trash_btn": "コミ箱を空にする",
|
||||||
"trash_page_empty_trash_dialog_content": "Do you want to empty your trashed assets? These items will be permanently removed from Immich",
|
"trash_page_empty_trash_dialog_content": "ゴミ箱を空にしますか?選択された項目は完全に削除されます。この操作は取り消せません",
|
||||||
"trash_page_empty_trash_dialog_ok": "Ok",
|
"trash_page_empty_trash_dialog_ok": "了解",
|
||||||
"trash_page_info": "Trashed items will be permanently deleted after {} days",
|
"trash_page_info": "ゴミ箱に移動したアイテムは{}日後に削除されます",
|
||||||
"trash_page_no_assets": "No trashed assets",
|
"trash_page_no_assets": "ゴミ箱は空です",
|
||||||
"trash_page_restore": "Restore",
|
"trash_page_restore": "復元",
|
||||||
"trash_page_restore_all": "Restore All",
|
"trash_page_restore_all": "全て復元",
|
||||||
"trash_page_select_assets_btn": "Select assets",
|
"trash_page_select_assets_btn": "項目を選択",
|
||||||
"trash_page_select_btn": "Select",
|
"trash_page_select_btn": "選択",
|
||||||
"trash_page_title": "Trash ({})",
|
"trash_page_title": "削除({})",
|
||||||
"upload_dialog_cancel": "Cancel",
|
"upload_dialog_cancel": "キャンセル",
|
||||||
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
|
"upload_dialog_info": "選択した項目のバックアップをしますか?",
|
||||||
"upload_dialog_ok": "Upload",
|
"upload_dialog_ok": "アップロード",
|
||||||
"upload_dialog_title": "Upload Asset",
|
"upload_dialog_title": "アップロード",
|
||||||
"version_announcement_overlay_ack": "了解",
|
"version_announcement_overlay_ack": "了解",
|
||||||
"version_announcement_overlay_release_notes": "更新情報",
|
"version_announcement_overlay_release_notes": "更新情報",
|
||||||
"version_announcement_overlay_text_1": "こんにちは、またはこんばんは!新しい",
|
"version_announcement_overlay_text_1": "こんにちは、またはこんばんは!新しい",
|
||||||
"version_announcement_overlay_text_2": "のバージョンが公開中です。",
|
"version_announcement_overlay_text_2": "のバージョンが公開中です。",
|
||||||
"version_announcement_overlay_text_3": "を確認してみてください。docker-composeや.envファイルが最新の状態に更新されているか、特にWatchTowerなどのツールを使ってDockerイメージを自動アップデートしてる人は確認してください。",
|
"version_announcement_overlay_text_3": "を確認してみてください。docker-composeや.envファイルが最新の状態に更新されているか、特にWatchTowerなどのツールを使ってDockerイメージを自動アップデートしてる人は確認してください。",
|
||||||
"version_announcement_overlay_title": "サーバーの新バージョンリリース\uD83C\uDF89",
|
"version_announcement_overlay_title": "サーバーの新バージョンリリース\uD83C\uDF89",
|
||||||
"viewer_remove_from_stack": "Remove from Stack",
|
"viewer_remove_from_stack": "スタックから外す",
|
||||||
"viewer_stack_use_as_main_asset": "Use as Main Asset",
|
"viewer_stack_use_as_main_asset": "メインの画像として使用する",
|
||||||
"viewer_unstack": "Un-Stack"
|
"viewer_unstack": "スタックを解除"
|
||||||
}
|
}
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "상세정보",
|
"exif_bottom_sheet_details": "상세정보",
|
||||||
"exif_bottom_sheet_location": "위치",
|
"exif_bottom_sheet_location": "위치",
|
||||||
"exif_bottom_sheet_location_add": "위치 지정",
|
"exif_bottom_sheet_location_add": "위치 지정",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "진행중",
|
"experimental_settings_new_asset_list_subtitle": "진행중",
|
||||||
"experimental_settings_new_asset_list_title": "실험적 사진 그리드 적용",
|
"experimental_settings_new_asset_list_title": "실험적 사진 그리드 적용",
|
||||||
"experimental_settings_subtitle": "문제시 책임지지 않습니다!",
|
"experimental_settings_subtitle": "문제시 책임지지 않습니다!",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "INFORMĀCIJA",
|
"exif_bottom_sheet_details": "INFORMĀCIJA",
|
||||||
"exif_bottom_sheet_location": "ATRAŠANĀS VIETA",
|
"exif_bottom_sheet_location": "ATRAŠANĀS VIETA",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Izstrādes posmā",
|
"experimental_settings_new_asset_list_subtitle": "Izstrādes posmā",
|
||||||
"experimental_settings_new_asset_list_title": "Iespējot eksperimentālo fotorežģi",
|
"experimental_settings_new_asset_list_title": "Iespējot eksperimentālo fotorežģi",
|
||||||
"experimental_settings_subtitle": "Izmanto uzņemoties risku!",
|
"experimental_settings_subtitle": "Izmanto uzņemoties risku!",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETAILS",
|
"exif_bottom_sheet_details": "DETAILS",
|
||||||
"exif_bottom_sheet_location": "LOCATION",
|
"exif_bottom_sheet_location": "LOCATION",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
||||||
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||||
"experimental_settings_subtitle": "Use at your own risk!",
|
"experimental_settings_subtitle": "Use at your own risk!",
|
||||||
|
@ -35,8 +35,8 @@
|
|||||||
"app_bar_signout_dialog_title": "Logg ut",
|
"app_bar_signout_dialog_title": "Logg ut",
|
||||||
"archive_page_no_archived_assets": "Ingen arkiverte objekter funnet",
|
"archive_page_no_archived_assets": "Ingen arkiverte objekter funnet",
|
||||||
"archive_page_title": "Arkiv ({})",
|
"archive_page_title": "Arkiv ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "Kan ikke slette objekt(er) med kun lese-rettighet, hopper over",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "Kan ikke hente offline objekt(er), hopper over",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Dynamisk bildeorganisering",
|
"asset_list_layout_settings_dynamic_layout_title": "Dynamisk bildeorganisering",
|
||||||
"asset_list_layout_settings_group_automatically": "Automatisk",
|
"asset_list_layout_settings_group_automatically": "Automatisk",
|
||||||
"asset_list_layout_settings_group_by": "Grupper bilder etter",
|
"asset_list_layout_settings_group_by": "Grupper bilder etter",
|
||||||
@ -142,15 +142,15 @@
|
|||||||
"control_bottom_app_bar_archive": "Arkiver",
|
"control_bottom_app_bar_archive": "Arkiver",
|
||||||
"control_bottom_app_bar_create_new_album": "Lag nytt album",
|
"control_bottom_app_bar_create_new_album": "Lag nytt album",
|
||||||
"control_bottom_app_bar_delete": "Slett",
|
"control_bottom_app_bar_delete": "Slett",
|
||||||
"control_bottom_app_bar_delete_from_immich": "Delete from Immich",
|
"control_bottom_app_bar_delete_from_immich": "Slett fra Immich",
|
||||||
"control_bottom_app_bar_delete_from_local": "Delete from device",
|
"control_bottom_app_bar_delete_from_local": "Slett fra enhet",
|
||||||
"control_bottom_app_bar_edit_location": "Endre lokasjon",
|
"control_bottom_app_bar_edit_location": "Endre lokasjon",
|
||||||
"control_bottom_app_bar_edit_time": "Endre Dato og tid",
|
"control_bottom_app_bar_edit_time": "Endre Dato og tid",
|
||||||
"control_bottom_app_bar_favorite": "Favoritt",
|
"control_bottom_app_bar_favorite": "Favoritt",
|
||||||
"control_bottom_app_bar_share": "Del",
|
"control_bottom_app_bar_share": "Del",
|
||||||
"control_bottom_app_bar_share_to": "Del til",
|
"control_bottom_app_bar_share_to": "Del til",
|
||||||
"control_bottom_app_bar_stack": "Stable",
|
"control_bottom_app_bar_stack": "Stable",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Flytt til søppelkasse",
|
||||||
"control_bottom_app_bar_unarchive": "Fjern fra arkiv",
|
"control_bottom_app_bar_unarchive": "Fjern fra arkiv",
|
||||||
"control_bottom_app_bar_unfavorite": "Fjern favoritt",
|
"control_bottom_app_bar_unfavorite": "Fjern favoritt",
|
||||||
"control_bottom_app_bar_upload": "Last opp",
|
"control_bottom_app_bar_upload": "Last opp",
|
||||||
@ -165,15 +165,15 @@
|
|||||||
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
||||||
"date_format": "E, LLL d, y • h:mm a",
|
"date_format": "E, LLL d, y • h:mm a",
|
||||||
"delete_dialog_alert": "Disse objektene vil bli slettet permanent fra Immich og fra enheten din",
|
"delete_dialog_alert": "Disse objektene vil bli slettet permanent fra Immich og fra enheten din",
|
||||||
"delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server",
|
"delete_dialog_alert_local": "Disse objektene vil bli permanent slettet fra enheten din, men vil fortsatt være tilgjengelige fra Immich serveren",
|
||||||
"delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device",
|
"delete_dialog_alert_local_non_backed_up": "Noen av objektene er ikke sikkerhetskopiert til Immich og vil bli permanent fjernet fra enheten din",
|
||||||
"delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server",
|
"delete_dialog_alert_remote": "Disse objektene vil bli permanent slettet fra Immich serveren",
|
||||||
"delete_dialog_cancel": "Avbryt",
|
"delete_dialog_cancel": "Avbryt",
|
||||||
"delete_dialog_ok": "Slett",
|
"delete_dialog_ok": "Slett",
|
||||||
"delete_dialog_ok_force": "Delete Anyway",
|
"delete_dialog_ok_force": "Slett uansett",
|
||||||
"delete_dialog_title": "Slett permanent",
|
"delete_dialog_title": "Slett permanent",
|
||||||
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
|
"delete_local_dialog_ok_backed_up_only": "Slett kun sikkerhetskopierte objekter",
|
||||||
"delete_local_dialog_ok_force": "Delete Anyway",
|
"delete_local_dialog_ok_force": "Slett uansett",
|
||||||
"delete_shared_link_dialog_content": "Er du sikker på at du vil slette denne delte linken?",
|
"delete_shared_link_dialog_content": "Er du sikker på at du vil slette denne delte linken?",
|
||||||
"delete_shared_link_dialog_title": "Slett delt link",
|
"delete_shared_link_dialog_title": "Slett delt link",
|
||||||
"description_input_hint_text": "Legg til beskrivelse ...",
|
"description_input_hint_text": "Legg til beskrivelse ...",
|
||||||
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETALJER",
|
"exif_bottom_sheet_details": "DETALJER",
|
||||||
"exif_bottom_sheet_location": "PLASSERING",
|
"exif_bottom_sheet_location": "PLASSERING",
|
||||||
"exif_bottom_sheet_location_add": "Legg til lokasjon",
|
"exif_bottom_sheet_location_add": "Legg til lokasjon",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Under utvikling",
|
"experimental_settings_new_asset_list_subtitle": "Under utvikling",
|
||||||
"experimental_settings_new_asset_list_title": "Aktiver eksperimentell rutenettsvisning",
|
"experimental_settings_new_asset_list_title": "Aktiver eksperimentell rutenettsvisning",
|
||||||
"experimental_settings_subtitle": "Bruk på egen risiko!",
|
"experimental_settings_subtitle": "Bruk på egen risiko!",
|
||||||
@ -199,7 +200,7 @@
|
|||||||
"home_page_archive_err_partner": "Kan ikke arkivere partnerobjekter, hopper over",
|
"home_page_archive_err_partner": "Kan ikke arkivere partnerobjekter, hopper over",
|
||||||
"home_page_building_timeline": "Genererer tidslinjen",
|
"home_page_building_timeline": "Genererer tidslinjen",
|
||||||
"home_page_delete_err_partner": "Kan ikke slette partnerobjekter, hopper over",
|
"home_page_delete_err_partner": "Kan ikke slette partnerobjekter, hopper over",
|
||||||
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
"home_page_delete_remote_err_local": "Lokale objekter i fjernslettingsvalgene, hopper over",
|
||||||
"home_page_favorite_err_local": "Kan ikke sette favoritt på lokale objekter enda, hopper over",
|
"home_page_favorite_err_local": "Kan ikke sette favoritt på lokale objekter enda, hopper over",
|
||||||
"home_page_favorite_err_partner": "Kan ikke merke partnerobjekter som favoritt enda, hopper over",
|
"home_page_favorite_err_partner": "Kan ikke merke partnerobjekter som favoritt enda, hopper over",
|
||||||
"home_page_first_time_notice": "Hvis dette er første gangen du benytter appen, velg et album (eller flere) for sikkerhetskopiering, slik at tidslinjen kan fylles med dine bilder og videoer.",
|
"home_page_first_time_notice": "Hvis dette er første gangen du benytter appen, velg et album (eller flere) for sikkerhetskopiering, slik at tidslinjen kan fylles med dine bilder og videoer.",
|
||||||
@ -275,12 +276,12 @@
|
|||||||
"map_settings_include_show_archived": "Inkluder arkiverte",
|
"map_settings_include_show_archived": "Inkluder arkiverte",
|
||||||
"map_settings_only_relative_range": "Datoområde",
|
"map_settings_only_relative_range": "Datoområde",
|
||||||
"map_settings_only_show_favorites": "Vis kun favoritter",
|
"map_settings_only_show_favorites": "Vis kun favoritter",
|
||||||
"map_settings_theme_settings": "Map Theme",
|
"map_settings_theme_settings": "Karttema",
|
||||||
"map_zoom_to_see_photos": "Zoom ut for å se bilder",
|
"map_zoom_to_see_photos": "Zoom ut for å se bilder",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Bevegelige bilder",
|
"motion_photos_page_title": "Bevegelige bilder",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Kan ikke endre dato på objekt(er) med kun lese-rettigheter, hopper over",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
"multiselect_grid_edit_gps_err_read_only": "Kan ikke endre lokasjon på objekt(er) med kun lese-rettigheter, hopper over",
|
||||||
"notification_permission_dialog_cancel": "Avbryt",
|
"notification_permission_dialog_cancel": "Avbryt",
|
||||||
"notification_permission_dialog_content": "For å aktivere notifikasjoner, gå til Innstillinger og velg tillat.",
|
"notification_permission_dialog_content": "For å aktivere notifikasjoner, gå til Innstillinger og velg tillat.",
|
||||||
"notification_permission_dialog_settings": "Innstillinger",
|
"notification_permission_dialog_settings": "Innstillinger",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action_common_cancel": "Annuleren",
|
"action_common_cancel": "Annuleren",
|
||||||
"action_common_update": "Updaten",
|
"action_common_update": "Bijwerken",
|
||||||
"add_to_album_bottom_sheet_added": "Toegevoegd aan {album}",
|
"add_to_album_bottom_sheet_added": "Toegevoegd aan {album}",
|
||||||
"add_to_album_bottom_sheet_already_exists": "Staat al in {album}",
|
"add_to_album_bottom_sheet_already_exists": "Staat al in {album}",
|
||||||
"advanced_settings_log_level_title": "Log niveau: {}",
|
"advanced_settings_log_level_title": "Log niveau: {}",
|
||||||
@ -26,17 +26,17 @@
|
|||||||
"album_viewer_appbar_share_err_title": "Albumtitel wijzigen mislukt",
|
"album_viewer_appbar_share_err_title": "Albumtitel wijzigen mislukt",
|
||||||
"album_viewer_appbar_share_leave": "Verlaat album",
|
"album_viewer_appbar_share_leave": "Verlaat album",
|
||||||
"album_viewer_appbar_share_remove": "Verwijder uit album",
|
"album_viewer_appbar_share_remove": "Verwijder uit album",
|
||||||
"album_viewer_appbar_share_to": "Deel Naar",
|
"album_viewer_appbar_share_to": "Delen met",
|
||||||
"album_viewer_page_share_add_users": "Gebruikers toevoegen",
|
"album_viewer_page_share_add_users": "Gebruikers toevoegen",
|
||||||
"all_people_page_title": "Personen",
|
"all_people_page_title": "Personen",
|
||||||
"all_videos_page_title": "Video's",
|
"all_videos_page_title": "Video's",
|
||||||
"app_bar_signout_dialog_content": "Weet je zeker dat je je wilt afmelden?",
|
"app_bar_signout_dialog_content": "Weet je zeker dat je wilt uitloggen?",
|
||||||
"app_bar_signout_dialog_ok": "Ja",
|
"app_bar_signout_dialog_ok": "Ja",
|
||||||
"app_bar_signout_dialog_title": "Log uit",
|
"app_bar_signout_dialog_title": "Log uit",
|
||||||
"archive_page_no_archived_assets": "Geen gearchiveerde assets gevonden",
|
"archive_page_no_archived_assets": "Geen gearchiveerde assets gevonden",
|
||||||
"archive_page_title": "Archief ({})",
|
"archive_page_title": "Archief ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "Kan alleen-lezen asset(s) niet verwijderen, overslaan",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "Kan offline asset(s) niet ophalen, overslaan",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Dynamische layout",
|
"asset_list_layout_settings_dynamic_layout_title": "Dynamische layout",
|
||||||
"asset_list_layout_settings_group_automatically": "Automatisch",
|
"asset_list_layout_settings_group_automatically": "Automatisch",
|
||||||
"asset_list_layout_settings_group_by": "Groupeer assets per",
|
"asset_list_layout_settings_group_by": "Groupeer assets per",
|
||||||
@ -104,7 +104,7 @@
|
|||||||
"backup_err_only_album": "Kan het enige album niet verwijderen",
|
"backup_err_only_album": "Kan het enige album niet verwijderen",
|
||||||
"backup_info_card_assets": "assets",
|
"backup_info_card_assets": "assets",
|
||||||
"backup_manual_cancelled": "Geannuleerd",
|
"backup_manual_cancelled": "Geannuleerd",
|
||||||
"backup_manual_failed": "Gefaald",
|
"backup_manual_failed": "Mislukt",
|
||||||
"backup_manual_in_progress": "Het uploaden is al bezig. Probeer het na een tijdje",
|
"backup_manual_in_progress": "Het uploaden is al bezig. Probeer het na een tijdje",
|
||||||
"backup_manual_success": "Succes",
|
"backup_manual_success": "Succes",
|
||||||
"backup_manual_title": "Uploadstatus",
|
"backup_manual_title": "Uploadstatus",
|
||||||
@ -113,7 +113,7 @@
|
|||||||
"cache_settings_clear_cache_button_title": "Wist de cache van de app. Dit zal de presentaties van de app aanzienlijk beïnvloeden totdat de cache opnieuw is opgebouwd.",
|
"cache_settings_clear_cache_button_title": "Wist de cache van de app. Dit zal de presentaties van de app aanzienlijk beïnvloeden totdat de cache opnieuw is opgebouwd.",
|
||||||
"cache_settings_duplicated_assets_clear_button": "MAAK VRIJ",
|
"cache_settings_duplicated_assets_clear_button": "MAAK VRIJ",
|
||||||
"cache_settings_duplicated_assets_subtitle": "Foto's en video's op de zwarte lijst van de app",
|
"cache_settings_duplicated_assets_subtitle": "Foto's en video's op de zwarte lijst van de app",
|
||||||
"cache_settings_duplicated_assets_title": "Gedupliceerde Assets ({})",
|
"cache_settings_duplicated_assets_title": "Gedupliceerde assets ({})",
|
||||||
"cache_settings_image_cache_size": "Grootte afbeeldingscache ({} assets)",
|
"cache_settings_image_cache_size": "Grootte afbeeldingscache ({} assets)",
|
||||||
"cache_settings_statistics_album": "Bibliotheekthumbnails",
|
"cache_settings_statistics_album": "Bibliotheekthumbnails",
|
||||||
"cache_settings_statistics_assets": "{} assets ({})",
|
"cache_settings_statistics_assets": "{} assets ({})",
|
||||||
@ -124,7 +124,7 @@
|
|||||||
"cache_settings_subtitle": "Beheer het cachegedrag van de Immich app",
|
"cache_settings_subtitle": "Beheer het cachegedrag van de Immich app",
|
||||||
"cache_settings_thumbnail_size": "Thumbnail-cachegrootte ({} assets)",
|
"cache_settings_thumbnail_size": "Thumbnail-cachegrootte ({} assets)",
|
||||||
"cache_settings_tile_subtitle": "Beheer het gedrag van lokale opslag",
|
"cache_settings_tile_subtitle": "Beheer het gedrag van lokale opslag",
|
||||||
"cache_settings_tile_title": "Lokale Opslag",
|
"cache_settings_tile_title": "Lokale opslag",
|
||||||
"cache_settings_title": "Cache-instellingen",
|
"cache_settings_title": "Cache-instellingen",
|
||||||
"change_password_form_confirm_password": "Bevestig wachtwoord",
|
"change_password_form_confirm_password": "Bevestig wachtwoord",
|
||||||
"change_password_form_description": "Hallo {name},\n\nDit is ofwel de eerste keer dat je inlogt, of er is een verzoek gedaan om je wachtwoord te wijzigen. Vul hieronder een nieuw wachtwoord in.",
|
"change_password_form_description": "Hallo {name},\n\nDit is ofwel de eerste keer dat je inlogt, of er is een verzoek gedaan om je wachtwoord te wijzigen. Vul hieronder een nieuw wachtwoord in.",
|
||||||
@ -142,15 +142,15 @@
|
|||||||
"control_bottom_app_bar_archive": "Archiveren",
|
"control_bottom_app_bar_archive": "Archiveren",
|
||||||
"control_bottom_app_bar_create_new_album": "Nieuw album maken",
|
"control_bottom_app_bar_create_new_album": "Nieuw album maken",
|
||||||
"control_bottom_app_bar_delete": "Verwijderen",
|
"control_bottom_app_bar_delete": "Verwijderen",
|
||||||
"control_bottom_app_bar_delete_from_immich": "Delete from Immich",
|
"control_bottom_app_bar_delete_from_immich": "Verwijderen van Immich",
|
||||||
"control_bottom_app_bar_delete_from_local": "Delete from device",
|
"control_bottom_app_bar_delete_from_local": "Verwijderen van apparaat",
|
||||||
"control_bottom_app_bar_edit_location": "Locatie Bewerken",
|
"control_bottom_app_bar_edit_location": "Locatie bewerken",
|
||||||
"control_bottom_app_bar_edit_time": "Datum & Tijd Bewerken",
|
"control_bottom_app_bar_edit_time": "Datum & tijd bewerken",
|
||||||
"control_bottom_app_bar_favorite": "Favoriet",
|
"control_bottom_app_bar_favorite": "Favoriet",
|
||||||
"control_bottom_app_bar_share": "Delen",
|
"control_bottom_app_bar_share": "Delen",
|
||||||
"control_bottom_app_bar_share_to": "Deel Naar",
|
"control_bottom_app_bar_share_to": "Delen met",
|
||||||
"control_bottom_app_bar_stack": "Stapel",
|
"control_bottom_app_bar_stack": "Stapel",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Verplaatsen naar prullenbak",
|
||||||
"control_bottom_app_bar_unarchive": "Herstellen",
|
"control_bottom_app_bar_unarchive": "Herstellen",
|
||||||
"control_bottom_app_bar_unfavorite": "Onfavoriet",
|
"control_bottom_app_bar_unfavorite": "Onfavoriet",
|
||||||
"control_bottom_app_bar_upload": "Uploaden",
|
"control_bottom_app_bar_upload": "Uploaden",
|
||||||
@ -165,26 +165,27 @@
|
|||||||
"daily_title_text_date_year": "E dd MMM yyyy",
|
"daily_title_text_date_year": "E dd MMM yyyy",
|
||||||
"date_format": "E d LLL y • H:mm",
|
"date_format": "E d LLL y • H:mm",
|
||||||
"delete_dialog_alert": "Deze items zullen permanent verwijderd worden van Immich en je apparaat",
|
"delete_dialog_alert": "Deze items zullen permanent verwijderd worden van Immich en je apparaat",
|
||||||
"delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server",
|
"delete_dialog_alert_local": "Deze items worden permanent verwijderd van je apparaat, maar blijven beschikbaar op de Immich server",
|
||||||
"delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device",
|
"delete_dialog_alert_local_non_backed_up": "Van sommige items is geen back-up gemaakt in Immich en zullen permanent van je apparaat worden verwijderd",
|
||||||
"delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server",
|
"delete_dialog_alert_remote": "Deze items worden permanent verwijderd van de Immich server",
|
||||||
"delete_dialog_cancel": "Annuleren",
|
"delete_dialog_cancel": "Annuleren",
|
||||||
"delete_dialog_ok": "Verwijderen",
|
"delete_dialog_ok": "Verwijderen",
|
||||||
"delete_dialog_ok_force": "Delete Anyway",
|
"delete_dialog_ok_force": "Toch verwijderen",
|
||||||
"delete_dialog_title": "Permanent verwijderen",
|
"delete_dialog_title": "Permanent verwijderen",
|
||||||
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
|
"delete_local_dialog_ok_backed_up_only": "Verwijder alleen met back-up",
|
||||||
"delete_local_dialog_ok_force": "Delete Anyway",
|
"delete_local_dialog_ok_force": "Toch verwijderen",
|
||||||
"delete_shared_link_dialog_content": "Weet je zeker dat je deze gedeelde link wilt verwijderen?",
|
"delete_shared_link_dialog_content": "Weet je zeker dat je deze gedeelde link wilt verwijderen?",
|
||||||
"delete_shared_link_dialog_title": "Verwijder Gedeelde Link",
|
"delete_shared_link_dialog_title": "Verwijder gedeelde link",
|
||||||
"description_input_hint_text": "Beschrijving toevoegen...",
|
"description_input_hint_text": "Beschrijving toevoegen...",
|
||||||
"description_input_submit_error": "Beschrijving bijwerken mislukt, controleer het logboek voor meer details",
|
"description_input_submit_error": "Beschrijving bijwerken mislukt, controleer het logboek voor meer details",
|
||||||
"edit_date_time_dialog_date_time": "Datum en Tijd",
|
"edit_date_time_dialog_date_time": "Datum en tijd",
|
||||||
"edit_date_time_dialog_timezone": "Tijdzone",
|
"edit_date_time_dialog_timezone": "Tijdzone",
|
||||||
"edit_location_dialog_title": "Locatie",
|
"edit_location_dialog_title": "Locatie",
|
||||||
"exif_bottom_sheet_description": "Beschrijving toevoegen...",
|
"exif_bottom_sheet_description": "Beschrijving toevoegen...",
|
||||||
"exif_bottom_sheet_details": "DETAILS",
|
"exif_bottom_sheet_details": "DETAILS",
|
||||||
"exif_bottom_sheet_location": "LOCATIE",
|
"exif_bottom_sheet_location": "LOCATIE",
|
||||||
"exif_bottom_sheet_location_add": "Locatie toevoegen",
|
"exif_bottom_sheet_location_add": "Locatie toevoegen",
|
||||||
|
"exif_bottom_sheet_people": "MENSEN",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Werk in uitvoering",
|
"experimental_settings_new_asset_list_subtitle": "Werk in uitvoering",
|
||||||
"experimental_settings_new_asset_list_title": "Experimenteel fotoraster inschakelen",
|
"experimental_settings_new_asset_list_title": "Experimenteel fotoraster inschakelen",
|
||||||
"experimental_settings_subtitle": "Gebruik op eigen risico!",
|
"experimental_settings_subtitle": "Gebruik op eigen risico!",
|
||||||
@ -199,7 +200,7 @@
|
|||||||
"home_page_archive_err_partner": "Partner assets kunnen niet gearchiveerd worden, overslaan",
|
"home_page_archive_err_partner": "Partner assets kunnen niet gearchiveerd worden, overslaan",
|
||||||
"home_page_building_timeline": "Tijdlijn opbouwen",
|
"home_page_building_timeline": "Tijdlijn opbouwen",
|
||||||
"home_page_delete_err_partner": "Partner assets kunnen niet verwijderd worden, overslaan",
|
"home_page_delete_err_partner": "Partner assets kunnen niet verwijderd worden, overslaan",
|
||||||
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
"home_page_delete_remote_err_local": "Lokale assets staan in verwijder selectie externe assets, overslaan",
|
||||||
"home_page_favorite_err_local": "Lokale assets kunnen nog niet als favoriet worden aangemerkt, overslaan",
|
"home_page_favorite_err_local": "Lokale assets kunnen nog niet als favoriet worden aangemerkt, overslaan",
|
||||||
"home_page_favorite_err_partner": "Partner assets kunnen nog niet ge-favoriet worden, overslaan",
|
"home_page_favorite_err_partner": "Partner assets kunnen nog niet ge-favoriet worden, overslaan",
|
||||||
"home_page_first_time_notice": "Als dit de eerste keer is dat je de app gebruikt, zorg er dan voor dat je een back-up album kiest, zodat de tijdlijn gevuld kan worden met foto's en video's uit het album.",
|
"home_page_first_time_notice": "Als dit de eerste keer is dat je de app gebruikt, zorg er dan voor dat je een back-up album kiest, zodat de tijdlijn gevuld kan worden met foto's en video's uit het album.",
|
||||||
@ -259,10 +260,10 @@
|
|||||||
"map_location_dialog_yes": "Ja",
|
"map_location_dialog_yes": "Ja",
|
||||||
"map_location_picker_page_use_location": "Gebruik deze locatie",
|
"map_location_picker_page_use_location": "Gebruik deze locatie",
|
||||||
"map_location_service_disabled_content": "Locatie service moet ingeschakeld zijn om assets van je huidige locatie weer te geven. Wil je het nu inschakelen?",
|
"map_location_service_disabled_content": "Locatie service moet ingeschakeld zijn om assets van je huidige locatie weer te geven. Wil je het nu inschakelen?",
|
||||||
"map_location_service_disabled_title": "Locatie Service uitgeschakeld",
|
"map_location_service_disabled_title": "Locatie service uitgeschakeld",
|
||||||
"map_no_assets_in_bounds": "Geen foto's in dit gebied",
|
"map_no_assets_in_bounds": "Geen foto's in dit gebied",
|
||||||
"map_no_location_permission_content": "Locatie toestemming is nodig om assets van je huidige locatie weer te geven. Wil je het nu toestaan?",
|
"map_no_location_permission_content": "Locatie toestemming is nodig om assets van je huidige locatie weer te geven. Wil je het nu toestaan?",
|
||||||
"map_no_location_permission_title": "Locatie Toestemming geweigerd",
|
"map_no_location_permission_title": "Locatie toestemming geweigerd",
|
||||||
"map_settings_dark_mode": "Donkere modus",
|
"map_settings_dark_mode": "Donkere modus",
|
||||||
"map_settings_date_range_option_all": "Alle",
|
"map_settings_date_range_option_all": "Alle",
|
||||||
"map_settings_date_range_option_day": "Afgelopen 24 uur",
|
"map_settings_date_range_option_day": "Afgelopen 24 uur",
|
||||||
@ -270,17 +271,17 @@
|
|||||||
"map_settings_date_range_option_year": "Afgelopen jaar",
|
"map_settings_date_range_option_year": "Afgelopen jaar",
|
||||||
"map_settings_date_range_option_years": "Afgelopen {} jaar",
|
"map_settings_date_range_option_years": "Afgelopen {} jaar",
|
||||||
"map_settings_dialog_cancel": "Annuleren",
|
"map_settings_dialog_cancel": "Annuleren",
|
||||||
"map_settings_dialog_save": "Sla op",
|
"map_settings_dialog_save": "Opslaan",
|
||||||
"map_settings_dialog_title": "Kaart Instellingen",
|
"map_settings_dialog_title": "Kaart Instellingen",
|
||||||
"map_settings_include_show_archived": "Weergeef Gearchiveerden",
|
"map_settings_include_show_archived": "Toon gearchiveerde",
|
||||||
"map_settings_only_relative_range": "Datum bereik",
|
"map_settings_only_relative_range": "Datum bereik",
|
||||||
"map_settings_only_show_favorites": "Toon enkel favorieten",
|
"map_settings_only_show_favorites": "Toon enkel favorieten",
|
||||||
"map_settings_theme_settings": "Map Theme",
|
"map_settings_theme_settings": "Kaart thema",
|
||||||
"map_zoom_to_see_photos": "Zoom uit om foto's te zien",
|
"map_zoom_to_see_photos": "Zoom uit om foto's te zien",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Bewegende foto's",
|
"motion_photos_page_title": "Bewegende foto's",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Kan datum van alleen-lezen asset(s) niet wijzigen, overslaan",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
"multiselect_grid_edit_gps_err_read_only": "Kan locatie van alleen-lezen asset(s) niet wijzigen, overslaan",
|
||||||
"notification_permission_dialog_cancel": "Annuleren",
|
"notification_permission_dialog_cancel": "Annuleren",
|
||||||
"notification_permission_dialog_content": "Om meldingen in te schakelen, ga naar Instellingen en selecteer toestaan.",
|
"notification_permission_dialog_content": "Om meldingen in te schakelen, ga naar Instellingen en selecteer toestaan.",
|
||||||
"notification_permission_dialog_settings": "Instellingen",
|
"notification_permission_dialog_settings": "Instellingen",
|
||||||
@ -390,7 +391,7 @@
|
|||||||
"shared_link_app_bar_title": "Gedeelde links",
|
"shared_link_app_bar_title": "Gedeelde links",
|
||||||
"shared_link_clipboard_copied_massage": "Gekopieerd naar klembord",
|
"shared_link_clipboard_copied_massage": "Gekopieerd naar klembord",
|
||||||
"shared_link_clipboard_text": "Link: {}\nWachtwoord: {}",
|
"shared_link_clipboard_text": "Link: {}\nWachtwoord: {}",
|
||||||
"shared_link_create_app_bar_title": "Link maken om te delen",
|
"shared_link_create_app_bar_title": "Gedeelde link maken",
|
||||||
"shared_link_create_error": "Fout bij het maken van een gedeelde link",
|
"shared_link_create_error": "Fout bij het maken van een gedeelde link",
|
||||||
"shared_link_create_info": "Laat iedereen met de link de geselecteerde foto(s) zien",
|
"shared_link_create_info": "Laat iedereen met de link de geselecteerde foto(s) zien",
|
||||||
"shared_link_create_submit_button": "Link maken",
|
"shared_link_create_submit_button": "Link maken",
|
||||||
@ -399,7 +400,7 @@
|
|||||||
"shared_link_edit_app_bar_title": "Bewerk link",
|
"shared_link_edit_app_bar_title": "Bewerk link",
|
||||||
"shared_link_edit_change_expiry": "Bewerk vervaltijd",
|
"shared_link_edit_change_expiry": "Bewerk vervaltijd",
|
||||||
"shared_link_edit_description": "Beschrijving",
|
"shared_link_edit_description": "Beschrijving",
|
||||||
"shared_link_edit_description_hint": "Geef de deel beschrijving",
|
"shared_link_edit_description_hint": "Voer beschrijving voor de gedeelde link in",
|
||||||
"shared_link_edit_expire_after": "Verval na",
|
"shared_link_edit_expire_after": "Verval na",
|
||||||
"shared_link_edit_expire_after_option_day": "1 dag",
|
"shared_link_edit_expire_after_option_day": "1 dag",
|
||||||
"shared_link_edit_expire_after_option_days": "{} dagen",
|
"shared_link_edit_expire_after_option_days": "{} dagen",
|
||||||
@ -409,9 +410,9 @@
|
|||||||
"shared_link_edit_expire_after_option_minutes": "{} minuten",
|
"shared_link_edit_expire_after_option_minutes": "{} minuten",
|
||||||
"shared_link_edit_expire_after_option_never": "Nooit",
|
"shared_link_edit_expire_after_option_never": "Nooit",
|
||||||
"shared_link_edit_password": "Wachtwoord",
|
"shared_link_edit_password": "Wachtwoord",
|
||||||
"shared_link_edit_password_hint": "Voer het deel wachtwoord in",
|
"shared_link_edit_password_hint": "Voer wachtwoord voor de gedeelde link in",
|
||||||
"shared_link_edit_show_meta": "Toon metadata",
|
"shared_link_edit_show_meta": "Toon metadata",
|
||||||
"shared_link_edit_submit_button": "Update link",
|
"shared_link_edit_submit_button": "Link bijwerken",
|
||||||
"shared_link_empty": "Je hebt geen gedeelde links",
|
"shared_link_empty": "Je hebt geen gedeelde links",
|
||||||
"shared_link_error_server_url_fetch": "Kan de server url niet ophalen",
|
"shared_link_error_server_url_fetch": "Kan de server url niet ophalen",
|
||||||
"shared_link_expired": "Verlopen",
|
"shared_link_expired": "Verlopen",
|
||||||
@ -452,19 +453,19 @@
|
|||||||
"theme_setting_three_stage_loading_title": "Laden in drie fasen inschakelen",
|
"theme_setting_three_stage_loading_title": "Laden in drie fasen inschakelen",
|
||||||
"translated_text_options": "Opties",
|
"translated_text_options": "Opties",
|
||||||
"trash_page_delete": "Verwijderen",
|
"trash_page_delete": "Verwijderen",
|
||||||
"trash_page_delete_all": "Verwijder Alle",
|
"trash_page_delete_all": "Verwijder alle",
|
||||||
"trash_page_empty_trash_btn": "Leeg prullenbak",
|
"trash_page_empty_trash_btn": "Leeg prullenbak",
|
||||||
"trash_page_empty_trash_dialog_content": "Wil je je weggegooide assets leegmaken? Deze items worden permanent verwijderd van Immich",
|
"trash_page_empty_trash_dialog_content": "Wil je de prullenbak leegmaken? Deze items worden permanent verwijderd van Immich",
|
||||||
"trash_page_empty_trash_dialog_ok": "Ok",
|
"trash_page_empty_trash_dialog_ok": "Ok",
|
||||||
"trash_page_info": "Verwijderde items worden permanent verwijderd na {} dagen",
|
"trash_page_info": "Verwijderde items worden permanent verwijderd na {} dagen",
|
||||||
"trash_page_no_assets": "Geen verwijderde assets",
|
"trash_page_no_assets": "Geen verwijderde assets",
|
||||||
"trash_page_restore": "Herstellen",
|
"trash_page_restore": "Herstellen",
|
||||||
"trash_page_restore_all": "Herstel Alle",
|
"trash_page_restore_all": "Herstel alle",
|
||||||
"trash_page_select_assets_btn": "Selecteer assets",
|
"trash_page_select_assets_btn": "Selecteer assets",
|
||||||
"trash_page_select_btn": "Selecteren",
|
"trash_page_select_btn": "Selecteren",
|
||||||
"trash_page_title": "Prullenbak ({})",
|
"trash_page_title": "Prullenbak ({})",
|
||||||
"upload_dialog_cancel": "Annuleren",
|
"upload_dialog_cancel": "Annuleren",
|
||||||
"upload_dialog_info": "Wilt u een backup maken van de geselecteerde Asset(s) op de server?",
|
"upload_dialog_info": "Wil je een backup maken van de geselecteerde asset(s) op de server?",
|
||||||
"upload_dialog_ok": "Uploaden",
|
"upload_dialog_ok": "Uploaden",
|
||||||
"upload_dialog_title": "Asset uploaden",
|
"upload_dialog_title": "Asset uploaden",
|
||||||
"version_announcement_overlay_ack": "Bevestig",
|
"version_announcement_overlay_ack": "Bevestig",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "SZCZEGÓŁY",
|
"exif_bottom_sheet_details": "SZCZEGÓŁY",
|
||||||
"exif_bottom_sheet_location": "LOKALIZACJA",
|
"exif_bottom_sheet_location": "LOKALIZACJA",
|
||||||
"exif_bottom_sheet_location_add": "Dodaj lokalizację",
|
"exif_bottom_sheet_location_add": "Dodaj lokalizację",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Praca w toku",
|
"experimental_settings_new_asset_list_subtitle": "Praca w toku",
|
||||||
"experimental_settings_new_asset_list_title": "Włącz eksperymentalną układ zdjęć",
|
"experimental_settings_new_asset_list_title": "Włącz eksperymentalną układ zdjęć",
|
||||||
"experimental_settings_subtitle": "Używaj na własne ryzyko!",
|
"experimental_settings_subtitle": "Używaj na własne ryzyko!",
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"action_common_cancel": "Cancel",
|
"action_common_cancel": "Cancelar",
|
||||||
"action_common_update": "Update",
|
"action_common_update": "Atualizar",
|
||||||
"add_to_album_bottom_sheet_added": "Added to {album}",
|
"add_to_album_bottom_sheet_added": "Adicionar a {album}",
|
||||||
"add_to_album_bottom_sheet_already_exists": "Already in {album}",
|
"add_to_album_bottom_sheet_already_exists": "Já pertence a {album}",
|
||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
||||||
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
||||||
@ -16,7 +16,7 @@
|
|||||||
"album_info_card_backup_album_included": "INCLUÍDO",
|
"album_info_card_backup_album_included": "INCLUÍDO",
|
||||||
"album_thumbnail_card_item": "1 item",
|
"album_thumbnail_card_item": "1 item",
|
||||||
"album_thumbnail_card_items": "{} itens",
|
"album_thumbnail_card_items": "{} itens",
|
||||||
"album_thumbnail_card_shared": "Compartilhado",
|
"album_thumbnail_card_shared": " · Partilhado",
|
||||||
"album_thumbnail_owned": "Owned",
|
"album_thumbnail_owned": "Owned",
|
||||||
"album_thumbnail_shared_by": "Shared by {}",
|
"album_thumbnail_shared_by": "Shared by {}",
|
||||||
"album_viewer_appbar_share_delete": "Deletar álbum",
|
"album_viewer_appbar_share_delete": "Deletar álbum",
|
||||||
@ -29,21 +29,21 @@
|
|||||||
"album_viewer_appbar_share_to": "Share To",
|
"album_viewer_appbar_share_to": "Share To",
|
||||||
"album_viewer_page_share_add_users": "Adicionar usuários",
|
"album_viewer_page_share_add_users": "Adicionar usuários",
|
||||||
"all_people_page_title": "People",
|
"all_people_page_title": "People",
|
||||||
"all_videos_page_title": "Videos",
|
"all_videos_page_title": "Vídeos",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
"app_bar_signout_dialog_content": "Tem a certeza que deseja sair?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sair",
|
||||||
"archive_page_no_archived_assets": "No archived assets found",
|
"archive_page_no_archived_assets": "No archived assets found",
|
||||||
"archive_page_title": "Archive ({})",
|
"archive_page_title": "Archive ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "Não é possível eliminar o(s) recurso(s) só de leitura, ignorando",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "Não é possível obter recurso(s) offline, ignorando",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Dynamic layout",
|
"asset_list_layout_settings_dynamic_layout_title": "Disposição dinâmica",
|
||||||
"asset_list_layout_settings_group_automatically": "Automatic",
|
"asset_list_layout_settings_group_automatically": "Automatic",
|
||||||
"asset_list_layout_settings_group_by": "Group assets by",
|
"asset_list_layout_settings_group_by": "Agrupar recursos por",
|
||||||
"asset_list_layout_settings_group_by_month": "Month",
|
"asset_list_layout_settings_group_by_month": "Mês",
|
||||||
"asset_list_layout_settings_group_by_month_day": "Month + day",
|
"asset_list_layout_settings_group_by_month_day": "Mês + dia",
|
||||||
"asset_list_settings_subtitle": "Configurações de layout da grade de fotos",
|
"asset_list_settings_subtitle": "Configurações de layout da grelha de fotos",
|
||||||
"asset_list_settings_title": "Grade de fotos",
|
"asset_list_settings_title": "Grelha de fotos",
|
||||||
"backup_album_selection_page_albums_device": "Álbuns no dispositivo ({})",
|
"backup_album_selection_page_albums_device": "Álbuns no dispositivo ({})",
|
||||||
"backup_album_selection_page_albums_tap": "Toque para incluir, duplo toque para exluir",
|
"backup_album_selection_page_albums_tap": "Toque para incluir, duplo toque para exluir",
|
||||||
"backup_album_selection_page_assets_scatter": "Os itens podem estar espalhados por vários álbuns. Assim, os álbuns podem ser incluídos ou excluídos durante o processo de backup.",
|
"backup_album_selection_page_assets_scatter": "Os itens podem estar espalhados por vários álbuns. Assim, os álbuns podem ser incluídos ou excluídos durante o processo de backup.",
|
||||||
@ -90,11 +90,11 @@
|
|||||||
"backup_controller_page_remainder": "Restante",
|
"backup_controller_page_remainder": "Restante",
|
||||||
"backup_controller_page_remainder_sub": "Fotos e vídeos restantes para fazer backup da seleção",
|
"backup_controller_page_remainder_sub": "Fotos e vídeos restantes para fazer backup da seleção",
|
||||||
"backup_controller_page_select": "Selecione",
|
"backup_controller_page_select": "Selecione",
|
||||||
"backup_controller_page_server_storage": "Espaço no Servidor",
|
"backup_controller_page_server_storage": "Armazenamento no servidor",
|
||||||
"backup_controller_page_start_backup": "Iniciar Backup",
|
"backup_controller_page_start_backup": "Iniciar Backup",
|
||||||
"backup_controller_page_status_off": "Backup está desligado",
|
"backup_controller_page_status_off": "Backup está desligado",
|
||||||
"backup_controller_page_status_on": "Backup está ligado",
|
"backup_controller_page_status_on": "Backup está ligado",
|
||||||
"backup_controller_page_storage_format": "{} de {} usado",
|
"backup_controller_page_storage_format": "{} de {} usados",
|
||||||
"backup_controller_page_to_backup": "Álbuns para fazer backup",
|
"backup_controller_page_to_backup": "Álbuns para fazer backup",
|
||||||
"backup_controller_page_total": "Total",
|
"backup_controller_page_total": "Total",
|
||||||
"backup_controller_page_total_sub": "Todas as fotos e vídeos dos álbuns selecionados",
|
"backup_controller_page_total_sub": "Todas as fotos e vídeos dos álbuns selecionados",
|
||||||
@ -118,91 +118,92 @@
|
|||||||
"cache_settings_statistics_album": "Miniaturas da biblioteca",
|
"cache_settings_statistics_album": "Miniaturas da biblioteca",
|
||||||
"cache_settings_statistics_assets": "{} itens ({})",
|
"cache_settings_statistics_assets": "{} itens ({})",
|
||||||
"cache_settings_statistics_full": "Imagens completas",
|
"cache_settings_statistics_full": "Imagens completas",
|
||||||
"cache_settings_statistics_shared": "Miniaturas de álbuns compartilhados",
|
"cache_settings_statistics_shared": "Miniaturas de álbuns partilhados",
|
||||||
"cache_settings_statistics_thumbnail": "Miniaturas",
|
"cache_settings_statistics_thumbnail": "Miniaturas",
|
||||||
"cache_settings_statistics_title": "Uso de cache",
|
"cache_settings_statistics_title": "Uso de cache",
|
||||||
"cache_settings_subtitle": "Controle o comportamento de cache do aplicativo Immich",
|
"cache_settings_subtitle": "Controle o comportamento de cache do aplicativo Immich",
|
||||||
"cache_settings_thumbnail_size": "Tamanho do cache de miniaturas ({} itens)",
|
"cache_settings_thumbnail_size": "Tamanho do cache de miniaturas ({} itens)",
|
||||||
"cache_settings_tile_subtitle": "Control the local storage behaviour",
|
"cache_settings_tile_subtitle": "Controlar o comportamento do armazenamento local",
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Armazenamento local",
|
||||||
"cache_settings_title": "Configurações de cache",
|
"cache_settings_title": "Configurações de cache",
|
||||||
"change_password_form_confirm_password": "Confirm Password",
|
"change_password_form_confirm_password": "Confirme a senha",
|
||||||
"change_password_form_description": "Hi {name},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
"change_password_form_description": "Olá {name},\n\nÉ a primeira vez que entra no sistema ou foi-lhe pedido que alterasse a sua palavra-passe. Introduza a nova palavra-passe abaixo.",
|
||||||
"change_password_form_new_password": "New Password",
|
"change_password_form_new_password": "Nova senha",
|
||||||
"change_password_form_password_mismatch": "Passwords do not match",
|
"change_password_form_password_mismatch": "As senhas não coincidem",
|
||||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
"change_password_form_reenter_new_password": "Re-introduza a nova senha",
|
||||||
"common_add_to_album": "Add to album",
|
"common_add_to_album": "Adicionar ao álbum",
|
||||||
"common_change_password": "Change Password",
|
"common_change_password": "Mudar a senha",
|
||||||
"common_create_new_album": "Create new album",
|
"common_create_new_album": "Criar novo álbum",
|
||||||
"common_server_error": "Please check your network connection, make sure the server is reachable and app/server versions are compatible.",
|
"common_server_error": "Verifique a sua ligação de rede, certifique-se de que o servidor está acessível e de que as versões da aplicação/servidor são compatíveis.",
|
||||||
"common_shared": "Shared",
|
"common_shared": "Shared",
|
||||||
"control_bottom_app_bar_add_to_album": "Adicionar ao álbum",
|
"control_bottom_app_bar_add_to_album": "Adicionar ao álbum",
|
||||||
"control_bottom_app_bar_album_info": "{} itens",
|
"control_bottom_app_bar_album_info": "{} itens",
|
||||||
"control_bottom_app_bar_album_info_shared": "{} itens · Compartilhado",
|
"control_bottom_app_bar_album_info_shared": "{} itens · Partilhado",
|
||||||
"control_bottom_app_bar_archive": "Archive",
|
"control_bottom_app_bar_archive": "Archive",
|
||||||
"control_bottom_app_bar_create_new_album": "Criar novo álbum",
|
"control_bottom_app_bar_create_new_album": "Criar novo álbum",
|
||||||
"control_bottom_app_bar_delete": "Deletar",
|
"control_bottom_app_bar_delete": "Deletar",
|
||||||
"control_bottom_app_bar_delete_from_immich": "Delete from Immich",
|
"control_bottom_app_bar_delete_from_immich": "Apagar do Immich",
|
||||||
"control_bottom_app_bar_delete_from_local": "Delete from device",
|
"control_bottom_app_bar_delete_from_local": "Apagar do dispositivo",
|
||||||
"control_bottom_app_bar_edit_location": "Edit Location",
|
"control_bottom_app_bar_edit_location": "Edit Location",
|
||||||
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
||||||
"control_bottom_app_bar_favorite": "Favorite",
|
"control_bottom_app_bar_favorite": "Favorite",
|
||||||
"control_bottom_app_bar_share": "Compartilhar",
|
"control_bottom_app_bar_share": "Partilhar",
|
||||||
"control_bottom_app_bar_share_to": "Share To",
|
"control_bottom_app_bar_share_to": "Share To",
|
||||||
"control_bottom_app_bar_stack": "Stack",
|
"control_bottom_app_bar_stack": "Stack",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Mover para o lixo",
|
||||||
"control_bottom_app_bar_unarchive": "Unarchive",
|
"control_bottom_app_bar_unarchive": "Unarchive",
|
||||||
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
||||||
"control_bottom_app_bar_upload": "Upload",
|
"control_bottom_app_bar_upload": "Upload",
|
||||||
"create_album_page_untitled": "Sem título",
|
"create_album_page_untitled": "Sem título",
|
||||||
"create_shared_album_page_create": "Criar",
|
"create_shared_album_page_create": "Criar",
|
||||||
"create_shared_album_page_share": "Compartilhar",
|
"create_shared_album_page_share": "Partilhar",
|
||||||
"create_shared_album_page_share_add_assets": "ADICIONAR ITENS",
|
"create_shared_album_page_share_add_assets": "ADICIONAR ITENS",
|
||||||
"create_shared_album_page_share_select_photos": "Selecionar Fotos",
|
"create_shared_album_page_share_select_photos": "Selecionar Fotos",
|
||||||
"curated_location_page_title": "Places",
|
"curated_location_page_title": "Sítios",
|
||||||
"curated_object_page_title": "Things",
|
"curated_object_page_title": "Objetos",
|
||||||
"daily_title_text_date": "E, MMM dd",
|
"daily_title_text_date": "E, MMM dd",
|
||||||
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
||||||
"date_format": "E, LLL d, y • h:mm a",
|
"date_format": "E, LLL d, y • h:mm a",
|
||||||
"delete_dialog_alert": "Esses itens serão permanentemente deletados do Immich e do seu dispositivo",
|
"delete_dialog_alert": "Esses itens serão permanentemente deletados do Immich e do seu dispositivo",
|
||||||
"delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server",
|
"delete_dialog_alert_local": "Estes itens serão removidos permanentemente do seu dispositivo, mas continuarão disponíveis no servidor Immich",
|
||||||
"delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device",
|
"delete_dialog_alert_local_non_backed_up": "Alguns dos itens não estão guardados no Immich e serão removidos permanentemente do seu dispositivo",
|
||||||
"delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server",
|
"delete_dialog_alert_remote": "Estes itens serão permanentemente eliminados do servidor Immich",
|
||||||
"delete_dialog_cancel": "Cancelar",
|
"delete_dialog_cancel": "Cancelar",
|
||||||
"delete_dialog_ok": "Deletar",
|
"delete_dialog_ok": "Deletar",
|
||||||
"delete_dialog_ok_force": "Delete Anyway",
|
"delete_dialog_ok_force": "Apagar de qualquer forma",
|
||||||
"delete_dialog_title": "Deletar Permanentemente",
|
"delete_dialog_title": "Deletar Permanentemente",
|
||||||
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
|
"delete_local_dialog_ok_backed_up_only": "Eliminar apenas existentes na cópia de segurança",
|
||||||
"delete_local_dialog_ok_force": "Delete Anyway",
|
"delete_local_dialog_ok_force": "Apagar de qualquer forma",
|
||||||
"delete_shared_link_dialog_content": "Are you sure you want to delete this shared link?",
|
"delete_shared_link_dialog_content": "Are you sure you want to delete this shared link?",
|
||||||
"delete_shared_link_dialog_title": "Delete Shared Link",
|
"delete_shared_link_dialog_title": "Delete Shared Link",
|
||||||
"description_input_hint_text": "Add description...",
|
"description_input_hint_text": "Add description...",
|
||||||
"description_input_submit_error": "Error updating description, check the log for more details",
|
"description_input_submit_error": "Error updating description, check the log for more details",
|
||||||
"edit_date_time_dialog_date_time": "Date and Time",
|
"edit_date_time_dialog_date_time": "Data e Hora",
|
||||||
"edit_date_time_dialog_timezone": "Timezone",
|
"edit_date_time_dialog_timezone": "Fuso horário",
|
||||||
"edit_location_dialog_title": "Location",
|
"edit_location_dialog_title": "Location",
|
||||||
"exif_bottom_sheet_description": "Adicionar Descrição...",
|
"exif_bottom_sheet_description": "Adicionar Descrição...",
|
||||||
"exif_bottom_sheet_details": "DETALHES",
|
"exif_bottom_sheet_details": "DETALHES",
|
||||||
"exif_bottom_sheet_location": "LOCALIZAÇÃO",
|
"exif_bottom_sheet_location": "LOCALIZAÇÃO",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Trabalho em andamento",
|
"experimental_settings_new_asset_list_subtitle": "Trabalho em andamento",
|
||||||
"experimental_settings_new_asset_list_title": "Ativar visualização de grade experimental",
|
"experimental_settings_new_asset_list_title": "Ativar visualização de grelha experimental",
|
||||||
"experimental_settings_subtitle": "Use por sua conta e risco!",
|
"experimental_settings_subtitle": "Use por sua conta e risco!",
|
||||||
"experimental_settings_title": "Experimental",
|
"experimental_settings_title": "Experimental",
|
||||||
"favorites_page_no_favorites": "No favorite assets found",
|
"favorites_page_no_favorites": "No favorite assets found",
|
||||||
"favorites_page_title": "Favorites",
|
"favorites_page_title": "Favoritos",
|
||||||
"home_page_add_to_album_conflicts": "Ativos {added} adicionados ao álbum {album}. {failed} ativos já estão no álbum.",
|
"home_page_add_to_album_conflicts": "Ativos {added} adicionados ao álbum {album}. {failed} ativos já estão no álbum.",
|
||||||
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
"home_page_add_to_album_err_local": "Ainda não é possível adicionar recursos locais aos álbuns, ignorando",
|
||||||
"home_page_add_to_album_success": "Ativos {added} adicionados ao álbum {album}.",
|
"home_page_add_to_album_success": "Ativos {added} adicionados ao álbum {album}.",
|
||||||
"home_page_album_err_partner": "Can not add partner assets to an album yet, skipping",
|
"home_page_album_err_partner": "Can not add partner assets to an album yet, skipping",
|
||||||
"home_page_archive_err_local": "Can not archive local assets yet, skipping",
|
"home_page_archive_err_local": "Can not archive local assets yet, skipping",
|
||||||
"home_page_archive_err_partner": "Can not archive partner assets, skipping",
|
"home_page_archive_err_partner": "Can not archive partner assets, skipping",
|
||||||
"home_page_building_timeline": "Building the timeline",
|
"home_page_building_timeline": "A construir a timeline",
|
||||||
"home_page_delete_err_partner": "Can not delete partner assets, skipping",
|
"home_page_delete_err_partner": "Can not delete partner assets, skipping",
|
||||||
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
"home_page_delete_remote_err_local": "Recursos locais na seleção remota de eliminação, ignorando",
|
||||||
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
|
"home_page_favorite_err_local": "Ainda não é possível adicionar recursos locais favoritos, ignorando",
|
||||||
"home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping",
|
"home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping",
|
||||||
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
|
"home_page_first_time_notice": "Se for a primeira vez que utiliza a aplicação, certifique-se de que escolhe um álbum ou álbuns de cópia de segurança, para que a linha cronológica possa preencher as fotografias e os vídeos no(s) álbum(s).",
|
||||||
"home_page_share_err_local": "Can not share local assets via link, skipping",
|
"home_page_share_err_local": "Can not share local assets via link, skipping",
|
||||||
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
|
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
|
||||||
"image_viewer_page_state_provider_download_error": "Download Error",
|
"image_viewer_page_state_provider_download_error": "Download Error",
|
||||||
@ -210,16 +211,16 @@
|
|||||||
"image_viewer_page_state_provider_share_error": "Share Error",
|
"image_viewer_page_state_provider_share_error": "Share Error",
|
||||||
"library_page_albums": "Álbuns",
|
"library_page_albums": "Álbuns",
|
||||||
"library_page_archive": "Archive",
|
"library_page_archive": "Archive",
|
||||||
"library_page_device_albums": "Albums on Device",
|
"library_page_device_albums": "Álbuns no dispositivo",
|
||||||
"library_page_favorites": "Favorites",
|
"library_page_favorites": "Favoritos",
|
||||||
"library_page_new_album": "Novo Album",
|
"library_page_new_album": "Novo álbum",
|
||||||
"library_page_sharing": "Sharing",
|
"library_page_sharing": "Partilhar",
|
||||||
"library_page_sort_asset_count": "Number of assets",
|
"library_page_sort_asset_count": "Número de recursos",
|
||||||
"library_page_sort_created": "Created date",
|
"library_page_sort_created": "Data de criação",
|
||||||
"library_page_sort_last_modified": "Last modified",
|
"library_page_sort_last_modified": "Last modified",
|
||||||
"library_page_sort_most_oldest_photo": "Oldest photo",
|
"library_page_sort_most_oldest_photo": "Foto mais antiga",
|
||||||
"library_page_sort_most_recent_photo": "Most recent photo",
|
"library_page_sort_most_recent_photo": "Most recent photo",
|
||||||
"library_page_sort_title": "Album title",
|
"library_page_sort_title": "Título do álbum",
|
||||||
"location_picker_choose_on_map": "Choose on map",
|
"location_picker_choose_on_map": "Choose on map",
|
||||||
"location_picker_latitude": "Latitude",
|
"location_picker_latitude": "Latitude",
|
||||||
"location_picker_latitude_error": "Enter a valid latitude",
|
"location_picker_latitude_error": "Enter a valid latitude",
|
||||||
@ -228,8 +229,8 @@
|
|||||||
"location_picker_longitude_error": "Enter a valid longitude",
|
"location_picker_longitude_error": "Enter a valid longitude",
|
||||||
"location_picker_longitude_hint": "Enter your longitude here",
|
"location_picker_longitude_hint": "Enter your longitude here",
|
||||||
"login_disabled": "Login has been disabled",
|
"login_disabled": "Login has been disabled",
|
||||||
"login_form_api_exception": "API exception. Please check the server URL and try again.",
|
"login_form_api_exception": "Excepção de API. Verifique o URL do servidor e tente novamente.",
|
||||||
"login_form_back_button_text": "Back",
|
"login_form_back_button_text": "Voltar",
|
||||||
"login_form_button_text": "Login",
|
"login_form_button_text": "Login",
|
||||||
"login_form_email_hint": "seuemail@email.com",
|
"login_form_email_hint": "seuemail@email.com",
|
||||||
"login_form_endpoint_hint": "http://ip-do-seu-servidor:porta/api",
|
"login_form_endpoint_hint": "http://ip-do-seu-servidor:porta/api",
|
||||||
@ -245,15 +246,15 @@
|
|||||||
"login_form_handshake_exception": "There was an Handshake Exception with the server. Enable self-signed certificate support in the settings if you are using a self-signed certificate.",
|
"login_form_handshake_exception": "There was an Handshake Exception with the server. Enable self-signed certificate support in the settings if you are using a self-signed certificate.",
|
||||||
"login_form_label_email": "Email",
|
"login_form_label_email": "Email",
|
||||||
"login_form_label_password": "Senha",
|
"login_form_label_password": "Senha",
|
||||||
"login_form_next_button": "Next",
|
"login_form_next_button": "Avançar",
|
||||||
"login_form_password_hint": "senha",
|
"login_form_password_hint": "senha",
|
||||||
"login_form_save_login": "Permanecer logado",
|
"login_form_save_login": "Permanecer logado",
|
||||||
"login_form_server_empty": "Enter a server URL.",
|
"login_form_server_empty": "Introduzir um URL de servidor.",
|
||||||
"login_form_server_error": "Could not connect to server.",
|
"login_form_server_error": "Não foi possível ligar ao servidor.",
|
||||||
"login_password_changed_error": "There was an error updating your password",
|
"login_password_changed_error": "There was an error updating your password",
|
||||||
"login_password_changed_success": "Password updated successfully",
|
"login_password_changed_success": "Password updated successfully",
|
||||||
"map_assets_in_bound": "{} photo",
|
"map_assets_in_bound": "{} photo",
|
||||||
"map_assets_in_bounds": "{} photos",
|
"map_assets_in_bounds": "{} fotos",
|
||||||
"map_cannot_get_user_location": "Cannot get user's location",
|
"map_cannot_get_user_location": "Cannot get user's location",
|
||||||
"map_location_dialog_cancel": "Cancel",
|
"map_location_dialog_cancel": "Cancel",
|
||||||
"map_location_dialog_yes": "Yes",
|
"map_location_dialog_yes": "Yes",
|
||||||
@ -264,83 +265,83 @@
|
|||||||
"map_no_location_permission_content": "Location permission is needed to display assets from your current location. Do you want to allow it now?",
|
"map_no_location_permission_content": "Location permission is needed to display assets from your current location. Do you want to allow it now?",
|
||||||
"map_no_location_permission_title": "Location Permission denied",
|
"map_no_location_permission_title": "Location Permission denied",
|
||||||
"map_settings_dark_mode": "Dark mode",
|
"map_settings_dark_mode": "Dark mode",
|
||||||
"map_settings_date_range_option_all": "All",
|
"map_settings_date_range_option_all": "Tudo",
|
||||||
"map_settings_date_range_option_day": "Past 24 hours",
|
"map_settings_date_range_option_day": "Últimas 24 horas",
|
||||||
"map_settings_date_range_option_days": "Past {} days",
|
"map_settings_date_range_option_days": "Últimos {} dias",
|
||||||
"map_settings_date_range_option_year": "Past year",
|
"map_settings_date_range_option_year": "Último ano",
|
||||||
"map_settings_date_range_option_years": "Past {} years",
|
"map_settings_date_range_option_years": "Últimos {} anos",
|
||||||
"map_settings_dialog_cancel": "Cancel",
|
"map_settings_dialog_cancel": "Cancel",
|
||||||
"map_settings_dialog_save": "Save",
|
"map_settings_dialog_save": "Save",
|
||||||
"map_settings_dialog_title": "Map Settings",
|
"map_settings_dialog_title": "Map Settings",
|
||||||
"map_settings_include_show_archived": "Include Archived",
|
"map_settings_include_show_archived": "Include Archived",
|
||||||
"map_settings_only_relative_range": "Date range",
|
"map_settings_only_relative_range": "Date range",
|
||||||
"map_settings_only_show_favorites": "Show Favorite Only",
|
"map_settings_only_show_favorites": "Show Favorite Only",
|
||||||
"map_settings_theme_settings": "Map Theme",
|
"map_settings_theme_settings": "Tema do mapa",
|
||||||
"map_zoom_to_see_photos": "Zoom out to see photos",
|
"map_zoom_to_see_photos": "Zoom out to see photos",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Motion Photos",
|
"motion_photos_page_title": "Fotos com movimento",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
||||||
"notification_permission_dialog_cancel": "Cancel",
|
"notification_permission_dialog_cancel": "Cancelar",
|
||||||
"notification_permission_dialog_content": "To enable notifications, go to Settings and select allow.",
|
"notification_permission_dialog_content": "Para ativar as notificações, vá a Definições e selecione permitir.",
|
||||||
"notification_permission_dialog_settings": "Settings",
|
"notification_permission_dialog_settings": "Settings",
|
||||||
"notification_permission_list_tile_content": "Grant permission to enable notifications.",
|
"notification_permission_list_tile_content": "Grant permission to enable notifications.",
|
||||||
"notification_permission_list_tile_enable_button": "Enable Notifications",
|
"notification_permission_list_tile_enable_button": "Enable Notifications",
|
||||||
"notification_permission_list_tile_title": "Notification Permission",
|
"notification_permission_list_tile_title": "Permissão de notificações",
|
||||||
"partner_page_add_partner": "Add partner",
|
"partner_page_add_partner": "Adicionar parceiro",
|
||||||
"partner_page_empty_message": "Your photos are not yet shared with any partner.",
|
"partner_page_empty_message": "Your photos are not yet shared with any partner.",
|
||||||
"partner_page_no_more_users": "No more users to add",
|
"partner_page_no_more_users": "No more users to add",
|
||||||
"partner_page_partner_add_failed": "Failed to add partner",
|
"partner_page_partner_add_failed": "Failed to add partner",
|
||||||
"partner_page_select_partner": "Select partner",
|
"partner_page_select_partner": "Selecionar parceiro",
|
||||||
"partner_page_shared_to_title": "Shared to",
|
"partner_page_shared_to_title": "Shared to",
|
||||||
"partner_page_stop_sharing_content": "{} will no longer be able to access your photos.",
|
"partner_page_stop_sharing_content": "{} will no longer be able to access your photos.",
|
||||||
"partner_page_stop_sharing_title": "Stop sharing your photos?",
|
"partner_page_stop_sharing_title": "Stop sharing your photos?",
|
||||||
"partner_page_title": "Partner",
|
"partner_page_title": "Partner",
|
||||||
"permission_onboarding_back": "Back",
|
"permission_onboarding_back": "Back",
|
||||||
"permission_onboarding_continue_anyway": "Continue anyway",
|
"permission_onboarding_continue_anyway": "Continuar de qualquer maneira",
|
||||||
"permission_onboarding_get_started": "Get started",
|
"permission_onboarding_get_started": "Get started",
|
||||||
"permission_onboarding_go_to_settings": "Go to settings",
|
"permission_onboarding_go_to_settings": "Go to settings",
|
||||||
"permission_onboarding_grant_permission": "Grant permission",
|
"permission_onboarding_grant_permission": "Grant permission",
|
||||||
"permission_onboarding_log_out": "Log out",
|
"permission_onboarding_log_out": "Sair",
|
||||||
"permission_onboarding_permission_denied": "Permission denied. To use Immich, grant photo and video permissions in Settings.",
|
"permission_onboarding_permission_denied": "Permissão negada. Para utilizar o Immich, conceda permissões de fotografia e vídeo nas Definições.",
|
||||||
"permission_onboarding_permission_granted": "Permission granted! You are all set.",
|
"permission_onboarding_permission_granted": "Autorização concedida! Está tudo pronto.",
|
||||||
"permission_onboarding_permission_limited": "Permission limited. To let Immich backup and manage your entire gallery collection, grant photo and video permissions in Settings.",
|
"permission_onboarding_permission_limited": "Permissão limitada. Para permitir que o Immich faça cópias de segurança e gira toda a sua coleção de galerias, conceda permissões para fotografias e vídeos nas Definições.",
|
||||||
"permission_onboarding_request": "Immich requires permission to view your photos and videos.",
|
"permission_onboarding_request": "O Immich requer autorização para ver as suas fotografias e vídeos.",
|
||||||
"profile_drawer_app_logs": "Logs",
|
"profile_drawer_app_logs": "Logs",
|
||||||
"profile_drawer_client_out_of_date_major": "Mobile App is out of date. Please update to the latest major version.",
|
"profile_drawer_client_out_of_date_major": "A aplicação móvel está desatualizada. Atualize para a versão principal mais recente.",
|
||||||
"profile_drawer_client_out_of_date_minor": "Mobile App is out of date. Please update to the latest minor version.",
|
"profile_drawer_client_out_of_date_minor": "A aplicação móvel está desatualizada. Por favor, atualize para a versão mais recente.",
|
||||||
"profile_drawer_client_server_up_to_date": "Cliente e Servidor atualizados",
|
"profile_drawer_client_server_up_to_date": "Cliente e Servidor atualizados",
|
||||||
"profile_drawer_documentation": "Documentation",
|
"profile_drawer_documentation": "Documentation",
|
||||||
"profile_drawer_github": "GitHub",
|
"profile_drawer_github": "GitHub",
|
||||||
"profile_drawer_server_out_of_date_major": "Server is out of date. Please update to the latest major version.",
|
"profile_drawer_server_out_of_date_major": "O servidor está desatualizado. Atualize para a versão principal mais recente.",
|
||||||
"profile_drawer_server_out_of_date_minor": "Server is out of date. Please update to the latest minor version.",
|
"profile_drawer_server_out_of_date_minor": "O servidor está desatualizado. Atualize para a versão mais recente.",
|
||||||
"profile_drawer_settings": "Configurações",
|
"profile_drawer_settings": "Configurações",
|
||||||
"profile_drawer_sign_out": "Sair",
|
"profile_drawer_sign_out": "Sair",
|
||||||
"profile_drawer_trash": "Trash",
|
"profile_drawer_trash": "Trash",
|
||||||
"recently_added_page_title": "Recently Added",
|
"recently_added_page_title": "Adicionado recentemente",
|
||||||
"scaffold_body_error_occurred": "Error occurred",
|
"scaffold_body_error_occurred": "Ocorreu um erro",
|
||||||
"search_bar_hint": "Busque suas fotos",
|
"search_bar_hint": "Busque suas fotos",
|
||||||
"search_page_categories": "Categories",
|
"search_page_categories": "Categories",
|
||||||
"search_page_favorites": "Favorites",
|
"search_page_favorites": "Favoritos",
|
||||||
"search_page_motion_photos": "Motion Photos",
|
"search_page_motion_photos": "Fotos com movimento",
|
||||||
"search_page_no_objects": "Nenhuma informação de objeto disponível",
|
"search_page_no_objects": "Nenhuma informação de objeto disponível",
|
||||||
"search_page_no_places": "Nenhuma informação de lugares disponível",
|
"search_page_no_places": "Nenhuma informação de sítios disponível",
|
||||||
"search_page_people": "People",
|
"search_page_people": "People",
|
||||||
"search_page_person_add_name_dialog_cancel": "Cancel",
|
"search_page_person_add_name_dialog_cancel": "Cancelar",
|
||||||
"search_page_person_add_name_dialog_hint": "Name",
|
"search_page_person_add_name_dialog_hint": "Nome",
|
||||||
"search_page_person_add_name_dialog_save": "Save",
|
"search_page_person_add_name_dialog_save": "Guardar",
|
||||||
"search_page_person_add_name_dialog_title": "Add a name",
|
"search_page_person_add_name_dialog_title": "Adicionar um nome",
|
||||||
"search_page_person_add_name_subtitle": "Find them fast by name with search",
|
"search_page_person_add_name_subtitle": "Encontre-os rapidamente pelo nome com a pesquisa",
|
||||||
"search_page_person_add_name_title": "Add a name",
|
"search_page_person_add_name_title": "Adicionar um nome",
|
||||||
"search_page_person_edit_name": "Edit name",
|
"search_page_person_edit_name": "Editar nome",
|
||||||
"search_page_places": "Lugares",
|
"search_page_places": "Sítios",
|
||||||
"search_page_recently_added": "Recently added",
|
"search_page_recently_added": "Adicionado recentemente",
|
||||||
"search_page_screenshots": "Screenshots",
|
"search_page_screenshots": "Screenshots",
|
||||||
"search_page_selfies": "Selfies",
|
"search_page_selfies": "Selfies",
|
||||||
"search_page_things": "Objetos",
|
"search_page_things": "Objetos",
|
||||||
"search_page_videos": "Videos",
|
"search_page_videos": "Vídeos",
|
||||||
"search_page_view_all_button": "View all",
|
"search_page_view_all_button": "Ver tudo",
|
||||||
"search_page_your_activity": "Your activity",
|
"search_page_your_activity": "A sua atividade",
|
||||||
"search_page_your_map": "Your Map",
|
"search_page_your_map": "Your Map",
|
||||||
"search_result_page_new_search_hint": "Nova Busca",
|
"search_result_page_new_search_hint": "Nova Busca",
|
||||||
"search_suggestion_list_smart_search_hint_1": "Smart search is enabled by default, to search for metadata use the syntax ",
|
"search_suggestion_list_smart_search_hint_1": "Smart search is enabled by default, to search for metadata use the syntax ",
|
||||||
@ -348,10 +349,10 @@
|
|||||||
"select_additional_user_for_sharing_page_suggestions": "Sugestões",
|
"select_additional_user_for_sharing_page_suggestions": "Sugestões",
|
||||||
"select_user_for_sharing_page_err_album": "Falha ao criar o álbum",
|
"select_user_for_sharing_page_err_album": "Falha ao criar o álbum",
|
||||||
"select_user_for_sharing_page_share_suggestions": "Sugestões",
|
"select_user_for_sharing_page_share_suggestions": "Sugestões",
|
||||||
"server_info_box_app_version": "App Version",
|
"server_info_box_app_version": "Versão da app",
|
||||||
"server_info_box_latest_release": "Latest Version",
|
"server_info_box_latest_release": "Última versão",
|
||||||
"server_info_box_server_url": "Server URL",
|
"server_info_box_server_url": "Server URL",
|
||||||
"server_info_box_server_version": "Server Version",
|
"server_info_box_server_version": "Versão do servidor",
|
||||||
"setting_image_viewer_help": "O visualizador de detalhes carrega primeiro a miniatura pequena, depois carrega a visualização de tamanho médio (se ativado) e, finalmente, carrega o original (se ativado).",
|
"setting_image_viewer_help": "O visualizador de detalhes carrega primeiro a miniatura pequena, depois carrega a visualização de tamanho médio (se ativado) e, finalmente, carrega o original (se ativado).",
|
||||||
"setting_image_viewer_original_subtitle": "Ative para carregar a imagem original em resolução total (grande!). Desative para reduzir o uso de dados (na rede e no cache do dispositivo).",
|
"setting_image_viewer_original_subtitle": "Ative para carregar a imagem original em resolução total (grande!). Desative para reduzir o uso de dados (na rede e no cache do dispositivo).",
|
||||||
"setting_image_viewer_original_title": "Carregar imagem original",
|
"setting_image_viewer_original_title": "Carregar imagem original",
|
||||||
@ -381,65 +382,65 @@
|
|||||||
"shared_album_activity_remove_title": "Delete Activity",
|
"shared_album_activity_remove_title": "Delete Activity",
|
||||||
"shared_album_activity_setting_subtitle": "Let others respond",
|
"shared_album_activity_setting_subtitle": "Let others respond",
|
||||||
"shared_album_activity_setting_title": "Comments & likes",
|
"shared_album_activity_setting_title": "Comments & likes",
|
||||||
"shared_album_section_people_action_error": "Error leaving/removing from album",
|
"shared_album_section_people_action_error": "Erro ao sair/remover do álbum",
|
||||||
"shared_album_section_people_action_leave": "Remove user from album",
|
"shared_album_section_people_action_leave": "Remover utilizador do álbum",
|
||||||
"shared_album_section_people_action_remove_user": "Remove user from album",
|
"shared_album_section_people_action_remove_user": "Remover utilizador do álbum",
|
||||||
"shared_album_section_people_owner_label": "Owner",
|
"shared_album_section_people_owner_label": "Owner",
|
||||||
"shared_album_section_people_title": "PEOPLE",
|
"shared_album_section_people_title": "PEOPLE",
|
||||||
"share_dialog_preparing": "Preparando...",
|
"share_dialog_preparing": "Preparando...",
|
||||||
"shared_link_app_bar_title": "Shared Links",
|
"shared_link_app_bar_title": "Links partilhados",
|
||||||
"shared_link_clipboard_copied_massage": "Copied to clipboard",
|
"shared_link_clipboard_copied_massage": "Copied to clipboard",
|
||||||
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
||||||
"shared_link_create_app_bar_title": "Create link to share",
|
"shared_link_create_app_bar_title": "Create link to share",
|
||||||
"shared_link_create_error": "Error while creating shared link",
|
"shared_link_create_error": "Error while creating shared link",
|
||||||
"shared_link_create_info": "Let anyone with the link see the selected photo(s)",
|
"shared_link_create_info": "Let anyone with the link see the selected photo(s)",
|
||||||
"shared_link_create_submit_button": "Create link",
|
"shared_link_create_submit_button": "Create link",
|
||||||
"shared_link_edit_allow_download": "Allow public user to download",
|
"shared_link_edit_allow_download": "Permitir que um utilizador público descarregue",
|
||||||
"shared_link_edit_allow_upload": "Allow public user to upload",
|
"shared_link_edit_allow_upload": "Permitir que um utilizador público carregue",
|
||||||
"shared_link_edit_app_bar_title": "Edit link",
|
"shared_link_edit_app_bar_title": "Edit link",
|
||||||
"shared_link_edit_change_expiry": "Change expiration time",
|
"shared_link_edit_change_expiry": "Alterar o prazo de validade",
|
||||||
"shared_link_edit_description": "Description",
|
"shared_link_edit_description": "Description",
|
||||||
"shared_link_edit_description_hint": "Enter the share description",
|
"shared_link_edit_description_hint": "Enter the share description",
|
||||||
"shared_link_edit_expire_after": "Expire after",
|
"shared_link_edit_expire_after": "Expire after",
|
||||||
"shared_link_edit_expire_after_option_day": "1 day",
|
"shared_link_edit_expire_after_option_day": "1 dia",
|
||||||
"shared_link_edit_expire_after_option_days": "{} days",
|
"shared_link_edit_expire_after_option_days": "{} dias",
|
||||||
"shared_link_edit_expire_after_option_hour": "1 hour",
|
"shared_link_edit_expire_after_option_hour": "1 hora",
|
||||||
"shared_link_edit_expire_after_option_hours": "{} hours",
|
"shared_link_edit_expire_after_option_hours": "{} horas",
|
||||||
"shared_link_edit_expire_after_option_minute": "1 minute",
|
"shared_link_edit_expire_after_option_minute": "1 minuto",
|
||||||
"shared_link_edit_expire_after_option_minutes": "{} minutes",
|
"shared_link_edit_expire_after_option_minutes": "{} minutos",
|
||||||
"shared_link_edit_expire_after_option_never": "Never",
|
"shared_link_edit_expire_after_option_never": "Never",
|
||||||
"shared_link_edit_password": "Password",
|
"shared_link_edit_password": "Password",
|
||||||
"shared_link_edit_password_hint": "Enter the share password",
|
"shared_link_edit_password_hint": "Enter the share password",
|
||||||
"shared_link_edit_show_meta": "Show metadata",
|
"shared_link_edit_show_meta": "Mostrar metadados",
|
||||||
"shared_link_edit_submit_button": "Update link",
|
"shared_link_edit_submit_button": "Atualizar link",
|
||||||
"shared_link_empty": "You don't have any shared links",
|
"shared_link_empty": "Não tem links partilhados",
|
||||||
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
||||||
"shared_link_expired": "Expired",
|
"shared_link_expired": "Expired",
|
||||||
"shared_link_expires_day": "Expires in {} day",
|
"shared_link_expires_day": "Expira em {} dia",
|
||||||
"shared_link_expires_days": "Expires in {} days",
|
"shared_link_expires_days": "Expira em {} dias",
|
||||||
"shared_link_expires_hour": "Expires in {} hour",
|
"shared_link_expires_hour": "Expira em {} hora",
|
||||||
"shared_link_expires_hours": "Expires in {} hours",
|
"shared_link_expires_hours": "Expira em {} horas",
|
||||||
"shared_link_expires_minute": "Expires in {} minute",
|
"shared_link_expires_minute": "Expira em {} minuto",
|
||||||
"shared_link_expires_minutes": "Expires in {} minutes",
|
"shared_link_expires_minutes": "Expires in {} minutes",
|
||||||
"shared_link_expires_never": "Expires ∞",
|
"shared_link_expires_never": "Expires ∞",
|
||||||
"shared_link_expires_second": "Expires in {} second",
|
"shared_link_expires_second": "Expira em {} segundo",
|
||||||
"shared_link_expires_seconds": "Expires in {} seconds",
|
"shared_link_expires_seconds": "Expires in {} seconds",
|
||||||
"shared_link_info_chip_download": "Download",
|
"shared_link_info_chip_download": "Descarregar",
|
||||||
"shared_link_info_chip_metadata": "EXIF",
|
"shared_link_info_chip_metadata": "EXIF",
|
||||||
"shared_link_info_chip_upload": "Upload",
|
"shared_link_info_chip_upload": "Upload",
|
||||||
"shared_link_manage_links": "Manage Shared links",
|
"shared_link_manage_links": "Gerir links partilhados",
|
||||||
"share_done": "Done",
|
"share_done": "Done",
|
||||||
"share_invite": "Convidar para álbum",
|
"share_invite": "Convidar para álbum",
|
||||||
"sharing_page_album": "Álbuns compartilhados",
|
"sharing_page_album": "Álbuns partilhados",
|
||||||
"sharing_page_description": "Criar álbuns compartilhados para compartilhas fotos e vídeos com pessoas na sua rede.",
|
"sharing_page_description": "Crie álbuns partilhados para partilhar fotografias e vídeos com pessoas da sua rede.",
|
||||||
"sharing_page_empty_list": "LISTA VAZIA",
|
"sharing_page_empty_list": "LISTA VAZIA",
|
||||||
"sharing_silver_appbar_create_shared_album": "Criar um álgum compartilhado",
|
"sharing_silver_appbar_create_shared_album": "Criar álbum partilhado",
|
||||||
"sharing_silver_appbar_shared_links": "Shared links",
|
"sharing_silver_appbar_shared_links": "Shared links",
|
||||||
"sharing_silver_appbar_share_partner": "Compartilhar com parceiro",
|
"sharing_silver_appbar_share_partner": "Partilhar com parceiro",
|
||||||
"tab_controller_nav_library": "Biblioteca",
|
"tab_controller_nav_library": "Biblioteca",
|
||||||
"tab_controller_nav_photos": "Fotos",
|
"tab_controller_nav_photos": "Fotos",
|
||||||
"tab_controller_nav_search": "Buscar",
|
"tab_controller_nav_search": "Procurar",
|
||||||
"tab_controller_nav_sharing": "Compartilhando",
|
"tab_controller_nav_sharing": "Partilhar",
|
||||||
"theme_setting_asset_list_storage_indicator_title": "Mostrar indicador de armazenamento em blocos de ativos",
|
"theme_setting_asset_list_storage_indicator_title": "Mostrar indicador de armazenamento em blocos de ativos",
|
||||||
"theme_setting_asset_list_tiles_per_row_title": "Número de itens por linha ({})",
|
"theme_setting_asset_list_tiles_per_row_title": "Número de itens por linha ({})",
|
||||||
"theme_setting_dark_mode_switch": "Modo escuro",
|
"theme_setting_dark_mode_switch": "Modo escuro",
|
||||||
@ -467,11 +468,11 @@
|
|||||||
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
|
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
|
||||||
"upload_dialog_ok": "Upload",
|
"upload_dialog_ok": "Upload",
|
||||||
"upload_dialog_title": "Upload Asset",
|
"upload_dialog_title": "Upload Asset",
|
||||||
"version_announcement_overlay_ack": "Need Context",
|
"version_announcement_overlay_ack": "Aceitar",
|
||||||
"version_announcement_overlay_release_notes": "notas de lançamento",
|
"version_announcement_overlay_release_notes": "notas de lançamento",
|
||||||
"version_announcement_overlay_text_1": "Olá, há um novo lançamento de",
|
"version_announcement_overlay_text_1": "Olá, há um novo lançamento de",
|
||||||
"version_announcement_overlay_text_2": "por favor, tome o seu tempo para visitar o",
|
"version_announcement_overlay_text_2": "por favor, tome o seu tempo para visitar o",
|
||||||
"version_announcement_overlay_text_3": "e certifique-se de que a configuração do docker-compose e do .env estejam atualizadas para evitar configurações incorretas, especialmente se você usar o WatchTower ou qualquer mecanismo que lide com a atualização automática do aplicativo do servidor.",
|
"version_announcement_overlay_text_3": "e certifique-se de que a configuração do docker-compose e do .env estejam atualizadas para evitar configurações incorretas, especialmente se usar o WatchTower ou qualquer mecanismo que lide com a atualização automática do servidor.",
|
||||||
"version_announcement_overlay_title": "Nova versão do servidor disponível \uD83C\uDF89",
|
"version_announcement_overlay_title": "Nova versão do servidor disponível \uD83C\uDF89",
|
||||||
"viewer_remove_from_stack": "Remove from Stack",
|
"viewer_remove_from_stack": "Remove from Stack",
|
||||||
"viewer_stack_use_as_main_asset": "Use as Main Asset",
|
"viewer_stack_use_as_main_asset": "Use as Main Asset",
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"action_common_cancel": "Cancel",
|
"action_common_cancel": "Отмена",
|
||||||
"action_common_update": "Update",
|
"action_common_update": "Обновить",
|
||||||
"add_to_album_bottom_sheet_added": "Добавлено в {album}",
|
"add_to_album_bottom_sheet_added": "Добавлено в {album}",
|
||||||
"add_to_album_bottom_sheet_already_exists": "Уже в {album}",
|
"add_to_album_bottom_sheet_already_exists": "Уже в {album}",
|
||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Некоторые устройства очень медленно загружают предпросмотр объектов, находящихся на устройстве. Активируйте эту настройку, чтобы вместо них загружались изображени с сервера.",
|
"advanced_settings_prefer_remote_subtitle": "Некоторые устройства очень медленно загружают предпросмотр объектов, находящихся на устройстве. Активируйте эту настройку, чтобы вместо них загружались изображения с сервера.",
|
||||||
"advanced_settings_prefer_remote_title": "Предпочитать фото на сервере",
|
"advanced_settings_prefer_remote_title": "Предпочитать фото на сервере",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Пропускает проверку сертификата SSL для конечной точки сервера. Требуется для самоподписанных сертификатов.",
|
"advanced_settings_self_signed_ssl_subtitle": "Пропускает проверку SSL-сертификата сервера. Требуется для самоподписанных сертификатов.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Разрешить самоподписанные SSL-сертификаты",
|
"advanced_settings_self_signed_ssl_title": "Разрешить самоподписанные SSL-сертификаты",
|
||||||
"advanced_settings_tile_subtitle": "Расширенные настройки пользователя",
|
"advanced_settings_tile_subtitle": "Расширенные настройки пользователя",
|
||||||
"advanced_settings_tile_title": "Расширенные",
|
"advanced_settings_tile_title": "Расширенные",
|
||||||
@ -35,14 +35,14 @@
|
|||||||
"app_bar_signout_dialog_title": "Выйти из системы",
|
"app_bar_signout_dialog_title": "Выйти из системы",
|
||||||
"archive_page_no_archived_assets": "В архиве сейчас пусто",
|
"archive_page_no_archived_assets": "В архиве сейчас пусто",
|
||||||
"archive_page_title": "Архив ({})",
|
"archive_page_title": "Архив ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "Невозможно удалить объект(ы) только для чтения, пропуск...",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "Невозможно получить оффлайн-объект(ы), пропуск...",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Динамическое расположение",
|
"asset_list_layout_settings_dynamic_layout_title": "Динамическое расположение",
|
||||||
"asset_list_layout_settings_group_automatically": "Автоматически",
|
"asset_list_layout_settings_group_automatically": "Автоматически",
|
||||||
"asset_list_layout_settings_group_by": "Группировать объекты по:",
|
"asset_list_layout_settings_group_by": "Группировать объекты по:",
|
||||||
"asset_list_layout_settings_group_by_month": "Месяцу",
|
"asset_list_layout_settings_group_by_month": "Месяцу",
|
||||||
"asset_list_layout_settings_group_by_month_day": "Месяцу и дню",
|
"asset_list_layout_settings_group_by_month_day": "Месяцу и дню",
|
||||||
"asset_list_settings_subtitle": "Настройки макета сетки фотографий",
|
"asset_list_settings_subtitle": "Настройка макета сетки фотографий",
|
||||||
"asset_list_settings_title": "Сетка фотографий",
|
"asset_list_settings_title": "Сетка фотографий",
|
||||||
"backup_album_selection_page_albums_device": "Альбомов на устройстве ({})",
|
"backup_album_selection_page_albums_device": "Альбомов на устройстве ({})",
|
||||||
"backup_album_selection_page_albums_tap": "Нажмите, чтобы включить, нажмите дважды, чтобы исключить",
|
"backup_album_selection_page_albums_tap": "Нажмите, чтобы включить, нажмите дважды, чтобы исключить",
|
||||||
@ -65,7 +65,7 @@
|
|||||||
"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": "\nОптимизация батареи",
|
"backup_controller_page_background_battery_info_title": "Оптимизация батареи",
|
||||||
"backup_controller_page_background_charging": "Только во время зарядки",
|
"backup_controller_page_background_charging": "Только во время зарядки",
|
||||||
"backup_controller_page_background_configure_error": "Не удалось настроить фоновую службу",
|
"backup_controller_page_background_configure_error": "Не удалось настроить фоновую службу",
|
||||||
"backup_controller_page_background_delay": "Отложить резервное копирование новых объектов: {}",
|
"backup_controller_page_background_delay": "Отложить резервное копирование новых объектов: {}",
|
||||||
@ -112,8 +112,8 @@
|
|||||||
"cache_settings_clear_cache_button": "Очистить кэш",
|
"cache_settings_clear_cache_button": "Очистить кэш",
|
||||||
"cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это значительно повлияет на производительность приложения, до тех пор, пока кэш не будет перестроен заново.",
|
"cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это значительно повлияет на производительность приложения, до тех пор, пока кэш не будет перестроен заново.",
|
||||||
"cache_settings_duplicated_assets_clear_button": "ОЧИСТИТЬ",
|
"cache_settings_duplicated_assets_clear_button": "ОЧИСТИТЬ",
|
||||||
"cache_settings_duplicated_assets_subtitle": "Photos and videos that are black listed by the app",
|
"cache_settings_duplicated_assets_subtitle": "Фото и видео, занесенные приложением в черный список",
|
||||||
"cache_settings_duplicated_assets_title": "Дублированные ресурсы",
|
"cache_settings_duplicated_assets_title": "Дублирующиеся объекты ({})",
|
||||||
"cache_settings_image_cache_size": "Размер кэша изображений ({} объектов)",
|
"cache_settings_image_cache_size": "Размер кэша изображений ({} объектов)",
|
||||||
"cache_settings_statistics_album": "Миниатюры библиотеки",
|
"cache_settings_statistics_album": "Миниатюры библиотеки",
|
||||||
"cache_settings_statistics_assets": "{} объектов ({})",
|
"cache_settings_statistics_assets": "{} объектов ({})",
|
||||||
@ -140,19 +140,19 @@
|
|||||||
"control_bottom_app_bar_album_info": "{} файлов",
|
"control_bottom_app_bar_album_info": "{} файлов",
|
||||||
"control_bottom_app_bar_album_info_shared": "{} файлов · Общий",
|
"control_bottom_app_bar_album_info_shared": "{} файлов · Общий",
|
||||||
"control_bottom_app_bar_archive": "Архив",
|
"control_bottom_app_bar_archive": "Архив",
|
||||||
"control_bottom_app_bar_create_new_album": "\nСоздать новый альбом",
|
"control_bottom_app_bar_create_new_album": "Создать новый альбом",
|
||||||
"control_bottom_app_bar_delete": "Удалить",
|
"control_bottom_app_bar_delete": "Удалить",
|
||||||
"control_bottom_app_bar_delete_from_immich": "Delete from Immich",
|
"control_bottom_app_bar_delete_from_immich": "Удалить из Immich\n",
|
||||||
"control_bottom_app_bar_delete_from_local": "Delete from device",
|
"control_bottom_app_bar_delete_from_local": "Удалить с устройства",
|
||||||
"control_bottom_app_bar_edit_location": "Изменить местоположение",
|
"control_bottom_app_bar_edit_location": "Редактировать местоположение",
|
||||||
"control_bottom_app_bar_edit_time": "Изменить дату и время",
|
"control_bottom_app_bar_edit_time": "Редактировать дату и время",
|
||||||
"control_bottom_app_bar_favorite": "Избранное",
|
"control_bottom_app_bar_favorite": "В избранное",
|
||||||
"control_bottom_app_bar_share": "Поделиться",
|
"control_bottom_app_bar_share": "Поделиться",
|
||||||
"control_bottom_app_bar_share_to": "Поделиться",
|
"control_bottom_app_bar_share_to": "Поделиться",
|
||||||
"control_bottom_app_bar_stack": "Стек",
|
"control_bottom_app_bar_stack": "Стек",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Переместить в корзину",
|
||||||
"control_bottom_app_bar_unarchive": "Восстановить",
|
"control_bottom_app_bar_unarchive": "Восстановить",
|
||||||
"control_bottom_app_bar_unfavorite": "Исключить из избранного",
|
"control_bottom_app_bar_unfavorite": "Удалить из избранного",
|
||||||
"control_bottom_app_bar_upload": "Загрузить",
|
"control_bottom_app_bar_upload": "Загрузить",
|
||||||
"create_album_page_untitled": "Без названия",
|
"create_album_page_untitled": "Без названия",
|
||||||
"create_shared_album_page_create": "Создать",
|
"create_shared_album_page_create": "Создать",
|
||||||
@ -165,26 +165,27 @@
|
|||||||
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
||||||
"date_format": "E, LLL d, y • h:mm a",
|
"date_format": "E, LLL d, y • h:mm a",
|
||||||
"delete_dialog_alert": "Эти элементы будут безвозвратно удалены из приложения, а также с вашего устройства",
|
"delete_dialog_alert": "Эти элементы будут безвозвратно удалены из приложения, а также с вашего устройства",
|
||||||
"delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server",
|
"delete_dialog_alert_local": "Эти объекты будут безвозвратно удалены с Вашего устройства, но по-прежнему будут доступны на сервере Immich",
|
||||||
"delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device",
|
"delete_dialog_alert_local_non_backed_up": "Резервные копии некоторых объектов не были загружены в Immich и будут безвозвратно удалены с Вашего устройства",
|
||||||
"delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server",
|
"delete_dialog_alert_remote": "Эти объекты будут безвозвратно удалены с сервера Immich",
|
||||||
"delete_dialog_cancel": "Отменить",
|
"delete_dialog_cancel": "Отменить",
|
||||||
"delete_dialog_ok": "Удалить",
|
"delete_dialog_ok": "Удалить",
|
||||||
"delete_dialog_ok_force": "Delete Anyway",
|
"delete_dialog_ok_force": "Все равно удалить",
|
||||||
"delete_dialog_title": "Удалить навсегда",
|
"delete_dialog_title": "Удалить навсегда",
|
||||||
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
|
"delete_local_dialog_ok_backed_up_only": "Удалить только резервные копии",
|
||||||
"delete_local_dialog_ok_force": "Delete Anyway",
|
"delete_local_dialog_ok_force": "Все равно удалить",
|
||||||
"delete_shared_link_dialog_content": "Вы уверены, что хотите удалить эту общую ссылку?",
|
"delete_shared_link_dialog_content": "Вы уверены, что хотите удалить эту общую ссылку?",
|
||||||
"delete_shared_link_dialog_title": "Удалить общую ссылку",
|
"delete_shared_link_dialog_title": "Удалить общую ссылку",
|
||||||
"description_input_hint_text": "Добавить описание...",
|
"description_input_hint_text": "Добавить описание...",
|
||||||
"description_input_submit_error": "Не удалось обновить описание, проверьте логи, чтобы узнать причину",
|
"description_input_submit_error": "Не удалось обновить описание, проверьте логи, чтобы узнать причину",
|
||||||
"edit_date_time_dialog_date_time": "Date and Time",
|
"edit_date_time_dialog_date_time": "Дата и время",
|
||||||
"edit_date_time_dialog_timezone": "Timezone",
|
"edit_date_time_dialog_timezone": "Часовой пояс",
|
||||||
"edit_location_dialog_title": "Location",
|
"edit_location_dialog_title": "Местоположение",
|
||||||
"exif_bottom_sheet_description": "Добавить описание...",
|
"exif_bottom_sheet_description": "Добавить описание...",
|
||||||
"exif_bottom_sheet_details": "ПОДРОБНОСТИ",
|
"exif_bottom_sheet_details": "ПОДРОБНОСТИ",
|
||||||
"exif_bottom_sheet_location": "МЕСТОПОЛОЖЕНИЕ",
|
"exif_bottom_sheet_location": "Местоположение",
|
||||||
"exif_bottom_sheet_location_add": "Добавить местоположение",
|
"exif_bottom_sheet_location_add": "Добавить местоположение",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Ведутся работы",
|
"experimental_settings_new_asset_list_subtitle": "Ведутся работы",
|
||||||
"experimental_settings_new_asset_list_title": "Включить экспериментальную сетку фотографий",
|
"experimental_settings_new_asset_list_title": "Включить экспериментальную сетку фотографий",
|
||||||
"experimental_settings_subtitle": "Используйте на свой страх и риск!",
|
"experimental_settings_subtitle": "Используйте на свой страх и риск!",
|
||||||
@ -194,39 +195,39 @@
|
|||||||
"home_page_add_to_album_conflicts": "Добавлено {added} объектов в альбом {album}. Объекты {failed} уже есть в альбоме.",
|
"home_page_add_to_album_conflicts": "Добавлено {added} объектов в альбом {album}. Объекты {failed} уже есть в альбоме.",
|
||||||
"home_page_add_to_album_err_local": "Пока нельзя добавлять локальные объекты в альбомы, пропускаем",
|
"home_page_add_to_album_err_local": "Пока нельзя добавлять локальные объекты в альбомы, пропускаем",
|
||||||
"home_page_add_to_album_success": "Добавлено {added} объектов в альбом {album}.",
|
"home_page_add_to_album_success": "Добавлено {added} объектов в альбом {album}.",
|
||||||
"home_page_album_err_partner": "Пока не удается добавить партнерские активы в альбом, пропуск...",
|
"home_page_album_err_partner": "Пока не удается добавить объекты партнера в альбом, пропуск...",
|
||||||
"home_page_archive_err_local": "Пока невозможно добавить локальные объекты в архив, пропускаем",
|
"home_page_archive_err_local": "Пока невозможно добавить локальные объекты в архив, пропускаем",
|
||||||
"home_page_archive_err_partner": "Невозможно архивировать активы партнеров, пропуск...",
|
"home_page_archive_err_partner": "Невозможно архивировать объекты партнера, пропуск...",
|
||||||
"home_page_building_timeline": "Построение временной шкалы",
|
"home_page_building_timeline": "Построение временной шкалы",
|
||||||
"home_page_delete_err_partner": "Невозможно удалить активы партнера, пропуск...",
|
"home_page_delete_err_partner": "Невозможно удалить объекты партнера, пропуск...",
|
||||||
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
"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_share_err_local": "Невозможно поделиться локальными данными по ссылке, пропуск...",
|
"home_page_share_err_local": "Невозможно поделиться локальными данными по ссылке, пропуск...",
|
||||||
"home_page_upload_err_limit": "Вы можете выгрузить максимум 30 файлов за раз",
|
"home_page_upload_err_limit": "Вы можете выгрузить максимум 30 файлов за раз",
|
||||||
"image_viewer_page_state_provider_download_error": "Ошибка загрузки",
|
"image_viewer_page_state_provider_download_error": "Ошибка загрузки",
|
||||||
"image_viewer_page_state_provider_download_success": "Успешно загружено",
|
"image_viewer_page_state_provider_download_success": "Успешно загружено",
|
||||||
"image_viewer_page_state_provider_share_error": "Ошибка при публикации",
|
"image_viewer_page_state_provider_share_error": "Ошибка общего доступа",
|
||||||
"library_page_albums": "Альбомы",
|
"library_page_albums": "Альбомы",
|
||||||
"library_page_archive": "Архив",
|
"library_page_archive": "Архив",
|
||||||
"library_page_device_albums": "Альбомы на устройстве",
|
"library_page_device_albums": "Альбомы на устройстве",
|
||||||
"library_page_favorites": "Избранное",
|
"library_page_favorites": "Избранное",
|
||||||
"library_page_new_album": "Новый альбом",
|
"library_page_new_album": "Новый альбом",
|
||||||
"library_page_sharing": "Общие",
|
"library_page_sharing": "Общие",
|
||||||
"library_page_sort_asset_count": "Number of assets",
|
"library_page_sort_asset_count": "Количество объектов",
|
||||||
"library_page_sort_created": "По новизне",
|
"library_page_sort_created": "Недавно созданные",
|
||||||
"library_page_sort_last_modified": "Последнее изменение",
|
"library_page_sort_last_modified": "Последнее изменение",
|
||||||
"library_page_sort_most_oldest_photo": "Oldest photo",
|
"library_page_sort_most_oldest_photo": "Самые старые фото",
|
||||||
"library_page_sort_most_recent_photo": "Последняя фотография",
|
"library_page_sort_most_recent_photo": "Самые последние фото",
|
||||||
"library_page_sort_title": "По названию альбома",
|
"library_page_sort_title": "Название альбома",
|
||||||
"location_picker_choose_on_map": "Choose on map",
|
"location_picker_choose_on_map": "Выбрать на карте",
|
||||||
"location_picker_latitude": "Latitude",
|
"location_picker_latitude": "Широта",
|
||||||
"location_picker_latitude_error": "Enter a valid latitude",
|
"location_picker_latitude_error": "Укажите правильную широту",
|
||||||
"location_picker_latitude_hint": "Enter your latitude here",
|
"location_picker_latitude_hint": "Укажите широту",
|
||||||
"location_picker_longitude": "Longitude",
|
"location_picker_longitude": "Долгота",
|
||||||
"location_picker_longitude_error": "Enter a valid longitude",
|
"location_picker_longitude_error": "Укажите правильную долготу",
|
||||||
"location_picker_longitude_hint": "Enter your longitude here",
|
"location_picker_longitude_hint": "Укажите долготу",
|
||||||
"login_disabled": "Вход отключен",
|
"login_disabled": "Вход отключен",
|
||||||
"login_form_api_exception": "Ошибка при попытке взаимодействия с сервером. Проверьте URL-адрес до него и попробуйте еще раз.",
|
"login_form_api_exception": "Ошибка при попытке взаимодействия с сервером. Проверьте URL-адрес до него и попробуйте еще раз.",
|
||||||
"login_form_back_button_text": "Назад",
|
"login_form_back_button_text": "Назад",
|
||||||
@ -252,35 +253,35 @@
|
|||||||
"login_form_server_error": "Нет соединения с сервером.",
|
"login_form_server_error": "Нет соединения с сервером.",
|
||||||
"login_password_changed_error": "Произошла ошибка при обновлении пароля",
|
"login_password_changed_error": "Произошла ошибка при обновлении пароля",
|
||||||
"login_password_changed_success": "Пароль успешно обновлен",
|
"login_password_changed_success": "Пароль успешно обновлен",
|
||||||
"map_assets_in_bound": "{} photo",
|
"map_assets_in_bound": "{} фото",
|
||||||
"map_assets_in_bounds": "{} photos",
|
"map_assets_in_bounds": "{} фото",
|
||||||
"map_cannot_get_user_location": "Невозможно получить местоположение пользователя",
|
"map_cannot_get_user_location": "Невозможно получить местоположение пользователя",
|
||||||
"map_location_dialog_cancel": "Отмена",
|
"map_location_dialog_cancel": "Отмена",
|
||||||
"map_location_dialog_yes": "Да",
|
"map_location_dialog_yes": "Да",
|
||||||
"map_location_picker_page_use_location": "Use this 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_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_dark_mode": "Темный режим",
|
"map_settings_dark_mode": "Темный режим",
|
||||||
"map_settings_date_range_option_all": "All",
|
"map_settings_date_range_option_all": "Все",
|
||||||
"map_settings_date_range_option_day": "Past 24 hours",
|
"map_settings_date_range_option_day": "Прошлые 24 часа",
|
||||||
"map_settings_date_range_option_days": "Past {} days",
|
"map_settings_date_range_option_days": "Прошлые {} дней",
|
||||||
"map_settings_date_range_option_year": "Past year",
|
"map_settings_date_range_option_year": "Прошлый год",
|
||||||
"map_settings_date_range_option_years": "Past {} years",
|
"map_settings_date_range_option_years": "Прошлые {} года",
|
||||||
"map_settings_dialog_cancel": "Отмена",
|
"map_settings_dialog_cancel": "Отмена",
|
||||||
"map_settings_dialog_save": "Сохранить",
|
"map_settings_dialog_save": "Сохранить",
|
||||||
"map_settings_dialog_title": "Настройки карты",
|
"map_settings_dialog_title": "Настройки карты",
|
||||||
"map_settings_include_show_archived": "Включить архивные данные",
|
"map_settings_include_show_archived": "Включить архивные данные",
|
||||||
"map_settings_only_relative_range": "Период времени",
|
"map_settings_only_relative_range": "Период времени",
|
||||||
"map_settings_only_show_favorites": "Показать только избранное",
|
"map_settings_only_show_favorites": "Показать только избранное",
|
||||||
"map_settings_theme_settings": "Map Theme",
|
"map_settings_theme_settings": "Тема карты",
|
||||||
"map_zoom_to_see_photos": "Уменьшение масштаба для просмотра фотографий",
|
"map_zoom_to_see_photos": "Уменьшение масштаба для просмотра фотографий",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Динамические фото",
|
"motion_photos_page_title": "Динамические фото",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Невозможно редактировать дату объектов только для чтения, пропуск...",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
"multiselect_grid_edit_gps_err_read_only": "Невозможно редактировать местоположение объектов только для чтения, пропуск...",
|
||||||
"notification_permission_dialog_cancel": "Отмена",
|
"notification_permission_dialog_cancel": "Отмена",
|
||||||
"notification_permission_dialog_content": "Чтобы включить уведомления, перейдите в «Настройки» и выберите «Разрешить».",
|
"notification_permission_dialog_content": "Чтобы включить уведомления, перейдите в «Настройки» и выберите «Разрешить».",
|
||||||
"notification_permission_dialog_settings": "Настройки",
|
"notification_permission_dialog_settings": "Настройки",
|
||||||
@ -318,7 +319,7 @@
|
|||||||
"profile_drawer_sign_out": "Выйти",
|
"profile_drawer_sign_out": "Выйти",
|
||||||
"profile_drawer_trash": "Корзина",
|
"profile_drawer_trash": "Корзина",
|
||||||
"recently_added_page_title": "Недавно добавленные",
|
"recently_added_page_title": "Недавно добавленные",
|
||||||
"scaffold_body_error_occurred": "Error occurred",
|
"scaffold_body_error_occurred": "Возникла ошибка",
|
||||||
"search_bar_hint": "Поиск фотографий",
|
"search_bar_hint": "Поиск фотографий",
|
||||||
"search_page_categories": "Категории",
|
"search_page_categories": "Категории",
|
||||||
"search_page_favorites": "Избранное",
|
"search_page_favorites": "Избранное",
|
||||||
@ -332,31 +333,31 @@
|
|||||||
"search_page_person_add_name_dialog_title": "Добавить имя",
|
"search_page_person_add_name_dialog_title": "Добавить имя",
|
||||||
"search_page_person_add_name_subtitle": "Быстро найдите их по имени с помощью поиска",
|
"search_page_person_add_name_subtitle": "Быстро найдите их по имени с помощью поиска",
|
||||||
"search_page_person_add_name_title": "Добавить имя",
|
"search_page_person_add_name_title": "Добавить имя",
|
||||||
"search_page_person_edit_name": "Изменить имя",
|
"search_page_person_edit_name": "Редактировать имя",
|
||||||
"search_page_places": "Места",
|
"search_page_places": "Места",
|
||||||
"search_page_recently_added": "Недавно добавленные",
|
"search_page_recently_added": "Недавно добавленные",
|
||||||
"search_page_screenshots": "Скриншоты",
|
"search_page_screenshots": "Снимки экрана",
|
||||||
"search_page_selfies": "Селфи",
|
"search_page_selfies": "Селфи",
|
||||||
"search_page_things": "Предметы",
|
"search_page_things": "Предметы",
|
||||||
"search_page_videos": "Видео",
|
"search_page_videos": "Видео",
|
||||||
"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_result_page_new_search_hint": "Новый поиск",
|
"search_result_page_new_search_hint": "Новый поиск",
|
||||||
"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:ваш-поисковый-запрос",
|
||||||
"select_additional_user_for_sharing_page_suggestions": "Предложения",
|
"select_additional_user_for_sharing_page_suggestions": "Предложения",
|
||||||
"select_user_for_sharing_page_err_album": "\nНе удалось создать альбом",
|
"select_user_for_sharing_page_err_album": "Не удалось создать альбом",
|
||||||
"select_user_for_sharing_page_share_suggestions": "Предложения",
|
"select_user_for_sharing_page_share_suggestions": "Предложения",
|
||||||
"server_info_box_app_version": "Версия приложения",
|
"server_info_box_app_version": "Версия приложения",
|
||||||
"server_info_box_latest_release": "Крайняя версия",
|
"server_info_box_latest_release": "Последняя версия",
|
||||||
"server_info_box_server_url": "URL сервера",
|
"server_info_box_server_url": "URL сервера",
|
||||||
"server_info_box_server_version": "Версия сервера",
|
"server_info_box_server_version": "Версия сервера",
|
||||||
"setting_image_viewer_help": "Средство просмотра деталей сначала загружает маленькую миниатюру, затем загружает предварительный просмотр среднего размера (если включено) и, наконец, загружает оригинал (если включено).",
|
"setting_image_viewer_help": "Полноэкранный просмотрщик сначала загружает изображение для предпросмотра в низком разрешении, затем загружает изображение в уменьшенном разрешении относительно оригинала (если включено) и в конце концов загружает оригинал (если включено).",
|
||||||
"setting_image_viewer_original_subtitle": "Включите загрузку оригинального изображения в полном разрешении (большое!). Отключите, чтобы уменьшить объем данных (как в сети, так и в кеше устройства).",
|
"setting_image_viewer_original_subtitle": "Включите для загрузки исходного изображения в полном разрешении (большое!).\nОтключите, чтобы уменьшить объем данных (как сети, так и кэша устройства).",
|
||||||
"setting_image_viewer_original_title": "Загрузить исходное изображение",
|
"setting_image_viewer_original_title": "Загружать исходное изображение",
|
||||||
"setting_image_viewer_preview_subtitle": "Включите загрузку изображения среднего разрешения. Отключите, чтобы загрузить оригинал напрямую или использовать только миниатюру.",
|
"setting_image_viewer_preview_subtitle": "Включите для загрузки изображения среднего разрешения.\nОтключите, чтобы загружать оригинал напрямую или использовать только миниатюру.",
|
||||||
"setting_image_viewer_preview_title": "Загрузить изображение для предварительного просмотра",
|
"setting_image_viewer_preview_title": "Загружать изображение для предварительного просмотра",
|
||||||
"setting_notifications_notify_failures_grace_period": "Уведомлять об ошибках фонового резервного копирования: {}",
|
"setting_notifications_notify_failures_grace_period": "Уведомлять об ошибках фонового резервного копирования: {}",
|
||||||
"setting_notifications_notify_hours": "{} часов",
|
"setting_notifications_notify_hours": "{} часов",
|
||||||
"setting_notifications_notify_immediately": "немедленно",
|
"setting_notifications_notify_immediately": "немедленно",
|
||||||
@ -365,7 +366,7 @@
|
|||||||
"setting_notifications_notify_seconds": "{} секунд",
|
"setting_notifications_notify_seconds": "{} секунд",
|
||||||
"setting_notifications_single_progress_subtitle": "Подробная информация о ходе загрузки для каждого объекта",
|
"setting_notifications_single_progress_subtitle": "Подробная информация о ходе загрузки для каждого объекта",
|
||||||
"setting_notifications_single_progress_title": "Показать ход выполнения фонового резервного копирования",
|
"setting_notifications_single_progress_title": "Показать ход выполнения фонового резервного копирования",
|
||||||
"setting_notifications_subtitle": "Настроить параметры уведомлений",
|
"setting_notifications_subtitle": "Настройка параметров уведомлени",
|
||||||
"setting_notifications_title": "Уведомления",
|
"setting_notifications_title": "Уведомления",
|
||||||
"setting_notifications_total_progress_subtitle": "Общий прогресс загрузки (выполнено/всего объектов)",
|
"setting_notifications_total_progress_subtitle": "Общий прогресс загрузки (выполнено/всего объектов)",
|
||||||
"setting_notifications_total_progress_title": "Показать общий прогресс фонового резервного копирования",
|
"setting_notifications_total_progress_title": "Показать общий прогресс фонового резервного копирования",
|
||||||
@ -375,61 +376,61 @@
|
|||||||
"share_add_photos": "Добавить фото",
|
"share_add_photos": "Добавить фото",
|
||||||
"share_add_title": "Добавить название",
|
"share_add_title": "Добавить название",
|
||||||
"share_create_album": "Создать альбом",
|
"share_create_album": "Создать альбом",
|
||||||
"shared_album_activities_input_disable": "Комментарий отключен",
|
"shared_album_activities_input_disable": "Комментирование отключено",
|
||||||
"shared_album_activities_input_hint": "Скажите что-нибудь",
|
"shared_album_activities_input_hint": "Скажите что-нибудь",
|
||||||
"shared_album_activity_remove_content": "Хотите ли Вы удалить это действие?",
|
"shared_album_activity_remove_content": "Хотите ли Вы удалить это сообщение?",
|
||||||
"shared_album_activity_remove_title": "Удалить действие",
|
"shared_album_activity_remove_title": "Удалить сообщение",
|
||||||
"shared_album_activity_setting_subtitle": "Предоставьте другим возможность отвечать",
|
"shared_album_activity_setting_subtitle": "Разрешить другим отвечат",
|
||||||
"shared_album_activity_setting_title": "Комментарии и лайки",
|
"shared_album_activity_setting_title": "Комментарии и лайки",
|
||||||
"shared_album_section_people_action_error": "Error leaving/removing from album",
|
"shared_album_section_people_action_error": "Ошибка при выходе/удалении из альбома",
|
||||||
"shared_album_section_people_action_leave": "Удалить пользователя из альбома",
|
"shared_album_section_people_action_leave": "Удалить пользователя из альбома",
|
||||||
"shared_album_section_people_action_remove_user": "Удалить пользователя из альбома",
|
"shared_album_section_people_action_remove_user": "Удалить пользователя из альбома",
|
||||||
"shared_album_section_people_owner_label": "Owner",
|
"shared_album_section_people_owner_label": "Владелец",
|
||||||
"shared_album_section_people_title": "PEOPLE",
|
"shared_album_section_people_title": "ЛЮДИ",
|
||||||
"share_dialog_preparing": "Подготовка...",
|
"share_dialog_preparing": "Подготовка...",
|
||||||
"shared_link_app_bar_title": "Общие ссылки",
|
"shared_link_app_bar_title": "Общие ссылки",
|
||||||
"shared_link_clipboard_copied_massage": "Скопировано в буфер обмена",
|
"shared_link_clipboard_copied_massage": "Скопировано в буфер обмена",
|
||||||
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
"shared_link_clipboard_text": "Ссылка: {}\nПароль: {}",
|
||||||
"shared_link_create_app_bar_title": "Создать ссылку для совместного использования",
|
"shared_link_create_app_bar_title": "Создать ссылку общего доступа",
|
||||||
"shared_link_create_error": "Error while creating shared link",
|
"shared_link_create_error": "Ошибка при создании общей ссылки",
|
||||||
"shared_link_create_info": "Позволить любому человеку, имеющему ссылку, увидеть выбранную фотографию (фотографии)",
|
"shared_link_create_info": "Разрешить всем, у кого есть ссылка, просматривать выбранные фото",
|
||||||
"shared_link_create_submit_button": "Создать ссылку",
|
"shared_link_create_submit_button": "Создать ссылку",
|
||||||
"shared_link_edit_allow_download": "Разрешить публичному пользователю скачивать",
|
"shared_link_edit_allow_download": "Разрешить публичному пользователю скачивать файлы",
|
||||||
"shared_link_edit_allow_upload": "Разрешить публичному пользователю загружать файлы",
|
"shared_link_edit_allow_upload": "Разрешить публичному пользователю загружать файлы",
|
||||||
"shared_link_edit_app_bar_title": "Редактировать ссылку",
|
"shared_link_edit_app_bar_title": "Редактировать ссылку",
|
||||||
"shared_link_edit_change_expiry": "Изменить срок действия доступа",
|
"shared_link_edit_change_expiry": "Изменить срок действия доступа",
|
||||||
"shared_link_edit_description": "Описание",
|
"shared_link_edit_description": "Описание",
|
||||||
"shared_link_edit_description_hint": "Введите описание совместного доступа",
|
"shared_link_edit_description_hint": "Введите описание для общего доступа",
|
||||||
"shared_link_edit_expire_after": "Истекает после",
|
"shared_link_edit_expire_after": "Истекает через",
|
||||||
"shared_link_edit_expire_after_option_day": "1 day",
|
"shared_link_edit_expire_after_option_day": "1 день",
|
||||||
"shared_link_edit_expire_after_option_days": "{} days",
|
"shared_link_edit_expire_after_option_days": "{} дней",
|
||||||
"shared_link_edit_expire_after_option_hour": "1 hour",
|
"shared_link_edit_expire_after_option_hour": "1 час",
|
||||||
"shared_link_edit_expire_after_option_hours": "{} hours",
|
"shared_link_edit_expire_after_option_hours": "{} часов",
|
||||||
"shared_link_edit_expire_after_option_minute": "1 minute",
|
"shared_link_edit_expire_after_option_minute": "1 минуту",
|
||||||
"shared_link_edit_expire_after_option_minutes": "{} minutes",
|
"shared_link_edit_expire_after_option_minutes": "{} минут",
|
||||||
"shared_link_edit_expire_after_option_never": "Никогда",
|
"shared_link_edit_expire_after_option_never": "Никогда",
|
||||||
"shared_link_edit_password": "Пароль",
|
"shared_link_edit_password": "Пароль",
|
||||||
"shared_link_edit_password_hint": "Введите пароль общего доступа",
|
"shared_link_edit_password_hint": "Введите пароль для общего доступа",
|
||||||
"shared_link_edit_show_meta": "Показать метаданные",
|
"shared_link_edit_show_meta": "Показывать метаданные",
|
||||||
"shared_link_edit_submit_button": "Обновить ссылку",
|
"shared_link_edit_submit_button": "Обновить ссылку",
|
||||||
"shared_link_empty": "У вас нет общих ссылок",
|
"shared_link_empty": "У вас нет общих ссылок",
|
||||||
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
"shared_link_error_server_url_fetch": "Невозможно запросить URL с сервера",
|
||||||
"shared_link_expired": "Expired",
|
"shared_link_expired": "Срок действия истек",
|
||||||
"shared_link_expires_day": "Expires in {} day",
|
"shared_link_expires_day": "Истекает через {} день",
|
||||||
"shared_link_expires_days": "Expires in {} days",
|
"shared_link_expires_days": "Истекает через {} дней",
|
||||||
"shared_link_expires_hour": "Expires in {} hour",
|
"shared_link_expires_hour": "Истекает через {} час",
|
||||||
"shared_link_expires_hours": "Expires in {} hours",
|
"shared_link_expires_hours": "Истекает через {} часов",
|
||||||
"shared_link_expires_minute": "Expires in {} minute",
|
"shared_link_expires_minute": "Истекает через {} минуту",
|
||||||
"shared_link_expires_minutes": "Истекает через {} минут",
|
"shared_link_expires_minutes": "Истекает через {} минут",
|
||||||
"shared_link_expires_never": "Expires ∞",
|
"shared_link_expires_never": "Истекает ∞",
|
||||||
"shared_link_expires_second": "Expires in {} second",
|
"shared_link_expires_second": "Истекает через {} секунду",
|
||||||
"shared_link_expires_seconds": "Истекает через {} секунд",
|
"shared_link_expires_seconds": "Истекает через {} секунд",
|
||||||
"shared_link_info_chip_download": "Download",
|
"shared_link_info_chip_download": "Скачать",
|
||||||
"shared_link_info_chip_metadata": "EXIF",
|
"shared_link_info_chip_metadata": "EXIF",
|
||||||
"shared_link_info_chip_upload": "Upload",
|
"shared_link_info_chip_upload": "Загрузить",
|
||||||
"shared_link_manage_links": "Управление общими ссылками",
|
"shared_link_manage_links": "Управление общими ссылками",
|
||||||
"share_done": "Выполнено",
|
"share_done": "Готово",
|
||||||
"share_invite": "\nПригласить в альбом",
|
"share_invite": "Пригласить в альбом",
|
||||||
"sharing_page_album": "Общие альбомы",
|
"sharing_page_album": "Общие альбомы",
|
||||||
"sharing_page_description": "Создавайте общие альбомы, чтобы делиться фотографиями и видео с людьми в вашей сети.",
|
"sharing_page_description": "Создавайте общие альбомы, чтобы делиться фотографиями и видео с людьми в вашей сети.",
|
||||||
"sharing_page_empty_list": "ПУСТОЙ СПИСОК",
|
"sharing_page_empty_list": "ПУСТОЙ СПИСОК",
|
||||||
@ -443,10 +444,10 @@
|
|||||||
"theme_setting_asset_list_storage_indicator_title": "Показать индикатор хранилища на плитках объектов",
|
"theme_setting_asset_list_storage_indicator_title": "Показать индикатор хранилища на плитках объектов",
|
||||||
"theme_setting_asset_list_tiles_per_row_title": "Количество объектов в строке ({})",
|
"theme_setting_asset_list_tiles_per_row_title": "Количество объектов в строке ({})",
|
||||||
"theme_setting_dark_mode_switch": "Тёмная тема",
|
"theme_setting_dark_mode_switch": "Тёмная тема",
|
||||||
"theme_setting_image_viewer_quality_subtitle": "Настройка качества детального просмотра изображения",
|
"theme_setting_image_viewer_quality_subtitle": "Настройка качества просмотра полноэкранных изображения",
|
||||||
"theme_setting_image_viewer_quality_title": "Качество просмотра изображений",
|
"theme_setting_image_viewer_quality_title": "Качество просмотра изображений",
|
||||||
"theme_setting_system_theme_switch": "Автоматически (Как в системе)",
|
"theme_setting_system_theme_switch": "Автоматически (как в системе)",
|
||||||
"theme_setting_theme_subtitle": "Выберите настройки темы приложения",
|
"theme_setting_theme_subtitle": "Настройка темы приложения",
|
||||||
"theme_setting_theme_title": "Тема",
|
"theme_setting_theme_title": "Тема",
|
||||||
"theme_setting_three_stage_loading_subtitle": "Трехэтапная загрузка может повысить производительность загрузки, но вызывает значительно более высокую нагрузку на сеть",
|
"theme_setting_three_stage_loading_subtitle": "Трехэтапная загрузка может повысить производительность загрузки, но вызывает значительно более высокую нагрузку на сеть",
|
||||||
"theme_setting_three_stage_loading_title": "Включить трехэтапную загрузку",
|
"theme_setting_three_stage_loading_title": "Включить трехэтапную загрузку",
|
||||||
@ -454,10 +455,10 @@
|
|||||||
"trash_page_delete": "Удалить",
|
"trash_page_delete": "Удалить",
|
||||||
"trash_page_delete_all": "Удалить все",
|
"trash_page_delete_all": "Удалить все",
|
||||||
"trash_page_empty_trash_btn": "Очистить корзину",
|
"trash_page_empty_trash_btn": "Очистить корзину",
|
||||||
"trash_page_empty_trash_dialog_content": "Вы хотите очистить свою корзину? Эти объекты будут навсегда удалены из Immich",
|
"trash_page_empty_trash_dialog_content": "Вы хотите очистить свою корзину? Эти объекты будут навсегда удалены из Immich.",
|
||||||
"trash_page_empty_trash_dialog_ok": "ОК",
|
"trash_page_empty_trash_dialog_ok": "ОК",
|
||||||
"trash_page_info": "Удаленные элементы будут окончательно удалены через {} дней",
|
"trash_page_info": "Удаленные элементы будут окончательно удалены через {} дней",
|
||||||
"trash_page_no_assets": "Отсутствие удаленных объектов",
|
"trash_page_no_assets": "Удаленные объекты отсутсвуют",
|
||||||
"trash_page_restore": "Восстановить",
|
"trash_page_restore": "Восстановить",
|
||||||
"trash_page_restore_all": "Восстановить все",
|
"trash_page_restore_all": "Восстановить все",
|
||||||
"trash_page_select_assets_btn": "Выбранные объекты",
|
"trash_page_select_assets_btn": "Выбранные объекты",
|
||||||
@ -474,6 +475,6 @@
|
|||||||
"version_announcement_overlay_text_3": " и убедитесь, что ваши настройки docker-compose и .env обновлены, чтобы предотвратить любые неправильные настройки, особенно если вы используете WatchTower или любой другой механизм, который обрабатывает обновление вашего серверного приложения автоматически.",
|
"version_announcement_overlay_text_3": " и убедитесь, что ваши настройки docker-compose и .env обновлены, чтобы предотвратить любые неправильные настройки, особенно если вы используете WatchTower или любой другой механизм, который обрабатывает обновление вашего серверного приложения автоматически.",
|
||||||
"version_announcement_overlay_title": "Доступна новая версия сервера \uD83C\uDF89",
|
"version_announcement_overlay_title": "Доступна новая версия сервера \uD83C\uDF89",
|
||||||
"viewer_remove_from_stack": "Удалить из стека",
|
"viewer_remove_from_stack": "Удалить из стека",
|
||||||
"viewer_stack_use_as_main_asset": "Использование в качестве основного объекта",
|
"viewer_stack_use_as_main_asset": "Использовать в качестве основного объекта",
|
||||||
"viewer_unstack": "Разобрать стек"
|
"viewer_unstack": "Разобрать стек"
|
||||||
}
|
}
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "PODROBNOSTI",
|
"exif_bottom_sheet_details": "PODROBNOSTI",
|
||||||
"exif_bottom_sheet_location": "LOKALITA",
|
"exif_bottom_sheet_location": "LOKALITA",
|
||||||
"exif_bottom_sheet_location_add": "Nastaviť polohu",
|
"exif_bottom_sheet_location_add": "Nastaviť polohu",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Prebiehajúca práca",
|
"experimental_settings_new_asset_list_subtitle": "Prebiehajúca práca",
|
||||||
"experimental_settings_new_asset_list_title": "Povolenie experimentálnej mriežky fotografií",
|
"experimental_settings_new_asset_list_title": "Povolenie experimentálnej mriežky fotografií",
|
||||||
"experimental_settings_subtitle": "Používajte na vlastné riziko!",
|
"experimental_settings_subtitle": "Používajte na vlastné riziko!",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETAILS",
|
"exif_bottom_sheet_details": "DETAILS",
|
||||||
"exif_bottom_sheet_location": "LOCATION",
|
"exif_bottom_sheet_location": "LOCATION",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
||||||
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||||
"experimental_settings_subtitle": "Use at your own risk!",
|
"experimental_settings_subtitle": "Use at your own risk!",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETALJI",
|
"exif_bottom_sheet_details": "DETALJI",
|
||||||
"exif_bottom_sheet_location": "LOKACIJA",
|
"exif_bottom_sheet_location": "LOKACIJA",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "U izradi",
|
"experimental_settings_new_asset_list_subtitle": "U izradi",
|
||||||
"experimental_settings_new_asset_list_title": "Aktiviraj eksperimentalni mrežni prikaz fotografija",
|
"experimental_settings_new_asset_list_title": "Aktiviraj eksperimentalni mrežni prikaz fotografija",
|
||||||
"experimental_settings_subtitle": "Koristiti na sopstvenu odgovornost!",
|
"experimental_settings_subtitle": "Koristiti na sopstvenu odgovornost!",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETAILS",
|
"exif_bottom_sheet_details": "DETAILS",
|
||||||
"exif_bottom_sheet_location": "LOCATION",
|
"exif_bottom_sheet_location": "LOCATION",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
||||||
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||||
"experimental_settings_subtitle": "Use at your own risk!",
|
"experimental_settings_subtitle": "Use at your own risk!",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "DETALJER",
|
"exif_bottom_sheet_details": "DETALJER",
|
||||||
"exif_bottom_sheet_location": "PLATS",
|
"exif_bottom_sheet_location": "PLATS",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Under uppbyggnad",
|
"experimental_settings_new_asset_list_subtitle": "Under uppbyggnad",
|
||||||
"experimental_settings_new_asset_list_title": "Aktivera experimentellt fotorutnät",
|
"experimental_settings_new_asset_list_title": "Aktivera experimentellt fotorutnät",
|
||||||
"experimental_settings_subtitle": "Använd på egen risk!",
|
"experimental_settings_subtitle": "Använd på egen risk!",
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "รายละเอียด",
|
"exif_bottom_sheet_details": "รายละเอียด",
|
||||||
"exif_bottom_sheet_location": "ตำแหน่ง",
|
"exif_bottom_sheet_location": "ตำแหน่ง",
|
||||||
"exif_bottom_sheet_location_add": "เพิ่มตำแหน่ง",
|
"exif_bottom_sheet_location_add": "เพิ่มตำแหน่ง",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "กำลังพัฒนา",
|
"experimental_settings_new_asset_list_subtitle": "กำลังพัฒนา",
|
||||||
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||||
"experimental_settings_subtitle": "Use at your own risk!",
|
"experimental_settings_subtitle": "Use at your own risk!",
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"action_common_cancel": "Cancel",
|
"action_common_cancel": "Скасувати",
|
||||||
"action_common_update": "Update",
|
"action_common_update": "Оновити",
|
||||||
"add_to_album_bottom_sheet_added": "Додати до {album}",
|
"add_to_album_bottom_sheet_added": "Додати до {album}",
|
||||||
"add_to_album_bottom_sheet_already_exists": "Вже є в {album}",
|
"add_to_album_bottom_sheet_already_exists": "Вже є в {album}",
|
||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Деякі пристрої вельми повільно завантажують мініатюри із елементів на пристрої. Активуйте для завантаження віддалених мініатюр натомість.",
|
"advanced_settings_prefer_remote_subtitle": "Деякі пристрої вельми повільно завантажують мініатюри із елементів на пристрої. Активуйте для завантаження віддалених мініатюр натомість.",
|
||||||
"advanced_settings_prefer_remote_title": "Перевага віддаленим зображенням",
|
"advanced_settings_prefer_remote_title": "Перевага віддаленим зображенням",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Пропускає SSL-сертифікат для точки доступу сервера. Потрібне для власноруч підписаних сертифікатів.",
|
"advanced_settings_self_signed_ssl_subtitle": "Пропускає перевірку SSL-сертифіката сервера. Потрібне для самопідписаних сертифікатів.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Дозволити власноруч підписані SSL-сертифікати",
|
"advanced_settings_self_signed_ssl_title": "Дозволити самопідписані SSL-сертифікати",
|
||||||
"advanced_settings_tile_subtitle": "Розширені користувацькі налаштування",
|
"advanced_settings_tile_subtitle": "Розширені користувацькі налаштування",
|
||||||
"advanced_settings_tile_title": "Розширені",
|
"advanced_settings_tile_title": "Розширені",
|
||||||
"advanced_settings_troubleshooting_subtitle": "Увімкніть додаткові функції для усунення несправностей",
|
"advanced_settings_troubleshooting_subtitle": "Увімкніть додаткові функції для усунення несправностей",
|
||||||
@ -26,17 +26,17 @@
|
|||||||
"album_viewer_appbar_share_err_title": "Не вдалося змінити назву альбому",
|
"album_viewer_appbar_share_err_title": "Не вдалося змінити назву альбому",
|
||||||
"album_viewer_appbar_share_leave": "Вийти з альбому",
|
"album_viewer_appbar_share_leave": "Вийти з альбому",
|
||||||
"album_viewer_appbar_share_remove": "Видалити з альбому",
|
"album_viewer_appbar_share_remove": "Видалити з альбому",
|
||||||
"album_viewer_appbar_share_to": "Share To",
|
"album_viewer_appbar_share_to": "Поділитися",
|
||||||
"album_viewer_page_share_add_users": "Додати користувачів",
|
"album_viewer_page_share_add_users": "Додати користувачів",
|
||||||
"all_people_page_title": "Люди",
|
"all_people_page_title": "Люди",
|
||||||
"all_videos_page_title": "Відео",
|
"all_videos_page_title": "Відео",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
"app_bar_signout_dialog_content": "Ви впевнені, що бажаєте вийти з аккаунта?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Так",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Вийти з аккаунта",
|
||||||
"archive_page_no_archived_assets": "Немає архівних елементів",
|
"archive_page_no_archived_assets": "Немає архівних елементів",
|
||||||
"archive_page_title": "Архів ({})",
|
"archive_page_title": "Архів ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "Неможливо видалити елемент(и) лише для читання, пропущено",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "Неможливо отримати оффлайн-елемент(и), пропущено",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Динамічне компонування",
|
"asset_list_layout_settings_dynamic_layout_title": "Динамічне компонування",
|
||||||
"asset_list_layout_settings_group_automatically": "Автоматично",
|
"asset_list_layout_settings_group_automatically": "Автоматично",
|
||||||
"asset_list_layout_settings_group_by": "Групувати елементи по",
|
"asset_list_layout_settings_group_by": "Групувати елементи по",
|
||||||
@ -50,7 +50,7 @@
|
|||||||
"backup_album_selection_page_select_albums": "Оберіть альбоми",
|
"backup_album_selection_page_select_albums": "Оберіть альбоми",
|
||||||
"backup_album_selection_page_selection_info": "Інформація про обране",
|
"backup_album_selection_page_selection_info": "Інформація про обране",
|
||||||
"backup_album_selection_page_total_assets": "Загальна кількість унікальних елементів",
|
"backup_album_selection_page_total_assets": "Загальна кількість унікальних елементів",
|
||||||
"backup_all": "Все",
|
"backup_all": "Усі",
|
||||||
"backup_background_service_backup_failed_message": "Не вдалося зробити резервну копію елементів. Повторюю...",
|
"backup_background_service_backup_failed_message": "Не вдалося зробити резервну копію елементів. Повторюю...",
|
||||||
"backup_background_service_connection_failed_message": "Не вдалося зв'язатися із сервером. Повторюю...",
|
"backup_background_service_connection_failed_message": "Не вдалося зв'язатися із сервером. Повторюю...",
|
||||||
"backup_background_service_current_upload_notification": "Завантажується {}",
|
"backup_background_service_current_upload_notification": "Завантажується {}",
|
||||||
@ -65,7 +65,7 @@
|
|||||||
"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": "Лише під час заряджання",
|
||||||
"backup_controller_page_background_configure_error": "Не вдалося налаштувати фоновий сервіс",
|
"backup_controller_page_background_configure_error": "Не вдалося налаштувати фоновий сервіс",
|
||||||
"backup_controller_page_background_delay": "Затримка перед резервним копіюванням нових елементів: {}",
|
"backup_controller_page_background_delay": "Затримка перед резервним копіюванням нових елементів: {}",
|
||||||
@ -111,9 +111,9 @@
|
|||||||
"cache_settings_album_thumbnails": "Мініатюри сторінок бібліотеки ({} елементи)",
|
"cache_settings_album_thumbnails": "Мініатюри сторінок бібліотеки ({} елементи)",
|
||||||
"cache_settings_clear_cache_button": "Очистити кеш",
|
"cache_settings_clear_cache_button": "Очистити кеш",
|
||||||
"cache_settings_clear_cache_button_title": "Очищає кеш програми. Це суттєво знизить продуктивність програми, доки кеш не буде перебудовано.",
|
"cache_settings_clear_cache_button_title": "Очищає кеш програми. Це суттєво знизить продуктивність програми, доки кеш не буде перебудовано.",
|
||||||
"cache_settings_duplicated_assets_clear_button": "CLEAR",
|
"cache_settings_duplicated_assets_clear_button": "ОЧИСТИТИ",
|
||||||
"cache_settings_duplicated_assets_subtitle": "Photos and videos that are black listed by the app",
|
"cache_settings_duplicated_assets_subtitle": "Фото та відео, занесені додатком у чорний список",
|
||||||
"cache_settings_duplicated_assets_title": "Duplicated Assets ({})",
|
"cache_settings_duplicated_assets_title": "Дубльовані елементи ({})",
|
||||||
"cache_settings_image_cache_size": "Розмір кешованих зображень ({} елементи)",
|
"cache_settings_image_cache_size": "Розмір кешованих зображень ({} елементи)",
|
||||||
"cache_settings_statistics_album": "Бібліотечні мініатюри",
|
"cache_settings_statistics_album": "Бібліотечні мініатюри",
|
||||||
"cache_settings_statistics_assets": "{} елементи ({})",
|
"cache_settings_statistics_assets": "{} елементи ({})",
|
||||||
@ -123,16 +123,16 @@
|
|||||||
"cache_settings_statistics_title": "Використання кешу",
|
"cache_settings_statistics_title": "Використання кешу",
|
||||||
"cache_settings_subtitle": "Контролює кешування у мобільному застосунку",
|
"cache_settings_subtitle": "Контролює кешування у мобільному застосунку",
|
||||||
"cache_settings_thumbnail_size": "Розмір кешованих мініатюр ({} елементи)",
|
"cache_settings_thumbnail_size": "Розмір кешованих мініатюр ({} елементи)",
|
||||||
"cache_settings_tile_subtitle": "Control the local storage behaviour",
|
"cache_settings_tile_subtitle": "Керування поведінкою локального сховища",
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Локальне сховище",
|
||||||
"cache_settings_title": "Налаштування Кешування",
|
"cache_settings_title": "Налаштування кешування",
|
||||||
"change_password_form_confirm_password": "Підтвердити пароль",
|
"change_password_form_confirm_password": "Підтвердити пароль",
|
||||||
"change_password_form_description": "Привіт {name},\n\nВи або або вперше входите у систему, або було зроблено запит на зміну вашого пароля. \nВведіть ваш новий пароль.",
|
"change_password_form_description": "Привіт {name},\n\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": "Повторіть новий пароль",
|
||||||
"common_add_to_album": "Додати в альбом",
|
"common_add_to_album": "Додати в альбом",
|
||||||
"common_change_password": "Змінити Пароль",
|
"common_change_password": "Змінити пароль",
|
||||||
"common_create_new_album": "Створити новий альбом",
|
"common_create_new_album": "Створити новий альбом",
|
||||||
"common_server_error": "Будь ласка, перевірте з'єднання, переконайтеся, що сервер доступний і версія програми/сервера сумісна.",
|
"common_server_error": "Будь ласка, перевірте з'єднання, переконайтеся, що сервер доступний і версія програми/сервера сумісна.",
|
||||||
"common_shared": "Спільні",
|
"common_shared": "Спільні",
|
||||||
@ -142,18 +142,18 @@
|
|||||||
"control_bottom_app_bar_archive": "Архівувати",
|
"control_bottom_app_bar_archive": "Архівувати",
|
||||||
"control_bottom_app_bar_create_new_album": "Створити новий альбом",
|
"control_bottom_app_bar_create_new_album": "Створити новий альбом",
|
||||||
"control_bottom_app_bar_delete": "Видалити",
|
"control_bottom_app_bar_delete": "Видалити",
|
||||||
"control_bottom_app_bar_delete_from_immich": "Delete from Immich",
|
"control_bottom_app_bar_delete_from_immich": "Видалити з Immich",
|
||||||
"control_bottom_app_bar_delete_from_local": "Delete from device",
|
"control_bottom_app_bar_delete_from_local": "Видалити з пристрою",
|
||||||
"control_bottom_app_bar_edit_location": "Edit Location",
|
"control_bottom_app_bar_edit_location": "Редагувати місцезнаходження",
|
||||||
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
"control_bottom_app_bar_edit_time": "Редагувати дату та час",
|
||||||
"control_bottom_app_bar_favorite": "Уподобати",
|
"control_bottom_app_bar_favorite": "До улюблених",
|
||||||
"control_bottom_app_bar_share": "Поділитися",
|
"control_bottom_app_bar_share": "Поділитися",
|
||||||
"control_bottom_app_bar_share_to": "Share To",
|
"control_bottom_app_bar_share_to": "Поділитися",
|
||||||
"control_bottom_app_bar_stack": "Stack",
|
"control_bottom_app_bar_stack": "Стек",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Перемістити до кошику",
|
||||||
"control_bottom_app_bar_unarchive": "Розархівувати",
|
"control_bottom_app_bar_unarchive": "Розархівувати",
|
||||||
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
"control_bottom_app_bar_unfavorite": "Видалити з улюблених",
|
||||||
"control_bottom_app_bar_upload": "Upload",
|
"control_bottom_app_bar_upload": "Завантажити",
|
||||||
"create_album_page_untitled": "Без назви",
|
"create_album_page_untitled": "Без назви",
|
||||||
"create_shared_album_page_create": "Створити",
|
"create_shared_album_page_create": "Створити",
|
||||||
"create_shared_album_page_share": "Поділитися",
|
"create_shared_album_page_share": "Поділитися",
|
||||||
@ -165,26 +165,27 @@
|
|||||||
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
||||||
"date_format": "E, LLL d, y • h:mm a",
|
"date_format": "E, LLL d, y • h:mm a",
|
||||||
"delete_dialog_alert": "Ці елементи будуть остаточно видалені з Immich та вашого пристрою",
|
"delete_dialog_alert": "Ці елементи будуть остаточно видалені з Immich та вашого пристрою",
|
||||||
"delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server",
|
"delete_dialog_alert_local": "Ці елементи будуть видалені видалені з Вашого пристрою, але залишаться доступними на сервері Immich",
|
||||||
"delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device",
|
"delete_dialog_alert_local_non_backed_up": "Резервні копії деяких елементів не були завантажені в Immich і будуть видалені видалені з Вашого пристрою",
|
||||||
"delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server",
|
"delete_dialog_alert_remote": "Ці елементи будуть назавжди видалені з сервера Immich",
|
||||||
"delete_dialog_cancel": "Скасувати",
|
"delete_dialog_cancel": "Скасувати",
|
||||||
"delete_dialog_ok": "Видалити",
|
"delete_dialog_ok": "Видалити",
|
||||||
"delete_dialog_ok_force": "Delete Anyway",
|
"delete_dialog_ok_force": "Все одно видалити",
|
||||||
"delete_dialog_title": "Видалити остаточно",
|
"delete_dialog_title": "Видалити остаточно",
|
||||||
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
|
"delete_local_dialog_ok_backed_up_only": "Видалити лише резервні копії",
|
||||||
"delete_local_dialog_ok_force": "Delete Anyway",
|
"delete_local_dialog_ok_force": "Все одно видалити",
|
||||||
"delete_shared_link_dialog_content": "Are you sure you want to delete this shared link?",
|
"delete_shared_link_dialog_content": "Ви впевнені, що хочете видалити це спільне посилання?",
|
||||||
"delete_shared_link_dialog_title": "Delete Shared Link",
|
"delete_shared_link_dialog_title": "Видалити спільне посилання",
|
||||||
"description_input_hint_text": "Додати опис...",
|
"description_input_hint_text": "Додати опис...",
|
||||||
"description_input_submit_error": "Помилка оновлення опису, перевірте логи для подробиць",
|
"description_input_submit_error": "Помилка оновлення опису, перевірте логи для подробиць",
|
||||||
"edit_date_time_dialog_date_time": "Date and Time",
|
"edit_date_time_dialog_date_time": "Дата і час",
|
||||||
"edit_date_time_dialog_timezone": "Timezone",
|
"edit_date_time_dialog_timezone": "Часовий пояс",
|
||||||
"edit_location_dialog_title": "Location",
|
"edit_location_dialog_title": "Місцезнаходження",
|
||||||
"exif_bottom_sheet_description": "Додати опис...",
|
"exif_bottom_sheet_description": "Додати опис...",
|
||||||
"exif_bottom_sheet_details": "ПОДРОБИЦІ",
|
"exif_bottom_sheet_details": "ПОДРОБИЦІ",
|
||||||
"exif_bottom_sheet_location": "МІСЦЕ",
|
"exif_bottom_sheet_location": "МІСЦЕ",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Додати місцезнаходження",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "В розробці",
|
"experimental_settings_new_asset_list_subtitle": "В розробці",
|
||||||
"experimental_settings_new_asset_list_title": "Експериментальний макет знімків",
|
"experimental_settings_new_asset_list_title": "Експериментальний макет знімків",
|
||||||
"experimental_settings_subtitle": "На власний ризик!",
|
"experimental_settings_subtitle": "На власний ризик!",
|
||||||
@ -194,42 +195,42 @@
|
|||||||
"home_page_add_to_album_conflicts": "Додано {added} елементів у альбом {album}. {failed} елементів вже було в альбомі.",
|
"home_page_add_to_album_conflicts": "Додано {added} елементів у альбом {album}. {failed} елементів вже було в альбомі.",
|
||||||
"home_page_add_to_album_err_local": "Неможливо додати локальні елементи до альбомів, пропущено",
|
"home_page_add_to_album_err_local": "Неможливо додати локальні елементи до альбомів, пропущено",
|
||||||
"home_page_add_to_album_success": "Додано {added} елементів у альбом {album}.",
|
"home_page_add_to_album_success": "Додано {added} елементів у альбом {album}.",
|
||||||
"home_page_album_err_partner": "Can not add partner assets to an album yet, skipping",
|
"home_page_album_err_partner": "Поки що не вдається додати елементи партнера до альбому, пропущено",
|
||||||
"home_page_archive_err_local": "Поки що неможливо заархівувати локальні елементи, пропущено",
|
"home_page_archive_err_local": "Поки що неможливо заархівувати локальні елементи, пропущено",
|
||||||
"home_page_archive_err_partner": "Can not archive partner assets, skipping",
|
"home_page_archive_err_partner": "Неможливо архівувати елементи партнера, пропущено",
|
||||||
"home_page_building_timeline": "Побудова хронології",
|
"home_page_building_timeline": "Побудова хронології",
|
||||||
"home_page_delete_err_partner": "Can not delete partner assets, skipping",
|
"home_page_delete_err_partner": "Неможливо видалити елементи партнера, пропущено",
|
||||||
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
"home_page_delete_remote_err_local": "Локальні елемент(и) вже в процесі видалення з сервера, пропущено",
|
||||||
"home_page_favorite_err_local": "Неможливо отримати улюблені локальні елементи, пропущено",
|
"home_page_favorite_err_local": "Поки що не можна додати до улюблених локальні елементи, пропущено",
|
||||||
"home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping",
|
"home_page_favorite_err_partner": "Поки що не можна додати до улюблених елементи партнера, пропущено",
|
||||||
"home_page_first_time_notice": "Якщо ви вперше користуєтеся програмою, переконайтеся, що ви вибрали альбоми для резервування, щоб могти заповнювати хронологію знімків та відео в альбомах.",
|
"home_page_first_time_notice": "Якщо ви вперше користуєтеся програмою, переконайтеся, що ви вибрали альбоми для резервування, щоб могти заповнювати хронологію знімків та відео в альбомах.",
|
||||||
"home_page_share_err_local": "Can not share local assets via link, skipping",
|
"home_page_share_err_local": "Неможливо поділитися локальними елементами через посилання, пропущено",
|
||||||
"home_page_upload_err_limit": "Можна вантажити не більше 30 елементів водночас, пропущено",
|
"home_page_upload_err_limit": "Можна вантажити не більше 30 елементів водночас, пропущено",
|
||||||
"image_viewer_page_state_provider_download_error": "Помилка завантаження",
|
"image_viewer_page_state_provider_download_error": "Помилка завантаження",
|
||||||
"image_viewer_page_state_provider_download_success": "Усіпшно завантажено",
|
"image_viewer_page_state_provider_download_success": "Усіпшно завантажено",
|
||||||
"image_viewer_page_state_provider_share_error": "Share Error",
|
"image_viewer_page_state_provider_share_error": "Помилка спільного доступу",
|
||||||
"library_page_albums": "Альбоми",
|
"library_page_albums": "Альбоми",
|
||||||
"library_page_archive": "Архів",
|
"library_page_archive": "Архів",
|
||||||
"library_page_device_albums": "Альбоми на Пристрої",
|
"library_page_device_albums": "Альбоми на пристрої",
|
||||||
"library_page_favorites": "Улюблені",
|
"library_page_favorites": "Улюблені",
|
||||||
"library_page_new_album": "Новий альбом",
|
"library_page_new_album": "Новий альбом",
|
||||||
"library_page_sharing": "Спільні",
|
"library_page_sharing": "Спільні",
|
||||||
"library_page_sort_asset_count": "Number of assets",
|
"library_page_sort_asset_count": "Кількість елементів",
|
||||||
"library_page_sort_created": "Нещодавно створені",
|
"library_page_sort_created": "Нещодавно створені",
|
||||||
"library_page_sort_last_modified": "Last modified",
|
"library_page_sort_last_modified": "Остання зміна",
|
||||||
"library_page_sort_most_oldest_photo": "Oldest photo",
|
"library_page_sort_most_oldest_photo": "Найдавніші фото",
|
||||||
"library_page_sort_most_recent_photo": "Most recent photo",
|
"library_page_sort_most_recent_photo": "Найновіші фото",
|
||||||
"library_page_sort_title": "Назва альбому",
|
"library_page_sort_title": "Назва альбому",
|
||||||
"location_picker_choose_on_map": "Choose on map",
|
"location_picker_choose_on_map": "Обрати на мапі",
|
||||||
"location_picker_latitude": "Latitude",
|
"location_picker_latitude": "Широта",
|
||||||
"location_picker_latitude_error": "Enter a valid latitude",
|
"location_picker_latitude_error": "Вкажіть дійсну широту",
|
||||||
"location_picker_latitude_hint": "Enter your latitude here",
|
"location_picker_latitude_hint": "Вкажіть широту",
|
||||||
"location_picker_longitude": "Longitude",
|
"location_picker_longitude": "Довгота",
|
||||||
"location_picker_longitude_error": "Enter a valid longitude",
|
"location_picker_longitude_error": "Вкажіть дійсну довготу",
|
||||||
"location_picker_longitude_hint": "Enter your longitude here",
|
"location_picker_longitude_hint": "Вкажіть довготу",
|
||||||
"login_disabled": "Авторизація була відключена",
|
"login_disabled": "Авторизація була відключена",
|
||||||
"login_form_api_exception": "Помилка API. Перевірте адресу сервера і спробуйте знову",
|
"login_form_api_exception": "Помилка API. Перевірте адресу сервера і спробуйте знову",
|
||||||
"login_form_back_button_text": "Back",
|
"login_form_back_button_text": "Назад",
|
||||||
"login_form_button_text": "Увійти",
|
"login_form_button_text": "Увійти",
|
||||||
"login_form_email_hint": "youremail@email.com",
|
"login_form_email_hint": "youremail@email.com",
|
||||||
"login_form_endpoint_hint": "http://your-server-ip:port/api",
|
"login_form_endpoint_hint": "http://your-server-ip:port/api",
|
||||||
@ -239,10 +240,10 @@
|
|||||||
"login_form_err_invalid_url": "Хибний URL",
|
"login_form_err_invalid_url": "Хибний URL",
|
||||||
"login_form_err_leading_whitespace": "Пробіл на початку",
|
"login_form_err_leading_whitespace": "Пробіл на початку",
|
||||||
"login_form_err_trailing_whitespace": "Пробіл в кінці",
|
"login_form_err_trailing_whitespace": "Пробіл в кінці",
|
||||||
"login_form_failed_get_oauth_server_config": "Помилка входу через OAuth, перевірте адресу сервера\n",
|
"login_form_failed_get_oauth_server_config": "Помилка входу через OAuth, перевірте адресу сервера",
|
||||||
"login_form_failed_get_oauth_server_disable": "OAuth недоступний на цьому сервері\n",
|
"login_form_failed_get_oauth_server_disable": "OAuth недоступний на цьому сервері",
|
||||||
"login_form_failed_login": "Помилка входу, перевірте URL-адресу сервера, електронну пошту та пароль",
|
"login_form_failed_login": "Помилка входу, перевірте URL-адресу сервера, електронну пошту та пароль",
|
||||||
"login_form_handshake_exception": "There was an Handshake Exception with the server. Enable self-signed certificate support in the settings if you are using a self-signed certificate.",
|
"login_form_handshake_exception": "Виняток рукостискання з сервером. Увімкніть підтримку самопідписаного сертифіката в налаштуваннях, якщо ви використовуєте самопідписаний сертифікат.",
|
||||||
"login_form_label_email": "Електронна пошта",
|
"login_form_label_email": "Електронна пошта",
|
||||||
"login_form_label_password": "Пароль",
|
"login_form_label_password": "Пароль",
|
||||||
"login_form_next_button": "Далі",
|
"login_form_next_button": "Далі",
|
||||||
@ -252,35 +253,35 @@
|
|||||||
"login_form_server_error": "Неможливо з'єднатися із сервером",
|
"login_form_server_error": "Неможливо з'єднатися із сервером",
|
||||||
"login_password_changed_error": "Помилка у оновлені вашого пароля",
|
"login_password_changed_error": "Помилка у оновлені вашого пароля",
|
||||||
"login_password_changed_success": "Пароль оновлено успішно",
|
"login_password_changed_success": "Пароль оновлено успішно",
|
||||||
"map_assets_in_bound": "{} photo",
|
"map_assets_in_bound": "{} фото",
|
||||||
"map_assets_in_bounds": "{} photos",
|
"map_assets_in_bounds": "{} фото",
|
||||||
"map_cannot_get_user_location": "Не можу отримати місцеперебування",
|
"map_cannot_get_user_location": "Не можу отримати місцезнаходження",
|
||||||
"map_location_dialog_cancel": "Скасувати",
|
"map_location_dialog_cancel": "Скасувати",
|
||||||
"map_location_dialog_yes": "Так",
|
"map_location_dialog_yes": "Так",
|
||||||
"map_location_picker_page_use_location": "Use this 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_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_dark_mode": "Темний режим",
|
"map_settings_dark_mode": "Темний режим",
|
||||||
"map_settings_date_range_option_all": "All",
|
"map_settings_date_range_option_all": "Усі",
|
||||||
"map_settings_date_range_option_day": "Past 24 hours",
|
"map_settings_date_range_option_day": "Минулі 24 години",
|
||||||
"map_settings_date_range_option_days": "Past {} days",
|
"map_settings_date_range_option_days": "Минулих {} днів",
|
||||||
"map_settings_date_range_option_year": "Past year",
|
"map_settings_date_range_option_year": "Минулий рік",
|
||||||
"map_settings_date_range_option_years": "Past {} years",
|
"map_settings_date_range_option_years": "Минулі {} роки",
|
||||||
"map_settings_dialog_cancel": "Скасувати",
|
"map_settings_dialog_cancel": "Скасувати",
|
||||||
"map_settings_dialog_save": "Зберегти",
|
"map_settings_dialog_save": "Зберегти",
|
||||||
"map_settings_dialog_title": "Налаштування мапи",
|
"map_settings_dialog_title": "Налаштування мапи",
|
||||||
"map_settings_include_show_archived": "Include Archived",
|
"map_settings_include_show_archived": "Включити архівні дані",
|
||||||
"map_settings_only_relative_range": "Діапазон дат",
|
"map_settings_only_relative_range": "Проміжок часу",
|
||||||
"map_settings_only_show_favorites": "Лише улюбені",
|
"map_settings_only_show_favorites": "Лише улюбені",
|
||||||
"map_settings_theme_settings": "Map Theme",
|
"map_settings_theme_settings": "Тема карти",
|
||||||
"map_zoom_to_see_photos": "Зменшіть, аби переглянути знімки",
|
"map_zoom_to_see_photos": "Зменшіть, аби переглянути знімки",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Рухомі Знімки",
|
"motion_photos_page_title": "Рухомі Знімки",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Неможливо редагувати дату елементів лише для читання, пропущено",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
"multiselect_grid_edit_gps_err_read_only": "Неможливо редагувати місцезнаходження елементів лише для читання, пропущено",
|
||||||
"notification_permission_dialog_cancel": "Скасувати",
|
"notification_permission_dialog_cancel": "Скасувати",
|
||||||
"notification_permission_dialog_content": "Щоб увімкнути сповіщення, перейдіть до Налаштувань і надайте дозвіл.",
|
"notification_permission_dialog_content": "Щоб увімкнути сповіщення, перейдіть до Налаштувань і надайте дозвіл.",
|
||||||
"notification_permission_dialog_settings": "Налаштування",
|
"notification_permission_dialog_settings": "Налаштування",
|
||||||
@ -296,7 +297,7 @@
|
|||||||
"partner_page_stop_sharing_content": "{} втратить доступ до ваших знімків.",
|
"partner_page_stop_sharing_content": "{} втратить доступ до ваших знімків.",
|
||||||
"partner_page_stop_sharing_title": "Припинити надання ваших знімків?",
|
"partner_page_stop_sharing_title": "Припинити надання ваших знімків?",
|
||||||
"partner_page_title": "Партнер",
|
"partner_page_title": "Партнер",
|
||||||
"permission_onboarding_back": "Back",
|
"permission_onboarding_back": "Назад",
|
||||||
"permission_onboarding_continue_anyway": "Все одно продовжити",
|
"permission_onboarding_continue_anyway": "Все одно продовжити",
|
||||||
"permission_onboarding_get_started": "Розпочати",
|
"permission_onboarding_get_started": "Розпочати",
|
||||||
"permission_onboarding_go_to_settings": "Перейти до налаштувань",
|
"permission_onboarding_go_to_settings": "Перейти до налаштувань",
|
||||||
@ -307,56 +308,56 @@
|
|||||||
"permission_onboarding_permission_limited": "Обмежений доступ. Аби дозволити Immich резервне копіювання та керування вашою галереєю, надайте доступ до знімків та відео у Налаштуваннях",
|
"permission_onboarding_permission_limited": "Обмежений доступ. Аби дозволити Immich резервне копіювання та керування вашою галереєю, надайте доступ до знімків та відео у Налаштуваннях",
|
||||||
"permission_onboarding_request": "Immich потребує доступу до ваших знімків та відео.",
|
"permission_onboarding_request": "Immich потребує доступу до ваших знімків та відео.",
|
||||||
"profile_drawer_app_logs": "Журнал",
|
"profile_drawer_app_logs": "Журнал",
|
||||||
"profile_drawer_client_out_of_date_major": "Mobile App is out of date. Please update to the latest major version.",
|
"profile_drawer_client_out_of_date_major": "Мобільний додаток застарів. Будь ласка, оновіть до останньої мажорної версії.",
|
||||||
"profile_drawer_client_out_of_date_minor": "Mobile App is out of date. Please update to the latest minor version.",
|
"profile_drawer_client_out_of_date_minor": "Мобільний додаток застарів. Будь ласка, оновіть до останньої мінорної версії.",
|
||||||
"profile_drawer_client_server_up_to_date": "Клієнт та Сервер — актуальні",
|
"profile_drawer_client_server_up_to_date": "Клієнт та сервер — актуальні",
|
||||||
"profile_drawer_documentation": "Documentation",
|
"profile_drawer_documentation": "Документація",
|
||||||
"profile_drawer_github": "GitHub",
|
"profile_drawer_github": "GitHub",
|
||||||
"profile_drawer_server_out_of_date_major": "Server is out of date. Please update to the latest major version.",
|
"profile_drawer_server_out_of_date_major": "Сервер застарів. Будь ласка, оновіть до останньої мажорної версії.",
|
||||||
"profile_drawer_server_out_of_date_minor": "Server is out of date. Please update to the latest minor version.",
|
"profile_drawer_server_out_of_date_minor": "Сервер застарів. Будь ласка, оновіть до останньої мінорної версії.",
|
||||||
"profile_drawer_settings": "Налаштування",
|
"profile_drawer_settings": "Налаштування",
|
||||||
"profile_drawer_sign_out": "Вийти",
|
"profile_drawer_sign_out": "Вийти",
|
||||||
"profile_drawer_trash": "Trash",
|
"profile_drawer_trash": "Кошик",
|
||||||
"recently_added_page_title": "Нещодавні",
|
"recently_added_page_title": "Нещодавні",
|
||||||
"scaffold_body_error_occurred": "Error occurred",
|
"scaffold_body_error_occurred": "Виникла помилка",
|
||||||
"search_bar_hint": "Шукати ваші знімки",
|
"search_bar_hint": "Шукати ваші знімки",
|
||||||
"search_page_categories": "Категорії",
|
"search_page_categories": "Категорії",
|
||||||
"search_page_favorites": "Улюблені",
|
"search_page_favorites": "Улюблені",
|
||||||
"search_page_motion_photos": "Рухомі Знімки",
|
"search_page_motion_photos": "Рухомі знімки",
|
||||||
"search_page_no_objects": "Немає інформації про об'єкти",
|
"search_page_no_objects": "Немає інформації про об'єкти",
|
||||||
"search_page_no_places": "No Places Info Available",
|
"search_page_no_places": "Інформація про місця недоступна",
|
||||||
"search_page_people": "People",
|
"search_page_people": "Люди",
|
||||||
"search_page_person_add_name_dialog_cancel": "Cancel",
|
"search_page_person_add_name_dialog_cancel": "Скасувати",
|
||||||
"search_page_person_add_name_dialog_hint": "Name",
|
"search_page_person_add_name_dialog_hint": "Ім'я",
|
||||||
"search_page_person_add_name_dialog_save": "Save",
|
"search_page_person_add_name_dialog_save": "Зберегти",
|
||||||
"search_page_person_add_name_dialog_title": "Add a name",
|
"search_page_person_add_name_dialog_title": "Додати ім'я",
|
||||||
"search_page_person_add_name_subtitle": "Find them fast by name with search",
|
"search_page_person_add_name_subtitle": "Швидко знайдіть їх за назвою за допомогою пошуку",
|
||||||
"search_page_person_add_name_title": "Add a name",
|
"search_page_person_add_name_title": "Додати ім'я",
|
||||||
"search_page_person_edit_name": "Edit name",
|
"search_page_person_edit_name": "Відредагувати ім'я",
|
||||||
"search_page_places": "Places",
|
"search_page_places": "Місця",
|
||||||
"search_page_recently_added": "Recently added",
|
"search_page_recently_added": "Нещодавно додані",
|
||||||
"search_page_screenshots": "Screenshots",
|
"search_page_screenshots": "Знімки екрану",
|
||||||
"search_page_selfies": "Selfies",
|
"search_page_selfies": "Селфі",
|
||||||
"search_page_things": "Things",
|
"search_page_things": "Речі",
|
||||||
"search_page_videos": "Videos",
|
"search_page_videos": "Відео",
|
||||||
"search_page_view_all_button": "View all",
|
"search_page_view_all_button": "Переглянути усі",
|
||||||
"search_page_your_activity": "Your activity",
|
"search_page_your_activity": "Ваші дії",
|
||||||
"search_page_your_map": "Your Map",
|
"search_page_your_map": "Ваша мапа",
|
||||||
"search_result_page_new_search_hint": "New Search",
|
"search_result_page_new_search_hint": "Новий пошук",
|
||||||
"search_suggestion_list_smart_search_hint_1": "Smart search is enabled by default, to search for metadata use the syntax ",
|
"search_suggestion_list_smart_search_hint_1": "Інтелектуальний пошук увімкнено за замовчуванням, для пошуку метаданих використовуйте синтаксис",
|
||||||
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
"search_suggestion_list_smart_search_hint_2": "m:ваш-пошуковий-термін",
|
||||||
"select_additional_user_for_sharing_page_suggestions": "Suggestions",
|
"select_additional_user_for_sharing_page_suggestions": "Пропозиції",
|
||||||
"select_user_for_sharing_page_err_album": "Не вдалося створити альбом",
|
"select_user_for_sharing_page_err_album": "Не вдалося створити альбом",
|
||||||
"select_user_for_sharing_page_share_suggestions": "Suggestions",
|
"select_user_for_sharing_page_share_suggestions": "Пропозиції",
|
||||||
"server_info_box_app_version": "App Version",
|
"server_info_box_app_version": "Версія додатка",
|
||||||
"server_info_box_latest_release": "Latest Version",
|
"server_info_box_latest_release": "Остання версія",
|
||||||
"server_info_box_server_url": "Server URL",
|
"server_info_box_server_url": "URL сервера",
|
||||||
"server_info_box_server_version": "Server Version",
|
"server_info_box_server_version": "Версія сервера",
|
||||||
"setting_image_viewer_help": "The detail viewer loads the small thumbnail first, then loads the medium-size preview (if enabled), finally loads the original (if enabled).",
|
"setting_image_viewer_help": "Повноекранний переглядач спочатку завантажує зображення для попереднього перегляду в низькій роздільній здатності, потім завантажує зображення в зменшеній роздільній здатності відносно оригіналу (якщо включено) і зрештою завантажує оригінал (якщо включено).",
|
||||||
"setting_image_viewer_original_subtitle": "Enable to load the original full-resolution image (large!). Disable to reduce data usage (both network and on device cache).",
|
"setting_image_viewer_original_subtitle": "Увімкніть для завантаження оригінального зображення з повною роздільною здатністю (велике!).\nВимкніть, щоб зменшити використання даних (мережі та кешу пристрою).",
|
||||||
"setting_image_viewer_original_title": "Завантажити оригінальне зображення",
|
"setting_image_viewer_original_title": "Завантажувати оригінальне зображення",
|
||||||
"setting_image_viewer_preview_subtitle": "Увімкніть для завантаження зображення середньої роздільної здатності. Вимкніть або для можливості безпосереднього завантаження оригіналу, або для використання лише мініатюр.",
|
"setting_image_viewer_preview_subtitle": "Увімкніть для завантаження зображень середньої роздільної здатності.\nВимкніть для безпосереднього завантаження оригіналу або використовувати лише мініатюру.",
|
||||||
"setting_image_viewer_preview_title": "Завантажити попередній перегляд зображення",
|
"setting_image_viewer_preview_title": "Завантажувати зображення попереднього перегляду",
|
||||||
"setting_notifications_notify_failures_grace_period": "Повідомити про помилки фонового резервного копіювання: {}",
|
"setting_notifications_notify_failures_grace_period": "Повідомити про помилки фонового резервного копіювання: {}",
|
||||||
"setting_notifications_notify_hours": "{} годин",
|
"setting_notifications_notify_hours": "{} годин",
|
||||||
"setting_notifications_notify_immediately": "негайно",
|
"setting_notifications_notify_immediately": "негайно",
|
||||||
@ -365,9 +366,9 @@
|
|||||||
"setting_notifications_notify_seconds": "{} секунд",
|
"setting_notifications_notify_seconds": "{} секунд",
|
||||||
"setting_notifications_single_progress_subtitle": "Детальна інформація про хід завантаження для кожного елементу",
|
"setting_notifications_single_progress_subtitle": "Детальна інформація про хід завантаження для кожного елементу",
|
||||||
"setting_notifications_single_progress_title": "Показати хід фонового резервного копіювання",
|
"setting_notifications_single_progress_title": "Показати хід фонового резервного копіювання",
|
||||||
"setting_notifications_subtitle": "Налаштуйте свої параметри сповіщень",
|
"setting_notifications_subtitle": "Налаштування параметрів сповіщень",
|
||||||
"setting_notifications_title": "Сповіщення",
|
"setting_notifications_title": "Сповіщення",
|
||||||
"setting_notifications_total_progress_subtitle": "Загальний прогрес (готово/загалом)",
|
"setting_notifications_total_progress_subtitle": "Загальний прогрес (виконано/загалом)",
|
||||||
"setting_notifications_total_progress_title": "Показати загальний хід фонового резервного копіювання",
|
"setting_notifications_total_progress_title": "Показати загальний хід фонового резервного копіювання",
|
||||||
"setting_pages_app_bar_settings": "Налаштування",
|
"setting_pages_app_bar_settings": "Налаштування",
|
||||||
"settings_require_restart": "Перезавантажте програму для застосування цього налаштування",
|
"settings_require_restart": "Перезавантажте програму для застосування цього налаштування",
|
||||||
@ -375,66 +376,66 @@
|
|||||||
"share_add_photos": "Додати знімки",
|
"share_add_photos": "Додати знімки",
|
||||||
"share_add_title": "Додати назву",
|
"share_add_title": "Додати назву",
|
||||||
"share_create_album": "Створити альбом",
|
"share_create_album": "Створити альбом",
|
||||||
"shared_album_activities_input_disable": "Comment is disabled",
|
"shared_album_activities_input_disable": "Коментування вимкнено",
|
||||||
"shared_album_activities_input_hint": "Say something",
|
"shared_album_activities_input_hint": "Скажіть що-небудь",
|
||||||
"shared_album_activity_remove_content": "Do you want to delete this activity?",
|
"shared_album_activity_remove_content": "Ви бажаєте видалити це повідомлення?",
|
||||||
"shared_album_activity_remove_title": "Delete Activity",
|
"shared_album_activity_remove_title": "Видалити повідомлення",
|
||||||
"shared_album_activity_setting_subtitle": "Let others respond",
|
"shared_album_activity_setting_subtitle": "Дозволити іншим відповідати",
|
||||||
"shared_album_activity_setting_title": "Comments & likes",
|
"shared_album_activity_setting_title": "Коментарі та лайки",
|
||||||
"shared_album_section_people_action_error": "Error leaving/removing from album",
|
"shared_album_section_people_action_error": "Помилка виходу/видалення з альбому",
|
||||||
"shared_album_section_people_action_leave": "Remove user from album",
|
"shared_album_section_people_action_leave": "Видалити користувача з альбому",
|
||||||
"shared_album_section_people_action_remove_user": "Remove user from album",
|
"shared_album_section_people_action_remove_user": "Видалити користувача з альбому",
|
||||||
"shared_album_section_people_owner_label": "Owner",
|
"shared_album_section_people_owner_label": "Власник",
|
||||||
"shared_album_section_people_title": "PEOPLE",
|
"shared_album_section_people_title": "ЛЮДИ",
|
||||||
"share_dialog_preparing": "Підготовка...",
|
"share_dialog_preparing": "Підготовка...",
|
||||||
"shared_link_app_bar_title": "Shared Links",
|
"shared_link_app_bar_title": "Спільні посилання",
|
||||||
"shared_link_clipboard_copied_massage": "Copied to clipboard",
|
"shared_link_clipboard_copied_massage": "Скопійовано в буфер обміну",
|
||||||
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
"shared_link_clipboard_text": "Посилання: {}\nПароль: {}",
|
||||||
"shared_link_create_app_bar_title": "Create link to share",
|
"shared_link_create_app_bar_title": "Створити посилання спільного доступу",
|
||||||
"shared_link_create_error": "Error while creating shared link",
|
"shared_link_create_error": "Помилка під час створення спільного посилання",
|
||||||
"shared_link_create_info": "Let anyone with the link see the selected photo(s)",
|
"shared_link_create_info": "Дозволити всім, хто має посилання, переглянути вибрані фото",
|
||||||
"shared_link_create_submit_button": "Create link",
|
"shared_link_create_submit_button": "Створити посилання",
|
||||||
"shared_link_edit_allow_download": "Allow public user to download",
|
"shared_link_edit_allow_download": "Дозволити публічному користувачеві скачувати файли",
|
||||||
"shared_link_edit_allow_upload": "Allow public user to upload",
|
"shared_link_edit_allow_upload": "Дозволити публічному користувачеві завантажувати файли",
|
||||||
"shared_link_edit_app_bar_title": "Edit link",
|
"shared_link_edit_app_bar_title": "Редагувати посилання",
|
||||||
"shared_link_edit_change_expiry": "Change expiration time",
|
"shared_link_edit_change_expiry": "Змінити термін дії",
|
||||||
"shared_link_edit_description": "Description",
|
"shared_link_edit_description": "Опис",
|
||||||
"shared_link_edit_description_hint": "Enter the share description",
|
"shared_link_edit_description_hint": "Введіть опис для спільного доступу",
|
||||||
"shared_link_edit_expire_after": "Expire after",
|
"shared_link_edit_expire_after": "Термін дії закінчується через",
|
||||||
"shared_link_edit_expire_after_option_day": "1 day",
|
"shared_link_edit_expire_after_option_day": "1 день",
|
||||||
"shared_link_edit_expire_after_option_days": "{} days",
|
"shared_link_edit_expire_after_option_days": "{} днів",
|
||||||
"shared_link_edit_expire_after_option_hour": "1 hour",
|
"shared_link_edit_expire_after_option_hour": "1 годину",
|
||||||
"shared_link_edit_expire_after_option_hours": "{} hours",
|
"shared_link_edit_expire_after_option_hours": "{} годин",
|
||||||
"shared_link_edit_expire_after_option_minute": "1 minute",
|
"shared_link_edit_expire_after_option_minute": "1 хвилину",
|
||||||
"shared_link_edit_expire_after_option_minutes": "{} minutes",
|
"shared_link_edit_expire_after_option_minutes": "{} хвилин",
|
||||||
"shared_link_edit_expire_after_option_never": "Never",
|
"shared_link_edit_expire_after_option_never": "Ніколи",
|
||||||
"shared_link_edit_password": "Password",
|
"shared_link_edit_password": "Пароль",
|
||||||
"shared_link_edit_password_hint": "Enter the share password",
|
"shared_link_edit_password_hint": "Введіть пароль для спільного доступу",
|
||||||
"shared_link_edit_show_meta": "Show metadata",
|
"shared_link_edit_show_meta": "Показувати метадані",
|
||||||
"shared_link_edit_submit_button": "Update link",
|
"shared_link_edit_submit_button": "Оновити посилання",
|
||||||
"shared_link_empty": "You don't have any shared links",
|
"shared_link_empty": "У вас немає спільних посилань",
|
||||||
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
"shared_link_error_server_url_fetch": "Неможливо запитати URL із сервера",
|
||||||
"shared_link_expired": "Expired",
|
"shared_link_expired": "Закінчився термін дії",
|
||||||
"shared_link_expires_day": "Expires in {} day",
|
"shared_link_expires_day": "Закінчується через {} день",
|
||||||
"shared_link_expires_days": "Expires in {} days",
|
"shared_link_expires_days": "Закінчується через {} днів",
|
||||||
"shared_link_expires_hour": "Expires in {} hour",
|
"shared_link_expires_hour": "Закінчується через {} годину",
|
||||||
"shared_link_expires_hours": "Expires in {} hours",
|
"shared_link_expires_hours": "Закінчується через {} годин",
|
||||||
"shared_link_expires_minute": "Expires in {} minute",
|
"shared_link_expires_minute": "Закінчується через {} хвилину",
|
||||||
"shared_link_expires_minutes": "Expires in {} minutes",
|
"shared_link_expires_minutes": "Закінчується через {} хвилин",
|
||||||
"shared_link_expires_never": "Expires ∞",
|
"shared_link_expires_never": "Закінчується ∞",
|
||||||
"shared_link_expires_second": "Expires in {} second",
|
"shared_link_expires_second": "Закінчується через {} секунду",
|
||||||
"shared_link_expires_seconds": "Expires in {} seconds",
|
"shared_link_expires_seconds": "Закінчується через {} секунд",
|
||||||
"shared_link_info_chip_download": "Download",
|
"shared_link_info_chip_download": "Скачати",
|
||||||
"shared_link_info_chip_metadata": "EXIF",
|
"shared_link_info_chip_metadata": "EXIF",
|
||||||
"shared_link_info_chip_upload": "Upload",
|
"shared_link_info_chip_upload": "Завантажити",
|
||||||
"shared_link_manage_links": "Manage Shared links",
|
"shared_link_manage_links": "Керування спільними посиланнями",
|
||||||
"share_done": "Done",
|
"share_done": "Готово",
|
||||||
"share_invite": "Запросити в альбом",
|
"share_invite": "Запросити в альбом",
|
||||||
"sharing_page_album": "Спільні альбоми",
|
"sharing_page_album": "Спільні альбоми",
|
||||||
"sharing_page_description": "Створюйте спільні альбоми, щоб ділитися знімками та відео з людьми у вашій мережі.",
|
"sharing_page_description": "Створюйте спільні альбоми, щоб ділитися знімками та відео з людьми у вашій мережі.",
|
||||||
"sharing_page_empty_list": "ПОРОЖНІЙ СПИСОК",
|
"sharing_page_empty_list": "ПОРОЖНІЙ СПИСОК",
|
||||||
"sharing_silver_appbar_create_shared_album": "Створити спільний альбом",
|
"sharing_silver_appbar_create_shared_album": "Створити спільний альбом",
|
||||||
"sharing_silver_appbar_shared_links": "Shared links",
|
"sharing_silver_appbar_shared_links": "Спільні посилання",
|
||||||
"sharing_silver_appbar_share_partner": "Поділитися з партнером",
|
"sharing_silver_appbar_share_partner": "Поділитися з партнером",
|
||||||
"tab_controller_nav_library": "Бібліотека",
|
"tab_controller_nav_library": "Бібліотека",
|
||||||
"tab_controller_nav_photos": "Знімки",
|
"tab_controller_nav_photos": "Знімки",
|
||||||
@ -443,26 +444,26 @@
|
|||||||
"theme_setting_asset_list_storage_indicator_title": "Показувати піктограму сховища на плитках елементів",
|
"theme_setting_asset_list_storage_indicator_title": "Показувати піктограму сховища на плитках елементів",
|
||||||
"theme_setting_asset_list_tiles_per_row_title": "Кількість елементів у рядку ({})",
|
"theme_setting_asset_list_tiles_per_row_title": "Кількість елементів у рядку ({})",
|
||||||
"theme_setting_dark_mode_switch": "Темна тема",
|
"theme_setting_dark_mode_switch": "Темна тема",
|
||||||
"theme_setting_image_viewer_quality_subtitle": "Налаштувати якість перегляду повних зображень",
|
"theme_setting_image_viewer_quality_subtitle": "Налаштування якості перегляду повноекранних зображень",
|
||||||
"theme_setting_image_viewer_quality_title": "Якість перегляду зображень",
|
"theme_setting_image_viewer_quality_title": "Якість перегляду зображень",
|
||||||
"theme_setting_system_theme_switch": "Автоматично (як система)",
|
"theme_setting_system_theme_switch": "Автоматично (як у системі)",
|
||||||
"theme_setting_theme_subtitle": "Виберіть налаштування теми програми",
|
"theme_setting_theme_subtitle": "Налаштування теми додатка",
|
||||||
"theme_setting_theme_title": "Тема",
|
"theme_setting_theme_title": "Тема",
|
||||||
"theme_setting_three_stage_loading_subtitle": "Триетапне завантаження може підвищити продуктивність завантаження, але спричинить значно більше навантаження на мережу",
|
"theme_setting_three_stage_loading_subtitle": "Триетапне завантаження може підвищити продуктивність завантаження, але спричинить значно більше навантаження на мережу",
|
||||||
"theme_setting_three_stage_loading_title": "Увімкнути триетапне завантаження",
|
"theme_setting_three_stage_loading_title": "Увімкнути триетапне завантаження",
|
||||||
"translated_text_options": "Налаштування",
|
"translated_text_options": "Налаштування",
|
||||||
"trash_page_delete": "Delete",
|
"trash_page_delete": "Видалити",
|
||||||
"trash_page_delete_all": "Delete All",
|
"trash_page_delete_all": "Видалити усі",
|
||||||
"trash_page_empty_trash_btn": "Empty trash",
|
"trash_page_empty_trash_btn": "Очистити кошик",
|
||||||
"trash_page_empty_trash_dialog_content": "Do you want to empty your trashed assets? These items will be permanently removed from Immich",
|
"trash_page_empty_trash_dialog_content": "Бажаєте очистити ваші елементи в кошику? Ці елементи буде остаточно видалено з Immich.",
|
||||||
"trash_page_empty_trash_dialog_ok": "Ok",
|
"trash_page_empty_trash_dialog_ok": "OK",
|
||||||
"trash_page_info": "Trashed items will be permanently deleted after {} days",
|
"trash_page_info": "Поміщені у кошик елементи буде остаточно видалено через {} днів",
|
||||||
"trash_page_no_assets": "No trashed assets",
|
"trash_page_no_assets": "Віддалені елементи відсутні",
|
||||||
"trash_page_restore": "Restore",
|
"trash_page_restore": "Відновити",
|
||||||
"trash_page_restore_all": "Restore All",
|
"trash_page_restore_all": "Відновити усі",
|
||||||
"trash_page_select_assets_btn": "Select assets",
|
"trash_page_select_assets_btn": "Вибрані елементи",
|
||||||
"trash_page_select_btn": "Select",
|
"trash_page_select_btn": "Вибрати",
|
||||||
"trash_page_title": "Trash ({})",
|
"trash_page_title": "Кошик ({})",
|
||||||
"upload_dialog_cancel": "Скасувати",
|
"upload_dialog_cancel": "Скасувати",
|
||||||
"upload_dialog_info": "Бажаєте створити резервну копію вибраних елементів на сервері?",
|
"upload_dialog_info": "Бажаєте створити резервну копію вибраних елементів на сервері?",
|
||||||
"upload_dialog_ok": "Завантажити",
|
"upload_dialog_ok": "Завантажити",
|
||||||
@ -473,7 +474,7 @@
|
|||||||
"version_announcement_overlay_text_2": "знайдіть хвильку навідатися на ",
|
"version_announcement_overlay_text_2": "знайдіть хвильку навідатися на ",
|
||||||
"version_announcement_overlay_text_3": "і переконайтеся, що ваші налаштування docker-compose та .env оновлені, аби запобігти будь-якій неправильній конфігурації, особливо, якщо ви використовуєте WatchTower або інший механізм, для автоматичних оновлень вашої серверної частини.",
|
"version_announcement_overlay_text_3": "і переконайтеся, що ваші налаштування docker-compose та .env оновлені, аби запобігти будь-якій неправильній конфігурації, особливо, якщо ви використовуєте WatchTower або інший механізм, для автоматичних оновлень вашої серверної частини.",
|
||||||
"version_announcement_overlay_title": "Доступна нова версія сервера \uD83C\uDF89",
|
"version_announcement_overlay_title": "Доступна нова версія сервера \uD83C\uDF89",
|
||||||
"viewer_remove_from_stack": "Remove from Stack",
|
"viewer_remove_from_stack": "Видалити зі стеку",
|
||||||
"viewer_stack_use_as_main_asset": "Use as Main Asset",
|
"viewer_stack_use_as_main_asset": "Використовувати як основний елементи",
|
||||||
"viewer_unstack": "Un-Stack"
|
"viewer_unstack": "Розібрати стек"
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"action_common_cancel": "Cancel",
|
"action_common_cancel": "Từ chối",
|
||||||
"action_common_update": "Update",
|
"action_common_update": "Cập nhật",
|
||||||
"add_to_album_bottom_sheet_added": "Thêm vào {album}",
|
"add_to_album_bottom_sheet_added": "Thêm vào {album}",
|
||||||
"add_to_album_bottom_sheet_already_exists": "Đã có sẵn trong {album}",
|
"add_to_album_bottom_sheet_already_exists": "Đã có sẵn trong {album}",
|
||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Phân loại nhật ký: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Trên một số thiết bị, việc tải hình thu nhỏ từ ảnh trên thiết bị diễn ra chậm. Kích hoạt cài đặt này để tải ảnh từ máy chủ.",
|
"advanced_settings_prefer_remote_subtitle": "Trên một số thiết bị, việc tải hình thu nhỏ từ ảnh trên thiết bị diễn ra chậm. Kích hoạt cài đặt này để tải ảnh từ máy chủ.",
|
||||||
"advanced_settings_prefer_remote_title": "Ưu tiên ảnh từ máy chủ",
|
"advanced_settings_prefer_remote_title": "Ưu tiên ảnh từ máy chủ",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Bỏ qua xác minh chứng chỉ SSL cho máy chủ cuối. Yêu cầu cho chứng chỉ tự ký.",
|
"advanced_settings_self_signed_ssl_subtitle": "Bỏ qua xác minh chứng chỉ SSL cho máy chủ cuối. Yêu cầu cho chứng chỉ tự ký.",
|
||||||
@ -35,8 +35,8 @@
|
|||||||
"app_bar_signout_dialog_title": "Đăng xuất",
|
"app_bar_signout_dialog_title": "Đăng xuất",
|
||||||
"archive_page_no_archived_assets": "Không tìm thấy ảnh đã lưu trữ",
|
"archive_page_no_archived_assets": "Không tìm thấy ảnh đã lưu trữ",
|
||||||
"archive_page_title": "Kho lưu trữ ({})",
|
"archive_page_title": "Kho lưu trữ ({})",
|
||||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
"asset_action_delete_err_read_only": "Không thể xoá ảnh chỉ có quyền đọc, bỏ qua",
|
||||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
"asset_action_share_err_offline": "Không thể tải ảnh ngoại tuyến, bỏ qua",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Bố cục động",
|
"asset_list_layout_settings_dynamic_layout_title": "Bố cục động",
|
||||||
"asset_list_layout_settings_group_automatically": "Tự động",
|
"asset_list_layout_settings_group_automatically": "Tự động",
|
||||||
"asset_list_layout_settings_group_by": " Nhóm ảnh theo",
|
"asset_list_layout_settings_group_by": " Nhóm ảnh theo",
|
||||||
@ -111,9 +111,9 @@
|
|||||||
"cache_settings_album_thumbnails": "Trang thư viện hình thu nhỏ ({} ảnh)",
|
"cache_settings_album_thumbnails": "Trang thư viện hình thu nhỏ ({} ảnh)",
|
||||||
"cache_settings_clear_cache_button": "Xoá bộ nhớ đệm",
|
"cache_settings_clear_cache_button": "Xoá bộ nhớ đệm",
|
||||||
"cache_settings_clear_cache_button_title": "Xóa bộ nhớ đệm của ứng dụng. Điều này sẽ ảnh hưởng đến hiệu suất của ứng dụng đến khi bộ nhớ đệm được tạo lại.",
|
"cache_settings_clear_cache_button_title": "Xóa bộ nhớ đệm của ứng dụng. Điều này sẽ ảnh hưởng đến hiệu suất của ứng dụng đến khi bộ nhớ đệm được tạo lại.",
|
||||||
"cache_settings_duplicated_assets_clear_button": "CLEAR",
|
"cache_settings_duplicated_assets_clear_button": "XOÁ",
|
||||||
"cache_settings_duplicated_assets_subtitle": "Photos and videos that are black listed by the app",
|
"cache_settings_duplicated_assets_subtitle": "Ảnh và video không được phép hiển thị trên ứng dụng",
|
||||||
"cache_settings_duplicated_assets_title": "Duplicated Assets ({})",
|
"cache_settings_duplicated_assets_title": "Ảnh bị trùng lặp ({})",
|
||||||
"cache_settings_image_cache_size": "Kích thước bộ nhớ đệm ảnh ({} ảnh)",
|
"cache_settings_image_cache_size": "Kích thước bộ nhớ đệm ảnh ({} ảnh)",
|
||||||
"cache_settings_statistics_album": "Thư viện hình thu nhỏ",
|
"cache_settings_statistics_album": "Thư viện hình thu nhỏ",
|
||||||
"cache_settings_statistics_assets": "{} ảnh ({})",
|
"cache_settings_statistics_assets": "{} ảnh ({})",
|
||||||
@ -142,17 +142,17 @@
|
|||||||
"control_bottom_app_bar_archive": "Kho lưu trữ",
|
"control_bottom_app_bar_archive": "Kho lưu trữ",
|
||||||
"control_bottom_app_bar_create_new_album": "Tạo album mới",
|
"control_bottom_app_bar_create_new_album": "Tạo album mới",
|
||||||
"control_bottom_app_bar_delete": "Xoá",
|
"control_bottom_app_bar_delete": "Xoá",
|
||||||
"control_bottom_app_bar_delete_from_immich": "Delete from Immich",
|
"control_bottom_app_bar_delete_from_immich": "Xóa khỏi Immich",
|
||||||
"control_bottom_app_bar_delete_from_local": "Delete from device",
|
"control_bottom_app_bar_delete_from_local": "Xóa khỏi thiết bị\n",
|
||||||
"control_bottom_app_bar_edit_location": "Edit Location",
|
"control_bottom_app_bar_edit_location": "Chỉnh sửa vị trí",
|
||||||
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
"control_bottom_app_bar_edit_time": "Chỉnh sửa Ngày và Giờ",
|
||||||
"control_bottom_app_bar_favorite": "Yêu thích",
|
"control_bottom_app_bar_favorite": "Yêu thích",
|
||||||
"control_bottom_app_bar_share": "Chia sẻ",
|
"control_bottom_app_bar_share": "Chia sẻ",
|
||||||
"control_bottom_app_bar_share_to": "Chia sẻ với",
|
"control_bottom_app_bar_share_to": "Chia sẻ với",
|
||||||
"control_bottom_app_bar_stack": "Ngắn xếp",
|
"control_bottom_app_bar_stack": "Xếp nhóm",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Di chuyển tới thùng rác",
|
||||||
"control_bottom_app_bar_unarchive": "Huỷ lưu trữ",
|
"control_bottom_app_bar_unarchive": "Huỷ lưu trữ",
|
||||||
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
"control_bottom_app_bar_unfavorite": "Bỏ yêu thích",
|
||||||
"control_bottom_app_bar_upload": "Tải lên",
|
"control_bottom_app_bar_upload": "Tải lên",
|
||||||
"create_album_page_untitled": "Không tiêu đề",
|
"create_album_page_untitled": "Không tiêu đề",
|
||||||
"create_shared_album_page_create": "Tạo",
|
"create_shared_album_page_create": "Tạo",
|
||||||
@ -165,26 +165,27 @@
|
|||||||
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
||||||
"date_format": "E, LLL d, y • h:mm a",
|
"date_format": "E, LLL d, y • h:mm a",
|
||||||
"delete_dialog_alert": "Những mục này sẽ bị xóa vĩnh viễn khỏi Immich và thiết bị của bạn",
|
"delete_dialog_alert": "Những mục này sẽ bị xóa vĩnh viễn khỏi Immich và thiết bị của bạn",
|
||||||
"delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server",
|
"delete_dialog_alert_local": "Những mục này sẽ bị xóa vĩnh viễn khỏi thiết bị của bạn nhưng vẫn còn lưu trữ trên máy chủ Immich",
|
||||||
"delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device",
|
"delete_dialog_alert_local_non_backed_up": "Một số mục chưa được sao lưu lên Immich và sẽ bị xóa vĩnh viễn khỏi thiết bị của bạn.",
|
||||||
"delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server",
|
"delete_dialog_alert_remote": "Những mục này sẽ bị xóa vĩnh viễn khỏi máy chủ Immich",
|
||||||
"delete_dialog_cancel": "Từ chối",
|
"delete_dialog_cancel": "Từ chối",
|
||||||
"delete_dialog_ok": "Xoá",
|
"delete_dialog_ok": "Xoá",
|
||||||
"delete_dialog_ok_force": "Delete Anyway",
|
"delete_dialog_ok_force": "Xóa Vĩnh Viễn",
|
||||||
"delete_dialog_title": "Xoá vĩnh viễn",
|
"delete_dialog_title": "Xoá vĩnh viễn",
|
||||||
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
|
"delete_local_dialog_ok_backed_up_only": "Xoá ảnh đã sao lưu",
|
||||||
"delete_local_dialog_ok_force": "Delete Anyway",
|
"delete_local_dialog_ok_force": "Vẫn xoá",
|
||||||
"delete_shared_link_dialog_content": "Bạn có muốn xóa liên kết đã chia sẻ này không?",
|
"delete_shared_link_dialog_content": "Bạn có muốn xóa liên kết đã chia sẻ này không?",
|
||||||
"delete_shared_link_dialog_title": "Xoá liên kết đã chia sẻ",
|
"delete_shared_link_dialog_title": "Xoá liên kết đã chia sẻ",
|
||||||
"description_input_hint_text": "Thêm mô tả...",
|
"description_input_hint_text": "Thêm mô tả...",
|
||||||
"description_input_submit_error": "Cập nhật mô tả không thành công, vui lòng kiểm tra nhật ký để biết thêm chi tiết",
|
"description_input_submit_error": "Cập nhật mô tả không thành công, vui lòng kiểm tra nhật ký để biết thêm chi tiết",
|
||||||
"edit_date_time_dialog_date_time": "Date and Time",
|
"edit_date_time_dialog_date_time": "Ngày và Giờ",
|
||||||
"edit_date_time_dialog_timezone": "Timezone",
|
"edit_date_time_dialog_timezone": "Múi giờ",
|
||||||
"edit_location_dialog_title": "Location",
|
"edit_location_dialog_title": "Vị trí",
|
||||||
"exif_bottom_sheet_description": "Thêm mô tả...",
|
"exif_bottom_sheet_description": "Thêm mô tả...",
|
||||||
"exif_bottom_sheet_details": "CHI TIẾT",
|
"exif_bottom_sheet_details": "CHI TIẾT",
|
||||||
"exif_bottom_sheet_location": "VỊ TRÍ",
|
"exif_bottom_sheet_location": "VỊ TRÍ",
|
||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Thêm vị trí",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "Đang trong quá trình phát triển",
|
"experimental_settings_new_asset_list_subtitle": "Đang trong quá trình phát triển",
|
||||||
"experimental_settings_new_asset_list_title": "Bật lưới ảnh thử nghiệm",
|
"experimental_settings_new_asset_list_title": "Bật lưới ảnh thử nghiệm",
|
||||||
"experimental_settings_subtitle": "Sử dụng có thể rủi ro!",
|
"experimental_settings_subtitle": "Sử dụng có thể rủi ro!",
|
||||||
@ -214,22 +215,22 @@
|
|||||||
"library_page_favorites": "Ảnh yêu thích",
|
"library_page_favorites": "Ảnh yêu thích",
|
||||||
"library_page_new_album": "Album mới",
|
"library_page_new_album": "Album mới",
|
||||||
"library_page_sharing": "Chia sẻ",
|
"library_page_sharing": "Chia sẻ",
|
||||||
"library_page_sort_asset_count": "Number of assets",
|
"library_page_sort_asset_count": "Số lượng ảnh",
|
||||||
"library_page_sort_created": "Mới tạo gần đây",
|
"library_page_sort_created": "Mới tạo gần đây",
|
||||||
"library_page_sort_last_modified": "Sửa đổi lần cuối",
|
"library_page_sort_last_modified": "Sửa đổi lần cuối",
|
||||||
"library_page_sort_most_oldest_photo": "Oldest photo",
|
"library_page_sort_most_oldest_photo": "Ảnh cũ nhất",
|
||||||
"library_page_sort_most_recent_photo": "Ảnh gần đây nhất",
|
"library_page_sort_most_recent_photo": "Ảnh gần đây nhất",
|
||||||
"library_page_sort_title": "Tiêu đề album",
|
"library_page_sort_title": "Tiêu đề album",
|
||||||
"location_picker_choose_on_map": "Choose on map",
|
"location_picker_choose_on_map": "Chọn trên bản đồ",
|
||||||
"location_picker_latitude": "Latitude",
|
"location_picker_latitude": "Vĩ độ",
|
||||||
"location_picker_latitude_error": "Enter a valid latitude",
|
"location_picker_latitude_error": "Nhập vĩ độ hợp lệ",
|
||||||
"location_picker_latitude_hint": "Enter your latitude here",
|
"location_picker_latitude_hint": "Nhập vĩ độ của bạn",
|
||||||
"location_picker_longitude": "Longitude",
|
"location_picker_longitude": "Kinh độ",
|
||||||
"location_picker_longitude_error": "Enter a valid longitude",
|
"location_picker_longitude_error": "Nhập kinh độ hợp lệ",
|
||||||
"location_picker_longitude_hint": "Enter your longitude here",
|
"location_picker_longitude_hint": "Nhập kinh độ của bạn",
|
||||||
"login_disabled": "Đăng nhập bị vô hiệu hoá",
|
"login_disabled": "Đăng nhập bị vô hiệu hoá",
|
||||||
"login_form_api_exception": "Lỗi API. Vui lòng kiểm tra địa chỉ máy chủ và thử lại.",
|
"login_form_api_exception": "Lỗi API. Vui lòng kiểm tra địa chỉ máy chủ và thử lại.",
|
||||||
"login_form_back_button_text": "Back",
|
"login_form_back_button_text": "Quay lại",
|
||||||
"login_form_button_text": "Đăng nhập",
|
"login_form_button_text": "Đăng nhập",
|
||||||
"login_form_email_hint": "emailcuaban@email.com",
|
"login_form_email_hint": "emailcuaban@email.com",
|
||||||
"login_form_endpoint_hint": "http://địa-chỉ-ip-máy-chủ-bạn:cổng/api",
|
"login_form_endpoint_hint": "http://địa-chỉ-ip-máy-chủ-bạn:cổng/api",
|
||||||
@ -252,35 +253,35 @@
|
|||||||
"login_form_server_error": "Không thể kết nối tới máy chủ.",
|
"login_form_server_error": "Không thể kết nối tới máy chủ.",
|
||||||
"login_password_changed_error": "Thay đổi mật khẩu không thành công",
|
"login_password_changed_error": "Thay đổi mật khẩu không thành công",
|
||||||
"login_password_changed_success": "Cập nhật mật khẩu thành công",
|
"login_password_changed_success": "Cập nhật mật khẩu thành công",
|
||||||
"map_assets_in_bound": "{} photo",
|
"map_assets_in_bound": "{} ảnh",
|
||||||
"map_assets_in_bounds": "{} photos",
|
"map_assets_in_bounds": "{} ảnh",
|
||||||
"map_cannot_get_user_location": "Không thể xác định vị trí của bạn",
|
"map_cannot_get_user_location": "Không thể xác định vị trí của bạn",
|
||||||
"map_location_dialog_cancel": "Từ chối",
|
"map_location_dialog_cancel": "Từ chối",
|
||||||
"map_location_dialog_yes": "Có",
|
"map_location_dialog_yes": "Có",
|
||||||
"map_location_picker_page_use_location": "Use this location",
|
"map_location_picker_page_use_location": "Dùng vị trí này",
|
||||||
"map_location_service_disabled_content": "Cần bật dịch vụ định vị để hiển thị ảnh hoặc video từ vị trí hiện tại của bạn. Bạn có muốn bật nó ngay bây giờ không?",
|
"map_location_service_disabled_content": "Cần bật dịch vụ định vị để hiển thị ảnh hoặc video từ vị trí hiện tại của bạn. Bạn có muốn bật nó ngay bây giờ không?",
|
||||||
"map_location_service_disabled_title": "Dịch vụ vị trí bị vô hiệu hoá",
|
"map_location_service_disabled_title": "Dịch vụ vị trí bị vô hiệu hoá",
|
||||||
"map_no_assets_in_bounds": "Không có ảnh trong khu vực này",
|
"map_no_assets_in_bounds": "Không có ảnh trong khu vực này",
|
||||||
"map_no_location_permission_content": "Cần quyền truy cập vị trí để hiển thị ảnh từ vị trí hiện tại của bạn. Bạn có muốn cho phép ngay bây giờ không?",
|
"map_no_location_permission_content": "Cần quyền truy cập vị trí để hiển thị ảnh từ vị trí hiện tại của bạn. Bạn có muốn cho phép ngay bây giờ không?",
|
||||||
"map_no_location_permission_title": "Ứng dụng không được phép truy cập vị trí",
|
"map_no_location_permission_title": "Ứng dụng không được phép truy cập vị trí",
|
||||||
"map_settings_dark_mode": "Chế độ tối",
|
"map_settings_dark_mode": "Chế độ tối",
|
||||||
"map_settings_date_range_option_all": "All",
|
"map_settings_date_range_option_all": "Tất cả",
|
||||||
"map_settings_date_range_option_day": "Past 24 hours",
|
"map_settings_date_range_option_day": "Trong vòng 24 giờ qua",
|
||||||
"map_settings_date_range_option_days": "Past {} days",
|
"map_settings_date_range_option_days": "Trong {} ngày qua",
|
||||||
"map_settings_date_range_option_year": "Past year",
|
"map_settings_date_range_option_year": "Năm ngoái",
|
||||||
"map_settings_date_range_option_years": "Past {} years",
|
"map_settings_date_range_option_years": "Trong {} năm qua",
|
||||||
"map_settings_dialog_cancel": "Từ chối",
|
"map_settings_dialog_cancel": "Từ chối",
|
||||||
"map_settings_dialog_save": "Lưu",
|
"map_settings_dialog_save": "Lưu",
|
||||||
"map_settings_dialog_title": "Cài đặt bản đồ",
|
"map_settings_dialog_title": "Cài đặt bản đồ",
|
||||||
"map_settings_include_show_archived": "Bao gồm ảnh đã lưu trữ",
|
"map_settings_include_show_archived": "Bao gồm ảnh đã lưu trữ",
|
||||||
"map_settings_only_relative_range": "Khoảng thời gian",
|
"map_settings_only_relative_range": "Khoảng thời gian",
|
||||||
"map_settings_only_show_favorites": "Chỉ hiển thị mục yêu thích",
|
"map_settings_only_show_favorites": "Chỉ hiển thị mục yêu thích",
|
||||||
"map_settings_theme_settings": "Map Theme",
|
"map_settings_theme_settings": "Giao diện bản đồ",
|
||||||
"map_zoom_to_see_photos": "Thu nhỏ để xem ảnh",
|
"map_zoom_to_see_photos": "Thu nhỏ để xem ảnh",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Ảnh động",
|
"motion_photos_page_title": "Ảnh động",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Không thể chỉnh sửa ngày của ảnh chỉ có quyền đọc, bỏ qua",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
|
"multiselect_grid_edit_gps_err_read_only": "Không thể chỉnh sửa vị trí của ảnh chỉ có quyền đọc, bỏ qua",
|
||||||
"notification_permission_dialog_cancel": "Từ chối",
|
"notification_permission_dialog_cancel": "Từ chối",
|
||||||
"notification_permission_dialog_content": "Để bật thông báo, chuyển tới Cài đặt và chọn cho phép",
|
"notification_permission_dialog_content": "Để bật thông báo, chuyển tới Cài đặt và chọn cho phép",
|
||||||
"notification_permission_dialog_settings": "Cài đặt",
|
"notification_permission_dialog_settings": "Cài đặt",
|
||||||
@ -307,18 +308,18 @@
|
|||||||
"permission_onboarding_permission_limited": "Quyền truy cập vào ảnh của bạn bị hạn chế. Để Immich sao lưu và quản lý toàn bộ thư viện ảnh của bạn, hãy cấp quyền truy cập toàn bộ ảnh trong Cài đặt.",
|
"permission_onboarding_permission_limited": "Quyền truy cập vào ảnh của bạn bị hạn chế. Để Immich sao lưu và quản lý toàn bộ thư viện ảnh của bạn, hãy cấp quyền truy cập toàn bộ ảnh trong Cài đặt.",
|
||||||
"permission_onboarding_request": "Immich cần quyền để xem ảnh và video của bạn",
|
"permission_onboarding_request": "Immich cần quyền để xem ảnh và video của bạn",
|
||||||
"profile_drawer_app_logs": "Nhật ký",
|
"profile_drawer_app_logs": "Nhật ký",
|
||||||
"profile_drawer_client_out_of_date_major": "Mobile App is out of date. Please update to the latest major version.",
|
"profile_drawer_client_out_of_date_major": "Ứng dụng đã lỗi thời. Vui lòng cập nhật lên phiên bản chính mới nhất.",
|
||||||
"profile_drawer_client_out_of_date_minor": "Mobile App is out of date. Please update to the latest minor version.",
|
"profile_drawer_client_out_of_date_minor": "Ứng dụng đã lỗi thời. Vui lòng cập nhật lên phiên bản phụ mới nhất.",
|
||||||
"profile_drawer_client_server_up_to_date": "Máy khách và máy chủ đã cập nhật",
|
"profile_drawer_client_server_up_to_date": "Máy khách và máy chủ đã cập nhật",
|
||||||
"profile_drawer_documentation": "Tài liệu",
|
"profile_drawer_documentation": "Tài liệu",
|
||||||
"profile_drawer_github": "GitHub",
|
"profile_drawer_github": "GitHub",
|
||||||
"profile_drawer_server_out_of_date_major": "Server is out of date. Please update to the latest major version.",
|
"profile_drawer_server_out_of_date_major": "Máy chủ đã lỗi thời. Vui lòng cập nhật lên phiên bản chính mới nhất.",
|
||||||
"profile_drawer_server_out_of_date_minor": "Server is out of date. Please update to the latest minor version.",
|
"profile_drawer_server_out_of_date_minor": "Máy chủ đã lỗi thời. Vui lòng cập nhật lên phiên bản phụ mới nhất.",
|
||||||
"profile_drawer_settings": "Cài đặt",
|
"profile_drawer_settings": "Cài đặt",
|
||||||
"profile_drawer_sign_out": "Đăng xuất",
|
"profile_drawer_sign_out": "Đăng xuất",
|
||||||
"profile_drawer_trash": "Thùng rác",
|
"profile_drawer_trash": "Thùng rác",
|
||||||
"recently_added_page_title": "Mới thêm gần đây",
|
"recently_added_page_title": "Mới thêm gần đây",
|
||||||
"scaffold_body_error_occurred": "Error occurred",
|
"scaffold_body_error_occurred": "Xảy ra lỗi",
|
||||||
"search_bar_hint": "Tìm kiếm ảnh của bạn",
|
"search_bar_hint": "Tìm kiếm ảnh của bạn",
|
||||||
"search_page_categories": "Danh mục",
|
"search_page_categories": "Danh mục",
|
||||||
"search_page_favorites": "Ảnh yêu thích",
|
"search_page_favorites": "Ảnh yêu thích",
|
||||||
@ -326,13 +327,13 @@
|
|||||||
"search_page_no_objects": "Không có thông tin sự vật",
|
"search_page_no_objects": "Không có thông tin sự vật",
|
||||||
"search_page_no_places": "Không có thông tin địa điểm nào",
|
"search_page_no_places": "Không có thông tin địa điểm nào",
|
||||||
"search_page_people": "Mọi người",
|
"search_page_people": "Mọi người",
|
||||||
"search_page_person_add_name_dialog_cancel": "Cancel",
|
"search_page_person_add_name_dialog_cancel": "Từ chối",
|
||||||
"search_page_person_add_name_dialog_hint": "Name",
|
"search_page_person_add_name_dialog_hint": "Tên",
|
||||||
"search_page_person_add_name_dialog_save": "Save",
|
"search_page_person_add_name_dialog_save": "Lưu",
|
||||||
"search_page_person_add_name_dialog_title": "Add a name",
|
"search_page_person_add_name_dialog_title": "Thêm tên",
|
||||||
"search_page_person_add_name_subtitle": "Find them fast by name with search",
|
"search_page_person_add_name_subtitle": "Tìm nhanh theo tên với chức năng tìm kiếm",
|
||||||
"search_page_person_add_name_title": "Add a name",
|
"search_page_person_add_name_title": "Thêm tên",
|
||||||
"search_page_person_edit_name": "Edit name",
|
"search_page_person_edit_name": "Chỉnh sửa tên",
|
||||||
"search_page_places": "Địa điểm",
|
"search_page_places": "Địa điểm",
|
||||||
"search_page_recently_added": "Mới thêm gần đây",
|
"search_page_recently_added": "Mới thêm gần đây",
|
||||||
"search_page_screenshots": "Ảnh màn hình",
|
"search_page_screenshots": "Ảnh màn hình",
|
||||||
@ -341,7 +342,7 @@
|
|||||||
"search_page_videos": "Video",
|
"search_page_videos": "Video",
|
||||||
"search_page_view_all_button": "Xem tất cả",
|
"search_page_view_all_button": "Xem tất cả",
|
||||||
"search_page_your_activity": "Hoạt động của bạn",
|
"search_page_your_activity": "Hoạt động của bạn",
|
||||||
"search_page_your_map": "Your Map",
|
"search_page_your_map": "Bản đồ của bạn",
|
||||||
"search_result_page_new_search_hint": "Tìm kiếm mới",
|
"search_result_page_new_search_hint": "Tìm kiếm mới",
|
||||||
"search_suggestion_list_smart_search_hint_1": "Tìm kiếm thông minh được bật mặc định, để tìm kiếm siêu dữ liệu hãy sử dụng cú pháp",
|
"search_suggestion_list_smart_search_hint_1": "Tìm kiếm thông minh được bật mặc định, để tìm kiếm siêu dữ liệu hãy sử dụng cú pháp",
|
||||||
"search_suggestion_list_smart_search_hint_2": "m:cụm-từ-tìm-kiếm-của-bạn",
|
"search_suggestion_list_smart_search_hint_2": "m:cụm-từ-tìm-kiếm-của-bạn",
|
||||||
@ -381,17 +382,17 @@
|
|||||||
"shared_album_activity_remove_title": "Xoá hoạt động",
|
"shared_album_activity_remove_title": "Xoá hoạt động",
|
||||||
"shared_album_activity_setting_subtitle": "Cho phép người khác phản hồi",
|
"shared_album_activity_setting_subtitle": "Cho phép người khác phản hồi",
|
||||||
"shared_album_activity_setting_title": "Bình luận và lượt thích",
|
"shared_album_activity_setting_title": "Bình luận và lượt thích",
|
||||||
"shared_album_section_people_action_error": "Error leaving/removing from album",
|
"shared_album_section_people_action_error": "Lỗi khi xoá khỏi album",
|
||||||
"shared_album_section_people_action_leave": "Remove user from album",
|
"shared_album_section_people_action_leave": "Xóa người dùng khỏi album",
|
||||||
"shared_album_section_people_action_remove_user": "Remove user from album",
|
"shared_album_section_people_action_remove_user": "Xóa người dùng khỏi album",
|
||||||
"shared_album_section_people_owner_label": "Owner",
|
"shared_album_section_people_owner_label": "Chủ sở hữu",
|
||||||
"shared_album_section_people_title": "PEOPLE",
|
"shared_album_section_people_title": "MỌI NGƯỜI",
|
||||||
"share_dialog_preparing": "Đang xử lý...",
|
"share_dialog_preparing": "Đang xử lý...",
|
||||||
"shared_link_app_bar_title": "Đường liên kết chia sẻ",
|
"shared_link_app_bar_title": "Đường liên kết chia sẻ",
|
||||||
"shared_link_clipboard_copied_massage": "Copied to clipboard",
|
"shared_link_clipboard_copied_massage": "Đã sao chép tới bản ghi tạm",
|
||||||
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
"shared_link_clipboard_text": "Liên kết: {}\nMật khẩu: {}",
|
||||||
"shared_link_create_app_bar_title": "Tạo liên kết để chia sẻ",
|
"shared_link_create_app_bar_title": "Tạo liên kết để chia sẻ",
|
||||||
"shared_link_create_error": "Error while creating shared link",
|
"shared_link_create_error": "Tạo liên kết chia sẻ không thành công",
|
||||||
"shared_link_create_info": "Cho phép bất cứ ai có liên kết xem (các) ảnh đã chọn",
|
"shared_link_create_info": "Cho phép bất cứ ai có liên kết xem (các) ảnh đã chọn",
|
||||||
"shared_link_create_submit_button": "Tạo liên kết",
|
"shared_link_create_submit_button": "Tạo liên kết",
|
||||||
"shared_link_edit_allow_download": "Cho phép bất cứ ai đều có thể tải xuống",
|
"shared_link_edit_allow_download": "Cho phép bất cứ ai đều có thể tải xuống",
|
||||||
@ -401,32 +402,32 @@
|
|||||||
"shared_link_edit_description": "Mô tả",
|
"shared_link_edit_description": "Mô tả",
|
||||||
"shared_link_edit_description_hint": "Nhập mô tả chia sẻ",
|
"shared_link_edit_description_hint": "Nhập mô tả chia sẻ",
|
||||||
"shared_link_edit_expire_after": "Hết hạn sau",
|
"shared_link_edit_expire_after": "Hết hạn sau",
|
||||||
"shared_link_edit_expire_after_option_day": "1 day",
|
"shared_link_edit_expire_after_option_day": "1 ngày",
|
||||||
"shared_link_edit_expire_after_option_days": "{} days",
|
"shared_link_edit_expire_after_option_days": "{} ngày",
|
||||||
"shared_link_edit_expire_after_option_hour": "1 hour",
|
"shared_link_edit_expire_after_option_hour": "1 giờ",
|
||||||
"shared_link_edit_expire_after_option_hours": "{} hours",
|
"shared_link_edit_expire_after_option_hours": "{} giờ",
|
||||||
"shared_link_edit_expire_after_option_minute": "1 minute",
|
"shared_link_edit_expire_after_option_minute": "1 phút",
|
||||||
"shared_link_edit_expire_after_option_minutes": "{} minutes",
|
"shared_link_edit_expire_after_option_minutes": "{} phút",
|
||||||
"shared_link_edit_expire_after_option_never": "Never",
|
"shared_link_edit_expire_after_option_never": "Không bao giờ",
|
||||||
"shared_link_edit_password": "Mật khẩu",
|
"shared_link_edit_password": "Mật khẩu",
|
||||||
"shared_link_edit_password_hint": "Nhập mật khẩu chia sẻ",
|
"shared_link_edit_password_hint": "Nhập mật khẩu chia sẻ",
|
||||||
"shared_link_edit_show_meta": "Hiện thị siêu dữ liệu",
|
"shared_link_edit_show_meta": "Hiện thị siêu dữ liệu",
|
||||||
"shared_link_edit_submit_button": "Cập nhật liên kết",
|
"shared_link_edit_submit_button": "Cập nhật liên kết",
|
||||||
"shared_link_empty": "Bạn không có liên kết được chia sẻ nào",
|
"shared_link_empty": "Bạn không có liên kết được chia sẻ nào",
|
||||||
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
"shared_link_error_server_url_fetch": "Không thể kết nối địa chỉ máy chủ",
|
||||||
"shared_link_expired": "Expired",
|
"shared_link_expired": "Đã hết hạn",
|
||||||
"shared_link_expires_day": "Expires in {} day",
|
"shared_link_expires_day": "Hết hạn trong {} ngày",
|
||||||
"shared_link_expires_days": "Expires in {} days",
|
"shared_link_expires_days": "Hết hạn trong {} ngày",
|
||||||
"shared_link_expires_hour": "Expires in {} hour",
|
"shared_link_expires_hour": "Hết hạn trong {} giờ",
|
||||||
"shared_link_expires_hours": "Expires in {} hours",
|
"shared_link_expires_hours": "Hết hạn trong {} giờ",
|
||||||
"shared_link_expires_minute": "Expires in {} minute",
|
"shared_link_expires_minute": "Hết hạn trong {} phút",
|
||||||
"shared_link_expires_minutes": "Expires in {} minutes",
|
"shared_link_expires_minutes": "Hết hạn trong {} phút",
|
||||||
"shared_link_expires_never": "Expires ∞",
|
"shared_link_expires_never": "Hết hạn ∞\n",
|
||||||
"shared_link_expires_second": "Expires in {} second",
|
"shared_link_expires_second": "Hết hạn trong {} giây",
|
||||||
"shared_link_expires_seconds": "Expires in {} seconds",
|
"shared_link_expires_seconds": "Hết hạn trong {} giây",
|
||||||
"shared_link_info_chip_download": "Download",
|
"shared_link_info_chip_download": "Tải xuống",
|
||||||
"shared_link_info_chip_metadata": "EXIF",
|
"shared_link_info_chip_metadata": "Dữ liệu EXIF",
|
||||||
"shared_link_info_chip_upload": "Upload",
|
"shared_link_info_chip_upload": "Tải lên",
|
||||||
"shared_link_manage_links": "Quản lý liên kết được chia sẻ",
|
"shared_link_manage_links": "Quản lý liên kết được chia sẻ",
|
||||||
"share_done": "Hoàn tất",
|
"share_done": "Hoàn tất",
|
||||||
"share_invite": "Mời vào album",
|
"share_invite": "Mời vào album",
|
||||||
@ -441,11 +442,11 @@
|
|||||||
"tab_controller_nav_search": "Tìm kiếm",
|
"tab_controller_nav_search": "Tìm kiếm",
|
||||||
"tab_controller_nav_sharing": "Chia sẻ",
|
"tab_controller_nav_sharing": "Chia sẻ",
|
||||||
"theme_setting_asset_list_storage_indicator_title": "Hiện thị trạng thái sao lưu ảnh trên hình thu nhỏ ",
|
"theme_setting_asset_list_storage_indicator_title": "Hiện thị trạng thái sao lưu ảnh trên hình thu nhỏ ",
|
||||||
"theme_setting_asset_list_tiles_per_row_title": "Số ảnh và video trên một dòng ({})",
|
"theme_setting_asset_list_tiles_per_row_title": "Số lượng ảnh trên một dòng ({})",
|
||||||
"theme_setting_dark_mode_switch": "Chế độ tối",
|
"theme_setting_dark_mode_switch": "Chế độ tối",
|
||||||
"theme_setting_image_viewer_quality_subtitle": "Điều chỉnh chất lượng của trình xem ảnh",
|
"theme_setting_image_viewer_quality_subtitle": "Điều chỉnh chất lượng của trình xem ảnh",
|
||||||
"theme_setting_image_viewer_quality_title": "Chất lượng trình xem ảnh",
|
"theme_setting_image_viewer_quality_title": "Chất lượng trình xem ảnh",
|
||||||
"theme_setting_system_theme_switch": "Tư động (Theo cài đặt hệ thống)",
|
"theme_setting_system_theme_switch": "Tự động (Theo cài đặt hệ thống)",
|
||||||
"theme_setting_theme_subtitle": "Chọn cài đặt giao diện ứng dụng",
|
"theme_setting_theme_subtitle": "Chọn cài đặt giao diện ứng dụng",
|
||||||
"theme_setting_theme_title": "Giao diện",
|
"theme_setting_theme_title": "Giao diện",
|
||||||
"theme_setting_three_stage_loading_subtitle": "Tải ba giai doạn có thể tăng hiệu năng tải ảnh nhưng sẽ tốn dữ liệu mạng đáng kể.",
|
"theme_setting_three_stage_loading_subtitle": "Tải ba giai doạn có thể tăng hiệu năng tải ảnh nhưng sẽ tốn dữ liệu mạng đáng kể.",
|
||||||
@ -473,7 +474,7 @@
|
|||||||
"version_announcement_overlay_text_2": "vui lòng dành thời gian của bạn để đến thăm",
|
"version_announcement_overlay_text_2": "vui lòng dành thời gian của bạn để đến thăm",
|
||||||
"version_announcement_overlay_text_3": "và đảm bảo cài đặt docker-compose và tệp .env của bạn đã cập nhật để tránh bất kỳ cấu hình sai sót, đặc biệt nếu bạn dùng WatchTower hoặc bất kỳ cơ chế nào xử lý việc cập nhật ứng dụng máy chủ của bạn tự động.",
|
"version_announcement_overlay_text_3": "và đảm bảo cài đặt docker-compose và tệp .env của bạn đã cập nhật để tránh bất kỳ cấu hình sai sót, đặc biệt nếu bạn dùng WatchTower hoặc bất kỳ cơ chế nào xử lý việc cập nhật ứng dụng máy chủ của bạn tự động.",
|
||||||
"version_announcement_overlay_title": "Phiên bản máy chủ có bản cập nhật mới",
|
"version_announcement_overlay_title": "Phiên bản máy chủ có bản cập nhật mới",
|
||||||
"viewer_remove_from_stack": "Loại bỏ khỏi ngăn xếp",
|
"viewer_remove_from_stack": "Xoá khỏi nhóm",
|
||||||
"viewer_stack_use_as_main_asset": "Sử dụng làm ảnh bìa ngăn xếp",
|
"viewer_stack_use_as_main_asset": "Đặt làm lựa chọn hàng đầu",
|
||||||
"viewer_unstack": "Hoàn tác ngăn xếp"
|
"viewer_unstack": "Huỷ xếp nhóm"
|
||||||
}
|
}
|
@ -80,7 +80,7 @@
|
|||||||
"backup_controller_page_backup_sub": "已备份的照片和视频",
|
"backup_controller_page_backup_sub": "已备份的照片和视频",
|
||||||
"backup_controller_page_cancel": "取消",
|
"backup_controller_page_cancel": "取消",
|
||||||
"backup_controller_page_created": "创建时间: {}",
|
"backup_controller_page_created": "创建时间: {}",
|
||||||
"backup_controller_page_desc_backup": "打开前台备份,以在程序运行时自动备份。",
|
"backup_controller_page_desc_backup": "打开前台备份,以在程序运行时自动备份新项目。",
|
||||||
"backup_controller_page_excluded": "已排除:",
|
"backup_controller_page_excluded": "已排除:",
|
||||||
"backup_controller_page_failed": "失败({})",
|
"backup_controller_page_failed": "失败({})",
|
||||||
"backup_controller_page_filename": "文件名称: {} [{}]",
|
"backup_controller_page_filename": "文件名称: {} [{}]",
|
||||||
@ -121,7 +121,7 @@
|
|||||||
"cache_settings_statistics_shared": "共享相册缩略图",
|
"cache_settings_statistics_shared": "共享相册缩略图",
|
||||||
"cache_settings_statistics_thumbnail": "缩略图",
|
"cache_settings_statistics_thumbnail": "缩略图",
|
||||||
"cache_settings_statistics_title": "缓存使用情况",
|
"cache_settings_statistics_title": "缓存使用情况",
|
||||||
"cache_settings_subtitle": "控制 Immich 的缓存行为",
|
"cache_settings_subtitle": "控制 Immich app 的缓存行为",
|
||||||
"cache_settings_thumbnail_size": "缩略图缓存大小({} 项)",
|
"cache_settings_thumbnail_size": "缩略图缓存大小({} 项)",
|
||||||
"cache_settings_tile_subtitle": "设置本地存储行为",
|
"cache_settings_tile_subtitle": "设置本地存储行为",
|
||||||
"cache_settings_tile_title": "本地存储",
|
"cache_settings_tile_title": "本地存储",
|
||||||
@ -134,7 +134,7 @@
|
|||||||
"common_add_to_album": "添加到相册",
|
"common_add_to_album": "添加到相册",
|
||||||
"common_change_password": "更改密码",
|
"common_change_password": "更改密码",
|
||||||
"common_create_new_album": "新建相册",
|
"common_create_new_album": "新建相册",
|
||||||
"common_server_error": "请检查您的网络连接,确保服务器可访问且该应用程序或服务器版本兼容。",
|
"common_server_error": "请检查您的网络连接,确保服务器可访问且该应用程序与服务器版本兼容。",
|
||||||
"common_shared": "共享",
|
"common_shared": "共享",
|
||||||
"control_bottom_app_bar_add_to_album": "添加到相册",
|
"control_bottom_app_bar_add_to_album": "添加到相册",
|
||||||
"control_bottom_app_bar_album_info": "{} 项",
|
"control_bottom_app_bar_album_info": "{} 项",
|
||||||
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "详情",
|
"exif_bottom_sheet_details": "详情",
|
||||||
"exif_bottom_sheet_location": "位置",
|
"exif_bottom_sheet_location": "位置",
|
||||||
"exif_bottom_sheet_location_add": "添加位置信息",
|
"exif_bottom_sheet_location_add": "添加位置信息",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "正在处理",
|
"experimental_settings_new_asset_list_subtitle": "正在处理",
|
||||||
"experimental_settings_new_asset_list_title": "启用实验性照片网格",
|
"experimental_settings_new_asset_list_title": "启用实验性照片网格",
|
||||||
"experimental_settings_subtitle": "使用风险自负!",
|
"experimental_settings_subtitle": "使用风险自负!",
|
||||||
@ -207,7 +208,7 @@
|
|||||||
"home_page_upload_err_limit": "一次最多只能上传 30 个项目,跳过",
|
"home_page_upload_err_limit": "一次最多只能上传 30 个项目,跳过",
|
||||||
"image_viewer_page_state_provider_download_error": "下载出现错误",
|
"image_viewer_page_state_provider_download_error": "下载出现错误",
|
||||||
"image_viewer_page_state_provider_download_success": "下载成功",
|
"image_viewer_page_state_provider_download_success": "下载成功",
|
||||||
"image_viewer_page_state_provider_share_error": "共享错误",
|
"image_viewer_page_state_provider_share_error": "共享出错",
|
||||||
"library_page_albums": "相册",
|
"library_page_albums": "相册",
|
||||||
"library_page_archive": "归档",
|
"library_page_archive": "归档",
|
||||||
"library_page_device_albums": "设备上的相册",
|
"library_page_device_albums": "设备上的相册",
|
||||||
@ -248,7 +249,7 @@
|
|||||||
"login_form_next_button": "下一个",
|
"login_form_next_button": "下一个",
|
||||||
"login_form_password_hint": "密码",
|
"login_form_password_hint": "密码",
|
||||||
"login_form_save_login": "保持登录",
|
"login_form_save_login": "保持登录",
|
||||||
"login_form_server_empty": "输入服务器地址。",
|
"login_form_server_empty": "输入服务器地址",
|
||||||
"login_form_server_error": "无法连接到服务器。",
|
"login_form_server_error": "无法连接到服务器。",
|
||||||
"login_password_changed_error": "更新密码时出错\n",
|
"login_password_changed_error": "更新密码时出错\n",
|
||||||
"login_password_changed_success": "密码更新成功",
|
"login_password_changed_success": "密码更新成功",
|
||||||
@ -267,7 +268,7 @@
|
|||||||
"map_settings_date_range_option_all": "所有",
|
"map_settings_date_range_option_all": "所有",
|
||||||
"map_settings_date_range_option_day": "过去24小时",
|
"map_settings_date_range_option_day": "过去24小时",
|
||||||
"map_settings_date_range_option_days": "{}天前",
|
"map_settings_date_range_option_days": "{}天前",
|
||||||
"map_settings_date_range_option_year": "去年",
|
"map_settings_date_range_option_year": "1年前",
|
||||||
"map_settings_date_range_option_years": "{}年前",
|
"map_settings_date_range_option_years": "{}年前",
|
||||||
"map_settings_dialog_cancel": "取消",
|
"map_settings_dialog_cancel": "取消",
|
||||||
"map_settings_dialog_save": "保存",
|
"map_settings_dialog_save": "保存",
|
||||||
@ -343,7 +344,7 @@
|
|||||||
"search_page_your_activity": "您的活动",
|
"search_page_your_activity": "您的活动",
|
||||||
"search_page_your_map": "足迹",
|
"search_page_your_map": "足迹",
|
||||||
"search_result_page_new_search_hint": "搜索新的",
|
"search_result_page_new_search_hint": "搜索新的",
|
||||||
"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:您的搜索关键词",
|
||||||
"select_additional_user_for_sharing_page_suggestions": "建议",
|
"select_additional_user_for_sharing_page_suggestions": "建议",
|
||||||
"select_user_for_sharing_page_err_album": "创建相册失败",
|
"select_user_for_sharing_page_err_album": "创建相册失败",
|
||||||
|
@ -80,7 +80,7 @@
|
|||||||
"backup_controller_page_backup_sub": "已备份的照片和视频",
|
"backup_controller_page_backup_sub": "已备份的照片和视频",
|
||||||
"backup_controller_page_cancel": "取消",
|
"backup_controller_page_cancel": "取消",
|
||||||
"backup_controller_page_created": "创建时间: {}",
|
"backup_controller_page_created": "创建时间: {}",
|
||||||
"backup_controller_page_desc_backup": "打开前台备份,以在程序运行时自动备份。",
|
"backup_controller_page_desc_backup": "打开前台备份,以在程序运行时自动备份新项目。",
|
||||||
"backup_controller_page_excluded": "已排除:",
|
"backup_controller_page_excluded": "已排除:",
|
||||||
"backup_controller_page_failed": "失败({})",
|
"backup_controller_page_failed": "失败({})",
|
||||||
"backup_controller_page_filename": "文件名称: {} [{}]",
|
"backup_controller_page_filename": "文件名称: {} [{}]",
|
||||||
@ -121,7 +121,7 @@
|
|||||||
"cache_settings_statistics_shared": "共享相册缩略图",
|
"cache_settings_statistics_shared": "共享相册缩略图",
|
||||||
"cache_settings_statistics_thumbnail": "缩略图",
|
"cache_settings_statistics_thumbnail": "缩略图",
|
||||||
"cache_settings_statistics_title": "缓存使用情况",
|
"cache_settings_statistics_title": "缓存使用情况",
|
||||||
"cache_settings_subtitle": "控制 Immich 的缓存行为",
|
"cache_settings_subtitle": "控制 Immich app 的缓存行为",
|
||||||
"cache_settings_thumbnail_size": "缩略图缓存大小({} 项)",
|
"cache_settings_thumbnail_size": "缩略图缓存大小({} 项)",
|
||||||
"cache_settings_tile_subtitle": "设置本地存储行为",
|
"cache_settings_tile_subtitle": "设置本地存储行为",
|
||||||
"cache_settings_tile_title": "本地存储",
|
"cache_settings_tile_title": "本地存储",
|
||||||
@ -134,7 +134,7 @@
|
|||||||
"common_add_to_album": "添加到相册",
|
"common_add_to_album": "添加到相册",
|
||||||
"common_change_password": "更改密码",
|
"common_change_password": "更改密码",
|
||||||
"common_create_new_album": "新建相册",
|
"common_create_new_album": "新建相册",
|
||||||
"common_server_error": "请检查您的网络连接,确保服务器可访问且该应用程序或服务器版本兼容。",
|
"common_server_error": "请检查您的网络连接,确保服务器可访问且该应用程序与服务器版本兼容。",
|
||||||
"common_shared": "共享",
|
"common_shared": "共享",
|
||||||
"control_bottom_app_bar_add_to_album": "添加到相册",
|
"control_bottom_app_bar_add_to_album": "添加到相册",
|
||||||
"control_bottom_app_bar_album_info": "{} 项",
|
"control_bottom_app_bar_album_info": "{} 项",
|
||||||
@ -185,6 +185,7 @@
|
|||||||
"exif_bottom_sheet_details": "详情",
|
"exif_bottom_sheet_details": "详情",
|
||||||
"exif_bottom_sheet_location": "位置",
|
"exif_bottom_sheet_location": "位置",
|
||||||
"exif_bottom_sheet_location_add": "添加位置信息",
|
"exif_bottom_sheet_location_add": "添加位置信息",
|
||||||
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"experimental_settings_new_asset_list_subtitle": "正在处理",
|
"experimental_settings_new_asset_list_subtitle": "正在处理",
|
||||||
"experimental_settings_new_asset_list_title": "启用实验性照片网格",
|
"experimental_settings_new_asset_list_title": "启用实验性照片网格",
|
||||||
"experimental_settings_subtitle": "使用风险自负!",
|
"experimental_settings_subtitle": "使用风险自负!",
|
||||||
@ -192,7 +193,7 @@
|
|||||||
"favorites_page_no_favorites": "未找到收藏项目",
|
"favorites_page_no_favorites": "未找到收藏项目",
|
||||||
"favorites_page_title": "收藏",
|
"favorites_page_title": "收藏",
|
||||||
"home_page_add_to_album_conflicts": "已向相册 {album} 中添加 {added} 项。\n其中 {failed} 项在相册中已存在。",
|
"home_page_add_to_album_conflicts": "已向相册 {album} 中添加 {added} 项。\n其中 {failed} 项在相册中已存在。",
|
||||||
"home_page_add_to_album_err_local": "暂不能将本地资项目添加到相册中,跳过",
|
"home_page_add_to_album_err_local": "暂不能将本地项目添加到相册中,跳过",
|
||||||
"home_page_add_to_album_success": "已向相册 {album} 中添加 {added} 项。",
|
"home_page_add_to_album_success": "已向相册 {album} 中添加 {added} 项。",
|
||||||
"home_page_album_err_partner": "暂无法将同伴的项目添加到相册,跳过",
|
"home_page_album_err_partner": "暂无法将同伴的项目添加到相册,跳过",
|
||||||
"home_page_archive_err_local": "暂无法归档本地项目,跳过",
|
"home_page_archive_err_local": "暂无法归档本地项目,跳过",
|
||||||
@ -207,7 +208,7 @@
|
|||||||
"home_page_upload_err_limit": "一次最多只能上传 30 个项目,跳过",
|
"home_page_upload_err_limit": "一次最多只能上传 30 个项目,跳过",
|
||||||
"image_viewer_page_state_provider_download_error": "下载出现错误",
|
"image_viewer_page_state_provider_download_error": "下载出现错误",
|
||||||
"image_viewer_page_state_provider_download_success": "下载成功",
|
"image_viewer_page_state_provider_download_success": "下载成功",
|
||||||
"image_viewer_page_state_provider_share_error": "共享错误",
|
"image_viewer_page_state_provider_share_error": "共享出错",
|
||||||
"library_page_albums": "相册",
|
"library_page_albums": "相册",
|
||||||
"library_page_archive": "归档",
|
"library_page_archive": "归档",
|
||||||
"library_page_device_albums": "设备上的相册",
|
"library_page_device_albums": "设备上的相册",
|
||||||
@ -248,7 +249,7 @@
|
|||||||
"login_form_next_button": "下一个",
|
"login_form_next_button": "下一个",
|
||||||
"login_form_password_hint": "密码",
|
"login_form_password_hint": "密码",
|
||||||
"login_form_save_login": "保持登录",
|
"login_form_save_login": "保持登录",
|
||||||
"login_form_server_empty": "输入服务器地址。",
|
"login_form_server_empty": "输入服务器地址",
|
||||||
"login_form_server_error": "无法连接到服务器。",
|
"login_form_server_error": "无法连接到服务器。",
|
||||||
"login_password_changed_error": "更新密码时出错\n",
|
"login_password_changed_error": "更新密码时出错\n",
|
||||||
"login_password_changed_success": "密码更新成功",
|
"login_password_changed_success": "密码更新成功",
|
||||||
@ -267,7 +268,7 @@
|
|||||||
"map_settings_date_range_option_all": "所有",
|
"map_settings_date_range_option_all": "所有",
|
||||||
"map_settings_date_range_option_day": "过去24小时",
|
"map_settings_date_range_option_day": "过去24小时",
|
||||||
"map_settings_date_range_option_days": "{}天前",
|
"map_settings_date_range_option_days": "{}天前",
|
||||||
"map_settings_date_range_option_year": "去年",
|
"map_settings_date_range_option_year": "1年前",
|
||||||
"map_settings_date_range_option_years": "{}年前",
|
"map_settings_date_range_option_years": "{}年前",
|
||||||
"map_settings_dialog_cancel": "取消",
|
"map_settings_dialog_cancel": "取消",
|
||||||
"map_settings_dialog_save": "保存",
|
"map_settings_dialog_save": "保存",
|
||||||
@ -343,7 +344,7 @@
|
|||||||
"search_page_your_activity": "您的活动",
|
"search_page_your_activity": "您的活动",
|
||||||
"search_page_your_map": "足迹",
|
"search_page_your_map": "足迹",
|
||||||
"search_result_page_new_search_hint": "搜索新的",
|
"search_result_page_new_search_hint": "搜索新的",
|
||||||
"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:您的搜索关键词",
|
||||||
"select_additional_user_for_sharing_page_suggestions": "建议",
|
"select_additional_user_for_sharing_page_suggestions": "建议",
|
||||||
"select_user_for_sharing_page_err_album": "创建相册失败",
|
"select_user_for_sharing_page_err_album": "创建相册失败",
|
||||||
|
@ -180,4 +180,4 @@ SPEC CHECKSUMS:
|
|||||||
|
|
||||||
PODFILE CHECKSUM: 64c9b5291666c0ca3caabdfe9865c141ac40321d
|
PODFILE CHECKSUM: 64c9b5291666c0ca3caabdfe9865c141ac40321d
|
||||||
|
|
||||||
COCOAPODS: 1.12.1
|
COCOAPODS: 1.11.3
|
||||||
|
@ -19,7 +19,7 @@ platform :ios do
|
|||||||
desc "iOS Beta"
|
desc "iOS Beta"
|
||||||
lane :beta do
|
lane :beta do
|
||||||
increment_version_number(
|
increment_version_number(
|
||||||
version_number: "1.97.0"
|
version_number: "1.98.0"
|
||||||
)
|
)
|
||||||
increment_build_number(
|
increment_build_number(
|
||||||
build_number: latest_testflight_build_number + 1,
|
build_number: latest_testflight_build_number + 1,
|
||||||
|
@ -1,26 +1,19 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:chewie/chewie.dart';
|
import 'package:chewie/chewie.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
|
||||||
import 'package:immich_mobile/shared/models/store.dart';
|
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
import 'package:immich_mobile/shared/models/store.dart' as store;
|
|
||||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
|
||||||
|
|
||||||
/// Provides the initialized video player controller
|
/// Provides the initialized video player controller
|
||||||
/// If the asset is local, use the local file
|
/// If the asset is local, use the local file
|
||||||
/// Otherwise, use a video player with a URL
|
/// Otherwise, use a video player with a URL
|
||||||
ChewieController? useChewieController(
|
ChewieController useChewieController({
|
||||||
Asset asset, {
|
required VideoPlayerController controller,
|
||||||
EdgeInsets controlsSafeAreaMinimum = const EdgeInsets.only(
|
EdgeInsets controlsSafeAreaMinimum = const EdgeInsets.only(
|
||||||
bottom: 100,
|
bottom: 100,
|
||||||
),
|
),
|
||||||
bool showOptions = true,
|
bool showOptions = true,
|
||||||
bool showControlsOnInitialize = false,
|
bool showControlsOnInitialize = false,
|
||||||
bool autoPlay = true,
|
bool autoPlay = true,
|
||||||
bool autoInitialize = true,
|
|
||||||
bool allowFullScreen = false,
|
bool allowFullScreen = false,
|
||||||
bool allowedScreenSleep = false,
|
bool allowedScreenSleep = false,
|
||||||
bool showControls = true,
|
bool showControls = true,
|
||||||
@ -33,7 +26,7 @@ ChewieController? useChewieController(
|
|||||||
}) {
|
}) {
|
||||||
return use(
|
return use(
|
||||||
_ChewieControllerHook(
|
_ChewieControllerHook(
|
||||||
asset: asset,
|
controller: controller,
|
||||||
placeholder: placeholder,
|
placeholder: placeholder,
|
||||||
showOptions: showOptions,
|
showOptions: showOptions,
|
||||||
controlsSafeAreaMinimum: controlsSafeAreaMinimum,
|
controlsSafeAreaMinimum: controlsSafeAreaMinimum,
|
||||||
@ -43,7 +36,6 @@ ChewieController? useChewieController(
|
|||||||
hideControlsTimer: hideControlsTimer,
|
hideControlsTimer: hideControlsTimer,
|
||||||
showControlsOnInitialize: showControlsOnInitialize,
|
showControlsOnInitialize: showControlsOnInitialize,
|
||||||
showControls: showControls,
|
showControls: showControls,
|
||||||
autoInitialize: autoInitialize,
|
|
||||||
allowedScreenSleep: allowedScreenSleep,
|
allowedScreenSleep: allowedScreenSleep,
|
||||||
onPlaying: onPlaying,
|
onPlaying: onPlaying,
|
||||||
onPaused: onPaused,
|
onPaused: onPaused,
|
||||||
@ -52,13 +44,12 @@ ChewieController? useChewieController(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChewieControllerHook extends Hook<ChewieController?> {
|
class _ChewieControllerHook extends Hook<ChewieController> {
|
||||||
final Asset asset;
|
final VideoPlayerController controller;
|
||||||
final EdgeInsets controlsSafeAreaMinimum;
|
final EdgeInsets controlsSafeAreaMinimum;
|
||||||
final bool showOptions;
|
final bool showOptions;
|
||||||
final bool showControlsOnInitialize;
|
final bool showControlsOnInitialize;
|
||||||
final bool autoPlay;
|
final bool autoPlay;
|
||||||
final bool autoInitialize;
|
|
||||||
final bool allowFullScreen;
|
final bool allowFullScreen;
|
||||||
final bool allowedScreenSleep;
|
final bool allowedScreenSleep;
|
||||||
final bool showControls;
|
final bool showControls;
|
||||||
@ -70,14 +61,13 @@ class _ChewieControllerHook extends Hook<ChewieController?> {
|
|||||||
final VoidCallback? onVideoEnded;
|
final VoidCallback? onVideoEnded;
|
||||||
|
|
||||||
const _ChewieControllerHook({
|
const _ChewieControllerHook({
|
||||||
required this.asset,
|
required this.controller,
|
||||||
this.controlsSafeAreaMinimum = const EdgeInsets.only(
|
this.controlsSafeAreaMinimum = const EdgeInsets.only(
|
||||||
bottom: 100,
|
bottom: 100,
|
||||||
),
|
),
|
||||||
this.showOptions = true,
|
this.showOptions = true,
|
||||||
this.showControlsOnInitialize = false,
|
this.showControlsOnInitialize = false,
|
||||||
this.autoPlay = true,
|
this.autoPlay = true,
|
||||||
this.autoInitialize = true,
|
|
||||||
this.allowFullScreen = false,
|
this.allowFullScreen = false,
|
||||||
this.allowedScreenSleep = false,
|
this.allowedScreenSleep = false,
|
||||||
this.showControls = true,
|
this.showControls = true,
|
||||||
@ -94,28 +84,33 @@ class _ChewieControllerHook extends Hook<ChewieController?> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ChewieControllerHookState
|
class _ChewieControllerHookState
|
||||||
extends HookState<ChewieController?, _ChewieControllerHook> {
|
extends HookState<ChewieController, _ChewieControllerHook> {
|
||||||
ChewieController? chewieController;
|
late ChewieController chewieController = ChewieController(
|
||||||
VideoPlayerController? videoPlayerController;
|
videoPlayerController: hook.controller,
|
||||||
|
controlsSafeAreaMinimum: hook.controlsSafeAreaMinimum,
|
||||||
@override
|
showOptions: hook.showOptions,
|
||||||
void initHook() async {
|
showControlsOnInitialize: hook.showControlsOnInitialize,
|
||||||
super.initHook();
|
autoPlay: hook.autoPlay,
|
||||||
unawaited(_initialize());
|
allowFullScreen: hook.allowFullScreen,
|
||||||
}
|
allowedScreenSleep: hook.allowedScreenSleep,
|
||||||
|
showControls: hook.showControls,
|
||||||
|
customControls: hook.customControls,
|
||||||
|
placeholder: hook.placeholder,
|
||||||
|
hideControlsTimer: hook.hideControlsTimer,
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
chewieController?.dispose();
|
chewieController.dispose();
|
||||||
videoPlayerController?.dispose();
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ChewieController? build(BuildContext context) {
|
ChewieController build(BuildContext context) {
|
||||||
return chewieController;
|
return chewieController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// Initializes the chewie controller and video player controller
|
/// Initializes the chewie controller and video player controller
|
||||||
Future<void> _initialize() async {
|
Future<void> _initialize() async {
|
||||||
if (hook.asset.isLocal && hook.asset.livePhotoVideoId == null) {
|
if (hook.asset.isLocal && hook.asset.livePhotoVideoId == null) {
|
||||||
@ -141,39 +136,21 @@ class _ChewieControllerHookState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
videoPlayerController!.addListener(() {
|
|
||||||
final value = videoPlayerController!.value;
|
|
||||||
if (value.isPlaying) {
|
|
||||||
WakelockPlus.enable();
|
|
||||||
hook.onPlaying?.call();
|
|
||||||
} else if (!value.isPlaying) {
|
|
||||||
WakelockPlus.disable();
|
|
||||||
hook.onPaused?.call();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.position == value.duration) {
|
|
||||||
WakelockPlus.disable();
|
|
||||||
hook.onVideoEnded?.call();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await videoPlayerController!.initialize();
|
await videoPlayerController!.initialize();
|
||||||
|
|
||||||
setState(() {
|
chewieController = ChewieController(
|
||||||
chewieController = ChewieController(
|
videoPlayerController: videoPlayerController!,
|
||||||
videoPlayerController: videoPlayerController!,
|
controlsSafeAreaMinimum: hook.controlsSafeAreaMinimum,
|
||||||
controlsSafeAreaMinimum: hook.controlsSafeAreaMinimum,
|
showOptions: hook.showOptions,
|
||||||
showOptions: hook.showOptions,
|
showControlsOnInitialize: hook.showControlsOnInitialize,
|
||||||
showControlsOnInitialize: hook.showControlsOnInitialize,
|
autoPlay: hook.autoPlay,
|
||||||
autoPlay: hook.autoPlay,
|
allowFullScreen: hook.allowFullScreen,
|
||||||
autoInitialize: hook.autoInitialize,
|
allowedScreenSleep: hook.allowedScreenSleep,
|
||||||
allowFullScreen: hook.allowFullScreen,
|
showControls: hook.showControls,
|
||||||
allowedScreenSleep: hook.allowedScreenSleep,
|
customControls: hook.customControls,
|
||||||
showControls: hook.showControls,
|
placeholder: hook.placeholder,
|
||||||
customControls: hook.customControls,
|
hideControlsTimer: hook.hideControlsTimer,
|
||||||
placeholder: hook.placeholder,
|
);
|
||||||
hideControlsTimer: hook.hideControlsTimer,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
|
import 'package:immich_mobile/shared/services/asset.service.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:openapi/api.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'asset_people.provider.g.dart';
|
||||||
|
|
||||||
|
/// Maintains the list of people for an asset.
|
||||||
|
@riverpod
|
||||||
|
class AssetPeopleNotifier extends _$AssetPeopleNotifier {
|
||||||
|
final log = Logger('AssetPeopleNotifier');
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<PersonWithFacesResponseDto>> build(Asset asset) async {
|
||||||
|
if (!asset.isRemote) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final list = await ref
|
||||||
|
.watch(assetServiceProvider)
|
||||||
|
.getRemotePeopleOfAsset(asset.remoteId!);
|
||||||
|
if (list == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// explicitly a sorted slice to make it deterministic
|
||||||
|
// named people will be at the beginning, and names are sorted
|
||||||
|
// ascendingly
|
||||||
|
list.sort((a, b) {
|
||||||
|
final aNotEmpty = a.name.isNotEmpty;
|
||||||
|
final bNotEmpty = b.name.isNotEmpty;
|
||||||
|
if (aNotEmpty && !bNotEmpty) {
|
||||||
|
return -1;
|
||||||
|
} else if (!aNotEmpty && bNotEmpty) {
|
||||||
|
return 1;
|
||||||
|
} else if (!aNotEmpty && !bNotEmpty) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.name.compareTo(b.name);
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> refresh() async {
|
||||||
|
// invalidate the state – this way we don't have to
|
||||||
|
// duplicate the code from build.
|
||||||
|
ref.invalidateSelf();
|
||||||
|
}
|
||||||
|
}
|
189
mobile/lib/modules/asset_viewer/providers/asset_people.provider.g.dart
generated
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'asset_people.provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$assetPeopleNotifierHash() =>
|
||||||
|
r'192a4ee188f781000fe43f1675c49e1081ccc631';
|
||||||
|
|
||||||
|
/// Copied from Dart SDK
|
||||||
|
class _SystemHash {
|
||||||
|
_SystemHash._();
|
||||||
|
|
||||||
|
static int combine(int hash, int value) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + value);
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||||
|
return hash ^ (hash >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int finish(int hash) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = hash ^ (hash >> 11);
|
||||||
|
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _$AssetPeopleNotifier extends BuildlessAutoDisposeAsyncNotifier<
|
||||||
|
List<PersonWithFacesResponseDto>> {
|
||||||
|
late final Asset asset;
|
||||||
|
|
||||||
|
Future<List<PersonWithFacesResponseDto>> build(
|
||||||
|
Asset asset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maintains the list of people for an asset.
|
||||||
|
///
|
||||||
|
/// Copied from [AssetPeopleNotifier].
|
||||||
|
@ProviderFor(AssetPeopleNotifier)
|
||||||
|
const assetPeopleNotifierProvider = AssetPeopleNotifierFamily();
|
||||||
|
|
||||||
|
/// Maintains the list of people for an asset.
|
||||||
|
///
|
||||||
|
/// Copied from [AssetPeopleNotifier].
|
||||||
|
class AssetPeopleNotifierFamily
|
||||||
|
extends Family<AsyncValue<List<PersonWithFacesResponseDto>>> {
|
||||||
|
/// Maintains the list of people for an asset.
|
||||||
|
///
|
||||||
|
/// Copied from [AssetPeopleNotifier].
|
||||||
|
const AssetPeopleNotifierFamily();
|
||||||
|
|
||||||
|
/// Maintains the list of people for an asset.
|
||||||
|
///
|
||||||
|
/// Copied from [AssetPeopleNotifier].
|
||||||
|
AssetPeopleNotifierProvider call(
|
||||||
|
Asset asset,
|
||||||
|
) {
|
||||||
|
return AssetPeopleNotifierProvider(
|
||||||
|
asset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AssetPeopleNotifierProvider getProviderOverride(
|
||||||
|
covariant AssetPeopleNotifierProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
provider.asset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'assetPeopleNotifierProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maintains the list of people for an asset.
|
||||||
|
///
|
||||||
|
/// Copied from [AssetPeopleNotifier].
|
||||||
|
class AssetPeopleNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl<
|
||||||
|
AssetPeopleNotifier, List<PersonWithFacesResponseDto>> {
|
||||||
|
/// Maintains the list of people for an asset.
|
||||||
|
///
|
||||||
|
/// Copied from [AssetPeopleNotifier].
|
||||||
|
AssetPeopleNotifierProvider(
|
||||||
|
Asset asset,
|
||||||
|
) : this._internal(
|
||||||
|
() => AssetPeopleNotifier()..asset = asset,
|
||||||
|
from: assetPeopleNotifierProvider,
|
||||||
|
name: r'assetPeopleNotifierProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$assetPeopleNotifierHash,
|
||||||
|
dependencies: AssetPeopleNotifierFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
AssetPeopleNotifierFamily._allTransitiveDependencies,
|
||||||
|
asset: asset,
|
||||||
|
);
|
||||||
|
|
||||||
|
AssetPeopleNotifierProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.asset,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final Asset asset;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<PersonWithFacesResponseDto>> runNotifierBuild(
|
||||||
|
covariant AssetPeopleNotifier notifier,
|
||||||
|
) {
|
||||||
|
return notifier.build(
|
||||||
|
asset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(AssetPeopleNotifier Function() create) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: AssetPeopleNotifierProvider._internal(
|
||||||
|
() => create()..asset = asset,
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
asset: asset,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeAsyncNotifierProviderElement<AssetPeopleNotifier,
|
||||||
|
List<PersonWithFacesResponseDto>> createElement() {
|
||||||
|
return _AssetPeopleNotifierProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is AssetPeopleNotifierProvider && other.asset == asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, asset.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin AssetPeopleNotifierRef
|
||||||
|
on AutoDisposeAsyncNotifierProviderRef<List<PersonWithFacesResponseDto>> {
|
||||||
|
/// The parameter `asset` of this provider.
|
||||||
|
Asset get asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AssetPeopleNotifierProviderElement
|
||||||
|
extends AutoDisposeAsyncNotifierProviderElement<AssetPeopleNotifier,
|
||||||
|
List<PersonWithFacesResponseDto>> with AssetPeopleNotifierRef {
|
||||||
|
_AssetPeopleNotifierProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Asset get asset => (origin as AssetPeopleNotifierProvider).asset;
|
||||||
|
}
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
@ -2,6 +2,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'asset_stack.provider.g.dart';
|
||||||
|
|
||||||
class AssetStackNotifier extends StateNotifier<List<Asset>> {
|
class AssetStackNotifier extends StateNotifier<List<Asset>> {
|
||||||
final Asset _asset;
|
final Asset _asset;
|
||||||
@ -49,3 +52,8 @@ final assetStackProvider =
|
|||||||
.sortByFileCreatedAtDesc()
|
.sortByFileCreatedAtDesc()
|
||||||
.findAll();
|
.findAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
int assetStackIndex(AssetStackIndexRef ref, Asset asset) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
158
mobile/lib/modules/asset_viewer/providers/asset_stack.provider.g.dart
generated
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'asset_stack.provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$assetStackIndexHash() => r'0f2df55e929767c8c698bd432b5e6e351d000a16';
|
||||||
|
|
||||||
|
/// Copied from Dart SDK
|
||||||
|
class _SystemHash {
|
||||||
|
_SystemHash._();
|
||||||
|
|
||||||
|
static int combine(int hash, int value) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + value);
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||||
|
return hash ^ (hash >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int finish(int hash) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = hash ^ (hash >> 11);
|
||||||
|
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [assetStackIndex].
|
||||||
|
@ProviderFor(assetStackIndex)
|
||||||
|
const assetStackIndexProvider = AssetStackIndexFamily();
|
||||||
|
|
||||||
|
/// See also [assetStackIndex].
|
||||||
|
class AssetStackIndexFamily extends Family<int> {
|
||||||
|
/// See also [assetStackIndex].
|
||||||
|
const AssetStackIndexFamily();
|
||||||
|
|
||||||
|
/// See also [assetStackIndex].
|
||||||
|
AssetStackIndexProvider call(
|
||||||
|
Asset asset,
|
||||||
|
) {
|
||||||
|
return AssetStackIndexProvider(
|
||||||
|
asset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AssetStackIndexProvider getProviderOverride(
|
||||||
|
covariant AssetStackIndexProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
provider.asset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'assetStackIndexProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [assetStackIndex].
|
||||||
|
class AssetStackIndexProvider extends AutoDisposeProvider<int> {
|
||||||
|
/// See also [assetStackIndex].
|
||||||
|
AssetStackIndexProvider(
|
||||||
|
Asset asset,
|
||||||
|
) : this._internal(
|
||||||
|
(ref) => assetStackIndex(
|
||||||
|
ref as AssetStackIndexRef,
|
||||||
|
asset,
|
||||||
|
),
|
||||||
|
from: assetStackIndexProvider,
|
||||||
|
name: r'assetStackIndexProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$assetStackIndexHash,
|
||||||
|
dependencies: AssetStackIndexFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
AssetStackIndexFamily._allTransitiveDependencies,
|
||||||
|
asset: asset,
|
||||||
|
);
|
||||||
|
|
||||||
|
AssetStackIndexProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.asset,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final Asset asset;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(
|
||||||
|
int Function(AssetStackIndexRef provider) create,
|
||||||
|
) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: AssetStackIndexProvider._internal(
|
||||||
|
(ref) => create(ref as AssetStackIndexRef),
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
asset: asset,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeProviderElement<int> createElement() {
|
||||||
|
return _AssetStackIndexProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is AssetStackIndexProvider && other.asset == asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, asset.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin AssetStackIndexRef on AutoDisposeProviderRef<int> {
|
||||||
|
/// The parameter `asset` of this provider.
|
||||||
|
Asset get asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AssetStackIndexProviderElement extends AutoDisposeProviderElement<int>
|
||||||
|
with AssetStackIndexRef {
|
||||||
|
_AssetStackIndexProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Asset get asset => (origin as AssetStackIndexProvider).asset;
|
||||||
|
}
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
@ -0,0 +1,44 @@
|
|||||||
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
|
import 'package:immich_mobile/shared/models/store.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
|
part 'video_player_controller_provider.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<VideoPlayerController> videoPlayerController(
|
||||||
|
VideoPlayerControllerRef ref, {
|
||||||
|
required Asset asset,
|
||||||
|
}) async {
|
||||||
|
late VideoPlayerController controller;
|
||||||
|
if (asset.isLocal && asset.livePhotoVideoId == null) {
|
||||||
|
// Use a local file for the video player controller
|
||||||
|
final file = await asset.local!.file;
|
||||||
|
if (file == null) {
|
||||||
|
throw Exception('No file found for the video');
|
||||||
|
}
|
||||||
|
controller = VideoPlayerController.file(file);
|
||||||
|
} else {
|
||||||
|
// Use a network URL for the video player controller
|
||||||
|
final serverEndpoint = Store.get(StoreKey.serverEndpoint);
|
||||||
|
final String videoUrl = asset.livePhotoVideoId != null
|
||||||
|
? '$serverEndpoint/asset/file/${asset.livePhotoVideoId}'
|
||||||
|
: '$serverEndpoint/asset/file/${asset.remoteId}';
|
||||||
|
|
||||||
|
final url = Uri.parse(videoUrl);
|
||||||
|
final accessToken = Store.get(StoreKey.accessToken);
|
||||||
|
|
||||||
|
controller = VideoPlayerController.networkUrl(
|
||||||
|
url,
|
||||||
|
httpHeaders: {"x-immich-user-token": accessToken},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await controller.initialize();
|
||||||
|
|
||||||
|
ref.onDispose(() {
|
||||||
|
controller.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
}
|
164
mobile/lib/modules/asset_viewer/providers/video_player_controller_provider.g.dart
generated
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'video_player_controller_provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$videoPlayerControllerHash() =>
|
||||||
|
r'72b45de66542021717807655e25ec92d78d80eec';
|
||||||
|
|
||||||
|
/// Copied from Dart SDK
|
||||||
|
class _SystemHash {
|
||||||
|
_SystemHash._();
|
||||||
|
|
||||||
|
static int combine(int hash, int value) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + value);
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||||
|
return hash ^ (hash >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int finish(int hash) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = hash ^ (hash >> 11);
|
||||||
|
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [videoPlayerController].
|
||||||
|
@ProviderFor(videoPlayerController)
|
||||||
|
const videoPlayerControllerProvider = VideoPlayerControllerFamily();
|
||||||
|
|
||||||
|
/// See also [videoPlayerController].
|
||||||
|
class VideoPlayerControllerFamily
|
||||||
|
extends Family<AsyncValue<VideoPlayerController>> {
|
||||||
|
/// See also [videoPlayerController].
|
||||||
|
const VideoPlayerControllerFamily();
|
||||||
|
|
||||||
|
/// See also [videoPlayerController].
|
||||||
|
VideoPlayerControllerProvider call({
|
||||||
|
required Asset asset,
|
||||||
|
}) {
|
||||||
|
return VideoPlayerControllerProvider(
|
||||||
|
asset: asset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
VideoPlayerControllerProvider getProviderOverride(
|
||||||
|
covariant VideoPlayerControllerProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
asset: provider.asset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'videoPlayerControllerProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [videoPlayerController].
|
||||||
|
class VideoPlayerControllerProvider
|
||||||
|
extends AutoDisposeFutureProvider<VideoPlayerController> {
|
||||||
|
/// See also [videoPlayerController].
|
||||||
|
VideoPlayerControllerProvider({
|
||||||
|
required Asset asset,
|
||||||
|
}) : this._internal(
|
||||||
|
(ref) => videoPlayerController(
|
||||||
|
ref as VideoPlayerControllerRef,
|
||||||
|
asset: asset,
|
||||||
|
),
|
||||||
|
from: videoPlayerControllerProvider,
|
||||||
|
name: r'videoPlayerControllerProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$videoPlayerControllerHash,
|
||||||
|
dependencies: VideoPlayerControllerFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
VideoPlayerControllerFamily._allTransitiveDependencies,
|
||||||
|
asset: asset,
|
||||||
|
);
|
||||||
|
|
||||||
|
VideoPlayerControllerProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.asset,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final Asset asset;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(
|
||||||
|
FutureOr<VideoPlayerController> Function(VideoPlayerControllerRef provider)
|
||||||
|
create,
|
||||||
|
) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: VideoPlayerControllerProvider._internal(
|
||||||
|
(ref) => create(ref as VideoPlayerControllerRef),
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
asset: asset,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeFutureProviderElement<VideoPlayerController> createElement() {
|
||||||
|
return _VideoPlayerControllerProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is VideoPlayerControllerProvider && other.asset == asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, asset.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin VideoPlayerControllerRef
|
||||||
|
on AutoDisposeFutureProviderRef<VideoPlayerController> {
|
||||||
|
/// The parameter `asset` of this provider.
|
||||||
|
Asset get asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoPlayerControllerProviderElement
|
||||||
|
extends AutoDisposeFutureProviderElement<VideoPlayerController>
|
||||||
|
with VideoPlayerControllerRef {
|
||||||
|
_VideoPlayerControllerProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Asset get asset => (origin as VideoPlayerControllerProvider).asset;
|
||||||
|
}
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|